diff --git a/README.md b/README.md index 00a4854..13ed945 100644 --- a/README.md +++ b/README.md @@ -9,10 +9,11 @@ npm install qwik-speak --save-dev ## Getting Started - [Quick Start](./docs/quick-start.md) -- [Tutorial: localized routing with prefix only](./docs/tutorial-routing.md) -- [Tutorial: localized routing with url rewriting](./docs/tutorial-routing-rewrite.md) +- [Tutorial: localized routing with the language](./docs/tutorial-routing.md) +- [Tutorial: translated routing with url rewriting](./docs/tutorial-routing-rewrite.md) - [Translate](./docs/translate.md) -- [Translation functions](./docs/translation-functions.md) +- [Translation functions](./docs/translation-functions.md) +- [Lazy loading translation](./docs/lazy-loading.md) - [Qwik Speak and Adapters](./docs/adapters.md) - [Testing](./docs/testing.md) @@ -21,15 +22,15 @@ Live example on [Cloudflare pages](https://qwik-speak.pages.dev/) and playground ## Overview ### Getting the translation ```tsx -import { useTranslate } from 'qwik-speak'; +import { inlineTranslate } from 'qwik-speak'; export default component$(() => { - const t = useTranslate(); + const t = inlineTranslate(); return ( <> -

{t('app.title@@Qwik Speak')}

{/* Qwik Speak */} -

{t('home.greeting@@Hi! I am {{name}}', { name: 'Qwik Speak' })}

{/* Hi! I am Qwik Speak */} +

{t('title@@Qwik Speak')}

{/* Qwik Speak */} +

{t('greeting@@Hi! I am {{name}}', { name: 'Qwik Speak' })}

{/* Hi! I am Qwik Speak */} ); }); @@ -53,6 +54,11 @@ export default component$(() => { }); ``` +## Static translations +Translation are loaded and inlined in chunks sent to the browser during the build. + +See [Qwik Speak Inline Vite plugin](./docs/inline.md) for more information on how it works and how to use it. + ## Extraction of translations To extract translations directly from the components, a command is available that automatically generates the files with the keys and default values. @@ -63,11 +69,6 @@ To automatically translate files, an external command is available that uses Ope See [GPT Translate JSON](./docs/gpt-translate-json.md) for more information on how to use it. -## Production -In production, translations are loaded and inlined during the build. - -See [Qwik Speak Inline Vite plugin](./docs/inline.md) for more information on how it works and how to use it. - ## Speak context ```mermaid stateDiagram-v2 @@ -93,16 +94,11 @@ stateDiagram-v2 - loadTranslation$ end note note right of State5 - key-value pairs - of translation data + runtime assets end note ``` > `SpeakState` is immutable: it cannot be updated after it is created and is not reactive -- `useSpeakContext()` Returns the Speak state -- `useSpeakConfig()` Returns the configuration in Speak context -- `useSpeakLocale()` Returns the locale in Speak context - ### Speak config - `defaultLocale` The default locale to use as fallback - `supportedLocales` List of locales supported by the app @@ -110,7 +106,7 @@ stateDiagram-v2 - `runtimeAssets` Assets available at runtime - `keySeparator` Separator of nested keys. Default is `.` - `keyValueSeparator` Key-value separator. Default is `@@` -- `rewriteRoutes` Rewrite routes as specified in Vite config for qwikCity +- `rewriteRoutes` Rewrite routes as specified in Vite config for `qwikCity` plugin ### SpeakLocale The `SpeakLocale` object contains the `lang`, in the format `language[-script][-region]`, where: @@ -129,36 +125,34 @@ and optionally contains: `TranslationFn` interface can be implemented to change the behavior of the library: - `loadTranslation$` QRL function to load translation data +### Translation +`Translation` contains only the key value pairs of the translation data provided with the `runtimeAssets` + ## APIs -### Components -#### QwikSpeakProvider component -`QwikSpeakProvider` component provides the Speak context to the app. `Props`: +### Providers +`useQwikSpeak(props: QwikSpeakProps)` provides the Speak context to the app. `QwikSpeakProps`: - `config` Speak config - `translationFn` Optional functions to use - - `locale` Optional locale to use - `langs` Optional additional languages to preload data for (multilingual) -#### Speak component (scoped translations) -`Speak` component can be used for scoped translations. `Props`: +`useSpeak(props: SpeakProps) ` can be used for lazy loading translation. `SpeakProps`: - `assets` Assets to load - `runtimeAssets` Assets to load available at runtime - `langs` Optional additional languages to preload data for (multilingual) -### Functions -#### Translate -- `useTranslate: () => (keys: string | string[], params?: Record, lang?: string)` -Translates a key or an array of keys. The syntax of the string is `key@@[default value]` +### Context +- `useSpeakContext()` Returns the Speak state +- `useSpeakConfig()` Returns the configuration in Speak context +- `useSpeakLocale()` Returns the locale in Speak context -- `inlineTranslate(keys: string | string[], ctx: SpeakState, params?: Record, lang?: string)` -Translates a key or an array of keys outside the `component$`. The syntax of the string is `key@@[default value]` +### Translate +- `inlineTranslate: () => (keys: string | string[], params?: Record, lang?: string)` +Translates a key or an array of keys. The syntax of the string is `key@@[default value]` -- `usePlural: () => (value: number | string, key?: string, params?: Record, options?: Intl.PluralRulesOptions, lang?: string)` +- `inlinePlural: () => (value: number | string, key?: string, params?: Record, options?: Intl.PluralRulesOptions, lang?: string)` Gets the plural by a number using [Intl.PluralRules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/PluralRules) API -- `useTranslatePath: () => (paths: string | string[], lang?: string)` -Translates a path or an array of paths. The translating string can be in any language. If not specified the target lang is the current one - -#### Localize +### Localize - `useFormatDate: () => (value: Date | number | string, options?: Intl.DateTimeFormatOptions, lang?: string, timeZone?: string)` Formats a date using [Intl.DateTimeFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat) API @@ -171,6 +165,16 @@ Formats a number using [Intl.NumberFormat](https://developer.mozilla.org/en-US/d - `useDisplayName: () => (code: string, options: Intl.DisplayNamesOptions, lang?: string)` Returns the translation of language, region, script or currency display names using [Intl.DisplayNames](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DisplayNames) API +### Routing +- `localizePath: () => (route: (string | URL) | string[], lang?: string)` +Localize a path, an URL or an array of paths with the language + +- `translatePath: () => (route: (string | URL) | string[], lang?: string)` +Translates a path, an URL or an array of paths. The translating string can be in any language. If not specified the target lang is the current one + +### Testing +- `QwikSpeakMockProvider` component provides the Speak context to test enviroments + ## Development Builds ### Library & tools #### Build diff --git a/SUMMARY.md b/SUMMARY.md index cbc89de..14eef82 100644 --- a/SUMMARY.md +++ b/SUMMARY.md @@ -3,10 +3,11 @@ ## Library * [Quick Start](docs/quick-start.md) -* [Tutorial: localized routing with prefix only](docs/tutorial-routing.md) -* [Tutorial: localized routing with url rewriting](docs/tutorial-routing-rewrite.md) +* [Tutorial: localized routing with the language](docs/tutorial-routing.md) +* [Tutorial: translated routing with url rewriting](docs/tutorial-routing-rewrite.md) * [Translate](docs/translate.md) * [Translation functions](docs/translation-functions.md) +* [Lazy loading translation](docs/lazy-loading.md) * [Qwik Speak and Adapters](docs/adapters.md) * [Testing](docs/testing.md) diff --git a/docs/adapters.md b/docs/adapters.md index 289e405..00a9fe5 100644 --- a/docs/adapters.md +++ b/docs/adapters.md @@ -7,7 +7,7 @@ If your production environment doesn't support _dynamic import_, you can import /** * Translation files are imported directly as string */ -const translationData = import.meta.glob('/i18n/**/*.json', { as: 'raw', eager: true }); +const translationData = import.meta.glob('/i18n/**/*.json', { as: 'raw', eager: true }); const loadTranslation$: LoadTranslationFn = server$((lang: string, asset: string) => JSON.parse(translationData[`/i18n/${lang}/${asset}.json`]) diff --git a/docs/extract.md b/docs/extract.md index 9b028e1..73e35f1 100644 --- a/docs/extract.md +++ b/docs/extract.md @@ -7,13 +7,13 @@ #### Get the code ready Optionally, you can use a default value for the keys. The syntax is `key@@[default value]`: ```html -

{t('app.title@@Qwik Speak'}

-

{t('home.greeting@@Hi! I am {{name}}', { name: 'Qwik Speak' })}

+

{t('title@@Qwik Speak'}

+

{t('greeting@@Hi! I am {{name}}', { name: 'Qwik Speak' })}

``` When you use a default value, it will be used as initial value for the key in every translation. -> Note. A key will not be extracted when it is an identifier or contains an indentifier (dynamic) +> Note that it is not necessary to provide the default value of a key every time: it is sufficient and not mandatory to provide it once in the app #### Naming conventions If you use scoped translations, the first property will be used as filename: diff --git a/docs/inline.md b/docs/inline.md index d9ae365..b28cae5 100644 --- a/docs/inline.md +++ b/docs/inline.md @@ -1,18 +1,19 @@ # Qwik Speak Inline Vite plugin -> Inline Qwik Speak `useTranslate`, `inlineTranslate` and `usePlural` functions at compile time +> Inline Qwik Speak `inlineTranslate` and `inlinePlural` functions at compile time ## How it works -In development mode, translation happens _at runtime_: `assets` are loaded during SSR or on client, and the lookup also happens at runtime. +O the server, translation happens _at runtime_: `assets` are loaded during SSR and the lookup also happens at runtime. -In production mode, `assets` are loaded only during SSR, and to get the translations on the client as well you have to use _Qwik Speak Inline_ Vite plugin. +On the client, translation happens _at compile-time_: `assets` are loaded and inlined in chunks sent to the browser during the build, reducing resource usage at runtime. -Using the _Qwik Speak Inline_, translation happens _at compile-time_: `assets` are loaded and inlined in chunks sent to the browser during the build, reducing resource usage at runtime: +`runtimeAssets` are always loaded at runtime, both on the server or on the client, allowing dynamic translations. ```mermaid sequenceDiagram participant Server participant assets + participant runtimeAssets participant Client Server->>assets: loadTranslation$ activate assets @@ -20,6 +21,12 @@ sequenceDiagram deactivate assets Server->>Client: SSR: no serialize data Note over Client: inlined data + Server->>runtimeAssets: loadTranslation$ + activate runtimeAssets + runtimeAssets-->>Server: data + deactivate runtimeAssets + Server->>Client: SSR: serialize data + Note over Client: runtime data ``` ## Usage @@ -104,32 +111,4 @@ _dist/build/it-IT/q-*.js_ At the end of the build, in root folder a `qwik-speak-inline.log` file is generated which contains: - Missing values -- Translations with dynamic keys -- Translations with dynamic params - -## Qwik Speak Inline Vite plugin & runtime -When there are translations with dynamic keys or params, you have to use separate files, and add them to `runtimeAssets`: - -```typescript -export const config: SpeakConfig = { - /* ... */ - assets: [ - 'app' // Translations shared by the pages - ], - runtimeAssets: [ - 'runtime' // Translations with dynamic keys or parameters - ] -}; -``` -Likewise, you can also create scoped runtime files for different pages and pass them to `Speak` components: -```tsx -export default component$(() => { - return ( - - - - ); -}); -``` -> `runtimeAssets` are serialized and sent to the client, and loaded when required - +- Translations with dynamic keys or params diff --git a/docs/lazy-loading.md b/docs/lazy-loading.md new file mode 100644 index 0000000..9500c98 --- /dev/null +++ b/docs/lazy-loading.md @@ -0,0 +1,43 @@ +# Lazy loading translation + +If you are developing a large app, you can consider using lazy loading translation: translations that are lazy loaded only when requested (when the user navigates to a specific section or page of the app): + +```mermaid +C4Container + Container_Boundary(a, "App") { + Component(a0, "root", "useQwikSpeak", "Translations available in the whole app") + Container_Boundary(b1, "Site") { + Component(b10, "Page", "useSpeak", "Translations available in Page component") + + } + Container_Boundary(b2, "Admin") { + Component(b20, "layout", "useSpeak", "Translations available in child components") + } + } +``` + +For lazy loading of files in a specific section, you need to add `useSpeak` to the layout: +```tsx +import { useSpeak } from 'qwik-speak'; + +export default component$(() => { + useSpeak({assets:['admin'], runtimeAssets: ['runtimeAdmin']}); + + return ( + <> +
+ +
+ + ); +}); +``` +or in a specific page: +```tsx +export default component$(() => { + useSpeak({runtimeAssets: ['runtimePage']}); + + return ; +}); +``` +> Note that you must create a component for the page, because Qwik renders components in isolation, and translations are only available in child components \ No newline at end of file diff --git a/docs/quick-start.md b/docs/quick-start.md index d23dec8..5f50107 100644 --- a/docs/quick-start.md +++ b/docs/quick-start.md @@ -1,14 +1,34 @@ # Quick Start -> Step by step, let's build a sample app with Qwik Speak +> Setup an app with Qwik Speak -```shell -npm create qwik@latest +```shell npm install qwik-speak --save-dev ``` +## Vite plugin +Add [Qwik Speak Inline Vite plugin](./inline.md) in `vite.config.ts`: +```typescript +import { qwikSpeakInline } from 'qwik-speak/inline'; + +export default defineConfig(() => { + return { + plugins: [ + qwikCity(), + qwikVite(), + qwikSpeakInline({ + supportedLangs: ['en-US', 'it-IT'], + defaultLang: 'en-US', + assetsPath: 'i18n' + }), + tsconfigPaths(), + ], + }; +}); +``` + ## Configuration -Let's create `speak-config.ts` and `speak-functions.ts` files in `src`: +Let's create `speak-config.ts` and `speak-functions.ts` files in `src` folder: _src/speak-config.ts_ ```typescript @@ -20,8 +40,13 @@ export const config: SpeakConfig = { { lang: 'it-IT', currency: 'EUR', timeZone: 'Europe/Rome' }, { lang: 'en-US', currency: 'USD', timeZone: 'America/Los_Angeles' } ], + // Translations available in the whole app assets: [ - 'app' // Translations shared by the pages + 'app' + ], + // Translations with dynamic keys available in the whole app + runtimeAssets: [ + 'runtime' ] }; ``` @@ -47,168 +72,47 @@ export const translationFn: TranslationFn = { loadTranslation$: loadTranslation$ }; ``` -We have added the Speak config and the implementation of the `loadTranslation$` function to load translation files. - > `loadTranslation$` is a customizable QRL function: you can load the translation files in the way you prefer -## Adding Qwik Speak -Just wrap Qwik City provider with `QwikSpeakProvider` component in `root.tsx` and pass it the configuration and the translation functions: + +Add `useQwikSpeak` provider in `root.tsx` and pass it the configuration and the translation functions: _src/root.tsx_ ```tsx -import { QwikSpeakProvider } from 'qwik-speak'; - -import { config } from './speak-config'; -import { translationFn } from './speak-functions'; +import { useQwikSpeak } from 'qwik-speak'; +import { config } from "./speak-config"; +import { translationFn } from "./speak-functions"; export default component$(() => { - return ( - - - - - - - - - - - - - - ); -}); -``` - -Finally we add an `index.tsx` with some translation, providing optional default values for each translation: `key@@[default value]`: - -_src/routes/index.tsx_ -```tsx -import { - useTranslate, - useFormatDate, - useFormatNumber, - Speak, -} from 'qwik-speak'; - -interface TitleProps { - name: string; -} - -export const Title = component$(props => { - return (

{props.name}

) -}); - -export const Home = component$(() => { - const t = useTranslate(); - const fd = useFormatDate(); - const fn = useFormatNumber(); - - // Prefer translating inside components rather than on props - const title = t('app.title@@{{name}} demo', { name: 'Qwik Speak' }); + /** + * Init Qwik Speak + */ + useQwikSpeak({ config, translationFn }); return ( - <> - - - <h3>{t('home.dates@@Dates')}</h3> - <p>{fd(Date.now(), { dateStyle: 'full', timeStyle: 'short' })}</p> - - <h3>{t('home.numbers@@Numbers')}</h3> - <p>{fn(1000000, { style: 'currency' })}</p> - </> - ); -}); - -export default component$(() => { - return ( - /** - * Add Home translations (only available in child components) - */ - <Speak assets={['home']}> - <Home /> - </Speak> - ); -}); - -export const head: DocumentHead = { - title: 'home.head.title@@Qwik Speak', - meta: [{ name: 'description', content: 'home.head.description@@Quick start' }] -}; -``` - -## Scoped translation -We have used the `Speak` component to add scoped translations to the `Home` component: -- `Home` component will use the `home` asset, in addition to the `app` asset that comes with the configuration -- Using the asset name `home` as the root property in each key is the best practice to avoid keys in different files being overwritten - -> `Speak` component is a `Slot` component: because Qwik renders `Slot` components and direct children in isolation, translations are not immediately available in direct children, and we need to use a component for the `Home` page. It is not necessary to use more than one `Speak` component per page - -## Head metas -You may have noticed, that in `index.tsx` we have provided the meta title and description with only the keys. Since the Qwik City `DocumentHead` is out of context, we need to do the translations directly in `router-head.tsx`: - -_src/components/router-head/router-head.tsx_ -```tsx -export const RouterHead = component$(() => { - const t = useTranslate(); - - const head = useDocumentHead(); - - return ( - <> - <title>{t(head.title, { name: 'Qwik Speak' })} - - {head.meta.map((m) => ( - - ))} - + + {/* ... */} + ); }); ``` -We can also pass the `lang` attribute in the html tag: - -_src/entry.ssr.tsx_ -```typescript -import { config } from './speak-config'; - -export default function (opts: RenderToStreamOptions) { - return renderToStream(, { - manifest, - ...opts, - // Use container attributes to set attributes on the html tag - containerAttributes: { - lang: opts.serverData?.locale || config.defaultLocale.lang, - ...opts.containerAttributes, - }, - }); -} -``` - ## Resolve locale -We can resolve the locale to use in two ways: passing the `locale` parameter to the `QwikSpeakProvider` component, or assigning it to the `locale` handled by Qwik. Create `plugin.ts` in the root of the `src/routes` directory: +Create `plugin.ts` in the root of the `src/routes` directory: _src/routes/plugin.ts_ ```typescript +import type { RequestHandler } from '@builder.io/qwik-city'; import { config } from '../speak-config'; export const onRequest: RequestHandler = ({ request, locale }) => { - const cookie = request.headers?.get('cookie'); const acceptLanguage = request.headers?.get('accept-language'); let lang: string | null = null; - // Try whether the language is stored in a cookie - if (cookie) { - const result = new RegExp('(?:^|; )' + encodeURIComponent('locale') + '=([^;]*)').exec(cookie); - if (result) { - lang = JSON.parse(result[1])['lang']; - } - } + // Try to use user language - if (!lang) { - if (acceptLanguage) { - lang = acceptLanguage.split(';')[0]?.split(',')[0]; - } + if (acceptLanguage) { + lang = acceptLanguage.split(';')[0]?.split(',')[0]; } // Check supported locales @@ -218,155 +122,13 @@ export const onRequest: RequestHandler = ({ request, locale }) => { locale(lang); }; ``` -Internally, Qwik Speak will try to use the Qwik `locale`, before falling back to default locale if it is not in `supportedLocales`. +> We're on the server here, and you can get the language from `acceptLanguage`, a cookie, or a URL parameter, as you like. But is mandatory to set the Qwik locale -## Change locale -Now we want to change locale. Let's create a `ChangeLocale` component: - -_src/components/change-locale.tsx_ -```tsx -import type { SpeakLocale } from 'qwik-speak'; -import { useSpeakConfig, useTranslate } from 'qwik-speak'; - -export const ChangeLocale = component$(() => { - const t = useTranslate(); - - const config = useSpeakConfig(); - - const changeLocale$ = $((newLocale: SpeakLocale) => { - // Store locale in a cookie - document.cookie = `locale=${JSON.stringify(newLocale)};max-age=86400;path=/`; - - location.reload(); - }); - - return ( -
-

{t('app.changeLocale@@Change locale')}

- {config.supportedLocales.map(value => ( - - ))} -
- ); -}); -``` -and add the component in `header.tsx`: -```tsx -export default component$(() => { - return ( -
- -
- ); -}); -``` -In `changeLocale$` we set the locale in a cookie, before reloading the page. - -## Extraction -We can now extract the translations and generate the `assets` as json. In `package.json` add the following command to the scripts: -```json -"qwik-speak-extract": "qwik-speak-extract --supportedLangs=en-US,it-IT --assetsPath=i18n" -``` - -```shell -npm run qwik-speak-extract -``` - -The following files are generated: -``` -i18n/en-US/app.json -i18n/en-US/home.json -i18n/it-IT/app.json -i18n/it-IT/home.json -translations skipped due to dynamic keys: 2 -extracted keys: 4 -``` -`app` asset and `home` asset for each language, initialized with the default values we provided. - -_translations skipped due to dynamic keys_ are meta title and description keys, because those keys are passed as dynamic parameters. We have to add them manually in a new file that we will call `runtime`: - -_i18n/[lang]/runtime.json_ -```json -{ - "runtime": { - "home": { - "head": { - "title": "Qwik Speak", - "description": "Quick start" - } - } - } -} -``` -Update the keys in `DocumentHead` of `index.tsx`: -```tsx -export const head: DocumentHead = { - title: 'runtime.home.head.title@@Qwik Speak', - meta: [{ name: 'description', content: 'runtime.home.head.description@@Quick start' }] -}; -``` -and add `runtime` asset in Speak config: -```typescript -assets: [ - 'app' // Translations shared by the pages -], -runtimeAssets: [ - 'runtime' // Translations with dynamic keys or parameters -] -``` - -See [Qwik Speak Extract](./extract.md) for more details. - -## Translation -We can translate the `it-IT` files. - -If you have an OpenAI API key, you could use `gpt-translate-json` package: -```shell -npm install gpt-translate-json --save-dev -``` -In `package.json` add the following command to the scripts: -```json -"gpt-translate-json": "gpt-translate-json --apiKey=openai_api_key --model=gpt-3.5-turbo --maxTokens=3000 --langs=en-US,it-IT --originalLang=en-US" -``` - -```shell -npm gpt-translate-json -``` - -Run the app: -```shell -npm start -``` - -See [GPT Translate JSON](./gpt-translate-json.md) for more details. - -## Production -In production mode, `assets` are loaded only during SSR, and to get the translations on the client as well it is required to inline the translations in chucks sent to the browser. - -Add `qwikSpeakInline` Vite plugin in `vite.config.ts`: -```typescript -import { qwikSpeakInline } from 'qwik-speak/inline'; - -export default defineConfig(() => { - return { - plugins: [ - qwikCity(), - qwikVite(), - qwikSpeakInline({ - supportedLangs: ['en-US', 'it-IT'], - defaultLang: 'en-US', - assetsPath: 'i18n' - }), - tsconfigPaths(), - ], - }; -}); -``` Set the base URL for loading the chunks in the browser in `entry.ssr.tsx` file: ```typescript import { isDev } from '@builder.io/qwik/build'; +import type { RenderOptions } from "@builder.io/qwik/server"; +import { config } from './speak-config'; /** * Determine the base URL to use for loading the chunks in the browser. @@ -387,22 +149,15 @@ export default function (opts: RenderToStreamOptions) { ...opts, // Determine the base URL for the client code base: extractBase, + // Use container attributes to set attributes on the html tag + containerAttributes: { + lang: opts.serverData?.locale || config.defaultLocale.lang, + ...opts.containerAttributes, + }, }); } ``` -Build the production app in preview mode: -```shell -npm run preview -``` -Inspect the `qwik-speak-inline.log` file in root folder: - -``` -client: root.tsx -dynamic key: t(head.title) - Make sure the keys are in 'runtimeAssets' -dynamic key: t(m.content) - Make sure the keys are in 'runtimeAssets' -``` -It contains the non-inlined dynamic keys that we added in the `runtime.json` file. - -> The app will have the same behavior as you saw in dev mode, but now the translations are inlined as you can verify by inspecting the production files, reducing resource usage at runtime -See [Qwik Speak Inline Vite plugin](./inline.md) for more details. +## Tutorials +- [Tutorial: localized routing with the language](./tutorial-routing.md) +- [Tutorial: translated routing with url rewriting](./tutorial-routing-rewrite.md) diff --git a/docs/testing.md b/docs/testing.md index ae97f72..99380aa 100644 --- a/docs/testing.md +++ b/docs/testing.md @@ -2,44 +2,23 @@ > Unit test a Qwik component using Qwik Speak -To unit test a component which uses `qwik-speak`, you need to wrap it with `QwikSpeakProvider` component, so that it can pass the `SpeakContext` to the test component and its children. +To unit test a component which uses `qwik-speak`, you need to wrap it with `QwikSpeakMockProvider` component, so that it can pass the `SpeakContext` to the test component and its children. -Given the `config` object and a component to test like in [Quick Start](./quick-start.md): +Given the `config` object and a component to test like: _src/routes/index.tsx_ ```tsx -import { - useTranslate, - useFormatDate, - useFormatNumber, - Speak, -} from 'qwik-speak'; +import { inlineTranslate, useFormatDate, useFormatNumber } from 'qwik-speak'; -export const Home = component$(() => { - const t = useTranslate(); - const fd = useFormatDate(); - const fn = useFormatNumber(); +export default component$(() => { + const t = inlineTranslate(); return ( <>

{t('app.title@@{{name}} demo', { name: 'Qwik Speak' })}

- -

{t('home.dates@@Dates')}

-

{fd(Date.now(), { dateStyle: 'full', timeStyle: 'short' })}

- -

{t('home.numbers@@Numbers')}

-

{fn(1000000, { style: 'currency' })}

); }); - -export default component$(() => { - return ( - - - - ); -}); ``` We'll have the following unit test (using _Vitest_): @@ -52,9 +31,9 @@ test(`[Home Component]: Should render the component`, async () => { const { screen, render } = await createDOM(); await render( - + - + ); expect(screen.outerHTML).toContain('Qwik Speak demo'); diff --git a/docs/translate.md b/docs/translate.md index bd47a02..44ebbc0 100644 --- a/docs/translate.md +++ b/docs/translate.md @@ -1,12 +1,12 @@ # Translate -> The return functions of `useTranslate`, `inlineTranslate` and `usePlural` are parsed and replaced with translated texts at compile time. For this reason, they expect _values_ or _identifiers_ as parameters, and no JavaScript _operators_ +> The return functions of `inlineTranslate` and `inlinePlural` are parsed and replaced with translated texts in chunks sent to the browser at compile time -## useTranslate -`useTranslate` returns a functions to get the translation using key-value pairs: +## inlineTranslate +`inlineTranslate` returns a functions to get the translation using key-value pairs: ```tsx -const t = useTranslate(); +const t = inlineTranslate(); -t('home.title@@Qwik Speak') +t('title@@Qwik Speak') ``` Value after `@@` is the optional default value: ```tsx @@ -16,7 +16,7 @@ Value after `@@` is the optional default value: ### Params interpolation `t` function accept params as well: ```tsx -t('home.greeting@@Hi! I am {{name}}', { name: 'Qwik Speak' }) +t('greeting@@Hi! I am {{name}}', { name: 'Qwik Speak' }) ``` `name` param is replaced at runtime or during the inlining: ```text @@ -37,16 +37,14 @@ and returns an array of translated values: `t` function can get arrays and objects directly from files: ```json { - "home": { - "array": [ - "one", - "two", - "three" - ], - "obj": { - "one": "one", - "two": "two" - } + "array": [ + "one", + "two", + "three" + ], + "obj": { + "one": "one", + "two": "two" } } ``` @@ -54,115 +52,54 @@ just pass to the function the type parameter: ```tsx import type { Translation } from 'qwik-speak'; -t('home.array') -t('home.obj') +t('array') +t('obj') ``` You can also access by array position: ```tsx -t('home.array.2@@three') +t('array.2@@three') ``` Finally, it is possible to set arrays and objects passing a _valid stringified_ default value: ```tsx -t('home.array@@["one","two","three"]') -t('home.obj@@{"one":"one","two":"two"}') +t('array@@["one","two","three"]') +t('obj@@{"one":"one","two":"two"}') ``` ### Html in translations You can have Html in translations, like: ```json { - "home": { - "text": "Internationalization (i18n) library to translate texts, dates and numbers in Qwik apps" - } + "description": "Internationalization (i18n) library to translate texts, dates and numbers in Qwik apps" } ``` but you have to use `dangerouslySetInnerHTML`: ```tsx -

+

``` > On the client the text is _inlined_ during build, so there are no XSS risks -## component$ props -> A component can wake up independently from the parent component. If the component wakes up, it needs to be able to know its props - -Prefer translating inside components rather than on props: - -```tsx -export const Title = component$((props) => { - return (

{props.name}

) -}); - -export const Home = component$(() => { - const t = useTranslate(); - - const name = t('app.title'); - return ( - - ); -}); -``` -or -```tsx -export const Title = component$<TitleProps>((props) => { - const t = useTranslate(); - - return (<h1>{t(props.name)}</h1>) -}); - -export const Home = component$(() => { - return ( - <Title name='app.title' /> - ); -}); -``` -In the latter case, `app.title` will have to be placed in the `runtimeAssets`, as a dynamic key is passed to the `t` function. - -## inlineTranslate -`inlineTranslate` function has the same behavior as the function returned by `useTranslate`, but can be used outside the `component$`, for example in _Inline components_, passing the Speak context as second argument: +## inlinePlural +`inlinePlural` returns a functions that uses [Intl.PluralRules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/PluralRules) API: ```tsx -import { inlineTranslate, useSpeakContext } from 'qwik-speak'; +const p = inlinePlural(); -export const TitleComponent = (props: { ctx: SpeakState }) => { - return <h1>{inlineTranslate('home.title@@Qwik Speak', props.ctx)}</h1>; -}; - -export const Home = component$(() => { - const ctx = useSpeakContext(); - - return ( - <div> - <TitleComponent ctx={ctx} /> - </div> - ); -}); +p(1, 'devs') ``` - -## usePlural -`usePlural` returns a functions that uses [Intl.PluralRules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/PluralRules) API: -```tsx -const p = usePlural(); - -p(1, 'home.devs') -``` -When you run the extraction tool, it creates a translation file with the Intl API plural rules for each language: +When you run the extraction tool, it creates the Intl API plural rules for each language: ```json { - "home": { - "devs": { - "one": "", - "other": "" - } + "devs": { + "one": "", + "other": "" } } ``` -There is no default value for `usePlural` function, so you must add the translation in each language, keeping in mind that the counter is optionally interpolated with the `value` parameter: +There is no default value for `inlinePlural` function, so you must add the translation in each language, keeping in mind that the counter is optionally interpolated with the `value` parameter: ```json { - "home": { - "devs": { - "one": "{{ value }} software developer", - "other": "{{ value }} software developers" - } + "devs": { + "one": "{{ value }} software developer", + "other": "{{ value }} software developers" } } ``` @@ -171,6 +108,54 @@ It is rendered as: 1 software developer ``` +## Runtime translation +When you use a translation like this: +```tsx +const key = 'dynamic'; + +t(key) +``` +you are using a dynamic translation. It means that it is not possible to evaluate the translation at compile time but only at runtime based on the value that the key takes on. + +To instruct Qwik Speak to use dynamic translations, create a file with the values that these translations can take: + +_i18n/[lang]/runtime.json_ +```json +{ + "dynamic": "I'm a dynamic value" +} +``` +and add the `runtime` file to `runtimeAssets` in configuration or `useSpeak` provider. + +## Server translation +`inlineTranslate` and `inlinePlural` work in `component$`, _Inline components_, QRL and functions if called by the components, but they might not work in functions invoked on the server, such as `routeLoader$` and _endpoints_. + +Functions like `routeLoader$` live on the server, which knows nothing about the context of the app, and depending on the case they can be invoked before the app runs. To translate on the server you need: +- make sure translations are available +- let the server know the current language of the user + +`server$` function can satisfy both conditions, since the function is executed only when invoked, and accepts parameters: + +```tsx +export const serverFn = server$(function (lang: string) { + const t = inlineTranslate(); + + return t('title', { name: 'Qwik Speak' }, lang); +}); + +export default component$(() => { + const locale = useSpeakLocale(); + const s = useSignal(''); + + useTask$(async () => { + s.value = await serverFn(locale.lang) + }); + + return (<p>{s.value}</p>); +}); +``` +You can also extract the language directly into the function, through the request (cookies, params), instead of passing it as a parameter. + # Localize ## useFormatDate `useFormatDate` returns a functions that uses [Intl.DateTimeFormat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat) API to format dates: @@ -251,13 +236,11 @@ American English # Multilingual Each of the translation and localization functions accepts a different language other than the current one as its last argument: ```tsx -const t = useTranslate(); +const t = inlineTranslate(); -t('home.title@@Qwik Speak', undefined, 'it-IT') +t('title@@Qwik Speak', undefined, 'it-IT') ``` -For the translation to occur in the language passed as an argument, you need to pass the additional language to `QwikSpeakProvider` or `Speak` components: +For the translation to occur in the language passed as an argument, you need to set the additional language to `useQwikSpeak` or `useSpeak` providers: ```tsx -<Speak assets={['home']} langs={['it-IT']}> - <Home /> -</Speak> +useQwikSpeak({ config, translationFn, langs: ['it-IT'] }); ``` diff --git a/docs/tutorial-routing-rewrite.md b/docs/tutorial-routing-rewrite.md index 8b3cbdf..0576f30 100644 --- a/docs/tutorial-routing-rewrite.md +++ b/docs/tutorial-routing-rewrite.md @@ -1,12 +1,11 @@ -# Tutorial: localized routing with url rewriting +# Tutorial: translated routing with url rewriting > Step by step, let's build a sample app with Qwik Speak and translated paths using Qwik City features -```shell -npm create qwik@latest -npm install qwik-speak --save-dev -``` +## Setup +See [Quick Start](./quick-start.md) +## Routing Let's assume that we want to create a navigation of this type: - default language (en-US): routes not localized `http://127.0.0.1:4173/` - other languages (it-IT): localized routes `http://127.0.0.1:4173/it-IT/` @@ -18,8 +17,7 @@ Or: But we DON'T want to have this url instead: - other languages (it-IT): localized routes `http://127.0.0.1:4173/it-IT/page` -## Configuration -Let's create `speak-routes.ts` file in `src`: +Now let's handle it. Create `speak-routes.ts` file in `src`: _src/speak-routes.ts_ ```typescript @@ -29,32 +27,43 @@ import type { RewriteRouteOption } from 'qwik-speak'; * Translation paths */ export const rewriteRoutes: RewriteRouteOption[] = [ + // No prefix for default locale + // { + // paths: { + // 'page': 'page' + // } + // }, { prefix: 'it-IT', paths: { - 'page': 'pagina' + 'page': 'pagina' } } -] +]; ``` -and update `qwikCity` Vite plugin in `vite.config.ts`: +Add `rewriteRoutes` to `qwikCity` Vite plugin in `vite.config.ts`: + ```typescript +import { qwikSpeakInline } from 'qwik-speak/inline'; + import { rewriteRoutes } from './src/speak-routes'; export default defineConfig(() => { return { plugins: [ - qwikCity( - { rewriteRoutes } - ), + qwikCity({ rewriteRoutes }), qwikVite(), + qwikSpeakInline({ + supportedLangs: ['en-US', 'it-IT'], + defaultLang: 'en-US', + assetsPath: 'i18n' + }), tsconfigPaths(), ], }; }); ``` - -Now create `speak-config.ts` and `speak-functions.ts` files in `src`: +Add `rewriteRoutes` to `speak-config.ts` in `src`: _src/speak-config.ts_ ```typescript @@ -69,39 +78,17 @@ export const config: SpeakConfig = { { lang: 'it-IT', currency: 'EUR', timeZone: 'Europe/Rome' }, { lang: 'en-US', currency: 'USD', timeZone: 'America/Los_Angeles' } ], + // Translations available in the whole app assets: [ - 'app' // Translations shared by the pages + 'app' + ], + // Translations with dynamic keys available in the whole app + runtimeAssets: [ + 'runtime' ] }; ``` -_src/speak-functions.ts_ -```typescript -import { server$ } from '@builder.io/qwik-city'; -import type { LoadTranslationFn, Translation, TranslationFn } from 'qwik-speak'; - -/** - * Translation files are lazy-loaded via dynamic import and will be split into separate chunks during build. - * Keys must be valid variable names - */ -const translationData = import.meta.glob<Translation>('/i18n/**/*.json'); - -/** - * Using server$, translation data is always accessed on the server - */ -const loadTranslation$: LoadTranslationFn = server$(async (lang: string, asset: string) => - await translationData[`/i18n/${lang}/${asset}.json`]?.() -); - -export const translationFn: TranslationFn = { - loadTranslation$: loadTranslation$ -}; -``` -We have added the Speak config and the implementation of the `loadTranslation$` function to load translation files. - -> `loadTranslation$` is a customizable QRL function: you can load the translation files in the way you prefer - -## Routing -Now let's handle the routing. Create `plugin.ts` in the root of the `src/routes` directory: +Update `plugin.ts` in the root of the `src/routes` directory: _src/routes/plugin.ts_ ```typescript @@ -122,230 +109,133 @@ export const onRequest: RequestHandler = ({ url, locale }) => { locale(lang || config.defaultLocale.lang); }; ``` -We assign the value of the `lang` parameter (from the url prefix) to Qwik `locale`. This way it will be immediately available to the library. -## Adding Qwik Speak -Just put `QwikSpeakProvider` inside Qwik City provider component in `root.tsx` and pass it the configuration and the translation functions: +## Usage +Add `index.tsx` with some translation, providing optional default values for each translation: `key@@[default value]`: -_src/root.tsx_ +_src/routes//index.tsx_ ```tsx -import { QwikSpeakProvider } from 'qwik-speak'; - -import { config } from './speak-config'; -import { translationFn } from './speak-functions'; +import { inlineTranslate, useFormatDate, useFormatNumber } from 'qwik-speak'; export default component$(() => { - return ( - <QwikCityProvider> - <QwikSpeakProvider config={config} translationFn={translationFn}> - <head> - <meta charSet="utf-8" /> - <link rel="manifest" href="/manifest.json" /> - <RouterHead /> - <ServiceWorkerRegister /> - </head> - <body lang="en"> - <RouterOutlet /> - </body> - </QwikSpeakProvider> - </QwikCityProvider> - ); -}); -``` + const t = inlineTranslate(); -Now we add an `index.tsx` with some translation, providing optional default values for each translation: `key@@[default value]`: - -_src/routes/index.tsx_ -```tsx -import { - useTranslate, - useFormatDate, - useFormatNumber, - Speak, -} from 'qwik-speak'; - -interface TitleProps { - name: string; -} - -export const Title = component$<TitleProps>(props => { - return (<h1>{props.name}</h1>) -}); - -export const Home = component$(() => { - const t = useTranslate(); const fd = useFormatDate(); const fn = useFormatNumber(); - // Prefer translating inside components rather than on props - const title = t('app.title@@{{name}} demo', { name: 'Qwik Speak' }); - return ( <> - <Title name={title} /> + <h1>{t('app.title@@{{name}} demo', { name: 'Qwik Speak' })}</h1> - <h3>{t('home.dates@@Dates')}</h3> + <h3>{t('dates@@Dates')}</h3> <p>{fd(Date.now(), { dateStyle: 'full', timeStyle: 'short' })}</p> - <h3>{t('home.numbers@@Numbers')}</h3> + <h3>{t('numbers@@Numbers')}</h3> <p>{fn(1000000, { style: 'currency' })}</p> </> ); }); -export default component$(() => { - return ( - /** - * Add Home translations (only available in child components) - */ - <Speak assets={['home']}> - <Home /> - </Speak> - ); -}); +export const head: DocumentHead = () => { + const t = inlineTranslate(); -export const head: DocumentHead = { - title: 'home.head.title@@Qwik Speak', - meta: [{ name: 'description', content: 'home.head.description@@Qwik Speak with localized routing' }] + return { + title: t('app.head.home.title@@{{name}}', { name: 'Qwik Speak' }), + meta: [{ name: 'description', content: t('app.head.home.description@@Localized routing') }], + }; }; ``` +Add a `page/index.tsx` to try the router: -Finally we add a `page/index.tsx` to try the router: - -_src/routes/page/index.tsx_ +_src/routes//page/index.tsx_ ```tsx -import { component$ } from '@builder.io/qwik'; -import { useTranslate } from 'qwik-speak'; +import { inlineTranslate } from 'qwik-speak'; export default component$(() => { - const t = useTranslate(); + const t = inlineTranslate(); - return ( - <> - <h1>{t('app.title')}</h1> - <h2>{t('app.subtitle')}</h2> - </> - ); -}); -``` - -## Scoped translation -We have used the `Speak` component to add scoped translations to the `Home` component: -- `Home` component will use the `home` asset, in addition to the `app` asset that comes with the configuration -- Using the asset name `home` as the root property in each key is the best practice to avoid keys in different files being overwritten - -> `Speak` component is a `Slot` component: because Qwik renders `Slot` components and direct children in isolation, translations are not immediately available in direct children, and we need to use a component for the `Home` page. It is not necessary to use more than one `Speak` component per page - -## Head metas -You may have noticed, that in `index.tsx` we have provided the meta title and description with only the keys. Since the Qwik City `DocumentHead` is out of context, we need to do the translations directly in `router-head.tsx`: - -_src/components/router-head/router-head.tsx_ -```tsx -export const RouterHead = component$(() => { - const t = useTranslate(); - - const head = useDocumentHead(); + const key = 'dynamic'; return ( <> - <title>{t(head.title, { name: 'Qwik Speak' })} +

{t('app.title', { name: 'Qwik Speak' })}

- {head.meta.map((m) => ( - - ))} +

{t(`runtime.${key}`)}

); }); ``` +> Note that it is not necessary to provide the default value in the key once again: it is sufficient and not mandatory to provide it once in the app -We can also pass the `lang` attribute in the html tag: - -_src/entry.ssr.tsx_ -```typescript -import { config } from './speak-config'; - -export default function (opts: RenderToStreamOptions) { - return renderToStream(, { - manifest, - ...opts, - // Use container attributes to set attributes on the html tag - containerAttributes: { - lang: opts.serverData?.locale || config.defaultLocale.lang, - ...opts.containerAttributes, - }, - }); -} -``` +> Note the use of a dynamic key (which will therefore only be available at runtime), which we assign to the `runtime` scope ## Change locale Now we want to change locale. Let's create a `ChangeLocale` component: -_src/components/change-locale.tsx_ +_src/components/change-locale/change-locale.tsx_ ```tsx -import type { SpeakLocale } from 'qwik-speak'; -import { useSpeakLocale, useSpeakConfig, useDisplayName, useTranslate, useTranslatePath } from 'qwik-speak'; +import { useLocation } from '@builder.io/qwik-city'; +import { useSpeakLocale, useSpeakConfig, useDisplayName, inlineTranslate, translatePath } from 'qwik-speak'; export const ChangeLocale = component$(() => { - const t = useTranslate(); - const tp = useTranslatePath(); - const dn = useDisplayName(); + const t = inlineTranslate(); + + const url = useLocation().url; - const loc = useLocation() const locale = useSpeakLocale(); const config = useSpeakConfig(); + const dn = useDisplayName(); - // Replace the locale and navigate to the new URL - const getLocalePath = (newLocale: SpeakLocale) => { - const url = new URL(loc.url) - url.pathname = tp(url.pathname, newLocale.lang) - return url.toString(); - }; + const getPath = translatePath(); return ( -
+ <>

{t('app.changeLocale@@Change locale')}

{config.supportedLocales.map(value => ( - + {dn(value.lang, { type: 'language' })} ))} -
+ ); }); ``` -and add the component in `header.tsx`: +> We use the `` tag tag because it is mandatory to reload the page when changing the language + +Add the `ChangeLocale` component in `header.tsx` along with localized navigation links: ```tsx import { Link, useLocation } from '@builder.io/qwik-city'; -import { useTranslate, useTranslatePath } from 'qwik-speak'; -import { ChangeLocale } from '../change-locale/change-locale'; +import { inlineTranslate, translatePath } from 'qwik-speak'; + +import { ChangeLocale } from '../../change-locale/change-locale'; export default component$(() => { - const t = useTranslate(); - const tp = useTranslatePath(); + const t = inlineTranslate(); - const { url } = useLocation(); + const pathname = useLocation().url.pathname; + + const getPath = translatePath(); + const [homePath, pagePath] = getPath(['/', '/page/']); - const [ - homePath, - pagePath, - ] = tp(['/', '/page/']) - return ( -
-
    -
  • - - {t('app.nav.home@@Home')} - -
  • -
  • - - {t('app.nav.page@@Page')} - -
  • -
+ <> +
+
    +
  • + + {t('app.nav.home@@Home')} + +
  • +
  • + + {t('app.nav.page@@Page')} + +
  • +
+
+ -
+ ); }); ``` @@ -363,141 +253,35 @@ npm run qwik-speak-extract The following files are generated: ``` i18n/en-US/app.json -i18n/en-US/home.json i18n/it-IT/app.json -i18n/it-IT/home.json -translations skipped due to dynamic keys: 2 -extracted keys: 4 +translations skipped due to dynamic keys: 1 +extracted keys: 9 ``` -`app` asset and `home` asset for each language, initialized with the default values we provided. +`app` asset for each language, initialized with the default values we provided. -_translations skipped due to dynamic keys_ are meta title and description keys, because those keys are passed as dynamic parameters. We have to add them manually in a new file that we will call `runtime`: +_translations skipped due to dynamic keys_ is `runtime.${key}`. During configuration, we provided in `runtimeAssets` a `runtime` file, which we can now create and populate with dynamic keys: _i18n/[lang]/runtime.json_ ```json { "runtime": { - "home": { - "head": { - "title": "Qwik Speak", - "description": "Qwik Speak with localized routing" - } - } + "dynamic": "I'm a dynamic value" } } ``` -Update the keys in `DocumentHead` of `index.tsx`: -```tsx -export const head: DocumentHead = { - title: 'runtime.home.head.title@@Qwik Speak', - meta: [{ name: 'description', content: 'runtime.home.head.description@@Qwik Speak with localized routing' }] -}; -``` -and add `runtime` asset in Speak config: -```typescript -assets: [ - 'app' // Translations shared by the pages -], -runtimeAssets: [ - 'runtime' // Translations with dynamic keys or parameters -] -``` - See [Qwik Speak Extract](./extract.md) for more details. -## Translation -We can translate the `it-IT` files. - -If you have an OpenAI API key, you could use `gpt-translate-json` package: -```shell -npm install gpt-translate-json --save-dev -``` -In `package.json` add the following command to the scripts: -```json -"gpt-translate-json": "gpt-translate-json --apiKey=openai_api_key --model=gpt-3.5-turbo --maxTokens=3000 --langs=en-US,it-IT --originalLang=en-US" -``` +## Development +We can translate the `it-IT` files and start the app: -```shell -npm gpt-translate-json -``` - -Run the app: ```shell npm start ``` -See [GPT Translate JSON](./gpt-translate-json.md) for more details. - ## Production -In production mode, `assets` are loaded only during SSR, and to get the translations on the client as well it is required to inline the translations in chucks sent to the browser. - -Add `qwikSpeakInline` Vite plugin in `vite.config.ts`: -```typescript -import { qwikSpeakInline } from 'qwik-speak/inline'; - -import { rewriteRoutes } from './src/speak-routes'; - -export default defineConfig(() => { - return { - plugins: [ - qwikCity( - { rewriteRoutes } - ), - qwikVite(), - qwikSpeakInline({ - supportedLangs: ['en-US', 'it-IT'], - defaultLang: 'en-US', - assetsPath: 'i18n' - }), - tsconfigPaths(), - ], - }; -}); -``` -Set the base URL for loading the chunks in the browser in `entry.ssr.tsx` file: -```typescript -import { isDev } from '@builder.io/qwik/build'; - -/** - * Determine the base URL to use for loading the chunks in the browser. - * The value set through Qwik 'locale()' in 'plugin.ts' is saved by Qwik in 'serverData.locale' directly. - * Make sure the locale is among the 'supportedLocales' - */ -export function extractBase({ serverData }: RenderOptions): string { - if (!isDev && serverData?.locale) { - return '/build/' + serverData.locale; - } else { - return '/build'; - } -} - -export default function (opts: RenderToStreamOptions) { - return renderToStream(, { - manifest, - ...opts, - // Determine the base URL for the client code - base: extractBase, - // Use container attributes to set attributes on the html tag - containerAttributes: { - lang: opts.serverData?.locale || config.defaultLocale.lang, - ...opts.containerAttributes, - }, - }); -} -``` Build the production app in preview mode: ```shell npm run preview ``` -Inspect the `qwik-speak-inline.log` file in root folder: - -``` -client: root.tsx -dynamic key: t(head.title) - Make sure the keys are in 'runtimeAssets' -dynamic key: t(m.content) - Make sure the keys are in 'runtimeAssets' -``` -It contains the non-inlined dynamic keys that we added in the `runtime.json` file. - -> The app will have the same behavior as you saw in dev mode, but now the translations are inlined as you can verify by inspecting the production files, reducing resource usage at runtime -See [Qwik Speak Inline Vite plugin](./inline.md) for more details. +and inspect the `qwik-speak-inline.log` file in root folder to see warnings for missing values or dynamic keys. diff --git a/docs/tutorial-routing.md b/docs/tutorial-routing.md index 6886e69..857375c 100644 --- a/docs/tutorial-routing.md +++ b/docs/tutorial-routing.md @@ -1,55 +1,9 @@ -# Tutorial: localized routing with prefix only +# Tutorial: localized routing with the language > Step by step, let's build a sample app with Qwik Speak and a localized router using Qwik City features -```shell -npm create qwik@latest -npm install qwik-speak --save-dev -``` - -## Configuration -Let's create `speak-config.ts` and `speak-functions.ts` files in `src`: - -_src/speak-config.ts_ -```typescript -import type { SpeakConfig } from 'qwik-speak'; - -export const config: SpeakConfig = { - defaultLocale: { lang: 'en-US', currency: 'USD', timeZone: 'America/Los_Angeles' }, - supportedLocales: [ - { lang: 'it-IT', currency: 'EUR', timeZone: 'Europe/Rome' }, - { lang: 'en-US', currency: 'USD', timeZone: 'America/Los_Angeles' } - ], - assets: [ - 'app' // Translations shared by the pages - ] -}; -``` -_src/speak-functions.ts_ -```typescript -import { server$ } from '@builder.io/qwik-city'; -import type { LoadTranslationFn, Translation, TranslationFn } from 'qwik-speak'; - -/** - * Translation files are lazy-loaded via dynamic import and will be split into separate chunks during build. - * Keys must be valid variable names - */ -const translationData = import.meta.glob('/i18n/**/*.json'); - -/** - * Using server$, translation data is always accessed on the server - */ -const loadTranslation$: LoadTranslationFn = server$(async (lang: string, asset: string) => - await translationData[`/i18n/${lang}/${asset}.json`]?.() -); - -export const translationFn: TranslationFn = { - loadTranslation$: loadTranslation$ -}; -``` -We have added the Speak config and the implementation of the `loadTranslation$` function to load translation files. - -> `loadTranslation$` is a customizable QRL function: you can load the translation files in the way you prefer +## Setup +See [Quick Start](./quick-start.md) ## Routing Let's assume that we want to create a navigation of this type: @@ -65,216 +19,161 @@ src/routes/ layout.tsx ``` -Now let's handle it. Create `plugin.ts` in the root of the `src/routes` directory: +Now let's handle it. Update `plugin.ts` in the root of the `src/routes` directory: _src/routes/plugin.ts_ ```typescript -import { config } from '../speak-config'; +import type { RequestHandler } from '@builder.io/qwik-city'; +import { validateLocale } from 'qwik-speak'; -export const onRequest: RequestHandler = ({ params, locale }) => { - // Check supported locales - const supportedLocale = config.supportedLocales.find(value => value.lang === params.lang) +import { config } from '../speak-config'; - // Check for 404 error page - const lang = supportedLocale - ? supportedLocale.lang - : !params.lang && config.defaultLocale.lang +export const onRequest: RequestHandler = ({ params, locale, error }) => { + let lang: string | undefined = undefined; - if(!lang) throw error(404, 'Page not found'); + if (params.lang && validateLocale(params.lang)) { + // Check supported locales + lang = config.supportedLocales.find(value => value.lang === params.lang)?.lang; + // 404 error page + if (!lang) throw error(404, 'Page not found'); + } else { + lang = config.defaultLocale.lang; + } // Set Qwik locale locale(lang); }; ``` -We assign the value of the `lang` parameter to Qwik `locale`. This way it will be immediately available to the library. - -## Adding Qwik Speak -Just wrap Qwik City provider with `QwikSpeakProvider` component in `root.tsx` and pass it the configuration and the translation functions: - -_src/root.tsx_ -```tsx -import { QwikSpeakProvider } from 'qwik-speak'; -import { config } from './speak-config'; -import { translationFn } from './speak-functions'; - -export default component$(() => { - return ( - - - - - - - - - - - - - - ); -}); -``` - -Finally we add an `index.tsx` with some translation, providing optional default values for each translation: `key@@[default value]`: +## Usage +Add `index.tsx` with some translation, providing optional default values for each translation: `key@@[default value]`: _src/routes/[...lang]/index.tsx_ ```tsx -import { - useTranslate, - useFormatDate, - useFormatNumber, - Speak, -} from 'qwik-speak'; - -interface TitleProps { - name: string; -} +import { inlineTranslate, useFormatDate, useFormatNumber } from 'qwik-speak'; -export const Title = component$(props => { - return (

{props.name}

) -}); +export default component$(() => { + const t = inlineTranslate(); -export const Home = component$(() => { - const t = useTranslate(); const fd = useFormatDate(); const fn = useFormatNumber(); - // Prefer translating inside components rather than on props - const title = t('app.title@@{{name}} demo', { name: 'Qwik Speak' }); - return ( <> - + <h1>{t('app.title@@{{name}} demo', { name: 'Qwik Speak' })}</h1> - <h3>{t('home.dates@@Dates')}</h3> + <h3>{t('dates@@Dates')}</h3> <p>{fd(Date.now(), { dateStyle: 'full', timeStyle: 'short' })}</p> - <h3>{t('home.numbers@@Numbers')}</h3> + <h3>{t('numbers@@Numbers')}</h3> <p>{fn(1000000, { style: 'currency' })}</p> </> ); }); -export default component$(() => { - return ( - /** - * Add Home translations (only available in child components) - */ - <Speak assets={['home']}> - <Home /> - </Speak> - ); -}); +export const head: DocumentHead = () => { + const t = inlineTranslate(); -export const head: DocumentHead = { - title: 'home.head.title@@Qwik Speak', - meta: [{ name: 'description', content: 'home.head.description@@Qwik Speak with localized routing' }] + return { + title: t('app.head.home.title@@{{name}}', { name: 'Qwik Speak' }), + meta: [{ name: 'description', content: t('app.head.home.description@@Localized routing') }], + }; }; ``` +Add a `page/index.tsx` to try the router: -## Scoped translation -We have used the `Speak` component to add scoped translations to the `Home` component: -- `Home` component will use the `home` asset, in addition to the `app` asset that comes with the configuration -- Using the asset name `home` as the root property in each key is the best practice to avoid keys in different files being overwritten - -> `Speak` component is a `Slot` component: because Qwik renders `Slot` components and direct children in isolation, translations are not immediately available in direct children, and we need to use a component for the `Home` page. It is not necessary to use more than one `Speak` component per page - -## Head metas -You may have noticed, that in `index.tsx` we have provided the meta title and description with only the keys. Since the Qwik City `DocumentHead` is out of context, we need to do the translations directly in `router-head.tsx`: - -_src/components/router-head/router-head.tsx_ +_src/routes/[...lang]/page/index.tsx_ ```tsx -export const RouterHead = component$(() => { - const t = useTranslate(); +import { inlineTranslate } from 'qwik-speak'; + +export default component$(() => { + const t = inlineTranslate(); - const head = useDocumentHead(); + const key = 'dynamic'; return ( <> - <title>{t(head.title, { name: 'Qwik Speak' })} +

{t('app.title', { name: 'Qwik Speak' })}

- {head.meta.map((m) => ( - - ))} +

{t(`runtime.${key}`)}

); }); ``` +> Note that it is not necessary to provide the default value in the key once again: it is sufficient and not mandatory to provide it once in the app -We can also pass the `lang` attribute in the html tag: - -_src/entry.ssr.tsx_ -```typescript -import { config } from './speak-config'; - -export default function (opts: RenderToStreamOptions) { - return renderToStream(, { - manifest, - ...opts, - // Use container attributes to set attributes on the html tag - containerAttributes: { - lang: opts.serverData?.locale || config.defaultLocale.lang, - ...opts.containerAttributes, - }, - }); -} -``` +> Note the use of a dynamic key (which will therefore only be available at runtime), which we assign to the `runtime` scope ## Change locale Now we want to change locale. Let's create a `ChangeLocale` component: -_src/components/change-locale.tsx_ +_src/components/change-locale/change-locale.tsx_ ```tsx -import type { SpeakLocale } from 'qwik-speak'; -import { useSpeakConfig, useTranslate } from 'qwik-speak'; +import { useLocation } from '@builder.io/qwik-city'; +import { useSpeakLocale, useSpeakConfig, useDisplayName, inlineTranslate, localizePath } from 'qwik-speak'; export const ChangeLocale = component$(() => { - const t = useTranslate(); + const t = inlineTranslate(); - const loc = useLocation(); + const url = useLocation().url; + + const locale = useSpeakLocale(); const config = useSpeakConfig(); + const dn = useDisplayName(); - // Replace the locale and navigate to the new URL - const navigateByLocale$ = $((newLocale: SpeakLocale) => { - const url = new URL(location.href); - if (loc.params.lang) { - if (newLocale.lang !== config.defaultLocale.lang) { - url.pathname = url.pathname.replace(loc.params.lang, newLocale.lang); - } else { - url.pathname = url.pathname.replace(new RegExp(`(/${loc.params.lang}/)|(/${loc.params.lang}$)`), '/'); - } - } else if (newLocale.lang !== config.defaultLocale.lang) { - url.pathname = `/${newLocale.lang}${url.pathname}`; - } - - location.href = url.toString(); - }); + const getPath = localizePath(); return ( -
+ ); }); ``` -and add the component in `header.tsx`: +> We use the `` tag tag because it is mandatory to reload the page when changing the language + +Add the `ChangeLocale` component in `header.tsx` along with localized navigation links: ```tsx +import { Link, useLocation } from '@builder.io/qwik-city'; +import { inlineTranslate, localizePath } from 'qwik-speak'; + +import { ChangeLocale } from '../../change-locale/change-locale'; + export default component$(() => { + const t = inlineTranslate(); + + const pathname = useLocation().url.pathname; + + const getPath = localizePath(); + const [homePath, pagePath] = getPath(['/', '/page/']); + return ( -
+ <> +
+
    +
  • + + {t('app.nav.home@@Home')} + +
  • +
  • + + {t('app.nav.page@@Page')} + +
  • +
+
+ -
+ ); }); ``` -In `navigateByLocale$` we replace the language in the URL, before navigating to the new localized URL. ## Extraction We can now extract the translations and generate the `assets` as json. In `package.json` add the following command to the scripts: @@ -289,137 +188,35 @@ npm run qwik-speak-extract The following files are generated: ``` i18n/en-US/app.json -i18n/en-US/home.json i18n/it-IT/app.json -i18n/it-IT/home.json -translations skipped due to dynamic keys: 2 -extracted keys: 4 +translations skipped due to dynamic keys: 1 +extracted keys: 9 ``` -`app` asset and `home` asset for each language, initialized with the default values we provided. +`app` asset for each language, initialized with the default values we provided. -_translations skipped due to dynamic keys_ are meta title and description keys, because those keys are passed as dynamic parameters. We have to add them manually in a new file that we will call `runtime`: +_translations skipped due to dynamic keys_ is `runtime.${key}`. During configuration, we provided in `runtimeAssets` a `runtime` file, which we can now create and populate with dynamic keys: _i18n/[lang]/runtime.json_ ```json { "runtime": { - "home": { - "head": { - "title": "Qwik Speak", - "description": "Qwik Speak with localized routing" - } - } + "dynamic": "I'm a dynamic value" } } ``` -Update the keys in `DocumentHead` of `index.tsx`: -```tsx -export const head: DocumentHead = { - title: 'runtime.home.head.title@@Qwik Speak', - meta: [{ name: 'description', content: 'runtime.home.head.description@@Qwik Speak with localized routing' }] -}; -``` -and add `runtime` asset in Speak config: -```typescript -assets: [ - 'app' // Translations shared by the pages -], -runtimeAssets: [ - 'runtime' // Translations with dynamic keys or parameters -] -``` - See [Qwik Speak Extract](./extract.md) for more details. -## Translation -We can translate the `it-IT` files. - -If you have an OpenAI API key, you could use `gpt-translate-json` package: -```shell -npm install gpt-translate-json --save-dev -``` -In `package.json` add the following command to the scripts: -```json -"gpt-translate-json": "gpt-translate-json --apiKey=openai_api_key --model=gpt-3.5-turbo --maxTokens=3000 --langs=en-US,it-IT --originalLang=en-US" -``` +## Development +We can translate the `it-IT` files and start the app: -```shell -npm gpt-translate-json -``` - -Run the app: ```shell npm start ``` -See [GPT Translate JSON](./gpt-translate-json.md) for more details. - ## Production -In production mode, `assets` are loaded only during SSR, and to get the translations on the client as well it is required to inline the translations in chucks sent to the browser. - -Add `qwikSpeakInline` Vite plugin in `vite.config.ts`: -```typescript -import { qwikSpeakInline } from 'qwik-speak/inline'; - -export default defineConfig(() => { - return { - plugins: [ - qwikCity(), - qwikVite(), - qwikSpeakInline({ - supportedLangs: ['en-US', 'it-IT'], - defaultLang: 'en-US', - assetsPath: 'i18n' - }), - tsconfigPaths(), - ], - }; -}); -``` -Set the base URL for loading the chunks in the browser in `entry.ssr.tsx` file: -```typescript -import { isDev } from '@builder.io/qwik/build'; - -/** - * Determine the base URL to use for loading the chunks in the browser. - * The value set through Qwik 'locale()' in 'plugin.ts' is saved by Qwik in 'serverData.locale' directly. - * Make sure the locale is among the 'supportedLocales' - */ -export function extractBase({ serverData }: RenderOptions): string { - if (!isDev && serverData?.locale) { - return '/build/' + serverData.locale; - } else { - return '/build'; - } -} - -export default function (opts: RenderToStreamOptions) { - return renderToStream(, { - manifest, - ...opts, - // Determine the base URL for the client code - base: extractBase, - // Use container attributes to set attributes on the html tag - containerAttributes: { - lang: opts.serverData?.locale || config.defaultLocale.lang, - ...opts.containerAttributes, - }, - }); -} -``` Build the production app in preview mode: ```shell npm run preview ``` -Inspect the `qwik-speak-inline.log` file in root folder: - -``` -client: root.tsx -dynamic key: t(head.title) - Make sure the keys are in 'runtimeAssets' -dynamic key: t(m.content) - Make sure the keys are in 'runtimeAssets' -``` -It contains the non-inlined dynamic keys that we added in the `runtime.json` file. - -> The app will have the same behavior as you saw in dev mode, but now the translations are inlined as you can verify by inspecting the production files, reducing resource usage at runtime -See [Qwik Speak Inline Vite plugin](./inline.md) for more details. +and inspect the `qwik-speak-inline.log` file in root folder to see warnings for missing values or dynamic keys. diff --git a/i18n/.metadata/translated-langs.json b/i18n/.metadata/translated-langs.json new file mode 100644 index 0000000..c4e4706 --- /dev/null +++ b/i18n/.metadata/translated-langs.json @@ -0,0 +1,4 @@ +[ + "it-IT", + "de-DE" +] \ No newline at end of file diff --git a/i18n/.metadata/translated.json b/i18n/.metadata/translated.json new file mode 100644 index 0000000..920ff16 --- /dev/null +++ b/i18n/.metadata/translated.json @@ -0,0 +1,24 @@ +[ + "app.changeLocale", + "app.head.home.description", + "app.head.home.title", + "app.head.page.description", + "app.head.page.title", + "app.nav.home", + "app.nav.page", + "app.subtitle", + "app.title", + "anotherPage", + "dates", + "defaultValue", + "description", + "devs.one", + "devs.other", + "greeting", + "increment", + "numbers", + "params", + "plural", + "tags", + "runtime.dynamic" +] \ No newline at end of file diff --git a/i18n/de-DE/app.json b/i18n/de-DE/app.json index 3e9dee5..b2ddf43 100644 --- a/i18n/de-DE/app.json +++ b/i18n/de-DE/app.json @@ -1,11 +1,35 @@ { "app": { - "changeLocale": "Den Ort wechseln", + "changeLocale": "Ändern Sie die Gebietsschema", + "head": { + "home": { + "description": "Internationalisierung (i18n) Bibliothek zur Übersetzung von Texten, Daten und Zahlen in Qwik Apps", + "title": "{{name}}" + }, + "page": { + "description": "Ich bin eine andere Seite", + "title": "Seite - {{name}}" + } + }, "nav": { - "home": "Heim", + "home": "Startseite", "page": "Seite" }, - "subtitle": "Übersetzen Sie Ihre Qwik-Apps in eine beliebige Sprache", + "subtitle": "Übersetzen Sie Ihre Qwik-Apps in jede Sprache", "title": "Qwik Speak" - } + }, + "anotherPage": "Ich bin eine andere Seite", + "dates": "Daten & relative Zeit", + "defaultValue": "Ich bin ein Standardwert", + "description": "Internationalisierung (i18n) Bibliothek zum Übersetzen von Texten, Daten und Zahlen in Qwik-Apps", + "devs": { + "one": "{{ value }} Softwareentwickler", + "other": "{{ value }} Softwareentwickler" + }, + "greeting": "Hallo! Ich bin {{name}}", + "increment": "Erhöhen", + "numbers": "Zahlen & Währungen", + "params": "Parameter", + "plural": "Mehrzahl", + "tags": "Html-Tags" } \ No newline at end of file diff --git a/i18n/de-DE/home.json b/i18n/de-DE/home.json deleted file mode 100644 index f57f618..0000000 --- a/i18n/de-DE/home.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "home": { - "dates": "Daten und relative Zeit", - "devs": { - "one": "{{ value }} Softwareentwickler", - "other": "{{ value }} Softwareentwickler" - }, - "greeting": "Hallo! Im {{name}}", - "increment": "Zunahme", - "numbers": "Zahlen und Währungen", - "params": "Parameter", - "plural": "Plural", - "tags": "HTML-Tags", - "text": "Internationalisierungsbibliothek (i18n) zum Übersetzen von Texten, Datumsangaben und Zahlen in Qwik-Apps" - } -} \ No newline at end of file diff --git a/i18n/de-DE/page.json b/i18n/de-DE/page.json deleted file mode 100644 index 1845d61..0000000 --- a/i18n/de-DE/page.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "page": { - "text": "Ich bin eine andere Seite" - } -} \ No newline at end of file diff --git a/i18n/de-DE/runtime.json b/i18n/de-DE/runtime.json index a334fac..082b2d1 100644 --- a/i18n/de-DE/runtime.json +++ b/i18n/de-DE/runtime.json @@ -1,14 +1,5 @@ { "runtime": { - "head": { - "home": { - "description": "Internationalisierungsbibliothek (i18n) zum Übersetzen von Texten, Datumsangaben und Zahlen in Qwik-Apps", - "title": "{{name}}" - }, - "page": { - "description": "Ich bin eine andere Seite", - "title": "Seite - {{name}}" - } - } + "dynamic": "Ich bin ein dynamischer Wert" } } \ No newline at end of file diff --git a/i18n/de-DE/runtimePage.json b/i18n/de-DE/runtimePage.json deleted file mode 100644 index b00ea57..0000000 --- a/i18n/de-DE/runtimePage.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "runtimePage": { - "dynamic": "Ich bin ein dynamischer Wert" - } -} \ No newline at end of file diff --git a/i18n/en-US/app.json b/i18n/en-US/app.json index 05a534e..f3cd379 100644 --- a/i18n/en-US/app.json +++ b/i18n/en-US/app.json @@ -1,11 +1,35 @@ { "app": { "changeLocale": "Change locale", + "head": { + "home": { + "description": "Internationalization (i18n) library to translate texts, dates and numbers in Qwik apps", + "title": "{{name}}" + }, + "page": { + "description": "I'm another page", + "title": "Page - {{name}}" + } + }, "nav": { "home": "Home", "page": "Page" }, "subtitle": "Translate your Qwik apps into any language", "title": "Qwik Speak" - } + }, + "anotherPage": "I'm another page", + "dates": "Dates & relative time", + "defaultValue": "I'm a default value", + "description": "Internationalization (i18n) library to translate texts, dates and numbers in Qwik apps", + "devs": { + "one": "{{ value }} software developer", + "other": "{{ value }} software developers" + }, + "greeting": "Hi! I am {{name}}", + "increment": "Increment", + "numbers": "Numbers & currencies", + "params": "Parameters", + "plural": "Plural", + "tags": "Html tags" } \ No newline at end of file diff --git a/i18n/en-US/home.json b/i18n/en-US/home.json deleted file mode 100644 index f2e5ca4..0000000 --- a/i18n/en-US/home.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "home": { - "dates": "Dates & relative time", - "devs": { - "one": "{{ value }} software developer", - "other": "{{ value }} software developers" - }, - "greeting": "Hi! I am {{name}}", - "increment": "Increment", - "numbers": "Numbers & currencies", - "params": "Parameters", - "plural": "Plural", - "tags": "Html tags", - "text": "Internationalization (i18n) library to translate texts, dates and numbers in Qwik apps" - } -} \ No newline at end of file diff --git a/i18n/en-US/page.json b/i18n/en-US/page.json deleted file mode 100644 index cb2e3e3..0000000 --- a/i18n/en-US/page.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "page": { - "default": "I'm a default value", - "text": "I'm another page" - } -} \ No newline at end of file diff --git a/i18n/en-US/runtime.json b/i18n/en-US/runtime.json index 410e16a..e8642fa 100644 --- a/i18n/en-US/runtime.json +++ b/i18n/en-US/runtime.json @@ -1,14 +1,5 @@ { "runtime": { - "head": { - "home": { - "description": "Internationalization (i18n) library to translate texts, dates and numbers in Qwik apps", - "title": "{{name}}" - }, - "page": { - "description": "I'm another page", - "title": "Page - {{name}}" - } - } + "dynamic": "I'm a dynamic value" } } \ No newline at end of file diff --git a/i18n/en-US/runtimePage.json b/i18n/en-US/runtimePage.json deleted file mode 100644 index fe289f7..0000000 --- a/i18n/en-US/runtimePage.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "runtimePage": { - "dynamic": "I'm a dynamic value" - } -} \ No newline at end of file diff --git a/i18n/it-IT/app.json b/i18n/it-IT/app.json index d609ead..0597d3b 100644 --- a/i18n/it-IT/app.json +++ b/i18n/it-IT/app.json @@ -1,11 +1,35 @@ { "app": { "changeLocale": "Cambia località", + "head": { + "home": { + "description": "Libreria di internazionalizzazione (i18n) per tradurre testi, date e numeri nelle app Qwik", + "title": "{{name}}" + }, + "page": { + "description": "Sono un'altra pagina", + "title": "Pagina - {{name}}" + } + }, "nav": { "home": "Home", "page": "Pagina" }, "subtitle": "Traduci le tue app Qwik in qualsiasi lingua", "title": "Qwik Speak" - } + }, + "anotherPage": "Sono un'altra pagina", + "dates": "Date e tempo relativo", + "defaultValue": "Sono un valore predefinito", + "description": "Libreria di internazionalizzazione (i18n) per tradurre testi, date e numeri nelle app Qwik", + "devs": { + "one": "{{ value }} sviluppatore di software", + "other": "{{ value }} sviluppatori di software" + }, + "greeting": "Ciao! Sono {{name}}", + "increment": "Incremento", + "numbers": "Numeri e valute", + "params": "Parametri", + "plural": "Plurale", + "tags": "Tag Html" } \ No newline at end of file diff --git a/i18n/it-IT/home.json b/i18n/it-IT/home.json deleted file mode 100644 index af27064..0000000 --- a/i18n/it-IT/home.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "home": { - "dates": "Date e tempo relativo", - "devs": { - "one": "{{ value }} sviluppatore software", - "other": "{{ value }} sviluppatori software" - }, - "greeting": "Ciao! Sono {{name}}", - "increment": "Incrementa", - "numbers": "Numeri e valute", - "params": "Parametri", - "plural": "Plurale", - "tags": "Tag Html", - "text": "Libreria di internazionalizzazione (i18n) per tradurre testi, date e numeri nelle app Qwik" - } -} \ No newline at end of file diff --git a/i18n/it-IT/page.json b/i18n/it-IT/page.json deleted file mode 100644 index 9d3cc41..0000000 --- a/i18n/it-IT/page.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "page": { - "text": "Io sono un'altra pagina" - } -} \ No newline at end of file diff --git a/i18n/it-IT/runtime.json b/i18n/it-IT/runtime.json index 13804d2..9bfca36 100644 --- a/i18n/it-IT/runtime.json +++ b/i18n/it-IT/runtime.json @@ -1,14 +1,5 @@ { "runtime": { - "head": { - "home": { - "description": "Libreria di internazionalizzazione (i18n) per tradurre testi, date e numeri nelle app Qwik", - "title": "{{name}}" - }, - "page": { - "description": "Io sono un'altra pagina", - "title": "Pagina - {{name}}" - } - } + "dynamic": "Sono un valore dinamico" } } \ No newline at end of file diff --git a/i18n/it-IT/runtimePage.json b/i18n/it-IT/runtimePage.json deleted file mode 100644 index a65133e..0000000 --- a/i18n/it-IT/runtimePage.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "runtimePage": { - "dynamic": "Io sono un valore dinamico" - } -} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index fc0af3b..856ad07 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,15 +6,16 @@ "": { "name": "qwik-speak", "devDependencies": { - "@builder.io/qwik": "1.2.17", - "@builder.io/qwik-city": "1.2.17", + "@builder.io/qwik": "1.2.18", + "@builder.io/qwik-city": "1.2.18", "@playwright/test": "1.38.0", "@types/eslint": "8.44.6", "@types/node": "^20.8.9", "@typescript-eslint/eslint-plugin": "6.9.0", "@typescript-eslint/parser": "6.9.0", "eslint": "8.52.0", - "eslint-plugin-qwik": "1.2.17", + "eslint-plugin-qwik": "1.2.18", + "gpt-translate-json": "^0.1.0", "typescript": "5.2.2", "undici": "5.27.0", "vite": "4.5.0", @@ -35,9 +36,9 @@ } }, "node_modules/@builder.io/qwik": { - "version": "1.2.17", - "resolved": "https://registry.npmjs.org/@builder.io/qwik/-/qwik-1.2.17.tgz", - "integrity": "sha512-66fGmPHIy/brJqtrUapxckw9EVAh6U3pcjRr1WiqGGjq1cvgJdP88jayMw85XvckEjrF4ymNLOYCmjdlQNzU+Q==", + "version": "1.2.18", + "resolved": "https://registry.npmjs.org/@builder.io/qwik/-/qwik-1.2.18.tgz", + "integrity": "sha512-YfkpRI8IoJ6OkIlMoJ4jdjbotZSmBfMtf9ibxbf9vZLgKVLkSbSb4hgpA+NMWwQb/ojgn/6YJ49MwaZP81sm4Q==", "dev": true, "dependencies": { "csstype": "^3.1.2", @@ -54,9 +55,9 @@ } }, "node_modules/@builder.io/qwik-city": { - "version": "1.2.17", - "resolved": "https://registry.npmjs.org/@builder.io/qwik-city/-/qwik-city-1.2.17.tgz", - "integrity": "sha512-aCAjNQZr/DMgdcjqkyPVh1Uqly9urJx3mRu2iteLLy62VB6QYhaHtOHA6WlcwBT8LQGOOVilHEdDNB6hbrOwvQ==", + "version": "1.2.18", + "resolved": "https://registry.npmjs.org/@builder.io/qwik-city/-/qwik-city-1.2.18.tgz", + "integrity": "sha512-MfWzMLi0MaoPpI11g4qXVF5mX6hqfjsIS3G+1FUU+x4FIJFcbTu9cMnbaw5YdMOgNdJRS5wf2M++KXVy5oyJ/w==", "dev": true, "dependencies": { "@mdx-js/mdx": "2.3.0", @@ -1319,6 +1320,12 @@ "astring": "bin/astring" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, "node_modules/available-typed-arrays": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", @@ -1331,6 +1338,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/axios": { + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", + "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", + "dev": true, + "dependencies": { + "follow-redirects": "^1.14.8" + } + }, "node_modules/b4a": { "version": "1.6.4", "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.4.tgz", @@ -1610,6 +1626,18 @@ "simple-swizzle": "^0.2.2" } }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/comma-separated-tokens": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", @@ -1817,6 +1845,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -2151,9 +2188,9 @@ } }, "node_modules/eslint-plugin-qwik": { - "version": "1.2.17", - "resolved": "https://registry.npmjs.org/eslint-plugin-qwik/-/eslint-plugin-qwik-1.2.17.tgz", - "integrity": "sha512-Q6gwahd8np5s7/SwWrgvhzAgymqHmiuXdgUvIgnDt0N0fZvdEJQUYQtTOpwMpRj8+E53oKLVk3vogeRki6QbFw==", + "version": "1.2.18", + "resolved": "https://registry.npmjs.org/eslint-plugin-qwik/-/eslint-plugin-qwik-1.2.18.tgz", + "integrity": "sha512-B4c8bo0x6QyhCgGLkSn3/fqLreCnHeLv6UsVlZfW41VpWc4nPiYQqURp+ChY3TiPy2SXJEKtn4F4bBrn3sn4Fw==", "dev": true, "dependencies": { "jsx-ast-utils": "^3.3.5" @@ -2481,6 +2518,26 @@ "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", "dev": true }, + "node_modules/follow-redirects": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -2490,6 +2547,20 @@ "is-callable": "^1.1.3" } }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", @@ -2695,6 +2766,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gpt-translate-json": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/gpt-translate-json/-/gpt-translate-json-0.1.0.tgz", + "integrity": "sha512-wbG6mzff1o4DAVN9tBDOA+qmfPsUYu4z3RW7j44Z8KpiZ9MIjkvq5hhLthLDenBALA25vb1A/mmwPohlUfgRmg==", + "dev": true, + "dependencies": { + "openai": "^3.3.0" + }, + "bin": { + "gpt-translate-json": "lib/cli.js" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", @@ -4210,6 +4296,27 @@ "node": ">=8.6" } }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/mimic-response": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", @@ -4398,6 +4505,16 @@ "wrappy": "1" } }, + "node_modules/openai": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-3.3.0.tgz", + "integrity": "sha512-uqxI/Au+aPRnsaQRe8CojU0eCR7I0mBiKjD3sNMzY6DaC1ZVrc85u98mtJW6voDug8fgGN+DIZmTDxTthxb7dQ==", + "dev": true, + "dependencies": { + "axios": "^0.26.0", + "form-data": "^4.0.0" + } + }, "node_modules/optionator": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", diff --git a/package.json b/package.json index 29f646b..7b9ecbf 100644 --- a/package.json +++ b/package.json @@ -12,24 +12,26 @@ "build.types": "tsc --incremental --noEmit", "dev": "vite --mode ssr", "dev.debug": "node --inspect-brk ./node_modules/vite/bin/vite.js --mode ssr --force", - "lint": "eslint src/**/*.ts*", + "lint": "eslint \"src/**/*.ts*\"", "preview": "qwik build preview && vite preview --open", "qwik-speak-extract": "node ./packages/qwik-speak/extract/cli.js --supportedLangs=en-US,it-IT,de-DE --assetsPath=i18n", + "gpt-translate-json": "gpt-translate-json --apiKey=openai_api_key --model=gpt-4 --maxTokens=3000 --langs=en-US,it-IT,de-DE --originalLang=en-US", "start": "vite --open --mode ssr", "test": "vitest test --run", "test.e2e": "playwright test", "qwik": "qwik" }, "devDependencies": { - "@builder.io/qwik": "1.2.17", - "@builder.io/qwik-city": "1.2.17", + "@builder.io/qwik": "1.2.18", + "@builder.io/qwik-city": "1.2.18", "@playwright/test": "1.38.0", "@types/eslint": "8.44.6", "@types/node": "^20.8.9", "@typescript-eslint/eslint-plugin": "6.9.0", "@typescript-eslint/parser": "6.9.0", "eslint": "8.52.0", - "eslint-plugin-qwik": "1.2.17", + "eslint-plugin-qwik": "1.2.18", + "gpt-translate-json": "^0.1.0", "typescript": "5.2.2", "undici": "5.27.0", "vite": "4.5.0", diff --git a/packages/qwik-speak/package-lock.json b/packages/qwik-speak/package-lock.json index 7ba136d..2a0080b 100644 --- a/packages/qwik-speak/package-lock.json +++ b/packages/qwik-speak/package-lock.json @@ -12,27 +12,27 @@ "qwik-speak-extract": "extract/cli.js" }, "devDependencies": { - "@builder.io/qwik": "1.1.4", - "@microsoft/api-documenter": "^7.22.3", - "@microsoft/api-extractor": "^7.36.1", - "@types/eslint": "8.37.0", - "@types/node": "^18.16.1", - "@typescript-eslint/eslint-plugin": "5.59.1", - "@typescript-eslint/parser": "5.59.1", - "eslint": "8.39.0", - "eslint-plugin-qwik": "1.1.4", - "np": "^7.7.0", + "@builder.io/qwik": "1.2.18", + "@microsoft/api-documenter": "^7.23.12", + "@microsoft/api-extractor": "^7.38.3", + "@types/eslint": "8.44.4", + "@types/node": "^20.8.4", + "@typescript-eslint/eslint-plugin": "6.7.5", + "@typescript-eslint/parser": "6.7.5", + "eslint": "8.51.0", + "eslint-plugin-qwik": "1.2.18", + "np": "^8.0.4", "rollup-plugin-add-shebang": "^0.3.1", - "typescript": "5.0.4", - "undici": "5.22.0", - "vite": "4.3.3", - "vitest": "^0.30.1" + "typescript": "5.2.2", + "undici": "5.26.0", + "vite": "4.4.11", + "vitest": "^0.34.6" }, "engines": { "node": ">=16.0.0" }, "peerDependencies": { - "@builder.io/qwik": ">=1.1.4" + "@builder.io/qwik": ">=1.2.18" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -45,34 +45,106 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.5.tgz", - "integrity": "sha512-Xmwn266vad+6DAqEB2A6V/CcZVp62BbwVmcOJc2RPuwih1kw02TjQvWVWlcKGbBPd+8/0V5DEkOcizRGYsspYQ==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "dev": true, "dependencies": { - "@babel/highlight": "^7.22.5" + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" }, "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/code-frame/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/code-frame/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/code-frame/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", - "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.5.tgz", - "integrity": "sha512-BSKlD1hgnedS5XRnGOljZawtag7H1yPfQp0tdNJCHoH6AZ+Pcm9VvkrK59/Yy593Ypg0zMxH2BxD1VPYUQ7UIw==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.22.5", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, "engines": { @@ -150,11 +222,26 @@ "node": ">=4" } }, + "node_modules/@bconnorwhite/module": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@bconnorwhite/module/-/module-2.0.2.tgz", + "integrity": "sha512-ck1me5WMgZKp06gnJrVKEkytpehTTQbvsAMbF1nGPeHri/AZNhj87++PSE2LOxmZqM0EtGMaqeLdx7Lw7SUnTA==", + "dev": true, + "dependencies": { + "find-up": "^5.0.0", + "read-json-safe": "^1.0.5", + "types-pkg-json": "^1.1.0" + } + }, "node_modules/@builder.io/qwik": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@builder.io/qwik/-/qwik-1.1.4.tgz", - "integrity": "sha512-FSbe2GcUBptAXMAHfN+oGUpnb3nZXzup2EYlza61bAfgWSx9SryOwNULyROis3mu7Ywdua3w6VKvCWOFdovz2w==", + "version": "1.2.18", + "resolved": "https://registry.npmjs.org/@builder.io/qwik/-/qwik-1.2.18.tgz", + "integrity": "sha512-YfkpRI8IoJ6OkIlMoJ4jdjbotZSmBfMtf9ibxbf9vZLgKVLkSbSb4hgpA+NMWwQb/ojgn/6YJ49MwaZP81sm4Q==", "dev": true, + "dependencies": { + "csstype": "^3.1.2", + "vite": "^4.4.11" + }, "bin": { "qwik": "qwik.cjs" }, @@ -166,9 +253,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", - "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz", + "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==", "cpu": [ "arm" ], @@ -182,9 +269,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", - "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz", + "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==", "cpu": [ "arm64" ], @@ -198,9 +285,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", - "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz", + "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==", "cpu": [ "x64" ], @@ -214,9 +301,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", - "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz", + "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==", "cpu": [ "arm64" ], @@ -230,9 +317,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", - "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz", + "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==", "cpu": [ "x64" ], @@ -246,9 +333,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", - "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz", + "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==", "cpu": [ "arm64" ], @@ -262,9 +349,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", - "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz", + "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==", "cpu": [ "x64" ], @@ -278,9 +365,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", - "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz", + "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==", "cpu": [ "arm" ], @@ -294,9 +381,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", - "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz", + "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==", "cpu": [ "arm64" ], @@ -310,9 +397,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", - "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz", + "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==", "cpu": [ "ia32" ], @@ -326,9 +413,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", - "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz", + "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==", "cpu": [ "loong64" ], @@ -342,9 +429,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", - "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz", + "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==", "cpu": [ "mips64el" ], @@ -358,9 +445,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", - "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz", + "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==", "cpu": [ "ppc64" ], @@ -374,9 +461,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", - "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz", + "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==", "cpu": [ "riscv64" ], @@ -390,9 +477,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", - "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz", + "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==", "cpu": [ "s390x" ], @@ -406,9 +493,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", - "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz", + "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==", "cpu": [ "x64" ], @@ -422,9 +509,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", - "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz", + "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==", "cpu": [ "x64" ], @@ -438,9 +525,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", - "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz", + "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==", "cpu": [ "x64" ], @@ -454,9 +541,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", - "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz", + "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==", "cpu": [ "x64" ], @@ -470,9 +557,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", - "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz", + "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==", "cpu": [ "arm64" ], @@ -486,9 +573,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", - "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz", + "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==", "cpu": [ "ia32" ], @@ -502,9 +589,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", - "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz", + "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==", "cpu": [ "x64" ], @@ -542,9 +629,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.1.tgz", - "integrity": "sha512-9t7ZA7NGGK8ckelF0PQCfcxIUzs1Md5rrO6U/c+FIQNanea5UZC0wqKXH4vHBccmu4ZJgZ2idtPeW7+Q2npOEA==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.3.tgz", + "integrity": "sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==", "dev": true, "dependencies": { "ajv": "^6.12.4", @@ -583,21 +670,30 @@ } }, "node_modules/@eslint/js": { - "version": "8.39.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.39.0.tgz", - "integrity": "sha512-kf9RB0Fg7NZfap83B3QOqOGg9QmD9yBudqQXzzOtn3i4y7ZUXe5ONeW34Gwi+TxhH4mvj72R1Zc300KUMa9Bng==", + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.51.0.tgz", + "integrity": "sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@fastify/busboy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.0.tgz", + "integrity": "sha512-+KpH+QxZU7O4675t3mnkQKcZZg56u+K/Ct2K+N2AZYNVK8kyeo/bI18tI8aPm3tvNNRyTWfj6s5tnGNlcbQRsA==", + "dev": true, + "engines": { + "node": ">=14" + } + }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", - "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", + "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", + "@humanwhocodes/object-schema": "^2.0.1", "debug": "^4.1.1", "minimatch": "^3.0.5" }, @@ -619,27 +715,51 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", + "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", "dev": true }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.15", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", "dev": true }, + "node_modules/@ljharb/through": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/@ljharb/through/-/through-2.3.11.tgz", + "integrity": "sha512-ccfcIDlogiXNq5KcbAwbaO7lMh3Tm1i3khMPYpxlK8hH/W53zN81KM9coerRLOnTGu3nfXIniAmQbRI9OxbC0w==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/@microsoft/api-documenter": { - "version": "7.22.32", - "resolved": "https://registry.npmjs.org/@microsoft/api-documenter/-/api-documenter-7.22.32.tgz", - "integrity": "sha512-JePSgTg3qz5SiqcINQO52EKNh15DTbnvUpnx1qcrBlpR9gX0TmCw5g5uGPegIHJzIeif4uYe15nEUynrYDT2nw==", + "version": "7.23.12", + "resolved": "https://registry.npmjs.org/@microsoft/api-documenter/-/api-documenter-7.23.12.tgz", + "integrity": "sha512-ZFQGHNs8fSe3KoSCNa+jt/HLTN8IdTRGd0TZqmSeHpz2cSvUYHJeyQKhv8s7yi2flr1LezBq5/ig65ITZPSSqw==", "dev": true, "dependencies": { - "@microsoft/api-extractor-model": "7.27.5", + "@microsoft/api-extractor-model": "7.28.2", "@microsoft/tsdoc": "0.14.2", - "@rushstack/node-core-library": "3.59.6", - "@rushstack/ts-command-line": "4.15.1", + "@rushstack/node-core-library": "3.61.0", + "@rushstack/ts-command-line": "4.17.1", "colors": "~1.2.1", "js-yaml": "~3.13.1", "resolve": "~1.22.1" @@ -649,17 +769,17 @@ } }, "node_modules/@microsoft/api-extractor": { - "version": "7.36.3", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.36.3.tgz", - "integrity": "sha512-u0H6362AQq+r55X8drHx4npgkrCfJnMzRRHfQo8PMNKB8TcBnrTLfXhXWi+xnTM6CzlU/netEN8c4bq581Rnrg==", + "version": "7.38.3", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.38.3.tgz", + "integrity": "sha512-xt9iYyC5f39281j77JTA9C3ISJpW1XWkCcnw+2vM78CPnro6KhPfwQdPDfwS5JCPNuq0grm8cMdPUOPvrchDWw==", "dev": true, "dependencies": { - "@microsoft/api-extractor-model": "7.27.5", + "@microsoft/api-extractor-model": "7.28.2", "@microsoft/tsdoc": "0.14.2", "@microsoft/tsdoc-config": "~0.16.1", - "@rushstack/node-core-library": "3.59.6", - "@rushstack/rig-package": "0.4.0", - "@rushstack/ts-command-line": "4.15.1", + "@rushstack/node-core-library": "3.61.0", + "@rushstack/rig-package": "0.5.1", + "@rushstack/ts-command-line": "4.17.1", "colors": "~1.2.1", "lodash": "~4.17.15", "resolve": "~1.22.1", @@ -672,14 +792,27 @@ } }, "node_modules/@microsoft/api-extractor-model": { - "version": "7.27.5", - "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.27.5.tgz", - "integrity": "sha512-9/tBzYMJitR+o+zkPr1lQh2+e8ClcaTF6eZo7vZGDqRt2O5XmXWPbYJZmxyM3wb5at6lfJNEeGZrQXLjsQ0Nbw==", + "version": "7.28.2", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.28.2.tgz", + "integrity": "sha512-vkojrM2fo3q4n4oPh4uUZdjJ2DxQ2+RnDQL/xhTWSRUNPF6P4QyrvY357HBxbnltKcYu+nNNolVqc6TIGQ73Ig==", "dev": true, "dependencies": { "@microsoft/tsdoc": "0.14.2", "@microsoft/tsdoc-config": "~0.16.1", - "@rushstack/node-core-library": "3.59.6" + "@rushstack/node-core-library": "3.61.0" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/typescript": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", + "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=12.20" } }, "node_modules/@microsoft/tsdoc": { @@ -748,10 +881,51 @@ "node": ">= 8" } }, + "node_modules/@pnpm/config.env-replace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", + "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==", + "dev": true, + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz", + "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==", + "dev": true, + "dependencies": { + "graceful-fs": "4.2.10" + }, + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file/node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "node_modules/@pnpm/npm-conf": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.2.2.tgz", + "integrity": "sha512-UA91GwWPhFExt3IizW6bOeY/pQ0BkuNwKjk9iQW9KqxluGCrg4VenZ0/L+2Y0+ZOtme72EVvg6v0zo3AMQRCeA==", + "dev": true, + "dependencies": { + "@pnpm/config.env-replace": "^1.1.0", + "@pnpm/network.ca-file": "^1.0.1", + "config-chain": "^1.1.11" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/@rushstack/node-core-library": { - "version": "3.59.6", - "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.59.6.tgz", - "integrity": "sha512-bMYJwNFfWXRNUuHnsE9wMlW/mOB4jIwSUkRKtu02CwZhQdmzMsUbxE0s1xOLwTpNIwlzfW/YT7OnOHgDffLgYg==", + "version": "3.61.0", + "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-3.61.0.tgz", + "integrity": "sha512-tdOjdErme+/YOu4gPed3sFS72GhtWCgNV9oDsHDnoLY5oDfwjKUc9Z+JOZZ37uAxcm/OCahDHfuu2ugqrfWAVQ==", "dev": true, "dependencies": { "colors": "~1.2.1", @@ -772,9 +946,9 @@ } }, "node_modules/@rushstack/rig-package": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.4.0.tgz", - "integrity": "sha512-FnM1TQLJYwSiurP6aYSnansprK5l8WUK8VG38CmAaZs29ZeL1msjK0AP1VS4ejD33G0kE/2cpsPsS9jDenBMxw==", + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.5.1.tgz", + "integrity": "sha512-pXRYSe29TjRw7rqxD4WS3HN/sRSbfr+tJs4a9uuaSIBAITbUggygdhuG0VrO0EO+QqH91GhYMN4S6KRtOEmGVA==", "dev": true, "dependencies": { "resolve": "~1.22.1", @@ -782,9 +956,9 @@ } }, "node_modules/@rushstack/ts-command-line": { - "version": "4.15.1", - "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.15.1.tgz", - "integrity": "sha512-EL4jxZe5fhb1uVL/P/wQO+Z8Rc8FMiWJ1G7VgnPDvdIt5GVjRfK7vwzder1CZQiX3x0PY6uxENYLNGTFd1InRQ==", + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-4.17.1.tgz", + "integrity": "sha512-2jweO1O57BYP5qdBGl6apJLB+aRIn5ccIRTPDyULh0KMwVzFqWtw6IZWt1qtUoZD/pD2RNkIOosH6Cq45rIYeg==", "dev": true, "dependencies": { "@types/argparse": "1.0.38", @@ -822,10 +996,16 @@ "node": ">=6" } }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true + }, "node_modules/@sindresorhus/is": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-2.1.1.tgz", - "integrity": "sha512-/aPsuoj/1Dw/kzhkgz+ES6TxG0zfTMGLwuK2ZG00k/iJzYHTLCE8mVU8EPqEOp/lmxPoq1C1C9RYToRKb2KEfg==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", "dev": true, "engines": { "node": ">=10" @@ -880,9 +1060,9 @@ } }, "node_modules/@types/eslint": { - "version": "8.37.0", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.37.0.tgz", - "integrity": "sha512-Piet7dG2JBuDIfohBngQ3rCt7MgO9xCO4xIMKxBThCq5PNRB91IjlJ10eJVwfoNtvTErmxLzwBZ7rHZtbOMmFQ==", + "version": "8.44.4", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.4.tgz", + "integrity": "sha512-lOzjyfY/D9QR4hY9oblZ76B90MYTB3RrQ4z2vBIJKj9ROCRqdkYl2gSUx1x1a4IWPjKJZLL4Aw1Zfay7eMnmnA==", "dev": true, "dependencies": { "@types/estree": "*", @@ -896,9 +1076,9 @@ "dev": true }, "node_modules/@types/http-cache-semantics": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", - "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz", + "integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==", "dev": true }, "node_modules/@types/json-schema": { @@ -916,72 +1096,64 @@ "@types/node": "*" } }, - "node_modules/@types/minimist": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", - "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", - "dev": true - }, "node_modules/@types/node": { - "version": "18.17.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.17.3.tgz", - "integrity": "sha512-2x8HWtFk0S99zqVQABU9wTpr8wPoaDHZUcAkoTKH+nL7kPv3WUI9cRi/Kk5Mz4xdqXSqTkKP7IWNoQQYCnDsTA==", - "dev": true + "version": "20.9.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.9.1.tgz", + "integrity": "sha512-HhmzZh5LSJNS5O8jQKpJ/3ZcrrlG6L70hpGqMIAoM9YVD0YBRNWYsfwcXq8VnSjlNpCpgLzMXdiPo+dxcvSmiA==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } }, "node_modules/@types/normalize-package-data": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", - "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", - "dev": true - }, - "node_modules/@types/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", "dev": true }, "node_modules/@types/responselike": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", - "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz", + "integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.5.tgz", + "integrity": "sha512-+d+WYC1BxJ6yVOgUgzK8gWvp5qF8ssV5r4nsDcZWKRWcDQLQ619tvWAxJQYGgBrO1MnLJC7a5GtiYsAoQ47dJg==", "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.59.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.1.tgz", - "integrity": "sha512-AVi0uazY5quFB9hlp2Xv+ogpfpk77xzsgsIEWyVS7uK/c7MZ5tw7ZPbapa0SbfkqE0fsAMkz5UwtgMLVk2BQAg==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.5.tgz", + "integrity": "sha512-JhtAwTRhOUcP96D0Y6KYnwig/MRQbOoLGXTON2+LlyB/N35SP9j1boai2zzwXb7ypKELXMx3DVk9UTaEq1vHEw==", "dev": true, "dependencies": { - "@eslint-community/regexpp": "^4.4.0", - "@typescript-eslint/scope-manager": "5.59.1", - "@typescript-eslint/type-utils": "5.59.1", - "@typescript-eslint/utils": "5.59.1", + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.7.5", + "@typescript-eslint/type-utils": "6.7.5", + "@typescript-eslint/utils": "6.7.5", + "@typescript-eslint/visitor-keys": "6.7.5", "debug": "^4.3.4", - "grapheme-splitter": "^1.0.4", - "ignore": "^5.2.0", - "natural-compare-lite": "^1.4.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -990,25 +1162,26 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "5.59.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.1.tgz", - "integrity": "sha512-nzjFAN8WEu6yPRDizIFyzAfgK7nybPodMNFGNH0M9tei2gYnYszRDqVA0xlnRjkl7Hkx2vYrEdb6fP2a21cG1g==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.7.5.tgz", + "integrity": "sha512-bIZVSGx2UME/lmhLcjdVc7ePBwn7CLqKarUBL4me1C5feOd663liTGjMBGVcGr+BhnSLeP4SgwdvNnnkbIdkCw==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.59.1", - "@typescript-eslint/types": "5.59.1", - "@typescript-eslint/typescript-estree": "5.59.1", + "@typescript-eslint/scope-manager": "6.7.5", + "@typescript-eslint/types": "6.7.5", + "@typescript-eslint/typescript-estree": "6.7.5", + "@typescript-eslint/visitor-keys": "6.7.5", "debug": "^4.3.4" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "eslint": "^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -1017,16 +1190,16 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.59.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.1.tgz", - "integrity": "sha512-mau0waO5frJctPuAzcxiNWqJR5Z8V0190FTSqRw1Q4Euop6+zTwHAf8YIXNwDOT29tyUDrQ65jSg9aTU/H0omA==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.5.tgz", + "integrity": "sha512-GAlk3eQIwWOJeb9F7MKQ6Jbah/vx1zETSDw8likab/eFcqkjSD7BI75SDAeC5N2L0MmConMoPvTsmkrg71+B1A==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.59.1", - "@typescript-eslint/visitor-keys": "5.59.1" + "@typescript-eslint/types": "6.7.5", + "@typescript-eslint/visitor-keys": "6.7.5" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", @@ -1034,25 +1207,25 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.59.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.59.1.tgz", - "integrity": "sha512-ZMWQ+Oh82jWqWzvM3xU+9y5U7MEMVv6GLioM3R5NJk6uvP47kZ7YvlgSHJ7ERD6bOY7Q4uxWm25c76HKEwIjZw==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.7.5.tgz", + "integrity": "sha512-Gs0qos5wqxnQrvpYv+pf3XfcRXW6jiAn9zE/K+DlmYf6FcpxeNYN0AIETaPR7rHO4K2UY+D0CIbDP9Ut0U4m1g==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "5.59.1", - "@typescript-eslint/utils": "5.59.1", + "@typescript-eslint/typescript-estree": "6.7.5", + "@typescript-eslint/utils": "6.7.5", "debug": "^4.3.4", - "tsutils": "^3.21.0" + "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "*" + "eslint": "^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -1061,12 +1234,12 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "5.59.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.1.tgz", - "integrity": "sha512-dg0ICB+RZwHlysIy/Dh1SP+gnXNzwd/KS0JprD3Lmgmdq+dJAJnUPe1gNG34p0U19HvRlGX733d/KqscrGC1Pg==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.5.tgz", + "integrity": "sha512-WboQBlOXtdj1tDFPyIthpKrUb+kZf2VroLZhxKa/VlwLlLyqv/PwUNgL30BlTVZV1Wu4Asu2mMYPqarSO4L5ZQ==", "dev": true, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", @@ -1074,21 +1247,21 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.59.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.1.tgz", - "integrity": "sha512-lYLBBOCsFltFy7XVqzX0Ju+Lh3WPIAWxYpmH/Q7ZoqzbscLiCW00LeYCdsUnnfnj29/s1WovXKh2gwCoinHNGA==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.5.tgz", + "integrity": "sha512-NhJiJ4KdtwBIxrKl0BqG1Ur+uw7FiOnOThcYx9DpOGJ/Abc9z2xNzLeirCG02Ig3vkvrc2qFLmYSSsaITbKjlg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.59.1", - "@typescript-eslint/visitor-keys": "5.59.1", + "@typescript-eslint/types": "6.7.5", + "@typescript-eslint/visitor-keys": "6.7.5", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", @@ -1101,42 +1274,41 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "5.59.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.1.tgz", - "integrity": "sha512-MkTe7FE+K1/GxZkP5gRj3rCztg45bEhsd8HYjczBuYm+qFHP5vtZmjx3B0yUCDotceQ4sHgTyz60Ycl225njmA==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.7.5.tgz", + "integrity": "sha512-pfRRrH20thJbzPPlPc4j0UNGvH1PjPlhlCMq4Yx7EGjV7lvEeGX0U6MJYe8+SyFutWgSHsdbJ3BXzZccYggezA==", "dev": true, "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.59.1", - "@typescript-eslint/types": "5.59.1", - "@typescript-eslint/typescript-estree": "5.59.1", - "eslint-scope": "^5.1.1", - "semver": "^7.3.7" + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.7.5", + "@typescript-eslint/types": "6.7.5", + "@typescript-eslint/typescript-estree": "6.7.5", + "semver": "^7.5.4" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "eslint": "^7.0.0 || ^8.0.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.59.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.1.tgz", - "integrity": "sha512-6waEYwBTCWryx0VJmP7JaM4FpipLsFl9CvYf2foAE8Qh/Y0s+bxWysciwOs0LTBED4JCaNxTZ5rGadB14M6dwA==", + "version": "6.7.5", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.5.tgz", + "integrity": "sha512-3MaWdDZtLlsexZzDSdQWsFQ9l9nL8B80Z4fImSpyllFC/KLqWQRdEcB+gGGO+N3Q2uL40EsG66wZLsohPxNXvg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.59.1", - "eslint-visitor-keys": "^3.3.0" + "@typescript-eslint/types": "6.7.5", + "eslint-visitor-keys": "^3.4.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", @@ -1144,26 +1316,31 @@ } }, "node_modules/@vitest/expect": { - "version": "0.30.1", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.30.1.tgz", - "integrity": "sha512-c3kbEtN8XXJSeN81iDGq29bUzSjQhjES2WR3aColsS4lPGbivwLtas4DNUe0jD9gg/FYGIteqOenfU95EFituw==", + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.34.6.tgz", + "integrity": "sha512-QUzKpUQRc1qC7qdGo7rMK3AkETI7w18gTCUrsNnyjjJKYiuUB9+TQK3QnR1unhCnWRC0AbKv2omLGQDF/mIjOw==", "dev": true, "dependencies": { - "@vitest/spy": "0.30.1", - "@vitest/utils": "0.30.1", - "chai": "^4.3.7" + "@vitest/spy": "0.34.6", + "@vitest/utils": "0.34.6", + "chai": "^4.3.10" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/runner": { - "version": "0.30.1", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.30.1.tgz", - "integrity": "sha512-W62kT/8i0TF1UBCNMRtRMOBWJKRnNyv9RrjIgdUryEe0wNpGZvvwPDLuzYdxvgSckzjp54DSpv1xUbv4BQ0qVA==", + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.34.6.tgz", + "integrity": "sha512-1CUQgtJSLF47NnhN+F9X2ycxUP0kLHQ/JWvNHbeBfwW8CzEGgeskzNnHDyv1ieKTltuR6sdIHV+nmR6kPxQqzQ==", "dev": true, "dependencies": { - "@vitest/utils": "0.30.1", - "concordance": "^5.0.4", + "@vitest/utils": "0.34.6", "p-limit": "^4.0.0", - "pathe": "^1.1.0" + "pathe": "^1.1.1" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/runner/node_modules/p-limit": { @@ -1194,20 +1371,23 @@ } }, "node_modules/@vitest/snapshot": { - "version": "0.30.1", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-0.30.1.tgz", - "integrity": "sha512-fJZqKrE99zo27uoZA/azgWyWbFvM1rw2APS05yB0JaLwUIg9aUtvvnBf4q7JWhEcAHmSwbrxKFgyBUga6tq9Tw==", + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-0.34.6.tgz", + "integrity": "sha512-B3OZqYn6k4VaN011D+ve+AA4whM4QkcwcrwaKwAbyyvS/NB1hCWjFIBQxAQQSQir9/RtyAAGuq+4RJmbn2dH4w==", "dev": true, "dependencies": { - "magic-string": "^0.30.0", - "pathe": "^1.1.0", - "pretty-format": "^27.5.1" + "magic-string": "^0.30.1", + "pathe": "^1.1.1", + "pretty-format": "^29.5.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/snapshot/node_modules/magic-string": { - "version": "0.30.2", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.2.tgz", - "integrity": "sha512-lNZdu7pewtq/ZvWUp9Wpf/x7WzMTsR26TWV03BRZrXFsv+BI6dy8RAiKgm1uM/kyR0rCfUcqvOlXKG66KhIGug==", + "version": "0.30.5", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", + "integrity": "sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==", "dev": true, "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" @@ -1217,23 +1397,29 @@ } }, "node_modules/@vitest/spy": { - "version": "0.30.1", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.30.1.tgz", - "integrity": "sha512-YfJeIf37GvTZe04ZKxzJfnNNuNSmTEGnla2OdL60C8od16f3zOfv9q9K0nNii0NfjDJRt/CVN/POuY5/zTS+BA==", + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.34.6.tgz", + "integrity": "sha512-xaCvneSaeBw/cz8ySmF7ZwGvL0lBjfvqc1LpQ/vcdHEvpLn3Ff1vAvjw+CoGn0802l++5L/pxb7whwcWAw+DUQ==", "dev": true, "dependencies": { - "tinyspy": "^2.1.0" + "tinyspy": "^2.1.1" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/utils": { - "version": "0.30.1", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.30.1.tgz", - "integrity": "sha512-/c8Xv2zUVc+rnNt84QF0Y0zkfxnaGhp87K2dYJMLtLOIckPzuxLVzAtFCicGFdB4NeBHNzTRr1tNn7rCtQcWFA==", + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.34.6.tgz", + "integrity": "sha512-IG5aDD8S6zlvloDsnzHw0Ut5xczlF+kv2BOTo+iXfPr54Yhi5qbVOgGB1hZaVq4iJ4C/MZ2J0y15IlsV/ZcI0A==", "dev": true, "dependencies": { - "concordance": "^5.0.4", + "diff-sequences": "^29.4.3", "loupe": "^2.3.6", - "pretty-format": "^27.5.1" + "pretty-format": "^29.5.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, "node_modules/acorn": { @@ -1267,25 +1453,31 @@ } }, "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-4.0.1.tgz", + "integrity": "sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w==", "dev": true, "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" + "clean-stack": "^4.0.0", + "indent-string": "^5.0.0" }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/aggregate-error/node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", "dev": true, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/ajv": { @@ -1304,6 +1496,22 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/all-package-names": { + "version": "2.0.780", + "resolved": "https://registry.npmjs.org/all-package-names/-/all-package-names-2.0.780.tgz", + "integrity": "sha512-gVk6lhl+7opXJQHNI+JO9RHxx+3JhoAb8wxhtqK12S1v+SBVjRG65+56JrMGWnjPvIS/olTmlk/Wcadsf/lD3A==", + "dev": true, + "dependencies": { + "commander-version": "^1.1.0", + "p-lock": "^2.0.0", + "parse-json-object": "^2.0.1", + "progress": "^2.0.3", + "types-json": "^1.2.2" + }, + "bin": { + "all-package-names": "build/bin/index.js" + } + }, "node_modules/ansi-align": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", @@ -1364,26 +1572,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/any-observable": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/any-observable/-/any-observable-0.5.1.tgz", - "integrity": "sha512-8zv01bgDOp9PTmRTNCAHTw64TFP2rvlX4LvtNJLachaXY+AjmIvLT47fABNPCiIe89hKiSCo2n5zmPqI9CElPA==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - }, - "peerDependenciesMeta": { - "rxjs": { - "optional": true - }, - "zen-observable": { - "optional": true - } - } - }, "node_modules/argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", @@ -1472,15 +1660,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/assertion-error": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", @@ -1490,15 +1669,6 @@ "node": "*" } }, - "node_modules/async-exit-hook": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/async-exit-hook/-/async-exit-hook-2.0.1.tgz", - "integrity": "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, "node_modules/available-typed-arrays": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", @@ -1517,63 +1687,183 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, - "node_modules/blueimp-md5": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/blueimp-md5/-/blueimp-md5-2.19.0.tgz", - "integrity": "sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w==", - "dev": true + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, - "node_modules/boxen": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz", - "integrity": "sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==", + "node_modules/big-integer": { + "version": "1.6.51", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.51.tgz", + "integrity": "sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==", "dev": true, - "dependencies": { - "ansi-align": "^3.0.0", - "camelcase": "^6.2.0", - "chalk": "^4.1.0", - "cli-boxes": "^2.2.1", - "string-width": "^4.2.2", - "type-fest": "^0.20.2", - "widest-line": "^3.1.0", - "wrap-ansi": "^7.0.0" - }, "engines": { - "node": ">=10" + "node": ">=0.6" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/boxen": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.1.1.tgz", + "integrity": "sha512-2hCgjEmP8YLWQ130n2FerGv7rYpfBmnmp9Uy2Le1vge6X3gZIfSmEzP5QTDElFxcvVcXlEn8Aq6MU/PZygIOog==", + "dev": true, + "dependencies": { + "ansi-align": "^3.0.1", + "camelcase": "^7.0.1", + "chalk": "^5.2.0", + "cli-boxes": "^3.0.0", + "string-width": "^5.1.2", + "type-fest": "^2.13.0", + "widest-line": "^4.0.1", + "wrap-ansi": "^8.1.0" + }, + "engines": { + "node": ">=14.16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/boxen/node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "node_modules/boxen/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", "dev": true, "engines": { - "node": ">=10" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/boxen/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/boxen/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/boxen/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/boxen/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/boxen/node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "dev": true, + "engines": { + "node": ">=12.20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/boxen/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" }, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/bplist-parser": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz", + "integrity": "sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw==", + "dev": true, + "dependencies": { + "big-integer": "^1.6.44" + }, + "engines": { + "node": ">= 5.10.0" + } + }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -1596,22 +1886,49 @@ "node": ">=8" } }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "node_modules/builtins": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", "integrity": "sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ==", "dev": true }, - "node_modules/busboy": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", - "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "node_modules/bundle-name": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-3.0.0.tgz", + "integrity": "sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw==", "dev": true, "dependencies": { - "streamsearch": "^1.1.0" + "run-applescript": "^5.0.0" }, "engines": { - "node": ">=10.16.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/cac": { @@ -1624,16 +1941,12 @@ } }, "node_modules/cacheable-lookup": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-2.0.1.tgz", - "integrity": "sha512-EMMbsiOTcdngM/K6gV/OxF2x0t07+vMOWxZNSCRQMjO2MY2nhZQ6OYhOOpyQrbhqsgtvKGI7hcq6xjnA92USjg==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", "dev": true, - "dependencies": { - "@types/keyv": "^3.1.1", - "keyv": "^4.0.0" - }, "engines": { - "node": ">=10" + "node": ">=10.6.0" } }, "node_modules/cacheable-request": { @@ -1683,53 +1996,42 @@ } }, "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-4.1.0.tgz", + "integrity": "sha512-aBMbD1Xxay75ViYezwT40aQONfr+pSXTHwNKvIXhXD6+LY3F1dLIcceoC5OZKBVHbXcysz1hL9D2w0JJIMXpUw==", "dev": true, "engines": { - "node": ">=6" + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase-keys": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", - "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.1.tgz", + "integrity": "sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==", "dev": true, - "dependencies": { - "camelcase": "^5.3.1", - "map-obj": "^4.0.0", - "quick-lru": "^4.0.1" - }, "engines": { - "node": ">=8" + "node": ">=14.16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/chai": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz", - "integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==", + "version": "4.3.10", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.10.tgz", + "integrity": "sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==", "dev": true, "dependencies": { "assertion-error": "^1.1.0", - "check-error": "^1.0.2", - "deep-eql": "^4.1.2", - "get-func-name": "^2.0.0", - "loupe": "^2.3.1", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", "pathval": "^1.1.1", - "type-detect": "^4.0.5" + "type-detect": "^4.0.8" }, "engines": { "node": ">=4" @@ -1758,36 +2060,66 @@ "dev": true }, "node_modules/check-error": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", - "integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", "dev": true, + "dependencies": { + "get-func-name": "^2.0.2" + }, "engines": { "node": "*" } }, "node_modules/ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } }, "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-4.2.0.tgz", + "integrity": "sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg==", "dev": true, + "dependencies": { + "escape-string-regexp": "5.0.0" + }, "engines": { - "node": ">=6" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/clean-stack/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/cli-boxes": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", - "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", + "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", "dev": true, "engines": { - "node": ">=6" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -1805,6 +2137,18 @@ "node": ">=8" } }, + "node_modules/cli-spinners": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.1.tgz", + "integrity": "sha512-jHgecW0pxkonBJdrKsqxgRX9AcG+u/5k0Q7WPDfi8AogLAdwxEkyYYNWwZ5GvVFoFx2uiY1eNcSK00fh+1+FyQ==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/cli-truncate": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-0.2.1.tgz", @@ -1874,6 +2218,15 @@ "node": ">= 10" } }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, "node_modules/clone-response": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", @@ -1886,15 +2239,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/clone-response/node_modules/mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/code-point-at": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", @@ -1932,13 +2276,22 @@ } }, "node_modules/commander": { - "version": "9.5.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", - "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", "dev": true, - "optional": true, "engines": { - "node": "^12.20.0 || >=14" + "node": ">= 6" + } + }, + "node_modules/commander-version": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/commander-version/-/commander-version-1.1.0.tgz", + "integrity": "sha512-9aNW4N6q6EPDUszLRH6k9IwO6OoGYh3HRgUF/fA7Zs+Mz1v1x5akSqT7QGB8JsGY7AG7qMA7oRRB/4yyn33FYA==", + "dev": true, + "dependencies": { + "@bconnorwhite/module": "^2.0.2", + "commander": "^6.1.0" } }, "node_modules/concat-map": { @@ -1947,68 +2300,98 @@ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, - "node_modules/concordance": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/concordance/-/concordance-5.0.4.tgz", - "integrity": "sha512-OAcsnTEYu1ARJqWVGwf4zh4JDfHZEaSNlNccFmt8YjB2l/n19/PF2viLINHc57vO4FKIAFl2FWASIGZZWZ2Kxw==", + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", "dev": true, "dependencies": { - "date-time": "^3.1.0", - "esutils": "^2.0.3", - "fast-diff": "^1.2.0", - "js-string-escape": "^1.0.1", - "lodash": "^4.17.15", - "md5-hex": "^3.0.1", - "semver": "^7.3.2", - "well-known-symbols": "^2.0.0" - }, - "engines": { - "node": ">=10.18.0 <11 || >=12.14.0 <13 || >=14" + "ini": "^1.3.4", + "proto-list": "~1.2.1" } }, + "node_modules/config-chain/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, "node_modules/configstore": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", - "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-6.0.0.tgz", + "integrity": "sha512-cD31W1v3GqUlQvbBCGcXmd2Nj9SvLDOP1oQ0YFuLETufzSPaKp11rYBsSOm7rCsW3OnIRAFM3OxRhceaXNYHkA==", "dev": true, "dependencies": { - "dot-prop": "^5.2.0", - "graceful-fs": "^4.1.2", - "make-dir": "^3.0.0", - "unique-string": "^2.0.0", - "write-file-atomic": "^3.0.0", - "xdg-basedir": "^4.0.0" + "dot-prop": "^6.0.1", + "graceful-fs": "^4.2.6", + "unique-string": "^3.0.0", + "write-file-atomic": "^3.0.3", + "xdg-basedir": "^5.0.1" }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/yeoman/configstore?sponsor=1" } }, "node_modules/configstore/node_modules/dot-prop": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", - "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", + "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", "dev": true, "dependencies": { "is-obj": "^2.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/cosmiconfig": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", - "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", "dev": true, "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" }, "engines": { - "node": ">=10" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cosmiconfig/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/cosmiconfig/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" } }, "node_modules/cross-spawn": { @@ -2026,32 +2409,44 @@ } }, "node_modules/crypto-random-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", - "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", + "integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==", "dev": true, + "dependencies": { + "type-fest": "^1.0.1" + }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/date-fns": { + "node_modules/crypto-random-string/node_modules/type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/csstype": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", + "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==", + "dev": true + }, + "node_modules/date-fns": { "version": "1.30.1", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz", "integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==", "dev": true }, - "node_modules/date-time": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/date-time/-/date-time-3.1.0.tgz", - "integrity": "sha512-uqCUKXE5q1PNBXjPqvwhwJf9SwMoAHBgWJ6DcrnS5o+W2JOiIILl0JEdVD8SGujrNS02GGxgwAg2PN2zONgtjg==", - "dev": true, - "dependencies": { - "time-zone": "^1.0.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -2069,50 +2464,31 @@ } } }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decamelize-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", - "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", "dev": true, "dependencies": { - "decamelize": "^1.1.0", - "map-obj": "^1.0.0" + "mimic-response": "^3.1.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/decamelize-keys/node_modules/map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decompress-response": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-5.0.0.tgz", - "integrity": "sha512-TLZWWybuxWgoW7Lykv+gq9xvzOsUjQ9tF09Tj6NSTYGMTCHNXzrPnD6Hi+TgZq19PyTAGH4Ll/NIM/eTGglnMw==", + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", "dev": true, - "dependencies": { - "mimic-response": "^2.0.0" - }, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/deep-eql": { @@ -2142,6 +2518,52 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "node_modules/default-browser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-4.0.0.tgz", + "integrity": "sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA==", + "dev": true, + "dependencies": { + "bundle-name": "^3.0.0", + "default-browser-id": "^3.0.0", + "execa": "^7.1.1", + "titleize": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-3.0.0.tgz", + "integrity": "sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA==", + "dev": true, + "dependencies": { + "bplist-parser": "^0.2.0", + "untildify": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dev": true, + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/defer-to-connect": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", @@ -2151,6 +2573,18 @@ "node": ">=10" } }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/define-properties": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz", @@ -2168,27 +2602,79 @@ } }, "node_modules/del": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", - "integrity": "sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/del/-/del-7.1.0.tgz", + "integrity": "sha512-v2KyNk7efxhlyHpjEvfyxaAihKKK0nWCuf6ZtqZcFFpQRG0bJ12Qsr0RpvsICMjAAZ8DOVCxrlqpxISlMHC4Kg==", "dev": true, "dependencies": { - "globby": "^11.0.1", - "graceful-fs": "^4.2.4", - "is-glob": "^4.0.1", - "is-path-cwd": "^2.2.0", - "is-path-inside": "^3.0.2", - "p-map": "^4.0.0", + "globby": "^13.1.2", + "graceful-fs": "^4.2.10", + "is-glob": "^4.0.3", + "is-path-cwd": "^3.0.0", + "is-path-inside": "^4.0.0", + "p-map": "^5.5.0", "rimraf": "^3.0.2", - "slash": "^3.0.0" + "slash": "^4.0.0" }, "engines": { - "node": ">=10" + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/del/node_modules/globby": { + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", + "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", + "dev": true, + "dependencies": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.3.0", + "ignore": "^5.2.4", + "merge2": "^1.4.1", + "slash": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/del/node_modules/is-path-inside": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-4.0.0.tgz", + "integrity": "sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/del/node_modules/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true, + "engines": { + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -2214,24 +2700,36 @@ } }, "node_modules/dot-prop": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", - "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-7.2.0.tgz", + "integrity": "sha512-Ol/IPXUARn9CSbkrdV4VJo7uCy1I3VuSiWCaFSg+8BdUOzF9n3jefIpcgAydvUZbTdEBZs2vEiTiS9m61ssiDA==", "dev": true, "dependencies": { - "is-obj": "^2.0.0" + "type-fest": "^2.11.2" }, "engines": { - "node": ">=10" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/dot-prop/node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "dev": true, + "engines": { + "node": ">=12.20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/duplexer3": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.5.tgz", - "integrity": "sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==", + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "dev": true }, "node_modules/elegant-spinner": { @@ -2361,9 +2859,9 @@ } }, "node_modules/esbuild": { - "version": "0.17.19", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", - "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", + "version": "0.18.20", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz", + "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==", "dev": true, "hasInstallScript": true, "bin": { @@ -2373,37 +2871,37 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/android-arm": "0.17.19", - "@esbuild/android-arm64": "0.17.19", - "@esbuild/android-x64": "0.17.19", - "@esbuild/darwin-arm64": "0.17.19", - "@esbuild/darwin-x64": "0.17.19", - "@esbuild/freebsd-arm64": "0.17.19", - "@esbuild/freebsd-x64": "0.17.19", - "@esbuild/linux-arm": "0.17.19", - "@esbuild/linux-arm64": "0.17.19", - "@esbuild/linux-ia32": "0.17.19", - "@esbuild/linux-loong64": "0.17.19", - "@esbuild/linux-mips64el": "0.17.19", - "@esbuild/linux-ppc64": "0.17.19", - "@esbuild/linux-riscv64": "0.17.19", - "@esbuild/linux-s390x": "0.17.19", - "@esbuild/linux-x64": "0.17.19", - "@esbuild/netbsd-x64": "0.17.19", - "@esbuild/openbsd-x64": "0.17.19", - "@esbuild/sunos-x64": "0.17.19", - "@esbuild/win32-arm64": "0.17.19", - "@esbuild/win32-ia32": "0.17.19", - "@esbuild/win32-x64": "0.17.19" + "@esbuild/android-arm": "0.18.20", + "@esbuild/android-arm64": "0.18.20", + "@esbuild/android-x64": "0.18.20", + "@esbuild/darwin-arm64": "0.18.20", + "@esbuild/darwin-x64": "0.18.20", + "@esbuild/freebsd-arm64": "0.18.20", + "@esbuild/freebsd-x64": "0.18.20", + "@esbuild/linux-arm": "0.18.20", + "@esbuild/linux-arm64": "0.18.20", + "@esbuild/linux-ia32": "0.18.20", + "@esbuild/linux-loong64": "0.18.20", + "@esbuild/linux-mips64el": "0.18.20", + "@esbuild/linux-ppc64": "0.18.20", + "@esbuild/linux-riscv64": "0.18.20", + "@esbuild/linux-s390x": "0.18.20", + "@esbuild/linux-x64": "0.18.20", + "@esbuild/netbsd-x64": "0.18.20", + "@esbuild/openbsd-x64": "0.18.20", + "@esbuild/sunos-x64": "0.18.20", + "@esbuild/win32-arm64": "0.18.20", + "@esbuild/win32-ia32": "0.18.20", + "@esbuild/win32-x64": "0.18.20" } }, "node_modules/escape-goat": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-3.0.0.tgz", - "integrity": "sha512-w3PwNZJwRxlp47QGzhuEBldEqVHHhh8/tIPcl6ecf2Bou99cdAt0knihBV0Ecc7CGxYduXVBDheH1K2oADRlvw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-4.0.0.tgz", + "integrity": "sha512-2Sd4ShcWxbx6OY1IHyla/CVNwvg7XwZVoXZHcSu9w9SReNP1EzzD5T8NWKIR38fIqEns9kDWKUQTXXAmlDrdPg==", "dev": true, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -2422,27 +2920,27 @@ } }, "node_modules/eslint": { - "version": "8.39.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.39.0.tgz", - "integrity": "sha512-mwiok6cy7KTW7rBpo05k6+p4YVZByLNjAZ/ACB9DRCu4YDRwjXI01tWHp6KAUWelsBetTxKK/2sHB0vdS8Z2Og==", + "version": "8.51.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.51.0.tgz", + "integrity": "sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.2", - "@eslint/js": "8.39.0", - "@humanwhocodes/config-array": "^0.11.8", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.2", + "@eslint/js": "8.51.0", + "@humanwhocodes/config-array": "^0.11.11", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", + "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.0", - "eslint-visitor-keys": "^3.4.0", - "espree": "^9.5.1", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -2450,22 +2948,19 @@ "find-up": "^5.0.0", "glob-parent": "^6.0.2", "globals": "^13.19.0", - "grapheme-splitter": "^1.0.4", + "graphemer": "^1.4.0", "ignore": "^5.2.0", - "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", - "js-sdsl": "^4.1.4", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", + "optionator": "^0.9.3", "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" }, "bin": { @@ -2479,37 +2974,24 @@ } }, "node_modules/eslint-plugin-qwik": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/eslint-plugin-qwik/-/eslint-plugin-qwik-1.1.4.tgz", - "integrity": "sha512-RHeH/OwYu6iLxVxyuHshCRiIetmrsEo585yGC8ZRTuIa25zCUbD54w/KumXU6u4W5t00NxxrDwt3+ZH206hQEA==", + "version": "1.2.18", + "resolved": "https://registry.npmjs.org/eslint-plugin-qwik/-/eslint-plugin-qwik-1.2.18.tgz", + "integrity": "sha512-B4c8bo0x6QyhCgGLkSn3/fqLreCnHeLv6UsVlZfW41VpWc4nPiYQqURp+ChY3TiPy2SXJEKtn4F4bBrn3sn4Fw==", "dev": true, "dependencies": { - "jsx-ast-utils": "^3.3.3" + "jsx-ast-utils": "^3.3.5" }, "engines": { - "node": ">=16" + "node": ">=16.8.0 <18.0.0 || >=18.11" }, "peerDependencies": { - "eslint": ">= 8" - } - }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" + "eslint": "^8.45.0" } }, "node_modules/eslint-visitor-keys": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.2.tgz", - "integrity": "sha512-8drBzUEyZ2llkpCA67iYrgEssKDUu68V8ChqqOfFupIaG/LCVPUT+CoGJpT77zJprs4T/W7p07LP7zAIMuweVw==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -2633,15 +3115,6 @@ "node": ">=4.0" } }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/estree-walker": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz", @@ -2658,28 +3131,67 @@ } }, "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-7.2.0.tgz", + "integrity": "sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA==", "dev": true, "dependencies": { "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", + "get-stream": "^6.0.1", + "human-signals": "^4.3.0", + "is-stream": "^3.0.0", "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^3.0.7", + "strip-final-newline": "^3.0.0" }, "engines": { - "node": ">=10" + "node": "^14.18.0 || ^16.14.0 || >=18.0.0" }, "funding": { "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, + "node_modules/execa/node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/execa/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/exit-hook": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-3.2.0.tgz", + "integrity": "sha512-aIQN7Q04HGAV/I5BszisuHTZHXNoC23WtLkxdCLuYZMdWviRD0TMIt2bnUBi9MrHaF/hH8b3gwG9iaAUHKnJGA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/external-editor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", @@ -2700,16 +3212,10 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, - "node_modules/fast-diff": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", - "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", - "dev": true - }, "node_modules/fast-glob": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", - "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -2847,6 +3353,15 @@ "is-callable": "^1.1.3" } }, + "node_modules/form-data-encoder": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", + "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==", + "dev": true, + "engines": { + "node": ">= 14.17" + } + }, "node_modules/fs-extra": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", @@ -2915,9 +3430,9 @@ } }, "node_modules/get-func-name": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz", - "integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", "dev": true, "engines": { "node": "*" @@ -3005,24 +3520,24 @@ } }, "node_modules/global-dirs": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-2.1.0.tgz", - "integrity": "sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", + "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==", "dev": true, "dependencies": { - "ini": "1.3.7" + "ini": "2.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "version": "13.23.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", + "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -3082,82 +3597,42 @@ } }, "node_modules/got": { - "version": "10.7.0", - "resolved": "https://registry.npmjs.org/got/-/got-10.7.0.tgz", - "integrity": "sha512-aWTDeNw9g+XqEZNcTjMMZSy7B7yE9toWOFYip7ofFTLleJhvZwUxxTxkTpKvF+p1SAA4VHmuEy7PiHTHyq8tJg==", + "version": "11.8.6", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", + "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", "dev": true, "dependencies": { - "@sindresorhus/is": "^2.0.0", - "@szmarczak/http-timer": "^4.0.0", + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", "@types/cacheable-request": "^6.0.1", - "cacheable-lookup": "^2.0.0", - "cacheable-request": "^7.0.1", - "decompress-response": "^5.0.0", - "duplexer3": "^0.1.4", - "get-stream": "^5.0.0", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", "lowercase-keys": "^2.0.0", - "mimic-response": "^2.1.0", "p-cancelable": "^2.0.0", - "p-event": "^4.0.0", - "responselike": "^2.0.0", - "to-readable-stream": "^2.0.0", - "type-fest": "^0.10.0" + "responselike": "^2.0.0" }, "engines": { - "node": ">=10" + "node": ">=10.19.0" }, "funding": { "url": "https://github.com/sindresorhus/got?sponsor=1" } }, - "node_modules/got/node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/got/node_modules/type-fest": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.10.0.tgz", - "integrity": "sha512-EUV9jo4sffrwlg8s0zDhP0T2WD3pru5Xi0+HTE3zTUmBaZNhfkite9PdSJwdXLwPVW0jnAHT56pZHIOYckPEiw==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, - "node_modules/hard-rejection": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", - "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -3261,24 +3736,36 @@ } }, "node_modules/has-yarn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", - "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-3.0.0.tgz", + "integrity": "sha512-IrsVwUHhEULx3R8f/aA8AHuEzAorplsab/v8HBzEiIukwq5i/EC+xmOW+HfP1OaDP+2JkgT1yILHN2O3UFIbcA==", "dev": true, "engines": { - "node": ">=8" - } + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/hosted-git-info": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.8.tgz", - "integrity": "sha512-aXpmwoOhRBrw6X3j0h5RloK4x1OzsxMPyxqIHyNfSe2pypkVTZFpEiRoSipPEPlMrh0HW/XsjkJ5WgnCirpNUw==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz", + "integrity": "sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==", "dev": true, "dependencies": { - "lru-cache": "^6.0.0" + "lru-cache": "^7.5.1" }, "engines": { - "node": ">=10" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" } }, "node_modules/http-cache-semantics": { @@ -3287,13 +3774,26 @@ "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", "dev": true }, + "node_modules/http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "dev": true, + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", + "integrity": "sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ==", "dev": true, "engines": { - "node": ">=10.17.0" + "node": ">=14.18.0" } }, "node_modules/iconv-lite": { @@ -3308,6 +3808,26 @@ "node": ">=0.10.0" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/ignore": { "version": "5.2.4", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", @@ -3318,12 +3838,39 @@ } }, "node_modules/ignore-walk": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.4.tgz", - "integrity": "sha512-PY6Ii8o1jMRA1z4F2hRkH/xN59ox43DavKvD3oDpfurRlOJyAHpifIwpbdv1n4jt4ov0jSpw3kQ4GhJnpBL6WQ==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.3.tgz", + "integrity": "sha512-C7FfFoTA+bI10qfeydT8aZbvr91vAEU+2W5BZUlzPec47oNb07SsOfwYrtxuvOYdUApPP/Qlh4DtAO51Ekk2QA==", + "dev": true, + "dependencies": { + "minimatch": "^9.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/ignore-walk/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/ignore-walk/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", "dev": true, "dependencies": { - "minimatch": "^3.0.4" + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/import-fresh": { @@ -3469,10 +4016,13 @@ "dev": true }, "node_modules/ini": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.7.tgz", - "integrity": "sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==", - "dev": true + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "dev": true, + "engines": { + "node": ">=10" + } }, "node_modules/inquirer": { "version": "7.3.3", @@ -3822,12 +4372,12 @@ } }, "node_modules/is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", + "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", "dev": true, "dependencies": { - "ci-info": "^2.0.0" + "ci-info": "^3.2.0" }, "bin": { "is-ci": "bin.js" @@ -3861,15 +4411,15 @@ } }, "node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", "dev": true, "bin": { "is-docker": "cli.js" }, "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -3905,29 +4455,61 @@ "node": ">=0.10.0" } }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-installed-globally": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.3.2.tgz", - "integrity": "sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", "dev": true, "dependencies": { - "global-dirs": "^2.0.1", - "is-path-inside": "^3.0.1" + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" }, "engines": { - "node": ">=8" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/is-interactive": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", - "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", + "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", "dev": true, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-name-taken": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-name-taken/-/is-name-taken-2.0.0.tgz", + "integrity": "sha512-W+FUWF5g7ONVJTx3rldZeVizmPzrMMUdscpSQ96vyYerx+4b2NcqaujLJJDWruGzE0FjzGZO9RFIipOGxx/WIw==", + "dev": true, + "dependencies": { + "all-package-names": "^2.0.2", + "package-name-conflict": "^1.0.3", + "validate-npm-package-name": "^3.0.0" } }, "node_modules/is-negative-zero": { @@ -3943,12 +4525,12 @@ } }, "node_modules/is-npm": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-5.0.0.tgz", - "integrity": "sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-6.0.0.tgz", + "integrity": "sha512-JEjxbSmtPSt1c8XTkVrlujcXdKV1/tvuQ7GwKcAlyiVLeYFQ2VHat8xfrDJsIkhCdF/tZ7CiIR3sy141c6+gPQ==", "dev": true, "engines": { - "node": ">=10" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -4009,12 +4591,15 @@ } }, "node_modules/is-path-cwd": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", - "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-3.0.0.tgz", + "integrity": "sha512-kyiNFFLU0Ampr6SDZitD/DwUo4Zs1nSdnygUBqsu3LooL00Qvb5j+UnvApUn/TTj1J3OuE6BTdQ5rudKmU2ZaA==", "dev": true, "engines": { - "node": ">=6" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/is-path-inside": { @@ -4026,15 +4611,6 @@ "node": ">=8" } }, - "node_modules/is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-promise": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", @@ -4058,15 +4634,18 @@ } }, "node_modules/is-scoped": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-scoped/-/is-scoped-2.1.0.tgz", - "integrity": "sha512-Cv4OpPTHAK9kHYzkzCrof3VJh7H/PrG2MBUMvvJebaaUMbqhm0YAtXnvh0I3Hnj2tMZWwrRROWLSgfJrKqWmlQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-scoped/-/is-scoped-3.0.0.tgz", + "integrity": "sha512-ezxLUq30kiTvP0w/5n9tj4qTOKlrA07Oty1hwTQ+lcqw11x6uc8sp7VRb2OVGRzKfCHZ2A22T5Zsau/Q2Akb0g==", "dev": true, "dependencies": { - "scoped-regex": "^2.0.0" + "scoped-regex": "^3.0.0" }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/is-shared-array-buffer": { @@ -4082,12 +4661,12 @@ } }, "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", "dev": true, "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -4145,24 +4724,24 @@ "dev": true }, "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", + "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", "dev": true, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/is-url-superb": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-url-superb/-/is-url-superb-4.0.0.tgz", - "integrity": "sha512-GI+WjezhPPcbM+tqE9LnmsY5qqjwHzTvjJ36wxYX5ujNXefSUJ/T17r5bqDV8yLhcgB59KTPNOc9O9cmHTPWsA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/is-url-superb/-/is-url-superb-6.1.0.tgz", + "integrity": "sha512-LXdhGlYqUPdvEyIhWPEEwYYK3yrUiPcBjmFGlZNv1u5GtIL5qQRf7ddDyPNAvsMFqdzS923FROpTQU97tLe3JQ==", "dev": true, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -4192,11 +4771,29 @@ "node": ">=8" } }, + "node_modules/is-wsl/node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "dev": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-yarn-global": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", - "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", - "dev": true + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.4.1.tgz", + "integrity": "sha512-/kppl+R+LO5VmhYSEWARUFjodS25D68gvj8W7z0I7OWhUla5xWu8KL6CtB2V0R6yqhnRgbcaREMr4EEM6htLPQ==", + "dev": true, + "engines": { + "node": ">=12" + } }, "node_modules/isarray": { "version": "2.0.5", @@ -4211,12 +4808,15 @@ "dev": true }, "node_modules/issue-regex": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/issue-regex/-/issue-regex-3.1.0.tgz", - "integrity": "sha512-0RHjbtw9QXeSYnIEY5Yrp2QZrdtz21xBDV9C/GIlY2POmgoS6a7qjkYS5siRKXScnuAj5/SPv1C3YForNCHTJA==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/issue-regex/-/issue-regex-4.1.0.tgz", + "integrity": "sha512-X3HBmm7+Th+l4/kMtqwcHHgELD0Lfl0Ina6S3+grr+mKmTxsrM84NAO1UuRPIxIbGLIl3TCEu45S1kdu21HYbQ==", "dev": true, "engines": { - "node": ">=10" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/jju": { @@ -4225,25 +4825,6 @@ "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==", "dev": true }, - "node_modules/js-sdsl": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.2.tgz", - "integrity": "sha512-dwXFwByc/ajSV6m5bcKAPwe4yDDF6D614pxmIi5odytzxRlwqF6nwoiCek80Ixc7Cvma5awClxrzFtxCQvcM8w==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" - } - }, - "node_modules/js-string-escape": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz", - "integrity": "sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg==", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -4318,33 +4899,27 @@ } }, "node_modules/keyv": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz", - "integrity": "sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==", + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, "dependencies": { "json-buffer": "3.0.1" } }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/latest-version": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", - "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-7.0.0.tgz", + "integrity": "sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==", "dev": true, "dependencies": { - "package-json": "^6.3.0" + "package-json": "^8.1.0" }, "engines": { - "node": ">=8" + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/levn": { @@ -4741,21 +5316,33 @@ "dev": true }, "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-5.1.0.tgz", + "integrity": "sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==", "dev": true, "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" + "chalk": "^5.0.0", + "is-unicode-supported": "^1.1.0" }, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/log-update": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/log-update/-/log-update-2.3.0.tgz", @@ -4826,12 +5413,12 @@ } }, "node_modules/loupe": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz", - "integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==", + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", "dev": true, "dependencies": { - "get-func-name": "^2.0.0" + "get-func-name": "^2.0.1" } }, "node_modules/lowercase-keys": { @@ -4864,156 +5451,59 @@ "sourcemap-codec": "^1.4.8" } }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "node_modules/meow": { + "version": "12.1.1", + "resolved": "https://registry.npmjs.org/meow/-/meow-12.1.1.tgz", + "integrity": "sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==", "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, "engines": { - "node": ">=8" + "node": ">=16.10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/make-dir/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, - "bin": { - "semver": "bin/semver.js" + "engines": { + "node": ">= 8" } }, - "node_modules/map-age-cleaner": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", - "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", "dev": true, "dependencies": { - "p-defer": "^1.0.0" + "braces": "^3.0.2", + "picomatch": "^2.3.1" }, "engines": { - "node": ">=6" + "node": ">=8.6" } }, - "node_modules/map-obj": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", - "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/md5-hex": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/md5-hex/-/md5-hex-3.0.1.tgz", - "integrity": "sha512-BUiRtTtV39LIJwinWBjqVsU9xhdnz7/i889V859IBFpuqGAj6LuOvHv5XLbgZ2R7ptJoJaEcxkv88/h25T7Ciw==", - "dev": true, - "dependencies": { - "blueimp-md5": "^2.10.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/meow": { - "version": "8.1.2", - "resolved": "https://registry.npmjs.org/meow/-/meow-8.1.2.tgz", - "integrity": "sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==", - "dev": true, - "dependencies": { - "@types/minimist": "^1.2.0", - "camelcase-keys": "^6.2.2", - "decamelize-keys": "^1.1.0", - "hard-rejection": "^2.1.0", - "minimist-options": "4.1.0", - "normalize-package-data": "^3.0.0", - "read-pkg-up": "^7.0.1", - "redent": "^3.0.0", - "trim-newlines": "^3.0.0", - "type-fest": "^0.18.0", - "yargs-parser": "^20.2.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/meow/node_modules/type-fest": { - "version": "0.18.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", - "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, - "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" + "node": ">=6" } }, "node_modules/mimic-response": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", - "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/min-indent": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", "dev": true, "engines": { "node": ">=4" @@ -5040,30 +5530,16 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/minimist-options": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", - "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", - "dev": true, - "dependencies": { - "arrify": "^1.0.1", - "is-plain-obj": "^1.1.0", - "kind-of": "^6.0.3" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/mlly": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.4.0.tgz", - "integrity": "sha512-ua8PAThnTwpprIaU47EPeZ/bPUVp2QYBbWMphUQpVdBI3Lgqzm5KZQ45Agm3YJedHXaIHl6pBGabaLSUPPSptg==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.4.2.tgz", + "integrity": "sha512-i/Ykufi2t1EZ6NaPLdfnZk2AX8cs0d+mTzVKuPfqPKPatxLApaBoxJQ9x1/uckXtrS/U5oisPMDkNs0yQTaBRg==", "dev": true, "dependencies": { - "acorn": "^8.9.0", + "acorn": "^8.10.0", "pathe": "^1.1.1", "pkg-types": "^1.0.3", - "ufo": "^1.1.2" + "ufo": "^1.3.0" } }, "node_modules/ms": { @@ -5102,31 +5578,31 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, - "node_modules/natural-compare-lite": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", - "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", - "dev": true - }, "node_modules/new-github-release-url": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/new-github-release-url/-/new-github-release-url-1.0.0.tgz", - "integrity": "sha512-dle7yf655IMjyFUqn6Nxkb18r4AOAkzRcgcZv6WZ0IqrOH4QCEZ8Sm6I7XX21zvHdBeeMeTkhR9qT2Z0EJDx6A==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/new-github-release-url/-/new-github-release-url-2.0.0.tgz", + "integrity": "sha512-NHDDGYudnvRutt/VhKFlX26IotXe1w0cmkDm6JGquh5bz/bDTw0LufSmH/GxTjEdpHEO+bVKFTwdrcGa/9XlKQ==", "dev": true, "dependencies": { - "type-fest": "^0.4.1" + "type-fest": "^2.5.1" }, "engines": { - "node": ">=10" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/new-github-release-url/node_modules/type-fest": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.4.1.tgz", - "integrity": "sha512-IwzA/LSfD2vC1/YDYMv/zHP4rDF1usCwllsDpbolT3D4fUepIO7f9K70jjmUewU/LmGUKJcwcVtDCpnKk4BPMw==", + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", "dev": true, "engines": { - "node": ">=6" + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/normalize-package-data": { @@ -5169,109 +5645,268 @@ } }, "node_modules/np": { - "version": "7.7.0", - "resolved": "https://registry.npmjs.org/np/-/np-7.7.0.tgz", - "integrity": "sha512-G4HfO6JUl7iKOX1qfYHM/kG5ApqqZ4ma8YjtVAJoyS5VdKkGE/OdSG3cOE9Lwr71klNz9n6KIZmPRnh0L7qM1Q==", - "dev": true, - "dependencies": { - "@samverschueren/stream-to-observable": "^0.3.1", - "any-observable": "^0.5.1", - "async-exit-hook": "^2.0.1", - "chalk": "^4.1.0", - "cosmiconfig": "^7.0.0", - "del": "^6.0.0", - "escape-goat": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "execa": "^5.0.0", + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/np/-/np-8.0.4.tgz", + "integrity": "sha512-a4s1yESHcIwsrk/oaTekfbhb1R/2z2yyfVLX6Atl54w/9+QR01qeYyK3vMWgJ0UY+kYsGzQXausgvUX0pkmIMg==", + "dev": true, + "dependencies": { + "chalk": "^5.2.0", + "cosmiconfig": "^8.1.3", + "del": "^7.0.0", + "escape-goat": "^4.0.0", + "escape-string-regexp": "^5.0.0", + "execa": "^7.1.1", + "exit-hook": "^3.2.0", "github-url-from-git": "^1.5.0", - "has-yarn": "^2.1.0", - "hosted-git-info": "^3.0.7", - "ignore-walk": "^3.0.3", - "import-local": "^3.0.2", - "inquirer": "^7.3.3", - "is-installed-globally": "^0.3.2", - "is-interactive": "^1.0.0", - "is-scoped": "^2.1.0", - "issue-regex": "^3.1.0", + "has-yarn": "^3.0.0", + "hosted-git-info": "^6.1.1", + "ignore-walk": "^6.0.3", + "import-local": "^3.1.0", + "inquirer": "^9.2.6", + "is-installed-globally": "^0.4.0", + "is-interactive": "^2.0.0", + "is-scoped": "^3.0.0", + "issue-regex": "^4.1.0", "listr": "^0.14.3", "listr-input": "^0.2.1", - "log-symbols": "^4.0.0", - "meow": "^8.1.0", - "minimatch": "^3.0.4", - "new-github-release-url": "^1.0.0", - "npm-name": "^6.0.1", - "onetime": "^5.1.2", - "open": "^7.3.0", - "ow": "^0.21.0", - "p-memoize": "^4.0.1", - "p-timeout": "^4.1.0", - "pkg-dir": "^5.0.0", - "read-pkg-up": "^7.0.1", - "rxjs": "^6.6.3", - "semver": "^7.3.4", - "split": "^1.0.1", - "symbol-observable": "^3.0.0", - "terminal-link": "^2.1.1", - "update-notifier": "^5.0.1" + "log-symbols": "^5.1.0", + "meow": "^12.0.1", + "new-github-release-url": "^2.0.0", + "npm-name": "^7.1.0", + "onetime": "^6.0.0", + "open": "^9.1.0", + "ow": "^1.1.1", + "p-memoize": "^7.1.1", + "p-timeout": "^6.1.1", + "path-exists": "^5.0.0", + "pkg-dir": "^7.0.0", + "read-pkg-up": "^9.1.0", + "rxjs": "^7.8.1", + "semver": "^7.5.1", + "symbol-observable": "^4.0.0", + "terminal-link": "^3.0.0", + "update-notifier": "^6.0.2" }, "bin": { "np": "source/cli.js" }, "engines": { "git": ">=2.11.0", - "node": ">=10", - "npm": ">=6.8.0", + "node": ">=16.6.0", + "npm": ">=7.19.0", "yarn": ">=1.7.0" }, "funding": { "url": "https://github.com/sindresorhus/np?sponsor=1" } }, - "node_modules/npm-name": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/npm-name/-/npm-name-6.0.1.tgz", - "integrity": "sha512-fhKRvUAxaYzMEUZim4mXWyfFbVS+M1CbrCLdAo3txWzrctxKka/h+KaBW0O9Cz5uOM00Nldn2JLWhuwnyW3SUw==", + "node_modules/np/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/np/node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/np/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/np/node_modules/figures": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-5.0.0.tgz", + "integrity": "sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg==", "dev": true, "dependencies": { - "got": "^10.6.0", - "is-scoped": "^2.1.0", - "is-url-superb": "^4.0.0", - "lodash.zip": "^4.2.0", - "org-regex": "^1.0.0", - "p-map": "^3.0.0", - "registry-auth-token": "^4.0.0", - "registry-url": "^5.1.0", - "validate-npm-package-name": "^3.0.0" + "escape-string-regexp": "^5.0.0", + "is-unicode-supported": "^1.2.0" }, "engines": { - "node": ">=10" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/np/node_modules/inquirer": { + "version": "9.2.12", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.2.12.tgz", + "integrity": "sha512-mg3Fh9g2zfuVWJn6lhST0O7x4n03k7G8Tx5nvikJkbq8/CK47WDVm+UznF0G6s5Zi0KcyUisr6DU8T67N5U+1Q==", + "dev": true, + "dependencies": { + "@ljharb/through": "^2.3.11", + "ansi-escapes": "^4.3.2", + "chalk": "^5.3.0", + "cli-cursor": "^3.1.0", + "cli-width": "^4.1.0", + "external-editor": "^3.1.0", + "figures": "^5.0.0", + "lodash": "^4.17.21", + "mute-stream": "1.0.0", + "ora": "^5.4.1", + "run-async": "^3.0.0", + "rxjs": "^7.8.1", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^6.2.0" + }, + "engines": { + "node": ">=14.18.0" + } + }, + "node_modules/np/node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/np/node_modules/mute-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", + "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/np/node_modules/onetime": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", + "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", + "dev": true, + "dependencies": { + "mimic-fn": "^4.0.0" + }, + "engines": { + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/npm-name/node_modules/p-map": { + "node_modules/np/node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/np/node_modules/run-async": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", - "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz", + "integrity": "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/np/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "dev": true, "dependencies": { - "aggregate-error": "^3.0.0" + "tslib": "^2.1.0" + } + }, + "node_modules/np/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, + "node_modules/np/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "engines": { "node": ">=8" } }, + "node_modules/npm-name": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/npm-name/-/npm-name-7.1.1.tgz", + "integrity": "sha512-lyOwsFndLoozriMEsaqJ5lXvhCATYOEhDvxlom8TNvB9a/htDXuLgpVhMUOBd9zCewUXCyBXAPxrGr2TK2adgQ==", + "dev": true, + "dependencies": { + "got": "^11.8.5", + "is-name-taken": "^2.0.0", + "is-scoped": "^3.0.0", + "is-url-superb": "^6.1.0", + "lodash.zip": "^4.2.0", + "org-regex": "^1.0.0", + "p-map": "^5.5.0", + "registry-auth-token": "^4.2.2", + "registry-url": "^6.0.1", + "validate-npm-package-name": "^3.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.1.0.tgz", + "integrity": "sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q==", "dev": true, "dependencies": { - "path-key": "^3.0.0" + "path-key": "^4.0.0" }, "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/number-is-nan": { @@ -5370,16 +6005,18 @@ } }, "node_modules/open": { - "version": "7.4.2", - "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", - "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/open/-/open-9.1.0.tgz", + "integrity": "sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg==", "dev": true, "dependencies": { - "is-docker": "^2.0.0", - "is-wsl": "^2.1.1" + "default-browser": "^4.0.0", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^2.2.0" }, "engines": { - "node": ">=8" + "node": ">=14.16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -5402,37 +6039,43 @@ "node": ">= 0.8.0" } }, - "node_modules/org-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/org-regex/-/org-regex-1.0.0.tgz", - "integrity": "sha512-7bqkxkEJwzJQUAlyYniqEZ3Ilzjh0yoa62c7gL6Ijxj5bEpPL+8IE1Z0PFj0ywjjXQcdrwR51g9MIcLezR0hKQ==", + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", "dev": true, + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "node_modules/ora/node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/ow": { - "version": "0.21.0", - "resolved": "https://registry.npmjs.org/ow/-/ow-0.21.0.tgz", - "integrity": "sha512-dlsoDe39g7mhdsdrC1R/YwjT7yjVqE3svWwOlMGvN690waBkgEZBmKBdkmKvSt5/wZ6E0Jn/nIesPqMZOpPKqw==", + "node_modules/ora/node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", "dev": true, - "dependencies": { - "@sindresorhus/is": "^4.0.0", - "callsites": "^3.1.0", - "dot-prop": "^6.0.1", - "lodash.isequal": "^4.5.0", - "type-fest": "^0.20.2", - "vali-date": "^1.0.0" - }, "engines": { "node": ">=10" }, @@ -5440,70 +6083,78 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ow/node_modules/@sindresorhus/is": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", - "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "node_modules/ora/node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/sindresorhus/is?sponsor=1" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-cancelable": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", - "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", + "node_modules/org-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/org-regex/-/org-regex-1.0.0.tgz", + "integrity": "sha512-7bqkxkEJwzJQUAlyYniqEZ3Ilzjh0yoa62c7gL6Ijxj5bEpPL+8IE1Z0PFj0ywjjXQcdrwR51g9MIcLezR0hKQ==", "dev": true, "engines": { "node": ">=8" } }, - "node_modules/p-defer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", - "integrity": "sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==", + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", "dev": true, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/p-event": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/p-event/-/p-event-4.2.0.tgz", - "integrity": "sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==", + "node_modules/ow": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ow/-/ow-1.1.1.tgz", + "integrity": "sha512-sJBRCbS5vh1Jp9EOgwp1Ws3c16lJrUkJYlvWTYC03oyiYVwS/ns7lKRWow4w4XjDyTrA2pplQv4B2naWSR6yDA==", "dev": true, "dependencies": { - "p-timeout": "^3.1.0" + "@sindresorhus/is": "^5.3.0", + "callsites": "^4.0.0", + "dot-prop": "^7.2.0", + "lodash.isequal": "^4.5.0", + "vali-date": "^1.0.0" }, "engines": { - "node": ">=8" + "node": ">=14.16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-event/node_modules/p-timeout": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-3.2.0.tgz", - "integrity": "sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==", + "node_modules/ow/node_modules/@sindresorhus/is": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz", + "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==", "dev": true, - "dependencies": { - "p-finally": "^1.0.0" - }, "engines": { - "node": ">=8" + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" } }, - "node_modules/p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "node_modules/p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", "dev": true, "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/p-limit": { @@ -5536,94 +6187,77 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-lock": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-lock/-/p-lock-2.1.0.tgz", + "integrity": "sha512-pi2yT8gNhVrV4LgsUvJWQy58TXH1HG2+NXDby9+UrsS/9fXb0FJH9aCxbdHJ0EAQ6XC7ggSP6GAzuR5puDArUQ==", + "dev": true + }, "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-5.5.0.tgz", + "integrity": "sha512-VFqfGDHlx87K66yZrNdI4YGtD70IRyd+zSvgks6mzHPRNkoKy+9EKP4SFC77/vTTQYmRmti7dvqC+m5jBrBAcg==", "dev": true, "dependencies": { - "aggregate-error": "^3.0.0" + "aggregate-error": "^4.0.0" }, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-memoize": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/p-memoize/-/p-memoize-4.0.4.tgz", - "integrity": "sha512-ijdh0DP4Mk6J4FXlOM6vPPoCjPytcEseW8p/k5SDTSSfGV3E9bpt9Yzfifvzp6iohIieoLTkXRb32OWV0fB2Lw==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/p-memoize/-/p-memoize-7.1.1.tgz", + "integrity": "sha512-DZ/bONJILHkQ721hSr/E9wMz5Am/OTJ9P6LhLFo2Tu+jL8044tgc9LwHO8g4PiaYePnlVVRAJcKmgy8J9MVFrA==", "dev": true, "dependencies": { - "map-age-cleaner": "^0.1.3", - "mimic-fn": "^3.0.0", - "p-settle": "^4.1.1" + "mimic-fn": "^4.0.0", + "type-fest": "^3.0.0" }, "engines": { - "node": ">=10" + "node": ">=14.16" }, "funding": { "url": "https://github.com/sindresorhus/p-memoize?sponsor=1" } }, "node_modules/p-memoize/node_modules/mimic-fn": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-3.1.0.tgz", - "integrity": "sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-reflect": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-reflect/-/p-reflect-2.1.0.tgz", - "integrity": "sha512-paHV8NUz8zDHu5lhr/ngGWQiW067DK/+IbJ+RfZ4k+s8y4EKyYCz8pGYWjxCg35eHztpJAt+NUgvN4L+GCbPlg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-settle": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/p-settle/-/p-settle-4.1.1.tgz", - "integrity": "sha512-6THGh13mt3gypcNMm0ADqVNCcYa3BK6DWsuJWFCuEKP1rpY+OKGp7gaZwVmLspmic01+fsg/fN57MfvDzZ/PuQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", "dev": true, - "dependencies": { - "p-limit": "^2.2.2", - "p-reflect": "^2.1.0" - }, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-settle/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "node_modules/p-memoize/node_modules/type-fest": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz", + "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==", "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, "engines": { - "node": ">=6" + "node": ">=14.16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-timeout": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-4.1.0.tgz", - "integrity": "sha512-+/wmHtzJuWii1sXn3HCuH/FTwGhrp4tmJTxSKJbfS+vkipci6osxXM5mY0jUiRzWKMTgUT8l7HFbeSwZAynqHw==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-6.1.2.tgz", + "integrity": "sha512-UbD77BuZ9Bc9aABo74gfXhNvzC9Tx7SxtHSh1fxvx3jTLLYvmVhiQZZrJzqqU0jKbN32kb5VOKiLEQI/3bIjgQ==", "dev": true, "engines": { - "node": ">=10" + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-try": { @@ -5636,213 +6270,190 @@ } }, "node_modules/package-json": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", - "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-8.1.1.tgz", + "integrity": "sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==", "dev": true, "dependencies": { - "got": "^9.6.0", - "registry-auth-token": "^4.0.0", - "registry-url": "^5.0.0", - "semver": "^6.2.0" + "got": "^12.1.0", + "registry-auth-token": "^5.0.1", + "registry-url": "^6.0.0", + "semver": "^7.3.7" }, "engines": { - "node": ">=8" + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/package-json/node_modules/@sindresorhus/is": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", - "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz", + "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==", "dev": true, "engines": { - "node": ">=6" + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" } }, "node_modules/package-json/node_modules/@szmarczak/http-timer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", - "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", + "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", "dev": true, "dependencies": { - "defer-to-connect": "^1.0.1" + "defer-to-connect": "^2.0.1" }, "engines": { - "node": ">=6" + "node": ">=14.16" } }, - "node_modules/package-json/node_modules/cacheable-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", - "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "node_modules/package-json/node_modules/cacheable-lookup": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", + "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", "dev": true, - "dependencies": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^3.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^4.1.0", - "responselike": "^1.0.2" - }, "engines": { - "node": ">=8" + "node": ">=14.16" } }, - "node_modules/package-json/node_modules/cacheable-request/node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "node_modules/package-json/node_modules/cacheable-request": { + "version": "10.2.14", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.14.tgz", + "integrity": "sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==", "dev": true, "dependencies": { - "pump": "^3.0.0" + "@types/http-cache-semantics": "^4.0.2", + "get-stream": "^6.0.1", + "http-cache-semantics": "^4.1.1", + "keyv": "^4.5.3", + "mimic-response": "^4.0.0", + "normalize-url": "^8.0.0", + "responselike": "^3.0.0" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=14.16" } }, - "node_modules/package-json/node_modules/decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", + "node_modules/package-json/node_modules/got": { + "version": "12.6.1", + "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz", + "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==", "dev": true, "dependencies": { - "mimic-response": "^1.0.0" + "@sindresorhus/is": "^5.2.0", + "@szmarczak/http-timer": "^5.0.1", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^10.2.8", + "decompress-response": "^6.0.0", + "form-data-encoder": "^2.1.2", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^3.0.0" }, "engines": { - "node": ">=4" - } - }, - "node_modules/package-json/node_modules/defer-to-connect": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", - "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", - "dev": true - }, - "node_modules/package-json/node_modules/get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "dependencies": { - "pump": "^3.0.0" + "node": ">=14.16" }, - "engines": { - "node": ">=6" + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" } }, - "node_modules/package-json/node_modules/got": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", - "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "node_modules/package-json/node_modules/http2-wrapper": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.1.tgz", + "integrity": "sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==", "dev": true, "dependencies": { - "@sindresorhus/is": "^0.14.0", - "@szmarczak/http-timer": "^1.1.2", - "cacheable-request": "^6.0.0", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^4.1.0", - "lowercase-keys": "^1.0.1", - "mimic-response": "^1.0.1", - "p-cancelable": "^1.0.0", - "to-readable-stream": "^1.0.0", - "url-parse-lax": "^3.0.0" + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" }, "engines": { - "node": ">=8.6" - } - }, - "node_modules/package-json/node_modules/got/node_modules/lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", - "dev": true, - "engines": { - "node": ">=0.10.0" + "node": ">=10.19.0" } }, - "node_modules/package-json/node_modules/json-buffer": { + "node_modules/package-json/node_modules/lowercase-keys": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==", - "dev": true - }, - "node_modules/package-json/node_modules/keyv": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", - "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", "dev": true, - "dependencies": { - "json-buffer": "3.0.0" + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/package-json/node_modules/mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", + "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", "dev": true, "engines": { - "node": ">=4" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/package-json/node_modules/normalize-url": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", - "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.0.tgz", + "integrity": "sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==", "dev": true, "engines": { - "node": ">=8" + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/package-json/node_modules/p-cancelable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", - "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", + "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", "dev": true, "engines": { - "node": ">=6" + "node": ">=12.20" } }, - "node_modules/package-json/node_modules/responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==", + "node_modules/package-json/node_modules/registry-auth-token": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.2.tgz", + "integrity": "sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==", "dev": true, "dependencies": { - "lowercase-keys": "^1.0.0" - } - }, - "node_modules/package-json/node_modules/responselike/node_modules/lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", - "dev": true, + "@pnpm/npm-conf": "^2.1.0" + }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/package-json/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" + "node": ">=14" } }, - "node_modules/package-json/node_modules/to-readable-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", - "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", + "node_modules/package-json/node_modules/responselike": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", + "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", "dev": true, + "dependencies": { + "lowercase-keys": "^3.0.0" + }, "engines": { - "node": ">=6" + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/package-name-conflict": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/package-name-conflict/-/package-name-conflict-1.0.3.tgz", + "integrity": "sha512-DPBNWSUWC0wPofXeNThao0uP4a93J7r90UyhagmJS0QcacTTkorZwXYsOop70phn1hKdcf/2e9lJIhazS8bx5A==", + "dev": true + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -5855,6 +6466,15 @@ "node": ">=6" } }, + "node_modules/parent-module/node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", @@ -5873,6 +6493,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/parse-json-object": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/parse-json-object/-/parse-json-object-2.0.1.tgz", + "integrity": "sha512-/oF7PUUBjCqHmMEE6xIQeX5ZokQ9+miudACzPt4KBU2qi6CxZYPdisPXx4ad7wpZJYi2ZpcW2PacLTU3De3ebw==", + "dev": true, + "dependencies": { + "types-json": "^1.2.0" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -5949,15 +6578,100 @@ } }, "node_modules/pkg-dir": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-5.0.0.tgz", - "integrity": "sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", + "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", "dev": true, "dependencies": { - "find-up": "^5.0.0" + "find-up": "^6.3.0" }, "engines": { - "node": ">=10" + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", + "dev": true, + "dependencies": { + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "dev": true, + "dependencies": { + "p-locate": "^6.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "dev": true, + "dependencies": { + "p-limit": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/pkg-dir/node_modules/yocto-queue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/pkg-types": { @@ -6008,27 +6722,18 @@ "node": ">= 0.8.0" } }, - "node_modules/prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, "dependencies": { - "ansi-regex": "^5.0.1", + "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" + "react-is": "^18.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/pretty-format/node_modules/ansi-styles": { @@ -6043,6 +6748,21 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "dev": true + }, "node_modules/pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -6054,33 +6774,27 @@ } }, "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/pupa": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.1.1.tgz", - "integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, - "dependencies": { - "escape-goat": "^2.0.0" - }, "engines": { - "node": ">=8" + "node": ">=6" } }, - "node_modules/pupa/node_modules/escape-goat": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", - "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", + "node_modules/pupa": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-3.1.0.tgz", + "integrity": "sha512-FLpr4flz5xZTSJxSeaheeMKN/EDzMdK7b8PTOC6a5PYFKTucWbdqjgqaEyH0shFiSJrVB1+Qqi4Tk19ccU6Aug==", "dev": true, + "dependencies": { + "escape-goat": "^4.0.0" + }, "engines": { - "node": ">=8" + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/queue-microtask": { @@ -6104,12 +6818,15 @@ ] }, "node_modules/quick-lru": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", - "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", "dev": true, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/rc": { @@ -6127,6 +6844,12 @@ "rc": "cli.js" } }, + "node_modules/rc/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, "node_modules/rc/node_modules/strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", @@ -6137,160 +6860,189 @@ } }, "node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "dev": true }, + "node_modules/read-file-safe": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/read-file-safe/-/read-file-safe-1.0.10.tgz", + "integrity": "sha512-qW25fd2uMX3dV6Ui/R0jYK1MhTpjx8FO/VHaHTXzwWsGnkNwLRcqYfCXd9qDM+NZ273DPUvP2RaimYuLSu1K/g==", + "dev": true + }, + "node_modules/read-json-safe": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/read-json-safe/-/read-json-safe-1.0.5.tgz", + "integrity": "sha512-SJyNY/U9+vW35FPus22Qvv1oilnR7PCfN2E70uKQEGaJS313A5/cz9Yhv7ZtWzZ+XIwrtEPxXf10BOyYemHehA==", + "dev": true, + "dependencies": { + "parse-json-object": "^1.0.5", + "read-file-safe": "^1.0.5" + } + }, + "node_modules/read-json-safe/node_modules/parse-json-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/parse-json-object/-/parse-json-object-1.1.0.tgz", + "integrity": "sha512-4w5s6uJY1tW9REY8UwUOyaZKSKsrbQrMEzlV/Le/g5t4iMWuuyK83pZZ0OZimSOL9iyv2ORvRSgz71Ekd7iD3g==", + "dev": true, + "dependencies": { + "types-json": "^1.0.6" + } + }, "node_modules/read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-7.1.0.tgz", + "integrity": "sha512-5iOehe+WF75IccPc30bWTbpdDQLOCc3Uu8bi3Dte3Eueij81yx1Mrufk8qBx/YAbR4uL1FdUr+7BKXDwEtisXg==", "dev": true, "dependencies": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" + "@types/normalize-package-data": "^2.4.1", + "normalize-package-data": "^3.0.2", + "parse-json": "^5.2.0", + "type-fest": "^2.0.0" }, "engines": { - "node": ">=8" + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-9.1.0.tgz", + "integrity": "sha512-vaMRR1AC1nrd5CQM0PhlRsO5oc2AAigqr7cCrZ/MW/Rsaflz4RlgzkpL4qoU/z1F6wrbd85iFv1OQj/y5RdGvg==", "dev": true, "dependencies": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" + "find-up": "^6.3.0", + "read-pkg": "^7.1.0", + "type-fest": "^2.5.0" }, "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/read-pkg-up/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", "dev": true, "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" }, "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/read-pkg-up/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", "dev": true, "dependencies": { - "p-locate": "^4.1.0" + "p-locate": "^6.0.0" }, "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/read-pkg-up/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", "dev": true, "dependencies": { - "p-try": "^2.0.0" + "yocto-queue": "^1.0.0" }, "engines": { - "node": ">=6" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/read-pkg-up/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", "dev": true, "dependencies": { - "p-limit": "^2.2.0" + "p-limit": "^4.0.0" }, "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/read-pkg-up/node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "node_modules/read-pkg-up/node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", "dev": true, "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, - "node_modules/read-pkg/node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "node_modules/read-pkg/node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "node_modules/read-pkg-up/node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", "dev": true, - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/read-pkg/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "node_modules/read-pkg-up/node_modules/yocto-queue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", "dev": true, - "bin": { - "semver": "bin/semver" + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/read-pkg/node_modules/type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", "dev": true, "engines": { - "node": ">=8" + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/redent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", - "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dev": true, "dependencies": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" }, "engines": { - "node": ">=8" - } - }, - "node_modules/redent/node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "engines": { - "node": ">=8" + "node": ">= 6" } }, "node_modules/regexp.prototype.flags": { @@ -6323,15 +7075,18 @@ } }, "node_modules/registry-url": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", - "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-6.0.1.tgz", + "integrity": "sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==", "dev": true, "dependencies": { - "rc": "^1.2.8" + "rc": "1.2.8" }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/resolve": { @@ -6351,6 +7106,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "dev": true + }, "node_modules/resolve-cwd": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", @@ -6466,6 +7227,86 @@ "estree-walker": "^0.6.1" } }, + "node_modules/run-applescript": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz", + "integrity": "sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==", + "dev": true, + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-applescript/node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/run-applescript/node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/run-applescript/node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-applescript/node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/run-applescript/node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/run-async": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", @@ -6528,6 +7369,26 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/safe-regex-test": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", @@ -6549,12 +7410,15 @@ "dev": true }, "node_modules/scoped-regex": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/scoped-regex/-/scoped-regex-2.1.0.tgz", - "integrity": "sha512-g3WxHrqSWCZHGHlSrF51VXFdjImhwvH8ZO/pryFH56Qi0cDsZfylQa/t0jCzVQFNbNvM00HfHjkDPEuarKDSWQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/scoped-regex/-/scoped-regex-3.0.0.tgz", + "integrity": "sha512-yEsN6TuxZhZ1Tl9iB81frTNS292m0I/IG7+w8lTvfcJQP2x3vnpOoevjBoE3Np5A6KnZM2+RtVenihj9t6NiYg==", "dev": true, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/semver": { @@ -6573,24 +7437,18 @@ } }, "node_modules/semver-diff": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", - "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-4.0.0.tgz", + "integrity": "sha512-0Ju4+6A8iOnpL/Thra7dZsSlOHYAHIeMxfhWQRI1/VLcT3WDBZKKtQt/QkBOsiIN9ZpuvHE6cGZ0x4glCMmfiA==", "dev": true, "dependencies": { - "semver": "^6.3.0" + "semver": "^7.3.5" }, "engines": { - "node": ">=8" - } - }, - "node_modules/semver-diff/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/shebang-command": { @@ -6704,29 +7562,17 @@ "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", "dev": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.13", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz", - "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==", - "dev": true - }, - "node_modules/split": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", - "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", - "dev": true, - "dependencies": { - "through": "2" - }, - "engines": { - "node": "*" + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" } }, + "node_modules/spdx-license-ids": { + "version": "3.0.16", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz", + "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==", + "dev": true + }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", @@ -6745,13 +7591,13 @@ "integrity": "sha512-Rz6yejtVyWnVjC1RFvNmYL10kgjC49EOghxWn0RFqlCHGFpQx+Xe7yW3I4ceK1SGrWIGMjD5Kbue8W/udkbMJg==", "dev": true }, - "node_modules/streamsearch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", - "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, - "engines": { - "node": ">=10.0.0" + "dependencies": { + "safe-buffer": "~5.2.0" } }, "node_modules/string-argv": { @@ -6835,24 +7681,15 @@ } }, "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-indent": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", + "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", "dev": true, - "dependencies": { - "min-indent": "^1.0.0" - }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/strip-json-comments": { @@ -6917,25 +7754,52 @@ } }, "node_modules/symbol-observable": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-3.0.0.tgz", - "integrity": "sha512-6tDOXSHiVjuCaasQSWTmHUWn4PuG7qa3+1WT031yTc/swT7+rLiw3GOrFxaH1E3lLP09dH3bVuVDf2gK5rxG3Q==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", + "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==", "dev": true, "engines": { "node": ">=0.10" } }, "node_modules/terminal-link": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", - "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-3.0.0.tgz", + "integrity": "sha512-flFL3m4wuixmf6IfhFJd1YPiLiMuxEc8uHRM1buzIeZPm22Au2pDqBJQgdo7n1WfPU1ONFGv7YDwpFBmHGF6lg==", "dev": true, "dependencies": { - "ansi-escapes": "^4.2.1", - "supports-hyperlinks": "^2.0.0" + "ansi-escapes": "^5.0.0", + "supports-hyperlinks": "^2.2.0" }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/terminal-link/node_modules/ansi-escapes": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-5.0.0.tgz", + "integrity": "sha512-5GFMVX8HqE/TB+FuBJGuO5XG0WrsA6ptUqoODaT/n9mmUaZFkqnBueB4leqGBCmrUHnCnC4PCZTCd0E7QQ83bA==", + "dev": true, + "dependencies": { + "type-fest": "^1.0.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/terminal-link/node_modules/type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "dev": true, + "engines": { + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -6953,15 +7817,6 @@ "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", "dev": true }, - "node_modules/time-zone": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/time-zone/-/time-zone-1.0.0.tgz", - "integrity": "sha512-TIsDdtKo6+XrPtiTm1ssmMngN1sAhyKnTO2kunQWqNPWIVvCm15Wmw4SWInwTVgJ5u/Tr04+8Ei9TNcw4x4ONA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/tinybench": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.5.0.tgz", @@ -6969,23 +7824,35 @@ "dev": true }, "node_modules/tinypool": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.4.0.tgz", - "integrity": "sha512-2ksntHOKf893wSAH4z/+JbPpi92esw8Gn9N2deXX+B0EO92hexAVI9GIZZPx7P5aYo5KULfeOSt3kMOmSOy6uA==", + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.7.0.tgz", + "integrity": "sha512-zSYNUlYSMhJ6Zdou4cJwo/p7w5nmAH17GRfU/ui3ctvjXFErXXkruT4MWW6poDeXgCaIBlGLrfU6TbTXxyGMww==", "dev": true, "engines": { "node": ">=14.0.0" } }, "node_modules/tinyspy": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.1.1.tgz", - "integrity": "sha512-XPJL2uSzcOyBMky6OFrusqWlzfFrXtE0hPuMgW8A2HmaqrPo4ZQHRN/V0QXN3FSjKxpsbRrFc5LI7KOwBsT1/w==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.0.tgz", + "integrity": "sha512-d2eda04AN/cPOR89F7Xv5bK/jrQEhmcLFe6HFldoeO9AJtps+fqEnh486vnT/8y4bw38pSyxDcTCAq+Ks2aJTg==", "dev": true, "engines": { "node": ">=14.0.0" } }, + "node_modules/titleize": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz", + "integrity": "sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -6998,15 +7865,6 @@ "node": ">=0.6.0" } }, - "node_modules/to-readable-stream": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-2.1.0.tgz", - "integrity": "sha512-o3Qa6DGg1CEXshSdvWNX2sN4QHqg03SPq7U6jPXRahlQdl5dK8oXjkU/2/sGrnOZKeGV1zLSO8qPwyKklPPE7w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -7019,13 +7877,16 @@ "node": ">=8.0" } }, - "node_modules/trim-newlines": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", - "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", + "node_modules/ts-api-utils": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", + "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", "dev": true, "engines": { - "node": ">=8" + "node": ">=16.13.0" + }, + "peerDependencies": { + "typescript": ">=4.2.0" } }, "node_modules/tslib": { @@ -7034,21 +7895,6 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - } - }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -7156,23 +8002,48 @@ "is-typedarray": "^1.0.0" } }, + "node_modules/types-eslintrc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/types-eslintrc/-/types-eslintrc-1.0.3.tgz", + "integrity": "sha512-zKTR6aKHEudQpl+JoZjS3qh0B5IzSpQK/BCpYBECujcnKtqL87DJJ1sJKe5B8k/y8/UJ5sukq42QDvlaJyCO2w==", + "dev": true, + "dependencies": { + "types-json": "^1.2.2" + } + }, + "node_modules/types-json": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/types-json/-/types-json-1.2.2.tgz", + "integrity": "sha512-VfVLISHypS7ayIHvhacOESOTib4Sm4mAhnsgR8fzQdGp89YoBwMqvGmqENjtYehUQzgclT+7NafpEXkK/MHKwA==", + "dev": true + }, + "node_modules/types-pkg-json": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/types-pkg-json/-/types-pkg-json-1.2.1.tgz", + "integrity": "sha512-Wj75lCkPwfj1BhmaJxMPpTQj9YGpihjs3WICigt1IjTAswr7zPXP0iJYPZjU0Rw/IriODhMJjAImkCIxt9KeuQ==", + "dev": true, + "dependencies": { + "types-eslintrc": "^1.0.3", + "types-json": "^1.2.2" + } + }, "node_modules/typescript": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", - "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=12.20" + "node": ">=14.17" } }, "node_modules/ufo": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.2.0.tgz", - "integrity": "sha512-RsPyTbqORDNDxqAdQPQBpgqhWle1VcTSou/FraClYlHf6TZnQcGslpLcAphNR+sQW4q5lLWLbOsRlh9j24baQg==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.3.2.tgz", + "integrity": "sha512-o+ORpgGwaYQXgqGDwd+hkS4PuZ3QnmqMMxRuajK/a38L6fTpcE5GPIfrf+L/KemFzfUpeUQc1rRS1iDBozvnFA==", "dev": true }, "node_modules/unbox-primitive": { @@ -7191,27 +8062,36 @@ } }, "node_modules/undici": { - "version": "5.22.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.22.0.tgz", - "integrity": "sha512-fR9RXCc+6Dxav4P9VV/sp5w3eFiSdOjJYsbtWfd4s5L5C4ogyuVpdKIVHeW0vV1MloM65/f7W45nR9ZxwVdyiA==", + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.26.0.tgz", + "integrity": "sha512-MLqGMyaJk2ubSl7FrmWuV7ZOsYWmdF7gcBHDRxm4AR8NoodQhgy3vO/D1god79HoetxR0uAeVNB65yj2lNRQnQ==", "dev": true, "dependencies": { - "busboy": "^1.6.0" + "@fastify/busboy": "^2.0.0" }, "engines": { "node": ">=14.0" } }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, "node_modules/unique-string": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", - "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz", + "integrity": "sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==", "dev": true, "dependencies": { - "crypto-random-string": "^2.0.0" + "crypto-random-string": "^4.0.0" }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/universalify": { @@ -7223,81 +8103,53 @@ "node": ">= 4.0.0" } }, - "node_modules/update-notifier": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-5.1.0.tgz", - "integrity": "sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==", + "node_modules/untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", "dev": true, - "dependencies": { - "boxen": "^5.0.0", - "chalk": "^4.1.0", - "configstore": "^5.0.1", - "has-yarn": "^2.1.0", - "import-lazy": "^2.1.0", - "is-ci": "^2.0.0", - "is-installed-globally": "^0.4.0", - "is-npm": "^5.0.0", - "is-yarn-global": "^0.3.0", - "latest-version": "^5.1.0", - "pupa": "^2.1.1", - "semver": "^7.3.4", - "semver-diff": "^3.1.1", - "xdg-basedir": "^4.0.0" - }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/yeoman/update-notifier?sponsor=1" + "node": ">=8" } }, - "node_modules/update-notifier/node_modules/global-dirs": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", - "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==", + "node_modules/update-notifier": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-6.0.2.tgz", + "integrity": "sha512-EDxhTEVPZZRLWYcJ4ZXjGFN0oP7qYvbXWzEgRm/Yql4dHX5wDbvh89YHP6PK1lzZJYrMtXUuZZz8XGK+U6U1og==", "dev": true, "dependencies": { - "ini": "2.0.0" + "boxen": "^7.0.0", + "chalk": "^5.0.1", + "configstore": "^6.0.0", + "has-yarn": "^3.0.0", + "import-lazy": "^4.0.0", + "is-ci": "^3.0.1", + "is-installed-globally": "^0.4.0", + "is-npm": "^6.0.0", + "is-yarn-global": "^0.4.0", + "latest-version": "^7.0.0", + "pupa": "^3.1.0", + "semver": "^7.3.7", + "semver-diff": "^4.0.0", + "xdg-basedir": "^5.1.0" }, "engines": { - "node": ">=10" + "node": ">=14.16" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/update-notifier/node_modules/import-lazy": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", - "integrity": "sha512-m7ZEHgtw69qOGw+jwxXkHlrlIPdTGkyh66zXZ1ajZbxkDBNjSY/LGbmjc7h0s2ELsUDTAhFr55TrPSSqJGPG0A==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/update-notifier/node_modules/ini": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", - "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", - "dev": true, - "engines": { - "node": ">=10" + "url": "https://github.com/yeoman/update-notifier?sponsor=1" } }, - "node_modules/update-notifier/node_modules/is-installed-globally": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", - "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "node_modules/update-notifier/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", "dev": true, - "dependencies": { - "global-dirs": "^3.0.0", - "is-path-inside": "^3.0.2" - }, "engines": { - "node": ">=10" + "node": "^12.17.0 || ^14.13 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, "node_modules/uri-js": { @@ -7309,17 +8161,11 @@ "punycode": "^2.1.0" } }, - "node_modules/url-parse-lax": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", - "integrity": "sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==", - "dev": true, - "dependencies": { - "prepend-http": "^2.0.0" - }, - "engines": { - "node": ">=4" - } + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true }, "node_modules/vali-date": { "version": "1.0.0", @@ -7359,14 +8205,14 @@ } }, "node_modules/vite": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.3.tgz", - "integrity": "sha512-MwFlLBO4udZXd+VBcezo3u8mC77YQk+ik+fbc0GZWGgzfbPP+8Kf0fldhARqvSYmtIWoAJ5BXPClUbMTlqFxrA==", + "version": "4.4.11", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.11.tgz", + "integrity": "sha512-ksNZJlkcU9b0lBwAGZGGaZHCMqHsc8OpgtoYhsQ4/I2v5cnpmmmqe5pM4nv/4Hn6G/2GhTdj0DhZh2e+Er1q5A==", "dev": true, "dependencies": { - "esbuild": "^0.17.5", - "postcss": "^8.4.23", - "rollup": "^3.21.0" + "esbuild": "^0.18.10", + "postcss": "^8.4.27", + "rollup": "^3.27.1" }, "bin": { "vite": "bin/vite.js" @@ -7374,12 +8220,16 @@ "engines": { "node": "^14.18.0 || >=16.0.0" }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, "optionalDependencies": { "fsevents": "~2.3.2" }, "peerDependencies": { "@types/node": ">= 14", "less": "*", + "lightningcss": "^1.21.0", "sass": "*", "stylus": "*", "sugarss": "*", @@ -7392,6 +8242,9 @@ "less": { "optional": true }, + "lightningcss": { + "optional": true + }, "sass": { "optional": true }, @@ -7407,17 +8260,17 @@ } }, "node_modules/vite-node": { - "version": "0.30.1", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.30.1.tgz", - "integrity": "sha512-vTikpU/J7e6LU/8iM3dzBo8ZhEiKZEKRznEMm+mJh95XhWaPrJQraT/QsT2NWmuEf+zgAoMe64PKT7hfZ1Njmg==", + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.34.6.tgz", + "integrity": "sha512-nlBMJ9x6n7/Amaz6F3zJ97EBwR2FkzhBRxF5e+jE6LA3yi6Wtc2lyTij1OnDMIr34v5g/tVQtsVAzhT0jc5ygA==", "dev": true, "dependencies": { "cac": "^6.7.14", "debug": "^4.3.4", - "mlly": "^1.2.0", - "pathe": "^1.1.0", + "mlly": "^1.4.0", + "pathe": "^1.1.1", "picocolors": "^1.0.0", - "vite": "^3.0.0 || ^4.0.0" + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0-0" }, "bin": { "vite-node": "vite-node.mjs" @@ -7426,40 +8279,38 @@ "node": ">=v14.18.0" }, "funding": { - "url": "https://github.com/sponsors/antfu" + "url": "https://opencollective.com/vitest" } }, "node_modules/vitest": { - "version": "0.30.1", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.30.1.tgz", - "integrity": "sha512-y35WTrSTlTxfMLttgQk4rHcaDkbHQwDP++SNwPb+7H8yb13Q3cu2EixrtHzF27iZ8v0XCciSsLg00RkPAzB/aA==", + "version": "0.34.6", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-0.34.6.tgz", + "integrity": "sha512-+5CALsOvbNKnS+ZHMXtuUC7nL8/7F1F2DnHGjSsszX8zCjWSSviphCb/NuS9Nzf4Q03KyyDRBAXhF/8lffME4Q==", "dev": true, "dependencies": { - "@types/chai": "^4.3.4", + "@types/chai": "^4.3.5", "@types/chai-subset": "^1.3.3", "@types/node": "*", - "@vitest/expect": "0.30.1", - "@vitest/runner": "0.30.1", - "@vitest/snapshot": "0.30.1", - "@vitest/spy": "0.30.1", - "@vitest/utils": "0.30.1", - "acorn": "^8.8.2", + "@vitest/expect": "0.34.6", + "@vitest/runner": "0.34.6", + "@vitest/snapshot": "0.34.6", + "@vitest/spy": "0.34.6", + "@vitest/utils": "0.34.6", + "acorn": "^8.9.0", "acorn-walk": "^8.2.0", "cac": "^6.7.14", - "chai": "^4.3.7", - "concordance": "^5.0.4", + "chai": "^4.3.10", "debug": "^4.3.4", "local-pkg": "^0.4.3", - "magic-string": "^0.30.0", - "pathe": "^1.1.0", + "magic-string": "^0.30.1", + "pathe": "^1.1.1", "picocolors": "^1.0.0", - "source-map": "^0.6.1", - "std-env": "^3.3.2", + "std-env": "^3.3.3", "strip-literal": "^1.0.1", - "tinybench": "^2.4.0", - "tinypool": "^0.4.0", - "vite": "^3.0.0 || ^4.0.0", - "vite-node": "0.30.1", + "tinybench": "^2.5.0", + "tinypool": "^0.7.0", + "vite": "^3.1.0 || ^4.0.0 || ^5.0.0-0", + "vite-node": "0.34.6", "why-is-node-running": "^2.2.2" }, "bin": { @@ -7469,7 +8320,7 @@ "node": ">=v14.18.0" }, "funding": { - "url": "https://github.com/sponsors/antfu" + "url": "https://opencollective.com/vitest" }, "peerDependencies": { "@edge-runtime/vm": "*", @@ -7520,13 +8371,13 @@ "node": ">=12" } }, - "node_modules/well-known-symbols": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/well-known-symbols/-/well-known-symbols-2.0.0.tgz", - "integrity": "sha512-ZMjC3ho+KXo0BfJb7JgtQ5IBuvnShdlACNkKkdsqBmYw3bPAaJfPeYUo6tLUaT5tG/Gkh7xkpBhKRQ9e7pyg9Q==", + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", "dev": true, - "engines": { - "node": ">=6" + "dependencies": { + "defaults": "^1.0.3" } }, "node_modules/which": { @@ -7596,15 +8447,68 @@ } }, "node_modules/widest-line": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", - "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", + "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", "dev": true, "dependencies": { - "string-width": "^4.0.0" + "string-width": "^5.0.1" }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/widest-line/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/widest-line/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/widest-line/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/widest-line/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, "node_modules/wrap-ansi": { @@ -7682,12 +8586,15 @@ } }, "node_modules/xdg-basedir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", - "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-5.1.0.tgz", + "integrity": "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==", "dev": true, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/yallist": { @@ -7696,24 +8603,6 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, - "node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "engines": { - "node": ">=10" - } - }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", @@ -7745,6 +8634,16 @@ "optionalDependencies": { "commander": "^9.4.1" } + }, + "node_modules/z-schema/node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "dev": true, + "optional": true, + "engines": { + "node": "^12.20.0 || >=14" + } } } } diff --git a/packages/qwik-speak/package.json b/packages/qwik-speak/package.json index 8a233c4..b42f92c 100644 --- a/packages/qwik-speak/package.json +++ b/packages/qwik-speak/package.json @@ -17,24 +17,24 @@ "qwik-speak-extract": "./extract/cli.js" }, "peerDependencies": { - "@builder.io/qwik": ">=1.1.4" + "@builder.io/qwik": ">=1.2.18" }, "devDependencies": { - "@builder.io/qwik": "1.1.4", - "@microsoft/api-documenter": "^7.22.3", - "@microsoft/api-extractor": "^7.36.1", - "@types/eslint": "8.37.0", - "@types/node": "^18.16.1", - "@typescript-eslint/eslint-plugin": "5.59.1", - "@typescript-eslint/parser": "5.59.1", - "eslint": "8.39.0", - "eslint-plugin-qwik": "1.1.4", - "np": "^7.7.0", + "@builder.io/qwik": "1.2.18", + "@microsoft/api-documenter": "^7.23.12", + "@microsoft/api-extractor": "^7.38.3", + "@types/eslint": "8.44.4", + "@types/node": "^20.8.4", + "@typescript-eslint/eslint-plugin": "6.7.5", + "@typescript-eslint/parser": "6.7.5", + "eslint": "8.51.0", + "eslint-plugin-qwik": "1.2.18", + "np": "^8.0.4", "rollup-plugin-add-shebang": "^0.3.1", - "typescript": "5.0.4", - "undici": "5.22.0", - "vite": "4.3.3", - "vitest": "^0.30.1" + "typescript": "5.2.2", + "undici": "5.26.0", + "vite": "4.4.11", + "vitest": "^0.34.6" }, "main": "./lib/index.qwik.cjs", "module": "./lib/index.qwik.mjs", diff --git a/packages/qwik-speak/src/context.ts b/packages/qwik-speak/src/context.ts index 9959023..c620ca2 100644 --- a/packages/qwik-speak/src/context.ts +++ b/packages/qwik-speak/src/context.ts @@ -1,5 +1,54 @@ import { createContextId } from '@builder.io/qwik'; +import { isServer } from '@builder.io/qwik/build'; import type { SpeakState } from './types'; -export const SpeakContext = createContextId('qwikspeak'); +type DeepPartial = T extends object ? { + [P in keyof T]?: DeepPartial; +} : T; + +/** + * Qwik context (per user) + */ +export const SpeakContext = createContextId('qwik-speak'); + +/** + * Qwik Speak server context (shared) + */ +const _speakServerContext: DeepPartial = { + translation: {}, + config: {} +}; + +/** + * Qwik Speak client context (per user) + */ +const _speakClientContext: DeepPartial = { + translation: {}, + config: {}, + locale: {} +}; + +/** + * Return Qwik Speak server or client context + */ +export const getSpeakContext = (): SpeakState => { + if (isServer) { + return _speakServerContext as SpeakState; + } else { + return _speakClientContext as SpeakState; + } +} + +/** + * Qwik Speak function to get language + */ +export let getLang = (): string => ''; + +/** + * Set getLang function + * @param fn + */ +export const setGetLangFn = (fn: () => string) => { + getLang = () => fn(); +}; diff --git a/packages/qwik-speak/src/core.ts b/packages/qwik-speak/src/core.ts index 5be6522..cf321be 100644 --- a/packages/qwik-speak/src/core.ts +++ b/packages/qwik-speak/src/core.ts @@ -1,13 +1,13 @@ -import { noSerialize } from '@builder.io/qwik'; import { isDev, isServer } from '@builder.io/qwik/build'; import type { Translation, SpeakState, LoadTranslationFn } from './types'; +import { getSpeakContext } from './context'; import { logWarn } from './log'; const cache: Record> = {}; /** - * In SPA mode, cache the results + * Cache the requests on server and on client in SPA mode */ export const memoize = (fn: LoadTranslationFn) => { return (...args: [string, string]) => { @@ -21,10 +21,9 @@ export const memoize = (fn: LoadTranslationFn) => { /** * Load translations when: - * - dev mode * - on server * - or runtime assets - * In prod mode, assets are not serialized + * runtimeAssets are serialized */ export const loadTranslations = async ( ctx: SpeakState, @@ -32,8 +31,10 @@ export const loadTranslations = async ( runtimeAssets?: string[], langs?: string[] ): Promise => { - if (isDev || isServer || runtimeAssets) { + if (isServer || runtimeAssets) { const { locale, translation, translationFn, config } = ctx; + // Qwik Speak server/client context + const { translation: _translation } = getSpeakContext(); if (isDev) { const conflictingAsset = assets?.find(asset => runtimeAssets?.includes(asset)) || @@ -45,7 +46,7 @@ export const loadTranslations = async ( } let resolvedAssets: string[]; - if (isDev || isServer) { + if (isServer) { resolvedAssets = [...assets ?? [], ...runtimeAssets ?? []]; } else { resolvedAssets = [...runtimeAssets ?? []]; @@ -57,28 +58,43 @@ export const loadTranslations = async ( resolvedLangs.add(locale.lang); for (const lang of resolvedLangs) { - const memoized = memoize(translationFn.loadTranslation$); - const tasks = resolvedAssets.map(asset => memoized(lang, asset)); + let tasks: Promise[]; + // Cache requests in prod mode + if (!isDev) { + const memoized = memoize(translationFn.loadTranslation$); + tasks = resolvedAssets.map(asset => memoized(lang, asset)); + } else { + tasks = resolvedAssets.map(asset => translationFn.loadTranslation$(lang, asset)); + } + const sources = await Promise.all(tasks); const assetSources = sources.map((source, i) => ({ asset: resolvedAssets[i], source: source })); + // Set Qwik Speak server/client context + if (!(lang in _translation)) { + Object.assign(_translation, { [lang]: {} }); + } + for (const data of assetSources) { if (data?.source) { - if (!isDev && isServer && assets?.includes(data.asset)) { - // In prod mode, assets are not serialized - for (let [key, value] of Object.entries(data.source)) { - // Depth 0: convert string to String object - if (typeof value === 'string') { - value = new String(value); - } - translation[lang][key] = noSerialize(value); + if (isServer) { + // On server: + // - assets & runtimeAssets in Qwik Speak server context + // - runtimeAssets in Qwik context (must be serialized to be passed to the client) + if (assets?.includes(data.asset)) { + Object.assign(_translation[lang], data.source); + } else { + Object.assign(_translation[lang], data.source); + // Serialize runtimeAssets + Object.assign(translation[lang], data.source); } } else { - // Serialize whether dev mode, or runtime assets - Object.assign(translation[lang], data.source); + // On client: + // - assets & runtimeAssets in Qwik Speak client context + Object.assign(_translation[lang], data.source); } } } @@ -106,8 +122,8 @@ export const getValue = ( undefined, data); if (value) { - if (typeof value === 'string' || value instanceof String) - return params ? transpileParams(value.toString(), params) : value.toString(); + if (typeof value === 'string') + return params ? transpileParams(value, params) : value; if (typeof value === 'object') return params ? JSON.parse(transpileParams(JSON.stringify(value), params)) : value; } diff --git a/packages/qwik-speak/src/index.ts b/packages/qwik-speak/src/index.ts index 15df14b..f38518a 100644 --- a/packages/qwik-speak/src/index.ts +++ b/packages/qwik-speak/src/index.ts @@ -8,25 +8,26 @@ export type { LoadTranslationFn, RewriteRouteOption } from './types'; -export type { QwikSpeakProps } from './qwik-speak-component'; -export type { SpeakProps } from './speak-component'; -export type { TranslateFn } from './use-translate'; -export type { TranslatePathFn } from './use-translate-path'; -export type { PluralFn } from './use-plural'; +export type { QwikSpeakProps, QwikSpeakMockProps } from './use-qwik-speak'; +export type { SpeakProps } from './use-speak'; +export type { LocalizePathFn } from './localize-path'; +export type { TranslatePathFn } from './translate-path'; +export type { InlinePluralFn } from './inline-plural'; export type { InlineTranslateFn } from './inline-translate'; export type { FormatDateFn } from './use-format-date'; export type { FormatNumberFn } from './use-format-number'; export type { RelativeTimeFn } from './use-relative-time'; export type { DisplayNameFn } from './use-display-name'; -// Components -export { QwikSpeakProvider } from './qwik-speak-component'; -export { Speak, useSpeak } from './speak-component'; -// Functions +// Inline functions export { inlineTranslate } from './inline-translate'; +export { inlinePlural } from './inline-plural'; +// Functions +export { localizePath } from './localize-path'; +export { translatePath } from './translate-path'; +export { validateLocale } from './validate-locale'; // Use functions -export { useTranslate } from './use-translate'; -export { useTranslatePath } from './use-translate-path'; -export { usePlural } from './use-plural'; +export { useQwikSpeak } from './use-qwik-speak'; +export { useSpeak } from './use-speak'; export { useFormatNumber } from './use-format-number'; export { useFormatDate } from './use-format-date'; export { useRelativeTime } from './use-relative-time'; @@ -35,4 +36,6 @@ export { useSpeakContext, useSpeakLocale, useSpeakConfig, -} from './use-speak'; +} from './use-functions'; +// Testing +export { QwikSpeakMockProvider } from './use-qwik-speak'; diff --git a/packages/qwik-speak/src/use-plural.ts b/packages/qwik-speak/src/inline-plural.ts similarity index 76% rename from packages/qwik-speak/src/use-plural.ts rename to packages/qwik-speak/src/inline-plural.ts index 65bff67..f0e3019 100644 --- a/packages/qwik-speak/src/use-plural.ts +++ b/packages/qwik-speak/src/inline-plural.ts @@ -1,8 +1,7 @@ -import { noSerialize } from '@builder.io/qwik'; -import { useSpeakContext } from './use-speak'; import { getValue } from './core'; +import { getLang, getSpeakContext } from './context'; -export type PluralFn = { +export type InlinePluralFn = { /** * Get the plural by a number. * The value is passed as a parameter to the translate function @@ -22,8 +21,8 @@ export type PluralFn = { ): string; }; -export const usePlural = (): PluralFn => { - const ctx = useSpeakContext(); +export const inlinePlural = (): InlinePluralFn => { + const currentLang = getLang(); const plural = ( value: number | string, @@ -32,8 +31,9 @@ export const usePlural = (): PluralFn => { options?: Intl.PluralRulesOptions, lang?: string ) => { - const { locale, translation, config } = ctx; - lang ??= locale.lang; + const { translation, config } = getSpeakContext(); + + lang ??= currentLang; value = +value; @@ -43,5 +43,5 @@ export const usePlural = (): PluralFn => { return getValue(key, translation[lang], { value, ...params }, config.keySeparator, config.keyValueSeparator); }; - return noSerialize(plural) as PluralFn; + return plural as InlinePluralFn; }; diff --git a/packages/qwik-speak/src/inline-translate.ts b/packages/qwik-speak/src/inline-translate.ts index 0d30cab..ef79db1 100644 --- a/packages/qwik-speak/src/inline-translate.ts +++ b/packages/qwik-speak/src/inline-translate.ts @@ -1,44 +1,43 @@ -import type { SpeakState } from './types'; import { getValue } from './core'; +import { getLang, getSpeakContext } from './context'; export type InlineTranslateFn = { /** - * Translate a key outside the component$. + * Translate a key. * The syntax of the string is 'key@@[default value]' * @param key The key to translate - * @param ctx The Speak context * @param params Optional parameters contained in the value * @param lang Optional language if different from the current one * @returns The translation or the key if not found */ - (key: string, ctx: SpeakState, params?: Record, lang?: string): string; - (key: string, ctx: SpeakState, params?: Record, lang?: string): T; + (key: string, params?: Record, lang?: string): string; + (key: string, params?: Record, lang?: string): T; /** - * Translate an array of keys outside the component$. + * Translate an array of keys. * The syntax of the strings is 'key@@[default value]' * @param keys The array of keys to translate - * @param ctx The Speak context * @param params Optional parameters contained in the values * @param lang Optional language if different from the current one * @returns The translations or the keys if not found */ - (keys: string[], ctx: SpeakState, params?: Record, lang?: string): string[]; - (keys: string[], ctx: SpeakState, params?: Record, lang?: string): T[]; + (keys: string[], params?: Record, lang?: string): string[]; + (keys: string[], params?: Record, lang?: string): T[]; }; -export const inlineTranslate: InlineTranslateFn = ( - keys: string | string[], - ctx: SpeakState, - params?: Record, - lang?: string -) => { - const { locale, translation, config } = ctx; +export const inlineTranslate = (): InlineTranslateFn => { + const currentLang = getLang(); - lang ??= locale.lang; + const translate = (keys: string | string[], params?: Record, lang?: string) => { + const { translation, config } = getSpeakContext(); - if (Array.isArray(keys)) { - return keys.map(k => getValue(k, translation[lang!], params, config.keySeparator, config.keyValueSeparator)); - } + lang ??= currentLang; - return getValue(keys, translation[lang], params, config.keySeparator, config.keyValueSeparator); + if (Array.isArray(keys)) { + return keys.map(k => getValue(k, translation[lang!], params, config.keySeparator, config.keyValueSeparator)); + } + + return getValue(keys, translation[lang], params, config.keySeparator, config.keyValueSeparator); + }; + + return translate as InlineTranslateFn; }; diff --git a/packages/qwik-speak/src/localize-path.ts b/packages/qwik-speak/src/localize-path.ts new file mode 100644 index 0000000..6d481c5 --- /dev/null +++ b/packages/qwik-speak/src/localize-path.ts @@ -0,0 +1,66 @@ +import { getLang, getSpeakContext } from './context'; + +export type LocalizePathFn = { + /** + * Localize a path with the language + * @param pathname The path to localize + * @param lang Optional language if different from the default one + * @returns The localized path + */ + (pathname: string, lang?: string): string; + /** + * Localize an url with the language + * @param url The url to localize + * @param lang Optional language if different from the default one + * @returns The localized url + */ + (url: URL, lang?: string): string; + /** + * Localize an array of paths with the language + * @param pathnames The array of paths to localize + * @param lang Optional language if different from the default one + * @returns The localized paths + */ + (pathnames: string[], lang?: string): string[]; +}; + +export const localizePath = (): LocalizePathFn => { + const currentLang = getLang(); + + const getRegEpx = (lang: string) => new RegExp(`(/${lang}/)|(/${lang}$)|(/(${lang})(?=\\?))`); + + const replace = (pathname: string, lang?: string) => { + const { config } = getSpeakContext(); + + lang ??= currentLang; + + const langParam = config.supportedLocales.find(locale => getRegEpx(locale.lang)?.test(pathname))?.lang; + if (langParam) { + if (lang !== config.defaultLocale.lang) { + pathname = pathname.replace(langParam, lang); + } else { + pathname = pathname.replace(getRegEpx(langParam), '/'); + } + } else if (lang !== config.defaultLocale.lang) { + pathname = `/${lang}${pathname}`; + } + + return pathname; + }; + + const localize = (route: (string | URL) | string[], lang?: string) => { + if (Array.isArray(route)) { + return route.map(path => replace(path, lang)); + } + + if (typeof route === 'string') { + return replace(route, lang); + } + + route.pathname = replace(route.pathname, lang); + + return route.toString().replace(/\/\?/, '?'); + }; + + return localize as LocalizePathFn; +}; diff --git a/packages/qwik-speak/src/qwik-speak-component.tsx b/packages/qwik-speak/src/qwik-speak-component.tsx deleted file mode 100644 index 81fca66..0000000 --- a/packages/qwik-speak/src/qwik-speak-component.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import { $, component$, Slot, useContextProvider, useServerData, useTask$ } from '@builder.io/qwik'; -import { isDev } from '@builder.io/qwik/build'; - -import type { SpeakConfig, SpeakLocale, SpeakState, TranslationFn } from './types'; -import { SpeakContext } from './context'; -import { loadTranslations } from './core'; -import { logDebug, logWarn } from './log'; - -export interface QwikSpeakProps { - /** - * Speak config - */ - config: SpeakConfig; - /** - * Optional functions to use - */ - translationFn?: TranslationFn; - /** - * Optional locale to use - */ - locale?: SpeakLocale; - /** - * Optional additional languages to preload data for (multilingual) - */ - langs?: string[]; -} - -/** - * Create and provide the Speak context - */ -export const QwikSpeakProvider = component$((props: QwikSpeakProps) => { - // Get Qwik locale - const lang = useServerData('locale'); - - // Resolve functions - const resolvedTranslationFn: TranslationFn = { - loadTranslation$: props.translationFn?.loadTranslation$ ?? $(() => null) - }; - - // Resolve locale - let resolvedLocale = props.locale ?? props.config.supportedLocales.find(value => value.lang === lang); - if (!resolvedLocale) { - resolvedLocale = props.config.defaultLocale; - - if (isDev) logWarn(`Locale not resolved. Fallback to default locale: ${props.config.defaultLocale.lang}`); - } else if (isDev) { - logDebug(`Resolved locale: ${resolvedLocale.lang}`); - } - - // Set initial state as object (no reactive) - const state: SpeakState = { - locale: Object.assign({}, resolvedLocale), - translation: Object.fromEntries(props.config.supportedLocales.map(value => [value.lang, {}])), - config: { - rewriteRoutes: props.config.rewriteRoutes, - defaultLocale: props.config.defaultLocale, - supportedLocales: props.config.supportedLocales, - assets: props.config.assets, - runtimeAssets: props.config.runtimeAssets, - keySeparator: props.config.keySeparator || '.', - keyValueSeparator: props.config.keyValueSeparator || '@@' - }, - translationFn: resolvedTranslationFn - }; - const { config } = state; - - // Create context - useContextProvider(SpeakContext, state); - - // Called the first time when the component mounts - useTask$(async () => { - await loadTranslations(state, config.assets, config.runtimeAssets, props.langs); - }); - - return ; -}); diff --git a/packages/qwik-speak/src/speak-component.tsx b/packages/qwik-speak/src/speak-component.tsx deleted file mode 100644 index 49ea506..0000000 --- a/packages/qwik-speak/src/speak-component.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import { component$, Slot, useTask$ } from '@builder.io/qwik'; -import { isDev } from '@builder.io/qwik/build'; - -import { useSpeakContext } from './use-speak'; -import { loadTranslations } from './core'; -import { logWarn } from './log'; - -export interface SpeakProps { - /** - * Assets to load - */ - assets?: string[]; - /** - * Assets to load available at runtime - */ - runtimeAssets?: string[]; - /** - * Optional additional languages to preload data for (multilingual) - */ - langs?: string[]; -} - -/** - * Add scoped translation data to the context. - * Translations will only be available in child components - */ -export const Speak = component$((props: SpeakProps) => { - useSpeak(props); - - return ; -}); - -/** - * Add scoped translation data to the context. - * Translations will only be available in child components - */ -export const useSpeak = (props: SpeakProps) => { - const ctx = useSpeakContext(); - - const { config } = ctx; - - // Called the first time when the component mounts - useTask$(async () => { - if (isDev) { - if (!props.assets && !props.runtimeAssets) logWarn('Speak component: no assets provided'); - const duplicateAsset = config.assets?.find(asset => props.assets?.includes(asset)); - if (duplicateAsset) { - logWarn(`Speak component: duplicate assets '${duplicateAsset}'`); - } - const duplicateRuntimeAsset = config.runtimeAssets?.find(asset => props.runtimeAssets?.includes(asset)); - if (duplicateRuntimeAsset) { - logWarn(`Speak component: duplicate runtimeAssets '${duplicateRuntimeAsset}'`); - } - } - - await loadTranslations(ctx, props.assets, props.runtimeAssets, props.langs); - }); -}; diff --git a/packages/qwik-speak/src/use-translate-path.ts b/packages/qwik-speak/src/translate-path.ts similarity index 71% rename from packages/qwik-speak/src/use-translate-path.ts rename to packages/qwik-speak/src/translate-path.ts index d656a81..3e85cdc 100644 --- a/packages/qwik-speak/src/use-translate-path.ts +++ b/packages/qwik-speak/src/translate-path.ts @@ -1,30 +1,37 @@ -import { noSerialize } from '@builder.io/qwik'; import { isDev } from '@builder.io/qwik/build'; -import { useSpeakContext } from './use-speak'; + +import { getLang, getSpeakContext } from './context'; import { logWarn } from './log'; export type TranslatePathFn = { /** - * Translate a path. + * Translate a path * @param pathname The path to translate * @param lang Optional language if different from the default one * @returns The translation or the path if not found */ (pathname: string, lang?: string): string; /** - * Translate an array of paths. + * Translate an url + * @param url The url to translate + * @param lang Optional language if different from the default one + * @returns The translation or the url if not found + */ + (url: URL, lang?: string): string; + /** + * Translate an array of paths * @param pathname The array of paths to translate * @param lang Optional language if different from the default one * @returns The translations or the paths if not found */ - (pathname: string[], lang?: string): string[]; + (pathnames: string[], lang?: string): string[]; }; -export const useTranslatePath = (): TranslatePathFn => { - const ctx = useSpeakContext(); +export const translatePath = (): TranslatePathFn => { + const currentLang = getLang(); const normalizePath = (pathname: string) => { - const { config } = ctx; + const { config } = getSpeakContext(); const source = config.rewriteRoutes?.find(rewrite => ( pathname === `/${rewrite.prefix}` || @@ -51,7 +58,7 @@ export const useTranslatePath = (): TranslatePathFn => { } const rewritePath = (pathname: string, prefix?: string) => { - const { config } = ctx; + const { config } = getSpeakContext(); let splitted = pathname.split('/'); const destination = config.rewriteRoutes?.find( @@ -85,31 +92,33 @@ export const useTranslatePath = (): TranslatePathFn => { } const translateOne = (pathname: string, lang?: string) => { - const { locale } = ctx; - - lang ??= locale.lang; + lang ??= currentLang; const normalized = normalizePath(pathname); const rewrote = rewritePath(normalized, lang); return slashPath(pathname, rewrote); }; - const translate = (pathname: string | string[], lang?: string) => { - const { locale, config } = ctx; + const translate = (route: (string | URL) | string[], lang?: string) => { + const { config } = getSpeakContext(); if (!config.rewriteRoutes) { - if (isDev) logWarn(`SpeakConfig: rewriteRoutes not found`); - return pathname; + if (isDev) logWarn(`translatePath: rewriteRoutes not found`); + return route; } - lang ??= locale.lang; + if (Array.isArray(route)) { + return route.map(path => translateOne(path, lang)); + } - if (Array.isArray(pathname)) { - return pathname.map(path => translateOne(path, lang)); + if (typeof route === 'string') { + return translateOne(route, lang); } - return translateOne(pathname, lang); + route.pathname = translateOne(route.pathname, lang); + + return route.toString(); }; - return noSerialize(translate) as TranslatePathFn; + return translate as TranslatePathFn; }; diff --git a/packages/qwik-speak/src/use-display-name.ts b/packages/qwik-speak/src/use-display-name.ts index 1bfd067..b3e05c8 100644 --- a/packages/qwik-speak/src/use-display-name.ts +++ b/packages/qwik-speak/src/use-display-name.ts @@ -1,5 +1,4 @@ -import { noSerialize } from '@builder.io/qwik'; -import { useSpeakLocale } from './use-speak'; +import { useSpeakLocale } from './use-functions'; export type DisplayNameFn = { /** @@ -21,5 +20,5 @@ export const useDisplayName = (): DisplayNameFn => { return new Intl.DisplayNames(lang, options).of(code) || code; }; - return noSerialize(displayName) as DisplayNameFn; + return displayName as DisplayNameFn; }; diff --git a/packages/qwik-speak/src/use-format-date.ts b/packages/qwik-speak/src/use-format-date.ts index 64554fd..ff4297c 100644 --- a/packages/qwik-speak/src/use-format-date.ts +++ b/packages/qwik-speak/src/use-format-date.ts @@ -1,5 +1,4 @@ -import { noSerialize } from '@builder.io/qwik'; -import { useSpeakLocale } from './use-speak'; +import { useSpeakLocale } from './use-functions'; export type FormatDateFn = { /** @@ -33,5 +32,5 @@ export const useFormatDate = (): FormatDateFn => { return new Intl.DateTimeFormat(lang, options).format(value); }; - return noSerialize(formateDate) as FormatDateFn; + return formateDate as FormatDateFn; }; diff --git a/packages/qwik-speak/src/use-format-number.ts b/packages/qwik-speak/src/use-format-number.ts index 566f9a0..143c3bc 100644 --- a/packages/qwik-speak/src/use-format-number.ts +++ b/packages/qwik-speak/src/use-format-number.ts @@ -1,5 +1,4 @@ -import { noSerialize } from '@builder.io/qwik'; -import { useSpeakLocale } from './use-speak'; +import { useSpeakLocale } from './use-functions'; export type FormatNumberFn = { /** @@ -33,5 +32,5 @@ export const useFormatNumber = (): FormatNumberFn => { return new Intl.NumberFormat(lang, options).format(value); }; - return noSerialize(formatNumber) as FormatNumberFn; + return formatNumber as FormatNumberFn; }; diff --git a/packages/qwik-speak/src/use-functions.ts b/packages/qwik-speak/src/use-functions.ts new file mode 100644 index 0000000..51936de --- /dev/null +++ b/packages/qwik-speak/src/use-functions.ts @@ -0,0 +1,10 @@ +import { useContext } from '@builder.io/qwik'; + +import type { SpeakLocale, SpeakConfig, SpeakState } from './types'; +import { SpeakContext } from './context'; + +export const useSpeakContext = (): SpeakState => useContext(SpeakContext); + +export const useSpeakLocale = (): SpeakLocale => useContext(SpeakContext).locale; + +export const useSpeakConfig = (): SpeakConfig => useContext(SpeakContext).config; diff --git a/packages/qwik-speak/src/use-qwik-speak.tsx b/packages/qwik-speak/src/use-qwik-speak.tsx new file mode 100644 index 0000000..1ff5410 --- /dev/null +++ b/packages/qwik-speak/src/use-qwik-speak.tsx @@ -0,0 +1,185 @@ +import { $, component$, getLocale, Slot, useContextProvider, useOnWindow, useTask$ } from '@builder.io/qwik'; +import { isDev, isServer } from '@builder.io/qwik/build'; + +import type { SpeakConfig, SpeakLocale, SpeakState, TranslationFn } from './types'; +import { getSpeakContext, setGetLangFn, SpeakContext } from './context'; +import { loadTranslations } from './core'; +import { logDebug, logWarn } from './log'; + +export interface QwikSpeakProps { + /** + * Speak config + */ + config: SpeakConfig; + /** + * Optional functions to use + */ + translationFn?: TranslationFn; + /** + * Optional additional languages to preload data for (multilingual) + */ + langs?: string[]; +} + +export interface QwikSpeakMockProps extends QwikSpeakProps { + /** + * Optional locale to use + */ + locale?: SpeakLocale; +} + +/** + * Create and provide the Speak context. + * Translations will be available in the whole app + */ +export const useQwikSpeak = (props: QwikSpeakProps) => { + // Get Qwik locale + const lang = getLocale(''); + + // Resolve locale + let resolvedLocale = props.config.supportedLocales.find(value => value.lang === lang); + if (!resolvedLocale) { + resolvedLocale = props.config.defaultLocale; + + if (isDev) logWarn(`Locale not resolved. Fallback to default locale: ${props.config.defaultLocale.lang}`); + } else if (isDev) { + logDebug(`Resolved locale: ${resolvedLocale.lang}`); + } + + // Resolve functions + const resolvedTranslationFn: TranslationFn = { + loadTranslation$: props.translationFn?.loadTranslation$ ?? $(() => null) + }; + + // Resolve config + const resolvedConfig: SpeakConfig = { + rewriteRoutes: props.config.rewriteRoutes, + defaultLocale: props.config.defaultLocale, + supportedLocales: props.config.supportedLocales, + assets: props.config.assets, + runtimeAssets: props.config.runtimeAssets, + keySeparator: props.config.keySeparator || '.', + keyValueSeparator: props.config.keyValueSeparator || '@@' + }; + + // Set initial state as object (no reactive) + const state: SpeakState = { + locale: Object.assign({}, resolvedLocale), + translation: Object.fromEntries(props.config.supportedLocales.map(value => [value.lang, {}])), + config: Object.assign({}, resolvedConfig), + translationFn: resolvedTranslationFn + }; + + const { config } = state; + + // Set Qwik Speak server context + const { config: _config } = getSpeakContext(); + Object.assign(_config, resolvedConfig); + + // Set the getLang function to use Qwik locale + setGetLangFn(() => getLocale(config.defaultLocale.lang)); + + // Create Qwik context + useContextProvider(SpeakContext, state); + + // Load translations + useTask$(async () => { + if (isServer) { + await loadTranslations(state, config.assets, config.runtimeAssets, props.langs); + } + }); + + // Resume Qwik Speak context on client + const resumeContext$ = $(() => { + const { locale, translation, config } = state; + // Set Qwik Speak client context + const _speakContext = getSpeakContext(); + const { locale: _locale, translation: _translation, config: _config } = _speakContext; + Object.assign(_locale, locale); + Object.assign(_translation, translation); + Object.assign(_config, config); + + // Set the getLang function to use the current lang + setGetLangFn(() => locale.lang); + + if (isDev) { + console.debug( + '%cQwik Speak Inline', + 'background: #0c75d2; color: white; padding: 2px 3px; border-radius: 2px; font-size: 0.8em;', + 'Client context', + _speakContext + ); + } + + // In dev mode, send lang from client to the server + if (isDev) { + console.debug( + '%cQwik Speak Inline', + 'background: #0c75d2; color: white; padding: 2px 3px; border-radius: 2px; font-size: 0.8em;', + 'Ready' + ); + if (import.meta.hot) { + import.meta.hot.send('qwik-speak:lang', { msg: locale.lang }); + } + } + }); + + // The load event is fired when the whole page has loaded + useOnWindow('load', resumeContext$); +}; + +/** + * Create and provide the Speak context to test enviroments + */ +export const QwikSpeakMockProvider = component$(props => { + const lang = props.locale?.lang; + + // Resolve locale + let resolvedLocale = props.config.supportedLocales.find(value => value.lang === lang); + if (!resolvedLocale) { + resolvedLocale = props.config.defaultLocale; + } + + // Resolve functions + const resolvedTranslationFn: TranslationFn = { + loadTranslation$: props.translationFn?.loadTranslation$ ?? $(() => null) + }; + + // Resolve config + const resolvedConfig: SpeakConfig = { + rewriteRoutes: props.config.rewriteRoutes, + defaultLocale: props.config.defaultLocale, + supportedLocales: props.config.supportedLocales, + assets: props.config.assets, + runtimeAssets: props.config.runtimeAssets, + keySeparator: props.config.keySeparator || '.', + keyValueSeparator: props.config.keyValueSeparator || '@@' + }; + + // Set initial state as object (no reactive) + const state: SpeakState = { + locale: Object.assign({}, resolvedLocale), + translation: Object.fromEntries(props.config.supportedLocales.map(value => [value.lang, {}])), + config: Object.assign({}, resolvedConfig), + translationFn: resolvedTranslationFn + }; + + const { config } = state; + + // Set Qwik Speak server context + const { config: _config } = getSpeakContext(); + Object.assign(_config, resolvedConfig); + + // Set the getLang function to use the provided lang + setGetLangFn(() => resolvedLocale!.lang); + + // Create context + useContextProvider(SpeakContext, state); + + // Load translations + useTask$(async () => { + await loadTranslations(state, config.assets, config.runtimeAssets, props.langs); + }); + + return ; +}); diff --git a/packages/qwik-speak/src/use-relative-time.ts b/packages/qwik-speak/src/use-relative-time.ts index dbfffe5..7080c2c 100644 --- a/packages/qwik-speak/src/use-relative-time.ts +++ b/packages/qwik-speak/src/use-relative-time.ts @@ -1,5 +1,4 @@ -import { noSerialize } from '@builder.io/qwik'; -import { useSpeakLocale } from './use-speak'; +import { useSpeakLocale } from './use-functions'; export type RelativeTimeFn = { /** @@ -33,5 +32,5 @@ export const useRelativeTime = (): RelativeTimeFn => { return new Intl.RelativeTimeFormat(lang, options).format(value, unit); }; - return noSerialize(relativeTime) as RelativeTimeFn; + return relativeTime as RelativeTimeFn; }; diff --git a/packages/qwik-speak/src/use-speak.ts b/packages/qwik-speak/src/use-speak.ts index 51936de..03b0b05 100644 --- a/packages/qwik-speak/src/use-speak.ts +++ b/packages/qwik-speak/src/use-speak.ts @@ -1,10 +1,59 @@ -import { useContext } from '@builder.io/qwik'; +import { useTask$ } from '@builder.io/qwik'; +import { isBrowser, isDev } from '@builder.io/qwik/build'; -import type { SpeakLocale, SpeakConfig, SpeakState } from './types'; -import { SpeakContext } from './context'; +import { useSpeakContext } from './use-functions'; +import { loadTranslations } from './core'; +import { getSpeakContext } from './context'; +import { logWarn } from './log'; -export const useSpeakContext = (): SpeakState => useContext(SpeakContext); +export interface SpeakProps { + /** + * Assets to load + */ + assets?: string[]; + /** + * Assets to load available at runtime + */ + runtimeAssets?: string[]; + /** + * Optional additional languages to preload data for (multilingual) + */ + langs?: string[]; +} -export const useSpeakLocale = (): SpeakLocale => useContext(SpeakContext).locale; +/** + * Add translation data to the context. + * Translations will only be available in child components + */ +export const useSpeak = (props: SpeakProps) => { + const ctx = useSpeakContext(); -export const useSpeakConfig = (): SpeakConfig => useContext(SpeakContext).config; + const { config } = ctx; + + // Load translations + useTask$(async () => { + if (isDev) { + if (!props.assets && !props.runtimeAssets) logWarn('useSpeak: no assets provided'); + const duplicateAsset = config.assets?.find(asset => props.assets?.includes(asset)); + if (duplicateAsset) { + logWarn(`useSpeak: duplicate assets '${duplicateAsset}'`); + } + const duplicateRuntimeAsset = config.runtimeAssets?.find(asset => props.runtimeAssets?.includes(asset)); + if (duplicateRuntimeAsset) { + logWarn(`useSpeak: duplicate runtimeAssets '${duplicateRuntimeAsset}'`); + } + } + + await loadTranslations(ctx, props.assets, props.runtimeAssets, props.langs); + + if (isDev && isBrowser) { + const _speakContext = getSpeakContext(); + console.debug( + '%cQwik Speak Inline', + 'background: #0c75d2; color: white; padding: 2px 3px; border-radius: 2px; font-size: 0.8em;', + 'Client context', + _speakContext + ); + } + }); +}; diff --git a/packages/qwik-speak/src/use-translate.ts b/packages/qwik-speak/src/use-translate.ts deleted file mode 100644 index 28b1fe7..0000000 --- a/packages/qwik-speak/src/use-translate.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { noSerialize } from '@builder.io/qwik'; -import { useSpeakContext } from './use-speak'; -import { getValue } from './core'; - -export type TranslateFn = { - /** - * Translate a key. - * The syntax of the string is 'key@@[default value]' - * @param key The key to translate - * @param params Optional parameters contained in the value - * @param lang Optional language if different from the current one - * @returns The translation or the key if not found - */ - (key: string, params?: Record, lang?: string): string; - (key: string, params?: Record, lang?: string): T; - /** - * Translate an array of keys. - * The syntax of the strings is 'key@@[default value]' - * @param keys The array of keys to translate - * @param params Optional parameters contained in the values - * @param lang Optional language if different from the current one - * @returns The translations or the keys if not found - */ - (keys: string[], params?: Record, lang?: string): string[]; - (keys: string[], params?: Record, lang?: string): T[]; -}; - -export const useTranslate = (): TranslateFn => { - const ctx = useSpeakContext(); - - const translate = (keys: string | string[], params?: Record, lang?: string) => { - const { locale, translation, config } = ctx; - - lang ??= locale.lang; - - if (Array.isArray(keys)) { - return keys.map(k => getValue(k, translation[lang!], params, config.keySeparator, config.keyValueSeparator)); - } - - return getValue(keys, translation[lang], params, config.keySeparator, config.keyValueSeparator); - }; - - return noSerialize(translate) as TranslateFn; -}; diff --git a/packages/qwik-speak/src/validate-locale.ts b/packages/qwik-speak/src/validate-locale.ts new file mode 100644 index 0000000..90031f5 --- /dev/null +++ b/packages/qwik-speak/src/validate-locale.ts @@ -0,0 +1,9 @@ +/** + * Validate language[-script][-region] + * - `language` ISO 639 two-letter or three-letter code + * - `script` ISO 15924 four-letter script code + * - `region` ISO 3166 two-letter, uppercase code + */ +export const validateLocale = (lang: string): boolean => { + return /^([a-z]{2,3})(-[A-Z][a-z]{3})?(-[A-Z]{2})?$/.test(lang); +}; diff --git a/packages/qwik-speak/tests/config.ts b/packages/qwik-speak/tests/config.ts index 55ce5c1..55b01e9 100644 --- a/packages/qwik-speak/tests/config.ts +++ b/packages/qwik-speak/tests/config.ts @@ -1,6 +1,19 @@ import { $ } from '@builder.io/qwik'; -import type { SpeakConfig, LoadTranslationFn, TranslationFn } from '../src/types'; -import { rewriteRoutes } from '../../../src/speak-routes'; +import type { SpeakConfig, LoadTranslationFn, TranslationFn, RewriteRouteOption } from '../src/types'; + +const rewriteRoutes: RewriteRouteOption[] = [ + { + prefix: 'it-IT', + paths: { + 'page': 'pagina' + } + }, { + prefix: 'de-DE', + paths: { + 'page': 'seite' + } + } +]; export const config: SpeakConfig = { rewriteRoutes, @@ -16,22 +29,38 @@ export const config: SpeakConfig = { }; export const mockJson = { - test: 'Test', - testParams: 'Test {{param}}', - nested: { + 'en-US': { test: 'Test', - array: ['Test1 {{ param }}', 'Test2 {{ param }}'] + testParams: 'Test {{param}}', + nested: { + test: 'Test', + array: ['Test1 {{ param }}', 'Test2 {{ param }}'] + }, + one: 'One {{ role }} developer', + other: '{{value}} {{ role }} developers', + arrayObjects: [ + { num: 'One {{ param }}' }, + { num: 'Two {{ param }}' } + ] + }, + 'it-IT': { + test: 'Prova', + testParams: 'Prova {{param}}', + nested: { + test: 'Prova', + array: ['Prova1 {{ param }}', 'Prova2 {{ param }}'] + }, + one: 'Un {{ role }} developer', + other: '{{value}} {{ role }} developers', + arrayObjects: [ + { num: 'Uno {{ param }}' }, + { num: 'Due {{ param }}' } + ] }, - one: 'One {{ role }} developer', - other: '{{value}} {{ role }} developers', - arrayObjects: [ - { num: 'One {{ param }}' }, - { num: 'Two {{ param }}' } - ] }; -export const loadTranslationStub$: LoadTranslationFn = $(() => { - return mockJson; +export const loadTranslationStub$: LoadTranslationFn = $((lang: string) => { + return (mockJson as any)[lang]; }); export const translationFnStub: TranslationFn = { diff --git a/packages/qwik-speak/tests/core.test.ts b/packages/qwik-speak/tests/core.test.ts index 2c75d11..727ea74 100644 --- a/packages/qwik-speak/tests/core.test.ts +++ b/packages/qwik-speak/tests/core.test.ts @@ -13,10 +13,6 @@ describe('core', () => { value = getValue('SUBKEY1.BB', { KEY1: 'key1', SUBKEY1: { AA: 'aa' } }); expect(value).toBe('SUBKEY1.BB'); }); - test('getValue when String', () => { - const value = getValue('KEY1', { KEY1: new String('key1') }); - expect(value).toBe('key1'); - }); test('transpileParams', () => { let value = transpileParams('Test {{param}}', { param: 'params' }); expect(value).toBe('Test params'); diff --git a/packages/qwik-speak/tests/use-plural.test.tsx b/packages/qwik-speak/tests/inline-plural.test.tsx similarity index 69% rename from packages/qwik-speak/tests/use-plural.test.tsx rename to packages/qwik-speak/tests/inline-plural.test.tsx index 1301a5e..7a0d4eb 100644 --- a/packages/qwik-speak/tests/use-plural.test.tsx +++ b/packages/qwik-speak/tests/inline-plural.test.tsx @@ -2,12 +2,12 @@ import { createDOM } from '@builder.io/qwik/testing'; import { component$ } from '@builder.io/qwik'; import { test, describe, expect } from 'vitest'; -import { usePlural } from '../src/use-plural'; -import { QwikSpeakProvider } from '../src/qwik-speak-component'; +import { inlinePlural } from '../src/inline-plural'; +import { QwikSpeakMockProvider } from '../src/use-qwik-speak'; import { config, translationFnStub } from './config'; const TestComponent = component$(() => { - const p = usePlural(); + const p = inlinePlural(); return (
@@ -17,13 +17,13 @@ const TestComponent = component$(() => { ); }); -describe('usePlural function', async () => { +describe('inlinePlural function', async () => { const { screen, render } = await createDOM(); await render( - + - + ); test('plural', () => { diff --git a/packages/qwik-speak/tests/inline-translate.test.tsx b/packages/qwik-speak/tests/inline-translate.test.tsx index 7143e30..ad583d6 100644 --- a/packages/qwik-speak/tests/inline-translate.test.tsx +++ b/packages/qwik-speak/tests/inline-translate.test.tsx @@ -1,34 +1,72 @@ import { createDOM } from '@builder.io/qwik/testing'; -import { component$, useSignal, useTask$, $ } from '@builder.io/qwik'; +import { component$, useSignal, $, useTask$ } from '@builder.io/qwik'; import { test, describe, expect } from 'vitest'; +import type { Translation } from '../src/types'; import { inlineTranslate } from '../src/inline-translate'; -import { useSpeakContext } from '../src/use-speak'; -import { QwikSpeakProvider } from '../src/qwik-speak-component'; +import { QwikSpeakMockProvider } from '../src/use-qwik-speak'; import { config, translationFnStub } from './config'; -import type { SpeakState } from '../src/types'; -const MyComponent = (props: { ctx: SpeakState }) => { - return
{inlineTranslate('test', props.ctx)}
; +const ChildComponent = component$((props: { value: string, value1: string }) => { + return ( +
+
{props.value}
+
{props.value1}
+
+ ); +}); + +const InlineComponent = () => { + const t = inlineTranslate(); + return
{t('test')}
; }; +const test$ = $(() => { + const t = inlineTranslate(); + return t('test'); +}); + const TestComponent = component$(() => { - const ctx = useSpeakContext(); + const t = inlineTranslate(); const s = useSignal(''); - - const test$ = $(() => { - return inlineTranslate('test', ctx); - }); + const s1 = useSignal(false); useTask$(async () => { s.value = await test$(); + s1.value = true; }); return (
-
{s.value}
- +
{t('test')}
+
{t('test@@Default')}
+
{t('testParams', { param: 'params' })}
+
{t(['test', 'testParams'], { param: 'params' }).map((v, i) => (
{v}
))}
+
{t('test1')}
+
{t('nested.test')}
+
{t('test1@@Test 1')}
+
{t('test1@@Test {{param}}', { param: 'params' })}
+
{t('nested.array', { param: 'params' }).map((v, i) => + (
{v}
))} +
+
{t('nested.array.1', { param: 'params' })}
+
{t('nested')['test']}
+
{t('arrayObjects', { param: 'params' }).map((o, i) => + (
{o['num']}
))} +
+
+ {s1.value && +

+ {t('test')} +

+ } +
+
{s1.value && t('test')}
+
+
{s.value}
+ +
); }); @@ -37,13 +75,83 @@ describe('inlineTranslate function', async () => { const { screen, render } = await createDOM(); await render( - + - + ); test('translate', () => { expect((screen.querySelector('#A') as HTMLDivElement).innerHTML).toContain('Test'); + }); + test('translate with default value', () => { + expect((screen.querySelector('#A1') as HTMLDivElement).innerHTML).toContain('Test'); + }); + test('translate with params', () => { + expect((screen.querySelector('#A2') as HTMLDivElement).innerHTML).toContain('Test params'); + }); + test('translate with array of keys', () => { + expect((screen.querySelector('#A3') as HTMLDivElement).innerHTML).toContain('Test'); + expect((screen.querySelector('#A3') as HTMLDivElement).innerHTML).toContain('Test params'); + }); + test('missing value', () => { + expect((screen.querySelector('#A4') as HTMLDivElement).innerHTML).toContain('test1'); + }); + test('key separator', () => { + expect((screen.querySelector('#A5') as HTMLDivElement).innerHTML).toContain('Test'); + }); + test('key-value separator', () => { + expect((screen.querySelector('#A6') as HTMLDivElement).innerHTML).toContain('Test 1'); + }); + test('key-value separator with params', () => { + expect((screen.querySelector('#A7') as HTMLDivElement).innerHTML).toContain('Test params'); + }); + test('array', () => { + expect((screen.querySelector('#A8') as HTMLDivElement).innerHTML).toContain('Test1 params'); + expect((screen.querySelector('#A8') as HTMLDivElement).innerHTML).toContain('Test2 params'); + }); + test('array with dot notation', () => { + expect((screen.querySelector('#A9') as HTMLDivElement).innerHTML).toContain('Test2 params'); + }); + test('object', () => { + expect((screen.querySelector('#A10') as HTMLDivElement).innerHTML).toContain('Test'); + }); + test('array of objects', () => { + expect((screen.querySelector('#A11') as HTMLDivElement).innerHTML).toContain('One params'); + expect((screen.querySelector('#A11') as HTMLDivElement).innerHTML).toContain('Two params'); + }); + test('conditional rendering', () => { + expect((screen.querySelector('#A12') as HTMLDivElement).innerHTML).toContain('Test'); + }); + test('inline conditional rendering', () => { + expect((screen.querySelector('#A13') as HTMLDivElement).innerHTML).toContain('Test'); + }); + test('jsx attributes', () => { + expect((screen.querySelector('#A14') as HTMLDivElement).getAttribute('title')).toContain('Test'); + }); + test('signal', () => { + expect((screen.querySelector('#A15') as HTMLDivElement).innerHTML).toContain('Test'); + }); + test('component props', () => { expect((screen.querySelector('#B') as HTMLDivElement).innerHTML).toContain('Test'); + expect((screen.querySelector('#B1') as HTMLDivElement).innerHTML).toContain('Test'); + }); + test('inline component', () => { + expect((screen.querySelector('#C') as HTMLDivElement).innerHTML).toContain('Test'); + }); +}); + +describe('inlineTranslate function with different lang', async () => { + const { screen, render } = await createDOM(); + + const locale = { lang: 'it-IT' }; + + await render( + + + + ); + + test('translate', () => { + expect((screen.querySelector('#A') as HTMLDivElement).innerHTML).toContain('Prova'); }); }); diff --git a/packages/qwik-speak/tests/localize-path.test.tsx b/packages/qwik-speak/tests/localize-path.test.tsx new file mode 100644 index 0000000..b2e3797 --- /dev/null +++ b/packages/qwik-speak/tests/localize-path.test.tsx @@ -0,0 +1,80 @@ +import { createDOM } from '@builder.io/qwik/testing'; +import { component$ } from '@builder.io/qwik'; +import { test, describe, expect } from 'vitest'; + +import { localizePath } from '../src'; +import { QwikSpeakMockProvider } from '../src/use-qwik-speak'; +import { config, translationFnStub } from './config'; + +const TestComponent = component$(() => { + const lp = localizePath(); + + return ( +
+ + + + + + + + + + + + + + +
+ ); +}); + +describe('localizePath function', async () => { + const { screen, render } = await createDOM(); + + await render( + + + + ); + + test('add language', () => { + expect((screen.querySelector('#A1') as HTMLDivElement).getAttribute('href')).toBe('http://localhost/it-IT/'); + expect((screen.querySelector('#A2') as HTMLDivElement).getAttribute('href')).toBe('http://localhost/it-IT/page?id=1'); + expect((screen.querySelector('#A3') as HTMLDivElement).getAttribute('href')).toBe('http://localhost/it-IT?id=1'); + }); + + test('remove language', () => { + expect((screen.querySelector('#B1') as HTMLDivElement).getAttribute('href')).toBe('http://localhost/'); + expect((screen.querySelector('#B2') as HTMLDivElement).getAttribute('href')).toBe('http://localhost/page?id=1'); + expect((screen.querySelector('#B4') as HTMLDivElement).getAttribute('href')).toBe('http://localhost?id=1'); + }); + + test('update language', () => { + expect((screen.querySelector('#C1') as HTMLDivElement).getAttribute('href')).toBe('http://localhost/de-DE/'); + expect((screen.querySelector('#C2') as HTMLDivElement).getAttribute('href')).toBe('http://localhost/de-DE/page?id=1'); + expect((screen.querySelector('#C4') as HTMLDivElement).getAttribute('href')).toBe('http://localhost/de-DE?id=1'); + }); + + test('default language', () => { + expect((screen.querySelector('#D1') as HTMLDivElement).getAttribute('href')).toBe('/'); + expect((screen.querySelector('#D2') as HTMLDivElement).getAttribute('href')).toBe('/page'); + }); +}); + +describe('localizePath function with different lang', async () => { + const { screen, render } = await createDOM(); + + const locale = { lang: 'it-IT' }; + + await render( + + + + ); + + test('default language', () => { + expect((screen.querySelector('#D1') as HTMLDivElement).getAttribute('href')).toBe('/it-IT/'); + expect((screen.querySelector('#D2') as HTMLDivElement).getAttribute('href')).toBe('/it-IT/page'); + }); +}); diff --git a/packages/qwik-speak/tests/use-translate-path.test.tsx b/packages/qwik-speak/tests/translate-path.test.tsx similarity index 97% rename from packages/qwik-speak/tests/use-translate-path.test.tsx rename to packages/qwik-speak/tests/translate-path.test.tsx index bbb78ad..dc25de3 100644 --- a/packages/qwik-speak/tests/use-translate-path.test.tsx +++ b/packages/qwik-speak/tests/translate-path.test.tsx @@ -2,12 +2,12 @@ import { createDOM } from '@builder.io/qwik/testing'; import { component$ } from '@builder.io/qwik'; import { test, describe, expect } from 'vitest'; -import { useTranslatePath } from '../src/use-translate-path'; -import { QwikSpeakProvider } from '../src/qwik-speak-component'; +import { translatePath } from '../src/translate-path'; +import { QwikSpeakMockProvider } from '../src/use-qwik-speak'; import { config, translationFnStub } from './config'; const TestComponent = component$(() => { - const tp = useTranslatePath(); + const tp = translatePath(); return (
@@ -91,13 +91,13 @@ const TestComponent = component$(() => { ); }); -describe('useTranslatePath function', async () => { +describe('translatePath function', async () => { const { screen, render } = await createDOM(); await render( - + - + ); test('translate without prefix', () => { diff --git a/packages/qwik-speak/tests/use-display-name.test.tsx b/packages/qwik-speak/tests/use-display-name.test.tsx index 03140b1..4043771 100644 --- a/packages/qwik-speak/tests/use-display-name.test.tsx +++ b/packages/qwik-speak/tests/use-display-name.test.tsx @@ -3,7 +3,7 @@ import { component$ } from '@builder.io/qwik'; import { test, describe, expect } from 'vitest'; import { useDisplayName } from '../src/use-display-name'; -import { QwikSpeakProvider } from '../src/qwik-speak-component'; +import { QwikSpeakMockProvider } from '../src/use-qwik-speak'; import { config } from './config'; const TestComponent = component$(() => { @@ -21,9 +21,9 @@ describe('useDisplayName function', async () => { const { screen, render } = await createDOM(); await render( - + - + ); test('display', () => { diff --git a/packages/qwik-speak/tests/use-format-date.test.tsx b/packages/qwik-speak/tests/use-format-date.test.tsx index 586494b..6a8fef6 100644 --- a/packages/qwik-speak/tests/use-format-date.test.tsx +++ b/packages/qwik-speak/tests/use-format-date.test.tsx @@ -3,7 +3,7 @@ import { component$ } from '@builder.io/qwik'; import { test, describe, expect } from 'vitest'; import { useFormatDate } from '../src/use-format-date'; -import { QwikSpeakProvider } from '../src/qwik-speak-component'; +import { QwikSpeakMockProvider } from '../src/use-qwik-speak'; import { config } from './config'; const TestComponent = component$(() => { @@ -22,9 +22,9 @@ describe('useFormatDate function', async () => { const { screen, render } = await createDOM(); await render( - + - + ); test('format', () => { diff --git a/packages/qwik-speak/tests/use-format-number.test.tsx b/packages/qwik-speak/tests/use-format-number.test.tsx index 0f40703..99e9fe6 100644 --- a/packages/qwik-speak/tests/use-format-number.test.tsx +++ b/packages/qwik-speak/tests/use-format-number.test.tsx @@ -3,9 +3,9 @@ import { component$ } from '@builder.io/qwik'; import { test, describe, expect } from 'vitest'; import { useFormatNumber } from '../src/use-format-number'; -import { QwikSpeakProvider } from '../src/qwik-speak-component'; +import { QwikSpeakMockProvider } from '../src/use-qwik-speak'; import { config } from './config'; -import { useSpeakLocale } from '../src/use-speak'; +import { useSpeakLocale } from '../src/use-functions'; const TestComponent = component$(() => { const fn = useFormatNumber(); @@ -27,9 +27,9 @@ describe('useFormatNumber function', async () => { const { screen, render } = await createDOM(); await render( - + - + ); test('format', () => { diff --git a/packages/qwik-speak/tests/use-relative-time.test.tsx b/packages/qwik-speak/tests/use-relative-time.test.tsx index b720782..1e65e7e 100644 --- a/packages/qwik-speak/tests/use-relative-time.test.tsx +++ b/packages/qwik-speak/tests/use-relative-time.test.tsx @@ -3,7 +3,7 @@ import { component$ } from '@builder.io/qwik'; import { test, describe, expect } from 'vitest'; import { useRelativeTime } from '../src/use-relative-time'; -import { QwikSpeakProvider } from '../src/qwik-speak-component'; +import { QwikSpeakMockProvider } from '../src/use-qwik-speak'; import { config } from './config'; const TestComponent = component$(() => { @@ -21,9 +21,9 @@ describe('useRelativeTime function', async () => { const { screen, render } = await createDOM(); await render( - + - + ); test('format', () => { diff --git a/packages/qwik-speak/tests/use-translate.test.tsx b/packages/qwik-speak/tests/use-translate.test.tsx deleted file mode 100644 index 7909637..0000000 --- a/packages/qwik-speak/tests/use-translate.test.tsx +++ /dev/null @@ -1,117 +0,0 @@ -import { createDOM } from '@builder.io/qwik/testing'; -import { component$ } from '@builder.io/qwik'; -import { test, describe, expect } from 'vitest'; - -import type { Translation } from '../src/types'; -import { useTranslate } from '../src/use-translate'; -import { QwikSpeakProvider } from '../src/qwik-speak-component'; -import { config, translationFnStub } from './config'; - -interface ChildComponentProps { - value: string; -} - -const ChildComponent = component$((props: ChildComponentProps) => { - return ( -
-
{props.value}
-
- ); -}); - -const TestComponent = component$(() => { - const t = useTranslate(); - - return ( -
-
{t('test')}
-
{t('test@@Default')}
-
{t('testParams', { param: 'params' })}
-
{t(['test', 'testParams'], { param: 'params' }).map((v, i) => (
{v}
))}
-
{t('test1')}
-
{t('nested.test')}
-
{t('test1@@Test 1')}
-
{t('test1@@Test {{param}}', { param: 'params' })}
-
{t('nested.array', { param: 'params' }).map((v, i) => - (
{v}
))} -
-
{t('nested.array.1', { param: 'params' })}
-
{t('nested')['test']}
-
{t('arrayObjects', { param: 'params' }).map((o, i) => - (
{o['num']}
))} -
-
- {true && -

- {t('test')} -

- } -
-
{true && t('test')}
-
- -
- ); -}); - -describe('useTranslate function', async () => { - const { screen, render } = await createDOM(); - - await render( - - - - ); - - test('translate', () => { - expect((screen.querySelector('#A') as HTMLDivElement).innerHTML).toContain('Test'); - }); - test('translate with default value', () => { - expect((screen.querySelector('#A1') as HTMLDivElement).innerHTML).toContain('Test'); - }); - test('translate with params', () => { - expect((screen.querySelector('#A2') as HTMLDivElement).innerHTML).toContain('Test params'); - }); - test('translate with array of keys', () => { - expect((screen.querySelector('#A3') as HTMLDivElement).innerHTML).toContain('Test'); - expect((screen.querySelector('#A3') as HTMLDivElement).innerHTML).toContain('Test params'); - }); - test('missing value', () => { - expect((screen.querySelector('#A4') as HTMLDivElement).innerHTML).toContain('test1'); - }); - test('key separator', () => { - expect((screen.querySelector('#A5') as HTMLDivElement).innerHTML).toContain('Test'); - }); - test('key-value separator', () => { - expect((screen.querySelector('#A6') as HTMLDivElement).innerHTML).toContain('Test 1'); - }); - test('key-value separator with params', () => { - expect((screen.querySelector('#A7') as HTMLDivElement).innerHTML).toContain('Test params'); - }); - test('array', () => { - expect((screen.querySelector('#A8') as HTMLDivElement).innerHTML).toContain('Test1 params'); - expect((screen.querySelector('#A8') as HTMLDivElement).innerHTML).toContain('Test2 params'); - }); - test('array with dot notation', () => { - expect((screen.querySelector('#A9') as HTMLDivElement).innerHTML).toContain('Test2 params'); - }); - test('object', () => { - expect((screen.querySelector('#A10') as HTMLDivElement).innerHTML).toContain('Test'); - }); - test('array of objects', () => { - expect((screen.querySelector('#A11') as HTMLDivElement).innerHTML).toContain('One params'); - expect((screen.querySelector('#A11') as HTMLDivElement).innerHTML).toContain('Two params'); - }); - test('conditional rendering', () => { - expect((screen.querySelector('#A12') as HTMLDivElement).innerHTML).toContain('Test'); - }); - test('inline conditional rendering', () => { - expect((screen.querySelector('#A13') as HTMLDivElement).innerHTML).toContain('Test'); - }); - test('html attributes', () => { - expect((screen.querySelector('#A14') as HTMLDivElement).getAttribute('title')).toContain('Test'); - }); - test('no reactive component props', () => { - expect((screen.querySelector('#B') as HTMLDivElement).innerHTML).toContain('Test'); - }) -}); diff --git a/packages/qwik-speak/tests/validate-locale.test.ts b/packages/qwik-speak/tests/validate-locale.test.ts new file mode 100644 index 0000000..9e6a62d --- /dev/null +++ b/packages/qwik-speak/tests/validate-locale.test.ts @@ -0,0 +1,12 @@ +import { test, describe, expect } from 'vitest'; + +import { validateLocale } from '../src'; + +describe('validateLocale', () => { + test('langs', () => { + expect(validateLocale('en')).toBe(true); + expect(validateLocale('en-US')).toBe(true); + expect(validateLocale('en-Zzzz-US')).toBe(true); + expect(validateLocale('en-us')).toBe(false); + }); +}); diff --git a/packages/qwik-speak/tools/core/format.ts b/packages/qwik-speak/tools/core/format.ts index a03776c..4b41ad1 100644 --- a/packages/qwik-speak/tools/core/format.ts +++ b/packages/qwik-speak/tools/core/format.ts @@ -4,12 +4,6 @@ export function toJsonString(target: Translation): string { return JSON.stringify(target, replacer, 2); } -export function minDepth(target: Translation): number { - return typeof target === 'object' && Object.keys(target).length > 0 ? - 1 + Math.min(1, ...Object.values(target).map(o => minDepth(o))) - : 0 -} - export function sortTarget(target: Translation) { return Object.keys(target).sort().reduce( (out: any, key: string) => { diff --git a/packages/qwik-speak/tools/core/merge.ts b/packages/qwik-speak/tools/core/merge.ts index 1775b4d..73c5b4d 100644 --- a/packages/qwik-speak/tools/core/merge.ts +++ b/packages/qwik-speak/tools/core/merge.ts @@ -5,7 +5,10 @@ export function deepSet(target: Translation, keys: string[], val: string | Trans const len = keys.length; while (i < len) { const key = keys[i++]; - target[key] = (i === len) ? val : typeof target[key] === 'object' ? target[key] : {}; + target[key] = target[key] && !val ? + target[key] : (i === len) ? + val : typeof target[key] === 'object' ? + target[key] : {}; target = target[key]; } } diff --git a/packages/qwik-speak/tools/core/parser.ts b/packages/qwik-speak/tools/core/parser.ts index d76de8a..e7128f0 100644 --- a/packages/qwik-speak/tools/core/parser.ts +++ b/packages/qwik-speak/tools/core/parser.ts @@ -394,7 +394,7 @@ export function parseSequenceExpressions(code: string, alias: string): CallExpre } catch (ex: any) { // Report Call expression console.error(ex); - console.error('\x1b[31m\nQwik Speak Inline error parsing \x1b[0m %s', + console.error('\n\x1b[31mQwik Speak Parser error\x1b[0m\n%s', code.substring(i, tokens[tokens.length - 1].position.end) + '\n'); } @@ -404,24 +404,20 @@ export function parseSequenceExpressions(code: string, alias: string): CallExpre return sequenceExpressions; } -/** - * Get useTranslate alias - */ -export function getUseTranslateAlias(code: string): string | null { - let translateAlias = code.match(/(?<=\bconst\s).*?(?=\s?=\s?useTranslate\(\);?)/)?.[0]?.trim(); - if (!translateAlias) return null; - // Assert position at a word boundary - if (!translateAlias.startsWith('$')) translateAlias = `\\b${translateAlias}`; - // Escape special characters - translateAlias = translateAlias.replace(/\$/g, '\\$'); - return translateAlias; +export function matchInlineTranslate(code: string): boolean { + return /inlineTranslate/.test(code); +} + +export function matchInlinePlural(code: string): boolean { + return /inlinePlural/.test(code); } /** * Get inlineTranslate alias */ -export function getInlineTranslateAlias(code: string): string { - let translateAlias = code.match(/(?<=inlineTranslate\s+as).*?(?=,|\})/s)?.[0]?.trim() || 'inlineTranslate'; +export function getInlineTranslateAlias(code: string): string | null { + let translateAlias = code.match(/(?<=\bconst\s).*?(?=\s?=\s?inlineTranslate\(\);?)/)?.[0]?.trim(); + if (!translateAlias) return null; // Assert position at a word boundary if (!translateAlias.startsWith('$')) translateAlias = `\\b${translateAlias}`; // Escape special characters @@ -430,10 +426,10 @@ export function getInlineTranslateAlias(code: string): string { } /** - * Get usePlural alias + * Get inlinePlural alias */ -export function getUsePluralAlias(code: string): string | null { - let pluralAlias = code.match(/(?<=\bconst\s).*?(?=\s?=\s?usePlural\(\);?)/)?.[0]?.trim(); +export function getInlinePluralAlias(code: string): string | null { + let pluralAlias = code.match(/(?<=\bconst\s).*?(?=\s?=\s?inlinePlural\(\);?)/)?.[0]?.trim(); if (!pluralAlias) return null; // Assert position at a word boundary if (!pluralAlias.startsWith('$')) pluralAlias = `\\b${pluralAlias}`; diff --git a/packages/qwik-speak/tools/extract/index.ts b/packages/qwik-speak/tools/extract/index.ts index 711f023..f2655c4 100644 --- a/packages/qwik-speak/tools/extract/index.ts +++ b/packages/qwik-speak/tools/extract/index.ts @@ -4,9 +4,16 @@ import { extname, join, normalize } from 'path'; import type { QwikSpeakExtractOptions, Translation } from '../core/types'; import type { Argument, CallExpression, Element } from '../core/parser'; -import { getUseTranslateAlias, getInlineTranslateAlias, getUsePluralAlias, parseJson, parseSequenceExpressions } from '../core/parser'; +import { + getInlineTranslateAlias, + getInlinePluralAlias, + parseJson, + parseSequenceExpressions, + matchInlineTranslate, + matchInlinePlural +} from '../core/parser'; import { deepClone, deepMerge, deepSet, merge } from '../core/merge'; -import { minDepth, sortTarget, toJsonString } from '../core/format'; +import { sortTarget, toJsonString } from '../core/format'; import { getOptions, getRules } from '../core/intl-parser'; /** @@ -109,9 +116,10 @@ export async function qwikSpeakExtract(options: QwikSpeakExtractOptions) { } } - // useTranslate - if (/useTranslate/.test(code)) { - const alias = getUseTranslateAlias(code); + // inlineTranslate + if (matchInlineTranslate(code)) { + const alias = getInlineTranslateAlias(code); + if (alias) { // Clear types clearTypes(alias); @@ -121,19 +129,9 @@ export async function qwikSpeakExtract(options: QwikSpeakExtractOptions) { } } - // inlineTranslate - if (/inlineTranslate/.test(code)) { - const alias = getInlineTranslateAlias(code); - // Clear types - clearTypes(alias); - // Parse sequence - const sequence = parseSequenceExpressions(code, alias); - parseSequence(sequence); - } - // usePlural - if (/usePlural/.test(code)) { - const alias = getUsePluralAlias(code); + if (matchInlinePlural(code)) { + const alias = getInlinePluralAlias(code); if (alias) { // Parse sequence @@ -160,10 +158,17 @@ export async function qwikSpeakExtract(options: QwikSpeakExtractOptions) { } } - for (const rule of rules) { - let key = args?.[1]?.value; - key = key ? `${key}${resolvedOptions.keySeparator}${rule}` : rule; - keys.push(key); + const key = args?.[1]?.value; + if (key) { + const valueObj: any = {}; + for (const rule of rules) { + valueObj[rule] = ''; + } + keys.push(`${key}${resolvedOptions.keyValueSeparator}${JSON.stringify(valueObj)}`); + } else { + for (const rule of rules) { + keys.push(rule); + } } } } @@ -222,7 +227,7 @@ export async function qwikSpeakExtract(options: QwikSpeakExtractOptions) { * min depth > 0: filenames = each top-level property name * min depth = 0: filename = 'app' */ - const writeAssets = async () => { + const writeAssets = async (prefixes: string[]) => { for (const lang of resolvedOptions.supportedLangs) { const baseAssets = normalize(`${resolvedOptions.basePath}/${resolvedOptions.assetsPath}/${lang}`); @@ -230,8 +235,10 @@ export async function qwikSpeakExtract(options: QwikSpeakExtractOptions) { mkdirSync(baseAssets, { recursive: true }); } - const topLevelKeys = Object.keys(translation[lang]).filter(key => minDepth(translation[lang][key]) > 0); - const bottomLevelKeys = Object.keys(translation[lang]).filter(key => minDepth(translation[lang][key]) === 0); + const topLevelKeys = Object.keys(translation[lang]) + .filter(key => !prefixes.includes(key)); + const bottomLevelKeys = Object.keys(translation[lang]) + .filter(key => prefixes.includes(key)); const bottomTranslation: Translation = {}; if (translation[lang][resolvedOptions.filename]) { @@ -285,6 +292,7 @@ export async function qwikSpeakExtract(options: QwikSpeakExtractOptions) { keys = [...new Set(keys)]; stats.set('unique keys', (stats.get('unique keys') ?? 0) + keys.length); + const prefixes: string[] = []; /* Deep set in translation data */ for (let key of keys) { let defaultValue: string | Translation | undefined = undefined; @@ -299,6 +307,8 @@ export async function qwikSpeakExtract(options: QwikSpeakExtractOptions) { for (const lang of resolvedOptions.supportedLangs) { deepSet(translation[lang], key.split(resolvedOptions.keySeparator), deepClone(defaultValue || '')); } + + prefixes.push(key); } /* Read assets */ @@ -317,7 +327,7 @@ export async function qwikSpeakExtract(options: QwikSpeakExtractOptions) { } /* Write translation data */ - await writeAssets(); + await writeAssets(prefixes); /* Log */ for (const [key, value] of stats) { diff --git a/packages/qwik-speak/tools/inline/plugin.ts b/packages/qwik-speak/tools/inline/plugin.ts index 40756ef..a290763 100644 --- a/packages/qwik-speak/tools/inline/plugin.ts +++ b/packages/qwik-speak/tools/inline/plugin.ts @@ -6,21 +6,30 @@ import { extname, normalize } from 'path'; import type { QwikSpeakInlineOptions, Translation } from '../core/types'; import type { Argument, Property } from '../core/parser'; -import { getUseTranslateAlias, getInlineTranslateAlias, getUsePluralAlias, parseJson, parse, tokenize } from '../core/parser'; +import { + getInlineTranslateAlias, + getInlinePluralAlias, + parseJson, + matchInlinePlural, + matchInlineTranslate +} from '../core/parser'; import { parseSequenceExpressions } from '../core/parser'; import { getOptions, getRules } from '../core/intl-parser'; import { merge } from '../core/merge'; -const inlinePlaceholder = '__qsInline'; const inlineTranslatePlaceholder = '__qsInlineTranslate'; const inlinePluralPlaceholder = '__qsInlinePlural'; -const signalAlias = '\\b_fnSignal'; - // Logs const missingValues: string[] = []; -const dynamicKeys: string[] = []; -const dynamicParams: string[] = []; +const dynamics: string[] = []; +const missingValueText = (lang: string, key: string) => `${lang} - ${key}`; +const dynamicText = (originalFn: string, text: string) => `dynamic ${text}: ${originalFn}`; + +// Config +let target: 'ssr' | 'lib' | 'test' | 'client'; +let mode: 'dev' | 'prod'; +let input: string | undefined; /** * Qwik Speak Inline Vite plugin @@ -39,18 +48,28 @@ export function qwikSpeakInline(options: QwikSpeakInlineOptions): Plugin { // Translation data const translation: Translation = Object.fromEntries(resolvedOptions.supportedLangs.map(value => [value, {}])); - // Client or server files - let target: string; - let input: string | undefined; + // Current lang + let devLang: string; + + // Inlined modules + const moduleIds = new Set(); const plugin: Plugin = { name: 'vite-plugin-qwik-speak-inline', enforce: 'post', - // Apply only on build - apply: 'build', + apply: undefined, // both configResolved(resolvedConfig) { - target = resolvedConfig.build?.ssr || resolvedConfig.mode === 'ssr' ? 'ssr' : 'client'; + if (resolvedConfig.build?.ssr || resolvedConfig.mode === 'ssr') { + target = 'ssr'; + } else if (resolvedConfig.mode === 'lib') { + target = 'lib'; + } else if (resolvedConfig.mode === 'test') { + target = 'test'; + } else { + target = 'client'; + } + mode = resolvedConfig.isProduction || resolvedConfig.mode === 'production' ? 'prod' : 'dev'; const inputOption = resolvedConfig.build?.rollupOptions?.input; if (inputOption) { @@ -62,41 +81,52 @@ export function qwikSpeakInline(options: QwikSpeakInlineOptions): Plugin { input = input?.split('/')?.pop(); }, + configureServer(server) { + // In dev mode, listen to lang from client + if (mode === 'dev') { + server.ws.on('qwik-speak:lang', (data) => { + if (devLang && devLang !== data.msg) { + // Invalidate inlined modules + for (const id of moduleIds) { + const module = server.moduleGraph.getModuleById(id); + if (module) server.moduleGraph.invalidateModule(module); + } + moduleIds.clear(); + } + // Update current lang + devLang = data.msg; + }); + } + }, + + handleHotUpdate({ file, server }) { + // Filter json + if (new RegExp(resolvedOptions.assetsPath).test(file) && /\.(json)$/.test(file)) { + for (const lang of resolvedOptions.supportedLangs) { + if (new RegExp(lang).test(file)) { + loadTranslations(translation, [lang], resolvedOptions.basePath, resolvedOptions.assetsPath); + } + } + // Invalidate inlined modules + for (const id of moduleIds) { + const module = server.moduleGraph.getModuleById(id); + if (module) server.moduleGraph.invalidateModule(module); + } + moduleIds.clear(); + } + }, + /** * Load translation files when build starts */ async buildStart() { - if (target === 'client') { - // For all langs - await Promise.all(resolvedOptions.supportedLangs.map(async lang => { - const baseDir = normalize(`${resolvedOptions.basePath}/${resolvedOptions.assetsPath}/${lang}`); - // For all files - const files = await readdir(baseDir); - - if (files.length > 0) { - const ext = extname(files[0]); - let data: Translation = {}; - - const tasks = files.map(filename => readFile(`${baseDir}/${filename}`, 'utf8')); - const sources = await Promise.all(tasks); - - for (const source of sources) { - if (source) { - let parsed: Translation = {}; - - switch (ext) { - case '.json': - parsed = parseJson(source); - break; - } - - data = merge(data, parsed); - } - } - - translation[lang] = { ...translation[lang], ...data }; // Shallow merge - } - })); + if (target === 'client' || mode === 'dev') { + await loadTranslations( + translation, + resolvedOptions.supportedLangs, + resolvedOptions.basePath, + resolvedOptions.assetsPath + ); } }, @@ -104,35 +134,42 @@ export function qwikSpeakInline(options: QwikSpeakInlineOptions): Plugin { * Transform functions * Prefer transform hook because unused imports will be removed, unlike renderChunk */ - async transform(code: string, id: string) { - if (target === 'client') { + async transform(code: string, id: string, options) { + if (target === 'client' || (target === 'ssr' && options?.ssr === false)) { // Filter id if (/\/src\//.test(id) && /\.(js|cjs|mjs|jsx|ts|tsx)$/.test(id)) { - // Filter code: usePlural - if (/usePlural/.test(code)) { + // Filter code: inlinePlural + if (matchInlinePlural(code)) { code = transformPlural(code); } - // Filter code: useTranslate - if (/useTranslate/.test(code)) { - code = transform(code); - } // Filter code: inlineTranslate - if (/inlineTranslate/.test(code)) { - code = transformInline(code); + if (matchInlineTranslate(code)) { + code = transformTranslate(code); } + + // Inline in dev mode + if (mode === 'dev') { + if (code.includes(inlineTranslatePlaceholder) || + code.includes(inlinePluralPlaceholder)) { + code = inlineAll(code, devLang, resolvedOptions, translation); + + moduleIds.add(id); + } + } + return code; } } // Check base url if (target === 'ssr') { - if (id.endsWith('entry.ssr.tsx' || id.endsWith('entry.ssr.jsx'))) { + if (id.endsWith('entry.ssr.tsx') || id.endsWith('entry.ssr.jsx')) { if (!/(? log.write(x + '\n')); - dynamicKeys.forEach(x => log.write(x + '\n')); - dynamicParams.forEach(x => log.write(x + '\n')); - log.write((`Qwik Speak Inline: build ends at ${new Date().toLocaleString()}\n`)); + log.write("\nMake sure the keys are in 'runtimeAssets':\n"); + dynamics.forEach(x => log.write(x + '\n')); - if (missingValues.length > 0 || dynamicKeys.length > 0 || dynamicParams.length > 0) { + log.write((`\nQwik Speak Inline: build ends at ${new Date().toLocaleString()}\n`)); + + if (missingValues.length > 0 || dynamics.length > 0) { console.log( '\n\x1b[33mQwik Speak Inline warn\x1b[0m\n%s', 'There are missing values or dynamic keys: see ./qwik-speak-inline.log' @@ -177,6 +216,46 @@ export function qwikSpeakInline(options: QwikSpeakInlineOptions): Plugin { return plugin; } +export async function loadTranslations( + translation: Translation, + langs: string[], + basePath: string, + assetsPath: string +) { + // For all langs + await Promise.all(langs.map(async lang => { + const baseDir = normalize(`${basePath}/${assetsPath}/${lang}`); + // For all files + if (existsSync(baseDir)) { + const files = await readdir(baseDir); + + if (files.length > 0) { + const ext = extname(files[0]); + let data: Translation = {}; + + const tasks = files.map(filename => readFile(`${baseDir}/${filename}`, 'utf8')); + const sources = await Promise.all(tasks); + + for (const source of sources) { + if (source) { + let parsed: Translation = {}; + + switch (ext) { + case '.json': + parsed = parseJson(source); + break; + } + + data = merge(data, parsed); + } + } + + translation[lang] = { ...translation[lang], ...data }; // Shallow merge + } + } + })); +} + export async function writeChunks( lang: string, bundles: (OutputAsset | OutputChunk)[], @@ -197,15 +276,7 @@ export async function writeChunks( // Inline let code = chunk.code; - if (code.includes(inlinePluralPlaceholder)) { - code = inlinePlural(code, inlinePluralPlaceholder, inlinePlaceholder, lang, opts); - } - if (code.includes(inlinePlaceholder)) { - code = inline(code, translation, inlinePlaceholder, lang, opts); - } - if (code.includes(inlineTranslatePlaceholder)) { - code = inline(code, translation, inlineTranslatePlaceholder, lang, opts); - } + code = inlineAll(code, lang, opts, translation); tasks.push(writeFile(filename, code)); // Original chunks to default lang @@ -220,86 +291,56 @@ export async function writeChunks( } /** - * Transform useTranslate to placeholder + * Transform inlineTranslate to placeholder */ -export function transform(code: string): string { - const alias = getUseTranslateAlias(code); - - if (alias) { - // Parse sequence - const sequence = parseSequenceExpressions(code, alias); - - if (sequence.length === 0) return code; - - for (const expr of sequence) { - // Original function - const originalFn = expr.value; - // Arguments - const args = expr.arguments; - - if (args?.length > 0) { - if (checkDynamic(args, originalFn)) continue; +export function transformTranslate(code: string): string { + const alias = getInlineTranslateAlias(code); - // Transpile with placeholder - const transpiled = originalFn.replace(new RegExp(`${alias}\\(`), `${inlinePlaceholder}(`); - // Replace - code = code.replace(originalFn, transpiled); - } - } - } + if (!alias) return code; - // Props - const sequence = parseSequenceExpressions(code, signalAlias); + let dynamic = false; + // Parse sequence + const sequence = parseSequenceExpressions(code, alias); if (sequence.length === 0) return code; for (const expr of sequence) { + // Original function + const originalFn = expr.value; // Arguments const args = expr.arguments; - // Check identifier - if (args?.length > 2) { - if (args[args.length - 1].type === 'ArrayExpression') { - const elements = args[args.length - 1].elements; - if (elements && elements.find(element => new RegExp(`^${alias}$`).test(element.value))) { - const index = elements.findIndex(element => new RegExp(`^${alias}$`).test(element.value)); - if (args[index].type === 'Identifier' && args[args.length - 2].type === 'CallExpression') { - // Transformed function - const transformedFn = args[args.length - 2].value; - if (transformedFn && args[index].value) { - const transformedAlias = `\\b${args[index].value}`; - const tokens = tokenize(transformedFn); - const transformedExpr = parse(tokens, transformedFn, transformedAlias); - - if (transformedExpr) { - // Arguments - const transformedArgs = transformedExpr.arguments; - - if (transformedArgs?.length > 0) { - if (checkDynamic(transformedArgs, transformedFn)) continue; - - // Transpile with placeholder - const transpiled = transformedFn.replace(new RegExp(`${transformedAlias}\\(`), `${inlinePlaceholder}(`); - // Replace - code = code.replace(transformedFn, transpiled); - } - } - } - } - } + if (args?.length > 0) { + // Dynamic + if (checkDynamicTranslate(args, originalFn)) { + dynamic = true; + continue; } + + // Transpile with placeholder + const transpiled = originalFn.replace(new RegExp(`${alias}\\(`), `${inlineTranslatePlaceholder}(`); + // Replace + code = code.replace(originalFn, transpiled); } } + // Remove invocation + if (!dynamic) { + code = removeInlineTranslate(code, alias); + } + return code; } /** - * Transform inlineTranslate to placeholder + * Transform inlinePlural to placeholder */ -export function transformInline(code: string): string { - const alias = getInlineTranslateAlias(code); +export function transformPlural(code: string): string { + const alias = getInlinePluralAlias(code); + + if (!alias) return code; + let dynamic = false; // Parse sequence const sequence = parseSequenceExpressions(code, alias); @@ -312,51 +353,42 @@ export function transformInline(code: string): string { const args = expr.arguments; if (args?.length > 0) { - if (checkDynamicInline(args, originalFn)) continue; + if (checkDynamicPlural(args, originalFn)) { + dynamic = true; + continue; + } // Transpile with placeholder - const transpiled = originalFn.replace(new RegExp(`${alias}\\(`), `${inlineTranslatePlaceholder}(`); + const transpiled = originalFn.replace(new RegExp(`${alias}\\(`), `${inlinePluralPlaceholder}(`); // Replace code = code.replace(originalFn, transpiled); } } + // Remove invocation + if (!dynamic) { + code = removeInlinePlural(code, alias); + } + return code; } -/** - * Transform usePlural to placeholder - */ -export function transformPlural(code: string): string { - const alias = getUsePluralAlias(code); - - if (alias) { - // Parse sequence - const sequence = parseSequenceExpressions(code, alias); - - if (sequence.length === 0) return code; - - for (const expr of sequence) { - // Original function - const originalFn = expr.value; - // Arguments - const args = expr.arguments; - - if (args?.length > 0) { - if (checkDynamicPlural(args, originalFn)) continue; - - // Transpile with placeholder - const transpiled = originalFn.replace(new RegExp(`${alias}\\(`), `${inlinePluralPlaceholder}(`); - // Replace - code = code.replace(originalFn, transpiled); - } - } +export function inlineAll( + code: string, + lang: string, + opts: Required, + translation: Translation +) { + if (code.includes(inlinePluralPlaceholder)) { + code = inlinePlural(code, inlinePluralPlaceholder, inlineTranslatePlaceholder, lang, opts); + } + if (code.includes(inlineTranslatePlaceholder)) { + code = inlineTranslate(code, translation, inlineTranslatePlaceholder, lang, opts); } - return code; } -export function inline( +export function inlineTranslate( code: string, translation: Translation, placeholder: string, @@ -375,55 +407,43 @@ export function inline( const args = expr.arguments; if (args?.length > 0) { - const resolvedLang = withLang(lang, placeholder === inlinePlaceholder ? args[2] : args[3], opts); + const resolvedLang = withLang(lang, args[2], opts); let resolvedValue: string | Translation = quoteValue(''); - // Get array of keys or key if (args[0].type === 'ArrayExpression') { - const keys = getKeys(args[0], opts.keyValueSeparator); + const keys = getKeys(args[0]); const keyValues: (string | Translation)[] = []; - for (const { key, defaultValue } of keys) { + for (const key of keys) { const value = getValue( key, translation[resolvedLang], - placeholder === inlinePlaceholder ? args[1] : args[2], - opts.keySeparator + args[1], + opts.keySeparator, + opts.keyValueSeparator, + resolvedLang ); - if (!value) { - missingValues.push(`${resolvedLang} - missing value for key: ${key}`); - if (defaultValue) { - keyValues.push(quoteValue(defaultValue)); - } else { - keyValues.push(quoteValue('')); - } - } else { - keyValues.push(value); - } + keyValues.push(value); } resolvedValue = keyValues; } else if (args?.[0]?.value) { - const { key, defaultValue } = getKey(args[0].value, opts.keyValueSeparator); + const key = getKey(args[0]); const value = getValue( key, translation[resolvedLang], - placeholder === inlinePlaceholder ? args[1] : args[2], - opts.keySeparator + args[1], + opts.keySeparator, + opts.keyValueSeparator, + resolvedLang ); - if (!value) { - missingValues.push(`${resolvedLang} - missing value for key: ${key}`); - if (defaultValue) { - resolvedValue = quoteValue(defaultValue); - } - } else { - resolvedValue = value; - } + + resolvedValue = value; } // Transpile - const transpiled = transpileFn(resolvedValue); + const transpiled = transpileTranslateFn(resolvedValue); // Replace code = code.replace(originalFn, transpiled); @@ -470,9 +490,9 @@ export function inlinePlural( } /** - * Transpile the function + * Transpile the translate function */ -export function transpileFn(value: string | Translation): string { +export function transpileTranslateFn(value: string | Translation): string { if (typeof value === 'object') { return `${stringifyObject(value)}`; } else { @@ -528,20 +548,16 @@ export function transpilePluralFn( return translation; } -export function checkDynamic(args: Argument[], originalFn: string): boolean { +export function checkDynamicTranslate(args: Argument[], originalFn: string): boolean { if (args?.[0]?.value) { // Dynamic key if (args[0].type === 'Identifier') { - dynamicKeys.push( - `dynamic key: ${originalFn.replace(/\s+/g, ' ')} - Make sure the keys are in 'runtimeAssets'` - ) + logDynamic(originalFn, 'key'); return true; } if (args[0].type === 'Literal') { if (/\${.*}/.test(args[0].value)) { - dynamicKeys.push( - `dynamic key: ${originalFn.replace(/\s+/g, ' ')} - Make sure the keys are in 'runtimeAssets'` - ) + logDynamic(originalFn, 'key'); return true; } } @@ -549,39 +565,7 @@ export function checkDynamic(args: Argument[], originalFn: string): boolean { // Dynamic argument (params, lang) if (args[1]?.type === 'Identifier' || args[1]?.type === 'CallExpression' || args[2]?.type === 'Identifier' || args[2]?.type === 'CallExpression') { - dynamicParams.push( - `dynamic params: ${originalFn.replace(/\s+/g, ' ')} - Make sure the keys are in 'runtimeAssets'` - ); - return true; - } - } - return false; -} - -export function checkDynamicInline(args: Argument[], originalFn: string): boolean { - if (args?.[0]?.value) { - // Dynamic key - if (args[0].type === 'Identifier') { - dynamicKeys.push( - `dynamic key: ${originalFn.replace(/\s+/g, ' ')} - Make sure the keys are in 'runtimeAssets'` - ) - return true; - } - if (args[0].type === 'Literal') { - if (/\${.*}/.test(args[0].value)) { - dynamicKeys.push( - `dynamic key: ${originalFn.replace(/\s+/g, ' ')} - Make sure the keys are in 'runtimeAssets'` - ) - return true; - } - } - - // Dynamic argument (params, lang) - if (args[2]?.type === 'Identifier' || args[2]?.type === 'CallExpression' || - args[3]?.type === 'Identifier' || args[3]?.type === 'CallExpression') { - dynamicParams.push(` - dynamic params: ${originalFn.replace(/\s+/g, ' ')} - Make sure the keys are in 'runtimeAssets'` - ); + logDynamic(originalFn, 'params'); return true; } } @@ -595,9 +579,7 @@ export function checkDynamicPlural(args: Argument[], originalFn: string): boolea args[2]?.type === 'Identifier' || args[2]?.type === 'CallExpression' || args[3]?.type === 'Identifier' || args[3]?.type === 'CallExpression' || args[4]?.type === 'Identifier' || args[4]?.type === 'CallExpression') { - dynamicParams.push( - `dynamic plural: ${originalFn.replace(/\s+/g, ' ')} - Make sure the keys are in 'runtimeAssets'` - ); + logDynamic(originalFn, 'params'); return true; } } @@ -615,21 +597,16 @@ export function withLang(lang: string, arg: Argument, opts: Required (acc && acc[cur] !== undefined) ? acc[cur] : @@ -654,9 +637,18 @@ export function getValue( if (value) { if (typeof value === 'string') return params ? transpileParams(value, params) : quoteValue(value); if (typeof value === 'object') return params ? transpileObjectParams(value, params) : value; + } else if (lang) { + logMissingValue(lang, key); } - return undefined; + if (defaultValue) { + if (!/^[[{].*[\]}]$/.test(defaultValue) || /^{{/.test(defaultValue)) + return params ? transpileParams(defaultValue, params) : quoteValue(defaultValue); + // Default value is an array/object + return params ? transpileObjectParams(JSON.parse(defaultValue), params) : JSON.parse(defaultValue); + } + + return mode === 'dev' ? quoteValue(key) : quoteValue(''); } export function transpileObjectParams(value: Translation, params?: Argument): Translation { @@ -710,6 +702,32 @@ export function stringifyObject(value: Translation): string { return strValue; } +export function logMissingValue(lang: string, key: string) { + const text = missingValueText(lang, key); + if (!missingValues.includes(text)) { + missingValues.push(text); + } +} + +export function logDynamic(originalFn: string, type: 'key' | 'params') { + const text = dynamicText(trimFn(originalFn), type); + if (!dynamics.includes(text)) { + dynamics.push(text); + } +} + +export function trimFn(fn: string): string { + return fn.replace(/\s+/g, ' ').trim(); +} + +export function removeInlineTranslate(code: string, alias: string): string { + return code.replace(new RegExp(`\\bconst\\s${alias}\\s=\\sinlineTranslate\\(\\);?`, 'g'), ''); +} + +export function removeInlinePlural(code: string, alias: string): string { + return code.replace(new RegExp(`\\bconst\\s${alias}\\s=\\sinlinePlural\\(\\);?`, 'g'), ''); +} + /** * Replace quoted values with a placeholder */ @@ -717,5 +735,3 @@ function replacer(key: string, value: string | Translation): string | Translatio if (typeof value === 'string' && /^`.*`$/.test(value)) return value.replace(/^`/, '__qsOpenBt').replace(/`$/, '__qsCloseBt'); return value; } - - diff --git a/packages/qwik-speak/tools/tests/extract.test.ts b/packages/qwik-speak/tools/tests/extract.test.ts index 0f91f44..8a7c0e3 100644 --- a/packages/qwik-speak/tools/tests/extract.test.ts +++ b/packages/qwik-speak/tools/tests/extract.test.ts @@ -14,7 +14,7 @@ vi.mock('fs/promises', async () => { ...mod, readdir: vi.fn() .mockImplementationOnce(() => [{ name: 'home.tsx', isDirectory: () => false }]) - .mockImplementationOnce(() => ['home.json']), + .mockImplementationOnce(() => ['app.json']), readFile: vi.fn() .mockImplementationOnce(() => mockSource) .mockImplementationOnce(() => mockAsset), @@ -32,13 +32,7 @@ describe('extract', () => { expect(readdir).toHaveBeenCalledTimes(2); expect(readFile).toHaveBeenCalledTimes(2); - expect(writeFile).toHaveBeenCalledTimes(2); - expect(writeFile).toHaveBeenNthCalledWith(1, normalize('../../i18n/en-US/app.json'), `{ - "app": { - "subtitle": "", - "title": "" - } -}`); - expect(writeFile).toHaveBeenNthCalledWith(2, normalize('../../i18n/en-US/home.json'), mockExtractedAsset); + expect(writeFile).toHaveBeenCalledTimes(1); + expect(writeFile).toHaveBeenNthCalledWith(1, normalize('../../i18n/en-US/app.json'), mockExtractedAsset); }); }); diff --git a/packages/qwik-speak/tools/tests/format.test.ts b/packages/qwik-speak/tools/tests/format.test.ts index 9a87815..1ddab39 100644 --- a/packages/qwik-speak/tools/tests/format.test.ts +++ b/packages/qwik-speak/tools/tests/format.test.ts @@ -1,19 +1,8 @@ import { test, describe, expect } from 'vitest'; -import { minDepth, sortTarget } from '../core/format'; +import { sortTarget } from '../core/format'; describe('format', () => { - test('minDepth', () => { - let target = {}; - let depth = minDepth(target); - expect(depth).toBe(0); - target = { key1: { subkey1: 'Subkey1' }, key2: 'Key2' }; - depth = minDepth(target); - expect(depth).toBe(1); - target = { key1: { subkey1: 'Subkey1' }, key2: { subkey2: 'Subkey2' } }; - depth = minDepth(target); - expect(depth).toBe(2); - }); test('sortTarget', () => { let target = { b: { b: 'B', a: 'A' }, a: 'A' }; target = sortTarget(target); diff --git a/packages/qwik-speak/tools/tests/inline.test.ts b/packages/qwik-speak/tools/tests/inline.test.ts index a9819af..9e5f8cb 100644 --- a/packages/qwik-speak/tools/tests/inline.test.ts +++ b/packages/qwik-speak/tools/tests/inline.test.ts @@ -4,7 +4,7 @@ import { writeFile } from 'fs/promises'; import { normalize } from 'path'; import { getRules } from '../core/intl-parser'; -import { getKey, getValue, inline, qwikSpeakInline, transform, transformInline, transpileFn, transpilePluralFn } from '../inline/plugin'; +import { getValue, inlineTranslate, qwikSpeakInline, transformTranslate, transpileTranslateFn, transpilePluralFn } from '../inline/plugin'; import { mockChunkCode, mockCode, mockInlinedCode, mockInlinedCodeByLang, mockTransformedCode, mockTranslatedAsset, mockTranslatedAssetByLang } from './mock'; // Mock part of 'fs' module @@ -33,18 +33,13 @@ vi.mock('fs/promises', async () => { }); describe('inline', () => { - test('getKey', () => { - const { key, defaultValue } = getKey('key1@@Key1', '@@'); - expect(key).toBe('key1'); - expect(defaultValue).toBe('Key1'); - }); test('getValue', () => { - let value = getValue('key1', { key1: 'Key1' }, undefined, '.'); + let value = getValue('key1', { key1: 'Key1' }, undefined, '.', '@@'); expect(value).toBe('`Key1`'); - value = getValue('key1.subkey1', { key1: { subkey1: 'Subkey1' } }, undefined, '.'); + value = getValue('key1.subkey1', { key1: { subkey1: 'Subkey1' } }, undefined, '.', '@@'); expect(value).toBe('`Subkey1`'); - value = getValue('key1.subkey2', { key1: { subkey1: 'Subkey1' } }, undefined, '.'); - expect(value).toBeUndefined(); + value = getValue('key1.subkey2', { key1: { subkey1: 'Subkey1' } }, undefined, '.', '@@'); + expect(value).toBe('``'); value = getValue('key1', { key1: 'Key1 {{param1}}' }, { type: 'ObjectExpression', properties: [ { @@ -53,7 +48,7 @@ describe('inline', () => { value: { type: 'Literal', value: 'Param1' } } ] - }, '.'); + }, '.', '@@'); expect(value).toBe('`Key1 Param1`'); value = getValue('key1', { key1: 'Key1 {{param1}} and {{param2}}' }, { @@ -69,7 +64,7 @@ describe('inline', () => { value: { type: 'Expression', value: 'variable' } } ] - }, '.'); + }, '.', '@@'); expect(value).toBe('`Key1 Param1 and ${variable}`'); value = getValue('key1', { key1: 'Key1' }, { type: 'ObjectExpression', properties: [ @@ -79,7 +74,7 @@ describe('inline', () => { value: { type: 'Literal', value: 'Param1' } } ] - }, '.'); + }, '.', '@@'); expect(value).toBe('`Key1`'); value = getValue('key1', { key1: 'Key1 {{param1}}' }, { type: 'ObjectExpression', properties: [ @@ -89,7 +84,7 @@ describe('inline', () => { value: { type: 'Literal', value: 'Param2' } } ] - }, '.'); + }, '.', '@@'); expect(value).toBe('`Key1 {{param1}}`'); value = getValue('key1', { key1: 'Key1 {{param1}}' }, { @@ -100,41 +95,41 @@ describe('inline', () => { value: { type: 'Literal', value: 'Param1 ${variable}' } } ] - }, '.'); + }, '.', '@@'); expect(value).toBe('`Key1 Param1 ${variable}`'); }); test('transpileFn', () => { const value = '`Value`'; - const line = transpileFn(value); + const line = transpileTranslateFn(value); expect(line).toBe('`Value`'); }); test('transpileFn with array', () => { let value = ['`Value1`', '`Value2`']; - let line = transpileFn(value); + let line = transpileTranslateFn(value); expect(line).toBe('[`Value1`,`Value2`]'); value = ['Value1', 'Value2']; - line = transpileFn(value); + line = transpileTranslateFn(value); expect(line).toBe('["Value1","Value2"]'); }); test('transpileFn with objects', () => { const value = { value1: 'Value1' }; - const line = transpileFn(value); + const line = transpileTranslateFn(value); expect(line).toBe('{"value1":"Value1"}'); }); test('transpilePluralFn', () => { const rules = getRules('en-US'); - const line = transpilePluralFn(rules, 'en-US', '__qsInline', + const line = transpilePluralFn(rules, 'en-US', '__qsInlineTranslate', [ { type: 'Identifier', value: 'count.value' }, { type: 'Literal', value: 'home.devs' } ], { keySeparator: '.' } as any ); - expect(line).toBe('(new Intl.PluralRules(`en-US`).select(+count.value) === `other` && __qsInline(`home.devs.other`, {value: count.value}, `en-US`) || __qsInline(`home.devs.one`, {value: count.value}, `en-US`))'); + expect(line).toBe('(new Intl.PluralRules(`en-US`).select(+count.value) === `other` && __qsInlineTranslate(`home.devs.other`, {value: count.value}, `en-US`) || __qsInlineTranslate(`home.devs.one`, {value: count.value}, `en-US`))'); }); test('transpilePluralFn with params and options', () => { const rules = getRules('en-US'); - const line = transpilePluralFn(rules, 'en-US', '__qsInline', + const line = transpilePluralFn(rules, 'en-US', '__qsInlineTranslate', [ { type: 'Identifier', value: 'count.value' }, { type: 'Literal', value: 'home.devs' }, @@ -155,10 +150,10 @@ describe('inline', () => { ], { keySeparator: '.' } as any ); - expect(line).toBe('(new Intl.PluralRules(`en-US`, {type: `cardinal`}).select(+count.value) === `other` && __qsInline(`home.devs.other`, {value: count.value, role: `software`}, `en-US`) || __qsInline(`home.devs.one`, {value: count.value, role: `software`}, `en-US`))'); + expect(line).toBe('(new Intl.PluralRules(`en-US`, {type: `cardinal`}).select(+count.value) === `other` && __qsInlineTranslate(`home.devs.other`, {value: count.value, role: `software`}, `en-US`) || __qsInlineTranslate(`home.devs.one`, {value: count.value, role: `software`}, `en-US`))'); }); test('inline arrays', async () => { - const inlined = inline(`const values = __qsInline(['app.title', 'app.subtitle'])`, + const inlined = inlineTranslate(`const values = __qsInlineTranslate(['app.title', 'app.subtitle'])`, { 'en-US': { 'app': { @@ -167,7 +162,7 @@ describe('inline', () => { } } }, - '__qsInline', + '__qsInlineTranslate', 'en-US', { supportedLangs: ['en-US', 'it-IT'], @@ -181,9 +176,9 @@ describe('inline', () => { expect(inlined).toBe('const values = [`Qwik Speak`,`Translate your Qwik apps into any language`]'); }); test('transform & inline multilingual', async () => { - const code = `import { useTranslate } from "qwik-speak";const t = useTranslate();const value = t('app.subtitle', undefined, 'it-IT')`; - const transformed = transform(code); - const inlined = inline(transformed, + const code = `import { inlineTranslate } from "qwik-speak";const t = inlineTranslate();const value = t('app.subtitle', undefined, 'it-IT')`; + const transformed = transformTranslate(code); + const inlined = inlineTranslate(transformed, { 'en-US': { 'app': { @@ -196,30 +191,6 @@ describe('inline', () => { } } }, - '__qsInline', - 'en-US', - { - supportedLangs: ['en-US', 'it-IT'], - defaultLang: 'en-US', - keySeparator: '.', - keyValueSeparator: '@@', - basePath: './', - assetsPath: 'i18n', - outDir: 'dist' - }); - expect(inlined).toBe('import { useTranslate } from "qwik-speak";const t = useTranslate();const value = `Traduci le tue app Qwik in qualsiasi lingua`'); - }); - test('transform & inlineTranslate', async () => { - const code = `import { inlineTranslate as t } from "qwik-speak";const value = t('app.subtitle', ctx)`; - const transformed = transformInline(code); - const inlined = inline(transformed, - { - 'en-US': { - 'app': { - 'subtitle': 'Translate your Qwik apps into any language', - } - } - }, '__qsInlineTranslate', 'en-US', { @@ -231,7 +202,7 @@ describe('inline', () => { assetsPath: 'i18n', outDir: 'dist' }); - expect(inlined).toBe('import { inlineTranslate as t } from "qwik-speak";const value = `Translate your Qwik apps into any language`'); + expect(inlined).toBe('import { inlineTranslate } from "qwik-speak";const value = `Traduci le tue app Qwik in qualsiasi lingua`'); }); test('writeChunks', async () => { const plugin = qwikSpeakInline({ @@ -239,7 +210,7 @@ describe('inline', () => { defaultLang: 'en-US', basePath: '../../' }) as any; - await plugin.configResolved?.({}); + await plugin.configResolved?.({ isProduction: true }); await plugin.buildStart?.(); const transformed = await plugin.transform?.(mockCode, '/src/mock.code.js'); expect(transformed).toBe(mockTransformedCode); diff --git a/packages/qwik-speak/tools/tests/mock.ts b/packages/qwik-speak/tools/tests/mock.ts index ce975e2..2217b67 100644 --- a/packages/qwik-speak/tools/tests/mock.ts +++ b/packages/qwik-speak/tools/tests/mock.ts @@ -1,49 +1,47 @@ /* eslint-disable */ export const mockSource = `import { component$, useSignal } from '@builder.io/qwik'; -import type { DocumentHead } from '@builder.io/qwik-city'; +import { type DocumentHead } from '@builder.io/qwik-city'; import { - Speak, inlineTranslate, + inlinePlural, useFormatDate, useFormatNumber, - usePlural, useRelativeTime, - useSpeakContext, useSpeakLocale, - useTranslate + type Translation } from 'qwik-speak'; -import type { SpeakState, Translation } from 'qwik-speak'; interface TitleProps { name: string; } -export const Title = component$((props: TitleProps) => { +export const Title = component$(props => { return (

{props.name}

) }); -export const SubTitle = (props: { ctx: SpeakState }) => { - return

{inlineTranslate('app.subtitle', props.ctx)}

; +export const SubTitle = () => { + const t = inlineTranslate(); + return

{t('app.subtitle')}

; }; -export const Home = component$(() => { - const t = useTranslate(); - const p = usePlural(); +export default component$(() => { + const t = inlineTranslate(); + const p = inlinePlural(); + const fd = useFormatDate(); const rt = useRelativeTime(); const fn = useFormatNumber(); - const ctx = useSpeakContext(); const locale = useSpeakLocale(); const units = locale.units!; const count = useSignal(0); - const tParam = t('home.greeting', { name: t('app.title') }); - const tArray = t('home.array@@["{{ name }} one", "{{ name }} two"]', { name: 'n.' }); - const item = t('home.array.2@@{{ name }} three', { name: 'n.' }); - const tObject = t('home.obj@@{"one": "{{ name }} one", "two": "{{ name }} two"}', { name: 'n.' }); - const tArrayObjects = t('home.arrayObjects@@[{"num": "one"}, {"num": "two"}]'); + const tParam = t('greeting', { name: t('app.title') }); + const tArray = t('array@@["{{ name }} one", "{{ name }} two"]', { name: 'n.' }); + const item = t('array.2@@{{ name }} three', { name: 'n.' }); + const tObject = t('obj@@{"one": "{{ name }} one", "two": "{{ name }} two"}', { name: 'n.' }); + const tArrayObjects = t('arrayObjects@@[{"num": "one"}, {"num": "two"}]'); console.log(tParam); tArray.map((x) => console.log(x)); console.log(item); @@ -54,23 +52,23 @@ export const Home = component$(() => {
- <SubTitle ctx={ctx} /> + <SubTitle /> - <h3>{t('home.params')}</h3> - <p>{t('home.greeting', { name: 'Qwik Speak' })}</p> + <h3>{t('params')}</h3> + <p>{t('greeting', { name: 'Qwik Speak' })}</p> - <h3>{t('home.tags')}</h3> - <p dangerouslySetInnerHTML={t('home.text')}></p> + <h3>{t('tags')}</h3> + <p dangerouslySetInnerHTML={t('description')}></p> - <h3>{t('home.plural')}</h3> - <p class="counter">{p(count.value, 'home.devs')}</p> - <button class="btn-counter" onClick$={() => count.value++}>{t('home.increment')}</button> + <h3>{t('plural')}</h3> + <p class="counter">{p(count.value, 'devs')}</p> + <button class="btn-counter" onClick$={() => count.value++}>{t('increment')}</button> - <h3>{t('home.dates')}</h3> + <h3>{t('dates')}</h3> <p>{fd(Date.now(), { dateStyle: 'full', timeStyle: 'short' })}</p> <p>{rt(-1, 'second')}</p> - <h3>{t('home.numbers')}</h3> + <h3>{t('numbers')}</h3> <p>{fn(1000000)}</p> <p>{fn(1000000, { style: 'currency' })}</p> <p>{fn(1, { style: 'unit', unit: units['length'] })}</p> @@ -78,53 +76,53 @@ export const Home = component$(() => { ); }); -export default component$(() => { - return ( - /** - * Add Home translations (only available in child components) - */ - <Speak assets={['home']}> - <Home /> - </Speak> - ); -}); +export const head: DocumentHead = () => { + const t = inlineTranslate(); -export const head: DocumentHead = { - title: 'runtime.head.home.title', - meta: [{ name: 'description', content: 'runtime.head.home.description' }] + return { + title: t('app.head.home.title', { name: 'Qwik Speak' }), + meta: [ + { + name: 'description', + content: t('app.head.home.description') + } + ], + }; };`; export const mockCode = `import { SubTitle } from "./routes/[...lang]/index.tsx"; import { Title } from "./routes/[...lang]/index.tsx"; -import { _IMMUTABLE } from "@builder.io/qwik"; -import { _fnSignal } from "@builder.io/qwik"; import { _jsxC } from "@builder.io/qwik"; import { _jsxQ } from "@builder.io/qwik"; -import { qrl } from "@builder.io/qwik"; +import { inlinePlural } from "qwik-speak"; +import { inlineTranslate } from "qwik-speak"; +import { qrlDEV } from "@builder.io/qwik"; import { useFormatDate } from "qwik-speak"; import { useFormatNumber } from "qwik-speak"; -import { usePlural } from "qwik-speak"; import { useRelativeTime } from "qwik-speak"; import { useSignal } from "@builder.io/qwik"; -import { useSpeakContext } from "qwik-speak"; import { useSpeakLocale } from "qwik-speak"; -import { useTranslate } from "qwik-speak"; -export const s_dYGb4b0cyCA = ()=>{ - const t = useTranslate(); - const p = usePlural(); +export const ____lang__component_eTU0cN78ZUc = ()=>{ + const t = inlineTranslate(); + const p = inlinePlural(); const fd = useFormatDate(); const rt = useRelativeTime(); const fn = useFormatNumber(); - const ctx = useSpeakContext(); const locale = useSpeakLocale(); const count = useSignal(0); - const tParam = t('home.greeting', { + const tParam = t('greeting', { name: t('app.title') }); - const tArray = t('home.array@@["{{ name }} one", "{{ name }} two"]', { name: 'n.' }); - const item = t('home.array.2@@{{ name }} three', { name: 'n.' }); - const tObject = t('home.obj@@{"one": "{{ name }} one", "two": "{{ name }} two"}', { name: 'n.' }); - const tArrayObjects = t('home.arrayObjects@@[{"num": "one"}, {"num": "two"}]'); + const tArray = t('array@@["{{ name }} one", "{{ name }} two"]', { + name: 'n.' + }); + const item = t('array.2@@{{ name }} three', { + name: 'n.' + }); + const tObject = t('obj@@{"one": "{{ name }} one", "two": "{{ name }} two"}', { + name: 'n.' + }); + const tArrayObjects = t('arrayObjects@@[{"num": "one"}, {"num": "two"}]'); console.log(tParam); tArray.map((x)=>console.log(x)); console.log(item); @@ -134,90 +132,151 @@ export const s_dYGb4b0cyCA = ()=>{ class: "content" }, [ /*#__PURE__*/ _jsxC(Title, { - get name () { - return t('app.title'); - }, - [_IMMUTABLE]: { - name: _fnSignal((p0)=>p0('app.title'), [ - t - ]) - } - }, 3, "1L_2"), - /*#__PURE__*/ _jsxC(SubTitle, { - ctx: ctx, - [_IMMUTABLE]: { - ctx: _IMMUTABLE - } - }, 3, "1L_3"), - /*#__PURE__*/ _jsxQ("h3", null, null, t('home.params'), 1, null), - /*#__PURE__*/ _jsxQ("p", null, null, t('home.greeting', { + name: t('app.title') + }, 3, "1L_2", { + fileName: "routes/[...lang]/index.tsx", + lineNumber: 52, + columnNumber: 7 + }), + /*#__PURE__*/ _jsxC(SubTitle, null, 3, "1L_3", { + fileName: "routes/[...lang]/index.tsx", + lineNumber: 54, + columnNumber: 7 + }), + /*#__PURE__*/ _jsxQ("h3", null, null, t('params'), 1, null, { + fileName: "routes/[...lang]/index.tsx", + lineNumber: 56, + columnNumber: 7 + }), + /*#__PURE__*/ _jsxQ("p", null, null, t('greeting', { name: 'Qwik Speak' - }), 1, null), - /*#__PURE__*/ _jsxQ("h3", null, null, t('home.tags'), 1, null), - /*#__PURE__*/ _jsxQ("p", null, { - dangerouslySetInnerHTML: _fnSignal((p0)=>p0('home.text'), [ - t - ]) - }, null, 3, null), - /*#__PURE__*/ _jsxQ("h3", null, null, t('home.plural'), 1, null), + }), 1, null, { + fileName: "routes/[...lang]/index.tsx", + lineNumber: 57, + columnNumber: 7 + }), + /*#__PURE__*/ _jsxQ("h3", null, null, t('tags'), 1, null, { + fileName: "routes/[...lang]/index.tsx", + lineNumber: 59, + columnNumber: 7 + }), + /*#__PURE__*/ _jsxQ("p", { + dangerouslySetInnerHTML: t('description') + }, null, null, 3, null, { + fileName: "routes/[...lang]/index.tsx", + lineNumber: 60, + columnNumber: 7 + }), + /*#__PURE__*/ _jsxQ("h3", null, null, t('plural'), 1, null, { + fileName: "routes/[...lang]/index.tsx", + lineNumber: 62, + columnNumber: 7 + }), /*#__PURE__*/ _jsxQ("p", null, { class: "counter" - }, __qsInlinePlural(count.value, 'home.devs'), 1, null), + }, p(count.value, 'devs'), 1, null, { + fileName: "routes/[...lang]/index.tsx", + lineNumber: 63, + columnNumber: 7 + }), /*#__PURE__*/ _jsxQ("button", null, { class: "btn-counter", - onClick$: /*#__PURE__*/ qrl(()=>import("./entry_Home.js"), "s_UVYDAmatcag", [ + onClick$: /*#__PURE__*/ qrlDEV(()=>import("./____lang__component_div_button_onclick_xgivgs2jpeg.js"), "____lang__component_div_button_onClick_XGiVgs2jpeg", { + file: "/home/robisim74/documents/github/qwik-speak/src/routes/[...lang]/index.tsx", + lo: 1796, + hi: 1815, + displayName: "____lang__component_div_button_onClick" + }, [ count ]) - }, t('home.increment'), 1, null), - /*#__PURE__*/ _jsxQ("h3", null, null, t('home.dates'), 1, null), + }, t('increment'), 1, null, { + fileName: "routes/[...lang]/index.tsx", + lineNumber: 64, + columnNumber: 7 + }), + /*#__PURE__*/ _jsxQ("h3", null, null, t('dates'), 1, null, { + fileName: "routes/[...lang]/index.tsx", + lineNumber: 66, + columnNumber: 7 + }), /*#__PURE__*/ _jsxQ("p", null, null, fd(Date.now(), { dateStyle: 'full', timeStyle: 'short' - }), 1, null), - /*#__PURE__*/ _jsxQ("p", null, null, rt(-1, 'second'), 1, null), - /*#__PURE__*/ _jsxQ("h3", null, null, t('home.numbers'), 1, null), - /*#__PURE__*/ _jsxQ("p", null, null, fn(1000000), 1, null), + }), 1, null, { + fileName: "routes/[...lang]/index.tsx", + lineNumber: 67, + columnNumber: 7 + }), + /*#__PURE__*/ _jsxQ("p", null, null, rt(-1, 'second'), 1, null, { + fileName: "routes/[...lang]/index.tsx", + lineNumber: 68, + columnNumber: 7 + }), + /*#__PURE__*/ _jsxQ("h3", null, null, t('numbers'), 1, null, { + fileName: "routes/[...lang]/index.tsx", + lineNumber: 70, + columnNumber: 7 + }), + /*#__PURE__*/ _jsxQ("p", null, null, fn(1000000), 1, null, { + fileName: "routes/[...lang]/index.tsx", + lineNumber: 71, + columnNumber: 7 + }), /*#__PURE__*/ _jsxQ("p", null, null, fn(1000000, { style: 'currency' - }), 1, null), + }), 1, null, { + fileName: "routes/[...lang]/index.tsx", + lineNumber: 72, + columnNumber: 7 + }), /*#__PURE__*/ _jsxQ("p", null, null, fn(1, { style: 'unit', unit: locale.units['length'] - }), 1, null) - ], 1, "1L_4"); + }), 1, null, { + fileName: "routes/[...lang]/index.tsx", + lineNumber: 73, + columnNumber: 7 + }) + ], 1, "1L_4", { + fileName: "routes/[...lang]/index.tsx", + lineNumber: 51, + columnNumber: 5 + }); };`; export const mockTransformedCode = `import { SubTitle } from "./routes/[...lang]/index.tsx"; import { Title } from "./routes/[...lang]/index.tsx"; -import { _IMMUTABLE } from "@builder.io/qwik"; -import { _fnSignal } from "@builder.io/qwik"; import { _jsxC } from "@builder.io/qwik"; import { _jsxQ } from "@builder.io/qwik"; -import { qrl } from "@builder.io/qwik"; +import { inlinePlural } from "qwik-speak"; +import { inlineTranslate } from "qwik-speak"; +import { qrlDEV } from "@builder.io/qwik"; import { useFormatDate } from "qwik-speak"; import { useFormatNumber } from "qwik-speak"; -import { usePlural } from "qwik-speak"; import { useRelativeTime } from "qwik-speak"; import { useSignal } from "@builder.io/qwik"; -import { useSpeakContext } from "qwik-speak"; import { useSpeakLocale } from "qwik-speak"; -import { useTranslate } from "qwik-speak"; -export const s_dYGb4b0cyCA = ()=>{ - const t = useTranslate(); - const p = usePlural(); +export const ____lang__component_eTU0cN78ZUc = ()=>{ + + const fd = useFormatDate(); const rt = useRelativeTime(); const fn = useFormatNumber(); - const ctx = useSpeakContext(); const locale = useSpeakLocale(); const count = useSignal(0); - const tParam = __qsInline('home.greeting', { - name: __qsInline('app.title') + const tParam = __qsInlineTranslate('greeting', { + name: __qsInlineTranslate('app.title') + }); + const tArray = __qsInlineTranslate('array@@["{{ name }} one", "{{ name }} two"]', { + name: 'n.' }); - const tArray = __qsInline('home.array@@["{{ name }} one", "{{ name }} two"]', { name: 'n.' }); - const item = __qsInline('home.array.2@@{{ name }} three', { name: 'n.' }); - const tObject = __qsInline('home.obj@@{"one": "{{ name }} one", "two": "{{ name }} two"}', { name: 'n.' }); - const tArrayObjects = __qsInline('home.arrayObjects@@[{"num": "one"}, {"num": "two"}]'); + const item = __qsInlineTranslate('array.2@@{{ name }} three', { + name: 'n.' + }); + const tObject = __qsInlineTranslate('obj@@{"one": "{{ name }} one", "two": "{{ name }} two"}', { + name: 'n.' + }); + const tArrayObjects = __qsInlineTranslate('arrayObjects@@[{"num": "one"}, {"num": "two"}]'); console.log(tParam); tArray.map((x)=>console.log(x)); console.log(item); @@ -227,147 +286,192 @@ export const s_dYGb4b0cyCA = ()=>{ class: "content" }, [ /*#__PURE__*/ _jsxC(Title, { - get name () { - return __qsInline('app.title'); - }, - [_IMMUTABLE]: { - name: _fnSignal((p0)=>__qsInline('app.title'), [ - t - ]) - } - }, 3, "1L_2"), - /*#__PURE__*/ _jsxC(SubTitle, { - ctx: ctx, - [_IMMUTABLE]: { - ctx: _IMMUTABLE - } - }, 3, "1L_3"), - /*#__PURE__*/ _jsxQ("h3", null, null, __qsInline('home.params'), 1, null), - /*#__PURE__*/ _jsxQ("p", null, null, __qsInline('home.greeting', { + name: __qsInlineTranslate('app.title') + }, 3, "1L_2", { + fileName: "routes/[...lang]/index.tsx", + lineNumber: 52, + columnNumber: 7 + }), + /*#__PURE__*/ _jsxC(SubTitle, null, 3, "1L_3", { + fileName: "routes/[...lang]/index.tsx", + lineNumber: 54, + columnNumber: 7 + }), + /*#__PURE__*/ _jsxQ("h3", null, null, __qsInlineTranslate('params'), 1, null, { + fileName: "routes/[...lang]/index.tsx", + lineNumber: 56, + columnNumber: 7 + }), + /*#__PURE__*/ _jsxQ("p", null, null, __qsInlineTranslate('greeting', { name: 'Qwik Speak' - }), 1, null), - /*#__PURE__*/ _jsxQ("h3", null, null, __qsInline('home.tags'), 1, null), - /*#__PURE__*/ _jsxQ("p", null, { - dangerouslySetInnerHTML: _fnSignal((p0)=>__qsInline('home.text'), [ - t - ]) - }, null, 3, null), - /*#__PURE__*/ _jsxQ("h3", null, null, __qsInline('home.plural'), 1, null), + }), 1, null, { + fileName: "routes/[...lang]/index.tsx", + lineNumber: 57, + columnNumber: 7 + }), + /*#__PURE__*/ _jsxQ("h3", null, null, __qsInlineTranslate('tags'), 1, null, { + fileName: "routes/[...lang]/index.tsx", + lineNumber: 59, + columnNumber: 7 + }), + /*#__PURE__*/ _jsxQ("p", { + dangerouslySetInnerHTML: __qsInlineTranslate('description') + }, null, null, 3, null, { + fileName: "routes/[...lang]/index.tsx", + lineNumber: 60, + columnNumber: 7 + }), + /*#__PURE__*/ _jsxQ("h3", null, null, __qsInlineTranslate('plural'), 1, null, { + fileName: "routes/[...lang]/index.tsx", + lineNumber: 62, + columnNumber: 7 + }), /*#__PURE__*/ _jsxQ("p", null, { class: "counter" - }, __qsInlinePlural(count.value, 'home.devs'), 1, null), + }, __qsInlinePlural(count.value, 'devs'), 1, null, { + fileName: "routes/[...lang]/index.tsx", + lineNumber: 63, + columnNumber: 7 + }), /*#__PURE__*/ _jsxQ("button", null, { class: "btn-counter", - onClick$: /*#__PURE__*/ qrl(()=>import("./entry_Home.js"), "s_UVYDAmatcag", [ + onClick$: /*#__PURE__*/ qrlDEV(()=>import("./____lang__component_div_button_onclick_xgivgs2jpeg.js"), "____lang__component_div_button_onClick_XGiVgs2jpeg", { + file: "/home/robisim74/documents/github/qwik-speak/src/routes/[...lang]/index.tsx", + lo: 1796, + hi: 1815, + displayName: "____lang__component_div_button_onClick" + }, [ count ]) - }, __qsInline('home.increment'), 1, null), - /*#__PURE__*/ _jsxQ("h3", null, null, __qsInline('home.dates'), 1, null), + }, __qsInlineTranslate('increment'), 1, null, { + fileName: "routes/[...lang]/index.tsx", + lineNumber: 64, + columnNumber: 7 + }), + /*#__PURE__*/ _jsxQ("h3", null, null, __qsInlineTranslate('dates'), 1, null, { + fileName: "routes/[...lang]/index.tsx", + lineNumber: 66, + columnNumber: 7 + }), /*#__PURE__*/ _jsxQ("p", null, null, fd(Date.now(), { dateStyle: 'full', timeStyle: 'short' - }), 1, null), - /*#__PURE__*/ _jsxQ("p", null, null, rt(-1, 'second'), 1, null), - /*#__PURE__*/ _jsxQ("h3", null, null, __qsInline('home.numbers'), 1, null), - /*#__PURE__*/ _jsxQ("p", null, null, fn(1000000), 1, null), + }), 1, null, { + fileName: "routes/[...lang]/index.tsx", + lineNumber: 67, + columnNumber: 7 + }), + /*#__PURE__*/ _jsxQ("p", null, null, rt(-1, 'second'), 1, null, { + fileName: "routes/[...lang]/index.tsx", + lineNumber: 68, + columnNumber: 7 + }), + /*#__PURE__*/ _jsxQ("h3", null, null, __qsInlineTranslate('numbers'), 1, null, { + fileName: "routes/[...lang]/index.tsx", + lineNumber: 70, + columnNumber: 7 + }), + /*#__PURE__*/ _jsxQ("p", null, null, fn(1000000), 1, null, { + fileName: "routes/[...lang]/index.tsx", + lineNumber: 71, + columnNumber: 7 + }), /*#__PURE__*/ _jsxQ("p", null, null, fn(1000000, { style: 'currency' - }), 1, null), + }), 1, null, { + fileName: "routes/[...lang]/index.tsx", + lineNumber: 72, + columnNumber: 7 + }), /*#__PURE__*/ _jsxQ("p", null, null, fn(1, { style: 'unit', unit: locale.units['length'] - }), 1, null) - ], 1, "1L_4"); + }), 1, null, { + fileName: "routes/[...lang]/index.tsx", + lineNumber: 73, + columnNumber: 7 + }) + ], 1, "1L_4", { + fileName: "routes/[...lang]/index.tsx", + lineNumber: 51, + columnNumber: 5 + }); };`; -export const mockChunkCode = `const s_dYGb4b0cyCA = () => { - const t = useTranslate(); - usePlural(); +export const mockChunkCode = `const s_eTU0cN78ZUc = () => { const fd = useFormatDate(); const rt = useRelativeTime(); const fn = useFormatNumber(); - const ctx = useSpeakContext(); const locale = useSpeakLocale(); - const count = Sc(0); - const tParam = __qsInline("home.greeting", { - name: __qsInline("app.title") + const count = Qc(0); + const tParam = __qsInlineTranslate("greeting", { + name: __qsInlineTranslate("app.title") + }); + const tArray = __qsInlineTranslate('array@@["{{ name }} one", "{{ name }} two"]', { + name: "n." }); - const tArray = __qsInline('home.array@@["{{ name }} one", "{{ name }} two"]', { name: 'n.' }); - const item = __qsInline('home.array.2@@{{ name }} three', { name: 'n.' }); - const tObject = __qsInline('home.obj@@{"one": "{{ name }} one", "two": "{{ name }} two"}', { name: 'n.' }); - const tArrayObjects = __qsInline('home.arrayObjects@@[{"num": "one"}, {"num": "two"}]'); + const item = __qsInlineTranslate("array.2@@{{ name }} three", { + name: "n." + }); + const tObject = __qsInlineTranslate('obj@@{"one": "{{ name }} one", "two": "{{ name }} two"}', { + name: "n." + }); + const tArrayObjects = __qsInlineTranslate('arrayObjects@@[{"num": "one"}, {"num": "two"}]'); console.log(tParam); tArray.map((x) => console.log(x)); console.log(item); Object.values(tObject).map((x) => console.log(x)); tArrayObjects.map((x) => console.log(x["num"])); - return /* @__PURE__ */ Nr("div", null, { + return /* @__PURE__ */ Cr("div", null, { class: "content" }, [ - /* @__PURE__ */ Ur(Title, { - get name() { - return __qsInline("app.title"); - }, - [Pt]: { - name: Ot((p0) => __qsInline("app.title"), [ - t - ]) - } + /* @__PURE__ */ jr(Title, { + name: __qsInlineTranslate("app.title") }, 3, "1L_2"), - /* @__PURE__ */ Ur(SubTitle, { - ctx, - [Pt]: { - ctx: Pt - } - }, 3, "1L_3"), - /* @__PURE__ */ Nr("h3", null, null, __qsInline("home.params"), 1, null), - /* @__PURE__ */ Nr("p", null, null, __qsInline("home.greeting", { + /* @__PURE__ */ jr(SubTitle, null, 3, "1L_3"), + /* @__PURE__ */ Cr("h3", null, null, __qsInlineTranslate("params"), 1, null), + /* @__PURE__ */ Cr("p", null, null, __qsInlineTranslate("greeting", { name: "Qwik Speak" }), 1, null), - /* @__PURE__ */ Nr("h3", null, null, __qsInline("home.tags"), 1, null), - /* @__PURE__ */ Nr("p", null, { - dangerouslySetInnerHTML: Ot((p0) => __qsInline("home.text"), [ - t - ]) - }, null, 3, null), - /* @__PURE__ */ Nr("h3", null, null, __qsInline("home.plural"), 1, null), - /* @__PURE__ */ Nr("p", null, { + /* @__PURE__ */ Cr("h3", null, null, __qsInlineTranslate("tags"), 1, null), + /* @__PURE__ */ Cr("p", { + dangerouslySetInnerHTML: __qsInlineTranslate("description") + }, null, null, 3, null), + /* @__PURE__ */ Cr("h3", null, null, __qsInlineTranslate("plural"), 1, null), + /* @__PURE__ */ Cr("p", null, { class: "counter" - }, __qsInlinePlural(count.value, "home.devs"), 1, null), - /* @__PURE__ */ Nr("button", null, { + }, __qsInlinePlural(count.value, "devs"), 1, null), + /* @__PURE__ */ Cr("button", null, { class: "btn-counter", - onClick$: /* @__PURE__ */ z(() => __vitePreload(() => Promise.resolve().then(() => entry_Home), true ? void 0 : void 0), "s_UVYDAmatcag", [ + onClick$: /* @__PURE__ */ vs(() => __vitePreload(() => Promise.resolve().then(() => entry_____lang_), true ? void 0 : void 0), "s_XGiVgs2jpeg", [ count ]) - }, __qsInline("home.increment"), 1, null), - /* @__PURE__ */ Nr("h3", null, null, __qsInline("home.dates"), 1, null), - /* @__PURE__ */ Nr("p", null, null, fd(Date.now(), { + }, __qsInlineTranslate("increment"), 1, null), + /* @__PURE__ */ Cr("h3", null, null, __qsInlineTranslate("dates"), 1, null), + /* @__PURE__ */ Cr("p", null, null, fd(Date.now(), { dateStyle: "full", timeStyle: "short" }), 1, null), - /* @__PURE__ */ Nr("p", null, null, rt(-1, "second"), 1, null), - /* @__PURE__ */ Nr("h3", null, null, __qsInline("home.numbers"), 1, null), - /* @__PURE__ */ Nr("p", null, null, fn(1e6), 1, null), - /* @__PURE__ */ Nr("p", null, null, fn(1e6, { + /* @__PURE__ */ Cr("p", null, null, rt(-1, "second"), 1, null), + /* @__PURE__ */ Cr("h3", null, null, __qsInlineTranslate("numbers"), 1, null), + /* @__PURE__ */ Cr("p", null, null, fn(1e6), 1, null), + /* @__PURE__ */ Cr("p", null, null, fn(1e6, { style: "currency" }), 1, null), - /* @__PURE__ */ Nr("p", null, null, fn(1, { + /* @__PURE__ */ Cr("p", null, null, fn(1, { style: "unit", unit: locale.units["length"] }), 1, null) ], 1, "1L_4"); };`; -export const mockInlinedCode = `const s_dYGb4b0cyCA = () => { - const t = useTranslate(); - usePlural(); +export const mockInlinedCode = `const s_eTU0cN78ZUc = () => { const fd = useFormatDate(); const rt = useRelativeTime(); const fn = useFormatNumber(); - const ctx = useSpeakContext(); const locale = useSpeakLocale(); - const count = Sc(0); - const tParam = \`Hi! I am \${\`\`}\`; + const count = Qc(0); + const tParam = \`Hi! I am \${\`Qwik Speak\`}\`; const tArray = [\`n. one\`,\`n. two\`,\`n. three\`]; const item = \`n. three\`; const tObject = {"one":\`n. one\`,"two":\`n. two\`}; @@ -377,71 +481,54 @@ export const mockInlinedCode = `const s_dYGb4b0cyCA = () => { console.log(item); Object.values(tObject).map((x) => console.log(x)); tArrayObjects.map((x) => console.log(x["num"])); - return /* @__PURE__ */ Nr("div", null, { + return /* @__PURE__ */ Cr("div", null, { class: "content" }, [ - /* @__PURE__ */ Ur(Title, { - get name() { - return \`\`; - }, - [Pt]: { - name: Ot((p0) => \`\`, [ - t - ]) - } + /* @__PURE__ */ jr(Title, { + name: \`Qwik Speak\` }, 3, "1L_2"), - /* @__PURE__ */ Ur(SubTitle, { - ctx, - [Pt]: { - ctx: Pt - } - }, 3, "1L_3"), - /* @__PURE__ */ Nr("h3", null, null, \`Parameters\`, 1, null), - /* @__PURE__ */ Nr("p", null, null, \`Hi! I am Qwik Speak\`, 1, null), - /* @__PURE__ */ Nr("h3", null, null, \`Html tags\`, 1, null), - /* @__PURE__ */ Nr("p", null, { - dangerouslySetInnerHTML: Ot((p0) => \`<em>Internationalization (i18n) library to translate texts, dates and numbers in Qwik apps</em>\`, [ - t - ]) - }, null, 3, null), - /* @__PURE__ */ Nr("h3", null, null, \`Plural\`, 1, null), - /* @__PURE__ */ Nr("p", null, { + /* @__PURE__ */ jr(SubTitle, null, 3, "1L_3"), + /* @__PURE__ */ Cr("h3", null, null, \`Parameters\`, 1, null), + /* @__PURE__ */ Cr("p", null, null, \`Hi! I am Qwik Speak\`, 1, null), + /* @__PURE__ */ Cr("h3", null, null, \`Html tags\`, 1, null), + /* @__PURE__ */ Cr("p", { + dangerouslySetInnerHTML: \`<em>Internationalization (i18n) library to translate texts, dates and numbers in Qwik apps</em>\` + }, null, null, 3, null), + /* @__PURE__ */ Cr("h3", null, null, \`Plural\`, 1, null), + /* @__PURE__ */ Cr("p", null, { class: "counter" }, (new Intl.PluralRules(\`en-US\`).select(+count.value) === \`other\` && \`\${count.value} software developers\` || \`\${count.value} software developer\`), 1, null), - /* @__PURE__ */ Nr("button", null, { + /* @__PURE__ */ Cr("button", null, { class: "btn-counter", - onClick$: /* @__PURE__ */ z(() => __vitePreload(() => Promise.resolve().then(() => entry_Home), true ? void 0 : void 0), "s_UVYDAmatcag", [ + onClick$: /* @__PURE__ */ vs(() => __vitePreload(() => Promise.resolve().then(() => entry_____lang_), true ? void 0 : void 0), "s_XGiVgs2jpeg", [ count ]) }, \`Increment\`, 1, null), - /* @__PURE__ */ Nr("h3", null, null, \`Dates & relative time\`, 1, null), - /* @__PURE__ */ Nr("p", null, null, fd(Date.now(), { + /* @__PURE__ */ Cr("h3", null, null, \`Dates & relative time\`, 1, null), + /* @__PURE__ */ Cr("p", null, null, fd(Date.now(), { dateStyle: "full", timeStyle: "short" }), 1, null), - /* @__PURE__ */ Nr("p", null, null, rt(-1, "second"), 1, null), - /* @__PURE__ */ Nr("h3", null, null, \`Numbers & currencies\`, 1, null), - /* @__PURE__ */ Nr("p", null, null, fn(1e6), 1, null), - /* @__PURE__ */ Nr("p", null, null, fn(1e6, { + /* @__PURE__ */ Cr("p", null, null, rt(-1, "second"), 1, null), + /* @__PURE__ */ Cr("h3", null, null, \`Numbers & currencies\`, 1, null), + /* @__PURE__ */ Cr("p", null, null, fn(1e6), 1, null), + /* @__PURE__ */ Cr("p", null, null, fn(1e6, { style: "currency" }), 1, null), - /* @__PURE__ */ Nr("p", null, null, fn(1, { + /* @__PURE__ */ Cr("p", null, null, fn(1, { style: "unit", unit: locale.units["length"] }), 1, null) ], 1, "1L_4"); };`; -export const mockInlinedCodeByLang = `const s_dYGb4b0cyCA = () => { - const t = useTranslate(); - usePlural(); +export const mockInlinedCodeByLang = `const s_eTU0cN78ZUc = () => { const fd = useFormatDate(); const rt = useRelativeTime(); const fn = useFormatNumber(); - const ctx = useSpeakContext(); const locale = useSpeakLocale(); - const count = Sc(0); - const tParam = \`Ciao! Sono \${\`\`}\`; + const count = Qc(0); + const tParam = \`Ciao! Sono \${\`Qwik Speak\`}\`; const tArray = [\`n. uno\`,\`n. due\`,\`n. tre\`]; const item = \`n. tre\`; const tObject = {"one":\`n. uno\`,"two":\`n. due\`}; @@ -451,55 +538,41 @@ export const mockInlinedCodeByLang = `const s_dYGb4b0cyCA = () => { console.log(item); Object.values(tObject).map((x) => console.log(x)); tArrayObjects.map((x) => console.log(x["num"])); - return /* @__PURE__ */ Nr("div", null, { + return /* @__PURE__ */ Cr("div", null, { class: "content" }, [ - /* @__PURE__ */ Ur(Title, { - get name() { - return \`\`; - }, - [Pt]: { - name: Ot((p0) => \`\`, [ - t - ]) - } + /* @__PURE__ */ jr(Title, { + name: \`Qwik Speak\` }, 3, "1L_2"), - /* @__PURE__ */ Ur(SubTitle, { - ctx, - [Pt]: { - ctx: Pt - } - }, 3, "1L_3"), - /* @__PURE__ */ Nr("h3", null, null, \`Parametri\`, 1, null), - /* @__PURE__ */ Nr("p", null, null, \`Ciao! Sono Qwik Speak\`, 1, null), - /* @__PURE__ */ Nr("h3", null, null, \`Tag Html\`, 1, null), - /* @__PURE__ */ Nr("p", null, { - dangerouslySetInnerHTML: Ot((p0) => \`<em>Libreria di internazionalizzazione (i18n) per tradurre testi, date e numeri nelle app Qwik</em>\`, [ - t - ]) - }, null, 3, null), - /* @__PURE__ */ Nr("h3", null, null, \`Plurale\`, 1, null), - /* @__PURE__ */ Nr("p", null, { + /* @__PURE__ */ jr(SubTitle, null, 3, "1L_3"), + /* @__PURE__ */ Cr("h3", null, null, \`Parametri\`, 1, null), + /* @__PURE__ */ Cr("p", null, null, \`Ciao! Sono Qwik Speak\`, 1, null), + /* @__PURE__ */ Cr("h3", null, null, \`Tag Html\`, 1, null), + /* @__PURE__ */ Cr("p", { + dangerouslySetInnerHTML: \`<em>Libreria di internazionalizzazione (i18n) per tradurre testi, date e numeri nelle app Qwik</em>\` + }, null, null, 3, null), + /* @__PURE__ */ Cr("h3", null, null, \`Plurale\`, 1, null), + /* @__PURE__ */ Cr("p", null, { class: "counter" - }, (new Intl.PluralRules(\`it-IT\`).select(+count.value) === \`other\` && \`\${count.value} sviluppatori software\` || \`\${count.value} sviluppatore software\`), 1, null), - /* @__PURE__ */ Nr("button", null, { + }, (new Intl.PluralRules(\`it-IT\`).select(+count.value) === \`other\` && \`\${count.value} sviluppatori di software\` || \`\${count.value} sviluppatore di software\`), 1, null), + /* @__PURE__ */ Cr("button", null, { class: "btn-counter", - onClick$: /* @__PURE__ */ z(() => __vitePreload(() => Promise.resolve().then(() => entry_Home), true ? void 0 : void 0), "s_UVYDAmatcag", [ + onClick$: /* @__PURE__ */ vs(() => __vitePreload(() => Promise.resolve().then(() => entry_____lang_), true ? void 0 : void 0), "s_XGiVgs2jpeg", [ count ]) - }, \`Incrementa\`, 1, null), - /* @__PURE__ */ Nr("h3", null, null, \`Date e tempo relativo\`, 1, null), - /* @__PURE__ */ Nr("p", null, null, fd(Date.now(), { + }, \`Incremento\`, 1, null), + /* @__PURE__ */ Cr("h3", null, null, \`Date e tempo relativo\`, 1, null), + /* @__PURE__ */ Cr("p", null, null, fd(Date.now(), { dateStyle: "full", timeStyle: "short" }), 1, null), - /* @__PURE__ */ Nr("p", null, null, rt(-1, "second"), 1, null), - /* @__PURE__ */ Nr("h3", null, null, \`Numeri e valute\`, 1, null), - /* @__PURE__ */ Nr("p", null, null, fn(1e6), 1, null), - /* @__PURE__ */ Nr("p", null, null, fn(1e6, { + /* @__PURE__ */ Cr("p", null, null, rt(-1, "second"), 1, null), + /* @__PURE__ */ Cr("h3", null, null, \`Numeri e valute\`, 1, null), + /* @__PURE__ */ Cr("p", null, null, fn(1e6), 1, null), + /* @__PURE__ */ Cr("p", null, null, fn(1e6, { style: "currency" }), 1, null), - /* @__PURE__ */ Nr("p", null, null, fn(1, { + /* @__PURE__ */ Cr("p", null, null, fn(1, { style: "unit", unit: locale.units["length"] }), 1, null) @@ -507,115 +580,126 @@ export const mockInlinedCodeByLang = `const s_dYGb4b0cyCA = () => { };`; export const mockAsset = JSON.stringify({ - "home": { - "dates": "Dates & relative time", - "greeting": "Hi! I am {{name}}", - "increment": "Increment", - "numbers": "Numbers & currencies", - "plural": "Plural", - "tags": "Html tags", - "text": "<em>Internationalization (i18n) library to translate texts, dates and numbers in Qwik apps</em>" - } + "dates": "Dates & relative time", + "greeting": "Hi! I am {{name}}", + "increment": "Increment", + "numbers": "Numbers & currencies", + "params": "Parameters", + "plural": "Plural", + "tags": "Html tags", + "description": "<em>Internationalization (i18n) library to translate texts, dates and numbers in Qwik apps</em>" }, null, 2); export const mockExtractedAsset = JSON.stringify({ - "home": { - "array": [ - "{{ name }} one", - "{{ name }} two", - "{{ name }} three" - ], - "arrayObjects": [ - { - "num": "one" - }, - { - "num": "two" + "app": { + "head": { + "home": { + "description": "", + "title": "" } - ], - "dates": "Dates & relative time", - "devs": { - "one": "", - "other": "" }, - "greeting": "Hi! I am {{name}}", - "increment": "Increment", - "numbers": "Numbers & currencies", - "obj": { - "one": "{{ name }} one", - "two": "{{ name }} two" + "subtitle": "", + "title": "" + }, + "array": [ + "{{ name }} one", + "{{ name }} two", + "{{ name }} three" + ], + "arrayObjects": [ + { + "num": "one" }, - "params": "", - "plural": "Plural", - "tags": "Html tags", - "text": "<em>Internationalization (i18n) library to translate texts, dates and numbers in Qwik apps</em>" - } + { + "num": "two" + } + ], + "dates": "Dates & relative time", + "description": "<em>Internationalization (i18n) library to translate texts, dates and numbers in Qwik apps</em>", + "devs": { + "one": "", + "other": "" + }, + "greeting": "Hi! I am {{name}}", + "increment": "Increment", + "numbers": "Numbers & currencies", + "obj": { + "one": "{{ name }} one", + "two": "{{ name }} two" + }, + "params": "Parameters", + "plural": "Plural", + "tags": "Html tags" }, null, 2); export const mockTranslatedAsset = JSON.stringify({ - "home": { - "array": [ - "{{ name }} one", - "{{ name }} two", - "{{ name }} three" - ], - "arrayObjects": [ - { - "num": "one" - }, - { - "num": "two" - } - ], - "dates": "Dates & relative time", - "devs": { - "one": "{{ value }} software developer", - "other": "{{ value }} software developers" - }, - "greeting": "Hi! I am {{name}}", - "increment": "Increment", - "numbers": "Numbers & currencies", - "obj": { - "one": "{{ name }} one", - "two": "{{ name }} two" + "app": { + "subtitle": "Translate your Qwik apps into any language", + "title": "Qwik Speak" + }, + "array": [ + "{{ name }} one", + "{{ name }} two", + "{{ name }} three" + ], + "arrayObjects": [ + { + "num": "one" }, - "params": "Parameters", - "plural": "Plural", - "tags": "Html tags", - "text": "<em>Internationalization (i18n) library to translate texts, dates and numbers in Qwik apps</em>" - } + { + "num": "two" + } + ], + "dates": "Dates & relative time", + "description": "<em>Internationalization (i18n) library to translate texts, dates and numbers in Qwik apps</em>", + "devs": { + "one": "{{ value }} software developer", + "other": "{{ value }} software developers" + }, + "greeting": "Hi! I am {{name}}", + "increment": "Increment", + "numbers": "Numbers & currencies", + "obj": { + "one": "{{ name }} one", + "two": "{{ name }} two" + }, + "params": "Parameters", + "plural": "Plural", + "tags": "Html tags" }, null, 2); export const mockTranslatedAssetByLang = JSON.stringify({ - "home": { - "array": [ - "{{ name }} uno", - "{{ name }} due", - "{{ name }} tre" - ], - "arrayObjects": [ - { - "num": "uno" - }, - { - "num": "due" - } - ], - "dates": "Date e tempo relativo", - "devs": { - "one": "{{ value }} sviluppatore software", - "other": "{{ value }} sviluppatori software" - }, - "greeting": "Ciao! Sono {{name}}", - "increment": "Incrementa", - "numbers": "Numeri e valute", - "obj": { - "one": "{{ name }} uno", - "two": "{{ name }} due" + "app": { + "subtitle": "Traduci le tue app Qwik in qualsiasi lingua", + "title": "Qwik Speak" + }, + "array": [ + "{{ name }} uno", + "{{ name }} due", + "{{ name }} tre" + ], + "arrayObjects": [ + { + "num": "uno" }, - "params": "Parametri", - "plural": "Plurale", - "tags": "Tag Html", - "text": "<em>Libreria di internazionalizzazione (i18n) per tradurre testi, date e numeri nelle app Qwik</em>", - } + { + "num": "due" + } + ], + "dates": "Date e tempo relativo", + "description": "<em>Libreria di internazionalizzazione (i18n) per tradurre testi, date e numeri nelle app Qwik</em>", + "devs": { + "one": "{{ value }} sviluppatore di software", + "other": "{{ value }} sviluppatori di software" + }, + "greeting": "Ciao! Sono {{name}}", + "increment": "Incremento", + "numbers": "Numeri e valute", + "obj": { + "one": "{{ name }} uno", + "two": "{{ name }} due" + }, + "params": "Parametri", + "plural": "Plurale", + "tags": "Tag Html" }, null, 2); diff --git a/packages/qwik-speak/tools/tests/parser.test.ts b/packages/qwik-speak/tools/tests/parser.test.ts index 9d93a9d..a769076 100644 --- a/packages/qwik-speak/tools/tests/parser.test.ts +++ b/packages/qwik-speak/tools/tests/parser.test.ts @@ -1,6 +1,6 @@ import { test, describe, expect } from 'vitest'; -import { getInlineTranslateAlias, getUsePluralAlias, getUseTranslateAlias, parse, parseSequenceExpressions, tokenize } from '../core/parser'; +import { getInlineTranslateAlias, getInlinePluralAlias, parse, parseSequenceExpressions, tokenize } from '../core/parser'; describe('parser: tokenize', () => { test('tokenize', () => { @@ -634,21 +634,12 @@ describe('parser: parseSequenceExpressions', () => { }); describe('aliases', () => { - test('getUseTranslateAlias', () => { - const alias = getUseTranslateAlias(`const t = useTranslate();`); - expect(alias).toBe('\\bt'); - }); test('getInlineTranslateAlias', () => { - let alias = getInlineTranslateAlias(`import { - inlineTranslate as t, - useSpeakLocale - } from 'qwik-speak';`); + const alias = getInlineTranslateAlias(`const t = inlineTranslate();`); expect(alias).toBe('\\bt'); - alias = getInlineTranslateAlias("import { inlineTranslate } from 'qwik-speak';"); - expect(alias).toBe('\\binlineTranslate'); }); - test('getUsePluralAlias', () => { - const alias = getUsePluralAlias('const p = usePlural();'); + test('getInlinePluralAlias', () => { + const alias = getInlinePluralAlias('const p = inlinePlural();'); expect(alias).toBe('\\bp'); }); }); diff --git a/packages/qwik-speak/vite.config.ts b/packages/qwik-speak/vite.config.ts index fc0c0e4..38622e6 100644 --- a/packages/qwik-speak/vite.config.ts +++ b/packages/qwik-speak/vite.config.ts @@ -18,5 +18,6 @@ export default defineConfig(() => { } }, plugins: [qwikVite()], + define: { 'import.meta.hot': 'import.meta.hot' } }; }); diff --git a/src/components/change-locale/change-locale.tsx b/src/components/change-locale/change-locale.tsx index 253e8c6..34c0f69 100644 --- a/src/components/change-locale/change-locale.tsx +++ b/src/components/change-locale/change-locale.tsx @@ -1,61 +1,33 @@ -import { $, component$, useStyles$ } from '@builder.io/qwik'; +import { component$, useStyles$ } from '@builder.io/qwik'; import { useLocation } from '@builder.io/qwik-city'; -import type { SpeakLocale } from 'qwik-speak'; -import { useSpeakLocale, useSpeakConfig, useDisplayName, useTranslate } from 'qwik-speak'; -// import { useTranslatePath } from 'qwik-speak'; +import { useSpeakLocale, useSpeakConfig, useDisplayName, inlineTranslate, localizePath } from 'qwik-speak'; +// import { translatePath } from 'qwik-speak'; import styles from './change-locale.css?inline'; export const ChangeLocale = component$(() => { useStyles$(styles); - const t = useTranslate(); - const dn = useDisplayName(); - - /** Uncomment this line to use url rewriting to translate paths */ - // const tp = useTranslatePath(); + const t = inlineTranslate(); - const loc = useLocation(); + const url = useLocation().url; const locale = useSpeakLocale(); const config = useSpeakConfig(); + const dn = useDisplayName(); - /** Uncomment this lines to use url rewriting to translate paths */ - // const getLocalePath = (newLocale: SpeakLocale) => { - // const url = new URL(loc.url) - // url.pathname = tp(url.pathname, newLocale.lang) - // return url.toString(); - // }; - - // Replace the locale and navigate to the new URL - const navigateByLocale$ = $((newLocale: SpeakLocale) => { - const url = new URL(location.href); - if (loc.params.lang) { - if (newLocale.lang !== config.defaultLocale.lang) { - url.pathname = url.pathname.replace(loc.params.lang, newLocale.lang); - } else { - url.pathname = url.pathname.replace(new RegExp(`(/${loc.params.lang}/)|(/${loc.params.lang}$)`), '/'); - } - } else if (newLocale.lang !== config.defaultLocale.lang) { - url.pathname = `/${newLocale.lang}${url.pathname}`; - } - - location.href = url.toString(); - }); + /** Uncomment this line to use url rewriting to translate paths */ + // const getPath = translatePath(); + const getPath = localizePath(); return ( <div class="change-locale"> <h2>{t('app.changeLocale')}</h2> <div class="names"> {config.supportedLocales.map(value => ( - <button key={value.lang} class={{ active: value.lang == locale.lang }} - onClick$={async () => await navigateByLocale$(value)}> + <a key={value.lang} class={{ button: true, active: value.lang == locale.lang }} href={getPath(url, value.lang)}> {dn(value.lang, { type: 'language' })} - </button> - /** Uncomment this lines to use url rewriting to translate paths */ - // <a key={value.lang} class={{ button: true, active: value.lang == locale.lang }} href={getLocalePath(value)}> - // {dn(value.lang, { type: 'language' })} - // </a> + </a> ))} </div> </div> diff --git a/src/components/header/header.tsx b/src/components/header/header.tsx index 7c1cb02..5a6e7cf 100644 --- a/src/components/header/header.tsx +++ b/src/components/header/header.tsx @@ -1,7 +1,7 @@ import { component$, useStyles$ } from '@builder.io/qwik'; import { Link, useLocation } from '@builder.io/qwik-city'; -import { useSpeakConfig, useSpeakLocale, useTranslate } from 'qwik-speak'; -// import { useTranslatePath } from 'qwik-speak'; +import { inlineTranslate, localizePath } from 'qwik-speak'; +// import { translatePath } from 'qwik-speak'; import { ChangeLocale } from '../change-locale/change-locale'; import { SpeakLogo } from '../icons/speak'; @@ -11,50 +11,37 @@ import styles from './header.css?inline'; export const Header = component$(() => { useStyles$(styles); - const t = useTranslate(); + const t = inlineTranslate(); const pathname = useLocation().url.pathname; - const lang = useSpeakLocale().lang; - const config = useSpeakConfig(); - - const getHref = (name: string) => { - return lang === config.defaultLocale.lang ? name : `/${lang}${name}`; - }; /** Uncomment this lines to use url rewriting to translate paths */ - // const tp = useTranslatePath(); - // const { url } = useLocation(); - // const [homePath, pagePath] = tp(['/', '/page/']) + // const getPath = translatePath(); + const getPath = localizePath(); + const [homePath, pagePath] = getPath(['/', '/page/']); return ( <> <header class="header"> <div class="logo"> - {/** Uncomment this line to use url rewriting to translate paths */} - {/* <Link href={homePath}> */} - <Link href={getHref('/')}> + <Link href={homePath} title={t('app.title')}> <SpeakLogo /> </Link> </div> <ul> <li> - {/** Uncomment this line to use url rewriting to translate paths */} - {/* <Link href={homePath} class={{ active: url.pathname === homePath }}> */} - <Link href={getHref('/')} - class={{ active: pathname === '/' || config.supportedLocales.some(x => pathname.endsWith(`${x.lang}/`)) }}> + <Link href={homePath} class={{ active: pathname === homePath }}> {t('app.nav.home')} </Link> </li> <li> - {/** Uncomment this line to use url rewriting to translate paths */} - {/* <Link href={pagePath} class={{ active: url.pathname === pagePath }}> */} - <Link href={getHref('/page')} - class={{ active: pathname.endsWith('/page/') }}> + <Link href={pagePath} class={{ active: pathname === pagePath }}> {t('app.nav.page')} </Link> </li> </ul> </header> + <ChangeLocale /> </> ); diff --git a/src/components/router-head/router-head.tsx b/src/components/router-head/router-head.tsx index 40261f7..17ad631 100644 --- a/src/components/router-head/router-head.tsx +++ b/src/components/router-head/router-head.tsx @@ -1,26 +1,23 @@ import { component$ } from '@builder.io/qwik'; import { useDocumentHead, useLocation } from '@builder.io/qwik-city'; -import { useTranslate } from 'qwik-speak'; /** * The RouterHead component is placed inside of the document `<head>` element. */ export const RouterHead = component$(() => { - const t = useTranslate(); - const head = useDocumentHead(); const loc = useLocation(); return ( <> - <title>{t(head.title, { name: 'Qwik Speak' })} + {head.title} {head.meta.map((m) => ( - + ))} {head.links.map((l) => ( diff --git a/src/e2e/home.spec.ts b/src/e2e/home.spec.ts index 66b8bbe..4f46fcf 100644 --- a/src/e2e/home.spec.ts +++ b/src/e2e/home.spec.ts @@ -34,7 +34,7 @@ test.describe('Home', () => { await page.locator('text=Pagina').click(); - await expect(page.locator('main')).toContainText("Io sono un'altra pagina"); - await expect(page.locator('main')).toContainText("Io sono un valore dinamico"); + await expect(page.locator('main')).toContainText("Sono un'altra pagina"); + await expect(page.locator('main')).toContainText("Sono un valore dinamico"); }); }); diff --git a/src/e2e/page.spec.ts b/src/e2e/page.spec.ts index b003ed6..3e0c2c2 100644 --- a/src/e2e/page.spec.ts +++ b/src/e2e/page.spec.ts @@ -21,11 +21,11 @@ test.describe('Page', () => { await expect(page.locator('main')).toContainText('Qwik Speak'); await expect(page.locator('main')).toContainText('Traduci le tue app Qwik in qualsiasi lingua'); - await expect(page.locator('main')).toContainText("Io sono un'altra pagina"); - await expect(page.locator('main')).toContainText("I'm a default value"); - await expect(page.locator('main')).toContainText("Io sono un valore dinamico"); + await expect(page.locator('main')).toContainText("Sono un'altra pagina"); + await expect(page.locator('main')).toContainText("Sono un valore predefinito"); + await expect(page.locator('main')).toContainText("Sono un valore dinamico"); await expect(page).toHaveTitle('Pagina - Qwik Speak'); - await expect(page.locator('meta[name="description"]')).toHaveAttribute('content', "Io sono un'altra pagina"); + await expect(page.locator('meta[name="description"]')).toHaveAttribute('content', "Sono un'altra pagina"); }); }); diff --git a/src/global.css b/src/global.css index 7a83755..87062a6 100644 --- a/src/global.css +++ b/src/global.css @@ -29,6 +29,7 @@ button, .button { background-color: #fff; font-size: 14px; text-decoration: none; + color: inherit; } button:hover, .button:hover { @@ -54,6 +55,5 @@ button:hover, .button:hover { display: inline-block; padding: 10px 20px; font-size: 16px; - text-decoration: none; } } \ No newline at end of file diff --git a/src/root.tsx b/src/root.tsx index e1e69dd..64d9306 100644 --- a/src/root.tsx +++ b/src/root.tsx @@ -1,6 +1,6 @@ import { component$ } from '@builder.io/qwik'; import { QwikCityProvider, RouterOutlet, ServiceWorkerRegister } from '@builder.io/qwik-city'; -import { QwikSpeakProvider } from 'qwik-speak'; +import { useQwikSpeak } from 'qwik-speak'; import { RouterHead } from './components/router-head/router-head'; import { config } from './speak-config'; @@ -9,22 +9,22 @@ import { translationFn } from './speak-functions'; import './global.css'; export default component$(() => { + /** + * Init Qwik Speak + */ + useQwikSpeak({ config, translationFn }); + return ( - /** - * Init Qwik Speak (only available in child components) - */ - - - - - - - - - - - - - + + + + + + + + + + + ); }); diff --git a/src/routes/[...lang]/index.test.tsx b/src/routes/[...lang]/index.test.tsx index 1b50393..315f711 100644 --- a/src/routes/[...lang]/index.test.tsx +++ b/src/routes/[...lang]/index.test.tsx @@ -1,6 +1,6 @@ import { createDOM } from '@builder.io/qwik/testing'; import { test, expect } from 'vitest'; -import { QwikSpeakProvider } from 'qwik-speak'; +import { QwikSpeakMockProvider } from 'qwik-speak'; import Home from './index'; import { config } from '../../speak-config'; @@ -10,9 +10,9 @@ test(`[Home Component]: Should render translated texts`, async () => { const { screen, render, userEvent } = await createDOM(); await render( - + - + ); expect(screen.outerHTML).toContain('Translate your Qwik apps into any language'); diff --git a/src/routes/[...lang]/index.tsx b/src/routes/[...lang]/index.tsx index 8d59a44..8c8ba88 100644 --- a/src/routes/[...lang]/index.tsx +++ b/src/routes/[...lang]/index.tsx @@ -1,17 +1,13 @@ import { component$, useSignal } from '@builder.io/qwik'; -import type { DocumentHead } from '@builder.io/qwik-city'; +import { type DocumentHead } from '@builder.io/qwik-city'; import { - Speak, inlineTranslate, + inlinePlural, useFormatDate, useFormatNumber, - usePlural, useRelativeTime, - useSpeakContext, - useSpeakLocale, - useTranslate + useSpeakLocale } from 'qwik-speak'; -import type { SpeakState } from 'qwik-speak'; interface TitleProps { name: string; @@ -21,47 +17,45 @@ export const Title = component$(props => { return (

{props.name}

) }); -export const SubTitle = (props: { ctx: SpeakState }) => { - return

{inlineTranslate('app.subtitle', props.ctx)}

; +export const SubTitle = () => { + const t = inlineTranslate(); + return

{t('app.subtitle')}

; }; -export const Home = component$(() => { - const t = useTranslate(); - const p = usePlural(); +export default component$(() => { + const t = inlineTranslate(); + const p = inlinePlural(); + const fd = useFormatDate(); const rt = useRelativeTime(); const fn = useFormatNumber(); - const ctx = useSpeakContext(); const locale = useSpeakLocale(); const units = locale.units!; const count = useSignal(0); - // Prefer translating inside components rather than on props - const title = t('app.title'); - return (
- + <Title name={t('app.title')} /> - <SubTitle ctx={ctx} /> + <SubTitle /> - <h3>{t('home.params')}</h3> - <p>{t('home.greeting', { name: 'Qwik Speak' })}</p> + <h3>{t('params')}</h3> + <p>{t('greeting', { name: 'Qwik Speak' })}</p> - <h3>{t('home.tags')}</h3> - <p dangerouslySetInnerHTML={t('home.text')}></p> + <h3>{t('tags')}</h3> + <p dangerouslySetInnerHTML={t('description')}></p> - <h3>{t('home.plural')}</h3> - <p class="counter">{p(count.value, 'home.devs')}</p> - <button class="btn-counter" onClick$={() => count.value++}>{t('home.increment')}</button> + <h3>{t('plural')}</h3> + <p class="counter">{p(count.value, 'devs')}</p> + <button class="btn-counter" onClick$={() => count.value++}>{t('increment')}</button> - <h3>{t('home.dates')}</h3> + <h3>{t('dates')}</h3> <p>{fd(Date.now(), { dateStyle: 'full', timeStyle: 'short' })}</p> <p>{rt(-1, 'second')}</p> - <h3>{t('home.numbers')}</h3> + <h3>{t('numbers')}</h3> <p>{fn(1000000)}</p> <p>{fn(1000000, { style: 'currency' })}</p> <p>{fn(1, { style: 'unit', unit: units['length'] })}</p> @@ -69,18 +63,16 @@ export const Home = component$(() => { ); }); -export default component$(() => { - return ( - /** - * Add Home translations (only available in child components) - */ - <Speak assets={['home']}> - <Home /> - </Speak> - ); -}); - -export const head: DocumentHead = { - title: 'runtime.head.home.title', - meta: [{ name: 'description', content: 'runtime.head.home.description' }] +export const head: DocumentHead = () => { + const t = inlineTranslate(); + + return { + title: t('app.head.home.title', { name: 'Qwik Speak' }), + meta: [ + { + name: 'description', + content: t('app.head.home.description') + } + ], + }; }; diff --git a/src/routes/[...lang]/page/[slug]/index.tsx b/src/routes/[...lang]/page/[slug]/index.tsx deleted file mode 100644 index 510d247..0000000 --- a/src/routes/[...lang]/page/[slug]/index.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { component$ } from '@builder.io/qwik'; -import type { DocumentHead } from '@builder.io/qwik-city'; -import { useLocation } from "@builder.io/qwik-city"; -import { useTranslate } from 'qwik-speak'; - -export default component$(() => { - const t = useTranslate(); - const loc = useLocation() - - return ( - <div class="content"> - <h1>{t('app.title')}</h1> - <h2>{t('app.subtitle')}</h2> - - <p>{loc.params.slug}</p> - </div> - ); -}); - -export const head: DocumentHead = { - title: 'runtime.head.page.title', - meta: [{ name: 'description', content: 'runtime.head.page.description' }] -}; diff --git a/src/routes/[...lang]/page/index.tsx b/src/routes/[...lang]/page/index.tsx index 98f7ffc..22bc4ec 100644 --- a/src/routes/[...lang]/page/index.tsx +++ b/src/routes/[...lang]/page/index.tsx @@ -1,9 +1,9 @@ import { component$ } from '@builder.io/qwik'; import type { DocumentHead } from '@builder.io/qwik-city'; -import { Speak, useTranslate } from 'qwik-speak'; +import { inlineTranslate } from 'qwik-speak'; -export const Page = component$(() => { - const t = useTranslate(); +export default component$(() => { + const t = inlineTranslate(); const key = 'dynamic'; @@ -12,25 +12,23 @@ export const Page = component$(() => { <h1>{t('app.title')}</h1> <h2>{t('app.subtitle')}</h2> - <p>{t('page.text')}</p> - <p>{t('page.default@@I\'m a default value')}</p> - <p>{t(`runtimePage.${key}`)}</p> + <p>{t('anotherPage')}</p> + <p>{t('defaultValue@@I\'m a default value')}</p> + <p>{t(`runtime.${key}`)}</p> </div> ); }); -export default component$(() => { - return ( - /** - * Add Page translations (only available in child components) - */ - <Speak assets={['page']} runtimeAssets={['runtimePage']}> - <Page /> - </Speak> - ); -}); +export const head: DocumentHead = () => { + const t = inlineTranslate(); -export const head: DocumentHead = { - title: 'runtime.head.page.title', - meta: [{ name: 'description', content: 'runtime.head.page.description' }] + return { + title: t('app.head.page.title', { name: 'Qwik Speak' }), + meta: [ + { + name: 'description', + content: t('app.head.page.description') + } + ], + }; }; diff --git a/src/routes/plugin.ts b/src/routes/plugin.ts index 328bbc1..4177ccf 100644 --- a/src/routes/plugin.ts +++ b/src/routes/plugin.ts @@ -1,18 +1,20 @@ import type { RequestHandler } from "@builder.io/qwik-city"; +import { validateLocale } from 'qwik-speak'; import { config } from '../speak-config'; // import { rewriteRoutes } from '../speak-routes'; export const onRequest: RequestHandler = ({ params, locale, error }) => { - // Check supported locales - const supportedLocale = config.supportedLocales.find(value => value.lang === params.lang) - - // Check for 404 error page - const lang = supportedLocale - ? supportedLocale.lang - : !params.lang && config.defaultLocale.lang - - if (!lang) throw error(404, 'Page not found'); + let lang: string | undefined = undefined; + + if (params.lang && validateLocale(params.lang)) { + // Check supported locales + lang = config.supportedLocales.find(value => value.lang === params.lang)?.lang; + // 404 error page + if (!lang) throw error(404, 'Page not found'); + } else { + lang = config.defaultLocale.lang; + } // Set Qwik locale locale(lang); diff --git a/src/speak-config.ts b/src/speak-config.ts index 89cf5ff..52abdca 100644 --- a/src/speak-config.ts +++ b/src/speak-config.ts @@ -14,10 +14,12 @@ export const config: SpeakConfig = { { lang: 'it-IT', currency: 'EUR', timeZone: 'Europe/Rome', units: { 'length': 'kilometer' }, dir: 'ltr' }, { lang: 'de-DE', currency: 'EUR', timeZone: 'Europe/Rome', units: { 'length': 'kilometer' }, dir: 'ltr' } ], + // Translations available in the whole app assets: [ - 'app' // Translations shared by the pages + 'app' ], + // Translations with dynamic keys available in the whole app runtimeAssets: [ - 'runtime' // Translations with dynamic keys or parameters + 'runtime' ] }; diff --git a/src/speak-routes.ts b/src/speak-routes.ts index 2c70771..ebb91ae 100644 --- a/src/speak-routes.ts +++ b/src/speak-routes.ts @@ -21,4 +21,4 @@ export const rewriteRoutes: RewriteRouteOption[] = [ 'page': 'seite' } } -] +];