Repository: Redocly/redocly-cli
Pull request #808 (2022-08-16 13:15:33)

Chore/configure eslint
## What/Why/How?

Introduces Eslint check for Redocly CLI.

Please pay special attention to [this line](https://github.com/Redocly/redocly-cli/pull/808/files#diff-47607adc7025266f655cda3df6abbd5cc9f1fbf4e9f493c7b0ba6ed6c3350614R175).

## Reference

## Testing

## Screenshots (optional)

## Check yourself

- [x] Code is linted (FINALLY)
- [x] Tested with redoc/reference-docs/workflows
- [x] All new/updated code is covered with tests

## Security

- [x] Security impact of change has been considered
- [x] Code follows company security practices and guidelines



Patch:
diff --git a/.eslintrc.yml b/.eslintrc.yml
new file mode 100644
index 00000000..56b5f6ef
--- /dev/null
+++ b/.eslintrc.yml
@@ -0,0 +1,29 @@
+env:
+  browser: true
+  es2021: true
+  node: true
+extends:
+  - eslint:recommended
+  - plugin:@typescript-eslint/recommended
+overrides: []
+parser: '@typescript-eslint/parser'
+parserOptions:
+  ecmaVersion: latest
+  sourceType: module
+plugins:
+  - '@typescript-eslint'
+rules:
+  '@typescript-eslint/no-unused-vars':
+    - error
+    - argsIgnorePattern: ^_
+      varsIgnorePattern: ^_
+  '@typescript-eslint/no-var-requires': off
+  '@typescript-eslint/no-empty-function': off
+  '@typescript-eslint/no-inferrable-types': off
+  '@typescript-eslint/ban-types': warn
+  no-prototype-builtins: off
+  no-useless-escape: warn
+ignorePatterns:
+  - '**/__tests__/'
+  - 'packages/*/lib/'
+  - '*.js'
diff --git a/jest.config.js b/jest.config.js
index 76c8b0b2..e7ea558d 100644
--- a/jest.config.js
+++ b/jest.config.js
@@ -14,7 +14,7 @@ module.exports = {
       statements: 79,
       branches: 71,
       functions: 68,
-      lines: 78,
+      lines: 79,
     },
     'packages/cli/': {
       statements: 37,
diff --git a/package-lock.json b/package-lock.json
index c84ced7d..d15f3c7c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -14,6 +14,9 @@
       "devDependencies": {
         "@types/jest": "^26.0.15",
         "@types/node": "^17.0.31",
+        "@typescript-eslint/eslint-plugin": "^5.33.0",
+        "@typescript-eslint/parser": "^5.33.0",
+        "eslint": "^8.22.0",
         "jest": "^26.6.3",
         "null-loader": "^4.0.0",
         "outdent": "^0.7.1",
@@ -593,6 +596,127 @@
         "node": ">=10.0.0"
       }
     },
+    "node_modules/@eslint/eslintrc": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz",
+      "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==",
+      "dev": true,
+      "dependencies": {
+        "ajv": "^6.12.4",
+        "debug": "^4.3.2",
+        "espree": "^9.3.2",
+        "globals": "^13.15.0",
+        "ignore": "^5.2.0",
+        "import-fresh": "^3.2.1",
+        "js-yaml": "^4.1.0",
+        "minimatch": "^3.1.2",
+        "strip-json-comments": "^3.1.1"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      }
+    },
+    "node_modules/@eslint/eslintrc/node_modules/brace-expansion": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "dev": true,
+      "dependencies": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "node_modules/@eslint/eslintrc/node_modules/globals": {
+      "version": "13.17.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz",
+      "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==",
+      "dev": true,
+      "dependencies": {
+        "type-fest": "^0.20.2"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@eslint/eslintrc/node_modules/minimatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+      "dev": true,
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/@eslint/eslintrc/node_modules/type-fest": {
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+      "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/@humanwhocodes/config-array": {
+      "version": "0.10.4",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.4.tgz",
+      "integrity": "sha512-mXAIHxZT3Vcpg83opl1wGlVZ9xydbfZO3r5YfRSH6Gpp2J/PfdBP0wbDa2sO6/qRbcalpoevVyW6A/fI6LfeMw==",
+      "dev": true,
+      "dependencies": {
+        "@humanwhocodes/object-schema": "^1.2.1",
+        "debug": "^4.1.1",
+        "minimatch": "^3.0.4"
+      },
+      "engines": {
+        "node": ">=10.10.0"
+      }
+    },
+    "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "dev": true,
+      "dependencies": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "node_modules/@humanwhocodes/config-array/node_modules/minimatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+      "dev": true,
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/@humanwhocodes/gitignore-to-minimatch": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz",
+      "integrity": "sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==",
+      "dev": true,
+      "funding": {
+        "type": "github",
+        "url": "https://github.com/sponsors/nzakas"
+      }
+    },
+    "node_modules/@humanwhocodes/object-schema": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
+      "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
+      "dev": true
+    },
     "node_modules/@istanbuljs/load-nyc-config": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
@@ -975,6 +1099,41 @@
         "@jridgewell/sourcemap-codec": "^1.4.10"
       }
     },
