From e97c808b412167d334353c7f6370e6d8b70bc0ae Mon Sep 17 00:00:00 2001 From: Sebastian Date: Wed, 14 Dec 2022 15:17:15 -0300 Subject: [PATCH] moving testing sdk to web-utils --- packages/web-util/build.mjs | 4 +- packages/web-util/package.json | 6 +- packages/web-util/src/components/index.ts | 1 - packages/web-util/src/context/index.ts | 7 +- packages/web-util/src/context/translation.ts | 6 +- packages/web-util/src/hooks/index.ts | 13 +- .../web-util/src/hooks/useLocalStorage.ts | 36 +- packages/web-util/src/index.browser.ts | 2 +- packages/web-util/src/live-reload.ts | 24 +- packages/web-util/src/serve.ts | 25 +- packages/web-util/src/test/index.ts | 224 ---- packages/web-util/src/tests/axios.ts | 136 +++ packages/web-util/src/tests/hook.ts | 310 +++++ packages/web-util/src/tests/index.ts | 2 + packages/web-util/src/tests/mock.ts | 458 ++++++++ packages/web-util/src/tests/swr.ts | 82 ++ packages/web-util/src/utils/axios.ts | 79 ++ packages/web-util/src/utils/index.ts | 1 + pnpm-lock.yaml | 1014 +++-------------- 19 files changed, 1308 insertions(+), 1122 deletions(-) delete mode 100644 packages/web-util/src/test/index.ts create mode 100644 packages/web-util/src/tests/axios.ts create mode 100644 packages/web-util/src/tests/hook.ts create mode 100644 packages/web-util/src/tests/index.ts create mode 100644 packages/web-util/src/tests/mock.ts create mode 100644 packages/web-util/src/tests/swr.ts create mode 100644 packages/web-util/src/utils/axios.ts create mode 100644 packages/web-util/src/utils/index.ts diff --git a/packages/web-util/build.mjs b/packages/web-util/build.mjs index ba277b666..e7aede81c 100755 --- a/packages/web-util/build.mjs +++ b/packages/web-util/build.mjs @@ -78,13 +78,13 @@ const buildConfigNode = { const buildConfigBrowser = { ...buildConfigBase, - entryPoints: ["src/index.browser.ts", "src/live-reload.ts", 'src/stories.tsx'], + entryPoints: ["src/tests/axios.ts", "src/tests/swr.ts", "src/index.browser.ts", "src/live-reload.ts", 'src/stories.tsx'], outExtension: { '.js': '.mjs' }, format: 'esm', platform: 'browser', - external: ["preact", "@gnu-taler/taler-util", "jed"], + external: ["preact", "@gnu-taler/taler-util", "jed","swr","axios"], jsxFactory: 'h', jsxFragment: 'Fragment', }; diff --git a/packages/web-util/package.json b/packages/web-util/package.json index 1add56d87..ad87304fe 100644 --- a/packages/web-util/package.json +++ b/packages/web-util/package.json @@ -12,6 +12,8 @@ "license": "AGPL-3.0-or-later", "private": false, "exports": { + "./lib/tests/swr": "./lib/tests/swr.mjs", + "./lib/tests/axios": "./lib/tests/axios.mjs", "./lib/index.browser": "./lib/index.browser.mjs", "./lib/index.node": "./lib/index.node.cjs" }, @@ -27,6 +29,7 @@ "@types/node": "^18.11.9", "@types/web": "^0.0.82", "@types/ws": "^8.5.3", + "axios": "^1.2.1", "chokidar": "^3.5.3", "esbuild": "^0.14.21", "express": "^4.18.2", @@ -34,8 +37,9 @@ "preact-render-to-string": "^5.2.6", "prettier": "^2.5.1", "rimraf": "^3.0.2", + "swr": "1.3.0", "tslib": "^2.4.0", "typescript": "^4.8.4", "ws": "7.4.5" } -} +} \ No newline at end of file diff --git a/packages/web-util/src/components/index.ts b/packages/web-util/src/components/index.ts index dc7c86d7d..9441e971d 100644 --- a/packages/web-util/src/components/index.ts +++ b/packages/web-util/src/components/index.ts @@ -1,2 +1 @@ - export * as utils from "./utils.js"; diff --git a/packages/web-util/src/context/index.ts b/packages/web-util/src/context/index.ts index 0ac2c752a..4bc1b22f2 100644 --- a/packages/web-util/src/context/index.ts +++ b/packages/web-util/src/context/index.ts @@ -1,2 +1,5 @@ - -export { InternationalizationAPI, TranslationProvider, useTranslationContext } from "./translation.js"; +export { + InternationalizationAPI, + TranslationProvider, + useTranslationContext, +} from "./translation.js"; diff --git a/packages/web-util/src/context/translation.ts b/packages/web-util/src/context/translation.ts index ce140ec42..3b79e31d3 100644 --- a/packages/web-util/src/context/translation.ts +++ b/packages/web-util/src/context/translation.ts @@ -19,7 +19,7 @@ import { ComponentChildren, createContext, h, VNode } from "preact"; import { useContext, useEffect } from "preact/hooks"; import { useLang } from "../hooks/index.js"; -export type InternationalizationAPI = typeof i18n +export type InternationalizationAPI = typeof i18n; interface Type { lang: string; @@ -54,7 +54,7 @@ interface Props { initial?: string; children: ComponentChildren; forceLang?: string; - source: Record + source: Record; } // Outmost UI wrapper. @@ -62,7 +62,7 @@ export const TranslationProvider = ({ initial, children, forceLang, - source + source, }: Props): VNode => { const [lang, changeLanguage, isSaved] = useLang(initial); useEffect(() => { diff --git a/packages/web-util/src/hooks/index.ts b/packages/web-util/src/hooks/index.ts index 9ac56c4ac..393a6fcbb 100644 --- a/packages/web-util/src/hooks/index.ts +++ b/packages/web-util/src/hooks/index.ts @@ -1,4 +1,11 @@ - export { useLang } from "./useLang.js"; -export { useLocalStorage, useNotNullLocalStorage } from "./useLocalStorage.js" -export { useAsyncAsHook, HookError, HookOk, HookResponse, HookResponseWithRetry, HookGenericError, HookOperationalError } from "./useAsyncAsHook.js" \ No newline at end of file +export { useLocalStorage, useNotNullLocalStorage } from "./useLocalStorage.js"; +export { + useAsyncAsHook, + HookError, + HookOk, + HookResponse, + HookResponseWithRetry, + HookGenericError, + HookOperationalError, +} from "./useAsyncAsHook.js"; diff --git a/packages/web-util/src/hooks/useLocalStorage.ts b/packages/web-util/src/hooks/useLocalStorage.ts index f518405b6..ab786db13 100644 --- a/packages/web-util/src/hooks/useLocalStorage.ts +++ b/packages/web-util/src/hooks/useLocalStorage.ts @@ -35,13 +35,13 @@ export function useLocalStorage( useEffect(() => { const listener = buildListenerForKey(key, (newValue) => { - setStoredValue(newValue ?? initialValue) - }) - window.addEventListener('storage', listener) + setStoredValue(newValue ?? initialValue); + }); + window.addEventListener("storage", listener); return () => { - window.removeEventListener('storage', listener) - } - }, []) + window.removeEventListener("storage", listener); + }; + }, []); const setValue = ( value?: string | ((val?: string) => string | undefined), @@ -62,11 +62,14 @@ export function useLocalStorage( return [storedValue, setValue]; } -function buildListenerForKey(key: string, onUpdate: (newValue: string | undefined) => void): () => void { +function buildListenerForKey( + key: string, + onUpdate: (newValue: string | undefined) => void, +): () => void { return function listenKeyChange() { - const value = window.localStorage.getItem(key) - onUpdate(value ?? undefined) - } + const value = window.localStorage.getItem(key); + onUpdate(value ?? undefined); + }; } //TODO: merge with the above function @@ -80,16 +83,15 @@ export function useNotNullLocalStorage( : initialValue; }); - useEffect(() => { const listener = buildListenerForKey(key, (newValue) => { - setStoredValue(newValue ?? initialValue) - }) - window.addEventListener('storage', listener) + setStoredValue(newValue ?? initialValue); + }); + window.addEventListener("storage", listener); return () => { - window.removeEventListener('storage', listener) - } - }) + window.removeEventListener("storage", listener); + }; + }); const setValue = (value: string | ((val: string) => string)): void => { const valueToStore = value instanceof Function ? value(storedValue) : value; diff --git a/packages/web-util/src/index.browser.ts b/packages/web-util/src/index.browser.ts index 734a2f426..d3aeae168 100644 --- a/packages/web-util/src/index.browser.ts +++ b/packages/web-util/src/index.browser.ts @@ -1,5 +1,5 @@ export * from "./hooks/index.js"; export * from "./context/index.js"; export * from "./components/index.js"; -export * as test from "./test/index.js"; +export * as tests from "./tests/index.js"; export { renderStories, parseGroupImport } from "./stories.js"; diff --git a/packages/web-util/src/live-reload.ts b/packages/web-util/src/live-reload.ts index 901127f83..74d542956 100644 --- a/packages/web-util/src/live-reload.ts +++ b/packages/web-util/src/live-reload.ts @@ -15,24 +15,24 @@ function setupLiveReload(): void { return; } if (event.type === "file-updated-failed") { - const h1 = document.getElementById("overlay-text") + const h1 = document.getElementById("overlay-text"); if (h1) { - h1.innerHTML = "compilation failed" - h1.style.color = 'red' - h1.style.margin = '' + h1.innerHTML = "compilation failed"; + h1.style.color = "red"; + h1.style.margin = ""; } - const div = document.getElementById("overlay") + const div = document.getElementById("overlay"); if (div) { - const content = JSON.stringify(event.data, undefined, 2) + const content = JSON.stringify(event.data, undefined, 2); const pre = document.createElement("pre"); - pre.id = "error-text" + pre.id = "error-text"; pre.style.margin = ""; pre.textContent = content; div.style.backgroundColor = "rgba(0,0,0,0.8)"; - div.style.flexDirection = 'column' + div.style.flexDirection = "column"; div.appendChild(pre); } - console.error(event.data.error) + console.error(event.data.error); return; } if (event.type === "file-updated") { @@ -56,17 +56,17 @@ setupLiveReload(); function showReloadOverlay(): void { const d = document.createElement("div"); - d.id = "overlay" + d.id = "overlay"; d.style.position = "absolute"; d.style.width = "100%"; d.style.height = "100%"; d.style.color = "white"; d.style.backgroundColor = "rgba(0,0,0,0.5)"; d.style.display = "flex"; - d.style.zIndex = String(Number.MAX_SAFE_INTEGER) + d.style.zIndex = String(Number.MAX_SAFE_INTEGER); d.style.justifyContent = "center"; const h = document.createElement("h1"); - h.id = "overlay-text" + h.id = "overlay-text"; h.style.margin = "auto"; h.innerHTML = "reloading..."; d.appendChild(h); diff --git a/packages/web-util/src/serve.ts b/packages/web-util/src/serve.ts index 3248bbeb8..f3a97e2e2 100644 --- a/packages/web-util/src/serve.ts +++ b/packages/web-util/src/serve.ts @@ -77,23 +77,26 @@ export async function serve(opts: { if (opts.onUpdate) { sendToAllClients({ type: "file-updated-start", data: { path } }); - opts.onUpdate().then((result) => { - sendToAllClients({ - type: "file-updated-done", - data: { path, result }, + opts + .onUpdate() + .then((result) => { + sendToAllClients({ + type: "file-updated-done", + data: { path, result }, + }); + }) + .catch((error) => { + sendToAllClients({ + type: "file-updated-failed", + data: { path, error }, + }); }); - }).catch((error) => { - sendToAllClients({ - type: "file-updated-failed", - data: { path, error }, - }); - }); } else { sendToAllClients({ type: "file-change", data: { path } }); } }); - if (opts.onUpdate) opts.onUpdate() + if (opts.onUpdate) opts.onUpdate(); app.get(PATHS.EXAMPLE, function (req: any, res: any) { res.set("Content-Type", "text/html"); diff --git a/packages/web-util/src/test/index.ts b/packages/web-util/src/test/index.ts deleted file mode 100644 index 623115e79..000000000 --- a/packages/web-util/src/test/index.ts +++ /dev/null @@ -1,224 +0,0 @@ -/* - This file is part of GNU Taler - (C) 2022 Taler Systems S.A. - - GNU Taler is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - GNU Taler; see the file COPYING. If not, see - */ - -import { NotificationType } from "@gnu-taler/taler-util"; -// import { -// WalletCoreApiClient, -// WalletCoreOpKeys, -// WalletCoreRequestType, -// WalletCoreResponseType, -// } from "@gnu-taler/taler-wallet-core"; -import { - ComponentChildren, - Fragment, - FunctionalComponent, - h as create, - options, - render as renderIntoDom, - VNode, -} from "preact"; -import { render as renderToString } from "preact-render-to-string"; -// import { BackgroundApiClient, wxApi } from "./wxApi.js"; - -// When doing tests we want the requestAnimationFrame to be as fast as possible. -// without this option the RAF will timeout after 100ms making the tests slower -options.requestAnimationFrame = (fn: () => void) => { - return fn(); -}; - -export function createExample( - Component: FunctionalComponent, - props: Partial | (() => Partial), -): ComponentChildren { - const evaluatedProps = typeof props === "function" ? props() : props; - const Render = (args: any): VNode => create(Component, args); - - return { - component: Render, - props: evaluatedProps - }; -} - -export function createExampleWithCustomContext( - Component: FunctionalComponent, - props: Partial | (() => Partial), - ContextProvider: FunctionalComponent, - contextProps: Partial, -): ComponentChildren { - /** - * FIXME: - * This may not be useful since the example can be created with context - * already - */ - const evaluatedProps = typeof props === "function" ? props() : props; - const Render = (args: any): VNode => create(Component, args); - const WithContext = (args: any): VNode => - create(ContextProvider, { - ...contextProps, - children: [Render(args)], - } as any); - - return { - component: WithContext, - props: evaluatedProps - }; -} - -const isNode = typeof window === "undefined"; - -/** - * To be used on automated unit test. - * So test will run under node or browser - * @param Component - * @param args - */ -export function renderNodeOrBrowser(Component: any, args: any): void { - const vdom = create(Component, args); - if (isNode) { - renderToString(vdom); - } else { - const div = document.createElement("div"); - document.body.appendChild(div); - renderIntoDom(vdom, div); - renderIntoDom(null, div); - document.body.removeChild(div); - } -} -type RecursiveState = S | (() => RecursiveState); - -interface Mounted { - unmount: () => void; - pullLastResultOrThrow: () => Exclude; - assertNoPendingUpdate: () => void; - // waitNextUpdate: (s?: string) => Promise; - waitForStateUpdate: () => Promise; -} - -/** - * Main test API, mount the hook and return testing API - * @param callback - * @param Context - * @returns - */ -export function mountHook( - callback: () => RecursiveState, - Context?: ({ children }: { children: any }) => VNode, -): Mounted { - let lastResult: Exclude | Error | null = null; - - const listener: Array<() => void> = []; - - // component that's going to hold the hook - function Component(): VNode { - try { - let componentOrResult = callback(); - while (typeof componentOrResult === "function") { - componentOrResult = componentOrResult(); - } - //typecheck fails here - const l: Exclude void> = componentOrResult as any; - lastResult = l; - } catch (e) { - if (e instanceof Error) { - lastResult = e; - } else { - lastResult = new Error(`mounting the hook throw an exception: ${e}`); - } - } - - // notify to everyone waiting for an update and clean the queue - listener.splice(0, listener.length).forEach((cb) => cb()); - return create(Fragment, {}); - } - - // create the vdom with context if required - const vdom = !Context - ? create(Component, {}) - : create(Context, { children: [create(Component, {})] }); - - const customElement = {} as Element; - const parentElement = isNode ? customElement : document.createElement("div"); - if (!isNode) { - document.body.appendChild(parentElement); - } - - renderIntoDom(vdom, parentElement); - - // clean up callback - function unmount(): void { - if (!isNode) { - document.body.removeChild(parentElement); - } - } - - function pullLastResult(): Exclude { - const copy: Exclude = lastResult; - lastResult = null; - return copy; - } - - function pullLastResultOrThrow(): Exclude { - const r = pullLastResult(); - if (r instanceof Error) throw r; - if (!r) throw Error("there was no last result"); - return r; - } - - async function assertNoPendingUpdate(): Promise { - await new Promise((res, rej) => { - const tid = setTimeout(() => { - res(undefined); - }, 10); - - listener.push(() => { - clearTimeout(tid); - rej( - Error(`Expecting no pending result but the hook got updated. - If the update was not intended you need to check the hook dependencies - (or dependencies of the internal state) but otherwise make - sure to consume the result before ending the test.`), - ); - }); - }); - - const r = pullLastResult(); - if (r) - throw Error(`There are still pending results. - This may happen because the hook did a new update but the test didn't consume the result using pullLastResult`); - } - async function waitForStateUpdate(): Promise { - return await new Promise((res, rej) => { - const tid = setTimeout(() => { - res(false); - }, 10); - - listener.push(() => { - clearTimeout(tid); - res(true); - }); - }); - } - - return { - unmount, - pullLastResultOrThrow, - waitForStateUpdate, - assertNoPendingUpdate, - }; -} - -export const nullFunction = (): void => { null } -export const nullAsyncFunction = (): Promise => { return Promise.resolve() } \ No newline at end of file diff --git a/packages/web-util/src/tests/axios.ts b/packages/web-util/src/tests/axios.ts new file mode 100644 index 000000000..38f8a9899 --- /dev/null +++ b/packages/web-util/src/tests/axios.ts @@ -0,0 +1,136 @@ +/* + This file is part of GNU Taler + (C) 2022 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see + */ + +// import axios, { AxiosPromise, AxiosRequestConfig } from "axios"; +import * as axios from "axios"; +import { + setAxiosRequestAsTestingEnvironment, + mockAxiosOnce, +} from "../utils/axios.js"; + +const TESTING_DEBUG_LOG = process.env["TESTING_DEBUG_LOG"] !== undefined; + +const defaultCallback = ( + actualQuery?: axios.AxiosRequestConfig, +): axios.AxiosPromise => { + if (TESTING_DEBUG_LOG) { + console.log("UNEXPECTED QUERY", actualQuery); + } + throw Error( + "Default Axios mock callback is called, this mean that the test did a tried to use axios but there was no expectation in place, try using JEST_DEBUG_LOG env", + ); +}; + +setAxiosRequestAsTestingEnvironment(defaultCallback); + +export type Query = { + method: axios.Method; + url: string; + code?: number; +}; + +type ExpectationValues = { + query: Query; + params?: { + auth?: string; + request?: object; + qparam?: Record; + response?: object; + }; +}; + +type TestValues = [ + axios.AxiosRequestConfig | undefined, + ExpectationValues | undefined, +]; + +export class AxiosMockEnvironment { + expectations: Array< + | { + query: Query; + auth?: string; + params?: { + request?: object; + qparam?: Record; + response?: object; + }; + result: { args: axios.AxiosRequestConfig | undefined }; + } + | undefined + > = []; + // axiosMock: jest.MockedFunction + + addRequestExpectation< + RequestType extends object, + ResponseType extends object, + >( + expectedQuery: Query, + params: { + auth?: string; + request?: RequestType; + qparam?: any; + response?: ResponseType; + }, + ): void { + const result = mockAxiosOnce(function ( + actualQuery?: axios.AxiosRequestConfig, + ): axios.AxiosPromise { + if (TESTING_DEBUG_LOG) { + console.log("query to the backend is made", actualQuery); + } + if (!expectedQuery) { + return Promise.reject("a query was made but it was not expected"); + } + if (TESTING_DEBUG_LOG) { + console.log("expected query:", params?.request); + console.log("expected qparams:", params?.qparam); + console.log("sending response:", params?.response); + } + + const responseCode = expectedQuery.code || 200; + + //This response is what buildRequestOk is expecting in file hook/backend.ts + if (responseCode >= 200 && responseCode < 300) { + return Promise.resolve({ + data: params?.response, + config: { + data: params?.response, + params: actualQuery?.params || {}, + }, + request: { params: actualQuery?.params || {} }, + } as any); + } + //This response is what buildRequestFailed is expecting in file hook/backend.ts + return Promise.reject({ + response: { + status: responseCode, + }, + request: { + data: params?.response, + params: actualQuery?.params || {}, + }, + }); + } as any); + + this.expectations.push({ query: expectedQuery, params, result }); + } + + getLastTestValues(): TestValues { + const expectedQuery = this.expectations.shift(); + + return [expectedQuery?.result.args, expectedQuery]; + } +} diff --git a/packages/web-util/src/tests/hook.ts b/packages/web-util/src/tests/hook.ts new file mode 100644 index 000000000..f5bebbd6d --- /dev/null +++ b/packages/web-util/src/tests/hook.ts @@ -0,0 +1,310 @@ +/* + This file is part of GNU Taler + (C) 2022 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see + */ + +import { + ComponentChildren, + Fragment, + FunctionalComponent, + h as create, + options, + render as renderIntoDom, + VNode +} from "preact"; + +// This library is expected to be included in testing environment only +// When doing tests we want the requestAnimationFrame to be as fast as possible. +// without this option the RAF will timeout after 100ms making the tests slower +options.requestAnimationFrame = (fn: () => void) => { + return fn(); +}; + +export function createExample( + Component: FunctionalComponent, + props: Partial | (() => Partial), +): ComponentChildren { + const evaluatedProps = typeof props === "function" ? props() : props; + const Render = (args: any): VNode => create(Component, args); + + return { + component: Render, + props: evaluatedProps, + }; +} + +// export function createExampleWithCustomContext( +// Component: FunctionalComponent, +// props: Partial | (() => Partial), +// ContextProvider: FunctionalComponent, +// contextProps: Partial, +// ): ComponentChildren { +// /** +// * FIXME: +// * This may not be useful since the example can be created with context +// * already +// */ +// const evaluatedProps = typeof props === "function" ? props() : props; +// const Render = (args: any): VNode => create(Component, args); +// const WithContext = (args: any): VNode => +// create(ContextProvider, { +// ...contextProps, +// children: [Render(args)], +// } as any); + +// return { +// component: WithContext, +// props: evaluatedProps, +// }; +// } + +const isNode = typeof window === "undefined"; + +/** + * To be used on automated unit test. + * So test will run under node or browser + * @param Component + * @param args + */ +export function renderNodeOrBrowser( + Component: any, + args: any, + Context: any, +): void { + const vdom = !Context + ? create(Component, args) + : create(Context, { children: [create(Component, args)] }); + + const customElement = {} as Element; + const parentElement = isNode ? customElement : document.createElement("div"); + if (!isNode) { + document.body.appendChild(parentElement); + } + + // renderIntoDom works also in nodejs + // if the VirtualDOM is composed only by functional components + // then no called is going to be made to the DOM api. + // vdom should not have any 'div' or other html component + renderIntoDom(vdom, parentElement); + + if (!isNode) { + document.body.removeChild(parentElement); + } +} +type RecursiveState = S | (() => RecursiveState); + +interface Mounted { + // unmount: () => void; + pullLastResultOrThrow: () => Exclude; + assertNoPendingUpdate: () => Promise; + // waitNextUpdate: (s?: string) => Promise; + waitForStateUpdate: () => Promise; +} + +/** + * Manual API mount the hook and return testing API + * Consider using hookBehaveLikeThis() function + * + * @param hookToBeTested + * @param Context + * + * @returns testing API + */ +export function mountHook( + hookToBeTested: () => RecursiveState, + Context?: ({ children }: { children: any }) => VNode | null, +): Mounted { + let lastResult: Exclude | Error | null = null; + + const listener: Array<() => void> = []; + + // component that's going to hold the hook + function Component(): VNode { + try { + let componentOrResult = hookToBeTested(); + while (typeof componentOrResult === "function") { + componentOrResult = componentOrResult(); + } + //typecheck fails here + const l: Exclude void> = componentOrResult as any; + lastResult = l; + } catch (e) { + if (e instanceof Error) { + lastResult = e; + } else { + lastResult = new Error(`mounting the hook throw an exception: ${e}`); + } + } + + // notify to everyone waiting for an update and clean the queue + listener.splice(0, listener.length).forEach((cb) => cb()); + return create(Fragment, {}); + } + + renderNodeOrBrowser(Component, {}, Context); + + function pullLastResult(): Exclude { + const copy: Exclude = lastResult; + lastResult = null; + return copy; + } + + function pullLastResultOrThrow(): Exclude { + const r = pullLastResult(); + if (r instanceof Error) throw r; + //sanity check + if (!r) throw Error("there was no last result"); + return r; + } + + async function assertNoPendingUpdate(): Promise { + await new Promise((res, rej) => { + const tid = setTimeout(() => { + res(true); + }, 10); + + listener.push(() => { + clearTimeout(tid); + res(false); + // Error(`Expecting no pending result but the hook got updated. + // If the update was not intended you need to check the hook dependencies + // (or dependencies of the internal state) but otherwise make + // sure to consume the result before ending the test.`), + // ); + }); + }); + + const r = pullLastResult(); + if (r) { + return Promise.resolve(false); + } + return Promise.resolve(true); + // throw Error(`There are still pending results. + // This may happen because the hook did a new update but the test didn't consume the result using pullLastResult`); + } + async function waitForStateUpdate(): Promise { + return await new Promise((res, rej) => { + const tid = setTimeout(() => { + res(false); + }, 10); + + listener.push(() => { + clearTimeout(tid); + res(true); + }); + }); + } + + return { + // unmount, + pullLastResultOrThrow, + waitForStateUpdate, + assertNoPendingUpdate, + }; +} + +export const nullFunction = (): void => { + null; +}; +export const nullAsyncFunction = (): Promise => { + return Promise.resolve(); +}; + +type HookTestResult = HookTestResultOk | HookTestResultError; + +interface HookTestResultOk { + result: "ok"; +} +interface HookTestResultError { + result: "fail"; + error: string; + index: number; +} + +/** + * Main testing driver. + * It will assert that there are no more and no less hook updates than expected. + * + * @param hookFunction hook function to be tested + * @param props initial props for the hook + * @param checks step by step state validation + * @param Context additional testing context for overrides + * + * @returns testing result, should also be checked to be "ok" + */ +export async function hookBehaveLikeThis( + hookFunction: (p: PropsType) => RecursiveState, + props: PropsType, + checks: Array<(state: T) => void>, + Context?: ({ children }: { children: any }) => VNode | null, +): Promise { + const { pullLastResultOrThrow, waitForStateUpdate, assertNoPendingUpdate } = + mountHook(() => hookFunction(props), Context); + + const [firstCheck, ...resultOfTheChecks] = checks; + { + const state = pullLastResultOrThrow(); + const checkError = firstCheck(state); + if (checkError !== undefined) { + return { + result: "fail", + index: 0, + error: `Check return not undefined error: ${checkError}`, + }; + } + } + + let index = 1; + for (const check of resultOfTheChecks) { + const hasNext = await waitForStateUpdate(); + if (!hasNext) { + return { + result: "fail", + error: "Component didn't update and the test expected one more state", + index, + }; + } + const state = pullLastResultOrThrow(); + const checkError = check(state); + if (checkError !== undefined) { + return { + result: "fail", + index, + error: `Check return not undefined error: ${checkError}`, + }; + } + index++; + } + + const hasNext = await waitForStateUpdate(); + if (hasNext) { + return { + result: "fail", + index, + error: "Component updated and test didn't expect more states", + }; + } + const noMoreUpdates = await assertNoPendingUpdate(); + if (noMoreUpdates === false) { + return { + result: "fail", + index, + error: "Component was updated but the test does not cover the update", + }; + } + + return { + result: "ok", + }; +} diff --git a/packages/web-util/src/tests/index.ts b/packages/web-util/src/tests/index.ts new file mode 100644 index 000000000..2c0d929f8 --- /dev/null +++ b/packages/web-util/src/tests/index.ts @@ -0,0 +1,2 @@ +export * from "./hook.js"; +// export * from "./axios.js" diff --git a/packages/web-util/src/tests/mock.ts b/packages/web-util/src/tests/mock.ts new file mode 100644 index 000000000..563e437e5 --- /dev/null +++ b/packages/web-util/src/tests/mock.ts @@ -0,0 +1,458 @@ +/* + This file is part of GNU Taler + (C) 2022 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see + */ + +import { Logger } from "@gnu-taler/taler-util"; + +type HttpMethod = + | "get" + | "GET" + | "delete" + | "DELETE" + | "head" + | "HEAD" + | "options" + | "OPTIONS" + | "post" + | "POST" + | "put" + | "PUT" + | "patch" + | "PATCH" + | "purge" + | "PURGE" + | "link" + | "LINK" + | "unlink" + | "UNLINK"; + +export type Query = { + method: HttpMethod; + url: string; + code?: number; +}; + +type ExpectationValues = { + query: Query; + auth?: string; + params?: { + request?: object; + qparam?: Record; + response?: object; + }; +}; + +type TestValues = { + currentExpectedQuery: ExpectationValues | undefined; + lastQuery: ExpectationValues | undefined; +}; + +const logger = new Logger("testing/swr.ts"); + +export abstract class MockEnvironment { + expectations: Array = []; + queriesMade: Array = []; + index = 0; + + debug: boolean; + constructor(debug: boolean) { + this.debug = debug; + this.registerRequest.bind(this); + } + + public addRequestExpectation< + RequestType extends object, + ResponseType extends object, + >( + query: Query, + params: { + auth?: string; + request?: RequestType; + qparam?: any; + response?: ResponseType; + }, + ): void { + const expected = { query, params, auth: params.auth }; + this.expectations.push(expected); + if (this.debug) { + logger.info("saving query as expected", expected); + } + this.mockApiIfNeeded(); + } + + abstract mockApiIfNeeded(): void; + + public registerRequest< + RequestType extends object, + ResponseType extends object, + >( + query: Query, + params: { + auth?: string; + request?: RequestType; + qparam?: any; + response?: ResponseType; + }, + ): { status: number; payload: ResponseType } | undefined { + const queryMade = { query, params, auth: params.auth }; + this.queriesMade.push(queryMade); + const expectedQuery = this.expectations[this.index]; + if (!expectedQuery) { + if (this.debug) { + logger.info("unexpected query made", queryMade); + } + return undefined; + } + const responseCode = this.expectations[this.index].query.code ?? 200; + const mockedResponse = this.expectations[this.index].params + ?.response as ResponseType; + if (this.debug) { + logger.info("tracking query made", { + queryMade, + expectedQuery, + }); + } + this.index++; + return { status: responseCode, payload: mockedResponse }; + } + + public assertJustExpectedRequestWereMade(): AssertStatus { + let queryNumber = 0; + + while (queryNumber < this.expectations.length) { + const r = this.assertNextRequest(queryNumber); + if (r.result !== "ok") return r; + queryNumber++; + } + return this.assertNoMoreRequestWereMade(queryNumber); + } + + private getLastTestValues(idx: number): TestValues { + const currentExpectedQuery = this.expectations[idx]; + const lastQuery = this.queriesMade[idx]; + + return { currentExpectedQuery, lastQuery }; + } + + private assertNoMoreRequestWereMade(idx: number): AssertStatus { + const { currentExpectedQuery, lastQuery } = this.getLastTestValues(idx); + + if (lastQuery !== undefined) { + return { + result: "error-did-one-more", + made: lastQuery, + }; + } + if (currentExpectedQuery !== undefined) { + return { + result: "error-did-one-less", + expected: currentExpectedQuery, + }; + } + + return { + result: "ok", + }; + } + + private assertNextRequest(idx: number): AssertStatus { + const { currentExpectedQuery, lastQuery } = this.getLastTestValues(idx); + + if (!currentExpectedQuery) { + return { + result: "error-query-missing", + }; + } + + if (!lastQuery) { + return { + result: "error-did-one-less", + expected: currentExpectedQuery, + }; + } + + if (lastQuery.query.method) { + if (currentExpectedQuery.query.method !== lastQuery.query.method) { + return { + result: "error-difference", + diff: "method", + }; + } + if (currentExpectedQuery.query.url !== lastQuery.query.url) { + return { + result: "error-difference", + diff: "url", + }; + } + } + if ( + !deepEquals( + currentExpectedQuery.params?.request, + lastQuery.params?.request, + ) + ) { + return { + result: "error-difference", + diff: "query-body", + }; + } + if ( + !deepEquals(currentExpectedQuery.params?.qparam, lastQuery.params?.qparam) + ) { + return { + result: "error-difference", + diff: "query-params", + }; + } + if (!deepEquals(currentExpectedQuery.auth, lastQuery.auth)) { + return { + result: "error-difference", + diff: "query-auth", + }; + } + + return { + result: "ok", + }; + } +} + +type AssertStatus = + | AssertOk + | AssertQueryNotMadeButExpected + | AssertQueryMadeButNotExpected + | AssertQueryMissing + | AssertExpectedQueryMethodMismatch + | AssertExpectedQueryUrlMismatch + | AssertExpectedQueryAuthMismatch + | AssertExpectedQueryBodyMismatch + | AssertExpectedQueryParamsMismatch; + +interface AssertOk { + result: "ok"; +} + +//trying to assert for a expected query but there is +//no expected query in the queue +interface AssertQueryMissing { + result: "error-query-missing"; +} + +//tested component did one more query that expected +interface AssertQueryNotMadeButExpected { + result: "error-did-one-more"; + made: ExpectationValues; +} + +//tested component didn't make an expected query +interface AssertQueryMadeButNotExpected { + result: "error-did-one-less"; + expected: ExpectationValues; +} + +interface AssertExpectedQueryMethodMismatch { + result: "error-difference"; + diff: "method"; +} +interface AssertExpectedQueryUrlMismatch { + result: "error-difference"; + diff: "url"; +} +interface AssertExpectedQueryAuthMismatch { + result: "error-difference"; + diff: "query-auth"; +} +interface AssertExpectedQueryBodyMismatch { + result: "error-difference"; + diff: "query-body"; +} +interface AssertExpectedQueryParamsMismatch { + result: "error-difference"; + diff: "query-params"; +} + +/** + * helpers + * + */ +export type Tester = (a: any, b: any) => boolean | undefined; + +function deepEquals( + a: unknown, + b: unknown, + aStack: Array = [], + bStack: Array = [], +): boolean { + //one if the element is null or undefined + if (a === null || b === null || b === undefined || a === undefined) { + return a === b; + } + //both are errors + if (a instanceof Error && b instanceof Error) { + return a.message == b.message; + } + //is the same object + if (Object.is(a, b)) { + return true; + } + //both the same class + const name = Object.prototype.toString.call(a); + if (name != Object.prototype.toString.call(b)) { + return false; + } + // + switch (name) { + case "[object Boolean]": + case "[object String]": + case "[object Number]": + if (typeof a !== typeof b) { + // One is a primitive, one a `new Primitive()` + return false; + } else if (typeof a !== "object" && typeof b !== "object") { + // both are proper primitives + return Object.is(a, b); + } else { + // both are `new Primitive()`s + return Object.is(a.valueOf(), b.valueOf()); + } + case "[object Date]": { + const _a = a as Date; + const _b = b as Date; + return _a == _b; + } + case "[object RegExp]": { + const _a = a as RegExp; + const _b = b as RegExp; + return _a.source === _b.source && _a.flags === _b.flags; + } + case "[object Array]": { + const _a = a as Array; + const _b = b as Array; + if (_a.length !== _b.length) { + return false; + } + } + } + if (typeof a !== "object" || typeof b !== "object") { + return false; + } + + if ( + typeof a === "object" && + typeof b === "object" && + !Array.isArray(a) && + !Array.isArray(b) && + hasIterator(a) && + hasIterator(b) + ) { + return iterable(a, b); + } + + // Used to detect circular references. + let length = aStack.length; + while (length--) { + if (aStack[length] === a) { + return bStack[length] === b; + } else if (bStack[length] === b) { + return false; + } + } + aStack.push(a); + bStack.push(b); + + const aKeys = allKeysFromObject(a); + const bKeys = allKeysFromObject(b); + let keySize = aKeys.length; + + //same number of keys + if (bKeys.length !== keySize) { + return false; + } + + let keyIterator: string; + while (keySize--) { + const _a = a as Record; + const _b = b as Record; + + keyIterator = aKeys[keySize]; + + const de = deepEquals(_a[keyIterator], _b[keyIterator], aStack, bStack); + if (!de) { + return false; + } + } + + aStack.pop(); + bStack.pop(); + + return true; +} + +function allKeysFromObject(obj: object): Array { + const keys = []; + for (const key in obj) { + if (Object.prototype.hasOwnProperty.call(obj, key)) { + keys.push(key); + } + } + return keys; +} + +const IteratorSymbol = Symbol.iterator; + +function hasIterator(object: any): boolean { + return !!(object != null && object[IteratorSymbol]); +} + +function iterable( + a: unknown, + b: unknown, + aStack: Array = [], + bStack: Array = [], +): boolean { + if (a === null || b === null || b === undefined || a === undefined) { + return a === b; + } + if (a.constructor !== b.constructor) { + return false; + } + let length = aStack.length; + while (length--) { + if (aStack[length] === a) { + return bStack[length] === b; + } + } + aStack.push(a); + bStack.push(b); + + const aIterator = (a as any)[IteratorSymbol](); + const bIterator = (b as any)[IteratorSymbol](); + + const nextA = aIterator.next(); + while (nextA.done) { + const nextB = bIterator.next(); + if (nextB.done || !deepEquals(nextA.value, nextB.value)) { + return false; + } + } + if (!bIterator.next().done) { + return false; + } + + // Remove the first value from the stack of traversed values. + aStack.pop(); + bStack.pop(); + return true; +} diff --git a/packages/web-util/src/tests/swr.ts b/packages/web-util/src/tests/swr.ts new file mode 100644 index 000000000..95c62ebea --- /dev/null +++ b/packages/web-util/src/tests/swr.ts @@ -0,0 +1,82 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see + */ + +import { ComponentChildren, FunctionalComponent, h, VNode } from "preact"; +import { MockEnvironment, Query } from "./mock.js"; +import { SWRConfig } from "swr"; + +export { Query }; +/** + * Helper for hook that use SWR inside. + * + * buildTestingContext() will return a testing context + * + */ +export class SwrMockEnvironment extends MockEnvironment { + constructor(debug = false) { + super(debug); + } + + mockApiIfNeeded(): void { + null; // do nothing + } + + public buildTestingContext(): FunctionalComponent<{ + children: ComponentChildren; + }> { + const __REGISTER_REQUEST = this.registerRequest.bind(this); + return function TestingContext({ + children, + }: { + children: ComponentChildren; + }): VNode { + return h( + SWRConfig, + { + value: { + fetcher: (url: string, options: object) => { + const mocked = __REGISTER_REQUEST( + { + method: "get", + url, + }, + {}, + ); + if (!mocked) return undefined; + if (mocked.status > 400) { + const e: any = Error("simulated error for testing"); + //example error handling from https://swr.vercel.app/docs/error-handling + e.status = mocked.status; + throw e; + } + return mocked.payload; + }, + //These options are set for ending the test faster + //otherwise SWR will create timeouts that will live after the test finished + loadingTimeout: 0, + dedupingInterval: 0, + shouldRetryOnError: false, + errorRetryInterval: 0, + errorRetryCount: 0, + //clean cache for every test + provider: () => new Map(), + }, + }, + children, + ); + }; + } +} diff --git a/packages/web-util/src/utils/axios.ts b/packages/web-util/src/utils/axios.ts new file mode 100644 index 000000000..c38314009 --- /dev/null +++ b/packages/web-util/src/utils/axios.ts @@ -0,0 +1,79 @@ +/* + This file is part of GNU Taler + (C) 2021 Taler Systems S.A. + + GNU Taler is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + GNU Taler; see the file COPYING. If not, see + */ + +import axios, { AxiosPromise, AxiosRequestConfig } from "axios"; + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + */ + +//FIXME: remove this, since it is not used anymore +/** + * @deprecated + */ +export let removeAxiosCancelToken = false; + +export let axiosHandler = function doAxiosRequest( + config: AxiosRequestConfig, +): AxiosPromise { + return axios(config); +}; + +const listOfHandlersToUseOnce = new Array(); + +/** + * Set this backend library to testing mode. + * Instead of calling the axios library the @handler will be called + * + * @param handler callback that will mock axios + */ +export function setAxiosRequestAsTestingEnvironment( + handler: AxiosHandler, +): void { + removeAxiosCancelToken = true; + axiosHandler = function defaultTestingHandler(config) { + const currentHanlder = listOfHandlersToUseOnce.shift(); + if (!currentHanlder) { + return handler(config); + } + + return currentHanlder(config); + }; +} + +type AxiosHandler = (config: AxiosRequestConfig) => AxiosPromise; +type AxiosArguments = { args: AxiosRequestConfig | undefined }; + +/** + * Replace Axios handler with a mock. + * Throw if is called more than once + * + * @param handler mock function + * @returns savedArgs + */ +export function mockAxiosOnce(handler: AxiosHandler): { + args: AxiosRequestConfig | undefined; +} { + const savedArgs: AxiosArguments = { args: undefined }; + listOfHandlersToUseOnce.push( + (config: AxiosRequestConfig): AxiosPromise => { + savedArgs.args = config; + return handler(config); + }, + ); + return savedArgs; +} diff --git a/packages/web-util/src/utils/index.ts b/packages/web-util/src/utils/index.ts new file mode 100644 index 000000000..6dfbd5f8d --- /dev/null +++ b/packages/web-util/src/utils/index.ts @@ -0,0 +1 @@ +export * from "./axios.js"; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 43c45691b..c5255b4f1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -96,24 +96,30 @@ importers: '@gnu-taler/pogen': ^0.0.5 '@gnu-taler/taler-util': workspace:* '@gnu-taler/web-util': workspace:* + '@types/chai': ^4.3.0 '@types/history': ^4.7.8 + '@types/mocha': ^10.0.1 + '@types/node': ^18.11.14 '@typescript-eslint/eslint-plugin': ^5.41.0 '@typescript-eslint/parser': ^5.41.0 + async_hooks: ^1.0.0 bulma: ^0.9.4 bulma-checkbox: ^1.1.1 bulma-radio: ^1.1.1 + chai: ^4.3.6 date-fns: 2.29.3 esbuild: ^0.15.12 eslint-config-preact: ^1.2.0 history: 4.10.1 jed: 1.1.1 + mocha: ^9.2.0 po2json: ^0.4.5 preact: 10.11.3 preact-router: 3.2.1 qrcode-generator: ^1.4.4 sass: 1.56.1 swr: 1.3.0 - typescript: ^4.4.4 + typescript: 4.8.4 dependencies: '@gnu-taler/taler-util': link:../taler-util '@gnu-taler/web-util': link:../web-util @@ -127,14 +133,20 @@ importers: devDependencies: '@creativebulma/bulma-tooltip': 1.2.0 '@gnu-taler/pogen': link:../pogen + '@types/chai': 4.3.3 '@types/history': 4.7.11 + '@types/mocha': 10.0.1 + '@types/node': 18.11.14 '@typescript-eslint/eslint-plugin': 5.41.0_2dmizcyfdgb4npqs6z4fehioli '@typescript-eslint/parser': 5.41.0_typescript@4.8.4 + async_hooks: 1.0.0 bulma: 0.9.4 bulma-checkbox: 1.2.1 bulma-radio: 1.2.0 + chai: 4.3.6 esbuild: 0.15.12 eslint-config-preact: 1.3.0_qqbgcrpnpybc6dh47gt272vyy4 + mocha: 9.2.2 po2json: 0.4.5 sass: 1.56.1 typescript: 4.8.4 @@ -383,7 +395,7 @@ importers: sirv-cli: ^1.0.11 swr: 1.3.0 typedoc: ^0.20.36 - typescript: 4.4.4 + typescript: 4.8.4 yup: ^0.32.9 dependencies: '@gnu-taler/taler-util': link:../taler-util @@ -405,9 +417,9 @@ importers: '@gnu-taler/pogen': link:../pogen '@storybook/addon-a11y': 6.5.13_@preact+compat@17.1.2 '@storybook/addon-actions': 6.5.13_@preact+compat@17.1.2 - '@storybook/addon-essentials': 6.5.13_e4oandlgwkzlaxn6zc3btvol24 + '@storybook/addon-essentials': 6.5.13_2nt5iz47gcdduxcnvfnexph4hq '@storybook/addon-links': 6.5.13_@preact+compat@17.1.2 - '@storybook/preact': 6.5.13_q57tjbu375p52k2lkxkownwouu + '@storybook/preact': 6.5.13_xa5zyoe4qu34opzfrw5imxak3u '@storybook/preset-scss': 1.0.3_sass-loader@10.1.1 '@testing-library/preact': 2.0.1_preact@10.6.5 '@testing-library/preact-hooks': 1.1.0_vfcmu6iy7nffpurikpgxo6gwxi @@ -415,8 +427,8 @@ importers: '@types/jest': 26.0.24 '@types/mocha': 8.2.3 '@types/node': 18.11.5 - '@typescript-eslint/eslint-plugin': 4.33.0_zrqxgwgitu7trrjeml3nqco3jq - '@typescript-eslint/parser': 4.33.0_wnilx7boviscikmvsfkd6ljepe + '@typescript-eslint/eslint-plugin': 4.33.0_k4l66av2tbo6kxzw52jzgbfzii + '@typescript-eslint/parser': 4.33.0_3rubbgt5ekhqrcgx4uwls3neim babel-loader: 8.2.5_@babel+core@7.18.9 base64-inline-loader: 1.1.1 bulma: 0.9.4 @@ -428,7 +440,7 @@ importers: bulma-upload-control: 1.2.0 dotenv: 8.6.0 eslint: 7.32.0 - eslint-config-preact: 1.3.0_55vw575o5aj4h37h7cossdtfje + eslint-config-preact: 1.3.0_nxlzr75jbqkso2fds5zjovs2ii eslint-plugin-header: 3.1.1_eslint@7.32.0 html-webpack-inline-chunk-plugin: 1.1.1 html-webpack-inline-source-plugin: 0.0.10 @@ -445,8 +457,8 @@ importers: sass-loader: 10.1.1_sass@1.55.0 script-ext-html-webpack-plugin: 2.1.5 sirv-cli: 1.0.14 - typedoc: 0.20.37_typescript@4.4.4 - typescript: 4.4.4 + typedoc: 0.20.37_typescript@4.8.4 + typescript: 4.8.4 packages/pogen: specifiers: @@ -697,6 +709,7 @@ importers: '@types/node': ^18.11.9 '@types/web': ^0.0.82 '@types/ws': ^8.5.3 + axios: ^1.2.1 chokidar: ^3.5.3 esbuild: ^0.14.21 express: ^4.18.2 @@ -704,6 +717,7 @@ importers: preact-render-to-string: ^5.2.6 prettier: ^2.5.1 rimraf: ^3.0.2 + swr: 1.3.0 tslib: ^2.4.0 typescript: ^4.8.4 ws: 7.4.5 @@ -713,6 +727,7 @@ importers: '@types/node': 18.11.9 '@types/web': 0.0.82 '@types/ws': 8.5.3 + axios: 1.2.1 chokidar: 3.5.3 esbuild: 0.14.54 express: 4.18.2 @@ -720,6 +735,7 @@ importers: preact-render-to-string: 5.2.6_preact@10.11.3 prettier: 2.7.1 rimraf: 3.0.2 + swr: 1.3.0 tslib: 2.4.1 typescript: 4.8.4 ws: 7.4.5 @@ -4635,7 +4651,7 @@ packages: - webpack-command dev: true - /@storybook/addon-controls/6.5.13_ipjevasairp6knvwkrpikcsgoq: + /@storybook/addon-controls/6.5.13_j3fy4dsuv6tweqy6dixwnav3v4: resolution: {integrity: sha512-lYq3uf2mlVevm0bi6ueL3H6TpUMRYW9s/pTNTVJT225l27kLdFR9wEKxAkCBrlKaTgDLJmzzDRsJE3NLZlR/5Q==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -4650,7 +4666,7 @@ packages: '@storybook/api': 6.5.13_@preact+compat@17.1.2 '@storybook/client-logger': 6.5.13 '@storybook/components': 6.5.13_@preact+compat@17.1.2 - '@storybook/core-common': 6.5.13_ipjevasairp6knvwkrpikcsgoq + '@storybook/core-common': 6.5.13_j3fy4dsuv6tweqy6dixwnav3v4 '@storybook/csf': 0.0.2--canary.4566f4d.1 '@storybook/node-logger': 6.5.13 '@storybook/store': 6.5.13_@preact+compat@17.1.2 @@ -4668,6 +4684,60 @@ packages: - webpack-command dev: true + /@storybook/addon-docs/6.5.13_2nt5iz47gcdduxcnvfnexph4hq: + resolution: {integrity: sha512-RG/NjsheD9FixZ789RJlNyNccaR2Cuy7CtAwph4oUNi3aDFjtOI8Oe9L+FOT7qtVnZLw/YMjF+pZxoDqJNKLPw==} + peerDependencies: + '@storybook/mdx2-csf': ^0.0.3 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@storybook/mdx2-csf': + optional: true + react: + optional: true + react-dom: + optional: true + dependencies: + '@babel/plugin-transform-react-jsx': 7.19.0_@babel+core@7.18.9 + '@babel/preset-env': 7.19.4_@babel+core@7.18.9 + '@jest/transform': 26.6.2 + '@mdx-js/react': 1.6.22_@preact+compat@17.1.2 + '@storybook/addons': 6.5.13_@preact+compat@17.1.2 + '@storybook/api': 6.5.13_@preact+compat@17.1.2 + '@storybook/components': 6.5.13_@preact+compat@17.1.2 + '@storybook/core-common': 6.5.13_j3fy4dsuv6tweqy6dixwnav3v4 + '@storybook/core-events': 6.5.13 + '@storybook/csf': 0.0.2--canary.4566f4d.1 + '@storybook/docs-tools': 6.5.13_@preact+compat@17.1.2 + '@storybook/mdx1-csf': 0.0.1_@babel+core@7.18.9 + '@storybook/node-logger': 6.5.13 + '@storybook/postinstall': 6.5.13 + '@storybook/preview-web': 6.5.13_@preact+compat@17.1.2 + '@storybook/source-loader': 6.5.13_@preact+compat@17.1.2 + '@storybook/store': 6.5.13_@preact+compat@17.1.2 + '@storybook/theming': 6.5.13_@preact+compat@17.1.2 + babel-loader: 8.2.5_@babel+core@7.18.9 + core-js: 3.26.0 + fast-deep-equal: 3.1.3 + global: 4.4.0 + lodash: 4.17.21 + react: /@preact/compat/17.1.2_preact@10.6.5 + regenerator-runtime: 0.13.10 + remark-external-links: 8.0.0 + remark-slug: 6.1.0 + ts-dedent: 2.2.0 + util-deprecate: 1.0.2 + transitivePeerDependencies: + - '@babel/core' + - eslint + - supports-color + - typescript + - vue-template-compiler + - webpack + - webpack-cli + - webpack-command + dev: true + /@storybook/addon-docs/6.5.13_dazlt7ye7nu7xsezygxn7bviwy: resolution: {integrity: sha512-RG/NjsheD9FixZ789RJlNyNccaR2Cuy7CtAwph4oUNi3aDFjtOI8Oe9L+FOT7qtVnZLw/YMjF+pZxoDqJNKLPw==} peerDependencies: @@ -4721,56 +4791,86 @@ packages: - webpack-command dev: true - /@storybook/addon-docs/6.5.13_e4oandlgwkzlaxn6zc3btvol24: - resolution: {integrity: sha512-RG/NjsheD9FixZ789RJlNyNccaR2Cuy7CtAwph4oUNi3aDFjtOI8Oe9L+FOT7qtVnZLw/YMjF+pZxoDqJNKLPw==} + /@storybook/addon-essentials/6.5.13_2nt5iz47gcdduxcnvfnexph4hq: + resolution: {integrity: sha512-G9FVAWV7ixjVLWeLgIX+VT90tcAk6yQxfZQegfg5ucRilGysJCDaNnoab4xuuvm1R40TfFhba3iAGZtQYsddmw==} peerDependencies: - '@storybook/mdx2-csf': ^0.0.3 - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 + '@babel/core': ^7.9.6 + '@storybook/angular': '*' + '@storybook/builder-manager4': '*' + '@storybook/builder-manager5': '*' + '@storybook/builder-webpack4': '*' + '@storybook/builder-webpack5': '*' + '@storybook/html': '*' + '@storybook/vue': '*' + '@storybook/vue3': '*' + '@storybook/web-components': '*' + lit: '*' + lit-html: '*' + react: '*' + react-dom: '*' + svelte: '*' + sveltedoc-parser: '*' + vue: '*' + webpack: '*' peerDependenciesMeta: - '@storybook/mdx2-csf': + '@storybook/angular': + optional: true + '@storybook/builder-manager4': + optional: true + '@storybook/builder-manager5': + optional: true + '@storybook/builder-webpack4': + optional: true + '@storybook/builder-webpack5': + optional: true + '@storybook/html': + optional: true + '@storybook/vue': + optional: true + '@storybook/vue3': + optional: true + '@storybook/web-components': + optional: true + lit: + optional: true + lit-html: optional: true react: optional: true react-dom: optional: true + svelte: + optional: true + sveltedoc-parser: + optional: true + vue: + optional: true + webpack: + optional: true dependencies: - '@babel/plugin-transform-react-jsx': 7.19.0_@babel+core@7.18.9 - '@babel/preset-env': 7.19.4_@babel+core@7.18.9 - '@jest/transform': 26.6.2 - '@mdx-js/react': 1.6.22_@preact+compat@17.1.2 + '@babel/core': 7.18.9 + '@storybook/addon-actions': 6.5.13_@preact+compat@17.1.2 + '@storybook/addon-backgrounds': 6.5.13_@preact+compat@17.1.2 + '@storybook/addon-controls': 6.5.13_j3fy4dsuv6tweqy6dixwnav3v4 + '@storybook/addon-docs': 6.5.13_2nt5iz47gcdduxcnvfnexph4hq + '@storybook/addon-measure': 6.5.13_@preact+compat@17.1.2 + '@storybook/addon-outline': 6.5.13_@preact+compat@17.1.2 + '@storybook/addon-toolbars': 6.5.13_@preact+compat@17.1.2 + '@storybook/addon-viewport': 6.5.13_@preact+compat@17.1.2 '@storybook/addons': 6.5.13_@preact+compat@17.1.2 '@storybook/api': 6.5.13_@preact+compat@17.1.2 - '@storybook/components': 6.5.13_@preact+compat@17.1.2 - '@storybook/core-common': 6.5.13_ipjevasairp6knvwkrpikcsgoq - '@storybook/core-events': 6.5.13 - '@storybook/csf': 0.0.2--canary.4566f4d.1 - '@storybook/docs-tools': 6.5.13_@preact+compat@17.1.2 - '@storybook/mdx1-csf': 0.0.1_@babel+core@7.18.9 + '@storybook/core-common': 6.5.13_j3fy4dsuv6tweqy6dixwnav3v4 '@storybook/node-logger': 6.5.13 - '@storybook/postinstall': 6.5.13 - '@storybook/preview-web': 6.5.13_@preact+compat@17.1.2 - '@storybook/source-loader': 6.5.13_@preact+compat@17.1.2 - '@storybook/store': 6.5.13_@preact+compat@17.1.2 - '@storybook/theming': 6.5.13_@preact+compat@17.1.2 - babel-loader: 8.2.5_@babel+core@7.18.9 core-js: 3.26.0 - fast-deep-equal: 3.1.3 - global: 4.4.0 - lodash: 4.17.21 react: /@preact/compat/17.1.2_preact@10.6.5 regenerator-runtime: 0.13.10 - remark-external-links: 8.0.0 - remark-slug: 6.1.0 ts-dedent: 2.2.0 - util-deprecate: 1.0.2 transitivePeerDependencies: - - '@babel/core' + - '@storybook/mdx2-csf' - eslint - supports-color - typescript - vue-template-compiler - - webpack - webpack-cli - webpack-command dev: true @@ -4858,90 +4958,6 @@ packages: - webpack-command dev: true - /@storybook/addon-essentials/6.5.13_e4oandlgwkzlaxn6zc3btvol24: - resolution: {integrity: sha512-G9FVAWV7ixjVLWeLgIX+VT90tcAk6yQxfZQegfg5ucRilGysJCDaNnoab4xuuvm1R40TfFhba3iAGZtQYsddmw==} - peerDependencies: - '@babel/core': ^7.9.6 - '@storybook/angular': '*' - '@storybook/builder-manager4': '*' - '@storybook/builder-manager5': '*' - '@storybook/builder-webpack4': '*' - '@storybook/builder-webpack5': '*' - '@storybook/html': '*' - '@storybook/vue': '*' - '@storybook/vue3': '*' - '@storybook/web-components': '*' - lit: '*' - lit-html: '*' - react: '*' - react-dom: '*' - svelte: '*' - sveltedoc-parser: '*' - vue: '*' - webpack: '*' - peerDependenciesMeta: - '@storybook/angular': - optional: true - '@storybook/builder-manager4': - optional: true - '@storybook/builder-manager5': - optional: true - '@storybook/builder-webpack4': - optional: true - '@storybook/builder-webpack5': - optional: true - '@storybook/html': - optional: true - '@storybook/vue': - optional: true - '@storybook/vue3': - optional: true - '@storybook/web-components': - optional: true - lit: - optional: true - lit-html: - optional: true - react: - optional: true - react-dom: - optional: true - svelte: - optional: true - sveltedoc-parser: - optional: true - vue: - optional: true - webpack: - optional: true - dependencies: - '@babel/core': 7.18.9 - '@storybook/addon-actions': 6.5.13_@preact+compat@17.1.2 - '@storybook/addon-backgrounds': 6.5.13_@preact+compat@17.1.2 - '@storybook/addon-controls': 6.5.13_ipjevasairp6knvwkrpikcsgoq - '@storybook/addon-docs': 6.5.13_e4oandlgwkzlaxn6zc3btvol24 - '@storybook/addon-measure': 6.5.13_@preact+compat@17.1.2 - '@storybook/addon-outline': 6.5.13_@preact+compat@17.1.2 - '@storybook/addon-toolbars': 6.5.13_@preact+compat@17.1.2 - '@storybook/addon-viewport': 6.5.13_@preact+compat@17.1.2 - '@storybook/addons': 6.5.13_@preact+compat@17.1.2 - '@storybook/api': 6.5.13_@preact+compat@17.1.2 - '@storybook/core-common': 6.5.13_ipjevasairp6knvwkrpikcsgoq - '@storybook/node-logger': 6.5.13 - core-js: 3.26.0 - react: /@preact/compat/17.1.2_preact@10.6.5 - regenerator-runtime: 0.13.10 - ts-dedent: 2.2.0 - transitivePeerDependencies: - - '@storybook/mdx2-csf' - - eslint - - supports-color - - typescript - - vue-template-compiler - - webpack-cli - - webpack-command - dev: true - /@storybook/addon-links/6.5.13: resolution: {integrity: sha512-K/LYYu9R/Xoah5h9MNh4mSHOic3q5csqjderLqr2YW/KPYiuNubgvzEbAAbzI5xq5JrtAZqnINrZUv2A4CyYbQ==} peerDependencies: @@ -5311,75 +5327,6 @@ packages: util-deprecate: 1.0.2 dev: true - /@storybook/builder-webpack4/6.5.13_oj3zznhuofsh7mvlmigrvm3x7y: - resolution: {integrity: sha512-Agqy3IKPv3Nl8QqdS7PjtqLp+c0BD8+/3A2ki/YfKqVz+F+J34EpbZlh3uU053avm1EoNQHSmhZok3ZlWH6O7A==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@babel/core': 7.18.9 - '@storybook/addons': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty - '@storybook/api': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty - '@storybook/channel-postmessage': 6.5.13 - '@storybook/channels': 6.5.13 - '@storybook/client-api': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty - '@storybook/client-logger': 6.5.13 - '@storybook/components': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty - '@storybook/core-common': 6.5.13_oj3zznhuofsh7mvlmigrvm3x7y - '@storybook/core-events': 6.5.13 - '@storybook/node-logger': 6.5.13 - '@storybook/preview-web': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty - '@storybook/router': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty - '@storybook/semver': 7.3.2 - '@storybook/store': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty - '@storybook/theming': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty - '@storybook/ui': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty - '@types/node': 16.18.0 - '@types/webpack': 4.41.33 - autoprefixer: 9.8.8 - babel-loader: 8.2.5_7uc2ny5pnz7ums2wq2q562bf6y - case-sensitive-paths-webpack-plugin: 2.4.0 - core-js: 3.26.0 - css-loader: 3.6.0_webpack@4.46.0 - file-loader: 6.2.0_webpack@4.46.0 - find-up: 5.0.0 - fork-ts-checker-webpack-plugin: 4.1.6_bbqhrndznz6a4k7d23h2kkrexi - glob: 7.2.3 - glob-promise: 3.4.0_glob@7.2.3 - global: 4.4.0 - html-webpack-plugin: 4.5.2_webpack@4.46.0 - pnp-webpack-plugin: 1.6.4_typescript@4.4.4 - postcss: 7.0.39 - postcss-flexbugs-fixes: 4.2.1 - postcss-loader: 4.3.0_gzaxsinx64nntyd3vmdqwl7coe - raw-loader: 4.0.2_webpack@4.46.0 - react: 16.14.0 - react-dom: 16.14.0_react@16.14.0 - stable: 0.1.8 - style-loader: 1.3.0_webpack@4.46.0 - terser-webpack-plugin: 4.2.3_webpack@4.46.0 - ts-dedent: 2.2.0 - typescript: 4.4.4 - url-loader: 4.1.1_lit45vopotvaqup7lrvlnvtxwy - util-deprecate: 1.0.2 - webpack: 4.46.0 - webpack-dev-middleware: 3.7.3_webpack@4.46.0 - webpack-filter-warnings-plugin: 1.2.1_webpack@4.46.0 - webpack-hot-middleware: 2.25.2 - webpack-virtual-modules: 0.2.2 - transitivePeerDependencies: - - bluebird - - eslint - - supports-color - - vue-template-compiler - - webpack-cli - - webpack-command - dev: true - /@storybook/builder-webpack4/6.5.13_u5cwnb36e3nipolzgtjnnpepdu: resolution: {integrity: sha512-Agqy3IKPv3Nl8QqdS7PjtqLp+c0BD8+/3A2ki/YfKqVz+F+J34EpbZlh3uU053avm1EoNQHSmhZok3ZlWH6O7A==} peerDependencies: @@ -5567,80 +5514,6 @@ packages: util-deprecate: 1.0.2 dev: true - /@storybook/core-client/6.5.13_4z4xstjutcmkuoh5zkinl7lmym: - resolution: {integrity: sha512-YuELbRokTBdqjbx/R4/7O4rou9kvbBIOJjlUkor9hdLLuJ3P0yGianERGNkZFfvcfMBAxU0p52o7QvDldSR3kA==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - typescript: '*' - webpack: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@storybook/addons': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty - '@storybook/channel-postmessage': 6.5.13 - '@storybook/channel-websocket': 6.5.13 - '@storybook/client-api': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty - '@storybook/client-logger': 6.5.13 - '@storybook/core-events': 6.5.13 - '@storybook/csf': 0.0.2--canary.4566f4d.1 - '@storybook/preview-web': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty - '@storybook/store': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty - '@storybook/ui': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty - airbnb-js-shims: 2.2.1 - ansi-to-html: 0.6.15 - core-js: 3.26.0 - global: 4.4.0 - lodash: 4.17.21 - qs: 6.11.0 - react: 16.14.0 - react-dom: 16.14.0_react@16.14.0 - regenerator-runtime: 0.13.10 - ts-dedent: 2.2.0 - typescript: 4.4.4 - unfetch: 4.2.0 - util-deprecate: 1.0.2 - webpack: 5.74.0 - dev: true - - /@storybook/core-client/6.5.13_6dhvdvok4rm6xhvn3ntojenmae: - resolution: {integrity: sha512-YuELbRokTBdqjbx/R4/7O4rou9kvbBIOJjlUkor9hdLLuJ3P0yGianERGNkZFfvcfMBAxU0p52o7QvDldSR3kA==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - typescript: '*' - webpack: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@storybook/addons': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty - '@storybook/channel-postmessage': 6.5.13 - '@storybook/channel-websocket': 6.5.13 - '@storybook/client-api': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty - '@storybook/client-logger': 6.5.13 - '@storybook/core-events': 6.5.13 - '@storybook/csf': 0.0.2--canary.4566f4d.1 - '@storybook/preview-web': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty - '@storybook/store': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty - '@storybook/ui': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty - airbnb-js-shims: 2.2.1 - ansi-to-html: 0.6.15 - core-js: 3.26.0 - global: 4.4.0 - lodash: 4.17.21 - qs: 6.11.0 - react: 16.14.0 - react-dom: 16.14.0_react@16.14.0 - regenerator-runtime: 0.13.10 - ts-dedent: 2.2.0 - typescript: 4.4.4 - unfetch: 4.2.0 - util-deprecate: 1.0.2 - webpack: 4.46.0 - dev: true - /@storybook/core-client/6.5.13_plmdyubmb7xm6euvqu3qohl7ea: resolution: {integrity: sha512-YuELbRokTBdqjbx/R4/7O4rou9kvbBIOJjlUkor9hdLLuJ3P0yGianERGNkZFfvcfMBAxU0p52o7QvDldSR3kA==} peerDependencies: @@ -5784,7 +5657,7 @@ packages: - webpack-command dev: true - /@storybook/core-common/6.5.13_ipjevasairp6knvwkrpikcsgoq: + /@storybook/core-common/6.5.13_j3fy4dsuv6tweqy6dixwnav3v4: resolution: {integrity: sha512-+DVZrRsteE9pw0X5MNffkdBgejQnbnL+UOG3qXkE9xxUamQALnuqS/w1BzpHE9WmOHuf7RWMKflyQEW3OLKAJg==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 @@ -5828,7 +5701,7 @@ packages: express: 4.18.2 file-system-cache: 1.1.0 find-up: 5.0.0 - fork-ts-checker-webpack-plugin: 6.5.2_bbqhrndznz6a4k7d23h2kkrexi + fork-ts-checker-webpack-plugin: 6.5.2_3n2x3j6farblcaf52bherr6og4 fs-extra: 9.1.0 glob: 7.2.3 handlebars: 4.7.7 @@ -5843,78 +5716,7 @@ packages: slash: 3.0.0 telejson: 6.0.8 ts-dedent: 2.2.0 - typescript: 4.4.4 - util-deprecate: 1.0.2 - webpack: 4.46.0 - transitivePeerDependencies: - - eslint - - supports-color - - vue-template-compiler - - webpack-cli - - webpack-command - dev: true - - /@storybook/core-common/6.5.13_oj3zznhuofsh7mvlmigrvm3x7y: - resolution: {integrity: sha512-+DVZrRsteE9pw0X5MNffkdBgejQnbnL+UOG3qXkE9xxUamQALnuqS/w1BzpHE9WmOHuf7RWMKflyQEW3OLKAJg==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@babel/core': 7.18.9 - '@babel/plugin-proposal-class-properties': 7.18.6_@babel+core@7.18.9 - '@babel/plugin-proposal-decorators': 7.19.6_@babel+core@7.18.9 - '@babel/plugin-proposal-export-default-from': 7.18.10_@babel+core@7.18.9 - '@babel/plugin-proposal-nullish-coalescing-operator': 7.18.6_@babel+core@7.18.9 - '@babel/plugin-proposal-object-rest-spread': 7.19.4_@babel+core@7.18.9 - '@babel/plugin-proposal-optional-chaining': 7.18.9_@babel+core@7.18.9 - '@babel/plugin-proposal-private-methods': 7.18.6_@babel+core@7.18.9 - '@babel/plugin-proposal-private-property-in-object': 7.18.6_@babel+core@7.18.9 - '@babel/plugin-syntax-dynamic-import': 7.8.3_@babel+core@7.18.9 - '@babel/plugin-transform-arrow-functions': 7.18.6_@babel+core@7.18.9 - '@babel/plugin-transform-block-scoping': 7.19.4_@babel+core@7.18.9 - '@babel/plugin-transform-classes': 7.19.0_@babel+core@7.18.9 - '@babel/plugin-transform-destructuring': 7.19.4_@babel+core@7.18.9 - '@babel/plugin-transform-for-of': 7.18.8_@babel+core@7.18.9 - '@babel/plugin-transform-parameters': 7.18.8_@babel+core@7.18.9 - '@babel/plugin-transform-shorthand-properties': 7.18.6_@babel+core@7.18.9 - '@babel/plugin-transform-spread': 7.19.0_@babel+core@7.18.9 - '@babel/preset-env': 7.19.4_@babel+core@7.18.9 - '@babel/preset-react': 7.18.6_@babel+core@7.18.9 - '@babel/preset-typescript': 7.18.6_@babel+core@7.18.9 - '@babel/register': 7.18.9_@babel+core@7.18.9 - '@storybook/node-logger': 6.5.13 - '@storybook/semver': 7.3.2 - '@types/node': 16.18.0 - '@types/pretty-hrtime': 1.0.1 - babel-loader: 8.2.5_7uc2ny5pnz7ums2wq2q562bf6y - babel-plugin-macros: 3.1.0 - babel-plugin-polyfill-corejs3: 0.1.7_@babel+core@7.18.9 - chalk: 4.1.2 - core-js: 3.26.0 - express: 4.18.2 - file-system-cache: 1.1.0 - find-up: 5.0.0 - fork-ts-checker-webpack-plugin: 6.5.2_bbqhrndznz6a4k7d23h2kkrexi - fs-extra: 9.1.0 - glob: 7.2.3 - handlebars: 4.7.7 - interpret: 2.2.0 - json5: 2.2.1 - lazy-universal-dotenv: 3.0.1 - picomatch: 2.3.1 - pkg-dir: 5.0.0 - pretty-hrtime: 1.0.3 - react: 16.14.0 - react-dom: 16.14.0_react@16.14.0 - resolve-from: 5.0.0 - slash: 3.0.0 - telejson: 6.0.8 - ts-dedent: 2.2.0 - typescript: 4.4.4 + typescript: 4.8.4 util-deprecate: 1.0.2 webpack: 4.46.0 transitivePeerDependencies: @@ -6002,83 +5804,6 @@ packages: core-js: 3.26.0 dev: true - /@storybook/core-server/6.5.13_oj3zznhuofsh7mvlmigrvm3x7y: - resolution: {integrity: sha512-vs7tu3kAnFwuINio1p87WyqDNlFyZESmeh9s7vvrZVbe/xS/ElqDscr9DT5seW+jbtxufAaHsx+JUTver1dheQ==} - peerDependencies: - '@storybook/builder-webpack5': '*' - '@storybook/manager-webpack5': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - typescript: '*' - peerDependenciesMeta: - '@storybook/builder-webpack5': - optional: true - '@storybook/manager-webpack5': - optional: true - typescript: - optional: true - dependencies: - '@discoveryjs/json-ext': 0.5.7 - '@storybook/builder-webpack4': 6.5.13_oj3zznhuofsh7mvlmigrvm3x7y - '@storybook/core-client': 6.5.13_6dhvdvok4rm6xhvn3ntojenmae - '@storybook/core-common': 6.5.13_oj3zznhuofsh7mvlmigrvm3x7y - '@storybook/core-events': 6.5.13 - '@storybook/csf': 0.0.2--canary.4566f4d.1 - '@storybook/csf-tools': 6.5.13 - '@storybook/manager-webpack4': 6.5.13_oj3zznhuofsh7mvlmigrvm3x7y - '@storybook/node-logger': 6.5.13 - '@storybook/semver': 7.3.2 - '@storybook/store': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty - '@storybook/telemetry': 6.5.13_oj3zznhuofsh7mvlmigrvm3x7y - '@types/node': 16.18.0 - '@types/node-fetch': 2.6.2 - '@types/pretty-hrtime': 1.0.1 - '@types/webpack': 4.41.33 - better-opn: 2.1.1 - boxen: 5.1.2 - chalk: 4.1.2 - cli-table3: 0.6.3 - commander: 6.2.1 - compression: 1.7.4 - core-js: 3.26.0 - cpy: 8.1.2 - detect-port: 1.5.1 - express: 4.18.2 - fs-extra: 9.1.0 - global: 4.4.0 - globby: 11.1.0 - ip: 2.0.0 - lodash: 4.17.21 - node-fetch: 2.6.7 - open: 8.4.0 - pretty-hrtime: 1.0.3 - prompts: 2.4.2 - react: 16.14.0 - react-dom: 16.14.0_react@16.14.0 - regenerator-runtime: 0.13.10 - serve-favicon: 2.5.0 - slash: 3.0.0 - telejson: 6.0.8 - ts-dedent: 2.2.0 - typescript: 4.4.4 - util-deprecate: 1.0.2 - watchpack: 2.4.0 - webpack: 4.46.0 - ws: 8.10.0 - x-default-browser: 0.4.0 - transitivePeerDependencies: - - '@storybook/mdx2-csf' - - bluebird - - bufferutil - - encoding - - eslint - - supports-color - - utf-8-validate - - vue-template-compiler - - webpack-cli - - webpack-command - dev: true - /@storybook/core-server/6.5.13_u5cwnb36e3nipolzgtjnnpepdu: resolution: {integrity: sha512-vs7tu3kAnFwuINio1p87WyqDNlFyZESmeh9s7vvrZVbe/xS/ElqDscr9DT5seW+jbtxufAaHsx+JUTver1dheQ==} peerDependencies: @@ -6192,42 +5917,6 @@ packages: - webpack-command dev: true - /@storybook/core/6.5.13_ujfskrypehrywuobbsgnsb3724: - resolution: {integrity: sha512-kw1lCgbsxzUimGww6t5rmuWJmFPe9kGGyzIqvj4RC4BBcEsP40LEu9XhSfvnb8vTOLIULFZeZpdRFfJs4TYbUw==} - peerDependencies: - '@storybook/builder-webpack5': '*' - '@storybook/manager-webpack5': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - typescript: '*' - webpack: '*' - peerDependenciesMeta: - '@storybook/builder-webpack5': - optional: true - '@storybook/manager-webpack5': - optional: true - typescript: - optional: true - dependencies: - '@storybook/core-client': 6.5.13_4z4xstjutcmkuoh5zkinl7lmym - '@storybook/core-server': 6.5.13_oj3zznhuofsh7mvlmigrvm3x7y - react: 16.14.0 - react-dom: 16.14.0_react@16.14.0 - typescript: 4.4.4 - webpack: 5.74.0 - transitivePeerDependencies: - - '@storybook/mdx2-csf' - - bluebird - - bufferutil - - encoding - - eslint - - supports-color - - utf-8-validate - - vue-template-compiler - - webpack-cli - - webpack-command - dev: true - /@storybook/csf-tools/6.5.13: resolution: {integrity: sha512-63Ev+VmBqzwSwfUzbuXOLKBD5dMTK2zBYLQ9anTVw70FuTikwTsGIbPgb098K0vsxRCgxl7KM7NpivHqtZtdjw==} peerDependencies: @@ -6292,64 +5981,6 @@ packages: - supports-color dev: true - /@storybook/manager-webpack4/6.5.13_oj3zznhuofsh7mvlmigrvm3x7y: - resolution: {integrity: sha512-pURzS5W3XM0F7bCBWzpl7TRsuy+OXFwLXiWLaexuvo0POZe31Ueo2A1R4rx3MT5Iee8O9mYvG2XTmvK9MlLefQ==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@babel/core': 7.18.9 - '@babel/plugin-transform-template-literals': 7.18.9_@babel+core@7.18.9 - '@babel/preset-react': 7.18.6_@babel+core@7.18.9 - '@storybook/addons': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty - '@storybook/core-client': 6.5.13_6dhvdvok4rm6xhvn3ntojenmae - '@storybook/core-common': 6.5.13_oj3zznhuofsh7mvlmigrvm3x7y - '@storybook/node-logger': 6.5.13 - '@storybook/theming': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty - '@storybook/ui': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty - '@types/node': 16.18.0 - '@types/webpack': 4.41.33 - babel-loader: 8.2.5_7uc2ny5pnz7ums2wq2q562bf6y - case-sensitive-paths-webpack-plugin: 2.4.0 - chalk: 4.1.2 - core-js: 3.26.0 - css-loader: 3.6.0_webpack@4.46.0 - express: 4.18.2 - file-loader: 6.2.0_webpack@4.46.0 - find-up: 5.0.0 - fs-extra: 9.1.0 - html-webpack-plugin: 4.5.2_webpack@4.46.0 - node-fetch: 2.6.7 - pnp-webpack-plugin: 1.6.4_typescript@4.4.4 - react: 16.14.0 - react-dom: 16.14.0_react@16.14.0 - read-pkg-up: 7.0.1 - regenerator-runtime: 0.13.10 - resolve-from: 5.0.0 - style-loader: 1.3.0_webpack@4.46.0 - telejson: 6.0.8 - terser-webpack-plugin: 4.2.3_webpack@4.46.0 - ts-dedent: 2.2.0 - typescript: 4.4.4 - url-loader: 4.1.1_lit45vopotvaqup7lrvlnvtxwy - util-deprecate: 1.0.2 - webpack: 4.46.0 - webpack-dev-middleware: 3.7.3_webpack@4.46.0 - webpack-virtual-modules: 0.2.2 - transitivePeerDependencies: - - bluebird - - encoding - - eslint - - supports-color - - vue-template-compiler - - webpack-cli - - webpack-command - dev: true - /@storybook/manager-webpack4/6.5.13_u5cwnb36e3nipolzgtjnnpepdu: resolution: {integrity: sha512-pURzS5W3XM0F7bCBWzpl7TRsuy+OXFwLXiWLaexuvo0POZe31Ueo2A1R4rx3MT5Iee8O9mYvG2XTmvK9MlLefQ==} peerDependencies: @@ -6443,7 +6074,7 @@ packages: core-js: 3.26.0 dev: true - /@storybook/preact/6.5.13_q57tjbu375p52k2lkxkownwouu: + /@storybook/preact/6.5.13_xa5zyoe4qu34opzfrw5imxak3u: resolution: {integrity: sha512-5/ufRgxh5VypFcOeIBQMg/AqZQ2+KfUw4Glo9HU75dbIe/kYqSnN3+5SEv8J6ykxHHtUWcmnILS1r7/I5R7j/w==} engines: {node: '>=10.13.0'} hasBin: true @@ -6454,8 +6085,8 @@ packages: '@babel/core': 7.18.9 '@babel/plugin-transform-react-jsx': 7.19.0_@babel+core@7.18.9 '@storybook/addons': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty - '@storybook/core': 6.5.13_ujfskrypehrywuobbsgnsb3724 - '@storybook/core-common': 6.5.13_oj3zznhuofsh7mvlmigrvm3x7y + '@storybook/core': 6.5.13_cadditq4xyv3neitvabz3hzhjy + '@storybook/core-common': 6.5.13_u5cwnb36e3nipolzgtjnnpepdu '@storybook/csf': 0.0.2--canary.4566f4d.1 '@storybook/store': 6.5.13_wcqkhtmu7mswc6yz4uyexck3ty '@types/node': 16.18.0 @@ -6778,33 +6409,6 @@ packages: util-deprecate: 1.0.2 dev: true - /@storybook/telemetry/6.5.13_oj3zznhuofsh7mvlmigrvm3x7y: - resolution: {integrity: sha512-PFJEfGbunmfFWabD3rdCF8EHH+45578OHOkMPpXJjqXl94vPQxUH2XTVKQgEQJbYrgX0Vx9Z4tSkdMHuzYDbWQ==} - dependencies: - '@storybook/client-logger': 6.5.13 - '@storybook/core-common': 6.5.13_oj3zznhuofsh7mvlmigrvm3x7y - chalk: 4.1.2 - core-js: 3.26.0 - detect-package-manager: 2.0.1 - fetch-retry: 5.0.3 - fs-extra: 9.1.0 - global: 4.4.0 - isomorphic-unfetch: 3.1.0 - nanoid: 3.3.4 - read-pkg-up: 7.0.1 - regenerator-runtime: 0.13.10 - transitivePeerDependencies: - - encoding - - eslint - - react - - react-dom - - supports-color - - typescript - - vue-template-compiler - - webpack-cli - - webpack-command - dev: true - /@storybook/telemetry/6.5.13_u5cwnb36e3nipolzgtjnnpepdu: resolution: {integrity: sha512-PFJEfGbunmfFWabD3rdCF8EHH+45578OHOkMPpXJjqXl94vPQxUH2XTVKQgEQJbYrgX0Vx9Z4tSkdMHuzYDbWQ==} dependencies: @@ -7212,6 +6816,10 @@ packages: resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==} dev: true + /@types/mocha/10.0.1: + resolution: {integrity: sha512-/fvYntiO1GeICvqbQ3doGDIP97vWmvFt83GKguJ6prmQM2iXZfFcq6YE8KteFyRtX2/h5Hf91BYvPodJKFYv5Q==} + dev: true + /@types/mocha/8.2.3: resolution: {integrity: sha512-ekGvFhFgrc2zYQoX4JeZPmVzZxw6Dtllga7iGHzfbYIYkAMUx/sAFP2GdFpLff+vdHXu5fl7WX9AT+TtqYcsyw==} dev: true @@ -7235,6 +6843,10 @@ packages: resolution: {integrity: sha512-LqYqYzYvnbCaQfLAwRt0zboqnsViwhZm+vjaMSqcfN36vulAg7Pt0T83q4WZO2YOBw3XdyHi8cQ88H22zmULOA==} dev: true + /@types/node/18.11.14: + resolution: {integrity: sha512-0KXV57tENYmmJMl+FekeW9V3O/rlcqGQQJ/hNh9r8pKIj304pskWuEd8fCyNT86g/TpO0gcOTiLzsHLEURFMIQ==} + dev: true + /@types/node/18.11.5: resolution: {integrity: sha512-3JRwhbjI+cHLAkUorhf8RnqUbFXajvzX4q6fMn5JwkgtuwfYtRQYI3u4V92vI6NJuTsbBQWWh3RZjFsuevyMGQ==} @@ -7438,32 +7050,6 @@ packages: - supports-color dev: true - /@typescript-eslint/eslint-plugin/4.33.0_zrqxgwgitu7trrjeml3nqco3jq: - resolution: {integrity: sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg==} - engines: {node: ^10.12.0 || >=12.0.0} - peerDependencies: - '@typescript-eslint/parser': ^4.0.0 - eslint: ^5.0.0 || ^6.0.0 || ^7.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/experimental-utils': 4.33.0_wnilx7boviscikmvsfkd6ljepe - '@typescript-eslint/parser': 4.33.0_wnilx7boviscikmvsfkd6ljepe - '@typescript-eslint/scope-manager': 4.33.0 - debug: 4.3.4 - eslint: 7.32.0 - functional-red-black-tree: 1.0.1 - ignore: 5.2.0 - regexpp: 3.2.0 - semver: 7.3.8 - tsutils: 3.21.0_typescript@4.4.4 - typescript: 4.4.4 - transitivePeerDependencies: - - supports-color - dev: true - /@typescript-eslint/eslint-plugin/5.41.0_2dmizcyfdgb4npqs6z4fehioli: resolution: {integrity: sha512-DXUS22Y57/LAFSg3x7Vi6RNAuLpTXwxB9S2nIA7msBb/Zt8p7XqMwdpdc1IU7CkOQUPgAqR5fWvxuKCbneKGmA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -7533,24 +7119,6 @@ packages: - typescript dev: true - /@typescript-eslint/experimental-utils/4.33.0_wnilx7boviscikmvsfkd6ljepe: - resolution: {integrity: sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q==} - engines: {node: ^10.12.0 || >=12.0.0} - peerDependencies: - eslint: '*' - dependencies: - '@types/json-schema': 7.0.11 - '@typescript-eslint/scope-manager': 4.33.0 - '@typescript-eslint/types': 4.33.0 - '@typescript-eslint/typescript-estree': 4.33.0_typescript@4.4.4 - eslint: 7.32.0 - eslint-scope: 5.1.1 - eslint-utils: 3.0.0_eslint@7.32.0 - transitivePeerDependencies: - - supports-color - - typescript - dev: true - /@typescript-eslint/experimental-utils/5.41.0_3rubbgt5ekhqrcgx4uwls3neim: resolution: {integrity: sha512-/qxT2Kd2q/A22JVIllvws4rvc00/3AT4rAo/0YgEN28y+HPhbJbk6X4+MAHEoZzpNyAOugIT7D/OLnKBW8FfhA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -7576,19 +7144,6 @@ packages: - typescript dev: true - /@typescript-eslint/experimental-utils/5.41.0_wnilx7boviscikmvsfkd6ljepe: - resolution: {integrity: sha512-/qxT2Kd2q/A22JVIllvws4rvc00/3AT4rAo/0YgEN28y+HPhbJbk6X4+MAHEoZzpNyAOugIT7D/OLnKBW8FfhA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - dependencies: - '@typescript-eslint/utils': 5.41.0_wnilx7boviscikmvsfkd6ljepe - eslint: 7.32.0 - transitivePeerDependencies: - - supports-color - - typescript - dev: true - /@typescript-eslint/parser/4.33.0_3rubbgt5ekhqrcgx4uwls3neim: resolution: {integrity: sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA==} engines: {node: ^10.12.0 || >=12.0.0} @@ -7609,26 +7164,6 @@ packages: - supports-color dev: true - /@typescript-eslint/parser/4.33.0_wnilx7boviscikmvsfkd6ljepe: - resolution: {integrity: sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA==} - engines: {node: ^10.12.0 || >=12.0.0} - peerDependencies: - eslint: ^5.0.0 || ^6.0.0 || ^7.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/scope-manager': 4.33.0 - '@typescript-eslint/types': 4.33.0 - '@typescript-eslint/typescript-estree': 4.33.0_typescript@4.4.4 - debug: 4.3.4 - eslint: 7.32.0 - typescript: 4.4.4 - transitivePeerDependencies: - - supports-color - dev: true - /@typescript-eslint/parser/5.41.0_typescript@4.8.4: resolution: {integrity: sha512-HQVfix4+RL5YRWZboMD1pUfFN8MpRH4laziWkkAzyO1fvNOY/uinZcvo3QiFJVS/siNHupV8E5+xSwQZrl6PZA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -7733,27 +7268,6 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /@typescript-eslint/typescript-estree/4.33.0_typescript@4.4.4: - resolution: {integrity: sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA==} - engines: {node: ^10.12.0 || >=12.0.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/types': 4.33.0 - '@typescript-eslint/visitor-keys': 4.33.0 - debug: 4.3.4 - globby: 11.1.0 - is-glob: 4.0.3 - semver: 7.3.8 - tsutils: 3.21.0_typescript@4.4.4 - typescript: 4.4.4 - transitivePeerDependencies: - - supports-color - dev: true - /@typescript-eslint/typescript-estree/4.33.0_typescript@4.8.4: resolution: {integrity: sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA==} engines: {node: ^10.12.0 || >=12.0.0} @@ -7775,27 +7289,6 @@ packages: - supports-color dev: true - /@typescript-eslint/typescript-estree/5.41.0_typescript@4.4.4: - resolution: {integrity: sha512-SlzFYRwFSvswzDSQ/zPkIWcHv8O5y42YUskko9c4ki+fV6HATsTODUPbRbcGDFYP86gaJL5xohUEytvyNNcXWg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/types': 5.41.0 - '@typescript-eslint/visitor-keys': 5.41.0 - debug: 4.3.4 - globby: 11.1.0 - is-glob: 4.0.3 - semver: 7.3.8 - tsutils: 3.21.0_typescript@4.4.4 - typescript: 4.4.4 - transitivePeerDependencies: - - supports-color - dev: true - /@typescript-eslint/typescript-estree/5.41.0_typescript@4.8.4: resolution: {integrity: sha512-SlzFYRwFSvswzDSQ/zPkIWcHv8O5y42YUskko9c4ki+fV6HATsTODUPbRbcGDFYP86gaJL5xohUEytvyNNcXWg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -7856,26 +7349,6 @@ packages: - typescript dev: true - /@typescript-eslint/utils/5.41.0_wnilx7boviscikmvsfkd6ljepe: - resolution: {integrity: sha512-QlvfwaN9jaMga9EBazQ+5DDx/4sAdqDkcs05AsQHMaopluVCUyu1bTRUVKzXbgjDlrRAQrYVoi/sXJ9fmG+KLQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - dependencies: - '@types/json-schema': 7.0.11 - '@types/semver': 7.3.12 - '@typescript-eslint/scope-manager': 5.41.0 - '@typescript-eslint/types': 5.41.0 - '@typescript-eslint/typescript-estree': 5.41.0_typescript@4.4.4 - eslint: 7.32.0 - eslint-scope: 5.1.1 - eslint-utils: 3.0.0_eslint@7.32.0 - semver: 7.3.8 - transitivePeerDependencies: - - supports-color - - typescript - dev: true - /@typescript-eslint/utils/5.41.0_wyqvi574yv7oiwfeinomdzmc3m: resolution: {integrity: sha512-QlvfwaN9jaMga9EBazQ+5DDx/4sAdqDkcs05AsQHMaopluVCUyu1bTRUVKzXbgjDlrRAQrYVoi/sXJ9fmG+KLQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -8715,6 +8188,10 @@ packages: resolution: {integrity: sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==} dev: true + /async_hooks/1.0.0: + resolution: {integrity: sha512-t4BSJgx48V3e7U6Ll3/WOUNmxIRPzmPdxVfgbyzcnRItEnn4iKp4F//b0sV3L9hzbdr5qxWdNWzOF7t+rjYSfA==} + dev: true + /asynckit/0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} @@ -8916,6 +8393,16 @@ packages: - debug dev: true + /axios/1.2.1: + resolution: {integrity: sha512-I88cFiGu9ryt/tfVEi4kX2SITsvDddTajXTOFmt2uK1ZVA8LytjtdeyefdQWEf5PU8w+4SSJDoYnggflB5tW4A==} + dependencies: + follow-redirects: 1.15.2 + form-data: 4.0.0 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + dev: true + /axobject-query/2.2.0: resolution: {integrity: sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==} dev: true @@ -12488,28 +11975,6 @@ packages: eslint-plugin-import: 2.26.0_c2flhriocdzler6lrwbyxxyoca dev: true - /eslint-config-preact/1.3.0_55vw575o5aj4h37h7cossdtfje: - resolution: {integrity: sha512-yHYXg5qNzEJd3D/30AmsIW0W8MuY858KpApXp7xxBF08IYUljSKCOqMx+dVucXHQnAm7+11wOnMkgVHIBAechw==} - peerDependencies: - eslint: 6.x || 7.x || 8.x - dependencies: - '@babel/core': 7.18.9 - '@babel/eslint-parser': 7.19.1_o5peei4wpze5egwf42u76kwdva - '@babel/plugin-syntax-class-properties': 7.12.13_@babel+core@7.18.9 - '@babel/plugin-syntax-decorators': 7.19.0_@babel+core@7.18.9 - '@babel/plugin-syntax-jsx': 7.18.6_@babel+core@7.18.9 - eslint: 7.32.0 - eslint-plugin-compat: 4.0.2_eslint@7.32.0 - eslint-plugin-jest: 25.7.0_55vw575o5aj4h37h7cossdtfje - eslint-plugin-react: 7.31.10_eslint@7.32.0 - eslint-plugin-react-hooks: 4.6.0_eslint@7.32.0 - transitivePeerDependencies: - - '@typescript-eslint/eslint-plugin' - - jest - - supports-color - - typescript - dev: true - /eslint-config-preact/1.3.0_nxlzr75jbqkso2fds5zjovs2ii: resolution: {integrity: sha512-yHYXg5qNzEJd3D/30AmsIW0W8MuY858KpApXp7xxBF08IYUljSKCOqMx+dVucXHQnAm7+11wOnMkgVHIBAechw==} peerDependencies: @@ -12672,28 +12137,6 @@ packages: - supports-color dev: true - /eslint-plugin-jest/25.7.0_55vw575o5aj4h37h7cossdtfje: - resolution: {integrity: sha512-PWLUEXeeF7C9QGKqvdSbzLOiLTx+bno7/HC9eefePfEb257QFHg7ye3dh80AZVkaa/RQsBB1Q/ORQvg2X7F0NQ==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - peerDependencies: - '@typescript-eslint/eslint-plugin': ^4.0.0 || ^5.0.0 - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - jest: '*' - peerDependenciesMeta: - '@typescript-eslint/eslint-plugin': - optional: true - jest: - optional: true - dependencies: - '@typescript-eslint/eslint-plugin': 4.33.0_zrqxgwgitu7trrjeml3nqco3jq - '@typescript-eslint/experimental-utils': 5.41.0_wnilx7boviscikmvsfkd6ljepe - eslint: 7.32.0 - jest: 26.6.3 - transitivePeerDependencies: - - supports-color - - typescript - dev: true - /eslint-plugin-jest/25.7.0_nxlzr75jbqkso2fds5zjovs2ii: resolution: {integrity: sha512-PWLUEXeeF7C9QGKqvdSbzLOiLTx+bno7/HC9eefePfEb257QFHg7ye3dh80AZVkaa/RQsBB1Q/ORQvg2X7F0NQ==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} @@ -13661,34 +13104,6 @@ packages: - supports-color dev: true - /fork-ts-checker-webpack-plugin/4.1.6_bbqhrndznz6a4k7d23h2kkrexi: - resolution: {integrity: sha512-DUxuQaKoqfNne8iikd14SAkh5uw4+8vNifp6gmA73yYNS6ywLIWSLD/n/mBzHQRpW3J7rbATEakmiA8JvkTyZw==} - engines: {node: '>=6.11.5', yarn: '>=1.0.0'} - peerDependencies: - eslint: '>= 6' - typescript: '>= 2.7' - vue-template-compiler: '*' - webpack: '>= 4' - peerDependenciesMeta: - eslint: - optional: true - vue-template-compiler: - optional: true - dependencies: - '@babel/code-frame': 7.18.6 - chalk: 2.4.2 - eslint: 7.32.0 - micromatch: 3.1.10 - minimatch: 3.1.2 - semver: 5.7.1 - tapable: 1.1.3 - typescript: 4.4.4 - webpack: 4.46.0 - worker-rpc: 0.1.1 - transitivePeerDependencies: - - supports-color - dev: true - /fork-ts-checker-webpack-plugin/4.1.6_gplzhsecki363wzvnzp4wfrwvi: resolution: {integrity: sha512-DUxuQaKoqfNne8iikd14SAkh5uw4+8vNifp6gmA73yYNS6ywLIWSLD/n/mBzHQRpW3J7rbATEakmiA8JvkTyZw==} engines: {node: '>=6.11.5', yarn: '>=1.0.0'} @@ -13776,38 +13191,6 @@ packages: webpack: 4.46.0 dev: true - /fork-ts-checker-webpack-plugin/6.5.2_bbqhrndznz6a4k7d23h2kkrexi: - resolution: {integrity: sha512-m5cUmF30xkZ7h4tWUgTAcEaKmUW7tfyUyTqNNOz7OxWJ0v1VWKTcOvH8FWHUwSjlW/356Ijc9vi3XfcPstpQKA==} - engines: {node: '>=10', yarn: '>=1.0.0'} - peerDependencies: - eslint: '>= 6' - typescript: '>= 2.7' - vue-template-compiler: '*' - webpack: '>= 4' - peerDependenciesMeta: - eslint: - optional: true - vue-template-compiler: - optional: true - dependencies: - '@babel/code-frame': 7.18.6 - '@types/json-schema': 7.0.11 - chalk: 4.1.2 - chokidar: 3.5.3 - cosmiconfig: 6.0.0 - deepmerge: 4.2.2 - eslint: 7.32.0 - fs-extra: 9.1.0 - glob: 7.2.3 - memfs: 3.4.7 - minimatch: 3.1.2 - schema-utils: 2.7.0 - semver: 7.3.8 - tapable: 1.1.3 - typescript: 4.4.4 - webpack: 4.46.0 - dev: true - /form-data/2.3.3: resolution: {integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==} engines: {node: '>= 0.12'} @@ -18326,15 +17709,6 @@ packages: resolution: {integrity: sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==} dev: true - /pnp-webpack-plugin/1.6.4_typescript@4.4.4: - resolution: {integrity: sha512-7Wjy+9E3WwLOEL30D+m8TSTF7qJJUJLONBnwQp0518siuMxUQUbgZwssaFX+QKlZkjHZcw/IpZCt/H0srrntSg==} - engines: {node: '>=6'} - dependencies: - ts-pnp: 1.2.0_typescript@4.4.4 - transitivePeerDependencies: - - typescript - dev: true - /pnp-webpack-plugin/1.6.4_typescript@4.8.4: resolution: {integrity: sha512-7Wjy+9E3WwLOEL30D+m8TSTF7qJJUJLONBnwQp0518siuMxUQUbgZwssaFX+QKlZkjHZcw/IpZCt/H0srrntSg==} engines: {node: '>=6'} @@ -21626,7 +21000,6 @@ packages: resolution: {integrity: sha512-dkghQrOl2ORX9HYrMDtPa7LTVHJjCTeZoB1dqTbnnEDlSvN8JEKpYIYurDfvbQFUUS8Cg8PceFVZNkW0KNNYPw==} peerDependencies: react: ^16.11.0 || ^17.0.0 || ^18.0.0 - dev: false /swr/1.3.0_@preact+compat@17.1.2: resolution: {integrity: sha512-dkghQrOl2ORX9HYrMDtPa7LTVHJjCTeZoB1dqTbnnEDlSvN8JEKpYIYurDfvbQFUUS8Cg8PceFVZNkW0KNNYPw==} @@ -22041,18 +21414,6 @@ packages: tslib: 2.4.1 dev: true - /ts-pnp/1.2.0_typescript@4.4.4: - resolution: {integrity: sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw==} - engines: {node: '>=6'} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - typescript: 4.4.4 - dev: true - /ts-pnp/1.2.0_typescript@4.6.4: resolution: {integrity: sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw==} engines: {node: '>=6'} @@ -22085,16 +21446,6 @@ packages: resolution: {integrity: sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==} dev: true - /tsutils/3.21.0_typescript@4.4.4: - resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} - 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' - dependencies: - tslib: 1.14.1 - typescript: 4.4.4 - dev: true - /tsutils/3.21.0_typescript@4.8.4: resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} engines: {node: '>= 6'} @@ -22190,27 +21541,6 @@ packages: engines: {node: '>= 8'} dev: true - /typedoc/0.20.37_typescript@4.4.4: - resolution: {integrity: sha512-9+qDhdc4X00qTNOtii6QX2z7ndAeWVOso7w3MPSoSJdXlVhpwPfm1yEp4ooKuWA9fiQILR8FKkyjmeqa13hBbw==} - engines: {node: '>= 10.8.0'} - hasBin: true - peerDependencies: - typescript: 3.9.x || 4.0.x || 4.1.x || 4.2.x - dependencies: - colors: 1.4.0 - fs-extra: 9.1.0 - handlebars: 4.7.7 - lodash: 4.17.21 - lunr: 2.3.9 - marked: 2.0.7 - minimatch: 3.1.2 - progress: 2.0.3 - shelljs: 0.8.5 - shiki: 0.9.15 - typedoc-default-themes: 0.12.10 - typescript: 4.4.4 - dev: true - /typedoc/0.20.37_typescript@4.8.4: resolution: {integrity: sha512-9+qDhdc4X00qTNOtii6QX2z7ndAeWVOso7w3MPSoSJdXlVhpwPfm1yEp4ooKuWA9fiQILR8FKkyjmeqa13hBbw==} engines: {node: '>= 10.8.0'} @@ -22246,12 +21576,6 @@ packages: typescript: 4.8.4 dev: true - /typescript/4.4.4: - resolution: {integrity: sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==} - engines: {node: '>=4.2.0'} - hasBin: true - dev: true - /typescript/4.6.4: resolution: {integrity: sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==} engines: {node: '>=4.2.0'}