diff --git a/.eslintrc.js b/.eslintrc.js index 1415136093..514ab56bd7 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -54,6 +54,7 @@ module.exports = { "react-hooks", ], rules: { + "no-constant-condition": ["error", { "checkLoops": false }], "header/header": [2, "./license-header"], "comma-dangle": ["error", "always-multiline"], "comma-spacing": "error", @@ -107,7 +108,10 @@ module.exports = { ], parser: "@typescript-eslint/parser", extends: [ + "eslint:recommended", "plugin:@typescript-eslint/recommended", + "plugin:import/recommended", + "plugin:import/typescript", ], plugins: [ "header", @@ -118,7 +122,7 @@ module.exports = { sourceType: "module", }, rules: { - "no-irregular-whitespace": "error", + "no-constant-condition": ["error", { "checkLoops": false }], "header/header": [2, "./license-header"], "no-invalid-this": "off", "@typescript-eslint/no-invalid-this": ["error"], @@ -191,8 +195,11 @@ module.exports = { "unused-imports", ], extends: [ + "eslint:recommended", "plugin:@typescript-eslint/recommended", "plugin:react/recommended", + "plugin:import/recommended", + "plugin:import/typescript", ], parserOptions: { ecmaVersion: 2018, @@ -200,8 +207,9 @@ module.exports = { jsx: true, }, rules: { - "no-irregular-whitespace": "error", + "no-constant-condition": ["error", { "checkLoops": false }], "header/header": [2, "./license-header"], + "react/prop-types": "off", "no-invalid-this": "off", "@typescript-eslint/no-invalid-this": ["error"], "@typescript-eslint/explicit-function-return-type": "off", @@ -246,7 +254,6 @@ module.exports = { "objectsInObjects": false, "arraysInObjects": true, }], - "react/prop-types": "off", "semi": "off", "@typescript-eslint/semi": ["error"], "linebreak-style": ["error", "unix"], diff --git a/extensions/.eslintrc.js b/extensions/.eslintrc.js new file mode 100644 index 0000000000..d0daadb1aa --- /dev/null +++ b/extensions/.eslintrc.js @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +module.exports = { + "overrides": [ + { + files: [ + "**/*.ts", + "**/*.tsx", + ], + rules: { + "import/no-unresolved": ["error", { + ignore: ["@k8slens/extensions"], + }], + }, + }, + ], +}; diff --git a/package.json b/package.json index 2f7288f794..36a971a3a1 100644 --- a/package.json +++ b/package.json @@ -62,8 +62,7 @@ }, "moduleNameMapper": { "\\.(css|scss)$": "/__mocks__/styleMock.ts", - "\\.(svg)$": "/__mocks__/imageMock.ts", - "src/(.*)": "/__mocks__/windowMock.ts" + "\\.(svg)$": "/__mocks__/imageMock.ts" }, "modulePathIgnorePatterns": [ "/dist", @@ -200,6 +199,7 @@ "@ogre-tools/injectable-react": "3.1.1", "@sentry/electron": "^2.5.4", "@sentry/integrations": "^6.15.0", + "@types/circular-dependency-plugin": "5.0.4", "abort-controller": "^3.0.0", "auto-bind": "^4.0.0", "autobind-decorator": "^2.4.0", @@ -214,7 +214,7 @@ "filehound": "^1.17.5", "fs-extra": "^9.0.1", "glob-to-regexp": "^0.4.1", - "got": "^11.8.2", + "got": "^11.8.3", "grapheme-splitter": "^1.0.4", "handlebars": "^4.7.7", "http-proxy": "^1.18.1", @@ -333,7 +333,7 @@ "concurrently": "^5.3.0", "css-loader": "^5.2.7", "deepdash": "^5.3.9", - "dompurify": "^2.3.3", + "dompurify": "^2.3.4", "electron": "^13.6.1", "electron-builder": "^22.14.5", "electron-notarize": "^0.3.0", @@ -341,6 +341,7 @@ "esbuild-loader": "^2.16.0", "eslint": "^7.32.0", "eslint-plugin-header": "^3.1.1", + "eslint-plugin-import": "^2.25.3", "eslint-plugin-react": "^7.27.1", "eslint-plugin-react-hooks": "^4.3.0", "eslint-plugin-unused-imports": "^1.1.5", diff --git a/src/common/__tests__/cluster-store.test.ts b/src/common/__tests__/cluster-store.test.ts index 947cfc2d17..a70d470a64 100644 --- a/src/common/__tests__/cluster-store.test.ts +++ b/src/common/__tests__/cluster-store.test.ts @@ -493,42 +493,9 @@ users: it("moves the icon into preferences", async () => { const storedClusterData = clusterStore.clustersList[0]; - expect(storedClusterData.hasOwnProperty("icon")).toBe(false); - expect(storedClusterData.preferences.hasOwnProperty("icon")).toBe(true); - expect( - storedClusterData.preferences.icon.startsWith("data:;base64,"), - ).toBe(true); - }); - }); - - describe("for a pre 2.7.0-beta.0 config without a workspace", () => { - beforeEach(() => { - ClusterStore.resetInstance(); - const mockOpts = { - "some-directory-for-user-data": { - "lens-cluster-store.json": JSON.stringify({ - __internal__: { - migrations: { - version: "2.6.6", - }, - }, - cluster1: { - kubeConfig: minimalValidKubeConfig, - preferences: { - terminalCWD: "/some-directory-for-user-data", - }, - }, - }), - }, - }; - - mockFs(mockOpts); - - clusterStore = mainDi.inject(clusterStoreInjectable); - }); - - afterEach(() => { - mockFs.restore(); + expect(Object.prototype.hasOwnProperty.call(storedClusterData, "icon")).toBe(false); + expect(Object.prototype.hasOwnProperty.call(storedClusterData.preferences, "icon")).toBe(true); + expect(storedClusterData.preferences.icon.startsWith("data:;base64,")).toBe(true); }); }); @@ -580,6 +547,7 @@ users: }); }); }); + const minimalValidKubeConfig = JSON.stringify({ apiVersion: "v1", clusters: [ diff --git a/src/common/__tests__/user-store.test.ts b/src/common/__tests__/user-store.test.ts index 01e6ea63b9..76bf138cb6 100644 --- a/src/common/__tests__/user-store.test.ts +++ b/src/common/__tests__/user-store.test.ts @@ -42,19 +42,19 @@ import { Console } from "console"; import { SemVer } from "semver"; import electron from "electron"; import { stdout, stderr } from "process"; -import { ThemeStore } from "../../renderer/theme.store"; -import type { ClusterStoreModel } from "../cluster-store/cluster-store"; import { getDisForUnitTesting } from "../../test-utils/get-dis-for-unit-testing"; import userStoreInjectable from "../user-store/user-store.injectable"; import type { DependencyInjectionContainer } from "@ogre-tools/injectable"; import directoryForUserDataInjectable from "../app-paths/directory-for-user-data/directory-for-user-data.injectable"; +import type { ClusterStoreModel } from "../cluster-store/cluster-store"; +import { defaultTheme } from "../vars"; console = new Console(stdout, stderr); describe("user store tests", () => { let userStore: UserStore; let mainDi: DependencyInjectionContainer; - + beforeEach(async () => { const dis = getDisForUnitTesting({ doGeneralOverrides: true }); @@ -92,7 +92,7 @@ describe("user store tests", () => { userStore.httpsProxy = "abcd://defg"; expect(userStore.httpsProxy).toBe("abcd://defg"); - expect(userStore.colorTheme).toBe(ThemeStore.defaultTheme); + expect(userStore.colorTheme).toBe(defaultTheme); userStore.colorTheme = "light"; expect(userStore.colorTheme).toBe("light"); @@ -101,7 +101,7 @@ describe("user store tests", () => { it("correctly resets theme to default value", async () => { userStore.colorTheme = "some other theme"; userStore.resetTheme(); - expect(userStore.colorTheme).toBe(ThemeStore.defaultTheme); + expect(userStore.colorTheme).toBe(defaultTheme); }); it("correctly calculates if the last seen version is an old release", () => { diff --git a/src/common/catalog-entities/kubernetes-cluster.ts b/src/common/catalog-entities/kubernetes-cluster.ts index e589adb91a..d62effc387 100644 --- a/src/common/catalog-entities/kubernetes-cluster.ts +++ b/src/common/catalog-entities/kubernetes-cluster.ts @@ -20,11 +20,10 @@ */ import { catalogCategoryRegistry } from "../catalog/catalog-category-registry"; -import { CatalogEntity, CatalogEntityActionContext, CatalogEntityContextMenuContext, CatalogEntityMetadata, CatalogEntityStatus } from "../catalog"; +import { CatalogEntity, CatalogEntityActionContext, CatalogEntityContextMenuContext, CatalogEntityMetadata, CatalogEntityStatus, CatalogCategory, CatalogCategorySpec } from "../catalog"; import { clusterActivateHandler, clusterDisconnectHandler } from "../cluster-ipc"; import { ClusterStore } from "../cluster-store/cluster-store"; import { broadcastMessage, requestMain } from "../ipc"; -import { CatalogCategory, CatalogCategorySpec } from "../catalog"; import { app } from "electron"; import type { CatalogEntitySpec } from "../catalog/catalog-entity"; import { IpcRendererNavigationEvents } from "../../renderer/navigation/events"; diff --git a/src/common/ipc/ipc.ts b/src/common/ipc/ipc.ts index b0eaa01e2a..0442d07630 100644 --- a/src/common/ipc/ipc.ts +++ b/src/common/ipc/ipc.ts @@ -30,7 +30,15 @@ import { ClusterFrameInfo, clusterFrameMap } from "../cluster-frames"; import type { Disposer } from "../utils"; import type remote from "@electron/remote"; -const electronRemote = ipcMain ? null : require("@electron/remote"); +const electronRemote = (() => { + if (ipcRenderer) { + try { + return require("@electron/remote"); + } catch {} + } + + return null; +})(); const subFramesChannel = "ipc:get-sub-frames"; diff --git a/src/common/k8s-api/__tests__/crd.test.ts b/src/common/k8s-api/__tests__/crd.test.ts index 0eba45e2cd..4403a9c7a4 100644 --- a/src/common/k8s-api/__tests__/crd.test.ts +++ b/src/common/k8s-api/__tests__/crd.test.ts @@ -19,10 +19,10 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { CustomResourceDefinition } from "../endpoints"; +import { CustomResourceDefinition, CustomResourceDefinitionSpec } from "../endpoints"; describe("Crds", () => { - describe("getVersion", () => { + describe("getVersion()", () => { it("should throw if none of the versions are served", () => { const crd = new CustomResourceDefinition({ apiVersion: "apiextensions.k8s.io/v1", @@ -136,7 +136,7 @@ describe("Crds", () => { expect(crd.getVersion()).toBe("123"); }); - it("should get the version name from the version field", () => { + it("should get the version name from the version field, ignoring versions on v1beta", () => { const crd = new CustomResourceDefinition({ apiVersion: "apiextensions.k8s.io/v1beta1", kind: "CustomResourceDefinition", @@ -147,7 +147,14 @@ describe("Crds", () => { }, spec: { version: "abc", - }, + versions: [ + { + name: "foobar", + served: true, + storage: true, + }, + ], + } as CustomResourceDefinitionSpec, }); expect(crd.getVersion()).toBe("abc"); diff --git a/src/common/k8s-api/__tests__/kube-object.test.ts b/src/common/k8s-api/__tests__/kube-object.test.ts index cb2a412a5e..edc7a52505 100644 --- a/src/common/k8s-api/__tests__/kube-object.test.ts +++ b/src/common/k8s-api/__tests__/kube-object.test.ts @@ -164,14 +164,14 @@ describe("KubeObject", () => { describe("isJsonApiDataList", () => { function isAny(val: unknown): val is any { - return !Boolean(void val); + return true; } function isNotAny(val: unknown): val is any { - return Boolean(void val); + return false; } - function isBoolean(val: unknown): val is Boolean { + function isBoolean(val: unknown): val is boolean { return typeof val === "boolean"; } diff --git a/src/common/k8s-api/endpoints/crd.api.ts b/src/common/k8s-api/endpoints/crd.api.ts index 4e2244d8a8..4892a8a262 100644 --- a/src/common/k8s-api/endpoints/crd.api.ts +++ b/src/common/k8s-api/endpoints/crd.api.ts @@ -48,34 +48,36 @@ export interface CRDVersion { additionalPrinterColumns?: AdditionalPrinterColumnsV1[]; } -export interface CustomResourceDefinition { - spec: { - group: string; - /** - * @deprecated for apiextensions.k8s.io/v1 but used previously - */ - version?: string; - names: { - plural: string; - singular: string; - kind: string; - listKind: string; - }; - scope: "Namespaced" | "Cluster" | string; - /** - * @deprecated for apiextensions.k8s.io/v1 but used previously - */ - validation?: object; - versions?: CRDVersion[]; - conversion: { - strategy?: string; - webhook?: any; - }; - /** - * @deprecated for apiextensions.k8s.io/v1 but used previously - */ - additionalPrinterColumns?: AdditionalPrinterColumnsV1Beta[]; +export interface CustomResourceDefinitionSpec { + group: string; + /** + * @deprecated for apiextensions.k8s.io/v1 but used in v1beta1 + */ + version?: string; + names: { + plural: string; + singular: string; + kind: string; + listKind: string; }; + scope: "Namespaced" | "Cluster"; + /** + * @deprecated for apiextensions.k8s.io/v1 but used in v1beta1 + */ + validation?: object; + versions?: CRDVersion[]; + conversion: { + strategy?: string; + webhook?: any; + }; + /** + * @deprecated for apiextensions.k8s.io/v1 but used in v1beta1 + */ + additionalPrinterColumns?: AdditionalPrinterColumnsV1Beta[]; +} + +export interface CustomResourceDefinition { + spec: CustomResourceDefinitionSpec; status: { conditions: { lastTransitionTime: string; @@ -150,27 +152,32 @@ export class CustomResourceDefinition extends KubeObject { } getPreferedVersion(): CRDVersion { - // Prefer the modern `versions` over the legacy `version` - if (this.spec.versions) { - for (const version of this.spec.versions) { - if (version.storage) { - return version; - } - } - } else if (this.spec.version) { - const { additionalPrinterColumns: apc } = this.spec; - const additionalPrinterColumns = apc?.map(({ JSONPath, ...apc }) => ({ ...apc, jsonPath: JSONPath })); + const { apiVersion } = this; - return { - name: this.spec.version, - served: true, - storage: true, - schema: this.spec.validation, - additionalPrinterColumns, - }; + switch (apiVersion) { + case "apiextensions.k8s.io/v1": + for (const version of this.spec.versions) { + if (version.storage) { + return version; + } + } + break; + + case "apiextensions.k8s.io/v1beta1": { + const { additionalPrinterColumns: apc } = this.spec; + const additionalPrinterColumns = apc?.map(({ JSONPath, ...apc }) => ({ ...apc, jsonPath: JSONPath })); + + return { + name: this.spec.version, + served: true, + storage: true, + schema: this.spec.validation, + additionalPrinterColumns, + }; + } } - throw new Error(`Failed to find a version for CustomResourceDefinition ${this.metadata.name}`); + throw new Error(`Unknown apiVersion=${apiVersion}: Failed to find a version for CustomResourceDefinition ${this.metadata.name}`); } getVersion() { @@ -197,7 +204,7 @@ export class CustomResourceDefinition extends KubeObject { const columns = this.getPreferedVersion().additionalPrinterColumns ?? []; return columns - .filter(column => column.name != "Age" && (ignorePriority || !column.priority)); + .filter(column => column.name.toLowerCase() != "age" && (ignorePriority || !column.priority)); } getValidation() { diff --git a/src/common/k8s-api/endpoints/ingress.api.ts b/src/common/k8s-api/endpoints/ingress.api.ts index 7b80dca29e..8e46021eae 100644 --- a/src/common/k8s-api/endpoints/ingress.api.ts +++ b/src/common/k8s-api/endpoints/ingress.api.ts @@ -187,7 +187,7 @@ export class Ingress extends KubeObject { const servicePort = defaultBackend?.service.port.number ?? backend?.servicePort; if (rules && rules.length > 0) { - if (rules.some(rule => rule.hasOwnProperty("http"))) { + if (rules.some(rule => Object.prototype.hasOwnProperty.call(rule, "http"))) { ports.push(httpPort); } } else if (servicePort !== undefined) { diff --git a/src/common/k8s-api/endpoints/metrics.api.ts b/src/common/k8s-api/endpoints/metrics.api.ts index bd6bc4709c..0fdadbe0dc 100644 --- a/src/common/k8s-api/endpoints/metrics.api.ts +++ b/src/common/k8s-api/endpoints/metrics.api.ts @@ -184,7 +184,8 @@ export function getMetricLastPoints(metrics: Record) { if (metric.data.result.length) { result[metricName] = +metric.data.result[0].values.slice(-1)[0][1]; } - } catch (e) { + } catch { + // ignore error } return result; diff --git a/src/common/k8s-api/kube-api.ts b/src/common/k8s-api/kube-api.ts index 8911aa7a9f..390140a0c8 100644 --- a/src/common/k8s-api/kube-api.ts +++ b/src/common/k8s-api/kube-api.ts @@ -34,6 +34,9 @@ import type { IKubeWatchEvent } from "./kube-watch-event"; import { KubeJsonApi, KubeJsonApiData } from "./kube-json-api"; import { noop } from "../utils"; import type { RequestInit } from "node-fetch"; + +// BUG: https://github.com/mysticatea/abort-controller/pull/22 +// eslint-disable-next-line import/no-named-as-default import AbortController from "abort-controller"; import { Agent, AgentOptions } from "https"; import type { Patch } from "rfc6902"; @@ -698,21 +701,16 @@ export class KubeApi { } protected modifyWatchEvent(event: IKubeWatchEvent) { + if (event.type === "ERROR") { + return; - switch (event.type) { - case "ADDED": - case "DELETED": - - case "MODIFIED": { - ensureObjectSelfLink(this, event.object); - - const { namespace, resourceVersion } = event.object.metadata; - - this.setResourceVersion(namespace, resourceVersion); - this.setResourceVersion("", resourceVersion); - - break; - } } + + ensureObjectSelfLink(this, event.object); + + const { namespace, resourceVersion } = event.object.metadata; + + this.setResourceVersion(namespace, resourceVersion); + this.setResourceVersion("", resourceVersion); } } diff --git a/src/common/k8s-api/kube-object.store.ts b/src/common/k8s-api/kube-object.store.ts index b67d24547e..f8d7ad2988 100644 --- a/src/common/k8s-api/kube-object.store.ts +++ b/src/common/k8s-api/kube-object.store.ts @@ -30,6 +30,9 @@ import { ensureObjectSelfLink, IKubeApiQueryParams, KubeApi } from "./kube-api"; import { parseKubeApi } from "./kube-api-parse"; import type { KubeJsonApiData } from "./kube-json-api"; import type { RequestInit } from "node-fetch"; + +// BUG: https://github.com/mysticatea/abort-controller/pull/22 +// eslint-disable-next-line import/no-named-as-default import AbortController from "abort-controller"; import type { Patch } from "rfc6902"; @@ -469,7 +472,9 @@ export abstract class KubeObjectStore extends ItemStore switch (type) { case "ADDED": - case "MODIFIED": + + // falls through + case "MODIFIED": { const newItem = new this.api.objectConstructor(object); if (!item) { @@ -477,7 +482,9 @@ export abstract class KubeObjectStore extends ItemStore } else { items[index] = newItem; } + break; + } case "DELETED": if (item) { items.splice(index, 1); diff --git a/src/common/protocol-handler/router.ts b/src/common/protocol-handler/router.ts index a3950ca100..127436a65d 100644 --- a/src/common/protocol-handler/router.ts +++ b/src/common/protocol-handler/router.ts @@ -89,7 +89,7 @@ export abstract class LensProtocolRouter { public static readonly LoggingPrefix = "[PROTOCOL ROUTER]"; - static readonly ExtensionUrlSchema = `/:${EXTENSION_PUBLISHER_MATCH}(\@[A-Za-z0-9_]+)?/:${EXTENSION_NAME_MATCH}`; + static readonly ExtensionUrlSchema = `/:${EXTENSION_PUBLISHER_MATCH}(@[A-Za-z0-9_]+)?/:${EXTENSION_NAME_MATCH}`; constructor(protected dependencies: Dependencies) {} diff --git a/src/common/user-store/preferences-helpers.ts b/src/common/user-store/preferences-helpers.ts index 450c75ae89..1ded307f0d 100644 --- a/src/common/user-store/preferences-helpers.ts +++ b/src/common/user-store/preferences-helpers.ts @@ -22,11 +22,11 @@ import moment from "moment-timezone"; import path from "path"; import os from "os"; -import { ThemeStore } from "../../renderer/theme.store"; import { getAppVersion, ObservableToggleSet } from "../utils"; import type { editor } from "monaco-editor"; import merge from "lodash/merge"; import { SemVer } from "semver"; +import { defaultTheme } from "../vars"; export interface KubeconfigSyncEntry extends KubeconfigSyncValue { filePath: string; @@ -72,10 +72,10 @@ const shell: PreferenceDescription = { const colorTheme: PreferenceDescription = { fromStore(val) { - return val || ThemeStore.defaultTheme; + return val || defaultTheme; }, toStore(val) { - if (!val || val === ThemeStore.defaultTheme) { + if (!val || val === defaultTheme) { return undefined; } diff --git a/src/common/utils/defineGlobal.ts b/src/common/utils/defineGlobal.ts index eeaea8baa5..1c205a0632 100755 --- a/src/common/utils/defineGlobal.ts +++ b/src/common/utils/defineGlobal.ts @@ -26,7 +26,7 @@ export function defineGlobal(propName: string, descriptor: PropertyDescriptor) { const scope = typeof global !== "undefined" ? global : window; - if (scope.hasOwnProperty(propName)) { + if (Object.prototype.hasOwnProperty.call(scope, propName)) { return; } diff --git a/src/common/utils/iter.ts b/src/common/utils/iter.ts index 6271a05969..9d185ab5d7 100644 --- a/src/common/utils/iter.ts +++ b/src/common/utils/iter.ts @@ -25,6 +25,7 @@ export type Falsey = false | 0 | "" | null | undefined; * Create a new type safe empty Iterable * @returns An `Iterable` that yields 0 items */ +// eslint-disable-next-line require-yield export function* newEmpty(): IterableIterator { return; } diff --git a/src/common/utils/tar.ts b/src/common/utils/tar.ts index d0c67976e9..b3ef949173 100644 --- a/src/common/utils/tar.ts +++ b/src/common/utils/tar.ts @@ -31,12 +31,13 @@ export interface ReadFileFromTarOpts { } export function readFileFromTar({ tarPath, filePath, parseJson }: ReadFileFromTarOpts): Promise { - return new Promise(async (resolve, reject) => { + return new Promise((resolve, reject) => { const fileChunks: Buffer[] = []; - await tar.list({ + tar.list({ file: tarPath, filter: entryPath => path.normalize(entryPath) === filePath, + sync: true, onentry(entry: FileStat) { entry.on("data", chunk => { fileChunks.push(chunk); diff --git a/src/common/utils/tuple.ts b/src/common/utils/tuple.ts index 5a252cf89c..b7b751bb30 100644 --- a/src/common/utils/tuple.ts +++ b/src/common/utils/tuple.ts @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { array } from "../utils"; +import * as array from "../utils/array"; /** * A strict N-tuple of type T diff --git a/src/common/vars.ts b/src/common/vars.ts index 138626a04b..b3d75f9bf3 100644 --- a/src/common/vars.ts +++ b/src/common/vars.ts @@ -41,6 +41,7 @@ export const isIntegrationTesting = process.argv.includes(integrationTestingArg) export const productName = packageInfo.productName; export const appName = `${packageInfo.productName}${isDevelopment ? "Dev" : ""}`; export const publicPath = "/build/" as string; +export const defaultTheme = "lens-dark" as string; // Webpack build paths export const contextDir = process.cwd(); diff --git a/src/extensions/registries/base-registry.ts b/src/extensions/registries/base-registry.ts index 9b596172c9..1fe7530779 100644 --- a/src/extensions/registries/base-registry.ts +++ b/src/extensions/registries/base-registry.ts @@ -22,7 +22,7 @@ // Base class for extensions-api registries import { action, observable, makeObservable } from "mobx"; import { Singleton } from "../../common/utils"; -import { LensExtension } from "../lens-extension"; +import type { LensExtension } from "../lens-extension"; export class BaseRegistry extends Singleton { private items = observable.map([], { deep: false }); diff --git a/src/main/app-updater.ts b/src/main/app-updater.ts index 3c358acde6..fb4300b266 100644 --- a/src/main/app-updater.ts +++ b/src/main/app-updater.ts @@ -25,10 +25,9 @@ import { isLinux, isMac, isPublishConfigured, isTestEnv } from "../common/vars"; import { delay } from "../common/utils"; import { areArgsUpdateAvailableToBackchannel, AutoUpdateChecking, AutoUpdateLogPrefix, AutoUpdateNoUpdateAvailable, broadcastMessage, onceCorrect, UpdateAvailableChannel, UpdateAvailableToBackchannel } from "../common/ipc"; import { once } from "lodash"; -import { ipcMain } from "electron"; +import { ipcMain, autoUpdater as electronAutoUpdater } from "electron"; import { nextUpdateChannel } from "./utils/update-channel"; import { UserStore } from "../common/user-store"; -import { autoUpdater as electronAutoUpdater } from "electron"; let installVersion: null | string = null; diff --git a/src/main/helm/helm-release-manager.ts b/src/main/helm/helm-release-manager.ts index 25c8b67737..d7ce9db5c1 100644 --- a/src/main/helm/helm-release-manager.ts +++ b/src/main/helm/helm-release-manager.ts @@ -19,7 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import * as tempy from "tempy"; +import tempy from "tempy"; import fse from "fs-extra"; import * as yaml from "js-yaml"; import { promiseExecFile } from "../../common/utils/promise-exec"; diff --git a/src/main/helm/helm-repo-manager.ts b/src/main/helm/helm-repo-manager.ts index f8edc12e00..8c8c0c6996 100644 --- a/src/main/helm/helm-repo-manager.ts +++ b/src/main/helm/helm-repo-manager.ts @@ -119,7 +119,9 @@ export class HelmRepoManager extends Singleton { if (typeof parsedConfig === "object" && parsedConfig) { return parsedConfig as HelmRepoConfig; } - } catch { } + } catch { + // ignore error + } return { repositories: [], diff --git a/src/main/initializers/init-ipc-main-handlers/init-ipc-main-handlers.ts b/src/main/initializers/init-ipc-main-handlers/init-ipc-main-handlers.ts index 9fd2bf8d0c..5737cd20a5 100644 --- a/src/main/initializers/init-ipc-main-handlers/init-ipc-main-handlers.ts +++ b/src/main/initializers/init-ipc-main-handlers/init-ipc-main-handlers.ts @@ -101,7 +101,9 @@ export const initIpcMainHandlers = ({ electronMenuItems, directoryForLensLocalSt const localStorageFilePath = path.resolve(directoryForLensLocalStorage, `${cluster.id}.json`); await remove(localStorageFilePath); - } catch {} + } catch { + // ignore error + } }); ipcMainHandle(clusterSetDeletingHandler, (event, clusterId: string) => { diff --git a/src/main/kubectl/kubectl.ts b/src/main/kubectl/kubectl.ts index d37a798b58..48ac269806 100644 --- a/src/main/kubectl/kubectl.ts +++ b/src/main/kubectl/kubectl.ts @@ -356,10 +356,10 @@ export class Kubectl { bashScript += `export PATH="${helmPath}:${kubectlPath}:$PATH"\n`; bashScript += "export KUBECONFIG=\"$tempkubeconfig\"\n"; - bashScript += `NO_PROXY=\",\${NO_PROXY:-localhost},\"\n`; - bashScript += `NO_PROXY=\"\${NO_PROXY//,localhost,/,}\"\n`; - bashScript += `NO_PROXY=\"\${NO_PROXY//,127.0.0.1,/,}\"\n`; - bashScript += `NO_PROXY=\"localhost,127.0.0.1\${NO_PROXY%,}\"\n`; + bashScript += `NO_PROXY=",\${NO_PROXY:-localhost},"\n`; + bashScript += `NO_PROXY="\${NO_PROXY//,localhost,/,}"\n`; + bashScript += `NO_PROXY="\${NO_PROXY//,127.0.0.1,/,}"\n`; + bashScript += `NO_PROXY="localhost,127.0.0.1\${NO_PROXY%,}"\n`; bashScript += "export NO_PROXY\n"; bashScript += "unset tempkubeconfig\n"; await fsPromises.writeFile(bashScriptPath, bashScript.toString(), { mode: 0o644 }); @@ -377,18 +377,18 @@ export class Kubectl { zshScript += "test -f \"$OLD_ZDOTDIR/.zshrc\" && . \"$OLD_ZDOTDIR/.zshrc\"\n"; // voodoo to replace any previous occurrences of kubectl path in the PATH - zshScript += `kubectlpath=\"${kubectlPath}"\n`; - zshScript += `helmpath=\"${helmPath}"\n`; + zshScript += `kubectlpath="${kubectlPath}"\n`; + zshScript += `helmpath="${helmPath}"\n`; zshScript += "p=\":$kubectlpath:\"\n"; zshScript += "d=\":$PATH:\"\n"; zshScript += `d=\${d//$p/:}\n`; zshScript += `d=\${d/#:/}\n`; - zshScript += `export PATH=\"$helmpath:$kubectlpath:\${d/%:/}\"\n`; + zshScript += `export PATH="$helmpath:$kubectlpath:\${d/%:/}"\n`; zshScript += "export KUBECONFIG=\"$tempkubeconfig\"\n"; - zshScript += `NO_PROXY=\",\${NO_PROXY:-localhost},\"\n`; - zshScript += `NO_PROXY=\"\${NO_PROXY//,localhost,/,}\"\n`; - zshScript += `NO_PROXY=\"\${NO_PROXY//,127.0.0.1,/,}\"\n`; - zshScript += `NO_PROXY=\"localhost,127.0.0.1\${NO_PROXY%,}\"\n`; + zshScript += `NO_PROXY=",\${NO_PROXY:-localhost},"\n`; + zshScript += `NO_PROXY="\${NO_PROXY//,localhost,/,}"\n`; + zshScript += `NO_PROXY="\${NO_PROXY//,127.0.0.1,/,}"\n`; + zshScript += `NO_PROXY="localhost,127.0.0.1\${NO_PROXY%,}"\n`; zshScript += "export NO_PROXY\n"; zshScript += "unset tempkubeconfig\n"; zshScript += "unset OLD_ZDOTDIR\n"; diff --git a/src/main/resource-applier.ts b/src/main/resource-applier.ts index b414cecc4c..6488dce848 100644 --- a/src/main/resource-applier.ts +++ b/src/main/resource-applier.ts @@ -25,7 +25,7 @@ import { exec } from "child_process"; import fs from "fs-extra"; import * as yaml from "js-yaml"; import path from "path"; -import * as tempy from "tempy"; +import tempy from "tempy"; import logger from "./logger"; import { appEventBus } from "../common/app-event-bus/event-bus"; import { cloneJsonObject } from "../common/utils"; diff --git a/src/main/shell-session/node-shell-session/node-shell-session.ts b/src/main/shell-session/node-shell-session/node-shell-session.ts index 339ecd4933..d3f9f9d5ab 100644 --- a/src/main/shell-session/node-shell-session/node-shell-session.ts +++ b/src/main/shell-session/node-shell-session/node-shell-session.ts @@ -73,6 +73,7 @@ export class NodeShellSession extends ShellSession { switch (nodeOs) { default: logger.warn(`[NODE-SHELL-SESSION]: could not determine node OS, falling back with assumption of linux`); + // fallthrough case "linux": args.push("sh", "-c", "((clear && bash) || (clear && ash) || (clear && sh))"); break; diff --git a/src/main/shell-session/shell-session.ts b/src/main/shell-session/shell-session.ts index 8614fab3cb..fbda5250df 100644 --- a/src/main/shell-session/shell-session.ts +++ b/src/main/shell-session/shell-session.ts @@ -134,7 +134,9 @@ export abstract class ShellSession { for (const shellProcess of this.processes.values()) { try { process.kill(shellProcess.pid); - } catch {} + } catch { + // ignore error + } } this.processes.clear(); @@ -212,7 +214,9 @@ export abstract class ShellSession { if (stats.isDirectory()) { return potentialCwd; } - } catch {} + } catch { + // ignore error + } } return "."; // Always valid diff --git a/src/migrations/cluster-store/2.0.0-beta.2.ts b/src/migrations/cluster-store/2.0.0-beta.2.ts index e3a89b37d3..8d49aa3ab0 100644 --- a/src/migrations/cluster-store/2.0.0-beta.2.ts +++ b/src/migrations/cluster-store/2.0.0-beta.2.ts @@ -33,7 +33,7 @@ export default { const contextName = value[0]; // Looping all the keys gives out the store internal stuff too... - if (contextName === "__internal__" || value[1].hasOwnProperty("kubeConfig")) continue; + if (contextName === "__internal__" || Object.prototype.hasOwnProperty.call(value[1], "kubeConfig")) continue; store.set(contextName, { kubeConfig: value[1] }); } }, diff --git a/src/migrations/cluster-store/2.6.0-beta.3.ts b/src/migrations/cluster-store/2.6.0-beta.3.ts index a33dd7523f..82f1ac0f88 100644 --- a/src/migrations/cluster-store/2.6.0-beta.3.ts +++ b/src/migrations/cluster-store/2.6.0-beta.3.ts @@ -34,7 +34,7 @@ export default { if (!cluster.kubeConfig) continue; const config = yaml.load(cluster.kubeConfig); - if (!config || typeof config !== "object" || !config.hasOwnProperty("users")) { + if (!config || typeof config !== "object" || !Object.prototype.hasOwnProperty.call(config, "users")) { continue; } diff --git a/src/renderer/api/__tests__/catalog-entity-registry.test.ts b/src/renderer/api/__tests__/catalog-entity-registry.test.ts index f4261df995..26a4aaeb03 100644 --- a/src/renderer/api/__tests__/catalog-entity-registry.test.ts +++ b/src/renderer/api/__tests__/catalog-entity-registry.test.ts @@ -20,7 +20,6 @@ */ import { CatalogEntityRegistry } from "../catalog-entity-registry"; -import "../../../common/catalog-entities"; import { catalogCategoryRegistry } from "../../../common/catalog/catalog-category-registry"; import { CatalogCategory, CatalogEntityData, CatalogEntityKindData } from "../catalog-entity"; import { KubernetesCluster, WebLink } from "../../../common/catalog-entities"; diff --git a/src/renderer/api/catalog-entity-registry.ts b/src/renderer/api/catalog-entity-registry.ts index 83cfd96b01..51d38d04da 100644 --- a/src/renderer/api/catalog-entity-registry.ts +++ b/src/renderer/api/catalog-entity-registry.ts @@ -28,14 +28,21 @@ import { ClusterStore } from "../../common/cluster-store/cluster-store"; import { Disposer, iter } from "../utils"; import { once } from "lodash"; import logger from "../../common/logger"; -import { catalogEntityRunContext } from "./catalog-entity"; import { CatalogRunEvent } from "../../common/catalog/catalog-run-event"; import { ipcRenderer } from "electron"; import { CatalogIpcEvents } from "../../common/ipc/catalog"; +import { navigate } from "../navigation"; export type EntityFilter = (entity: CatalogEntity) => any; export type CatalogEntityOnBeforeRun = (event: CatalogRunEvent) => void | Promise; +export const catalogEntityRunContext = { + navigate: (url: string) => navigate(url), + setCommandPaletteContext: (entity?: CatalogEntity) => { + catalogEntityRegistry.activeEntity = entity; + }, +}; + export class CatalogEntityRegistry { @observable protected activeEntityId: string | undefined = undefined; protected _entities = observable.map([], { deep: true }); diff --git a/src/renderer/api/catalog-entity.ts b/src/renderer/api/catalog-entity.ts index 1d07291659..debb235c8f 100644 --- a/src/renderer/api/catalog-entity.ts +++ b/src/renderer/api/catalog-entity.ts @@ -19,10 +19,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { navigate } from "../navigation"; -import type { CatalogEntity } from "../../common/catalog"; -import { catalogEntityRegistry } from "./catalog-entity-registry"; - +export { catalogEntityRunContext } from "./catalog-entity-registry"; export { CatalogCategory, CatalogEntity } from "../../common/catalog"; export type { CatalogEntityData, @@ -33,10 +30,3 @@ export type { CatalogEntityContextMenu, CatalogEntityContextMenuContext, } from "../../common/catalog"; - -export const catalogEntityRunContext = { - navigate: (url: string) => navigate(url), - setCommandPaletteContext: (entity?: CatalogEntity) => { - catalogEntityRegistry.activeEntity = entity; - }, -}; diff --git a/src/renderer/components/+config-autoscalers/hpa-details.tsx b/src/renderer/components/+config-autoscalers/hpa-details.tsx index 3e6c74b9bb..78a0457293 100644 --- a/src/renderer/components/+config-autoscalers/hpa-details.tsx +++ b/src/renderer/components/+config-autoscalers/hpa-details.tsx @@ -45,15 +45,17 @@ export class HpaDetails extends React.Component { const renderName = (metric: IHpaMetric) => { switch (metric.type) { - case HpaMetricType.Resource: - const addition = metric.resource.targetAverageUtilization ? <>(as a percentage of request) : ""; + case HpaMetricType.Resource: { + const addition = metric.resource.targetAverageUtilization + ? "(as a percentage of request)" + : ""; return <>Resource {metric.resource.name} on Pods {addition}; - + } case HpaMetricType.Pods: return <>{metric.pods.metricName} on Pods; - case HpaMetricType.Object: + case HpaMetricType.Object: { const { target } = metric.object; const { kind, name } = target; const objectUrl = getDetailsUrl(apiManager.lookupApiLink(target, hpa)); @@ -64,6 +66,7 @@ export class HpaDetails extends React.Component { {kind}/{name} ); + } case HpaMetricType.External: return ( <> diff --git a/src/renderer/components/+extensions/attempt-install/unpack-extension/unpack-extension.injectable.tsx b/src/renderer/components/+extensions/attempt-install/unpack-extension/unpack-extension.injectable.tsx index 5cebbd0220..80fe1097d1 100644 --- a/src/renderer/components/+extensions/attempt-install/unpack-extension/unpack-extension.injectable.tsx +++ b/src/renderer/components/+extensions/attempt-install/unpack-extension/unpack-extension.injectable.tsx @@ -18,8 +18,7 @@ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { getInjectable } from "@ogre-tools/injectable"; -import { lifecycleEnum } from "@ogre-tools/injectable"; +import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable"; import { unpackExtension } from "./unpack-extension"; import extensionLoaderInjectable from "../../../../../extensions/extension-loader/extension-loader.injectable"; import getExtensionDestFolderInjectable diff --git a/src/renderer/components/+extensions/get-base-registry-url/get-base-registry-url.tsx b/src/renderer/components/+extensions/get-base-registry-url/get-base-registry-url.tsx index c811a21319..1e9c582d39 100644 --- a/src/renderer/components/+extensions/get-base-registry-url/get-base-registry-url.tsx +++ b/src/renderer/components/+extensions/get-base-registry-url/get-base-registry-url.tsx @@ -47,8 +47,8 @@ export const getBaseRegistryUrl = ({ getRegistryUrlPreference }: Dependencies) = } catch (error) { Notifications.error(

Failed to get configured registry from .npmrc. Falling back to default registry

); console.warn("[EXTENSIONS]: failed to get configured registry from .npmrc", error); - // fallthrough } + // fallthrough } default: case ExtensionRegistryLocation.DEFAULT: diff --git a/src/renderer/components/delete-cluster-dialog/__tests__/delete-cluster-dialog.test.tsx b/src/renderer/components/delete-cluster-dialog/__tests__/delete-cluster-dialog.test.tsx index 499af7c336..a26eac252f 100644 --- a/src/renderer/components/delete-cluster-dialog/__tests__/delete-cluster-dialog.test.tsx +++ b/src/renderer/components/delete-cluster-dialog/__tests__/delete-cluster-dialog.test.tsx @@ -23,7 +23,7 @@ import { KubeConfig } from "@kubernetes/client-node"; import { fireEvent, render } from "@testing-library/react"; import mockFs from "mock-fs"; import React from "react"; -import selectEvent from "react-select-event"; +import * as selectEvent from "react-select-event"; import type { Cluster } from "../../../../common/cluster/cluster"; import { DeleteClusterDialog } from "../delete-cluster-dialog"; diff --git a/src/renderer/components/dock/__test__/log-resource-selector.test.tsx b/src/renderer/components/dock/__test__/log-resource-selector.test.tsx index c65499f742..e737dac036 100644 --- a/src/renderer/components/dock/__test__/log-resource-selector.test.tsx +++ b/src/renderer/components/dock/__test__/log-resource-selector.test.tsx @@ -21,8 +21,7 @@ import React from "react"; import "@testing-library/jest-dom/extend-expect"; -import selectEvent from "react-select-event"; - +import * as selectEvent from "react-select-event"; import { Pod } from "../../../../common/k8s-api/endpoints"; import { LogResourceSelector } from "../log-resource-selector"; import type { LogTabData } from "../log-tab-store/log-tab.store"; @@ -33,8 +32,7 @@ import mockFs from "mock-fs"; import { getDiForUnitTesting } from "../../getDiForUnitTesting"; import type { DiRender } from "../../test-utils/renderFor"; import { renderFor } from "../../test-utils/renderFor"; -import directoryForUserDataInjectable - from "../../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable"; +import directoryForUserDataInjectable from "../../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable"; import callForLogsInjectable from "../log-store/call-for-logs/call-for-logs.injectable"; jest.mock("electron", () => ({ diff --git a/src/renderer/components/file-picker/file-picker.tsx b/src/renderer/components/file-picker/file-picker.tsx index 3661bb2cb2..ed955c4a22 100644 --- a/src/renderer/components/file-picker/file-picker.tsx +++ b/src/renderer/components/file-picker/file-picker.tsx @@ -133,7 +133,8 @@ export class FilePicker extends React.Component { switch (onOverSizeLimit) { case OverSizeLimitStyle.FILTER: return files.filter(file => file.size <= maxSize ); - case OverSizeLimitStyle.REJECT: + + case OverSizeLimitStyle.REJECT: { const firstFileToLarge = files.find(file => file.size > maxSize); if (firstFileToLarge) { @@ -141,6 +142,7 @@ export class FilePicker extends React.Component { } return files; + } } } @@ -156,7 +158,9 @@ export class FilePicker extends React.Component { switch (onOverTotalSizeLimit) { case OverTotalSizeLimitStyle.FILTER_LARGEST: files = _.orderBy(files, ["size"]); - case OverTotalSizeLimitStyle.FILTER_LAST: + + // fallthrough + case OverTotalSizeLimitStyle.FILTER_LAST: { let newTotalSize = totalSize; for (;files.length > 0;) { @@ -168,6 +172,7 @@ export class FilePicker extends React.Component { } return files; + } case OverTotalSizeLimitStyle.REJECT: throw `Total file size to upload is too large. Expected at most ${maxTotalSize}. Found ${totalSize}.`; } diff --git a/src/renderer/components/icon/icon.tsx b/src/renderer/components/icon/icon.tsx index e5258f1a14..f5943ba109 100644 --- a/src/renderer/components/icon/icon.tsx +++ b/src/renderer/components/icon/icon.tsx @@ -73,6 +73,7 @@ export class Icon extends React.PureComponent { switch (evt.nativeEvent.code) { case "Space": + // fallthrough case "Enter": { // eslint-disable-next-line react/no-find-dom-node const icon = findDOMNode(this) as HTMLElement; diff --git a/src/renderer/components/input/input_validators.ts b/src/renderer/components/input/input_validators.ts index 8ea1a7e3c2..36086aca24 100644 --- a/src/renderer/components/input/input_validators.ts +++ b/src/renderer/components/input/input_validators.ts @@ -39,7 +39,7 @@ export const isRequired: InputValidator = { export const isEmail: InputValidator = { condition: ({ type }) => type === "email", message: () => `Wrong email format`, - validate: value => !!value.match(/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/), + validate: value => !!value.match(/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/), }; export const isNumber: InputValidator = { diff --git a/src/renderer/components/kube-object-details/kube-object-details.tsx b/src/renderer/components/kube-object-details/kube-object-details.tsx index be888c6505..e01c109fc5 100644 --- a/src/renderer/components/kube-object-details/kube-object-details.tsx +++ b/src/renderer/components/kube-object-details/kube-object-details.tsx @@ -31,7 +31,6 @@ import { apiManager } from "../../../common/k8s-api/api-manager"; import { crdStore } from "../+custom-resources/crd.store"; import { KubeObjectMenu } from "../kube-object-menu"; import { KubeObjectDetailRegistry } from "../../api/kube-object-detail-registry"; -import logger from "../../../main/logger"; import { CrdResourceDetails } from "../+custom-resources"; import { KubeObjectMeta } from "../kube-object-meta"; import { hideDetails, kubeDetailsUrlParam } from "../kube-detail-params"; @@ -62,7 +61,7 @@ export class KubeObjectDetails extends React.Component { .getStore(this.path) ?.getByPath(this.path); } catch (error) { - logger.error(`[KUBE-OBJECT-DETAILS]: failed to get store or object: ${error}`, { path: this.path }); + console.error(`[KUBE-OBJECT-DETAILS]: failed to get store or object: ${error}`, { path: this.path }); return undefined; } diff --git a/src/renderer/components/kube-object-menu/dependencies/hide-details.injectable.ts b/src/renderer/components/kube-object-menu/dependencies/hide-details.injectable.ts index 4937f97b26..fab0639190 100644 --- a/src/renderer/components/kube-object-menu/dependencies/hide-details.injectable.ts +++ b/src/renderer/components/kube-object-menu/dependencies/hide-details.injectable.ts @@ -21,7 +21,7 @@ import { hideDetails } from "../../kube-detail-params"; import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable"; -export const hideDetailsInjectable = getInjectable({ +const hideDetailsInjectable = getInjectable({ instantiate: () => hideDetails, lifecycle: lifecycleEnum.singleton, }); diff --git a/src/renderer/components/menu/menu-actions.tsx b/src/renderer/components/menu/menu-actions.tsx index 7c2ed5b7be..957147cd1b 100644 --- a/src/renderer/components/menu/menu-actions.tsx +++ b/src/renderer/components/menu/menu-actions.tsx @@ -27,7 +27,7 @@ import { observer } from "mobx-react"; import { boundMethod, cssNames } from "../../utils"; import { ConfirmDialog } from "../confirm-dialog"; import { Icon, IconProps } from "../icon"; -import { Menu, MenuItem, MenuProps } from "../menu"; +import { Menu, MenuItem, MenuProps } from "./menu"; import uniqueId from "lodash/uniqueId"; import isString from "lodash/isString"; diff --git a/src/renderer/components/menu/menu.tsx b/src/renderer/components/menu/menu.tsx index 71ca69c6a8..2ef570a938 100644 --- a/src/renderer/components/menu/menu.tsx +++ b/src/renderer/components/menu/menu.tsx @@ -243,7 +243,9 @@ export class Menu extends React.Component { break; case "Space": - case "Enter": + // fallthrough + + case "Enter": { const focusedItem = this.focusedItem; if (focusedItem) { @@ -251,10 +253,12 @@ export class Menu extends React.Component { evt.preventDefault(); } break; + } case "ArrowUp": this.focusNextItem(true); break; + case "ArrowDown": this.focusNextItem(); break; diff --git a/src/renderer/components/monaco-editor/monaco-editor.tsx b/src/renderer/components/monaco-editor/monaco-editor.tsx index 96301e8a7f..4a6a4320ba 100644 --- a/src/renderer/components/monaco-editor/monaco-editor.tsx +++ b/src/renderer/components/monaco-editor/monaco-editor.tsx @@ -24,7 +24,8 @@ import React from "react"; import { observer } from "mobx-react"; import { action, computed, makeObservable, observable, reaction } from "mobx"; import { editor, Uri } from "monaco-editor"; -import { MonacoTheme, MonacoValidator, monacoValidators } from "./index"; +import type { MonacoTheme } from "./monaco-themes"; +import { MonacoValidator, monacoValidators } from "./monaco-validators"; import { debounce, merge } from "lodash"; import { cssNames, disposer } from "../../utils"; import { UserStore } from "../../../common/user-store"; diff --git a/src/renderer/components/table/react-table.tsx b/src/renderer/components/table/react-table.tsx index de001c2a9c..e5cedff78f 100644 --- a/src/renderer/components/table/react-table.tsx +++ b/src/renderer/components/table/react-table.tsx @@ -20,8 +20,7 @@ */ import styles from "./react-table.module.scss"; -import React from "react"; -import { useCallback, useMemo } from "react"; +import React, { useCallback, useMemo } from "react"; import { useFlexLayout, useSortBy, useTable, UseTableOptions } from "react-table"; import { Icon } from "../icon"; import { cssNames } from "../../utils"; diff --git a/src/renderer/port-forward/port-forward-dialog.tsx b/src/renderer/port-forward/port-forward-dialog.tsx index c9d9046d01..8ea7181967 100644 --- a/src/renderer/port-forward/port-forward-dialog.tsx +++ b/src/renderer/port-forward/port-forward-dialog.tsx @@ -31,7 +31,8 @@ import { Notifications } from "../components/notifications"; import { cssNames } from "../utils"; import { getPortForwards } from "./port-forward-store/port-forward-store"; import type { ForwardedPort } from "./port-forward-item"; -import { aboutPortForwarding, openPortForward } from "."; +import { openPortForward } from "./port-forward-utils"; +import { aboutPortForwarding } from "./port-forward-notify"; import { Checkbox } from "../components/checkbox"; import { withInjectables } from "@ogre-tools/injectable-react"; import modifyPortForwardInjectable from "./port-forward-store/modify-port-forward/modify-port-forward.injectable"; diff --git a/src/renderer/search-store/search-store.ts b/src/renderer/search-store/search-store.ts index a6aa540593..3c2df6897c 100644 --- a/src/renderer/search-store/search-store.ts +++ b/src/renderer/search-store/search-store.ts @@ -33,7 +33,7 @@ export class SearchStore { * @param value Unescaped string */ public static escapeRegex(value?: string): string { - return value ? value.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&") : ""; + return value ? value.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&") : ""; } /** diff --git a/src/renderer/theme.store.ts b/src/renderer/theme.store.ts index 144ecf7d47..15aa055f92 100644 --- a/src/renderer/theme.store.ts +++ b/src/renderer/theme.store.ts @@ -27,6 +27,7 @@ import lensDarkThemeJson from "./themes/lens-dark.json"; import lensLightThemeJson from "./themes/lens-light.json"; import type { SelectOption } from "./components/select"; import type { MonacoEditorProps } from "./components/monaco-editor"; +import { defaultTheme } from "../common/vars"; export type ThemeId = string; @@ -40,7 +41,6 @@ export interface Theme { } export class ThemeStore extends Singleton { - static readonly defaultTheme = "lens-dark"; protected styles: HTMLStyleElement; // bundled themes from `themes/${themeId}.json` @@ -54,7 +54,7 @@ export class ThemeStore extends Singleton { } @computed get activeTheme(): Theme { - return this.themes.get(this.activeThemeId) ?? this.themes.get(ThemeStore.defaultTheme); + return this.themes.get(this.activeThemeId) ?? this.themes.get(defaultTheme); } @computed get themeOptions(): SelectOption[] { diff --git a/src/renderer/utils/storageHelper.ts b/src/renderer/utils/storageHelper.ts index 0fbb9e29db..ce955de387 100755 --- a/src/renderer/utils/storageHelper.ts +++ b/src/renderer/utils/storageHelper.ts @@ -20,16 +20,8 @@ */ // Helper for working with storages (e.g. window.localStorage, NodeJS/file-system, etc.) -import { - action, - comparer, - computed, - makeObservable, - observable, - toJS, - when, -} from "mobx"; -import produce, { Draft, isDraft } from "immer"; +import { action, comparer, computed, makeObservable, observable, toJS, when } from "mobx"; +import { produce, Draft, isDraft } from "immer"; import { isEqual, isPlainObject } from "lodash"; import logger from "../../main/logger"; @@ -142,7 +134,7 @@ export class StorageHelper { get(): T { return this.value; } - + @computed get value(): T { return this.data.get() ?? this.defaultValue; diff --git a/webpack.main.ts b/webpack.main.ts index f18dba4c0b..a3967dd071 100755 --- a/webpack.main.ts +++ b/webpack.main.ts @@ -27,6 +27,7 @@ import nodeExternals from "webpack-node-externals"; import ProgressBarPlugin from "progress-bar-webpack-plugin"; import * as vars from "./src/common/vars"; import getTSLoader from "./src/common/getTSLoader"; +import CircularDependencyPlugin from "circular-dependency-plugin"; const configs: { (): webpack.Configuration }[] = []; @@ -64,6 +65,12 @@ configs.push((): webpack.Configuration => { plugins: [ new ProgressBarPlugin(), new ForkTsCheckerPlugin(), + + new CircularDependencyPlugin({ + cwd: __dirname, + exclude: /node_modules/, + failOnError: true, + }), ].filter(Boolean), }; }); diff --git a/webpack.renderer.ts b/webpack.renderer.ts index 4e07d42ffb..8be6eb35dc 100755 --- a/webpack.renderer.ts +++ b/webpack.renderer.ts @@ -30,6 +30,7 @@ import ProgressBarPlugin from "progress-bar-webpack-plugin"; import ReactRefreshWebpackPlugin from "@pmmmwh/react-refresh-webpack-plugin"; import MonacoWebpackPlugin from "monaco-editor-webpack-plugin"; import getTSLoader from "./src/common/getTSLoader"; +import CircularDependencyPlugin from "circular-dependency-plugin"; export default [ webpackLensRenderer, @@ -173,6 +174,12 @@ export function webpackLensRenderer({ showVars = true } = {}): webpack.Configura inject: true, }), + new CircularDependencyPlugin({ + cwd: __dirname, + exclude: /node_modules/, + failOnError: true, + }), + new MiniCssExtractPlugin({ filename: "[name].css", }), diff --git a/yarn.lock b/yarn.lock index d30cb4777d..9437aff4b7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1358,6 +1358,13 @@ dependencies: moment "^2.10.2" +"@types/circular-dependency-plugin@5.0.4": + version "5.0.4" + resolved "https://registry.yarnpkg.com/@types/circular-dependency-plugin/-/circular-dependency-plugin-5.0.4.tgz#c5ccbd1d2bbb39b60e9859b39c6b826f60567ef2" + integrity sha512-J4XkMJfkGv3o3q2Ca821cufIBNBFms45fz+xD9tEESR0YqL5BlwETOwm2desSCdki2zdcPRhG9ZQCm/WITCEPQ== + dependencies: + "@types/webpack" "^4" + "@types/clean-css@*": version "4.2.1" resolved "https://registry.yarnpkg.com/@types/clean-css/-/clean-css-4.2.1.tgz#cb0134241ec5e6ede1b5344bc829668fd9871a8d" @@ -2711,6 +2718,15 @@ array-unique@^0.3.2: resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= +array.prototype.flat@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz#07e0975d84bbc7c48cd1879d609e682598d33e13" + integrity sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.0" + array.prototype.flatmap@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.2.5.tgz#908dc82d8a406930fdf38598d51e7411d18d4446" @@ -3415,17 +3431,17 @@ cacheable-request@^6.0.0: normalize-url "^4.1.0" responselike "^1.0.2" -cacheable-request@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.1.tgz#062031c2856232782ed694a257fa35da93942a58" - integrity sha512-lt0mJ6YAnsrBErpTMWeu5kl/tg9xMAWjavYTN6VQXM1A/teBITuNcccXsCxF0tDQQJf9DfAaX5O4e0zp0KlfZw== +cacheable-request@^7.0.2: + version "7.0.2" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-7.0.2.tgz#ea0d0b889364a25854757301ca12b2da77f91d27" + integrity sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew== dependencies: clone-response "^1.0.2" get-stream "^5.1.0" http-cache-semantics "^4.0.0" keyv "^4.0.0" lowercase-keys "^2.0.0" - normalize-url "^4.1.0" + normalize-url "^6.0.1" responselike "^2.0.0" call-bind@^1.0.0: @@ -4431,21 +4447,28 @@ debug@3.1.0, debug@~3.1.0: dependencies: ms "2.0.0" -debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2: +debug@4, debug@^4.3.2: version "4.3.2" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== dependencies: ms "2.1.2" -debug@4.3.1: +debug@4.3.1, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: version "4.3.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== dependencies: ms "2.1.2" -debug@^3.0.0, debug@^3.1.0, debug@^3.1.1, debug@^3.2.6: +debug@^3.0.0, debug@^3.1.1, debug@^3.2.6: + version "3.2.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== + dependencies: + ms "^2.1.1" + +debug@^3.1.0, debug@^3.2.7: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== @@ -4853,10 +4876,10 @@ domhandler@^2.3.0: dependencies: domelementtype "1" -dompurify@^2.3.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.3.3.tgz#c1af3eb88be47324432964d8abc75cf4b98d634c" - integrity sha512-dqnqRkPMAjOZE0FogZ+ceJNM2dZ3V/yNOuFB7+39qpO93hHhfRpHw3heYQC7DPK9FqbQTfBKUJhiSfz4MvXYwg== +dompurify@^2.3.4: + version "2.3.4" + resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.3.4.tgz#1cf5cf0105ccb4debdf6db162525bd41e6ddacc6" + integrity sha512-6BVcgOAVFXjI0JTjEvZy901Rghm+7fDQOrNIcxB4+gdhj6Kwp6T9VBhBY/AbagKHJocRkDYGd6wvI+p4/10xtQ== domutils@1.5.1: version "1.5.1" @@ -5436,11 +5459,47 @@ escodegen@^2.0.0: optionalDependencies: source-map "~0.6.1" +eslint-import-resolver-node@^0.3.6: + version "0.3.6" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz#4048b958395da89668252001dbd9eca6b83bacbd" + integrity sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw== + dependencies: + debug "^3.2.7" + resolve "^1.20.0" + +eslint-module-utils@^2.7.1: + version "2.7.1" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.1.tgz#b435001c9f8dd4ab7f6d0efcae4b9696d4c24b7c" + integrity sha512-fjoetBXQZq2tSTWZ9yWVl2KuFrTZZH3V+9iD1V1RfpDgxzJR+mPd/KZmMiA8gbPqdBzpNiEHOuT7IYEWxrH0zQ== + dependencies: + debug "^3.2.7" + find-up "^2.1.0" + pkg-dir "^2.0.0" + eslint-plugin-header@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/eslint-plugin-header/-/eslint-plugin-header-3.1.1.tgz#6ce512432d57675265fac47292b50d1eff11acd6" integrity sha512-9vlKxuJ4qf793CmeeSrZUvVClw6amtpghq3CuWcB5cUNnWHQhgcqy5eF8oVKFk1G3Y/CbchGfEaw3wiIJaNmVg== +eslint-plugin-import@^2.25.3: + version "2.25.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.25.3.tgz#a554b5f66e08fb4f6dc99221866e57cfff824766" + integrity sha512-RzAVbby+72IB3iOEL8clzPLzL3wpDrlwjsTBAQXgyp5SeTqqY+0bFubwuo+y/HLhNZcXV4XqTBO4LGsfyHIDXg== + dependencies: + array-includes "^3.1.4" + array.prototype.flat "^1.2.5" + debug "^2.6.9" + doctrine "^2.1.0" + eslint-import-resolver-node "^0.3.6" + eslint-module-utils "^2.7.1" + has "^1.0.3" + is-core-module "^2.8.0" + is-glob "^4.0.3" + minimatch "^3.0.4" + object.values "^1.1.5" + resolve "^1.20.0" + tsconfig-paths "^3.11.0" + eslint-plugin-react-hooks@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.3.0.tgz#318dbf312e06fab1c835a4abef00121751ac1172" @@ -6039,7 +6098,7 @@ find-root@^1.1.0: resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng== -find-up@^2.0.0: +find-up@^2.0.0, find-up@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= @@ -6593,17 +6652,17 @@ globby@^6.1.0: pify "^2.0.0" pinkie-promise "^2.0.0" -got@^11.8.0, got@^11.8.2: - version "11.8.2" - resolved "https://registry.yarnpkg.com/got/-/got-11.8.2.tgz#7abb3959ea28c31f3576f1576c1effce23f33599" - integrity sha512-D0QywKgIe30ODs+fm8wMZiAcZjypcCodPNuMz5H9Mny7RJ+IjJ10BdmGW7OM7fHXP+O7r6ZwapQ/YQmMSvB0UQ== +got@^11.8.0, got@^11.8.3: + version "11.8.3" + resolved "https://registry.yarnpkg.com/got/-/got-11.8.3.tgz#f496c8fdda5d729a90b4905d2b07dbd148170770" + integrity sha512-7gtQ5KiPh1RtGS9/Jbv1ofDpBFuq42gyfEib+ejaRBJuj/3tQFeR5+gw57e4ipaU8c/rCjvX6fkQz2lyDlGAOg== dependencies: "@sindresorhus/is" "^4.0.0" "@szmarczak/http-timer" "^4.0.5" "@types/cacheable-request" "^6.0.1" "@types/responselike" "^1.0.0" cacheable-lookup "^5.0.3" - cacheable-request "^7.0.1" + cacheable-request "^7.0.2" decompress-response "^6.0.0" http2-wrapper "^1.0.0-beta.5.2" lowercase-keys "^2.0.0" @@ -7439,6 +7498,13 @@ is-core-module@^2.2.0: dependencies: has "^1.0.3" +is-core-module@^2.8.0: + version "2.8.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.0.tgz#0321336c3d0925e497fd97f5d95cb114a5ccd548" + integrity sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw== + dependencies: + has "^1.0.3" + is-data-descriptor@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" @@ -9885,6 +9951,11 @@ normalize-url@^4.1.0: resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a" integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA== +normalize-url@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" + integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== + npm-audit-report@^1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/npm-audit-report/-/npm-audit-report-1.3.3.tgz#8226deeb253b55176ed147592a3995442f2179ed" @@ -10823,6 +10894,13 @@ pirates@^4.0.1: dependencies: node-modules-regexp "^1.0.0" +pkg-dir@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" + integrity sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s= + dependencies: + find-up "^2.1.0" + pkg-dir@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" @@ -13527,9 +13605,9 @@ truncate-utf8-bytes@^1.0.0: utf8-byte-length "^1.0.1" ts-essentials@^7.0.2: - version "7.0.3" - resolved "https://registry.yarnpkg.com/ts-essentials/-/ts-essentials-7.0.3.tgz#686fd155a02133eedcc5362dc8b5056cde3e5a38" - integrity sha512-8+gr5+lqO3G84KdiTSMRLtuyJ+nTBVRKuCrK4lidMPdVeEp0uqC875uE5NMcaA7YYMN7XsNiFQuMvasF8HT/xQ== + version "7.0.2" + resolved "https://registry.yarnpkg.com/ts-essentials/-/ts-essentials-7.0.2.tgz#e21142df8034dbd444cb9573ed204d0b85fc64fb" + integrity sha512-qWPVC1xZGdefbsgFP7tPo+bsgSA2ZIXL1XeEe5M2WoMZxIOr/HbsHxP/Iv75IFhiMHMDGL7cOOwi5SXcgx9mHw== ts-jest@26.5.6: version "26.5.6" @@ -13576,6 +13654,16 @@ ts-node@^10.4.0: make-error "^1.1.1" yn "3.1.1" +tsconfig-paths@^3.11.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz#19769aca6ee8f6a1a341e38c8fa45dd9fb18899b" + integrity sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg== + dependencies: + "@types/json5" "^0.0.29" + json5 "^1.0.1" + minimist "^1.2.0" + strip-bom "^3.0.0" + tsconfig-paths@^3.9.0: version "3.9.0" resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz#098547a6c4448807e8fcb8eae081064ee9a3c90b" @@ -13674,7 +13762,12 @@ type-fest@^0.8.1: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== -type-fest@^1.0.2, type-fest@^1.4.0: +type-fest@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-1.0.2.tgz#3f9c39982859f385c77c38b7e5f1432b8a3661c6" + integrity sha512-a720oz3Kjbp3ll0zkeN9qjRhO7I34MKMhPGQiQJAmaZQZQ1lo+NWThK322f7sXV+kTg9B1Ybt16KgBXWgteT8w== + +type-fest@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-1.4.0.tgz#e9fb813fe3bf1744ec359d55d1affefa76f14be1" integrity sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==