+    "node_modules/@nodelib/fs.scandir": {
+      "version": "2.1.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+      "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+      "dev": true,
+      "dependencies": {
+        "@nodelib/fs.stat": "2.0.5",
+        "run-parallel": "^1.1.9"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@nodelib/fs.stat": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+      "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+      "dev": true,
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@nodelib/fs.walk": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+      "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+      "dev": true,
+      "dependencies": {
+        "@nodelib/fs.scandir": "2.1.5",
+        "fastq": "^1.6.0"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
     "node_modules/@redocly/ajv": {
       "version": "8.6.5",
       "resolved": "https://registry.npmjs.org/@redocly/ajv/-/ajv-8.6.5.tgz",
@@ -1236,6 +1395,220 @@
       "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==",
       "dev": true
     },
+    "node_modules/@typescript-eslint/eslint-plugin": {
+      "version": "5.33.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.33.0.tgz",
+      "integrity": "sha512-jHvZNSW2WZ31OPJ3enhLrEKvAZNyAFWZ6rx9tUwaessTc4sx9KmgMNhVcqVAl1ETnT5rU5fpXTLmY9YvC1DCNg==",
+      "dev": true,
+      "dependencies": {
+        "@typescript-eslint/scope-manager": "5.33.0",
+        "@typescript-eslint/type-utils": "5.33.0",
+        "@typescript-eslint/utils": "5.33.0",
+        "debug": "^4.3.4",
+        "functional-red-black-tree": "^1.0.1",
+        "ignore": "^5.2.0",
+        "regexpp": "^3.2.0",
+        "semver": "^7.3.7",
+        "tsutils": "^3.21.0"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "@typescript-eslint/parser": "^5.0.0",
+        "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": {
+      "version": "7.3.7",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
+      "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
+      "dev": true,
+      "dependencies": {
+        "lru-cache": "^6.0.0"
+      },
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@typescript-eslint/parser": {
+      "version": "5.33.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.33.0.tgz",
+      "integrity": "sha512-cgM5cJrWmrDV2KpvlcSkelTBASAs1mgqq+IUGKJvFxWrapHpaRy5EXPQz9YaKF3nZ8KY18ILTiVpUtbIac86/w==",
+      "dev": true,
+      "dependencies": {
+        "@typescript-eslint/scope-manager": "5.33.0",
+        "@typescript-eslint/types": "5.33.0",
+        "@typescript-eslint/typescript-estree": "5.33.0",
+        "debug": "^4.3.4"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@typescript-eslint/scope-manager": {
+      "version": "5.33.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.33.0.tgz",
+      "integrity": "sha512-/Jta8yMNpXYpRDl8EwF/M8It2A9sFJTubDo0ATZefGXmOqlaBffEw0ZbkbQ7TNDK6q55NPHFshGBPAZvZkE8Pw==",
+      "dev": true,
+      "dependencies": {
+        "@typescript-eslint/types": "5.33.0",
+        "@typescript-eslint/visitor-keys": "5.33.0"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      }
+    },
+    "node_modules/@typescript-eslint/type-utils": {
+      "version": "5.33.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.33.0.tgz",
+      "integrity": "sha512-2zB8uEn7hEH2pBeyk3NpzX1p3lF9dKrEbnXq1F7YkpZ6hlyqb2yZujqgRGqXgRBTHWIUG3NGx/WeZk224UKlIA==",
+      "dev": true,
+      "dependencies": {
+        "@typescript-eslint/utils": "5.33.0",
+        "debug": "^4.3.4",
+        "tsutils": "^3.21.0"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "eslint": "*"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@typescript-eslint/types": {
+      "version": "5.33.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.33.0.tgz",
+      "integrity": "sha512-nIMt96JngB4MYFYXpZ/3ZNU4GWPNdBbcB5w2rDOCpXOVUkhtNlG2mmm8uXhubhidRZdwMaMBap7Uk8SZMU/ppw==",
+      "dev": true,
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      }
+    },
+    "node_modules/@typescript-eslint/typescript-estree": {
+      "version": "5.33.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.33.0.tgz",
+      "integrity": "sha512-tqq3MRLlggkJKJUrzM6wltk8NckKyyorCSGMq4eVkyL5sDYzJJcMgZATqmF8fLdsWrW7OjjIZ1m9v81vKcaqwQ==",
+      "dev": true,
+      "dependencies": {
+        "@typescript-eslint/types": "5.33.0",
+        "@typescript-eslint/visitor-keys": "5.33.0",
+        "debug": "^4.3.4",
+        "globby": "^11.1.0",
+        "is-glob": "^4.0.3",
+        "semver": "^7.3.7",
+        "tsutils": "^3.21.0"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": {
+      "version": "7.3.7",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
+      "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
+      "dev": true,
+      "dependencies": {
+        "lru-cache": "^6.0.0"
+      },
+      "bin": {
+        "semver": "bin/semver.js"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/@typescript-eslint/utils": {
+      "version": "5.33.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.33.0.tgz",
+      "integrity": "sha512-JxOAnXt9oZjXLIiXb5ZIcZXiwVHCkqZgof0O8KPgz7C7y0HS42gi75PdPlqh1Tf109M0fyUw45Ao6JLo7S5AHw==",
+      "dev": true,
+      "dependencies": {
+        "@types/json-schema": "^7.0.9",
+        "@typescript-eslint/scope-manager": "5.33.0",
+        "@typescript-eslint/types": "5.33.0",
+        "@typescript-eslint/typescript-estree": "5.33.0",
+        "eslint-scope": "^5.1.1",
+        "eslint-utils": "^3.0.0"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      },
+      "peerDependencies": {
+        "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0"
+      }
+    },
+    "node_modules/@typescript-eslint/visitor-keys": {
+      "version": "5.33.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.33.0.tgz",
+      "integrity": "sha512-/XsqCzD4t+Y9p5wd9HZiptuGKBlaZO5showwqODii5C0nZawxWLF+Q6k5wYHBrQv96h6GYKyqqMHCSTqta8Kiw==",
+      "dev": true,
+      "dependencies": {
+        "@typescript-eslint/types": "5.33.0",
+        "eslint-visitor-keys": "^3.3.0"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/typescript-eslint"
+      }
+    },
     "node_modules/@webassemblyjs/ast": {
       "version": "1.11.1",
       "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz",
@@ -1479,6 +1852,15 @@
         "acorn": "^8"
       }
     },
+    "node_modules/acorn-jsx": {
+      "version": "5.3.2",
+      "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+      "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+      "dev": true,
+      "peerDependencies": {
+        "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+      }
+    },
     "node_modules/acorn-walk": {
       "version": "7.2.0",
       "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz",
@@ -1618,6 +2000,15 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/array-union": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
+      "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/array-unique": {
       "version": "0.3.2",
       "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
@@ -2482,6 +2873,30 @@
         "node": ">= 10.14.2"
       }
     },
+    "node_modules/dir-glob": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
+      "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
+      "dev": true,
+      "dependencies": {
+        "path-type": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/doctrine": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+      "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+      "dev": true,
+      "dependencies": {
+        "esutils": "^2.0.2"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
     "node_modules/domexception": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz",
@@ -2645,6 +3060,62 @@
         "node": ">=4.0"
       }
     },
+    "node_modules/eslint": {
+      "version": "8.22.0",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.22.0.tgz",
+      "integrity": "sha512-ci4t0sz6vSRKdmkOGmprBo6fmI4PrphDFMy5JEq/fNS0gQkJM3rLmrqcp8ipMcdobH3KtUP40KniAE9W19S4wA==",
+      "dev": true,
+      "dependencies": {
+        "@eslint/eslintrc": "^1.3.0",
+        "@humanwhocodes/config-array": "^0.10.4",
+        "@humanwhocodes/gitignore-to-minimatch": "^1.0.2",
+        "ajv": "^6.10.0",
+        "chalk": "^4.0.0",
+        "cross-spawn": "^7.0.2",
+        "debug": "^4.3.2",
+        "doctrine": "^3.0.0",
+        "escape-string-regexp": "^4.0.0",
+        "eslint-scope": "^7.1.1",
+        "eslint-utils": "^3.0.0",
+        "eslint-visitor-keys": "^3.3.0",
+        "espree": "^9.3.3",
+        "esquery": "^1.4.0",
+        "esutils": "^2.0.2",
+        "fast-deep-equal": "^3.1.3",
+        "file-entry-cache": "^6.0.1",
+        "find-up": "^5.0.0",
+        "functional-red-black-tree": "^1.0.1",
+        "glob-parent": "^6.0.1",
+        "globals": "^13.15.0",
+        "globby": "^11.1.0",
+        "grapheme-splitter": "^1.0.4",
+        "ignore": "^5.2.0",
+        "import-fresh": "^3.0.0",
+        "imurmurhash": "^0.1.4",
+        "is-glob": "^4.0.0",
+        "js-yaml": "^4.1.0",
+        "json-stable-stringify-without-jsonify": "^1.0.1",
+        "levn": "^0.4.1",
+        "lodash.merge": "^4.6.2",
+        "minimatch": "^3.1.2",
+        "natural-compare": "^1.4.0",
+        "optionator": "^0.9.1",
+        "regexpp": "^3.2.0",
+        "strip-ansi": "^6.0.1",
+        "strip-json-comments": "^3.1.0",
+        "text-table": "^0.2.0",
+        "v8-compile-cache": "^2.0.3"
+      },
+      "bin": {
+        "eslint": "bin/eslint.js"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
     "node_modules/eslint-scope": {
       "version": "5.1.1",
       "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
@@ -2658,6 +3129,266 @@
         "node": ">=8.0.0"
       }
     },
+    "node_modules/eslint-utils": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz",
+      "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==",
+      "dev": true,
+      "dependencies": {
+        "eslint-visitor-keys": "^2.0.0"
+      },
+      "engines": {
+        "node": "^10.0.0 || ^12.0.0 || >= 14.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/mysticatea"
+      },
+      "peerDependencies": {
+        "eslint": ">=5"
+      }
+    },
+    "node_modules/eslint-utils/node_modules/eslint-visitor-keys": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
+      "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/eslint-visitor-keys": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
+      "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
+      "dev": true,
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      }
+    },
+    "node_modules/eslint/node_modules/brace-expansion": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "dev": true,
+      "dependencies": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "node_modules/eslint/node_modules/escape-string-regexp": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+      "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/eslint/node_modules/eslint-scope": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz",
+      "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==",
+      "dev": true,
+      "dependencies": {
+        "esrecurse": "^4.3.0",
+        "estraverse": "^5.2.0"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      }
+    },
+    "node_modules/eslint/node_modules/estraverse": {
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+      "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+      "dev": true,
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
+    "node_modules/eslint/node_modules/find-up": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+      "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+      "dev": true,
+      "dependencies": {
+        "locate-path": "^6.0.0",
+        "path-exists": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/eslint/node_modules/glob-parent": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+      "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+      "dev": true,
+      "dependencies": {
+        "is-glob": "^4.0.3"
+      },
+      "engines": {
+        "node": ">=10.13.0"
+      }
+    },
+    "node_modules/eslint/node_modules/globals": {
+      "version": "13.17.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz",
+      "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==",
+      "dev": true,
+      "dependencies": {
+        "type-fest": "^0.20.2"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/eslint/node_modules/levn": {
+      "version": "0.4.1",
+      "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+      "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+      "dev": true,
+      "dependencies": {
+        "prelude-ls": "^1.2.1",
+        "type-check": "~0.4.0"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/eslint/node_modules/locate-path": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+      "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+      "dev": true,
+      "dependencies": {
+        "p-locate": "^5.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/eslint/node_modules/minimatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+      "dev": true,
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/eslint/node_modules/optionator": {
+      "version": "0.9.1",
+      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
+      "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
+      "dev": true,
+      "dependencies": {
+        "deep-is": "^0.1.3",
+        "fast-levenshtein": "^2.0.6",
+        "levn": "^0.4.1",
+        "prelude-ls": "^1.2.1",
+        "type-check": "^0.4.0",
+        "word-wrap": "^1.2.3"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/eslint/node_modules/p-limit": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+      "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+      "dev": true,
+      "dependencies": {
+        "yocto-queue": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/eslint/node_modules/p-locate": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+      "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+      "dev": true,
+      "dependencies": {
+        "p-limit": "^3.0.2"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/eslint/node_modules/prelude-ls": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+      "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/eslint/node_modules/type-check": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+      "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
+      "dev": true,
+      "dependencies": {
+        "prelude-ls": "^1.2.1"
+      },
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
+    "node_modules/eslint/node_modules/type-fest": {
+      "version": "0.20.2",
+      "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+      "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/espree": {
+      "version": "9.3.3",
+      "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.3.tgz",
+      "integrity": "sha512-ORs1Rt/uQTqUKjDdGCyrtYxbazf5umATSf/K4qxjmZHORR6HJk+2s/2Pqe+Kk49HHINC/xNIrGfgh8sZcll0ng==",
+      "dev": true,
+      "dependencies": {
+        "acorn": "^8.8.0",
+        "acorn-jsx": "^5.3.2",
+        "eslint-visitor-keys": "^3.3.0"
+      },
+      "engines": {
+        "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+      },
+      "funding": {
+        "url": "https://opencollective.com/eslint"
+      }
+    },
     "node_modules/esprima": {
       "version": "4.0.1",
       "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
@@ -2671,6 +3402,27 @@
         "node": ">=4"
       }
     },
+    "node_modules/esquery": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
+      "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==",
+      "dev": true,
+      "dependencies": {
+        "estraverse": "^5.1.0"
+      },
+      "engines": {
+        "node": ">=0.10"
+      }
+    },
+    "node_modules/esquery/node_modules/estraverse": {
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+      "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+      "dev": true,
+      "engines": {
+        "node": ">=4.0"
+      }
+    },
     "node_modules/esrecurse": {
       "version": "4.3.0",
       "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
@@ -2989,6 +3741,22 @@
       "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
       "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
     },
+    "node_modules/fast-glob": {
+      "version": "3.2.11",
+      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz",
+      "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==",
+      "dev": true,
+      "dependencies": {
+        "@nodelib/fs.stat": "^2.0.2",
+        "@nodelib/fs.walk": "^1.2.3",
+        "glob-parent": "^5.1.2",
+        "merge2": "^1.3.0",
+        "micromatch": "^4.0.4"
+      },
+      "engines": {
+        "node": ">=8.6.0"
+      }
+    },
     "node_modules/fast-json-stable-stringify": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
@@ -3010,6 +3778,15 @@
         "node": ">= 4.9.1"
       }
     },
+    "node_modules/fastq": {
+      "version": "1.13.0",
+      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz",
+      "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==",
+      "dev": true,
+      "dependencies": {
+        "reusify": "^1.0.4"
+      }
+    },
     "node_modules/fb-watchman": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz",
@@ -3019,6 +3796,18 @@
         "bser": "2.1.1"
       }
     },
+    "node_modules/file-entry-cache": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
+      "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
+      "dev": true,
+      "dependencies": {
+        "flat-cache": "^3.0.4"
+      },
+      "engines": {
+        "node": "^10.12.0 || >=12.0.0"
+      }
+    },
     "node_modules/fill-range": {
       "version": "7.0.1",
       "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
@@ -3043,6 +3832,25 @@
         "node": ">=8"
       }
     },
+    "node_modules/flat-cache": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
+      "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
+      "dev": true,
+      "dependencies": {
+        "flatted": "^3.1.0",
+        "rimraf": "^3.0.2"
+      },
+      "engines": {
+        "node": "^10.12.0 || >=12.0.0"
+      }
+    },
+    "node_modules/flatted": {
+      "version": "3.2.6",
+      "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.6.tgz",
+      "integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==",
+      "dev": true
+    },
     "node_modules/for-in": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
@@ -3102,6 +3910,12 @@
       "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
       "dev": true
     },
+    "node_modules/functional-red-black-tree": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
+      "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==",
+      "dev": true
+    },
     "node_modules/gensync": {
       "version": "1.0.0-beta.2",
       "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
@@ -3231,12 +4045,38 @@
         "node": ">=4"
       }
     },
+    "node_modules/globby": {
+      "version": "11.1.0",
+      "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
+      "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
+      "dev": true,
+      "dependencies": {
+        "array-union": "^2.1.0",
+        "dir-glob": "^3.0.1",
+        "fast-glob": "^3.2.9",
+        "ignore": "^5.2.0",
+        "merge2": "^1.4.1",
+        "slash": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/graceful-fs": {
       "version": "4.2.10",
       "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
       "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
       "dev": true
     },
+    "node_modules/grapheme-splitter": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
+      "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
+      "dev": true
+    },
     "node_modules/growly": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz",
@@ -3420,6 +4260,40 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/ignore": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz",
+      "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==",
+      "dev": true,
+      "engines": {
+        "node": ">= 4"
+      }
+    },
+    "node_modules/import-fresh": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+      "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+      "dev": true,
+      "dependencies": {
+        "parent-module": "^1.0.0",
+        "resolve-from": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/import-fresh/node_modules/resolve-from": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+      "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+      "dev": true,
+      "engines": {
+        "node": ">=4"
+      }
+    },
     "node_modules/import-local": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz",
@@ -4670,6 +5544,12 @@
       "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
       "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
     },
+    "node_modules/json-stable-stringify-without-jsonify": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+      "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
+      "dev": true
+    },
     "node_modules/json5": {
       "version": "2.2.1",
       "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
@@ -4773,6 +5653,12 @@
       "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
       "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ=="
     },
+    "node_modules/lodash.merge": {
+      "version": "4.6.2",
+      "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+      "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+      "dev": true
+    },
     "node_modules/lru-cache": {
       "version": "6.0.0",
       "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
@@ -4879,6 +5765,15 @@
       "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
       "dev": true
     },
+    "node_modules/merge2": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+      "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+      "dev": true,
+      "engines": {
+        "node": ">= 8"
+      }
+    },
     "node_modules/micromatch": {
       "version": "4.0.5",
       "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
@@ -5347,6 +6242,18 @@
         "node": ">=6"
       }
     },
+    "node_modules/parent-module": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+      "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+      "dev": true,
+      "dependencies": {
+        "callsites": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
     "node_modules/parse-json": {
       "version": "5.2.0",
       "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
@@ -5412,6 +6319,15 @@
       "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
       "dev": true
     },
+    "node_modules/path-type": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+      "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
     "node_modules/picocolors": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
@@ -5708,6 +6624,18 @@
         "node": ">=0.10.0"
       }
     },
+    "node_modules/regexpp": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
+      "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/mysticatea"
+      }
+    },
     "node_modules/remove-trailing-separator": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
@@ -5808,6 +6736,16 @@
         "node": ">=0.12"
       }
     },
+    "node_modules/reusify": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+      "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+      "dev": true,
+      "engines": {
+        "iojs": ">=1.0.0",
+        "node": ">=0.10.0"
+      }
+    },
     "node_modules/rimraf": {
       "version": "3.0.2",
       "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
@@ -5832,6 +6770,29 @@
         "node": "6.* || >= 7.*"
       }
     },
+    "node_modules/run-parallel": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+      "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "dependencies": {
+        "queue-microtask": "^1.2.2"
+      }
+    },
     "node_modules/safe-buffer": {
       "version": "5.1.2",
       "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
@@ -6814,6 +7775,18 @@
         "node": ">=6"
       }
     },
+    "node_modules/strip-json-comments": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+      "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "node_modules/supports-color": {
       "version": "7.2.0",
       "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@@ -6999,6 +7972,12 @@
         "node": "*"
       }
     },
