← Back to team overview

sts-sponsors team mailing list archive

[Merge] ~nickdv99/maas-site-manager:chore-allow-absolute-path-imports-MAASENG-1438 into maas-site-manager:main

 

Nick De Villiers has proposed merging ~nickdv99/maas-site-manager:chore-allow-absolute-path-imports-MAASENG-1438 into maas-site-manager:main.

Commit message:
chore: Allow absolute path imports and add rule preventing relative imports MAASENG-1438

Requested reviews:
  MAAS Committers (maas-committers)

For more details, see:
https://code.launchpad.net/~nickdv99/maas-site-manager/+git/site-manager/+merge/438613

## Done

- Added import resolver for typescript
- Modified ESLint config to support absolute path imports
- Added ESLint plugin to discourage relative imports (except for same folder imports, i.e. `./thing`)
- Changed all relative imports to absolute

## Fixes

Fixes https://warthogs.atlassian.net/browse/MAASENG-1438
-- 
Your team MAAS Committers is requested to review the proposed merge of ~nickdv99/maas-site-manager:chore-allow-absolute-path-imports-MAASENG-1438 into maas-site-manager:main.
diff --git a/frontend/.eslintrc.js b/frontend/.eslintrc.js
index 242261d..8aceff5 100644
--- a/frontend/.eslintrc.js
+++ b/frontend/.eslintrc.js
@@ -1,8 +1,11 @@
 module.exports = {
   root: true,
-  plugins: ["prettier"],
+  plugins: ["prettier", "no-relative-import-paths"],
   extends: [
     "react-app", // Use the recommended rules from CRA.
+    "plugin:import/errors",
+    "plugin:import/warnings",
+    "plugin:import/typescript",
     "eslint-config-prettier", // Ensure this is last in the list.
   ],
   parserOptions: {
@@ -14,11 +17,19 @@ module.exports = {
   },
   rules: {
     "prettier/prettier": "error",
+    "no-relative-import-paths/no-relative-import-paths": ["warn", { allowSameFolder: true, rootDir: "frontend/src" }],
   },
   settings: {
     react: {
       version: "detect",
     },
+    "import/resolver": {
+      typescript: {},
+      node: {
+        moduleDirectory: ["src/"],
+        extensions: [".js", ".jsx", ".ts", ".tsx"],
+      },
+    },
   },
   globals: {
     usabilla_live: false,
diff --git a/frontend/package.json b/frontend/package.json
index 5dbce87..74f087d 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -38,15 +38,18 @@
     "@types/pluralize": "0.0.29",
     "@types/react": "18.0.27",
     "@types/react-dom": "18.0.10",
+    "@typescript-eslint/parser": "^5.54.1",
     "@vitejs/plugin-react-swc": "3.0.0",
     "chance": "1.1.10",
     "dotenv": "16.0.3",
     "eslint": "8.35.0",
     "eslint-config-prettier": "8.6.0",
     "eslint-config-react-app": "7.0.1",
+    "eslint-import-resolver-typescript": "^3.5.3",
     "eslint-plugin-cypress": "2.12.1",
     "eslint-plugin-jsx-a11y": "6.7.1",
     "eslint-plugin-no-only-tests": "3.1.0",
+    "eslint-plugin-no-relative-import-paths": "1.5.2",
     "eslint-plugin-prettier": "4.2.1",
     "eslint-plugin-react": "7.32.2",
     "fishery": "2.2.2",
@@ -61,6 +64,7 @@
     "typescript": "4.9.3",
     "unique-names-generator": "4.7.1",
     "vite": "4.1.0",
+    "vite-tsconfig-paths": "^4.0.5",
     "vitest": "0.28.5"
   },
   "msw": {
diff --git a/frontend/src/components/MainLayout/MainLayout.tsx b/frontend/src/components/MainLayout/MainLayout.tsx
index a7b67db..0948359 100644
--- a/frontend/src/components/MainLayout/MainLayout.tsx
+++ b/frontend/src/components/MainLayout/MainLayout.tsx
@@ -1,7 +1,7 @@
 import { Outlet } from "react-router-dom";
 
 import "./MainLayout.scss";
-import Navigation from "../Navigation";
+import Navigation from "components/Navigation";
 
 const MainLayout: React.FC = () => (
   <div className="l-application">
diff --git a/frontend/src/components/Navigation/Navigation.test.tsx b/frontend/src/components/Navigation/Navigation.test.tsx
index 3201cb9..d6b7fac 100644
--- a/frontend/src/components/Navigation/Navigation.test.tsx
+++ b/frontend/src/components/Navigation/Navigation.test.tsx
@@ -1,10 +1,10 @@
 import userEvent from "@testing-library/user-event";
 import { MemoryRouter } from "react-router-dom";
 
-import { render, screen } from "../../test-utils";
-
 import Navigation from "./Navigation";
 
+import { render, screen } from "test-utils";
+
 describe("Navigation", () => {
   it("displays navigation", () => {
     render(
diff --git a/frontend/src/components/Navigation/NavigationBanner/NavigationBanner.test.tsx b/frontend/src/components/Navigation/NavigationBanner/NavigationBanner.test.tsx
index 125be52..36f8842 100644
--- a/frontend/src/components/Navigation/NavigationBanner/NavigationBanner.test.tsx
+++ b/frontend/src/components/Navigation/NavigationBanner/NavigationBanner.test.tsx
@@ -1,9 +1,9 @@
 import { BrowserRouter } from "react-router-dom";
 
-import { screen, render } from "../../../test-utils";
-
 import NavigationBanner from "./NavigationBanner";
 
+import { screen, render } from "test-utils";
+
 describe("Navigation Banner", () => {
   it("displays a link to the homepage", () => {
     render(
diff --git a/frontend/src/components/Navigation/NavigationBanner/NavigationBanner.tsx b/frontend/src/components/Navigation/NavigationBanner/NavigationBanner.tsx
index f7a833d..1a663ba 100644
--- a/frontend/src/components/Navigation/NavigationBanner/NavigationBanner.tsx
+++ b/frontend/src/components/Navigation/NavigationBanner/NavigationBanner.tsx
@@ -1,6 +1,6 @@
 import { Link, useLocation } from "react-router-dom";
 
-import { isSelected } from "../utils";
+import { isSelected } from "components/Navigation/utils";
 
 const NavigationBanner = ({ children }: { children?: React.ReactNode }): JSX.Element => {
   const location = useLocation();
diff --git a/frontend/src/components/Navigation/NavigationItem/NavigationItem.tsx b/frontend/src/components/Navigation/NavigationItem/NavigationItem.tsx
index 242df50..eae5395 100644
--- a/frontend/src/components/Navigation/NavigationItem/NavigationItem.tsx
+++ b/frontend/src/components/Navigation/NavigationItem/NavigationItem.tsx
@@ -3,8 +3,8 @@ import { useId } from "react";
 import { Icon } from "@canonical/react-components";
 import { Link } from "react-router-dom";
 
-import type { NavLink } from "../types";
-import { isSelected } from "../utils";
+import type { NavLink } from "components/Navigation/types";
+import { isSelected } from "components/Navigation/utils";
 
 type Props = {
   navLink: NavLink;
diff --git a/frontend/src/components/Placeholder/Placeholder.test.tsx b/frontend/src/components/Placeholder/Placeholder.test.tsx
index 6f19223..3288207 100644
--- a/frontend/src/components/Placeholder/Placeholder.test.tsx
+++ b/frontend/src/components/Placeholder/Placeholder.test.tsx
@@ -1,7 +1,7 @@
-import { render, screen } from "../../test-utils";
-
 import Placeholder from "./Placeholder";
 
+import { render, screen } from "test-utils";
+
 describe("Placeholder", () => {
   it("always hides placeholder text passed as a text prop", () => {
     const { rerender } = render(<Placeholder text="Placeholder text" />);
diff --git a/frontend/src/components/SitesList/SitesList.test.tsx b/frontend/src/components/SitesList/SitesList.test.tsx
index 56dd9f7..1dbf7aa 100644
--- a/frontend/src/components/SitesList/SitesList.test.tsx
+++ b/frontend/src/components/SitesList/SitesList.test.tsx
@@ -1,11 +1,11 @@
-import urls from "../../api/urls";
-import { siteFactory } from "../../mocks/factories";
-import { createMockSitesResolver } from "../../mocks/resolvers";
-import { createMockGetServer } from "../../mocks/server";
-import { render, screen, waitFor, within } from "../../test-utils";
-
 import SitesList from "./SitesList";
 
+import urls from "api/urls";
+import { siteFactory } from "mocks/factories";
+import { createMockSitesResolver } from "mocks/resolvers";
+import { createMockGetServer } from "mocks/server";
+import { render, screen, waitFor, within } from "test-utils";
+
 const sites = siteFactory.buildList(2);
 const mockServer = createMockGetServer(urls.sites, createMockSitesResolver(sites));
 
diff --git a/frontend/src/components/SitesList/SitesList.tsx b/frontend/src/components/SitesList/SitesList.tsx
index 1b520ea..66b8f63 100644
--- a/frontend/src/components/SitesList/SitesList.tsx
+++ b/frontend/src/components/SitesList/SitesList.tsx
@@ -2,10 +2,10 @@ import { useState } from "react";
 
 import { Pagination } from "@canonical/react-components";
 
-import { useSitesQuery } from "../../hooks/api";
-
 import SitesTable from "./components/SitesTable";
 
+import { useSitesQuery } from "hooks/api";
+
 const DEFAULT_PAGE_SIZE = 50;
 
 const SitesList = () => {
diff --git a/frontend/src/components/SitesList/components/SitesCount.test.tsx b/frontend/src/components/SitesList/components/SitesCount.test.tsx
index defa9e4..4b9747c 100644
--- a/frontend/src/components/SitesList/components/SitesCount.test.tsx
+++ b/frontend/src/components/SitesList/components/SitesCount.test.tsx
@@ -1,8 +1,8 @@
-import { siteFactory } from "../../../mocks/factories";
-import { render, screen } from "../../../test-utils";
-
 import SitesCount from "./SitesCount";
 
+import { siteFactory } from "mocks/factories";
+import { render, screen } from "test-utils";
+
 it("displays plural sites count", () => {
   const total = 11;
   const items = siteFactory.buildList(total);
diff --git a/frontend/src/components/SitesList/components/SitesCount.tsx b/frontend/src/components/SitesList/components/SitesCount.tsx
index 431dacf..d4038ab 100644
--- a/frontend/src/components/SitesList/components/SitesCount.tsx
+++ b/frontend/src/components/SitesList/components/SitesCount.tsx
@@ -1,7 +1,7 @@
 import pluralize from "pluralize";
 
-import type { UseSitesQueryResult } from "../../../hooks/api";
-import Placeholder from "../../Placeholder";
+import Placeholder from "components/Placeholder";
+import type { UseSitesQueryResult } from "hooks/api";
 
 const SitesCount = ({ data, isLoading }: Pick<UseSitesQueryResult, "data" | "isLoading">) =>
   isLoading ? (
diff --git a/frontend/src/components/SitesList/components/SitesTable.test.tsx b/frontend/src/components/SitesList/components/SitesTable.test.tsx
index 95f7c0b..3820733 100644
--- a/frontend/src/components/SitesList/components/SitesTable.test.tsx
+++ b/frontend/src/components/SitesList/components/SitesTable.test.tsx
@@ -1,11 +1,11 @@
-import timezoneMock from "timezone-mock";
+import * as timezoneMock from "timezone-mock";
 import { vi } from "vitest";
 
-import { siteFactory } from "../../../mocks/factories";
-import { render, screen, within } from "../../../test-utils";
-
 import SitesTable from "./SitesTable";
 
+import { siteFactory } from "mocks/factories";
+import { render, screen, within } from "test-utils";
+
 beforeEach(() => {
   vi.useFakeTimers();
   timezoneMock.register("Etc/GMT");
diff --git a/frontend/src/components/SitesList/components/SitesTable.tsx b/frontend/src/components/SitesList/components/SitesTable.tsx
index ebaf1bb..520a551 100644
--- a/frontend/src/components/SitesList/components/SitesTable.tsx
+++ b/frontend/src/components/SitesList/components/SitesTable.tsx
@@ -14,12 +14,13 @@ import { utcToZonedTime } from "date-fns-tz";
 import pick from "lodash/fp/pick";
 import useLocalStorageState from "use-local-storage-state";
 
-import type { SitesQueryResult } from "../../../api/types";
-import type { UseSitesQueryResult } from "../../../hooks/api";
-import { getCountryName } from "../../../utils";
+import SitesTableControls from "./SitesTableControls";
+
+import type { SitesQueryResult } from "api/types";
+import type { UseSitesQueryResult } from "hooks/api";
+import { getCountryName } from "utils";
 
 import "./SitesTable.scss";
-import SitesTableControls from "./SitesTableControls";
 
 const createAccessor =
   <T, K extends keyof T>(keys: K[] | K) =>
diff --git a/frontend/src/components/SitesList/components/SitesTableControls.test.tsx b/frontend/src/components/SitesList/components/SitesTableControls.test.tsx
index 46a13d6..1ae29f9 100644
--- a/frontend/src/components/SitesList/components/SitesTableControls.test.tsx
+++ b/frontend/src/components/SitesList/components/SitesTableControls.test.tsx
@@ -1,7 +1,7 @@
-import { render, screen } from "../../../test-utils";
-
 import SitesTableControls from "./SitesTableControls";
 
+import { render, screen } from "test-utils";
+
 it("displays correct total number of sites", () => {
   render(<SitesTableControls allColumns={[]} data={{ items: [], total: 3, page: 1, size: 0 }} isLoading={false} />);
 
diff --git a/frontend/src/components/SitesList/components/SitesTableControls.tsx b/frontend/src/components/SitesList/components/SitesTableControls.tsx
index 255b698..7e9261c 100644
--- a/frontend/src/components/SitesList/components/SitesTableControls.tsx
+++ b/frontend/src/components/SitesList/components/SitesTableControls.tsx
@@ -2,12 +2,12 @@ import { useState } from "react";
 
 import { Row, Col, SearchBox } from "@canonical/react-components";
 
-import type { UseSitesQueryResult } from "../../../hooks/api";
-
 import ColumnsVisibilityControl from "./ColumnsVisibilityControl";
 import SitesCount from "./SitesCount";
 import type { SitesColumn } from "./SitesTable";
 
+import type { UseSitesQueryResult } from "hooks/api";
+
 const SitesTableControls = ({
   data,
   isLoading,
diff --git a/frontend/src/hooks/api.test.ts b/frontend/src/hooks/api.test.ts
index 736b168..a7002fe 100644
--- a/frontend/src/hooks/api.test.ts
+++ b/frontend/src/hooks/api.test.ts
@@ -1,13 +1,13 @@
 import { renderHook, waitFor } from "@testing-library/react";
 
-import urls from "../api/urls";
-import { siteFactory } from "../mocks/factories";
-import { createMockSitesResolver } from "../mocks/resolvers";
-import { createMockGetServer } from "../mocks/server";
-import { Providers } from "../test-utils";
-
 import { useSitesQuery } from "./api";
 
+import urls from "api/urls";
+import { siteFactory } from "mocks/factories";
+import { createMockSitesResolver } from "mocks/resolvers";
+import { createMockGetServer } from "mocks/server";
+import { Providers } from "test-utils";
+
 const sitesData = siteFactory.buildList(2);
 const mockServer = createMockGetServer(urls.sites, createMockSitesResolver(sitesData));
 
diff --git a/frontend/src/hooks/api.ts b/frontend/src/hooks/api.ts
index ccf0b4d..2a5d55d 100644
--- a/frontend/src/hooks/api.ts
+++ b/frontend/src/hooks/api.ts
@@ -1,8 +1,8 @@
 import { useQuery } from "@tanstack/react-query";
 
-import type { GetSitesQueryParams } from "../api/handlers";
-import { getSites } from "../api/handlers";
-import type { SitesQueryResult } from "../api/types";
+import type { GetSitesQueryParams } from "api/handlers";
+import { getSites } from "api/handlers";
+import type { SitesQueryResult } from "api/types";
 
 export type UseSitesQueryResult = ReturnType<typeof useSitesQuery>;
 
diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx
index 3ab4152..ba02364 100644
--- a/frontend/src/main.tsx
+++ b/frontend/src/main.tsx
@@ -1,6 +1,6 @@
-import React from "react";
+import * as React from "react";
 
-import ReactDOM from "react-dom/client";
+import * as ReactDOM from "react-dom/client";
 
 import App from "./App";
 
diff --git a/frontend/src/mocks/browser.ts b/frontend/src/mocks/browser.ts
index b2b9266..b9da17b 100644
--- a/frontend/src/mocks/browser.ts
+++ b/frontend/src/mocks/browser.ts
@@ -1,7 +1,7 @@
 import { setupWorker, rest } from "msw";
 
-import urls from "../api/urls";
-
 import { createMockSitesResolver } from "./resolvers";
 
+import urls from "api/urls";
+
 export const worker = setupWorker(rest.get(urls.sites, createMockSitesResolver()));
diff --git a/frontend/src/mocks/factories.ts b/frontend/src/mocks/factories.ts
index db2d34b..9703559 100644
--- a/frontend/src/mocks/factories.ts
+++ b/frontend/src/mocks/factories.ts
@@ -2,7 +2,7 @@ import Chance from "chance";
 import { Factory } from "fishery";
 import { uniqueNamesGenerator, adjectives, colors, animals } from "unique-names-generator";
 
-import type { Site } from "../api/types";
+import type { Site } from "api/types";
 
 const connections: Site["connection"][] = ["stable", "lost", "stale", "unstable"];
 
diff --git a/frontend/src/mocks/resolvers.ts b/frontend/src/mocks/resolvers.ts
index 76207f7..b76d7c4 100644
--- a/frontend/src/mocks/resolvers.ts
+++ b/frontend/src/mocks/resolvers.ts
@@ -1,9 +1,9 @@
 import type { RestRequest, restContext, ResponseResolver } from "msw";
 
-import type { GetSitesQueryParams } from "../api/handlers";
-
 import { siteFactory } from "./factories";
 
+import type { GetSitesQueryParams } from "api/handlers";
+
 export const sitesList = siteFactory.buildList(155);
 
 type SitesResponseResolver = ResponseResolver<RestRequest<never, GetSitesQueryParams>, typeof restContext>;
diff --git a/frontend/src/mocks/server.ts b/frontend/src/mocks/server.ts
index 52577dd..6f01008 100644
--- a/frontend/src/mocks/server.ts
+++ b/frontend/src/mocks/server.ts
@@ -2,10 +2,10 @@
 import { rest } from "msw";
 import { setupServer } from "msw/node";
 
-import urls from "../api/urls";
-
 import { createMockSitesResolver } from "./resolvers";
 
+import urls from "api/urls";
+
 const createMockGetServer = (endpoint: string, resolver: ReturnType<typeof createMockSitesResolver>) =>
   setupServer(rest.get(endpoint, resolver));
 
diff --git a/frontend/src/pages/sites.tsx b/frontend/src/pages/sites.tsx
index 895b383..47eb174 100644
--- a/frontend/src/pages/sites.tsx
+++ b/frontend/src/pages/sites.tsx
@@ -1,4 +1,4 @@
-import SitesList from "../components/SitesList";
+import SitesList from "components/SitesList";
 
 const Sites: React.FC = () => <SitesList />;
 
diff --git a/frontend/src/test-utils.tsx b/frontend/src/test-utils.tsx
index 918031f..7d3514e 100644
--- a/frontend/src/test-utils.tsx
+++ b/frontend/src/test-utils.tsx
@@ -1,5 +1,5 @@
 import type { ReactElement } from "react";
-import React from "react";
+import * as React from "react";
 
 import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
 import type { RenderOptions, RenderResult } from "@testing-library/react";
diff --git a/frontend/src/utils.ts b/frontend/src/utils.ts
index 4849540..222ad2a 100644
--- a/frontend/src/utils.ts
+++ b/frontend/src/utils.ts
@@ -1,4 +1,5 @@
-import countries, { getName } from "i18n-iso-countries";
+import * as countries from "i18n-iso-countries";
+import { getName } from "i18n-iso-countries";
 import en from "i18n-iso-countries/langs/en.json";
 
 if (typeof window !== "undefined") {
diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json
index 3d0a51a..1a51092 100644
--- a/frontend/tsconfig.json
+++ b/frontend/tsconfig.json
@@ -1,5 +1,6 @@
 {
   "compilerOptions": {
+    "baseUrl": "./src",
     "target": "ESNext",
     "useDefineForClassFields": true,
     "lib": ["DOM", "DOM.Iterable", "ESNext"],
diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts
index ba6e7f7..ef1cc85 100644
--- a/frontend/vite.config.ts
+++ b/frontend/vite.config.ts
@@ -1,12 +1,13 @@
 import { defineConfig } from "vite";
 import react from "@vitejs/plugin-react-swc";
 import dotenv from "dotenv";
+import tsconfigPaths from "vite-tsconfig-paths";
 
 dotenv.config({ path: "../.env" });
 
 // https://vitejs.dev/config/
 export default defineConfig({
-  plugins: [react()],
+  plugins: [react(), tsconfigPaths()],
   server: { port: Number(process.env.VITE_UI_PORT) },
   css: {
     preprocessorOptions: {
diff --git a/frontend/yarn.lock b/frontend/yarn.lock
index e583282..87f314f 100644
--- a/frontend/yarn.lock
+++ b/frontend/yarn.lock
@@ -1357,6 +1357,18 @@
   resolved "https://registry.yarnpkg.com/@open-draft/until/-/until-1.0.3.tgz#db9cc719191a62e7d9200f6e7bab21c5b848adca";
   integrity sha512-Aq58f5HiWdyDlFffbbSjAlv596h/cOnt2DO1w3DOC7OJ5EHs0hd/nycJfiu9RJbT6Yk6F1knnRRXNSpxoIVZ9Q==
 
+"@pkgr/utils@^2.3.1":
+  version "2.3.1"
+  resolved "https://registry.yarnpkg.com/@pkgr/utils/-/utils-2.3.1.tgz#0a9b06ffddee364d6642b3cd562ca76f55b34a03";
+  integrity sha512-wfzX8kc1PMyUILA+1Z/EqoE4UCXGy0iRGMhPwdfae1+f0OXlLqCk+By+aMzgJBzR9AzS4CDizioG6Ss1gvAFJw==
+  dependencies:
+    cross-spawn "^7.0.3"
+    is-glob "^4.0.3"
+    open "^8.4.0"
+    picocolors "^1.0.0"
+    tiny-glob "^0.2.9"
+    tslib "^2.4.0"
+
 "@playwright/test@1.31.1":
   version "1.31.1"
   resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.31.1.tgz#39d6873dc46af135f12451d79707db7d1357455d";
@@ -1511,7 +1523,7 @@
     "@testing-library/dom" "^8.5.0"
     "@types/react-dom" "^18.0.0"
 
-"@testing-library/user-event@^14.4.3":
+"@testing-library/user-event@14.4.3":
   version "14.4.3"
   resolved "https://registry.yarnpkg.com/@testing-library/user-event/-/user-event-14.4.3.tgz#af975e367743fa91989cd666666aec31a8f50591";
   integrity sha512-kCUc5MEwaEMakkO5x7aoD+DLi02ehmEM2QCGWvNqAS1dV/fAvORWEjnjsEIvml59M7Y5kCkWN6fCCyPOe8OL6Q==
@@ -1795,6 +1807,16 @@
     "@typescript-eslint/typescript-estree" "5.54.0"
     debug "^4.3.4"
 
+"@typescript-eslint/parser@^5.54.1":
+  version "5.54.1"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.54.1.tgz#05761d7f777ef1c37c971d3af6631715099b084c";
+  integrity sha512-8zaIXJp/nG9Ff9vQNh7TI+C3nA6q6iIsGJ4B4L6MhZ7mHnTMR4YP5vp2xydmFXIy8rpyIVbNAG44871LMt6ujg==
+  dependencies:
+    "@typescript-eslint/scope-manager" "5.54.1"
+    "@typescript-eslint/types" "5.54.1"
+    "@typescript-eslint/typescript-estree" "5.54.1"
+    debug "^4.3.4"
+
 "@typescript-eslint/scope-manager@5.54.0":
   version "5.54.0"
   resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.54.0.tgz#74b28ac9a3fc8166f04e806c957adb8c1fd00536";
@@ -1803,6 +1825,14 @@
     "@typescript-eslint/types" "5.54.0"
     "@typescript-eslint/visitor-keys" "5.54.0"
 
+"@typescript-eslint/scope-manager@5.54.1":
+  version "5.54.1"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.54.1.tgz#6d864b4915741c608a58ce9912edf5a02bb58735";
+  integrity sha512-zWKuGliXxvuxyM71UA/EcPxaviw39dB2504LqAmFDjmkpO8qNLHcmzlh6pbHs1h/7YQ9bnsO8CCcYCSA8sykUg==
+  dependencies:
+    "@typescript-eslint/types" "5.54.1"
+    "@typescript-eslint/visitor-keys" "5.54.1"
+
 "@typescript-eslint/type-utils@5.54.0":
   version "5.54.0"
   resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.54.0.tgz#390717216eb61393a0cad2995da154b613ba7b26";
@@ -1818,6 +1848,11 @@
   resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.54.0.tgz#7d519df01f50739254d89378e0dcac504cab2740";
   integrity sha512-nExy+fDCBEgqblasfeE3aQ3NuafBUxZxgxXcYfzYRZFHdVvk5q60KhCSkG0noHgHRo/xQ/BOzURLZAafFpTkmQ==
 
+"@typescript-eslint/types@5.54.1":
+  version "5.54.1"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.54.1.tgz#29fbac29a716d0f08c62fe5de70c9b6735de215c";
+  integrity sha512-G9+1vVazrfAfbtmCapJX8jRo2E4MDXxgm/IMOF4oGh3kq7XuK3JRkOg6y2Qu1VsTRmWETyTkWt1wxy7X7/yLkw==
+
 "@typescript-eslint/typescript-estree@5.54.0":
   version "5.54.0"
   resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.54.0.tgz#f6f3440cabee8a43a0b25fa498213ebb61fdfe99";
@@ -1831,6 +1866,19 @@
     semver "^7.3.7"
     tsutils "^3.21.0"
 
+"@typescript-eslint/typescript-estree@5.54.1":
+  version "5.54.1"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.54.1.tgz#df7b6ae05fd8fef724a87afa7e2f57fa4a599be1";
+  integrity sha512-bjK5t+S6ffHnVwA0qRPTZrxKSaFYocwFIkZx5k7pvWfsB1I57pO/0M0Skatzzw1sCkjJ83AfGTL0oFIFiDX3bg==
+  dependencies:
+    "@typescript-eslint/types" "5.54.1"
+    "@typescript-eslint/visitor-keys" "5.54.1"
+    debug "^4.3.4"
+    globby "^11.1.0"
+    is-glob "^4.0.3"
+    semver "^7.3.7"
+    tsutils "^3.21.0"
+
 "@typescript-eslint/utils@5.54.0", "@typescript-eslint/utils@^5.43.0":
   version "5.54.0"
   resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.54.0.tgz#3db758aae078be7b54b8ea8ea4537ff6cd3fbc21";
@@ -1853,6 +1901,14 @@
     "@typescript-eslint/types" "5.54.0"
     eslint-visitor-keys "^3.3.0"
 
+"@typescript-eslint/visitor-keys@5.54.1":
+  version "5.54.1"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.54.1.tgz#d7a8a0f7181d6ac748f4d47b2306e0513b98bf8b";
+  integrity sha512-q8iSoHTgwCfgcRJ2l2x+xCbu8nBlRAlsQ33k24Adj8eoVBE0f8dUeI+bAa8F84Mv05UGbAx57g2zrRsYIooqQg==
+  dependencies:
+    "@typescript-eslint/types" "5.54.1"
+    eslint-visitor-keys "^3.3.0"
+
 "@vitejs/plugin-react-swc@3.0.0":
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/@vitejs/plugin-react-swc/-/plugin-react-swc-3.0.0.tgz#a0dbf235ae0fdd937a302901d1433dffdaa5cb3b";
@@ -2565,7 +2621,7 @@ cosmiconfig@^8.0.0:
     parse-json "^5.0.0"
     path-type "^4.0.0"
 
-cross-spawn@^7.0.2:
+cross-spawn@^7.0.2, cross-spawn@^7.0.3:
   version "7.0.3"
   resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6";
   integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
@@ -2699,6 +2755,11 @@ defaults@^1.0.3:
   dependencies:
     clone "^1.0.2"
 
+define-lazy-prop@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f";
+  integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==
+
 define-properties@^1.1.3, define-properties@^1.1.4:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.0.tgz#52988570670c9eacedd8064f4a990f2405849bd5";
@@ -2795,6 +2856,14 @@ emoji-regex@^9.2.2:
   resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72";
   integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==
 
+enhanced-resolve@^5.10.0:
+  version "5.12.0"
+  resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.12.0.tgz#300e1c90228f5b570c4d35babf263f6da7155634";
+  integrity sha512-QHTXI/sZQmko1cbDoNAa3mJ5qhWUUNAq3vR0/YiD379fWQrcfuoX1+HW2S0MTt7XmoPLapdaDKUtelUSPic7hQ==
+  dependencies:
+    graceful-fs "^4.2.4"
+    tapable "^2.2.0"
+
 entities@^4.4.0:
   version "4.4.0"
   resolved "https://registry.yarnpkg.com/entities/-/entities-4.4.0.tgz#97bdaba170339446495e653cfd2db78962900174";
@@ -2980,6 +3049,19 @@ eslint-import-resolver-node@^0.3.7:
     is-core-module "^2.11.0"
     resolve "^1.22.1"
 
+eslint-import-resolver-typescript@^3.5.3:
+  version "3.5.3"
+  resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.5.3.tgz#db5ed9e906651b7a59dd84870aaef0e78c663a05";
+  integrity sha512-njRcKYBc3isE42LaTcJNVANR3R99H9bAxBDMNDr2W7yq5gYPxbU3MkdhsQukxZ/Xg9C2vcyLlDsbKfRDg0QvCQ==
+  dependencies:
+    debug "^4.3.4"
+    enhanced-resolve "^5.10.0"
+    get-tsconfig "^4.2.0"
+    globby "^13.1.2"
+    is-core-module "^2.10.0"
+    is-glob "^4.0.3"
+    synckit "^0.8.4"
+
 eslint-module-utils@^2.7.4:
   version "2.7.4"
   resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz#4f3e41116aaf13a20792261e61d3a2e7e0583974";
@@ -3057,6 +3139,11 @@ eslint-plugin-no-only-tests@3.1.0:
   resolved "https://registry.yarnpkg.com/eslint-plugin-no-only-tests/-/eslint-plugin-no-only-tests-3.1.0.tgz#f38e4935c6c6c4842bf158b64aaa20c366fe171b";
   integrity sha512-Lf4YW/bL6Un1R6A76pRZyE1dl1vr31G/ev8UzIc/geCgFWyrKil8hVjYqWVKGB/UIGmb6Slzs9T0wNezdSVegw==
 
+eslint-plugin-no-relative-import-paths@1.5.2:
+  version "1.5.2"
+  resolved "https://registry.yarnpkg.com/eslint-plugin-no-relative-import-paths/-/eslint-plugin-no-relative-import-paths-1.5.2.tgz#c35f2fd0bf2a6a57b268193ed7df63ff7000134e";
+  integrity sha512-wMlL+TVuDhKk1plP+w3L4Hc7+u89vUkrOYq6/0ARjcYqwc9/YaS9uEXNzaqAk+WLoEgakzNL5JgJJw6m4qd5zw==
+
 eslint-plugin-prettier@4.2.1:
   version "4.2.1"
   resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz#651cbb88b1dab98bfd42f017a12fa6b2d993f94b";
@@ -3262,7 +3349,7 @@ fast-diff@^1.1.2:
   resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03";
   integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==
 
-fast-glob@^3.2.7, fast-glob@^3.2.9:
+fast-glob@^3.2.11, fast-glob@^3.2.7, fast-glob@^3.2.9:
   version "3.2.12"
   resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80";
   integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==
@@ -3449,6 +3536,11 @@ get-symbol-description@^1.0.0:
     call-bind "^1.0.2"
     get-intrinsic "^1.1.1"
 
+get-tsconfig@^4.2.0:
+  version "4.4.0"
+  resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.4.0.tgz#64eee64596668a81b8fce18403f94f245ee0d4e5";
+  integrity sha512-0Gdjo/9+FzsYhXCEFueo2aY1z1tpXrxWZzP7k8ul9qt1U5o8rYJwTJYmaeHdrVosYIVYkOy2iwCJ9FdpocJhPQ==
+
 glob-parent@^5.1.2, glob-parent@~5.1.2:
   version "5.1.2"
   resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4";
@@ -3494,6 +3586,11 @@ globalthis@^1.0.3:
   dependencies:
     define-properties "^1.1.3"
 
+globalyzer@0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/globalyzer/-/globalyzer-0.1.0.tgz#cb76da79555669a1519d5a8edf093afaa0bf1465";
+  integrity sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==
+
 globby@^11.1.0:
   version "11.1.0"
   resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b";
@@ -3518,6 +3615,22 @@ globby@^12.0.0:
     merge2 "^1.4.1"
     slash "^4.0.0"
 
+globby@^13.1.2:
+  version "13.1.3"
+  resolved "https://registry.yarnpkg.com/globby/-/globby-13.1.3.tgz#f62baf5720bcb2c1330c8d4ef222ee12318563ff";
+  integrity sha512-8krCNHXvlCgHDpegPzleMq07yMYTO2sXKASmZmquEYWEmCx6J5UTRbp5RwMJkTJGtcQ44YpiUYUiN0b9mzy8Bw==
+  dependencies:
+    dir-glob "^3.0.1"
+    fast-glob "^3.2.11"
+    ignore "^5.2.0"
+    merge2 "^1.4.1"
+    slash "^4.0.0"
+
+globrex@^0.1.2:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/globrex/-/globrex-0.1.2.tgz#dd5d9ec826232730cd6793a5e33a9302985e6098";
+  integrity sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==
+
 gopd@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c";
@@ -3525,7 +3638,7 @@ gopd@^1.0.1:
   dependencies:
     get-intrinsic "^1.1.3"
 
-graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.9:
+graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.9:
   version "4.2.10"
   resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c";
   integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==
@@ -3794,7 +3907,7 @@ is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7:
   resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055";
   integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==
 
-is-core-module@^2.11.0, is-core-module@^2.5.0, is-core-module@^2.9.0:
+is-core-module@^2.10.0, is-core-module@^2.11.0, is-core-module@^2.5.0, is-core-module@^2.9.0:
   version "2.11.0"
   resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.11.0.tgz#ad4cb3e3863e814523c96f3f58d26cc570ff0144";
   integrity sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==
@@ -3808,6 +3921,11 @@ is-date-object@^1.0.1, is-date-object@^1.0.5:
   dependencies:
     has-tostringtag "^1.0.0"
 
+is-docker@^2.0.0, is-docker@^2.1.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa";
+  integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==
+
 is-extendable@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4";
@@ -3973,6 +4091,13 @@ is-weakset@^2.0.1:
     call-bind "^1.0.2"
     get-intrinsic "^1.1.1"
 
+is-wsl@^2.2.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271";
+  integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==
+  dependencies:
+    is-docker "^2.0.0"
+
 isarray@^2.0.5:
   version "2.0.5"
   resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723";
@@ -4617,6 +4742,15 @@ onetime@^5.1.0:
   dependencies:
     mimic-fn "^2.1.0"
 
+open@^8.4.0:
+  version "8.4.2"
+  resolved "https://registry.yarnpkg.com/open/-/open-8.4.2.tgz#5b5ffe2a8f793dcd2aad73e550cb87b59cb084f9";
+  integrity sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==
+  dependencies:
+    define-lazy-prop "^2.0.0"
+    is-docker "^2.1.1"
+    is-wsl "^2.2.0"
+
 optionator@^0.8.1:
   version "0.8.3"
   resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495";
@@ -5572,6 +5706,19 @@ symbol-tree@^3.2.4:
   resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2";
   integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==
 
+synckit@^0.8.4:
+  version "0.8.5"
+  resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.8.5.tgz#b7f4358f9bb559437f9f167eb6bc46b3c9818fa3";
+  integrity sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==
+  dependencies:
+    "@pkgr/utils" "^2.3.1"
+    tslib "^2.5.0"
+
+tapable@^2.2.0:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0";
+  integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==
+
 terser@^5.7.1:
   version "5.16.5"
   resolved "https://registry.yarnpkg.com/terser/-/terser-5.16.5.tgz#1c285ca0655f467f92af1bbab46ab72d1cb08e5a";
@@ -5602,6 +5749,14 @@ timezone-mock@1.3.6:
   resolved "https://registry.yarnpkg.com/timezone-mock/-/timezone-mock-1.3.6.tgz#44e4c5aeb57e6c07ae630a05c528fc4d9aab86f4";
   integrity sha512-YcloWmZfLD9Li5m2VcobkCDNVaLMx8ohAb/97l/wYS3m+0TIEK5PFNMZZfRcusc6sFjIfxu8qcJT0CNnOdpqmg==
 
+tiny-glob@^0.2.9:
+  version "0.2.9"
+  resolved "https://registry.yarnpkg.com/tiny-glob/-/tiny-glob-0.2.9.tgz#2212d441ac17928033b110f8b3640683129d31e2";
+  integrity sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==
+  dependencies:
+    globalyzer "0.1.0"
+    globrex "^0.1.2"
+
 tinybench@^2.3.1:
   version "2.3.1"
   resolved "https://registry.yarnpkg.com/tinybench/-/tinybench-2.3.1.tgz#14f64e6b77d7ef0b1f6ab850c7a808c6760b414d";
@@ -5663,6 +5818,11 @@ trim-newlines@^3.0.0:
   resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144";
   integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==
 
+tsconfck@^2.0.1:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/tsconfck/-/tsconfck-2.0.3.tgz#47b79fc6be3c5ec6ec9b3862d1c959e85038b117";
+  integrity sha512-o3DsPZO1+C98KqHMdAbWs30zpxD30kj8r9OLA4ML1yghx4khNDzaaShNalfluh8ZPPhzKe3qyVCP1HiZszSAsw==
+
 tsconfig-paths@^3.14.1:
   version "3.14.2"
   resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz#6e32f1f79412decd261f92d633a9dc1cfa99f088";
@@ -5678,7 +5838,7 @@ tslib@^1.8.1:
   resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00";
   integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
 
-tslib@^2.1.0:
+tslib@^2.1.0, tslib@^2.4.0, tslib@^2.5.0:
   version "2.5.0"
   resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf";
   integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==
@@ -5927,6 +6087,15 @@ vite-node@0.28.5:
     source-map-support "^0.5.21"
     vite "^3.0.0 || ^4.0.0"
 
+vite-tsconfig-paths@^4.0.5:
+  version "4.0.5"
+  resolved "https://registry.yarnpkg.com/vite-tsconfig-paths/-/vite-tsconfig-paths-4.0.5.tgz#c7c54e2cf7ccc5e600db565cecd7b368a1fa8889";
+  integrity sha512-/L/eHwySFYjwxoYt1WRJniuK/jPv+WGwgRGBYx3leciR5wBeqntQpUE6Js6+TJemChc+ter7fDBKieyEWDx4yQ==
+  dependencies:
+    debug "^4.1.1"
+    globrex "^0.1.2"
+    tsconfck "^2.0.1"
+
 vite@4.1.0:
   version "4.1.0"
   resolved "https://registry.yarnpkg.com/vite/-/vite-4.1.0.tgz#4f0d3aa0491d313cd8c144e4339171b2a0fb6b54";

Follow ups