diff --git a/.gitignore b/.gitignore index 53701a44d2..d6efc880e7 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ static/build/** binaries/client/ binaries/server/ locales/**/**.js +lens.log diff --git a/Makefile b/Makefile index 068116b3ba..54dcd6fc94 100644 --- a/Makefile +++ b/Makefile @@ -28,7 +28,7 @@ endif lint: yarn lint -test: +test: download-bins yarn test integration-linux: diff --git a/package.json b/package.json index 82442c1829..80e5b32de4 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "kontena-lens", "productName": "Lens", "description": "Lens - The Kubernetes IDE", - "version": "3.6.0-beta.1", + "version": "3.6.0-beta.2", "main": "static/build/main.js", "copyright": "© 2020, Mirantis, Inc.", "license": "MIT", @@ -254,8 +254,8 @@ "@types/webpack": "^4.41.17", "@types/webpack-env": "^1.15.2", "@types/webpack-node-externals": "^1.7.1", - "@typescript-eslint/eslint-plugin": "^3.4.0", - "@typescript-eslint/parser": "^3.4.0", + "@typescript-eslint/eslint-plugin": "^4.0.0", + "@typescript-eslint/parser": "^4.0.0", "ace-builds": "^1.4.11", "ansi_up": "^4.0.4", "babel-core": "^7.0.0-beta.3", @@ -274,7 +274,7 @@ "electron-builder": "^22.7.0", "electron-notarize": "^0.3.0", "electron-rebuild": "^1.11.0", - "eslint": "^7.3.1", + "eslint": "^7.7.0", "file-loader": "^6.0.0", "flex.box": "^3.4.4", "fork-ts-checker-webpack-plugin": "^5.0.0", diff --git a/src/main/helm/helm-repo-manager.ts b/src/main/helm/helm-repo-manager.ts index 2c132311c3..3bbec7841f 100644 --- a/src/main/helm/helm-repo-manager.ts +++ b/src/main/helm/helm-repo-manager.ts @@ -46,6 +46,7 @@ export class HelmRepoManager extends Singleton { } async init() { + helmCli.setLogger(logger) await helmCli.ensureBinary(); if (!this.initialized) { this.helmEnv = await this.parseHelmEnv() diff --git a/src/main/index.ts b/src/main/index.ts index 3014b78c41..e4fd246467 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -21,7 +21,7 @@ import logger from "./logger" const workingDir = path.join(app.getPath("appData"), appName); app.setName(appName); -if(!process.env.CICD) { +if (!process.env.CICD) { app.setPath("userData", workingDir); } @@ -49,7 +49,8 @@ async function main() { try { proxyPort = await getFreePort() } catch (error) { - await dialog.showErrorBox("Lens Error", "Could not find a free port for the cluster proxy") + logger.error(error) + dialog.showErrorBox("Lens Error", "Could not find a free port for the cluster proxy") app.quit(); } @@ -68,7 +69,7 @@ async function main() { proxyServer = LensProxy.create(proxyPort, clusterManager); } catch (error) { logger.error(`Could not start proxy (127.0.0:${proxyPort}): ${error.message}`) - await dialog.showErrorBox("Lens Error", `Could not start proxy (127.0.0:${proxyPort}): ${error.message || "unknown error"}`) + dialog.showErrorBox("Lens Error", `Could not start proxy (127.0.0:${proxyPort}): ${error.message || "unknown error"}`) app.quit(); } diff --git a/src/main/kube-auth-proxy.ts b/src/main/kube-auth-proxy.ts index b388720cce..33521fdcf5 100644 --- a/src/main/kube-auth-proxy.ts +++ b/src/main/kube-auth-proxy.ts @@ -44,6 +44,10 @@ export class KubeAuthProxy { } logger.debug(`spawning kubectl proxy with args: ${args}`) this.proxyProcess = spawn(proxyBin, args, { env: this.env, }) + this.proxyProcess.on("error", (error) => { + this.sendIpcLogMessage({ data: error.message, error: true }) + this.exit() + }) this.proxyProcess.on("exit", (code) => { this.sendIpcLogMessage({ data: `proxy exited with code: ${code}`, error: code > 0 }) diff --git a/src/main/kubectl.ts b/src/main/kubectl.ts index a48026a515..8973d6e3b8 100644 --- a/src/main/kubectl.ts +++ b/src/main/kubectl.ts @@ -22,9 +22,10 @@ const kubectlMap: Map = new Map([ ["1.13", "1.13.12"], ["1.14", "1.14.10"], ["1.15", "1.15.11"], - ["1.16", "1.16.8"], + ["1.16", "1.16.14"], ["1.17", bundledVersion], - ["1.18", "1.18.0"] + ["1.18", "1.18.8"], + ["1.19", "1.19.0"] ]) const packageMirrors: Map = new Map([ @@ -36,7 +37,8 @@ let bundledPath: string const initScriptVersionString = "# lens-initscript v3\n" if (isDevelopment || isTestEnv) { - bundledPath = path.join(process.cwd(), "binaries", "client", process.platform, process.arch, "kubectl") + const platformName = isWindows ? "windows" : process.platform + bundledPath = path.join(process.cwd(), "binaries", "client", platformName, process.arch, "kubectl") } else { bundledPath = path.join(process.resourcesPath, process.arch, "kubectl") } @@ -58,6 +60,7 @@ export class Kubectl { public static readonly bundledKubectlPath = bundledPath public static readonly bundledKubectlVersion: string = bundledVersion + public static invalidBundle = false private static bundledInstance: Kubectl; // Returns the single bundled Kubectl instance @@ -98,9 +101,22 @@ export class Kubectl { this.path = path.join(this.dirname, binaryName) } - public async getPath(): Promise { + public getBundledPath() { + return Kubectl.bundledKubectlPath + } + + public async getPath(bundled = false): Promise { + // return binary name if bundled path is not functional + if (!await this.checkBinary(this.getBundledPath(), false)) { + Kubectl.invalidBundle = true + return path.basename(bundledPath) + } + try { - await this.ensureKubectl() + if (!await this.ensureKubectl()) { + logger.error("Failed to ensure kubectl, fallback to the bundled version") + return Kubectl.bundledKubectlPath + } return this.path } catch (err) { logger.error("Failed to ensure kubectl, fallback to the bundled version") @@ -119,16 +135,15 @@ export class Kubectl { } } - public async checkBinary(checkVersion = true) { - const exists = await pathExists(this.path) + public async checkBinary(path: string, checkVersion = true) { + const exists = await pathExists(path) if (exists) { - if (!checkVersion) { - return true - } - try { - const { stdout } = await promiseExec(`"${this.path}" version --client=true -o json`) + const { stdout } = await promiseExec(`"${path}" version --client=true -o json`) const output = JSON.parse(stdout) + if (!checkVersion) { + return true + } let version: string = output.clientVersion.gitVersion if (version[0] === 'v') { version = version.slice(1) @@ -165,15 +180,28 @@ export class Kubectl { } public async ensureKubectl(): Promise { + if (Kubectl.invalidBundle) { + logger.error(`Detected invalid bundle binary, returning ...`) + return false + } await ensureDir(this.dirname, 0o755) return lockFile.lock(this.dirname).then(async (release) => { logger.debug(`Acquired a lock for ${this.kubectlVersion}`) const bundled = await this.checkBundled() - const isValid = await this.checkBinary(!bundled) - if (!isValid) { + let isValid = await this.checkBinary(this.path, !bundled) + if (!isValid && !bundled) { await this.downloadKubectl().catch((error) => { logger.error(error) + logger.debug(`Releasing lock for ${this.kubectlVersion}`) + release() + return false }); + isValid = !await this.checkBinary(this.path, false) + } + if(!isValid) { + logger.debug(`Releasing lock for ${this.kubectlVersion}`) + release() + return false } await this.writeInitScripts().catch((error) => { logger.error("Failed to write init scripts"); diff --git a/src/main/kubectl_spec.ts b/src/main/kubectl_spec.ts index 005361dfa3..4e5cdbf986 100644 --- a/src/main/kubectl_spec.ts +++ b/src/main/kubectl_spec.ts @@ -1,5 +1,7 @@ import packageInfo from "../../package.json" +import path from "path" import { bundledKubectl, Kubectl } from "../../src/main/kubectl"; +import { isWindows } from "../common/vars"; jest.mock("../common/user-store"); @@ -15,3 +17,29 @@ describe("kubectlVersion", () => { expect(kubectl.kubectlVersion).toBe(bundledKubectl.kubectlVersion) }) }) + +describe("getPath()", () => { + it("returns path to downloaded kubectl binary", async () => { + const { bundledKubectlVersion } = packageInfo.config; + const kubectl = new Kubectl(bundledKubectlVersion); + const kubectlPath = await kubectl.getPath() + let binaryName = "kubectl" + if (isWindows) { + binaryName += ".exe" + } + const expectedPath = path.join(Kubectl.kubectlDir, Kubectl.bundledKubectlVersion, binaryName) + expect(kubectlPath).toBe(expectedPath) + }) + + it("returns plain binary name if bundled kubectl is non-functional", async () => { + const { bundledKubectlVersion } = packageInfo.config; + const kubectl = new Kubectl(bundledKubectlVersion); + jest.spyOn(kubectl, "getBundledPath").mockReturnValue("/invalid/path/kubectl") + const kubectlPath = await kubectl.getPath() + let binaryName = "kubectl" + if (isWindows) { + binaryName += ".exe" + } + expect(kubectlPath).toBe(binaryName) + }) +}) diff --git a/src/main/lens-binary.ts b/src/main/lens-binary.ts index 0b0a9e1933..dd6f2aa058 100644 --- a/src/main/lens-binary.ts +++ b/src/main/lens-binary.ts @@ -1,10 +1,10 @@ import path from "path" import fs from "fs" import request from "request" -import logger from "./logger" import { ensureDir, pathExists } from "fs-extra" import * as tar from "tar" import { isWindows } from "../common/vars"; +import winston from "winston" export type LensBinaryOpts = { version: string; @@ -27,6 +27,7 @@ export class LensBinary { protected arch: string protected originalBinaryName: string protected requestOpts: request.Options + protected logger: Console | winston.Logger constructor(opts: LensBinaryOpts) { const baseDir = opts.baseDir @@ -34,7 +35,7 @@ export class LensBinary { this.binaryName = opts.newBinaryName || opts.originalBinaryName this.binaryVersion = opts.version this.requestOpts = opts.requestOpts - + this.logger = console let arch = null if (process.arch == "x64") { @@ -59,6 +60,10 @@ export class LensBinary { } } + public setLogger(logger: Console | winston.Logger) { + this.logger = logger + } + protected binaryDir() { throw new Error("binaryDir not implemented") } @@ -93,7 +98,7 @@ export class LensBinary { await this.ensureBinary() return this.dirname } catch (err) { - logger.error(err) + this.logger.error(err) return "" } } @@ -107,17 +112,17 @@ export class LensBinary { const isValid = await this.checkBinary() if (!isValid) { await this.downloadBinary().catch((error) => { - logger.error(error) + this.logger.error(error) }); if (this.tarPath) await this.untarBinary() if (this.originalBinaryName != this.binaryName) await this.renameBinary() - logger.info(`${this.originalBinaryName} has been downloaded to ${this.getBinaryPath()}`) + this.logger.info(`${this.originalBinaryName} has been downloaded to ${this.getBinaryPath()}`) } } protected async untarBinary() { return new Promise((resolve, reject) => { - logger.debug(`Extracting ${this.originalBinaryName} binary`) + this.logger.debug(`Extracting ${this.originalBinaryName} binary`) tar.x({ file: this.tarPath, cwd: this.dirname @@ -129,7 +134,7 @@ export class LensBinary { protected async renameBinary() { return new Promise((resolve, reject) => { - logger.debug(`Renaming ${this.originalBinaryName} binary to ${this.binaryName}`) + this.logger.debug(`Renaming ${this.originalBinaryName} binary to ${this.binaryName}`) fs.rename(this.getOriginalBinaryPath(), this.getBinaryPath(), (err) => { if (err) { reject(err) @@ -148,7 +153,7 @@ export class LensBinary { const file = fs.createWriteStream(binaryPath) const url = this.getUrl() - logger.info(`Downloading ${this.originalBinaryName} ${this.binaryVersion} from ${url} to ${binaryPath}`) + this.logger.info(`Downloading ${this.originalBinaryName} ${this.binaryVersion} from ${url} to ${binaryPath}`) const requestOpts: request.UriOptions & request.CoreOptions = { uri: url, gzip: true, @@ -158,12 +163,12 @@ export class LensBinary { const stream = request(requestOpts) stream.on("complete", () => { - logger.info(`Download of ${this.originalBinaryName} finished`) + this.logger.info(`Download of ${this.originalBinaryName} finished`) file.end() }) stream.on("error", (error) => { - logger.error(error) + this.logger.error(error) fs.unlink(binaryPath, () => { // do nothing }) @@ -171,7 +176,7 @@ export class LensBinary { }) return new Promise((resolve, reject) => { file.on("close", () => { - logger.debug(`${this.originalBinaryName} binary download closed`) + this.logger.debug(`${this.originalBinaryName} binary download closed`) if (!this.tarPath) fs.chmod(binaryPath, 0o755, (err) => { if (err) reject(err); }) diff --git a/src/main/logger.ts b/src/main/logger.ts index eab9478bf0..0d720b65ac 100644 --- a/src/main/logger.ts +++ b/src/main/logger.ts @@ -1,20 +1,30 @@ +import { app, remote } from "electron"; import winston from "winston" import { isDebugging } from "../common/vars"; -const options = { - colorize: true, +const consoleOptions: winston.transports.ConsoleTransportOptions = { handleExceptions: false, - json: false, level: isDebugging ? "debug" : "info", } +const fileOptions: winston.transports.FileTransportOptions = { + handleExceptions: false, + level: isDebugging ? "debug" : "info", + filename: "lens.log", + dirname: (app || remote.app).getPath("logs"), + maxsize: 16 * 1024, + maxFiles: 16, + tailable: true, +} + const logger = winston.createLogger({ format: winston.format.combine( winston.format.colorize(), winston.format.simple(), ), transports: [ - new winston.transports.Console(options), + new winston.transports.Console(consoleOptions), + new winston.transports.File(fileOptions), ], }); diff --git a/src/renderer/api/kube-api-parse.ts b/src/renderer/api/kube-api-parse.ts index d5e61c2305..c4c93562cf 100644 --- a/src/renderer/api/kube-api-parse.ts +++ b/src/renderer/api/kube-api-parse.ts @@ -121,6 +121,8 @@ export function lookupApiLink(ref: IKubeObjectRef, parentObject: KubeObject): st namespace = parentObject.getNs() } = ref; + if (!kind) return ""; + // search in registered apis by 'kind' & 'apiVersion' const api = apiManager.getApi(api => api.kind === kind && api.apiVersionWithGroup == apiVersion) if (api) { @@ -129,7 +131,7 @@ export function lookupApiLink(ref: IKubeObjectRef, parentObject: KubeObject): st // lookup api by generated resource link const apiPrefixes = ["/apis", "/api"]; - const resource = kind.toLowerCase() + kind.endsWith("s") ? "es" : "s"; + const resource = kind.endsWith("s") ? `${kind.toLowerCase()}es` : `${kind.toLowerCase()}s`; for (const apiPrefix of apiPrefixes) { const apiLink = createKubeApiURL({ apiPrefix, apiVersion, name, namespace, resource }); if (apiManager.getApi(apiLink)) { diff --git a/src/renderer/navigation.ts b/src/renderer/navigation.ts index df738b1ef4..ce831feac4 100644 --- a/src/renderer/navigation.ts +++ b/src/renderer/navigation.ts @@ -69,6 +69,7 @@ export function getSelectedDetails() { } export function getDetailsUrl(details: string) { + if (!details) return ""; return getQueryString({ details: details, selected: getSelectedDetails(), diff --git a/static/RELEASE_NOTES.md b/static/RELEASE_NOTES.md index 86356647ac..6e53eb990d 100644 --- a/static/RELEASE_NOTES.md +++ b/static/RELEASE_NOTES.md @@ -2,7 +2,12 @@ Here you can find description of changes we've built into each release. While we try our best to make each upgrade automatic and as smooth as possible, there may be some cases where you might need to do something to ensure the application works smoothly. So please read through the release highlights! -## 3.6.0-beta.1 (current version) +## 3.6.0-beta.2 (current version) +- Fix: too narrow sidebar without clusters +- Fix app crash when iterating Events without 'kind' property defined +- Detect non-functional bundled kubectl + +## 3.6.0-beta.1 - Allow user to select Kubeconfig from filesystem - Store reference to added Kubeconfig files - Show the path of the cluster's Kubeconfig in cluster settings diff --git a/yarn.lock b/yarn.lock index 9e75e68c2d..e8b6134b1a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1545,6 +1545,27 @@ prop-types "^15.7.2" react-is "^16.8.0" +"@nodelib/fs.scandir@2.1.3": + version "2.1.3" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz#3a582bdb53804c6ba6d146579c46e52130cf4a3b" + integrity sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw== + dependencies: + "@nodelib/fs.stat" "2.0.3" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.3", "@nodelib/fs.stat@^2.0.2": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz#34dc5f4cabbc720f4e60f75a747e7ecd6c175bd3" + integrity sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz#011b9202a70a6366e436ca5c065844528ab04976" + integrity sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ== + dependencies: + "@nodelib/fs.scandir" "2.1.3" + fastq "^1.6.0" + "@npmcli/move-file@^1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-1.0.1.tgz#de103070dac0f48ce49cf6693c23af59c0f70464" @@ -1710,11 +1731,6 @@ dependencies: electron "*" -"@types/eslint-visitor-keys@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d" - integrity sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag== - "@types/fs-extra@^9.0.1": version "9.0.1" resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-9.0.1.tgz#91c8fc4c51f6d5dbe44c2ca9ab09310bd00c7918" @@ -2228,51 +2244,76 @@ dependencies: "@types/node" "*" -"@typescript-eslint/eslint-plugin@^3.4.0": - version "3.4.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-3.4.0.tgz#8378062e6be8a1d049259bdbcf27ce5dfbeee62b" - integrity sha512-wfkpiqaEVhZIuQRmudDszc01jC/YR7gMSxa6ulhggAe/Hs0KVIuo9wzvFiDbG3JD5pRFQoqnf4m7REDsUvBnMQ== +"@typescript-eslint/eslint-plugin@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.0.0.tgz#99349a501447fed91de18346705c0c65cf603bee" + integrity sha512-5e6q1TR7gS2P+8W2xndCu7gBh3BzmYEo70OyIdsmCmknHha/yNbz2vdevl+tP1uoaMOcrzg4gyrAijuV3DDBHA== dependencies: - "@typescript-eslint/experimental-utils" "3.4.0" + "@typescript-eslint/experimental-utils" "4.0.0" + "@typescript-eslint/scope-manager" "4.0.0" debug "^4.1.1" functional-red-black-tree "^1.0.1" regexpp "^3.0.0" semver "^7.3.2" tsutils "^3.17.1" -"@typescript-eslint/experimental-utils@3.4.0": - version "3.4.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-3.4.0.tgz#8a44dfc6fb7f1d071937b390fe27608ebda122b8" - integrity sha512-rHPOjL43lOH1Opte4+dhC0a/+ks+8gOBwxXnyrZ/K4OTAChpSjP76fbI8Cglj7V5GouwVAGaK+xVwzqTyE/TPw== +"@typescript-eslint/experimental-utils@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.0.0.tgz#fbec21a3b5ab59127edb6ce2e139ed378cc50eb5" + integrity sha512-hbX6zR+a/vcpFVNJYN/Nbd7gmaMosDTxHEKcvmhWeWcq/0UDifrqmCfkkodbAKL46Fn4ekSBMTyq2zlNDzcQxw== dependencies: "@types/json-schema" "^7.0.3" - "@typescript-eslint/typescript-estree" "3.4.0" + "@typescript-eslint/scope-manager" "4.0.0" + "@typescript-eslint/types" "4.0.0" + "@typescript-eslint/typescript-estree" "4.0.0" eslint-scope "^5.0.0" eslint-utils "^2.0.0" -"@typescript-eslint/parser@^3.4.0": - version "3.4.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-3.4.0.tgz#fe52b68c5cb3bba3f5d875bd17adb70420d49d8d" - integrity sha512-ZUGI/de44L5x87uX5zM14UYcbn79HSXUR+kzcqU42gH0AgpdB/TjuJy3m4ezI7Q/jk3wTQd755mxSDLhQP79KA== - dependencies: - "@types/eslint-visitor-keys" "^1.0.0" - "@typescript-eslint/experimental-utils" "3.4.0" - "@typescript-eslint/typescript-estree" "3.4.0" - eslint-visitor-keys "^1.1.0" - -"@typescript-eslint/typescript-estree@3.4.0": - version "3.4.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-3.4.0.tgz#6a787eb70b48969e4cd1ea67b057083f96dfee29" - integrity sha512-zKwLiybtt4uJb4mkG5q2t6+W7BuYx2IISiDNV+IY68VfoGwErDx/RfVI7SWL4gnZ2t1A1ytQQwZ+YOJbHHJ2rw== +"@typescript-eslint/parser@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.0.0.tgz#0b19c25ad404b617caf33121e05f7dad14a594aa" + integrity sha512-KuBwTUzc3G3dD5k9ybTjgqIQjjJPY6WPaEoxdNS5vN5XV/Tixp0itA14+NQlbeswTHvsELaKXZhynxD/O2wHFA== dependencies: + "@typescript-eslint/scope-manager" "4.0.0" + "@typescript-eslint/types" "4.0.0" + "@typescript-eslint/typescript-estree" "4.0.0" debug "^4.1.1" - eslint-visitor-keys "^1.1.0" - glob "^7.1.6" + +"@typescript-eslint/scope-manager@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.0.0.tgz#8c9e3b3b8cdf5a1fbe671d9fad73ff67bc027ea8" + integrity sha512-9gcWUPoWo7gk/+ZQPg7L1ySRmR5HLIy3Vu6/LfhQbuzIkGm6v2CGIjpVRISoDLFRovNRDImd4aP/sa8O4yIEBg== + dependencies: + "@typescript-eslint/types" "4.0.0" + "@typescript-eslint/visitor-keys" "4.0.0" + +"@typescript-eslint/types@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.0.0.tgz#ec1f9fc06b8558a1d5afa6e337182d08beece7f5" + integrity sha512-bK+c2VLzznX2fUWLK6pFDv3cXGTp7nHIuBMq1B9klA+QCsqLHOOqe5TQReAQDl7DN2RfH+neweo0oC5hYlG7Rg== + +"@typescript-eslint/typescript-estree@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.0.0.tgz#2244c63de2f2190bc5718eb0fb3fd2c437d42097" + integrity sha512-ewFMPi2pMLDNIXGMPdf8r7El2oPSZw9PEYB0j+WcpKd7AX2ARmajGa7RUHTukllWX2bj4vWX6JLE1Oih2BMokA== + dependencies: + "@typescript-eslint/types" "4.0.0" + "@typescript-eslint/visitor-keys" "4.0.0" + debug "^4.1.1" + globby "^11.0.1" is-glob "^4.0.1" lodash "^4.17.15" semver "^7.3.2" tsutils "^3.17.1" +"@typescript-eslint/visitor-keys@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.0.0.tgz#e2bbb69d98076d6a3f06abcb2048225a74362c33" + integrity sha512-sTouJbv6rjVJeTE4lpSBVYXq/u5K3gbB6LKt7ccFEZPTZB/VeQ0ssUz9q5Hx++sCqBbdF8PzrrgvEnicXAR6NQ== + dependencies: + "@typescript-eslint/types" "4.0.0" + eslint-visitor-keys "^2.0.0" + "@webassemblyjs/ast@1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964" @@ -2476,10 +2517,10 @@ acorn@^7.1.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.2.0.tgz#17ea7e40d7c8640ff54a694c889c26f31704effe" integrity sha512-apwXVmYVpQ34m/i71vrApRrRKCWQnZZF1+npOD0WV5xZFfwWOmKGQ2RWlfdy9vWITsenisM8M0Qeq8agcFHNiQ== -acorn@^7.2.0: - version "7.3.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.3.1.tgz#85010754db53c3fbaf3b9ea3e083aa5c5d147ffd" - integrity sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA== +acorn@^7.4.0: + version "7.4.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.0.tgz#e1ad486e6c54501634c6c397c5c121daa383607c" + integrity sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w== aggregate-error@^1.0.0: version "1.0.0" @@ -2711,6 +2752,11 @@ array-find-index@^1.0.1: resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" integrity sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E= +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + array-unique@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" @@ -4399,6 +4445,13 @@ diffie-hellman@^5.0.0: miller-rabin "^4.0.0" randombytes "^2.0.0" +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + dmg-builder@22.7.0: version "22.7.0" resolved "https://registry.yarnpkg.com/dmg-builder/-/dmg-builder-22.7.0.tgz#ead7e7c046cbdc52d29d302a4455f6668cdf7d45" @@ -4855,22 +4908,27 @@ eslint-scope@^5.0.0, eslint-scope@^5.1.0: esrecurse "^4.1.0" estraverse "^4.1.1" -eslint-utils@^2.0.0: +eslint-utils@^2.0.0, eslint-utils@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27" integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== dependencies: eslint-visitor-keys "^1.1.0" -eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.2.0: +eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== -eslint@^7.3.1: - version "7.3.1" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.3.1.tgz#76392bd7e44468d046149ba128d1566c59acbe19" - integrity sha512-cQC/xj9bhWUcyi/RuMbRtC3I0eW8MH0jhRELSvpKYkWep3C6YZ2OkvcvJVUeO6gcunABmzptbXBuDoXsjHmfTA== +eslint-visitor-keys@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz#21fdc8fbcd9c795cc0321f0563702095751511a8" + integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ== + +eslint@^7.7.0: + version "7.7.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.7.0.tgz#18beba51411927c4b64da0a8ceadefe4030d6073" + integrity sha512-1KUxLzos0ZVsyL81PnRN335nDtQ8/vZUD6uMtWbF+5zDtjKcsklIi78XoE0MVL93QvWTu+E5y44VyyCsOMBrIg== dependencies: "@babel/code-frame" "^7.0.0" ajv "^6.10.0" @@ -4880,9 +4938,9 @@ eslint@^7.3.1: doctrine "^3.0.0" enquirer "^2.3.5" eslint-scope "^5.1.0" - eslint-utils "^2.0.0" - eslint-visitor-keys "^1.2.0" - espree "^7.1.0" + eslint-utils "^2.1.0" + eslint-visitor-keys "^1.3.0" + espree "^7.2.0" esquery "^1.2.0" esutils "^2.0.2" file-entry-cache "^5.0.1" @@ -4896,7 +4954,7 @@ eslint@^7.3.1: js-yaml "^3.13.1" json-stable-stringify-without-jsonify "^1.0.1" levn "^0.4.1" - lodash "^4.17.14" + lodash "^4.17.19" minimatch "^3.0.4" natural-compare "^1.4.0" optionator "^0.9.1" @@ -4909,14 +4967,14 @@ eslint@^7.3.1: text-table "^0.2.0" v8-compile-cache "^2.0.3" -espree@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/espree/-/espree-7.1.0.tgz#a9c7f18a752056735bf1ba14cb1b70adc3a5ce1c" - integrity sha512-dcorZSyfmm4WTuTnE5Y7MEN1DyoPYy1ZR783QW1FJoenn7RailyWFsq/UL6ZAAA7uXurN9FIpYyUs3OfiIW+Qw== +espree@^7.2.0: + version "7.3.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.0.tgz#dc30437cf67947cf576121ebd780f15eeac72348" + integrity sha512-dksIWsvKCixn1yrEXO8UosNSxaDoSYpq9reEjZSbHLpT5hpaCAKTLBwq0RHtLrIr+c0ByiYzWT8KTMRzoRCNlw== dependencies: - acorn "^7.2.0" + acorn "^7.4.0" acorn-jsx "^5.2.0" - eslint-visitor-keys "^1.2.0" + eslint-visitor-keys "^1.3.0" esprima@1.2.2: version "1.2.2" @@ -5133,6 +5191,18 @@ fast-deep-equal@^3.1.1: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== +fast-glob@^3.1.1: + version "3.2.4" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.4.tgz#d20aefbf99579383e7f3cc66529158c9b98554d3" + integrity sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.0" + merge2 "^1.3.0" + micromatch "^4.0.2" + picomatch "^2.2.1" + fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" @@ -5148,6 +5218,13 @@ fast-safe-stringify@^2.0.4: resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz#124aa885899261f68aedb42a7c080de9da608743" integrity sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA== +fastq@^1.6.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.8.0.tgz#550e1f9f59bbc65fe185cb6a9b4d95357107f481" + integrity sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q== + dependencies: + reusify "^1.0.4" + fb-watchman@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" @@ -5612,14 +5689,14 @@ glob-parent@^3.1.0: is-glob "^3.1.0" path-dirname "^1.0.0" -glob-parent@^5.0.0, glob-parent@~5.1.0: +glob-parent@^5.0.0, glob-parent@^5.1.0, glob-parent@~5.1.0: version "5.1.1" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ== dependencies: is-glob "^4.0.1" -glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@~7.1.1: +glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@~7.1.1: version "7.1.6" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== @@ -5716,6 +5793,18 @@ globalthis@^1.0.1: dependencies: define-properties "^1.1.3" +globby@^11.0.1: + version "11.0.1" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.1.tgz#9a2bf107a068f3ffeabc49ad702c79ede8cfd357" + integrity sha512-iH9RmgwCmUJHi2z5o2l3eTtGBtXek1OYlHrbcxOYugyHLmAsZrPj43OtHThd62Buh/Vv6VyCBD2bdyWcGNQqoQ== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.1.1" + ignore "^5.1.4" + merge2 "^1.3.0" + slash "^3.0.0" + globule@^1.0.0: version "1.3.2" resolved "https://registry.yarnpkg.com/globule/-/globule-1.3.2.tgz#d8bdd9e9e4eef8f96e245999a5dee7eb5d8529c4" @@ -6109,6 +6198,11 @@ ignore@^4.0.6: resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== +ignore@^5.1.4: + version "5.1.8" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" + integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== + immer@^7.0.5: version "7.0.5" resolved "https://registry.yarnpkg.com/immer/-/immer-7.0.5.tgz#8af347db5b60b40af8ae7baf1784ea4d35b5208e" @@ -7526,6 +7620,11 @@ lodash@^4.0.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.1 resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== +lodash@^4.17.19: + version "4.17.20" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" + integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== + log-symbols@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a" @@ -7775,6 +7874,11 @@ merge-stream@^2.0.0: resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== +merge2@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + messageformat-parser@^4.1.3: version "4.1.3" resolved "https://registry.yarnpkg.com/messageformat-parser/-/messageformat-parser-4.1.3.tgz#b824787f57fcda7d50769f5b63e8d4fda68f5b9e" @@ -9863,6 +9967,11 @@ retry@^0.12.0: resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + rfc4648@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/rfc4648/-/rfc4648-1.3.0.tgz#2a69c76f05bc0e388feab933672de9b492af95f1" @@ -9924,6 +10033,11 @@ run-async@^2.2.0, run-async@^2.4.0: resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== +run-parallel@^1.1.9: + version "1.1.9" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679" + integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q== + run-queue@^1.0.0, run-queue@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47"