+    "node_modules/text-table": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+      "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
+      "dev": true
+    },
     "node_modules/throat": {
       "version": "5.0.0",
       "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz",
@@ -7205,6 +8184,27 @@
         "typescript": ">=2.7"
       }
     },
+    "node_modules/tslib": {
+      "version": "1.14.1",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+      "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+      "dev": true
+    },
+    "node_modules/tsutils": {
+      "version": "3.21.0",
+      "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
+      "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
+      "dev": true,
+      "dependencies": {
+        "tslib": "^1.8.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      },
+      "peerDependencies": {
+        "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta"
+      }
+    },
     "node_modules/type-check": {
       "version": "0.3.2",
       "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
@@ -7418,6 +8418,12 @@
         "uuid": "dist/bin/uuid"
       }
     },
+    "node_modules/v8-compile-cache": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz",
+      "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==",
+      "dev": true
+    },
     "node_modules/v8-to-istanbul": {
       "version": "7.1.2",
       "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.1.2.tgz",
@@ -7835,6 +8841,18 @@
         "node": ">=6"
       }
     },
+    "node_modules/yocto-queue": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+      "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+      "dev": true,
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
     "packages/cli": {
       "name": "@redocly/cli",
       "version": "1.0.0-beta.107",
@@ -8333,6 +9351,103 @@
       "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==",
       "dev": true
     },
+    "@eslint/eslintrc": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.0.tgz",
+      "integrity": "sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw==",
+      "dev": true,
+      "requires": {
+        "ajv": "^6.12.4",
+        "debug": "^4.3.2",
+        "espree": "^9.3.2",
+        "globals": "^13.15.0",
+        "ignore": "^5.2.0",
+        "import-fresh": "^3.2.1",
+        "js-yaml": "^4.1.0",
+        "minimatch": "^3.1.2",
+        "strip-json-comments": "^3.1.1"
+      },
+      "dependencies": {
+        "brace-expansion": {
+          "version": "1.1.11",
+          "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+          "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+          "dev": true,
+          "requires": {
+            "balanced-match": "^1.0.0",
+            "concat-map": "0.0.1"
+          }
+        },
+        "globals": {
+          "version": "13.17.0",
+          "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz",
+          "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==",
+          "dev": true,
+          "requires": {
+            "type-fest": "^0.20.2"
+          }
+        },
+        "minimatch": {
+          "version": "3.1.2",
+          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+          "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+          "dev": true,
+          "requires": {
+            "brace-expansion": "^1.1.7"
+          }
+        },
+        "type-fest": {
+          "version": "0.20.2",
+          "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+          "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+          "dev": true
+        }
+      }
+    },
+    "@humanwhocodes/config-array": {
+      "version": "0.10.4",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.10.4.tgz",
+      "integrity": "sha512-mXAIHxZT3Vcpg83opl1wGlVZ9xydbfZO3r5YfRSH6Gpp2J/PfdBP0wbDa2sO6/qRbcalpoevVyW6A/fI6LfeMw==",
+      "dev": true,
+      "requires": {
+        "@humanwhocodes/object-schema": "^1.2.1",
+        "debug": "^4.1.1",
+        "minimatch": "^3.0.4"
+      },
+      "dependencies": {
+        "brace-expansion": {
+          "version": "1.1.11",
+          "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+          "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+          "dev": true,
+          "requires": {
+            "balanced-match": "^1.0.0",
+            "concat-map": "0.0.1"
+          }
+        },
+        "minimatch": {
+          "version": "3.1.2",
+          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+          "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+          "dev": true,
+          "requires": {
+            "brace-expansion": "^1.1.7"
+          }
+        }
+      }
+    },
+    "@humanwhocodes/gitignore-to-minimatch": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/gitignore-to-minimatch/-/gitignore-to-minimatch-1.0.2.tgz",
+      "integrity": "sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==",
+      "dev": true
+    },
+    "@humanwhocodes/object-schema": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
+      "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==",
+      "dev": true
+    },
     "@istanbuljs/load-nyc-config": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
@@ -8654,6 +9769,32 @@
         "@jridgewell/sourcemap-codec": "^1.4.10"
       }
     },
+    "@nodelib/fs.scandir": {
+      "version": "2.1.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+      "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+      "dev": true,
+      "requires": {
+        "@nodelib/fs.stat": "2.0.5",
+        "run-parallel": "^1.1.9"
+      }
+    },
+    "@nodelib/fs.stat": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+      "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+      "dev": true
+    },
+    "@nodelib/fs.walk": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+      "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+      "dev": true,
+      "requires": {
+        "@nodelib/fs.scandir": "2.1.5",
+        "fastq": "^1.6.0"
+      }
+    },
     "@redocly/ajv": {
       "version": "8.6.5",
       "resolved": "https://registry.npmjs.org/@redocly/ajv/-/ajv-8.6.5.tgz",
@@ -8936,26 +10077,143 @@
       "integrity": "sha512-ymZk3LEC/fsut+/Q5qejp6R9O1rMxz3XaRHDV6kX8MrGAhOSPqVARbDi+EZvInBpw+BnCX3TD240byVkOfQsHg==",
       "dev": true
     },
-    "@types/stack-utils": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz",
-      "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==",
+    "@types/stack-utils": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz",
+      "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==",
+      "dev": true
+    },
+    "@types/yargs": {
+      "version": "15.0.14",
+      "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz",
+      "integrity": "sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ==",
+      "dev": true,
+      "requires": {
+        "@types/yargs-parser": "*"
+      }
+    },
+    "@types/yargs-parser": {
+      "version": "21.0.0",
+      "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz",
+      "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==",
+      "dev": true
+    },
+    "@typescript-eslint/eslint-plugin": {
+      "version": "5.33.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.33.0.tgz",
+      "integrity": "sha512-jHvZNSW2WZ31OPJ3enhLrEKvAZNyAFWZ6rx9tUwaessTc4sx9KmgMNhVcqVAl1ETnT5rU5fpXTLmY9YvC1DCNg==",
+      "dev": true,
+      "requires": {
+        "@typescript-eslint/scope-manager": "5.33.0",
+        "@typescript-eslint/type-utils": "5.33.0",
+        "@typescript-eslint/utils": "5.33.0",
+        "debug": "^4.3.4",
+        "functional-red-black-tree": "^1.0.1",
+        "ignore": "^5.2.0",
+        "regexpp": "^3.2.0",
+        "semver": "^7.3.7",
+        "tsutils": "^3.21.0"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "7.3.7",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
+          "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
+          "dev": true,
+          "requires": {
+            "lru-cache": "^6.0.0"
+          }
+        }
+      }
+    },
+    "@typescript-eslint/parser": {
+      "version": "5.33.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.33.0.tgz",
+      "integrity": "sha512-cgM5cJrWmrDV2KpvlcSkelTBASAs1mgqq+IUGKJvFxWrapHpaRy5EXPQz9YaKF3nZ8KY18ILTiVpUtbIac86/w==",
+      "dev": true,
+      "requires": {
+        "@typescript-eslint/scope-manager": "5.33.0",
+        "@typescript-eslint/types": "5.33.0",
+        "@typescript-eslint/typescript-estree": "5.33.0",
+        "debug": "^4.3.4"
+      }
+    },
+    "@typescript-eslint/scope-manager": {
+      "version": "5.33.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.33.0.tgz",
+      "integrity": "sha512-/Jta8yMNpXYpRDl8EwF/M8It2A9sFJTubDo0ATZefGXmOqlaBffEw0ZbkbQ7TNDK6q55NPHFshGBPAZvZkE8Pw==",
+      "dev": true,
+      "requires": {
+        "@typescript-eslint/types": "5.33.0",
+        "@typescript-eslint/visitor-keys": "5.33.0"
+      }
+    },
+    "@typescript-eslint/type-utils": {
+      "version": "5.33.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.33.0.tgz",
+      "integrity": "sha512-2zB8uEn7hEH2pBeyk3NpzX1p3lF9dKrEbnXq1F7YkpZ6hlyqb2yZujqgRGqXgRBTHWIUG3NGx/WeZk224UKlIA==",
+      "dev": true,
+      "requires": {
+        "@typescript-eslint/utils": "5.33.0",
+        "debug": "^4.3.4",
+        "tsutils": "^3.21.0"
+      }
+    },
+    "@typescript-eslint/types": {
+      "version": "5.33.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.33.0.tgz",
+      "integrity": "sha512-nIMt96JngB4MYFYXpZ/3ZNU4GWPNdBbcB5w2rDOCpXOVUkhtNlG2mmm8uXhubhidRZdwMaMBap7Uk8SZMU/ppw==",
       "dev": true
     },
-    "@types/yargs": {
-      "version": "15.0.14",
-      "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.14.tgz",
-      "integrity": "sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ==",
+    "@typescript-eslint/typescript-estree": {
+      "version": "5.33.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.33.0.tgz",
+      "integrity": "sha512-tqq3MRLlggkJKJUrzM6wltk8NckKyyorCSGMq4eVkyL5sDYzJJcMgZATqmF8fLdsWrW7OjjIZ1m9v81vKcaqwQ==",
       "dev": true,
       "requires": {
-        "@types/yargs-parser": "*"
+        "@typescript-eslint/types": "5.33.0",
+        "@typescript-eslint/visitor-keys": "5.33.0",
+        "debug": "^4.3.4",
+        "globby": "^11.1.0",
+        "is-glob": "^4.0.3",
+        "semver": "^7.3.7",
+        "tsutils": "^3.21.0"
+      },
+      "dependencies": {
+        "semver": {
+          "version": "7.3.7",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz",
+          "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==",
+          "dev": true,
+          "requires": {
+            "lru-cache": "^6.0.0"
+          }
+        }
       }
     },
-    "@types/yargs-parser": {
-      "version": "21.0.0",
-      "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz",
-      "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==",
-      "dev": true
+    "@typescript-eslint/utils": {
+      "version": "5.33.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.33.0.tgz",
+      "integrity": "sha512-JxOAnXt9oZjXLIiXb5ZIcZXiwVHCkqZgof0O8KPgz7C7y0HS42gi75PdPlqh1Tf109M0fyUw45Ao6JLo7S5AHw==",
+      "dev": true,
+      "requires": {
+        "@types/json-schema": "^7.0.9",
+        "@typescript-eslint/scope-manager": "5.33.0",
+        "@typescript-eslint/types": "5.33.0",
+        "@typescript-eslint/typescript-estree": "5.33.0",
+        "eslint-scope": "^5.1.1",
+        "eslint-utils": "^3.0.0"
+      }
+    },
+    "@typescript-eslint/visitor-keys": {
+      "version": "5.33.0",
+      "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.33.0.tgz",
+      "integrity": "sha512-/XsqCzD4t+Y9p5wd9HZiptuGKBlaZO5showwqODii5C0nZawxWLF+Q6k5wYHBrQv96h6GYKyqqMHCSTqta8Kiw==",
+      "dev": true,
+      "requires": {
+        "@typescript-eslint/types": "5.33.0",
+        "eslint-visitor-keys": "^3.3.0"
+      }
     },
     "@webassemblyjs/ast": {
       "version": "1.11.1",
@@ -9175,6 +10433,13 @@
       "dev": true,
       "requires": {}
     },
+    "acorn-jsx": {
+      "version": "5.3.2",
+      "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
+      "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
+      "dev": true,
+      "requires": {}
+    },
     "acorn-walk": {
       "version": "7.2.0",
       "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz",
@@ -9277,6 +10542,12 @@
       "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==",
       "dev": true
     },
+    "array-union": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
+      "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+      "dev": true
+    },
     "array-unique": {
       "version": "0.3.2",
       "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
@@ -9943,6 +11214,24 @@
       "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==",
       "dev": true
     },
+    "dir-glob": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
+      "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
+      "dev": true,
+      "requires": {
+        "path-type": "^4.0.0"
+      }
+    },
+    "doctrine": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
+      "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+      "dev": true,
+      "requires": {
+        "esutils": "^2.0.2"
+      }
+    },
     "domexception": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz",
@@ -10065,6 +11354,196 @@
         }
       }
     },
+    "eslint": {
+      "version": "8.22.0",
+      "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.22.0.tgz",
+      "integrity": "sha512-ci4t0sz6vSRKdmkOGmprBo6fmI4PrphDFMy5JEq/fNS0gQkJM3rLmrqcp8ipMcdobH3KtUP40KniAE9W19S4wA==",
+      "dev": true,
+      "requires": {
+        "@eslint/eslintrc": "^1.3.0",
+        "@humanwhocodes/config-array": "^0.10.4",
+        "@humanwhocodes/gitignore-to-minimatch": "^1.0.2",
+        "ajv": "^6.10.0",
+        "chalk": "^4.0.0",
+        "cross-spawn": "^7.0.2",
+        "debug": "^4.3.2",
+        "doctrine": "^3.0.0",
+        "escape-string-regexp": "^4.0.0",
+        "eslint-scope": "^7.1.1",
+        "eslint-utils": "^3.0.0",
+        "eslint-visitor-keys": "^3.3.0",
+        "espree": "^9.3.3",
+        "esquery": "^1.4.0",
+        "esutils": "^2.0.2",
+        "fast-deep-equal": "^3.1.3",
+        "file-entry-cache": "^6.0.1",
+        "find-up": "^5.0.0",
+        "functional-red-black-tree": "^1.0.1",
+        "glob-parent": "^6.0.1",
+        "globals": "^13.15.0",
+        "globby": "^11.1.0",
+        "grapheme-splitter": "^1.0.4",
+        "ignore": "^5.2.0",
+        "import-fresh": "^3.0.0",
+        "imurmurhash": "^0.1.4",
+        "is-glob": "^4.0.0",
+        "js-yaml": "^4.1.0",
+        "json-stable-stringify-without-jsonify": "^1.0.1",
+        "levn": "^0.4.1",
+        "lodash.merge": "^4.6.2",
+        "minimatch": "^3.1.2",
+        "natural-compare": "^1.4.0",
+        "optionator": "^0.9.1",
+        "regexpp": "^3.2.0",
+        "strip-ansi": "^6.0.1",
+        "strip-json-comments": "^3.1.0",
+        "text-table": "^0.2.0",
+        "v8-compile-cache": "^2.0.3"
+      },
+      "dependencies": {
+        "brace-expansion": {
+          "version": "1.1.11",
+          "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+          "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+          "dev": true,
+          "requires": {
+            "balanced-match": "^1.0.0",
+            "concat-map": "0.0.1"
+          }
+        },
+        "escape-string-regexp": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
+          "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
+          "dev": true
+        },
+        "eslint-scope": {
+          "version": "7.1.1",
+          "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz",
+          "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==",
+          "dev": true,
+          "requires": {
+            "esrecurse": "^4.3.0",
+            "estraverse": "^5.2.0"
+          }
+        },
+        "estraverse": {
+          "version": "5.3.0",
+          "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+          "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+          "dev": true
+        },
+        "find-up": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
+          "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
+          "dev": true,
+          "requires": {
+            "locate-path": "^6.0.0",
+            "path-exists": "^4.0.0"
+          }
+        },
+        "glob-parent": {
+          "version": "6.0.2",
+          "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+          "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+          "dev": true,
+          "requires": {
+            "is-glob": "^4.0.3"
+          }
+        },
+        "globals": {
+          "version": "13.17.0",
+          "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz",
+          "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==",
+          "dev": true,
+          "requires": {
+            "type-fest": "^0.20.2"
+          }
+        },
+        "levn": {
+          "version": "0.4.1",
+          "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+          "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+          "dev": true,
+          "requires": {
+            "prelude-ls": "^1.2.1",
+            "type-check": "~0.4.0"
+          }
+        },
+        "locate-path": {
+          "version": "6.0.0",
+          "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
+          "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
+          "dev": true,
+          "requires": {
+            "p-locate": "^5.0.0"
+          }
+        },
+        "minimatch": {
+          "version": "3.1.2",
+          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+          "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+          "dev": true,
+          "requires": {
+            "brace-expansion": "^1.1.7"
+          }
+        },
+        "optionator": {
+          "version": "0.9.1",
+          "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
+          "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
+          "dev": true,
+          "requires": {
+            "deep-is": "^0.1.3",
+            "fast-levenshtein": "^2.0.6",
+            "levn": "^0.4.1",
+            "prelude-ls": "^1.2.1",
+            "type-check": "^0.4.0",
+            "word-wrap": "^1.2.3"
+          }
+        },
+        "p-limit": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
+          "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
+          "dev": true,
+          "requires": {
+            "yocto-queue": "^0.1.0"
+          }
+        },
+        "p-locate": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
+          "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
+          "dev": true,
+          "requires": {
+            "p-limit": "^3.0.2"
+          }
+        },
+        "prelude-ls": {
+          "version": "1.2.1",
+          "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
+          "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
+          "dev": true
+        },
+        "type-check": {
+          "version": "0.4.0",
+          "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
+          "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
+          "dev": true,
+          "requires": {
+            "prelude-ls": "^1.2.1"
+          }
+        },
+        "type-fest": {
+          "version": "0.20.2",
+          "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+          "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+          "dev": true
+        }
+      }
+    },
     "eslint-scope": {
       "version": "5.1.1",
       "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
@@ -10075,12 +11554,63 @@
         "estraverse": "^4.1.1"
       }
     },
+    "eslint-utils": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz",
+      "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==",
+      "dev": true,
+      "requires": {
+        "eslint-visitor-keys": "^2.0.0"
+      },
+      "dependencies": {
+        "eslint-visitor-keys": {
+          "version": "2.1.0",
+          "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
+          "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
+          "dev": true
+        }
+      }
+    },
+    "eslint-visitor-keys": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz",
+      "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==",
+      "dev": true
+    },
+    "espree": {
+      "version": "9.3.3",
+      "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.3.tgz",
+      "integrity": "sha512-ORs1Rt/uQTqUKjDdGCyrtYxbazf5umATSf/K4qxjmZHORR6HJk+2s/2Pqe+Kk49HHINC/xNIrGfgh8sZcll0ng==",
+      "dev": true,
+      "requires": {
+        "acorn": "^8.8.0",
+        "acorn-jsx": "^5.3.2",
+        "eslint-visitor-keys": "^3.3.0"
+      }
+    },
     "esprima": {
       "version": "4.0.1",
       "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
       "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
       "dev": true
     },
+    "esquery": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
+      "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==",
+      "dev": true,
+      "requires": {
+        "estraverse": "^5.1.0"
+      },
+      "dependencies": {
+        "estraverse": {
+          "version": "5.3.0",
+          "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
+          "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
+          "dev": true
+        }
+      }
+    },
     "esrecurse": {
       "version": "4.3.0",
       "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
@@ -10334,6 +11864,19 @@
       "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
       "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
     },
+    "fast-glob": {
+      "version": "3.2.11",
+      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz",
+      "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==",
+      "dev": true,
+      "requires": {
+        "@nodelib/fs.stat": "^2.0.2",
+        "@nodelib/fs.walk": "^1.2.3",
+        "glob-parent": "^5.1.2",
+        "merge2": "^1.3.0",
+        "micromatch": "^4.0.4"
+      }
+    },
     "fast-json-stable-stringify": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
@@ -10352,6 +11895,15 @@
       "integrity": "sha512-tFfWHjnuUfKE186Tfgr+jtaFc0mZTApEgKDOeyN+FwOqRkO/zK/3h1AiRd8u8CY53owL3CUmGr/oI9p/RdyLTA==",
       "dev": true
     },
+    "fastq": {
+      "version": "1.13.0",
+      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz",
+      "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==",
+      "dev": true,
+      "requires": {
+        "reusify": "^1.0.4"
+      }
+    },
     "fb-watchman": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz",
@@ -10361,6 +11913,15 @@
         "bser": "2.1.1"
       }
     },
+    "file-entry-cache": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
+      "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
+      "dev": true,
+      "requires": {
+        "flat-cache": "^3.0.4"
+      }
+    },
     "fill-range": {
       "version": "7.0.1",
       "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
@@ -10379,6 +11940,22 @@
         "path-exists": "^4.0.0"
       }
     },
+    "flat-cache": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
+      "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
+      "dev": true,
+      "requires": {
+        "flatted": "^3.1.0",
+        "rimraf": "^3.0.2"
+      }
+    },
+    "flatted": {
+      "version": "3.2.6",
+      "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.6.tgz",
+      "integrity": "sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ==",
+      "dev": true
+    },
     "for-in": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
@@ -10422,6 +11999,12 @@
       "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
       "dev": true
     },
+    "functional-red-black-tree": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
+      "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==",
+      "dev": true
+    },
     "gensync": {
       "version": "1.0.0-beta.2",
       "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
@@ -10514,12 +12097,32 @@
       "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==",
       "dev": true
     },
+    "globby": {
+      "version": "11.1.0",
+      "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
+      "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
+      "dev": true,
+      "requires": {
+        "array-union": "^2.1.0",
+        "dir-glob": "^3.0.1",
+        "fast-glob": "^3.2.9",
+        "ignore": "^5.2.0",
+        "merge2": "^1.4.1",
+        "slash": "^3.0.0"
+      }
+    },
     "graceful-fs": {
       "version": "4.2.10",
       "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz",
       "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==",
       "dev": true
     },
+    "grapheme-splitter": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz",
+      "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==",
+      "dev": true
+    },
     "growly": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz",
@@ -10663,6 +12266,30 @@
         "safer-buffer": ">= 2.1.2 < 3"
       }
     },
+    "ignore": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz",
+      "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==",
+      "dev": true
+    },
+    "import-fresh": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+      "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+      "dev": true,
+      "requires": {
+        "parent-module": "^1.0.0",
+        "resolve-from": "^4.0.0"
+      },
+      "dependencies": {
+        "resolve-from": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+          "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+          "dev": true
+        }
+      }
+    },
     "import-local": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz",
@@ -11638,6 +13265,12 @@
       "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
       "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
     },
+    "json-stable-stringify-without-jsonify": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
+      "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
+      "dev": true
+    },
     "json5": {
       "version": "2.2.1",
       "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
@@ -11714,6 +13347,12 @@
       "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
       "integrity": "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ=="
     },
+    "lodash.merge": {
+      "version": "4.6.2",
+      "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
+      "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
+      "dev": true
+    },
     "lru-cache": {
       "version": "6.0.0",
       "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
@@ -11804,6 +13443,12 @@
       "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
       "dev": true
     },
+    "merge2": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+      "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+      "dev": true
+    },
     "micromatch": {
       "version": "4.0.5",
       "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
@@ -12163,6 +13808,15 @@
       "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
       "dev": true
     },
+    "parent-module": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+      "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+      "dev": true,
+      "requires": {
+        "callsites": "^3.0.0"
+      }
+    },
     "parse-json": {
       "version": "5.2.0",
       "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
@@ -12210,6 +13864,12 @@
       "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
       "dev": true
     },
+    "path-type": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+      "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+      "dev": true
+    },
     "picocolors": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
@@ -12429,6 +14089,12 @@
         "safe-regex": "^1.1.0"
       }
     },
+    "regexpp": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
+      "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
+      "dev": true
+    },
     "remove-trailing-separator": {
       "version": "1.1.0",
       "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
@@ -12501,6 +14167,12 @@
       "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
       "dev": true
     },
+    "reusify": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+      "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+      "dev": true
+    },
     "rimraf": {
       "version": "3.0.2",
       "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
@@ -12516,6 +14188,15 @@
       "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==",
       "dev": true
     },
+    "run-parallel": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+      "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+      "dev": true,
+      "requires": {
+        "queue-microtask": "^1.2.2"
+      }
+    },
     "safe-buffer": {
       "version": "5.1.2",
       "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
@@ -13299,6 +14980,12 @@
       "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
       "dev": true
     },
+    "strip-json-comments": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
+      "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
+      "dev": true
+    },
     "supports-color": {
       "version": "7.2.0",
       "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@@ -13425,6 +15112,12 @@
         }
       }
     },
+    "text-table": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
+      "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
+      "dev": true
+    },
     "throat": {
       "version": "5.0.0",
       "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz",
@@ -13572,6 +15265,21 @@
         "yn": "3.1.1"
       }
     },
+    "tslib": {
+      "version": "1.14.1",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+      "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
+      "dev": true
+    },
+    "tsutils": {
+      "version": "3.21.0",
+      "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz",
+      "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==",
+      "dev": true,
+      "requires": {
+        "tslib": "^1.8.1"
+      }
+    },
     "type-check": {
       "version": "0.3.2",
       "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
@@ -13722,6 +15430,12 @@
       "dev": true,
       "optional": true
     },
+    "v8-compile-cache": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz",
+      "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==",
+      "dev": true
+    },
     "v8-to-istanbul": {
       "version": "7.1.2",
       "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-7.1.2.tgz",
@@ -14034,6 +15748,12 @@
       "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz",
       "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
       "dev": true
+    },
+    "yocto-queue": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
+      "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
+      "dev": true
     }
   }
 }
diff --git a/package.json b/package.json
index a4971ab8..2904ef69 100644
--- a/package.json
+++ b/package.json
@@ -17,6 +17,7 @@
     "e2e": "npm run webpack-bundle -- --mode=none && jest --roots=./__tests__/",
     "prettier": "npx prettier --write \"**/*.{ts,js}\"",
     "prettier:check": "npx prettier --check \"**/*.{ts,js}\"",
+    "eslint": "eslint packages/**",
     "clean": "rm -rf packages/**/lib packages/**/node_modules packages/**/*.tsbuildinfo package-lock.json node_modules",
     "watch": "tsc -b tsconfig.build.json --watch ",
     "compile": "tsc -b tsconfig.build.json",
@@ -57,6 +58,9 @@
   "devDependencies": {
     "@types/jest": "^26.0.15",
     "@types/node": "^17.0.31",
+    "@typescript-eslint/eslint-plugin": "^5.33.0",
+    "@typescript-eslint/parser": "^5.33.0",
+    "eslint": "^8.22.0",
     "jest": "^26.6.3",
     "null-loader": "^4.0.0",
     "outdent": "^0.7.1",
diff --git a/packages/cli/src/commands/join.ts b/packages/cli/src/commands/join.ts
index 13d7f44c..645c567d 100644
--- a/packages/cli/src/commands/join.ts
+++ b/packages/cli/src/commands/join.ts
@@ -131,8 +131,8 @@ export async function handleJoin(argv: JoinArgv, packageVersion: string) {
     }
   }
 
-  let joinedDef: any = {};
-  let potentialConflicts = {
+  const joinedDef: any = {};
+  const potentialConflicts = {
     tags: {},
     paths: {},
     components: {},
@@ -343,9 +343,7 @@ export async function handleJoin(argv: JoinArgv, packageVersion: string) {
         if (!potentialConflicts.paths.hasOwnProperty(path)) {
           potentialConflicts.paths[path] = {};
         }
-        for (const operation of Object.keys(paths[path])) {
-          // @ts-ignore
-          const pathOperation = paths[path][operation];
+        for (const [operation, pathOperation] of Object.entries(paths[path])) {
           joinedDef.paths[path][operation] = pathOperation;
           potentialConflicts.paths[path][operation] = [
             ...(potentialConflicts.paths[path][operation] || []),
@@ -361,7 +359,7 @@ export async function handleJoin(argv: JoinArgv, packageVersion: string) {
               api,
             ];
           }
-          let { tags, security } = joinedDef.paths[path][operation];
+          const { tags, security } = joinedDef.paths[path][operation];
           if (tags) {
             joinedDef.paths[path][operation].tags = tags.map((tag: string) =>
               addPrefix(tag, tagsPrefix)
@@ -412,13 +410,11 @@ export async function handleJoin(argv: JoinArgv, packageVersion: string) {
       if (!joinedDef.hasOwnProperty(COMPONENTS)) {
         joinedDef[COMPONENTS] = {};
       }
-      for (const component of Object.keys(components)) {
+      for (const [component, componentObj] of Object.entries(components)) {
         if (!potentialConflicts[COMPONENTS].hasOwnProperty(component)) {
           potentialConflicts[COMPONENTS][component] = {};
           joinedDef[COMPONENTS][component] = {};
         }
-        // @ts-ignore
-        const componentObj = components[component];
         for (const item of Object.keys(componentObj)) {
           const componentPrefix = addPrefix(item, componentsPrefix!);
           potentialConflicts.components[component][componentPrefix] = [
@@ -436,7 +432,6 @@ export async function handleJoin(argv: JoinArgv, packageVersion: string) {
     { apiFilename, api, potentialConflicts, tagsPrefix, componentsPrefix }: JoinDocumentContext
   ) {
     const xWebhooks = 'x-webhooks';
-    // @ts-ignore
     const openapiXWebhooks = openapi[xWebhooks];
     if (openapiXWebhooks) {
       if (!joinedDef.hasOwnProperty(xWebhooks)) {
@@ -455,7 +450,7 @@ export async function handleJoin(argv: JoinArgv, packageVersion: string) {
           ];
         }
         for (const operationKey of Object.keys(joinedDef[xWebhooks][webhook])) {
-          let { tags } = joinedDef[xWebhooks][webhook][operationKey];
+          const { tags } = joinedDef[xWebhooks][webhook][operationKey];
           if (tags) {
             joinedDef[xWebhooks][webhook][operationKey].tags = tags.map((tag: string) =>
               addPrefix(tag, tagsPrefix)
@@ -498,7 +493,7 @@ function doesComponentsDiffer(curr: object, next: object) {
 function validateComponentsDifference(files: any) {
   let isDiffer = false;
   for (let i = 0, len = files.length; i < len; i++) {
-    let next = files[i + 1];
+    const next = files[i + 1];
     if (next && doesComponentsDiffer(files[i], next)) {
       isDiffer = true;
     }
diff --git a/packages/cli/src/commands/lint.ts b/packages/cli/src/commands/lint.ts
index fa9cd0ec..8281ca19 100644
--- a/packages/cli/src/commands/lint.ts
+++ b/packages/cli/src/commands/lint.ts
@@ -84,7 +84,7 @@ export async function handleLint(argv: LintOptions, version: string) {
       totals.ignored += fileTotals.ignored;
 
       if (argv['generate-ignore-file']) {
-        for (let m of results) {
+        for (const m of results) {
           config.styleguide.addIgnore(m);
           totalIgnored++;
         }
diff --git a/packages/cli/src/commands/preview-docs/index.ts b/packages/cli/src/commands/preview-docs/index.ts
index 41d93310..008b5d45 100644
--- a/packages/cli/src/commands/preview-docs/index.ts
+++ b/packages/cli/src/commands/preview-docs/index.ts
@@ -23,7 +23,7 @@ export async function previewDocs(
     force?: boolean;
   } & Omit<Skips, 'skip-rule'>
 ) {
-  let isAuthorizedWithRedocly: boolean = false;
+  let isAuthorizedWithRedocly = false;
   let redocOptions: any = {};
   let config = await reloadConfig();
 
@@ -129,7 +129,7 @@ export async function previewDocs(
   });
 
   async function reloadConfig() {
-    let config = await loadConfig(argv.config);
+    const config = await loadConfig(argv.config);
     const redoclyClient = new RedoclyClient();
     isAuthorizedWithRedocly = await redoclyClient.isAuthorizedWithRedocly();
     const resolvedConfig = getMergedConfig(config, argv.api);
@@ -152,7 +152,9 @@ export function debounce(func: Function, wait: number, immediate?: boolean) {
   let timeout: NodeJS.Timeout | null;
 
   return function executedFunction(...args: any[]) {
+    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
     // @ts-ignore
+    // eslint-disable-next-line @typescript-eslint/no-this-alias
     const context = this;
 
     const later = () => {
diff --git a/packages/cli/src/commands/preview-docs/preview-server/preview-server.ts b/packages/cli/src/commands/preview-docs/preview-server/preview-server.ts
index cb5092ef..9707a19f 100644
--- a/packages/cli/src/commands/preview-docs/preview-server/preview-server.ts
+++ b/packages/cli/src/commands/preview-docs/preview-server/preview-server.ts
@@ -99,6 +99,7 @@ export default async function startPreviewServer(
       }
     } else {
       let filePath =
+        // eslint-disable-next-line @typescript-eslint/ban-ts-comment
         // @ts-ignore
         {
           '/hot.js': path.join(__dirname, 'hot.js'),
@@ -142,7 +143,7 @@ export default async function startPreviewServer(
     console.timeEnd(colorette.dim(`GET ${request.url}`));
   };
 
-  let wsPort = await portfinder.getPortPromise({ port: 32201 });
+  const wsPort = await portfinder.getPortPromise({ port: 32201 });
 
   const server = startHttpServer(port, host, handler);
   server.on('listening', () => {
diff --git a/packages/cli/src/commands/push.ts b/packages/cli/src/commands/push.ts
index d2e0eb5b..765e2be3 100644
--- a/packages/cli/src/commands/push.ts
+++ b/packages/cli/src/commands/push.ts
@@ -119,7 +119,7 @@ export async function handlePush(argv: PushArgs): Promise<void> {
 
       let uploaded = 0;
 
-      for (let file of filesToUpload.files) {
+      for (const file of filesToUpload.files) {
         const { signedUploadUrl, filePath } = await client.registryApi.prepareFileUpload({
           organizationId,
           name,
@@ -206,7 +206,7 @@ function getFilesList(dir: string, files?: any): string[] {
 }
 
 async function collectFilesToUpload(api: string, config: Config) {
-  let files: { filePath: string; keyOnS3: string; contents?: Buffer }[] = [];
+  const files: { filePath: string; keyOnS3: string; contents?: Buffer }[] = [];
   const [{ path: apiPath }] = await getFallbackApisOrExit([api], config);
 
   process.stdout.write('Bundling definition\n');
@@ -246,7 +246,7 @@ async function collectFilesToUpload(api: string, config: Config) {
       const fileList = getFilesList(dir, []);
       files.push(...fileList.map((f) => getFileEntry(f)));
     }
-    let pluginFiles = new Set<string>();
+    const pluginFiles = new Set<string>();
     for (const plugin of config.styleguide.pluginPaths) {
       if (typeof plugin !== 'string') continue;
       const fileList = getFilesList(getFolder(plugin), []);
@@ -282,7 +282,7 @@ function getFolder(filePath: string) {
 }
 
 function hashFiles(filePaths: { filePath: string }[]) {
-  let sum = createHash('sha256');
+  const sum = createHash('sha256');
   filePaths.forEach((file) => sum.update(fs.readFileSync(file.filePath)));
   return sum.digest('hex');
 }
@@ -318,7 +318,7 @@ type BarePushArgs = Omit<PushArgs, 'api' | 'destination' | 'branchName'> & {
 export const transformPush =
   (callback: typeof handlePush) =>
   ({ maybeApiOrDestination, maybeDestination, maybeBranchName, branch, ...rest }: BarePushArgs) => {
-    if (!!maybeBranchName) {
+    if (maybeBranchName) {
       process.stderr.write(
         yellow(
           'Deprecation warning: Do not use the third parameter as a branch name. Please use a separate --branch option instead.'
@@ -353,7 +353,7 @@ function uploadFileToS3(url: string, filePathOrBuffer: string | Buffer) {
     typeof filePathOrBuffer === 'string'
       ? fs.statSync(filePathOrBuffer).size
       : filePathOrBuffer.byteLength;
-  let readStream =
+  const readStream =
     typeof filePathOrBuffer === 'string' ? fs.createReadStream(filePathOrBuffer) : filePathOrBuffer;
 
   return fetch(url, {
diff --git a/packages/cli/src/commands/split/index.ts b/packages/cli/src/commands/split/index.ts
index 8ba858c1..3de3ece6 100644
--- a/packages/cli/src/commands/split/index.ts
+++ b/packages/cli/src/commands/split/index.ts
@@ -1,6 +1,7 @@
 import { red, blue, yellow, green } from 'colorette';
 import * as fs from 'fs';
-import { parseYaml, slash, isRef } from '@redocly/openapi-core';
+import { parseYaml, slash, isRef, isTruthy } from '@redocly/openapi-core';
+import type { OasRef } from '@redocly/openapi-core';
 import * as path from 'path';
 import { performance } from 'perf_hooks';
 const isEqual = require('lodash.isequal');
@@ -267,11 +268,11 @@ function gatherComponentsFiles(
   componentName: string,
   filename: string
 ) {
-  let inherits = [];
+  let inherits: string[] = [];
   if (componentType === OPENAPI3_COMPONENT.Schemas) {
     inherits = ((components?.[componentType]?.[componentName] as Oas3Schema)?.allOf || [])
-      .map((s: any) => s.$ref)
-      .filter(Boolean);
+      .map(({ $ref }) => $ref)
+      .filter(isTruthy);
   }
   componentsFiles[componentType] = componentsFiles[componentType] || {};
   componentsFiles[componentType][componentName] = { inherits, filename };
@@ -301,7 +302,7 @@ function iteratePathItems(
         continue;
       }
       for (const sample of methodDataXCode) {
-        if (sample.source && (sample.source as any).$ref) continue;
+        if (sample.source && (sample.source as unknown as OasRef).$ref) continue;
         const sampleFileName = path.join(
           openapiDir,
           'code_samples',
@@ -312,6 +313,7 @@ function iteratePathItems(
 
         fs.mkdirSync(path.dirname(sampleFileName), { recursive: true });
         fs.writeFileSync(sampleFileName, sample.source);
+        // eslint-disable-next-line @typescript-eslint/ban-ts-comment
         // @ts-ignore
         sample.source = {
           $ref: slash(path.relative(outDir, sampleFileName)),
@@ -340,6 +342,7 @@ function iterateComponents(
     componentTypes.forEach(iterateAndGatherComponentsFiles);
     componentTypes.forEach(iterateComponentTypes);
 
+    // eslint-disable-next-line no-inner-declarations
     function iterateAndGatherComponentsFiles(componentType: Oas3ComponentName) {
       const componentDirPath = path.join(componentsDir, componentType);
       for (const componentName of Object.keys(components?.[componentType] || {})) {
@@ -348,6 +351,7 @@ function iterateComponents(
       }
     }
 
+    // eslint-disable-next-line no-inner-declarations
     function iterateComponentTypes(componentType: Oas3ComponentName) {
       const componentDirPath = path.join(componentsDir, componentType);
       createComponentDir(componentDirPath, componentType);
diff --git a/packages/cli/src/utils.ts b/packages/cli/src/utils.ts
index 2698c9e8..a868d447 100644
--- a/packages/cli/src/utils.ts
+++ b/packages/cli/src/utils.ts
@@ -177,7 +177,6 @@ export function handleError(e: Error, ref: string) {
     process.stderr.write(`Failed to parse api definition at ${ref}:\n\n  - ${e.message}.\n\n`);
     // TODO: codeframe
   } else {
-    // @ts-ignore
     if (e instanceof CircularJSONNotSupportedError) {
       process.stderr.write(
         red(`Detected circular reference which can't be converted to JSON.\n`) +
diff --git a/packages/core/src/benchmark/benches/lint-with-top-level-rule-report.bench.ts b/packages/core/src/benchmark/benches/lint-with-top-level-rule-report.bench.ts
index 2ed4ea50..605c7422 100644
--- a/packages/core/src/benchmark/benches/lint-with-top-level-rule-report.bench.ts
+++ b/packages/core/src/benchmark/benches/lint-with-top-level-rule-report.bench.ts
@@ -15,7 +15,6 @@ const rebillyDocument = parseYamlToDocument(
 const config = makeConfigForRuleset({
   test: () => {
     return {
-      // @ts-ignore
       Schema(schema, ctx) {
         if (schema.type === 'number') {
           ctx.report({
diff --git a/packages/core/src/bundle.ts b/packages/core/src/bundle.ts
index 11b8a132..159aee29 100755
--- a/packages/core/src/bundle.ts
+++ b/packages/core/src/bundle.ts
@@ -10,7 +10,7 @@ import { detectOpenAPI, openAPIMajor, OasMajorVersion } from './oas-types';
 import { isAbsoluteUrl, isRef, Location, refBaseName } from './ref-utils';
 import { initRules } from './config/rules';
 import { reportUnresolvedRef } from './rules/no-unresolved-refs';
-import { isPlainObject } from './utils';
+import { isPlainObject, isTruthy } from './utils';
 import { OasRef } from './typings/openapi';
 import { isRedoclyRegistryURL } from './redocly';
 import { RemoveUnusedComponents as RemoveUnusedComponentsOas2 } from './rules/oas2/remove-unused-components';
@@ -302,6 +302,8 @@ function makeBundleVisitor(
     if (!isPlainObject(resolved.node)) {
       ctx.parent[ctx.key] = resolved.node;
     } else {
+      // TODO: why $ref isn't optional in OasRef?
+      // eslint-disable-next-line @typescript-eslint/ban-ts-comment
       // @ts-ignore
       delete ref.$ref;
       Object.assign(ref, resolved.node);
@@ -348,7 +350,7 @@ function makeBundleVisitor(
 
     let name = '';
 
-    const refParts = pointer.slice(2).split('/').filter(Boolean); // slice(2) removes "#/"
+    const refParts = pointer.slice(2).split('/').filter(isTruthy); // slice(2) removes "#/"
     while (refParts.length > 0) {
       name = refParts.pop() + (name ? `-${name}` : '');
       if (
diff --git a/packages/core/src/config/config-resolvers.ts b/packages/core/src/config/config-resolvers.ts
index bbb2b466..f501d02b 100644
--- a/packages/core/src/config/config-resolvers.ts
+++ b/packages/core/src/config/config-resolvers.ts
@@ -71,6 +71,7 @@ export function resolvePlugins(
 ): Plugin[] {
   if (!plugins) return [];
 
+  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
   // @ts-ignore
   const requireFunc = typeof __webpack_require__ === 'function' ? __non_webpack_require__ : require;
 
@@ -166,7 +167,7 @@ export async function resolveApis({
   resolver?: BaseResolver;
 }): Promise<Record<string, ResolvedApi>> {
   const { apis = {}, styleguide: styleguideConfig = {} } = rawConfig;
-  let resolvedApis: Record<string, ResolvedApi> = {};
+  const resolvedApis: Record<string, ResolvedApi> = {};
   for (const [apiName, apiContent] of Object.entries(apis || {})) {
     if (apiContent.styleguide?.extends?.some(isNotString)) {
       throw new Error(
@@ -287,7 +288,7 @@ export function resolvePreset(presetName: string, plugins: Plugin[]): ResolvedSt
     throw new Error(`Invalid config ${red(presetName)}: plugin ${pluginId} is not included.`);
   }
 
-  const preset = plugin.configs?.[configName]! as ResolvedStyleguideConfig;
+  const preset = plugin.configs?.[configName];
   if (!preset) {
     throw new Error(
       pluginId
diff --git a/packages/core/src/config/config.ts b/packages/core/src/config/config.ts
index ea8e5475..26ab4bee 100755
--- a/packages/core/src/config/config.ts
+++ b/packages/core/src/config/config.ts
@@ -172,9 +172,11 @@ export class StyleguideConfig {
           case OasVersion.Version3_1:
             if (!plugin.typeExtension.oas3) continue;
             extendedTypes = plugin.typeExtension.oas3(extendedTypes, version);
+            break;
           case OasVersion.Version2:
             if (!plugin.typeExtension.oas2) continue;
             extendedTypes = plugin.typeExtension.oas2(extendedTypes, version);
+            break;
           default:
             throw new Error('Not implemented');
         }
@@ -192,7 +194,7 @@ export class StyleguideConfig {
         severity: settings,
       };
     } else {
-      return { severity: 'error' as 'error', ...settings };
+      return { severity: 'error', ...settings };
     }
   }
 
@@ -203,10 +205,10 @@ export class StyleguideConfig {
     const settings = this.preprocessors[oasVersion][ruleId] || 'off';
     if (typeof settings === 'string') {
       return {
-        severity: settings === 'on' ? ('error' as 'error') : settings,
+        severity: settings === 'on' ? 'error' : settings,
       };
     } else {
-      return { severity: 'error' as 'error', ...settings };
+      return { severity: 'error', ...settings };
     }
   }
 
@@ -216,10 +218,10 @@ export class StyleguideConfig {
     const settings = this.decorators[oasVersion][ruleId] || 'off';
     if (typeof settings === 'string') {
       return {
-        severity: settings === 'on' ? ('error' as 'error') : settings,
+        severity: settings === 'on' ? 'error' : settings,
       };
     } else {
-      return { severity: 'error' as 'error', ...settings };
+      return { severity: 'error', ...settings };
     }
   }
 
@@ -250,12 +252,14 @@ export class StyleguideConfig {
   getRulesForOasVersion(version: OasMajorVersion) {
     switch (version) {
       case OasMajorVersion.Version3:
+        // eslint-disable-next-line no-case-declarations
         const oas3Rules: Oas3RuleSet[] = []; // default ruleset
         this.plugins.forEach((p) => p.preprocessors?.oas3 && oas3Rules.push(p.preprocessors.oas3));
         this.plugins.forEach((p) => p.rules?.oas3 && oas3Rules.push(p.rules.oas3));
         this.plugins.forEach((p) => p.decorators?.oas3 && oas3Rules.push(p.decorators.oas3));
         return oas3Rules;
       case OasMajorVersion.Version2:
+        // eslint-disable-next-line no-case-declarations
         const oas2Rules: Oas2RuleSet[] = []; // default ruleset
         this.plugins.forEach((p) => p.preprocessors?.oas2 && oas2Rules.push(p.preprocessors.oas2));
         this.plugins.forEach((p) => p.rules?.oas2 && oas2Rules.push(p.rules.oas2));
diff --git a/packages/core/src/config/utils.ts b/packages/core/src/config/utils.ts
index 9a0a040f..8d6a0cc0 100644
--- a/packages/core/src/config/utils.ts
+++ b/packages/core/src/config/utils.ts
@@ -1,6 +1,7 @@
 import { yellow } from 'colorette';
 import {
   assignExisting,
+  isTruthy,
   showErrorForDeprecatedField,
   showWarningForDeprecatedField,
 } from '../utils';
@@ -83,7 +84,7 @@ export function mergeExtends(rulesConfList: ResolvedStyleguideConfig[]) {
     extendPaths: [],
   };
 
-  for (let rulesConf of rulesConfList) {
+  for (const rulesConf of rulesConfList) {
     if (rulesConf.extends) {
       throw new Error(
         `'extends' is not supported in shared configs yet: ${JSON.stringify(rulesConf, null, 2)}.`
@@ -128,14 +129,14 @@ export function getMergedConfig(config: Config, apiName?: string): Config {
     config.rawConfig?.styleguide?.extendPaths,
   ]
     .flat()
-    .filter(Boolean) as string[];
+    .filter(isTruthy);
 
   const pluginPaths = [
     ...Object.values(config.apis).map((api) => api?.styleguide?.pluginPaths),
     config.rawConfig?.styleguide?.pluginPaths,
   ]
     .flat()
-    .filter(Boolean) as string[];
+    .filter(isTruthy);
 
   return apiName
     ? new Config(
diff --git a/packages/core/src/decorators/common/registry-dependencies.ts b/packages/core/src/decorators/common/registry-dependencies.ts
index 22838c6e..6e37a309 100644
--- a/packages/core/src/decorators/common/registry-dependencies.ts
+++ b/packages/core/src/decorators/common/registry-dependencies.ts
@@ -4,7 +4,7 @@ import { isRedoclyRegistryURL } from '../../redocly';
 import { Oas3Decorator, Oas2Decorator } from '../../visitors';
 
 export const RegistryDependencies: Oas3Decorator | Oas2Decorator = () => {
-  let registryDependencies = new Set<string>();
+  const registryDependencies = new Set<string>();
 
   return {
     DefinitionRoot: {
diff --git a/packages/core/src/format/codeframes.ts b/packages/core/src/format/codeframes.ts
index 4ee25e6a..93ee7151 100644
--- a/packages/core/src/format/codeframes.ts
+++ b/packages/core/src/format/codeframes.ts
@@ -36,8 +36,8 @@ export function getCodeframe(location: LineColLocationObject, color: boolean) {
     if (skipLines > 0 && i >= endLineNum - skipLines) break;
     const line = lines[i - 1] || '';
     if (line !== '') currentPad = padSize(line);
-    let startIdx = i === startLineNum ? start.col - 1 : currentPad;
-    let endIdx = i === endLineNum ? end.col - 1 : line.length;
+    const startIdx = i === startLineNum ? start.col - 1 : currentPad;
+    const endIdx = i === endLineNum ? end.col - 1 : line.length;
 
     prefixedLines.push([`${i}`, markLine(line, startIdx, endIdx, red)]);
     if (!color) prefixedLines.push(['', underlineLine(line, startIdx, endIdx)]);
diff --git a/packages/core/src/format/format.ts b/packages/core/src/format/format.ts
index 18953e5f..d9733c32 100644
--- a/packages/core/src/format/format.ts
+++ b/packages/core/src/format/format.ts
@@ -185,7 +185,7 @@ export function formatProblems(
       totals,
       version,
       problems: problems.map((p) => {
-        let problem = {
+        const problem = {
           ...p,
           location: p.location.map((location: any) => ({
             ...location,
@@ -320,6 +320,7 @@ const groupByFiles = (problems: NormalizedProblem[]) => {
 };
 
 function xmlEscape(s: string): string {
+  // eslint-disable-next-line no-control-regex
   return s.replace(/[<>&"'\x00-\x1F\x7F\u0080-\uFFFF]/gu, (char) => {
     switch (char) {
       case '<':
diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts
index 69a6c8ac..72382b59 100644
--- a/packages/core/src/index.ts
+++ b/packages/core/src/index.ts
@@ -1,9 +1,9 @@
-export { BundleOutputFormat, readFileFromUrl, slash, doesYamlFileExist } from './utils';
+export { BundleOutputFormat, readFileFromUrl, slash, doesYamlFileExist, isTruthy } from './utils';
 export { Oas3_1Types } from './types/oas3_1';
 export { Oas3Types } from './types/oas3';
 export { Oas2Types } from './types/oas2';
 export { ConfigTypes } from './types/redocly-yaml';
-export {
+export type {
   Oas3Definition,
   Oas3_1Definition,
   Oas3Components,
@@ -15,9 +15,10 @@ export {
   Oas3Tag,
   Oas3_1Webhooks,
   Referenced,
+  OasRef,
 } from './typings/openapi';
-export { Oas2Definition } from './typings/swagger';
-export { StatsAccumulator, StatsName } from './typings/common';
+export type { Oas2Definition } from './typings/swagger';
+export type { StatsAccumulator, StatsName } from './typings/common';
 export { normalizeTypes } from './types';
 export { Stats } from './rules/other/stats';
 
diff --git a/packages/core/src/js-yaml/index.ts b/packages/core/src/js-yaml/index.ts
index c1ba4157..d953ea01 100644
--- a/packages/core/src/js-yaml/index.ts
+++ b/packages/core/src/js-yaml/index.ts
@@ -1,4 +1,5 @@
 // TODO: add a type for "types" https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/js-yaml/index.d.ts
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
 // @ts-ignore
 import { JSON_SCHEMA, types, LoadOptions, DumpOptions, load, dump } from 'js-yaml';
 
diff --git a/packages/core/src/redocly/index.ts b/packages/core/src/redocly/index.ts
index e885597e..c9664e91 100644
--- a/packages/core/src/redocly/index.ts
+++ b/packages/core/src/redocly/index.ts
@@ -152,7 +152,7 @@ export class RedoclyClient {
 
     const credentials = {
       ...this.readCredentialsFile(credentialsPath),
-      [this.region!]: accessToken,
+      [this.region]: accessToken,
       token: accessToken, // FIXME: backward compatibility, remove on 1.0.0
     };
     this.accessTokens = credentials;
diff --git a/packages/core/src/redocly/registry-api-types.ts b/packages/core/src/redocly/registry-api-types.ts
index 9c51a825..9a62dcc3 100644
--- a/packages/core/src/redocly/registry-api-types.ts
+++ b/packages/core/src/redocly/registry-api-types.ts
@@ -1,34 +1,32 @@
-export namespace RegistryApiTypes {
-  interface VersionParams {
-    organizationId: string;
-    name: string;
-    version: string;
-  }
+interface VersionParams {
+  organizationId: string;
+  name: string;
+  version: string;
+}
 
-  export interface PrepareFileuploadParams extends VersionParams {
-    filesHash: string;
-    filename: string;
-    isUpsert?: boolean;
-  }
+export interface PrepareFileuploadParams extends VersionParams {
+  filesHash: string;
+  filename: string;
+  isUpsert?: boolean;
+}
 
-  export interface PushApiParams extends VersionParams {
-    rootFilePath: string;
-    filePaths: string[];
-    branch?: string;
-    isUpsert?: boolean;
-    isPublic?: boolean;
-    batchId?: string;
-    batchSize?: number;
-  }
+export interface PushApiParams extends VersionParams {
+  rootFilePath: string;
+  filePaths: string[];
+  branch?: string;
+  isUpsert?: boolean;
+  isPublic?: boolean;
+  batchId?: string;
+  batchSize?: number;
+}
 
-  export interface PrepareFileuploadOKResponse {
-    filePath: string;
-    signedUploadUrl: string;
-  }
+export interface PrepareFileuploadOKResponse {
+  filePath: string;
+  signedUploadUrl: string;
+}
 
-  export interface NotFoundProblemResponse {
-    status: 404;
-    title: 'Not Found';
-    code: 'ORGANIZATION_NOT_FOUND' | 'API_VERSION_NOT_FOUND';
-  }
+export interface NotFoundProblemResponse {
+  status: 404;
+  title: 'Not Found';
+  code: 'ORGANIZATION_NOT_FOUND' | 'API_VERSION_NOT_FOUND';
 }
diff --git a/packages/core/src/redocly/registry-api.ts b/packages/core/src/redocly/registry-api.ts
index 31e43f33..5c752ffa 100644
--- a/packages/core/src/redocly/registry-api.ts
+++ b/packages/core/src/redocly/registry-api.ts
@@ -1,11 +1,15 @@
 import fetch, { RequestInit, HeadersInit } from 'node-fetch';
-import { RegistryApiTypes } from './registry-api-types';
+import type {
+  NotFoundProblemResponse,
+  PrepareFileuploadOKResponse,
+  PrepareFileuploadParams,
+  PushApiParams,
+} from './registry-api-types';
+import type { AccessTokens, Region } from '../config/types';
 import { DEFAULT_REGION, DOMAINS } from '../config/config';
 import { isNotEmptyObject } from '../utils';
 const version = require('../../package.json').version;
 
-import type { AccessTokens, Region } from '../config/types';
-
 export class RegistryApi {
   constructor(private accessTokens: AccessTokens, private region: Region) {}
 
@@ -39,7 +43,7 @@ export class RegistryApi {
     }
 
     if (response.status === 404) {
-      const body: RegistryApiTypes.NotFoundProblemResponse = await response.json();
+      const body: NotFoundProblemResponse = await response.json();
       throw new Error(body.code);
     }
 
@@ -71,7 +75,7 @@ export class RegistryApi {
     filesHash,
     filename,
     isUpsert,
-  }: RegistryApiTypes.PrepareFileuploadParams): Promise<RegistryApiTypes.PrepareFileuploadOKResponse> {
+  }: PrepareFileuploadParams): Promise<PrepareFileuploadOKResponse> {
     const response = await this.request(
       `/${organizationId}/${name}/${version}/prepare-file-upload`,
       {
@@ -107,7 +111,7 @@ export class RegistryApi {
     isPublic,
     batchId,
     batchSize,
-  }: RegistryApiTypes.PushApiParams) {
+  }: PushApiParams) {
     const response = await this.request(
       `/${organizationId}/${name}/${version}`,
       {
diff --git a/packages/core/src/ref-utils.ts b/packages/core/src/ref-utils.ts
index 8368e9a8..cbc9b1f4 100644
--- a/packages/core/src/ref-utils.ts
+++ b/packages/core/src/ref-utils.ts
@@ -1,5 +1,6 @@
 import { Source } from './resolve';
 import { OasRef } from './typings/openapi';
+import { isTruthy } from './utils';
 
 export function joinPointer(base: string, key: string | number) {
   if (base === '') base = '#/';
@@ -45,7 +46,7 @@ export function parseRef(ref: string): { uri: string | null; pointer: string[] }
   const [uri, pointer] = ref.split('#/');
   return {
     uri: uri || null,
-    pointer: pointer ? pointer.split('/').map(unescapePointer).filter(Boolean) : [],
+    pointer: pointer ? pointer.split('/').map(unescapePointer).filter(isTruthy) : [],
   };
 }
 
diff --git a/packages/core/src/resolve.ts b/packages/core/src/resolve.ts
index 6751534c..9edfce6a 100644
--- a/packages/core/src/resolve.ts
+++ b/packages/core/src/resolve.ts
@@ -323,7 +323,7 @@ export async function resolveDocument(opts: {
           : document;
       } catch (error) {
         const resolvedRef = {
-          resolved: false as false,
+          resolved: false as const,
           isRemote,
           document: undefined,
           error: error,
@@ -334,7 +334,7 @@ export async function resolveDocument(opts: {
       }
 
       let resolvedRef: ResolvedRef = {
-        resolved: true as true,
+        resolved: true as const,
         document: targetDoc,
         isRemote,
         node: document.parsed,
@@ -344,7 +344,7 @@ export async function resolveDocument(opts: {
       let target = targetDoc.parsed as any;
 
       const segments = pointer;
-      for (let segment of segments) {
+      for (const segment of segments) {
         if (typeof target !== 'object') {
           target = undefined;
           break;
diff --git a/packages/core/src/rules/ajv.ts b/packages/core/src/rules/ajv.ts
index 9799c7ba..42eda361 100644
--- a/packages/core/src/rules/ajv.ts
+++ b/packages/core/src/rules/ajv.ts
@@ -73,7 +73,7 @@ export function validateJsonSchema(
 
   function beatifyErrorMessage(error: ErrorObject) {
     let message = error.message;
-    let suggest = error.keyword === 'enum' ? error.params.allowedValues : undefined;
+    const suggest = error.keyword === 'enum' ? error.params.allowedValues : undefined;
     if (suggest) {
       message += ` ${suggest.map((e: any) => `"${e}"`).join(', ')}`;
     }
diff --git a/packages/core/src/rules/common/assertions/asserts.ts b/packages/core/src/rules/common/assertions/asserts.ts
index 199b00a3..4e176ab3 100644
--- a/packages/core/src/rules/common/assertions/asserts.ts
+++ b/packages/core/src/rules/common/assertions/asserts.ts
@@ -46,7 +46,7 @@ export const asserts: Asserts = {
     if (typeof value === 'undefined') return { isValid: true }; // property doesn't exist, no need to lint it with this assert
     const values = runOnValue(value) ? [value] : value;
     const regx = regexFromString(condition);
-    for (let _val of values) {
+    for (const _val of values) {
       if (!regx?.test(_val)) {
         return { isValid: false, location: runOnValue(value) ? baseLocation : baseLocation.key() };
       }
@@ -56,7 +56,7 @@ export const asserts: Asserts = {
   enum: (value: string | string[], condition: string[], baseLocation: Location) => {
     if (typeof value === 'undefined') return { isValid: true }; // property doesn't exist, no need to lint it with this assert
     const values = runOnValue(value) ? [value] : value;
-    for (let _val of values) {
+    for (const _val of values) {
       if (!condition.includes(_val)) {
         return {
           isValid: false,
@@ -81,7 +81,7 @@ export const asserts: Asserts = {
   disallowed: (value: string | string[], condition: string[], baseLocation: Location) => {
     if (typeof value === 'undefined') return { isValid: true }; // property doesn't exist, no need to lint it with this assert
     const values = runOnValue(value) ? [value] : value;
-    for (let _val of values) {
+    for (const _val of values) {
       if (condition.includes(_val)) {
         return {
           isValid: false,
@@ -114,7 +114,7 @@ export const asserts: Asserts = {
   casing: (value: string | string[], condition: string, baseLocation: Location) => {
     if (typeof value === 'undefined') return { isValid: true }; // property doesn't exist, no need to lint it with this assert
     const values: string[] = runOnValue(value) ? [value] : value;
-    for (let _val of values) {
+    for (const _val of values) {
       let matchCase = false;
       switch (condition) {
         case 'camelCase':
diff --git a/packages/core/src/rules/common/assertions/index.ts b/packages/core/src/rules/common/assertions/index.ts
index fdddcfcb..9db2ba50 100644
--- a/packages/core/src/rules/common/assertions/index.ts
+++ b/packages/core/src/rules/common/assertions/index.ts
@@ -3,7 +3,7 @@ import { AssertToApply, buildSubjectVisitor, buildVisitorObject } from './utils'
 import { Oas2Rule, Oas3Rule } from '../../../visitors';
 
 export const Assertions: Oas3Rule | Oas2Rule = (opts: object) => {
-  let visitors: any[] = [];
+  const visitors: any[] = [];
 
   // As 'Assertions' has an array of asserts,
   // that array spreads into an 'opts' object on init rules phase here
diff --git a/packages/core/src/rules/common/operation-security-defined.ts b/packages/core/src/rules/common/operation-security-defined.ts
index 6ca79bdc..8a40c641 100644
--- a/packages/core/src/rules/common/operation-security-defined.ts
+++ b/packages/core/src/rules/common/operation-security-defined.ts
@@ -5,7 +5,7 @@ import { Oas2SecurityScheme } from '../../typings/swagger';
 import { Oas3SecurityScheme } from '../../typings/openapi';
 
 export const OperationSecurityDefined: Oas3Rule | Oas2Rule = () => {
-  let referencedSchemes = new Map<
+  const referencedSchemes = new Map<
     string,
     {
       defined?: boolean;
diff --git a/packages/core/src/rules/common/spec.ts b/packages/core/src/rules/common/spec.ts
index 168e7207..a212b945 100644
--- a/packages/core/src/rules/common/spec.ts
+++ b/packages/core/src/rules/common/spec.ts
@@ -28,7 +28,7 @@ export const OasSpec: Oas3Rule | Oas2Rule = () => {
       const required =
         typeof type.required === 'function' ? type.required(node, key) : type.required;
 
-      for (let propName of required || []) {
+      for (const propName of required || []) {
         if (!(node as object).hasOwnProperty(propName)) {
           report({
             message: `The field \`${propName}\` must be present on this level.`,
@@ -57,7 +57,7 @@ export const OasSpec: Oas3Rule | Oas2Rule = () => {
       const requiredOneOf = type.requiredOneOf || null;
       if (requiredOneOf) {
         let hasProperty = false;
-        for (let propName of requiredOneOf || []) {
+        for (const propName of requiredOneOf || []) {
           if ((node as object).hasOwnProperty(propName)) {
             hasProperty = true;
           }
diff --git a/packages/core/src/rules/oas2/remove-unused-components.ts b/packages/core/src/rules/oas2/remove-unused-components.ts
index 47ac811f..c7093c61 100644
--- a/packages/core/src/rules/oas2/remove-unused-components.ts
+++ b/packages/core/src/rules/oas2/remove-unused-components.ts
@@ -4,7 +4,7 @@ import { Oas2Components } from '../../typings/swagger';
 import { isEmptyObject } from '../../utils';
 
 export const RemoveUnusedComponents: Oas2Rule = () => {
-  let components = new Map<
+  const components = new Map<
     string,
     { used: boolean; componentType?: keyof Oas2Components; name: string }
   >();
@@ -39,7 +39,7 @@ export const RemoveUnusedComponents: Oas2Rule = () => {
         const data = ctx.getVisitorData() as { removedCount: number };
         data.removedCount = 0;
 
-        let rootComponents = new Set<keyof Oas2Components>();
+        const rootComponents = new Set<keyof Oas2Components>();
         components.forEach((usageInfo) => {
           const { used, name, componentType } = usageInfo;
           if (!used && componentType) {
diff --git a/packages/core/src/rules/oas3/no-servers-empty-enum.ts b/packages/core/src/rules/oas3/no-servers-empty-enum.ts
index 34792831..cae4997e 100644
--- a/packages/core/src/rules/oas3/no-servers-empty-enum.ts
+++ b/packages/core/src/rules/oas3/no-servers-empty-enum.ts
@@ -48,7 +48,7 @@ function checkEnumVariables(server: Oas3Server): enumError[] | undefined {
   if (server.variables && Object.keys(server.variables).length === 0) return;
 
   const errors: enumError[] = [];
-  for (var variable in server.variables) {
+  for (const variable in server.variables) {
     const serverVariable = server.variables[variable];
     if (!serverVariable.enum) continue;
 
diff --git a/packages/core/src/rules/oas3/no-unused-components.ts b/packages/core/src/rules/oas3/no-unused-components.ts
index e093c553..5b49448d 100644
--- a/packages/core/src/rules/oas3/no-unused-components.ts
+++ b/packages/core/src/rules/oas3/no-unused-components.ts
@@ -2,7 +2,7 @@ import { Oas3Rule } from '../../visitors';
 import { Location } from '../../ref-utils';
 
 export const NoUnusedComponents: Oas3Rule = () => {
-  let components = new Map<string, { used: boolean; location: Location; name: string }>();
+  const components = new Map<string, { used: boolean; location: Location; name: string }>();
 
   function registerComponent(location: Location, name: string): void {
     components.set(location.absolutePointer, {
diff --git a/packages/core/src/rules/oas3/remove-unused-components.ts b/packages/core/src/rules/oas3/remove-unused-components.ts
index 19c7a247..62a8f6c8 100644
--- a/packages/core/src/rules/oas3/remove-unused-components.ts
+++ b/packages/core/src/rules/oas3/remove-unused-components.ts
@@ -4,7 +4,7 @@ import { Oas3Components } from '../../typings/openapi';
 import { isEmptyObject } from '../../utils';
 
 export const RemoveUnusedComponents: Oas3Rule = () => {
-  let components = new Map<
+  const components = new Map<
     string,
     { used: boolean; componentType?: keyof Oas3Components; name: string }
   >();
@@ -45,12 +45,12 @@ export const RemoveUnusedComponents: Oas3Rule = () => {
 
         components.forEach((usageInfo) => {
           const { used, componentType, name } = usageInfo;
-          if (!used && componentType) {
-            let componentChild = root.components![componentType];
+          if (!used && componentType && root.components) {
+            const componentChild = root.components[componentType];
             delete componentChild![name];
             data.removedCount++;
             if (isEmptyObject(componentChild)) {
-              delete root.components![componentType];
+              delete root.components[componentType];
             }
           }
         });
diff --git a/packages/core/src/rules/utils.ts b/packages/core/src/rules/utils.ts
index 504810c3..d235e2c4 100644
--- a/packages/core/src/rules/utils.ts
+++ b/packages/core/src/rules/utils.ts
@@ -104,7 +104,7 @@ export function validateExample(
       allowAdditionalProperties
     );
     if (!valid) {
-      for (let error of errors) {
+      for (const error of errors) {
         report({
           message: `Example value must conform to the schema: ${error.message}.`,
           location: {
diff --git a/packages/core/src/utils.ts b/packages/core/src/utils.ts
index c3b3c685..e3c9f87d 100644
--- a/packages/core/src/utils.ts
+++ b/packages/core/src/utils.ts
@@ -96,7 +96,7 @@ export function omitObjectProps<T extends Record<string, unknown>>(
 export function splitCamelCaseIntoWords(str: string) {
   const camel = str
     .split(/(?:[-._])|([A-Z][a-z]+)/)
-    .filter(Boolean)
+    .filter(isTruthy)
     .map((item) => item.toLocaleLowerCase());
   const caps = str
     .split(/([A-Z]{2,})/)
@@ -183,7 +183,7 @@ export function isNotString<T>(value: string | T): value is T {
 }
 
 export function assignExisting<T>(target: Record<string, T>, obj: Record<string, T>) {
-  for (let k of Object.keys(obj)) {
+  for (const k of Object.keys(obj)) {
     if (target.hasOwnProperty(k)) {
       target[k] = obj[k];
     }
@@ -217,3 +217,9 @@ export function showWarningForDeprecatedField(deprecatedField: string, updatedFi
 export function showErrorForDeprecatedField(deprecatedField: string, updatedField: string) {
   throw new Error(`Do not use '${deprecatedField}' field. Use '${updatedField}' instead.\n`);
 }
+
+export type Falsy = undefined | null | false | '' | 0;
+
+export function isTruthy<Truthy>(value: Truthy | Falsy): value is Truthy {
+  return !!value;
+}
diff --git a/packages/core/src/visitors.ts b/packages/core/src/visitors.ts
index baedd9ce..a6353e3c 100644
--- a/packages/core/src/visitors.ts
+++ b/packages/core/src/visitors.ts
@@ -70,7 +70,7 @@ type NestedVisitObject<T, P> = VisitObject<T> & NestedVisitor<P>;
 
 type VisitFunctionOrObject<T> = VisitFunction<T> | VisitObject<T>;
 
-type VisitorNode<T extends any> = {
+type VisitorNode<T> = {
   ruleId: string;
   severity: ProblemSeverity;
   context: VisitorLevelContext | VisitorSkippedLevelContext;
@@ -309,7 +309,7 @@ export function normalizeVisitors<T extends BaseVisitor>(
 
     const possibleChildren = new Set<NormalizedNodeType>();
 
-    for (let type of Object.values(from.properties)) {
+    for (const type of Object.values(from.properties)) {
       if (type === to) {
         addWeakFromStack(ruleConf, stack);
         continue;
@@ -333,7 +333,7 @@ export function normalizeVisitors<T extends BaseVisitor>(
       }
     }
 
-    for (let fromType of Array.from(possibleChildren.values())) {
+    for (const fromType of Array.from(possibleChildren.values())) {
       addWeakNodes(ruleConf, fromType, to, parentContext, stack);
     }
 
@@ -350,7 +350,7 @@ export function normalizeVisitors<T extends BaseVisitor>(
           visit: () => undefined,
           depth: 0,
           context: {
-            isSkippedLevel: true as true,
+            isSkippedLevel: true,
             seen: new Set(),
             parent: parentContext,
           },
@@ -407,7 +407,7 @@ export function normalizeVisitors<T extends BaseVisitor>(
         activatedOn: null,
         type: types[typeName],
         parent: parentContext,
-        isSkippedLevel: false as false,
+        isSkippedLevel: false,
       };
 
       if (typeof typeVisitor === 'object') {
diff --git a/tsconfig.json b/tsconfig.json
index 1e4f8086..e88eb130 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -8,8 +8,6 @@
     "noImplicitReturns": true,
     "noImplicitThis": true,
     "resolveJsonModule": true,
-    "noUnusedLocals": true,
-    "noUnusedParameters": true,
     "strictPropertyInitialization": true,
     "strictNullChecks": true,
     "strictFunctionTypes": true,


Test patch:
diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml
index 341eaab0..82b3d60f 100644
--- a/.github/workflows/tests.yaml
+++ b/.github/workflows/tests.yaml
@@ -101,4 +101,26 @@ jobs:
           restore-keys: |
             npm-${{ hashFiles('package-lock.json') }}
             npm-
+      - name: Install dependencies
+        run: npm ci
+        env:
+          CI: true
       - run: npm run prettier:check
+
+  eslint:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v3
+      - name: Cache dependencies
+        uses: actions/cache@v3
+        with:
+          path: ~/.npm
+          key: npm-${{ hashFiles('package-lock.json') }}
+          restore-keys: |
+            npm-${{ hashFiles('package-lock.json') }}
+            npm-
+      - name: Install dependencies
+        run: npm ci
+        env:
+          CI: true
+      - run: npm run eslint
diff --git a/packages/core/src/config/__tests__/config.test.ts b/packages/core/src/config/__tests__/config.test.ts
index 8afd99b2..dc8a197e 100644
--- a/packages/core/src/config/__tests__/config.test.ts
+++ b/packages/core/src/config/__tests__/config.test.ts
@@ -1,3 +1,4 @@
+import { OasVersion } from '../../oas-types';
 import { Config, StyleguideConfig } from '../config';
 import { getMergedConfig } from '../utils';
 
@@ -242,3 +243,37 @@ describe('getMergedConfig', () => {
     `);
   });
 });
+
+describe('StyleguideConfig.extendTypes', () => {
+  let oas3 = jest.fn();
+  let oas2 = jest.fn();
+  let testRawConfigStyleguide = {
+    plugins: [
+      {
+        id: 'test-types-plugin',
+        typeExtension: {
+          oas3,
+          oas2,
+        },
+      },
+    ],
+  };
+  it('should call only oas3 types extension', () => {
+    const styleguideConfig = new StyleguideConfig(testRawConfigStyleguide);
+    styleguideConfig.extendTypes({}, OasVersion.Version3_0);
+    expect(oas3).toHaveBeenCalledTimes(1);
+    expect(oas2).toHaveBeenCalledTimes(0);
+  });
+  it('should call only oas2 types extension', () => {
+    const styleguideConfig = new StyleguideConfig(testRawConfigStyleguide);
+    styleguideConfig.extendTypes({}, OasVersion.Version2);
+    expect(oas3).toHaveBeenCalledTimes(0);
+    expect(oas2).toHaveBeenCalledTimes(1);
+  });
+  it('should throw error if for oas version different from 2 and 3', () => {
+    const styleguideConfig = new StyleguideConfig(testRawConfigStyleguide);
+    expect(() => styleguideConfig.extendTypes({}, 'something else' as OasVersion)).toThrowError(
+      'Not implemented'
+    );
+  });
+});