├── .eslintignore ├── .eslintrc.json ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .prettierignore ├── .prettierrc.json ├── .vscode ├── extensions.json └── settings.json ├── CONTRIBUTING.md ├── LICENSE.txt ├── README.md ├── lerna.json ├── package-lock.json ├── package.json └── packages ├── check-es-compat ├── README.md ├── bin │ └── cli.js ├── package-lock.json └── package.json ├── eslint-plugin-ecmascript-compat-example ├── .browserslistrc ├── .eslintrc.json ├── package-lock.json ├── package.json └── src │ └── app.js └── eslint-plugin-ecmascript-compat ├── .gitignore ├── README.md ├── lib ├── compareVersions.js ├── compareVersions.test.js ├── compatibility.js ├── compatibility.test.js ├── delegation.js ├── delegation.test.js ├── features │ ├── es-versions.md │ ├── es2016.js │ ├── es2016.test.js │ ├── es2017.js │ ├── es2017.test.js │ ├── es2018.js │ ├── es2018.test.js │ ├── es2019.js │ ├── es2019.test.js │ ├── es2020.js │ ├── es2020.test.js │ ├── es2021.js │ ├── es2021.test.js │ ├── es2022.js │ ├── es2022.test.js │ ├── es2023.js │ ├── es2023.test.js │ ├── index.js │ └── ruleOptionsUtil.js ├── index.js ├── rule.js ├── rule.test.js ├── targetRuntimes.js └── targetRuntimes.test.js ├── package-lock.json └── package.json /.eslintignore: -------------------------------------------------------------------------------- 1 | # Example has deliberate errors for demonstration purposes 2 | /packages/eslint-plugin-ecmascript-compat-example 3 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | // Prettier presets are partial "anti-presets" for other presets, that disable unnecessary/conflicting rules. 4 | 5 | /* 6 | * Enable all rules: 7 | * 1. Majority of rules and default options are good 8 | * 2. eslint:recommended is only a small subset 9 | * 3. We automatically gain new rules when they are released 10 | */ 11 | "eslint:all", 12 | "prettier", 13 | 14 | // Need to be specific, because this config is one level above the package.jsons that have type:module 15 | "plugin:n/recommended-module" 16 | ], 17 | "plugins": ["import"], 18 | "parserOptions": { 19 | "ecmaVersion": 2022, 20 | "sourceType": "module" 21 | }, 22 | "env": { 23 | "es2021": true, 24 | "node": true 25 | }, 26 | "reportUnusedDisableDirectives": true, 27 | "rules": { 28 | // eslint:all - Disable unwanted rules. Add appropriate others as and when they're discovered. 29 | "capitalized-comments": "off", 30 | "global-require": "off", 31 | "init-declarations": "off", 32 | "line-comment-position": "off", 33 | "multiline-comment-style": "off", 34 | "no-eq-null": "off", 35 | "no-inline-comments": "off", 36 | "no-magic-numbers": "off", 37 | "no-plusplus": "off", 38 | "no-ternary": "off", 39 | "no-undefined": "off", 40 | "one-var": "off", 41 | "sort-imports": "off", // using import/order instead 42 | "sort-keys": "off", 43 | "strict": "off", 44 | 45 | // eslint:all - Modify default options 46 | "eqeqeq": ["error", "always", { "null": "never" }], 47 | "func-names": ["error", "as-needed"], 48 | "func-style": ["error", "declaration"], 49 | "id-length": ["error", { "exceptions": ["_", "a", "b", "i"] }], 50 | "no-unused-vars": ["error", { "ignoreRestSiblings": true }], 51 | "no-use-before-define": ["error", "nofunc"], 52 | "spaced-comment": ["error", "always", { "block": { "balanced": true } }], 53 | 54 | // eslint:all & prettier - Re-enable some of the rules that are compatible when certain options are used 55 | // (https://github.com/prettier/eslint-config-prettier#special-rules) 56 | "curly": "error", 57 | "max-len": ["error", { "code": 1000, "comments": 90, "ignoreUrls": true }], 58 | "quotes": [ 59 | "error", 60 | "single", 61 | { "avoidEscape": true, "allowTemplateLiterals": false } 62 | ], 63 | 64 | // eslint:all - Rules whose default options do nothing. Options need to be compatible with Prettier. 65 | "padding-line-between-statements": [ 66 | "error", 67 | { "blankLine": "always", "prev": "*", "next": ["cjs-export"] }, 68 | 69 | { "blankLine": "always", "prev": "*", "next": "block-like" }, 70 | { "blankLine": "always", "prev": "block-like", "next": "*" } 71 | ], 72 | 73 | // eslint-plugin-import - selection (not comprehensive) 74 | "import/newline-after-import": "error", 75 | "import/no-extraneous-dependencies": "error", 76 | "import/order": ["error", { "newlines-between": "never" }] 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Node CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - 'master' 7 | pull_request: 8 | types: [opened, synchronize, reopened] 9 | 10 | jobs: 11 | ci: 12 | runs-on: ubuntu-latest 13 | 14 | strategy: 15 | matrix: 16 | node-version: [16.x, 18.x, 20.x] 17 | 18 | steps: 19 | - uses: actions/checkout@v3 20 | - name: Use Node.js ${{ matrix.node-version }} 21 | uses: actions/setup-node@v3 22 | with: 23 | node-version: ${{ matrix.node-version }} 24 | 25 | - run: npm install 26 | - run: npm run ci 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /packages/*/node_modules 3 | 4 | # Patterns for /packages must go in the individual packages, as that's the only place 5 | # where lerna publish will look. See https://github.com/robatwilliams/es-compat/issues/8 . 6 | # Not using .npmignore files, to avoid possibility of getting out of sync. 7 | 8 | # Adding something? Might also need to go in .prettierignore 9 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | lerna.json 2 | package-lock.json 3 | 4 | /packages/*/coverage 5 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 90, 3 | "singleQuote": true, 4 | "overrides": [ 5 | { 6 | "files": "*.md", 7 | "options": { 8 | "printWidth": 120, 9 | "proseWrap": "never" 10 | } 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode"] 3 | } 4 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.defaultFormatter": "esbenp.prettier-vscode", 3 | "editor.formatOnSave": true, 4 | "editor.rulers": [90], // Prettier: printWidth 5 | 6 | "files.associations": { 7 | ".eslintrc.json": "jsonc" 8 | }, 9 | 10 | "files.eol": "\n", 11 | "files.insertFinalNewline": true, 12 | "files.trimFinalNewlines": true, 13 | "files.trimTrailingWhitespace": true, 14 | 15 | // Prevent ESLint extension getting confused in monorepo 16 | // https://github.com/microsoft/vscode-eslint/issues/696#issuecomment-553697002 17 | "eslint.workingDirectories": ["./"], 18 | 19 | "[markdown]": { 20 | "editor.rulers": [120] // Prettier: *.md printWidth 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Please get in touch before spending any significant time preparing contributions. 4 | 5 | ## Prerequisites 6 | 7 | - Node.js and NPM, versions as per the root `package.json` `engines` field 8 | - Lerna 4, just install it globally and [it'll use this project's local version](https://github.com/lerna/lerna/pull/1122) when run 9 | 10 | Different versions may work, but majorly newer/older tooling versions are likely to cause upheaval in `package-lock.json` files. 11 | 12 | ## Workflow 13 | 14 | - Self-explanatory NPM scripts in root and packages 15 | - Prettier and ESLint for code hygiene 16 | 17 | ## Pre-release checks 18 | 19 | - Verify there are no uncommitted changes 20 | - `npm run ci` in root 21 | - `npm run lint` in the example project, check number of errors and presence of new expected ones 22 | - `../check-es-compat/bin/cli.js .` in the example project, it should produce the same errors 23 | - `lerna clean` then `lerna bootstrap`, verify no changes were introduced (e.g. to `package-lock.json`) 24 | 25 | ## Releasing 26 | 27 | 1. `lerna version`, with arguments as appropriate for signifigance of release 28 | 1. Verify the commit that it made did what you expected 29 | 1. `lerna publish from-git` 30 | 1. In GitHub's Releases tab, open the new tag then create a release out of it 31 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Robat Williams 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | [![npm version](https://badge.fury.io/js/eslint-plugin-ecmascript-compat.svg)](https://badge.fury.io/js/eslint-plugin-ecmascript-compat) 3 | [![npm downloads](https://img.shields.io/npm/dm/eslint-plugin-ecmascript-compat.svg)](http://www.npmtrends.com/eslint-plugin-ecmascript-compat) 4 | 5 | 6 | # es-compat 7 | 8 | > Check JavaScript code compatibility with target browsers and Node.js versions 9 | 10 | Checks that the language features used in your code/bundles are supported by your [browserslist](https://github.com/browserslist/browserslist) targets. 11 | 12 | ## Tools 13 | 14 | - [check-es-compat](/packages/check-es-compat/README.md) - standalone CLI tool 15 | - [eslint-plugin-ecmascript-compat](/packages/eslint-plugin-ecmascript-compat/README.md) - ESLint plugin 16 | 17 | ## Rationale 18 | 19 | You might not need a transpiler or polyfills. 20 | 21 | Or, you may be transpiling your own code but not prebuilt 3rd-party libraries - leaving you open to breakages when they use new language features. 22 | 23 | [ESLint](https://eslint.org) supports targeting a specific ECMAScript version, and [eslint-plugin-es-x](https://github.com/eslint-community/eslint-plugin-es-x) allows forbidding individual language features. However when building applications, what we target are particular browser/runtime versions. This project lets you check compatibility by specifying those targets directly via a browserslist. It will figure out which individual features you can use, by looking up those targets in the [MDN compatibility dataset](https://github.com/mdn/browser-compat-data). 24 | 25 | ## Usage scenario examples 26 | 27 | If you're not using a transpiler, run the tool/linter on your source code to ensure you're not using language features that aren't supported in your application's supported browsers. 28 | 29 | If you transpile your own code but not 3rd party libraries, run the tool/linter on your output bundles to ensure they're not using language features that aren't supported in your application's supported browsers. 30 | 31 | ## Scope 32 | 33 | ECMAScript language features only; this includes syntax, built-ins, and methods. 34 | 35 | It doesn't check browser/runtime-specific APIs (see [eslint-plugin-compat](https://github.com/amilajack/eslint-plugin-compat)), or CSS (see [doiuse](https://github.com/anandthakker/doiuse)). 36 | 37 | ## ECMAScript version coverage 38 | 39 | - ✅ [ES2023](https://pawelgrzybek.com/whats-new-in-ecmascript-2023) 40 | - ✅ [ES2022](https://exploringjs.com/impatient-js/ch_new-javascript-features.html#new-in-es2022) 41 | - ✅ [ES2021](https://v8.dev/features/tags/es2021) 42 | - ✅ [ES2020](https://v8.dev/features/tags/es2020) 43 | - ✅ [ES2019](https://flaviocopes.com/es2019)1, 2 44 | - ✅ [ES2018](https://flaviocopes.com/es2018) 45 | - ✅ [ES2017](https://flaviocopes.com/es2017) 46 | - ✅ [ES2016](https://flaviocopes.com/es2016) 47 | - ⛔ [ES2015 (ES6)](https://flaviocopes.com/es6)3 48 | - ⛔ ES54 49 | 50 |
51 | n Expand for footnotes... 52 | 53 | 1 Excluding features not statically detectable: revised `Function.prototype.toString`, stable `Array.prototype.sort`, well-formed `JSON.stringify`. 54 | 55 | 2 Excluding `Symbol.prototype.description`; as a debug feature, it's not worth the false positives that arise due to its name and not being a method. 56 | 57 | 3 ES2015 (ES6) is out of scope; it's been [supported](https://caniuse.com/#feat=es6) by evergreen browsers for many years. Assisting you to continue supporting [IE11](https://death-to-ie11.com/) is not a goal of this tool. 58 | 59 | 4 ES5 is out of scope; it's over 10 years old and [supported](https://caniuse.com/es6#feat=es5) even in IE10. 60 | 61 |
62 | 63 | ## Browser compatibility data 64 | 65 | We use a pinned version of `@mdn/browser-compat-data`, because their [SemVer policy](https://github.com/mdn/browser-compat-data#semantic-versioning-policy) allows for breaking changes to the data structure even in minor and patch releases. If you need to use more up to date data, use the `overrides` facility of `package.json` to specify a later version - but be aware that it might break. 66 | 67 | ## Limitations 68 | 69 | Because JavaScript is untyped, detection of some features' usage (namely prototype methods) through static analysis requires some assumptions to be made. This shouldn't be a problem as long as you avoid creating your own methods having the same names, or write code in an unusual way to deliberately evade detection. 70 | 71 | Support can only be checked for the [browsers and runtimes covered](https://github.com/mdn/browser-compat-data/tree/main/browsers) by the MDN compatibility dataset. 72 | 73 | The MDN compatibility dataset has very good feature coverage of the top ~6 desktop and mobile browsers, and Node.js (much more than [kangax/compat-table](https://github.com/kangax/compat-table)). In case of missing data for a feature (support unknown, or unknown in which version support was added), we currently assume support. 74 | 75 | ## Contributing 76 | 77 | [Contributions](CONTRIBUTING.md) and feedback welcome. Please see the GitHub issues or create one, as appropriate. 78 | 79 | ## Related 80 | 81 | - [eslint-plugin-compat](https://github.com/amilajack/eslint-plugin-compat) - for browser APIs 82 | - [doiuse](https://github.com/anandthakker/doiuse) - for CSS 83 | - [eslint-plugin-es-x](https://github.com/eslint-community/eslint-plugin-es-x) (formerly [eslint-plugin-es](https://github.com/mysticatea/eslint-plugin-es))\* 84 | - [@mdn/browser-compat-data](https://github.com/mdn/browser-compat-data)\* 85 | 86 | \* Thanks to these projects in particular (and many others) for making this project possible. 87 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": [ 3 | "packages/*" 4 | ], 5 | "version": "3.2.1" 6 | } 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "es-compat", 3 | "private": true, 4 | "scripts": { 5 | "check": "npm-run-all --parallel check:*", 6 | "check:lint": "eslint --no-eslintrc --config=.eslintrc.json **/*.js", 7 | "check:prettier": "prettier --check **/*.{js,json,md}", 8 | "ci": "npm-run-all check test", 9 | "postinstall": "lerna bootstrap", 10 | "test": "lerna run test" 11 | }, 12 | "devDependencies": { 13 | "eslint": "^8.56.0", 14 | "eslint-config-prettier": "^8.3.0", 15 | "eslint-plugin-import": "^2.25.4", 16 | "eslint-plugin-n": "^15.7.0", 17 | "lerna": "^4.0.0", 18 | "npm-run-all": "^4.1.5", 19 | "prettier": "^2.5.1" 20 | }, 21 | "engines": { 22 | "node": ">=16.0.0", 23 | "npm": "^10.2.3" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/check-es-compat/README.md: -------------------------------------------------------------------------------- 1 | 2 | [![npm version](https://badge.fury.io/js/check-es-compat.svg)](https://badge.fury.io/js/check-es-compat) 3 | [![npm downloads](https://img.shields.io/npm/dm/check-es-compat.svg)](http://www.npmtrends.com/check-es-compat) 4 | 5 | 6 | # check-es-compat 7 | 8 | > CLI tool for checking JavaScript code compatibility with target browsers and Node.js versions 9 | 10 | ```bash 11 | $ npx check-es-compat . 12 | ``` 13 | 14 | ``` 15 | // .browserslistrc 16 | Chrome >= 64 17 | Firefox >= 58 18 | ``` 19 | 20 | 21 | 22 | It [doesn't currently support](https://github.com/robatwilliams/es-compat/issues/69) ES modules. 23 | 24 | 25 | 26 | ➡ For more information, see the [main readme](https://github.com/robatwilliams/es-compat#readme). 27 | -------------------------------------------------------------------------------- /packages/check-es-compat/bin/cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | /* eslint-disable no-console */ 3 | import { ESLint } from 'eslint'; 4 | 5 | const args = process.argv.slice(2); 6 | 7 | if (args.length === 0) { 8 | console.log('Usage: check-es-compat file.js [file.js] [dir]'); 9 | process.exitCode = 1; 10 | } else { 11 | const { hasErrors } = await execute(args); 12 | 13 | if (hasErrors) { 14 | process.exitCode = 1; 15 | } else { 16 | console.log('No issues found. Files are compatible with the target runtimes.'); 17 | } 18 | } 19 | 20 | async function execute(files) { 21 | const eslint = new ESLint({ 22 | // Ignore any config; it's for target's own linter setup rather than this tool. 23 | useEslintrc: false, 24 | ignore: false, 25 | allowInlineConfig: false, 26 | 27 | baseConfig: { 28 | plugins: ['ecmascript-compat'], 29 | parserOptions: { 30 | // Latest version, so all features work 31 | ecmaVersion: 2023, 32 | }, 33 | env: { 34 | // Latest globals, so all features work 35 | es2023: true, 36 | }, 37 | rules: { 38 | 'ecmascript-compat/compat': 'error', 39 | }, 40 | }, 41 | }); 42 | 43 | const results = await eslint.lintFiles(files); 44 | 45 | const formatter = await eslint.loadFormatter(); 46 | console.log(formatter.format(results)); 47 | 48 | return { hasErrors: results.some((result) => result.errorCount > 0) }; 49 | } 50 | -------------------------------------------------------------------------------- /packages/check-es-compat/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "check-es-compat", 3 | "version": "3.2.1", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "check-es-compat", 9 | "version": "3.2.0", 10 | "license": "MIT", 11 | "dependencies": { 12 | "eslint": "^8.56.0" 13 | }, 14 | "bin": { 15 | "check-es-compat": "bin/cli.mjs" 16 | }, 17 | "engines": { 18 | "node": ">=16.0.0" 19 | } 20 | }, 21 | "node_modules/@aashutoshrathi/word-wrap": { 22 | "version": "1.2.6", 23 | "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", 24 | "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", 25 | "engines": { 26 | "node": ">=0.10.0" 27 | } 28 | }, 29 | "node_modules/@eslint-community/eslint-utils": { 30 | "version": "4.4.0", 31 | "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", 32 | "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", 33 | "dependencies": { 34 | "eslint-visitor-keys": "^3.3.0" 35 | }, 36 | "engines": { 37 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 38 | }, 39 | "peerDependencies": { 40 | "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" 41 | } 42 | }, 43 | "node_modules/@eslint-community/regexpp": { 44 | "version": "4.10.0", 45 | "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", 46 | "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", 47 | "engines": { 48 | "node": "^12.0.0 || ^14.0.0 || >=16.0.0" 49 | } 50 | }, 51 | "node_modules/@eslint/eslintrc": { 52 | "version": "2.1.4", 53 | "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", 54 | "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", 55 | "dependencies": { 56 | "ajv": "^6.12.4", 57 | "debug": "^4.3.2", 58 | "espree": "^9.6.0", 59 | "globals": "^13.19.0", 60 | "ignore": "^5.2.0", 61 | "import-fresh": "^3.2.1", 62 | "js-yaml": "^4.1.0", 63 | "minimatch": "^3.1.2", 64 | "strip-json-comments": "^3.1.1" 65 | }, 66 | "engines": { 67 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 68 | }, 69 | "funding": { 70 | "url": "https://opencollective.com/eslint" 71 | } 72 | }, 73 | "node_modules/@eslint/js": { 74 | "version": "8.56.0", 75 | "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", 76 | "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", 77 | "engines": { 78 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 79 | } 80 | }, 81 | "node_modules/@humanwhocodes/config-array": { 82 | "version": "0.11.14", 83 | "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", 84 | "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", 85 | "dependencies": { 86 | "@humanwhocodes/object-schema": "^2.0.2", 87 | "debug": "^4.3.1", 88 | "minimatch": "^3.0.5" 89 | }, 90 | "engines": { 91 | "node": ">=10.10.0" 92 | } 93 | }, 94 | "node_modules/@humanwhocodes/module-importer": { 95 | "version": "1.0.1", 96 | "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", 97 | "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", 98 | "engines": { 99 | "node": ">=12.22" 100 | }, 101 | "funding": { 102 | "type": "github", 103 | "url": "https://github.com/sponsors/nzakas" 104 | } 105 | }, 106 | "node_modules/@humanwhocodes/object-schema": { 107 | "version": "2.0.2", 108 | "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", 109 | "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==" 110 | }, 111 | "node_modules/@nodelib/fs.scandir": { 112 | "version": "2.1.5", 113 | "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", 114 | "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", 115 | "dependencies": { 116 | "@nodelib/fs.stat": "2.0.5", 117 | "run-parallel": "^1.1.9" 118 | }, 119 | "engines": { 120 | "node": ">= 8" 121 | } 122 | }, 123 | "node_modules/@nodelib/fs.stat": { 124 | "version": "2.0.5", 125 | "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", 126 | "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", 127 | "engines": { 128 | "node": ">= 8" 129 | } 130 | }, 131 | "node_modules/@nodelib/fs.walk": { 132 | "version": "1.2.8", 133 | "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", 134 | "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", 135 | "dependencies": { 136 | "@nodelib/fs.scandir": "2.1.5", 137 | "fastq": "^1.6.0" 138 | }, 139 | "engines": { 140 | "node": ">= 8" 141 | } 142 | }, 143 | "node_modules/@ungap/structured-clone": { 144 | "version": "1.2.0", 145 | "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", 146 | "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" 147 | }, 148 | "node_modules/acorn": { 149 | "version": "8.11.3", 150 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", 151 | "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", 152 | "bin": { 153 | "acorn": "bin/acorn" 154 | }, 155 | "engines": { 156 | "node": ">=0.4.0" 157 | } 158 | }, 159 | "node_modules/acorn-jsx": { 160 | "version": "5.3.2", 161 | "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", 162 | "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", 163 | "peerDependencies": { 164 | "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" 165 | } 166 | }, 167 | "node_modules/ajv": { 168 | "version": "6.12.6", 169 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", 170 | "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", 171 | "dependencies": { 172 | "fast-deep-equal": "^3.1.1", 173 | "fast-json-stable-stringify": "^2.0.0", 174 | "json-schema-traverse": "^0.4.1", 175 | "uri-js": "^4.2.2" 176 | }, 177 | "funding": { 178 | "type": "github", 179 | "url": "https://github.com/sponsors/epoberezkin" 180 | } 181 | }, 182 | "node_modules/ansi-regex": { 183 | "version": "5.0.1", 184 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 185 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", 186 | "engines": { 187 | "node": ">=8" 188 | } 189 | }, 190 | "node_modules/ansi-styles": { 191 | "version": "4.3.0", 192 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 193 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 194 | "dependencies": { 195 | "color-convert": "^2.0.1" 196 | }, 197 | "engines": { 198 | "node": ">=8" 199 | }, 200 | "funding": { 201 | "url": "https://github.com/chalk/ansi-styles?sponsor=1" 202 | } 203 | }, 204 | "node_modules/argparse": { 205 | "version": "2.0.1", 206 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", 207 | "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" 208 | }, 209 | "node_modules/balanced-match": { 210 | "version": "1.0.2", 211 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 212 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" 213 | }, 214 | "node_modules/brace-expansion": { 215 | "version": "1.1.11", 216 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 217 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 218 | "dependencies": { 219 | "balanced-match": "^1.0.0", 220 | "concat-map": "0.0.1" 221 | } 222 | }, 223 | "node_modules/callsites": { 224 | "version": "3.1.0", 225 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", 226 | "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", 227 | "engines": { 228 | "node": ">=6" 229 | } 230 | }, 231 | "node_modules/chalk": { 232 | "version": "4.1.2", 233 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", 234 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", 235 | "dependencies": { 236 | "ansi-styles": "^4.1.0", 237 | "supports-color": "^7.1.0" 238 | }, 239 | "engines": { 240 | "node": ">=10" 241 | }, 242 | "funding": { 243 | "url": "https://github.com/chalk/chalk?sponsor=1" 244 | } 245 | }, 246 | "node_modules/color-convert": { 247 | "version": "2.0.1", 248 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 249 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 250 | "dependencies": { 251 | "color-name": "~1.1.4" 252 | }, 253 | "engines": { 254 | "node": ">=7.0.0" 255 | } 256 | }, 257 | "node_modules/color-name": { 258 | "version": "1.1.4", 259 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 260 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" 261 | }, 262 | "node_modules/concat-map": { 263 | "version": "0.0.1", 264 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 265 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" 266 | }, 267 | "node_modules/cross-spawn": { 268 | "version": "7.0.3", 269 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", 270 | "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", 271 | "dependencies": { 272 | "path-key": "^3.1.0", 273 | "shebang-command": "^2.0.0", 274 | "which": "^2.0.1" 275 | }, 276 | "engines": { 277 | "node": ">= 8" 278 | } 279 | }, 280 | "node_modules/debug": { 281 | "version": "4.3.4", 282 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", 283 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", 284 | "dependencies": { 285 | "ms": "2.1.2" 286 | }, 287 | "engines": { 288 | "node": ">=6.0" 289 | }, 290 | "peerDependenciesMeta": { 291 | "supports-color": { 292 | "optional": true 293 | } 294 | } 295 | }, 296 | "node_modules/deep-is": { 297 | "version": "0.1.4", 298 | "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", 299 | "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" 300 | }, 301 | "node_modules/doctrine": { 302 | "version": "3.0.0", 303 | "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", 304 | "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", 305 | "dependencies": { 306 | "esutils": "^2.0.2" 307 | }, 308 | "engines": { 309 | "node": ">=6.0.0" 310 | } 311 | }, 312 | "node_modules/escape-string-regexp": { 313 | "version": "4.0.0", 314 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", 315 | "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", 316 | "engines": { 317 | "node": ">=10" 318 | }, 319 | "funding": { 320 | "url": "https://github.com/sponsors/sindresorhus" 321 | } 322 | }, 323 | "node_modules/eslint": { 324 | "version": "8.56.0", 325 | "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", 326 | "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", 327 | "dependencies": { 328 | "@eslint-community/eslint-utils": "^4.2.0", 329 | "@eslint-community/regexpp": "^4.6.1", 330 | "@eslint/eslintrc": "^2.1.4", 331 | "@eslint/js": "8.56.0", 332 | "@humanwhocodes/config-array": "^0.11.13", 333 | "@humanwhocodes/module-importer": "^1.0.1", 334 | "@nodelib/fs.walk": "^1.2.8", 335 | "@ungap/structured-clone": "^1.2.0", 336 | "ajv": "^6.12.4", 337 | "chalk": "^4.0.0", 338 | "cross-spawn": "^7.0.2", 339 | "debug": "^4.3.2", 340 | "doctrine": "^3.0.0", 341 | "escape-string-regexp": "^4.0.0", 342 | "eslint-scope": "^7.2.2", 343 | "eslint-visitor-keys": "^3.4.3", 344 | "espree": "^9.6.1", 345 | "esquery": "^1.4.2", 346 | "esutils": "^2.0.2", 347 | "fast-deep-equal": "^3.1.3", 348 | "file-entry-cache": "^6.0.1", 349 | "find-up": "^5.0.0", 350 | "glob-parent": "^6.0.2", 351 | "globals": "^13.19.0", 352 | "graphemer": "^1.4.0", 353 | "ignore": "^5.2.0", 354 | "imurmurhash": "^0.1.4", 355 | "is-glob": "^4.0.0", 356 | "is-path-inside": "^3.0.3", 357 | "js-yaml": "^4.1.0", 358 | "json-stable-stringify-without-jsonify": "^1.0.1", 359 | "levn": "^0.4.1", 360 | "lodash.merge": "^4.6.2", 361 | "minimatch": "^3.1.2", 362 | "natural-compare": "^1.4.0", 363 | "optionator": "^0.9.3", 364 | "strip-ansi": "^6.0.1", 365 | "text-table": "^0.2.0" 366 | }, 367 | "bin": { 368 | "eslint": "bin/eslint.js" 369 | }, 370 | "engines": { 371 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 372 | }, 373 | "funding": { 374 | "url": "https://opencollective.com/eslint" 375 | } 376 | }, 377 | "node_modules/eslint-scope": { 378 | "version": "7.2.2", 379 | "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", 380 | "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", 381 | "dependencies": { 382 | "esrecurse": "^4.3.0", 383 | "estraverse": "^5.2.0" 384 | }, 385 | "engines": { 386 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 387 | }, 388 | "funding": { 389 | "url": "https://opencollective.com/eslint" 390 | } 391 | }, 392 | "node_modules/eslint-visitor-keys": { 393 | "version": "3.4.3", 394 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", 395 | "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", 396 | "engines": { 397 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 398 | }, 399 | "funding": { 400 | "url": "https://opencollective.com/eslint" 401 | } 402 | }, 403 | "node_modules/espree": { 404 | "version": "9.6.1", 405 | "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", 406 | "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", 407 | "dependencies": { 408 | "acorn": "^8.9.0", 409 | "acorn-jsx": "^5.3.2", 410 | "eslint-visitor-keys": "^3.4.1" 411 | }, 412 | "engines": { 413 | "node": "^12.22.0 || ^14.17.0 || >=16.0.0" 414 | }, 415 | "funding": { 416 | "url": "https://opencollective.com/eslint" 417 | } 418 | }, 419 | "node_modules/esquery": { 420 | "version": "1.5.0", 421 | "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", 422 | "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", 423 | "dependencies": { 424 | "estraverse": "^5.1.0" 425 | }, 426 | "engines": { 427 | "node": ">=0.10" 428 | } 429 | }, 430 | "node_modules/esrecurse": { 431 | "version": "4.3.0", 432 | "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", 433 | "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", 434 | "dependencies": { 435 | "estraverse": "^5.2.0" 436 | }, 437 | "engines": { 438 | "node": ">=4.0" 439 | } 440 | }, 441 | "node_modules/estraverse": { 442 | "version": "5.3.0", 443 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", 444 | "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", 445 | "engines": { 446 | "node": ">=4.0" 447 | } 448 | }, 449 | "node_modules/esutils": { 450 | "version": "2.0.3", 451 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", 452 | "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", 453 | "engines": { 454 | "node": ">=0.10.0" 455 | } 456 | }, 457 | "node_modules/fast-deep-equal": { 458 | "version": "3.1.3", 459 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", 460 | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" 461 | }, 462 | "node_modules/fast-json-stable-stringify": { 463 | "version": "2.1.0", 464 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", 465 | "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" 466 | }, 467 | "node_modules/fast-levenshtein": { 468 | "version": "2.0.6", 469 | "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", 470 | "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" 471 | }, 472 | "node_modules/fastq": { 473 | "version": "1.16.0", 474 | "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz", 475 | "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==", 476 | "dependencies": { 477 | "reusify": "^1.0.4" 478 | } 479 | }, 480 | "node_modules/file-entry-cache": { 481 | "version": "6.0.1", 482 | "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", 483 | "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", 484 | "dependencies": { 485 | "flat-cache": "^3.0.4" 486 | }, 487 | "engines": { 488 | "node": "^10.12.0 || >=12.0.0" 489 | } 490 | }, 491 | "node_modules/find-up": { 492 | "version": "5.0.0", 493 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", 494 | "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", 495 | "dependencies": { 496 | "locate-path": "^6.0.0", 497 | "path-exists": "^4.0.0" 498 | }, 499 | "engines": { 500 | "node": ">=10" 501 | }, 502 | "funding": { 503 | "url": "https://github.com/sponsors/sindresorhus" 504 | } 505 | }, 506 | "node_modules/flat-cache": { 507 | "version": "3.0.4", 508 | "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", 509 | "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", 510 | "dependencies": { 511 | "flatted": "^3.1.0", 512 | "rimraf": "^3.0.2" 513 | }, 514 | "engines": { 515 | "node": "^10.12.0 || >=12.0.0" 516 | } 517 | }, 518 | "node_modules/flatted": { 519 | "version": "3.2.4", 520 | "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.4.tgz", 521 | "integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==" 522 | }, 523 | "node_modules/fs.realpath": { 524 | "version": "1.0.0", 525 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 526 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" 527 | }, 528 | "node_modules/glob": { 529 | "version": "7.2.0", 530 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", 531 | "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", 532 | "dependencies": { 533 | "fs.realpath": "^1.0.0", 534 | "inflight": "^1.0.4", 535 | "inherits": "2", 536 | "minimatch": "^3.0.4", 537 | "once": "^1.3.0", 538 | "path-is-absolute": "^1.0.0" 539 | }, 540 | "engines": { 541 | "node": "*" 542 | }, 543 | "funding": { 544 | "url": "https://github.com/sponsors/isaacs" 545 | } 546 | }, 547 | "node_modules/glob-parent": { 548 | "version": "6.0.2", 549 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", 550 | "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", 551 | "dependencies": { 552 | "is-glob": "^4.0.3" 553 | }, 554 | "engines": { 555 | "node": ">=10.13.0" 556 | } 557 | }, 558 | "node_modules/globals": { 559 | "version": "13.24.0", 560 | "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", 561 | "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", 562 | "dependencies": { 563 | "type-fest": "^0.20.2" 564 | }, 565 | "engines": { 566 | "node": ">=8" 567 | }, 568 | "funding": { 569 | "url": "https://github.com/sponsors/sindresorhus" 570 | } 571 | }, 572 | "node_modules/graphemer": { 573 | "version": "1.4.0", 574 | "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", 575 | "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==" 576 | }, 577 | "node_modules/has-flag": { 578 | "version": "4.0.0", 579 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 580 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", 581 | "engines": { 582 | "node": ">=8" 583 | } 584 | }, 585 | "node_modules/ignore": { 586 | "version": "5.3.0", 587 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", 588 | "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", 589 | "engines": { 590 | "node": ">= 4" 591 | } 592 | }, 593 | "node_modules/import-fresh": { 594 | "version": "3.3.0", 595 | "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", 596 | "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", 597 | "dependencies": { 598 | "parent-module": "^1.0.0", 599 | "resolve-from": "^4.0.0" 600 | }, 601 | "engines": { 602 | "node": ">=6" 603 | }, 604 | "funding": { 605 | "url": "https://github.com/sponsors/sindresorhus" 606 | } 607 | }, 608 | "node_modules/imurmurhash": { 609 | "version": "0.1.4", 610 | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", 611 | "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", 612 | "engines": { 613 | "node": ">=0.8.19" 614 | } 615 | }, 616 | "node_modules/inflight": { 617 | "version": "1.0.6", 618 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 619 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 620 | "dependencies": { 621 | "once": "^1.3.0", 622 | "wrappy": "1" 623 | } 624 | }, 625 | "node_modules/inherits": { 626 | "version": "2.0.4", 627 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 628 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 629 | }, 630 | "node_modules/is-extglob": { 631 | "version": "2.1.1", 632 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 633 | "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", 634 | "engines": { 635 | "node": ">=0.10.0" 636 | } 637 | }, 638 | "node_modules/is-glob": { 639 | "version": "4.0.3", 640 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 641 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 642 | "dependencies": { 643 | "is-extglob": "^2.1.1" 644 | }, 645 | "engines": { 646 | "node": ">=0.10.0" 647 | } 648 | }, 649 | "node_modules/is-path-inside": { 650 | "version": "3.0.3", 651 | "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", 652 | "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", 653 | "engines": { 654 | "node": ">=8" 655 | } 656 | }, 657 | "node_modules/isexe": { 658 | "version": "2.0.0", 659 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 660 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" 661 | }, 662 | "node_modules/js-yaml": { 663 | "version": "4.1.0", 664 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", 665 | "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", 666 | "dependencies": { 667 | "argparse": "^2.0.1" 668 | }, 669 | "bin": { 670 | "js-yaml": "bin/js-yaml.js" 671 | } 672 | }, 673 | "node_modules/json-schema-traverse": { 674 | "version": "0.4.1", 675 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 676 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" 677 | }, 678 | "node_modules/json-stable-stringify-without-jsonify": { 679 | "version": "1.0.1", 680 | "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", 681 | "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=" 682 | }, 683 | "node_modules/levn": { 684 | "version": "0.4.1", 685 | "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", 686 | "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", 687 | "dependencies": { 688 | "prelude-ls": "^1.2.1", 689 | "type-check": "~0.4.0" 690 | }, 691 | "engines": { 692 | "node": ">= 0.8.0" 693 | } 694 | }, 695 | "node_modules/locate-path": { 696 | "version": "6.0.0", 697 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", 698 | "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", 699 | "dependencies": { 700 | "p-locate": "^5.0.0" 701 | }, 702 | "engines": { 703 | "node": ">=10" 704 | }, 705 | "funding": { 706 | "url": "https://github.com/sponsors/sindresorhus" 707 | } 708 | }, 709 | "node_modules/lodash.merge": { 710 | "version": "4.6.2", 711 | "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", 712 | "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" 713 | }, 714 | "node_modules/minimatch": { 715 | "version": "3.1.2", 716 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 717 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 718 | "dependencies": { 719 | "brace-expansion": "^1.1.7" 720 | }, 721 | "engines": { 722 | "node": "*" 723 | } 724 | }, 725 | "node_modules/ms": { 726 | "version": "2.1.2", 727 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 728 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 729 | }, 730 | "node_modules/natural-compare": { 731 | "version": "1.4.0", 732 | "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", 733 | "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=" 734 | }, 735 | "node_modules/once": { 736 | "version": "1.4.0", 737 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 738 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 739 | "dependencies": { 740 | "wrappy": "1" 741 | } 742 | }, 743 | "node_modules/optionator": { 744 | "version": "0.9.3", 745 | "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", 746 | "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", 747 | "dependencies": { 748 | "@aashutoshrathi/word-wrap": "^1.2.3", 749 | "deep-is": "^0.1.3", 750 | "fast-levenshtein": "^2.0.6", 751 | "levn": "^0.4.1", 752 | "prelude-ls": "^1.2.1", 753 | "type-check": "^0.4.0" 754 | }, 755 | "engines": { 756 | "node": ">= 0.8.0" 757 | } 758 | }, 759 | "node_modules/p-limit": { 760 | "version": "3.1.0", 761 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", 762 | "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", 763 | "dependencies": { 764 | "yocto-queue": "^0.1.0" 765 | }, 766 | "engines": { 767 | "node": ">=10" 768 | }, 769 | "funding": { 770 | "url": "https://github.com/sponsors/sindresorhus" 771 | } 772 | }, 773 | "node_modules/p-locate": { 774 | "version": "5.0.0", 775 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", 776 | "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", 777 | "dependencies": { 778 | "p-limit": "^3.0.2" 779 | }, 780 | "engines": { 781 | "node": ">=10" 782 | }, 783 | "funding": { 784 | "url": "https://github.com/sponsors/sindresorhus" 785 | } 786 | }, 787 | "node_modules/parent-module": { 788 | "version": "1.0.1", 789 | "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", 790 | "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", 791 | "dependencies": { 792 | "callsites": "^3.0.0" 793 | }, 794 | "engines": { 795 | "node": ">=6" 796 | } 797 | }, 798 | "node_modules/path-exists": { 799 | "version": "4.0.0", 800 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", 801 | "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", 802 | "engines": { 803 | "node": ">=8" 804 | } 805 | }, 806 | "node_modules/path-is-absolute": { 807 | "version": "1.0.1", 808 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 809 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 810 | "engines": { 811 | "node": ">=0.10.0" 812 | } 813 | }, 814 | "node_modules/path-key": { 815 | "version": "3.1.1", 816 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", 817 | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", 818 | "engines": { 819 | "node": ">=8" 820 | } 821 | }, 822 | "node_modules/prelude-ls": { 823 | "version": "1.2.1", 824 | "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", 825 | "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", 826 | "engines": { 827 | "node": ">= 0.8.0" 828 | } 829 | }, 830 | "node_modules/punycode": { 831 | "version": "2.3.1", 832 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", 833 | "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", 834 | "engines": { 835 | "node": ">=6" 836 | } 837 | }, 838 | "node_modules/queue-microtask": { 839 | "version": "1.2.3", 840 | "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", 841 | "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", 842 | "funding": [ 843 | { 844 | "type": "github", 845 | "url": "https://github.com/sponsors/feross" 846 | }, 847 | { 848 | "type": "patreon", 849 | "url": "https://www.patreon.com/feross" 850 | }, 851 | { 852 | "type": "consulting", 853 | "url": "https://feross.org/support" 854 | } 855 | ] 856 | }, 857 | "node_modules/resolve-from": { 858 | "version": "4.0.0", 859 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", 860 | "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", 861 | "engines": { 862 | "node": ">=4" 863 | } 864 | }, 865 | "node_modules/reusify": { 866 | "version": "1.0.4", 867 | "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", 868 | "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", 869 | "engines": { 870 | "iojs": ">=1.0.0", 871 | "node": ">=0.10.0" 872 | } 873 | }, 874 | "node_modules/rimraf": { 875 | "version": "3.0.2", 876 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", 877 | "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", 878 | "dependencies": { 879 | "glob": "^7.1.3" 880 | }, 881 | "bin": { 882 | "rimraf": "bin.js" 883 | }, 884 | "funding": { 885 | "url": "https://github.com/sponsors/isaacs" 886 | } 887 | }, 888 | "node_modules/run-parallel": { 889 | "version": "1.2.0", 890 | "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", 891 | "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", 892 | "funding": [ 893 | { 894 | "type": "github", 895 | "url": "https://github.com/sponsors/feross" 896 | }, 897 | { 898 | "type": "patreon", 899 | "url": "https://www.patreon.com/feross" 900 | }, 901 | { 902 | "type": "consulting", 903 | "url": "https://feross.org/support" 904 | } 905 | ], 906 | "dependencies": { 907 | "queue-microtask": "^1.2.2" 908 | } 909 | }, 910 | "node_modules/shebang-command": { 911 | "version": "2.0.0", 912 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", 913 | "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", 914 | "dependencies": { 915 | "shebang-regex": "^3.0.0" 916 | }, 917 | "engines": { 918 | "node": ">=8" 919 | } 920 | }, 921 | "node_modules/shebang-regex": { 922 | "version": "3.0.0", 923 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", 924 | "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", 925 | "engines": { 926 | "node": ">=8" 927 | } 928 | }, 929 | "node_modules/strip-ansi": { 930 | "version": "6.0.1", 931 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 932 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 933 | "dependencies": { 934 | "ansi-regex": "^5.0.1" 935 | }, 936 | "engines": { 937 | "node": ">=8" 938 | } 939 | }, 940 | "node_modules/strip-json-comments": { 941 | "version": "3.1.1", 942 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", 943 | "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", 944 | "engines": { 945 | "node": ">=8" 946 | }, 947 | "funding": { 948 | "url": "https://github.com/sponsors/sindresorhus" 949 | } 950 | }, 951 | "node_modules/supports-color": { 952 | "version": "7.2.0", 953 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 954 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 955 | "dependencies": { 956 | "has-flag": "^4.0.0" 957 | }, 958 | "engines": { 959 | "node": ">=8" 960 | } 961 | }, 962 | "node_modules/text-table": { 963 | "version": "0.2.0", 964 | "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", 965 | "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" 966 | }, 967 | "node_modules/type-check": { 968 | "version": "0.4.0", 969 | "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", 970 | "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", 971 | "dependencies": { 972 | "prelude-ls": "^1.2.1" 973 | }, 974 | "engines": { 975 | "node": ">= 0.8.0" 976 | } 977 | }, 978 | "node_modules/type-fest": { 979 | "version": "0.20.2", 980 | "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", 981 | "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", 982 | "engines": { 983 | "node": ">=10" 984 | }, 985 | "funding": { 986 | "url": "https://github.com/sponsors/sindresorhus" 987 | } 988 | }, 989 | "node_modules/uri-js": { 990 | "version": "4.4.1", 991 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", 992 | "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", 993 | "dependencies": { 994 | "punycode": "^2.1.0" 995 | } 996 | }, 997 | "node_modules/which": { 998 | "version": "2.0.2", 999 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", 1000 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", 1001 | "dependencies": { 1002 | "isexe": "^2.0.0" 1003 | }, 1004 | "bin": { 1005 | "node-which": "bin/node-which" 1006 | }, 1007 | "engines": { 1008 | "node": ">= 8" 1009 | } 1010 | }, 1011 | "node_modules/wrappy": { 1012 | "version": "1.0.2", 1013 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1014 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" 1015 | }, 1016 | "node_modules/yocto-queue": { 1017 | "version": "0.1.0", 1018 | "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", 1019 | "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", 1020 | "engines": { 1021 | "node": ">=10" 1022 | }, 1023 | "funding": { 1024 | "url": "https://github.com/sponsors/sindresorhus" 1025 | } 1026 | } 1027 | }, 1028 | "dependencies": { 1029 | "@aashutoshrathi/word-wrap": { 1030 | "version": "1.2.6", 1031 | "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", 1032 | "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==" 1033 | }, 1034 | "@eslint-community/eslint-utils": { 1035 | "version": "4.4.0", 1036 | "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", 1037 | "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", 1038 | "requires": { 1039 | "eslint-visitor-keys": "^3.3.0" 1040 | } 1041 | }, 1042 | "@eslint-community/regexpp": { 1043 | "version": "4.10.0", 1044 | "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", 1045 | "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==" 1046 | }, 1047 | "@eslint/eslintrc": { 1048 | "version": "2.1.4", 1049 | "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", 1050 | "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", 1051 | "requires": { 1052 | "ajv": "^6.12.4", 1053 | "debug": "^4.3.2", 1054 | "espree": "^9.6.0", 1055 | "globals": "^13.19.0", 1056 | "ignore": "^5.2.0", 1057 | "import-fresh": "^3.2.1", 1058 | "js-yaml": "^4.1.0", 1059 | "minimatch": "^3.1.2", 1060 | "strip-json-comments": "^3.1.1" 1061 | } 1062 | }, 1063 | "@eslint/js": { 1064 | "version": "8.56.0", 1065 | "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", 1066 | "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==" 1067 | }, 1068 | "@humanwhocodes/config-array": { 1069 | "version": "0.11.14", 1070 | "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", 1071 | "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", 1072 | "requires": { 1073 | "@humanwhocodes/object-schema": "^2.0.2", 1074 | "debug": "^4.3.1", 1075 | "minimatch": "^3.0.5" 1076 | } 1077 | }, 1078 | "@humanwhocodes/module-importer": { 1079 | "version": "1.0.1", 1080 | "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", 1081 | "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==" 1082 | }, 1083 | "@humanwhocodes/object-schema": { 1084 | "version": "2.0.2", 1085 | "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", 1086 | "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==" 1087 | }, 1088 | "@nodelib/fs.scandir": { 1089 | "version": "2.1.5", 1090 | "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", 1091 | "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", 1092 | "requires": { 1093 | "@nodelib/fs.stat": "2.0.5", 1094 | "run-parallel": "^1.1.9" 1095 | } 1096 | }, 1097 | "@nodelib/fs.stat": { 1098 | "version": "2.0.5", 1099 | "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", 1100 | "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==" 1101 | }, 1102 | "@nodelib/fs.walk": { 1103 | "version": "1.2.8", 1104 | "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", 1105 | "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", 1106 | "requires": { 1107 | "@nodelib/fs.scandir": "2.1.5", 1108 | "fastq": "^1.6.0" 1109 | } 1110 | }, 1111 | "@ungap/structured-clone": { 1112 | "version": "1.2.0", 1113 | "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", 1114 | "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" 1115 | }, 1116 | "acorn": { 1117 | "version": "8.11.3", 1118 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", 1119 | "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==" 1120 | }, 1121 | "acorn-jsx": { 1122 | "version": "5.3.2", 1123 | "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", 1124 | "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", 1125 | "requires": {} 1126 | }, 1127 | "ajv": { 1128 | "version": "6.12.6", 1129 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", 1130 | "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", 1131 | "requires": { 1132 | "fast-deep-equal": "^3.1.1", 1133 | "fast-json-stable-stringify": "^2.0.0", 1134 | "json-schema-traverse": "^0.4.1", 1135 | "uri-js": "^4.2.2" 1136 | } 1137 | }, 1138 | "ansi-regex": { 1139 | "version": "5.0.1", 1140 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 1141 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" 1142 | }, 1143 | "ansi-styles": { 1144 | "version": "4.3.0", 1145 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 1146 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 1147 | "requires": { 1148 | "color-convert": "^2.0.1" 1149 | } 1150 | }, 1151 | "argparse": { 1152 | "version": "2.0.1", 1153 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", 1154 | "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" 1155 | }, 1156 | "balanced-match": { 1157 | "version": "1.0.2", 1158 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", 1159 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" 1160 | }, 1161 | "brace-expansion": { 1162 | "version": "1.1.11", 1163 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 1164 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 1165 | "requires": { 1166 | "balanced-match": "^1.0.0", 1167 | "concat-map": "0.0.1" 1168 | } 1169 | }, 1170 | "callsites": { 1171 | "version": "3.1.0", 1172 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", 1173 | "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" 1174 | }, 1175 | "chalk": { 1176 | "version": "4.1.2", 1177 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", 1178 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", 1179 | "requires": { 1180 | "ansi-styles": "^4.1.0", 1181 | "supports-color": "^7.1.0" 1182 | } 1183 | }, 1184 | "color-convert": { 1185 | "version": "2.0.1", 1186 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 1187 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 1188 | "requires": { 1189 | "color-name": "~1.1.4" 1190 | } 1191 | }, 1192 | "color-name": { 1193 | "version": "1.1.4", 1194 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 1195 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" 1196 | }, 1197 | "concat-map": { 1198 | "version": "0.0.1", 1199 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 1200 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" 1201 | }, 1202 | "cross-spawn": { 1203 | "version": "7.0.3", 1204 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", 1205 | "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", 1206 | "requires": { 1207 | "path-key": "^3.1.0", 1208 | "shebang-command": "^2.0.0", 1209 | "which": "^2.0.1" 1210 | } 1211 | }, 1212 | "debug": { 1213 | "version": "4.3.4", 1214 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", 1215 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", 1216 | "requires": { 1217 | "ms": "2.1.2" 1218 | } 1219 | }, 1220 | "deep-is": { 1221 | "version": "0.1.4", 1222 | "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", 1223 | "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" 1224 | }, 1225 | "doctrine": { 1226 | "version": "3.0.0", 1227 | "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", 1228 | "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", 1229 | "requires": { 1230 | "esutils": "^2.0.2" 1231 | } 1232 | }, 1233 | "escape-string-regexp": { 1234 | "version": "4.0.0", 1235 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", 1236 | "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" 1237 | }, 1238 | "eslint": { 1239 | "version": "8.56.0", 1240 | "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", 1241 | "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", 1242 | "requires": { 1243 | "@eslint-community/eslint-utils": "^4.2.0", 1244 | "@eslint-community/regexpp": "^4.6.1", 1245 | "@eslint/eslintrc": "^2.1.4", 1246 | "@eslint/js": "8.56.0", 1247 | "@humanwhocodes/config-array": "^0.11.13", 1248 | "@humanwhocodes/module-importer": "^1.0.1", 1249 | "@nodelib/fs.walk": "^1.2.8", 1250 | "@ungap/structured-clone": "^1.2.0", 1251 | "ajv": "^6.12.4", 1252 | "chalk": "^4.0.0", 1253 | "cross-spawn": "^7.0.2", 1254 | "debug": "^4.3.2", 1255 | "doctrine": "^3.0.0", 1256 | "escape-string-regexp": "^4.0.0", 1257 | "eslint-scope": "^7.2.2", 1258 | "eslint-visitor-keys": "^3.4.3", 1259 | "espree": "^9.6.1", 1260 | "esquery": "^1.4.2", 1261 | "esutils": "^2.0.2", 1262 | "fast-deep-equal": "^3.1.3", 1263 | "file-entry-cache": "^6.0.1", 1264 | "find-up": "^5.0.0", 1265 | "glob-parent": "^6.0.2", 1266 | "globals": "^13.19.0", 1267 | "graphemer": "^1.4.0", 1268 | "ignore": "^5.2.0", 1269 | "imurmurhash": "^0.1.4", 1270 | "is-glob": "^4.0.0", 1271 | "is-path-inside": "^3.0.3", 1272 | "js-yaml": "^4.1.0", 1273 | "json-stable-stringify-without-jsonify": "^1.0.1", 1274 | "levn": "^0.4.1", 1275 | "lodash.merge": "^4.6.2", 1276 | "minimatch": "^3.1.2", 1277 | "natural-compare": "^1.4.0", 1278 | "optionator": "^0.9.3", 1279 | "strip-ansi": "^6.0.1", 1280 | "text-table": "^0.2.0" 1281 | } 1282 | }, 1283 | "eslint-scope": { 1284 | "version": "7.2.2", 1285 | "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", 1286 | "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", 1287 | "requires": { 1288 | "esrecurse": "^4.3.0", 1289 | "estraverse": "^5.2.0" 1290 | } 1291 | }, 1292 | "eslint-visitor-keys": { 1293 | "version": "3.4.3", 1294 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", 1295 | "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==" 1296 | }, 1297 | "espree": { 1298 | "version": "9.6.1", 1299 | "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", 1300 | "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", 1301 | "requires": { 1302 | "acorn": "^8.9.0", 1303 | "acorn-jsx": "^5.3.2", 1304 | "eslint-visitor-keys": "^3.4.1" 1305 | } 1306 | }, 1307 | "esquery": { 1308 | "version": "1.5.0", 1309 | "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", 1310 | "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", 1311 | "requires": { 1312 | "estraverse": "^5.1.0" 1313 | } 1314 | }, 1315 | "esrecurse": { 1316 | "version": "4.3.0", 1317 | "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", 1318 | "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", 1319 | "requires": { 1320 | "estraverse": "^5.2.0" 1321 | } 1322 | }, 1323 | "estraverse": { 1324 | "version": "5.3.0", 1325 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", 1326 | "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" 1327 | }, 1328 | "esutils": { 1329 | "version": "2.0.3", 1330 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", 1331 | "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" 1332 | }, 1333 | "fast-deep-equal": { 1334 | "version": "3.1.3", 1335 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", 1336 | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" 1337 | }, 1338 | "fast-json-stable-stringify": { 1339 | "version": "2.1.0", 1340 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", 1341 | "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" 1342 | }, 1343 | "fast-levenshtein": { 1344 | "version": "2.0.6", 1345 | "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", 1346 | "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" 1347 | }, 1348 | "fastq": { 1349 | "version": "1.16.0", 1350 | "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz", 1351 | "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==", 1352 | "requires": { 1353 | "reusify": "^1.0.4" 1354 | } 1355 | }, 1356 | "file-entry-cache": { 1357 | "version": "6.0.1", 1358 | "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", 1359 | "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", 1360 | "requires": { 1361 | "flat-cache": "^3.0.4" 1362 | } 1363 | }, 1364 | "find-up": { 1365 | "version": "5.0.0", 1366 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", 1367 | "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", 1368 | "requires": { 1369 | "locate-path": "^6.0.0", 1370 | "path-exists": "^4.0.0" 1371 | } 1372 | }, 1373 | "flat-cache": { 1374 | "version": "3.0.4", 1375 | "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", 1376 | "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", 1377 | "requires": { 1378 | "flatted": "^3.1.0", 1379 | "rimraf": "^3.0.2" 1380 | } 1381 | }, 1382 | "flatted": { 1383 | "version": "3.2.4", 1384 | "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.4.tgz", 1385 | "integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==" 1386 | }, 1387 | "fs.realpath": { 1388 | "version": "1.0.0", 1389 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 1390 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" 1391 | }, 1392 | "glob": { 1393 | "version": "7.2.0", 1394 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", 1395 | "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", 1396 | "requires": { 1397 | "fs.realpath": "^1.0.0", 1398 | "inflight": "^1.0.4", 1399 | "inherits": "2", 1400 | "minimatch": "^3.0.4", 1401 | "once": "^1.3.0", 1402 | "path-is-absolute": "^1.0.0" 1403 | } 1404 | }, 1405 | "glob-parent": { 1406 | "version": "6.0.2", 1407 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", 1408 | "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", 1409 | "requires": { 1410 | "is-glob": "^4.0.3" 1411 | } 1412 | }, 1413 | "globals": { 1414 | "version": "13.24.0", 1415 | "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", 1416 | "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", 1417 | "requires": { 1418 | "type-fest": "^0.20.2" 1419 | } 1420 | }, 1421 | "graphemer": { 1422 | "version": "1.4.0", 1423 | "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", 1424 | "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==" 1425 | }, 1426 | "has-flag": { 1427 | "version": "4.0.0", 1428 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 1429 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" 1430 | }, 1431 | "ignore": { 1432 | "version": "5.3.0", 1433 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", 1434 | "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==" 1435 | }, 1436 | "import-fresh": { 1437 | "version": "3.3.0", 1438 | "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", 1439 | "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", 1440 | "requires": { 1441 | "parent-module": "^1.0.0", 1442 | "resolve-from": "^4.0.0" 1443 | } 1444 | }, 1445 | "imurmurhash": { 1446 | "version": "0.1.4", 1447 | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", 1448 | "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" 1449 | }, 1450 | "inflight": { 1451 | "version": "1.0.6", 1452 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 1453 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 1454 | "requires": { 1455 | "once": "^1.3.0", 1456 | "wrappy": "1" 1457 | } 1458 | }, 1459 | "inherits": { 1460 | "version": "2.0.4", 1461 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 1462 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 1463 | }, 1464 | "is-extglob": { 1465 | "version": "2.1.1", 1466 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 1467 | "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" 1468 | }, 1469 | "is-glob": { 1470 | "version": "4.0.3", 1471 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 1472 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 1473 | "requires": { 1474 | "is-extglob": "^2.1.1" 1475 | } 1476 | }, 1477 | "is-path-inside": { 1478 | "version": "3.0.3", 1479 | "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", 1480 | "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==" 1481 | }, 1482 | "isexe": { 1483 | "version": "2.0.0", 1484 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 1485 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" 1486 | }, 1487 | "js-yaml": { 1488 | "version": "4.1.0", 1489 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", 1490 | "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", 1491 | "requires": { 1492 | "argparse": "^2.0.1" 1493 | } 1494 | }, 1495 | "json-schema-traverse": { 1496 | "version": "0.4.1", 1497 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 1498 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" 1499 | }, 1500 | "json-stable-stringify-without-jsonify": { 1501 | "version": "1.0.1", 1502 | "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", 1503 | "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=" 1504 | }, 1505 | "levn": { 1506 | "version": "0.4.1", 1507 | "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", 1508 | "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", 1509 | "requires": { 1510 | "prelude-ls": "^1.2.1", 1511 | "type-check": "~0.4.0" 1512 | } 1513 | }, 1514 | "locate-path": { 1515 | "version": "6.0.0", 1516 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", 1517 | "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", 1518 | "requires": { 1519 | "p-locate": "^5.0.0" 1520 | } 1521 | }, 1522 | "lodash.merge": { 1523 | "version": "4.6.2", 1524 | "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", 1525 | "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" 1526 | }, 1527 | "minimatch": { 1528 | "version": "3.1.2", 1529 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", 1530 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", 1531 | "requires": { 1532 | "brace-expansion": "^1.1.7" 1533 | } 1534 | }, 1535 | "ms": { 1536 | "version": "2.1.2", 1537 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 1538 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 1539 | }, 1540 | "natural-compare": { 1541 | "version": "1.4.0", 1542 | "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", 1543 | "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=" 1544 | }, 1545 | "once": { 1546 | "version": "1.4.0", 1547 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 1548 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 1549 | "requires": { 1550 | "wrappy": "1" 1551 | } 1552 | }, 1553 | "optionator": { 1554 | "version": "0.9.3", 1555 | "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", 1556 | "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", 1557 | "requires": { 1558 | "@aashutoshrathi/word-wrap": "^1.2.3", 1559 | "deep-is": "^0.1.3", 1560 | "fast-levenshtein": "^2.0.6", 1561 | "levn": "^0.4.1", 1562 | "prelude-ls": "^1.2.1", 1563 | "type-check": "^0.4.0" 1564 | } 1565 | }, 1566 | "p-limit": { 1567 | "version": "3.1.0", 1568 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", 1569 | "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", 1570 | "requires": { 1571 | "yocto-queue": "^0.1.0" 1572 | } 1573 | }, 1574 | "p-locate": { 1575 | "version": "5.0.0", 1576 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", 1577 | "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", 1578 | "requires": { 1579 | "p-limit": "^3.0.2" 1580 | } 1581 | }, 1582 | "parent-module": { 1583 | "version": "1.0.1", 1584 | "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", 1585 | "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", 1586 | "requires": { 1587 | "callsites": "^3.0.0" 1588 | } 1589 | }, 1590 | "path-exists": { 1591 | "version": "4.0.0", 1592 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", 1593 | "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" 1594 | }, 1595 | "path-is-absolute": { 1596 | "version": "1.0.1", 1597 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 1598 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" 1599 | }, 1600 | "path-key": { 1601 | "version": "3.1.1", 1602 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", 1603 | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" 1604 | }, 1605 | "prelude-ls": { 1606 | "version": "1.2.1", 1607 | "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", 1608 | "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==" 1609 | }, 1610 | "punycode": { 1611 | "version": "2.3.1", 1612 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", 1613 | "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==" 1614 | }, 1615 | "queue-microtask": { 1616 | "version": "1.2.3", 1617 | "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", 1618 | "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" 1619 | }, 1620 | "resolve-from": { 1621 | "version": "4.0.0", 1622 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", 1623 | "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" 1624 | }, 1625 | "reusify": { 1626 | "version": "1.0.4", 1627 | "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", 1628 | "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" 1629 | }, 1630 | "rimraf": { 1631 | "version": "3.0.2", 1632 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", 1633 | "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", 1634 | "requires": { 1635 | "glob": "^7.1.3" 1636 | } 1637 | }, 1638 | "run-parallel": { 1639 | "version": "1.2.0", 1640 | "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", 1641 | "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", 1642 | "requires": { 1643 | "queue-microtask": "^1.2.2" 1644 | } 1645 | }, 1646 | "shebang-command": { 1647 | "version": "2.0.0", 1648 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", 1649 | "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", 1650 | "requires": { 1651 | "shebang-regex": "^3.0.0" 1652 | } 1653 | }, 1654 | "shebang-regex": { 1655 | "version": "3.0.0", 1656 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", 1657 | "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" 1658 | }, 1659 | "strip-ansi": { 1660 | "version": "6.0.1", 1661 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 1662 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 1663 | "requires": { 1664 | "ansi-regex": "^5.0.1" 1665 | } 1666 | }, 1667 | "strip-json-comments": { 1668 | "version": "3.1.1", 1669 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", 1670 | "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==" 1671 | }, 1672 | "supports-color": { 1673 | "version": "7.2.0", 1674 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 1675 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 1676 | "requires": { 1677 | "has-flag": "^4.0.0" 1678 | } 1679 | }, 1680 | "text-table": { 1681 | "version": "0.2.0", 1682 | "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", 1683 | "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" 1684 | }, 1685 | "type-check": { 1686 | "version": "0.4.0", 1687 | "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", 1688 | "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", 1689 | "requires": { 1690 | "prelude-ls": "^1.2.1" 1691 | } 1692 | }, 1693 | "type-fest": { 1694 | "version": "0.20.2", 1695 | "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", 1696 | "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==" 1697 | }, 1698 | "uri-js": { 1699 | "version": "4.4.1", 1700 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", 1701 | "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", 1702 | "requires": { 1703 | "punycode": "^2.1.0" 1704 | } 1705 | }, 1706 | "which": { 1707 | "version": "2.0.2", 1708 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", 1709 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", 1710 | "requires": { 1711 | "isexe": "^2.0.0" 1712 | } 1713 | }, 1714 | "wrappy": { 1715 | "version": "1.0.2", 1716 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1717 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" 1718 | }, 1719 | "yocto-queue": { 1720 | "version": "0.1.0", 1721 | "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", 1722 | "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" 1723 | } 1724 | } 1725 | } 1726 | -------------------------------------------------------------------------------- /packages/check-es-compat/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "check-es-compat", 3 | "version": "3.2.1", 4 | "description": "CLI tool for checking JavaScript code compatibility with target browsers and Node.js versions", 5 | "keywords": [ 6 | "browser", 7 | "compatibility", 8 | "compat", 9 | "support", 10 | "javascript", 11 | "ecmascript", 12 | "es", 13 | "checker", 14 | "browserslist", 15 | "browser-compat-data", 16 | "caniuse", 17 | "kangax" 18 | ], 19 | "homepage": "https://github.com/robatwilliams/es-compat#readme", 20 | "bugs": { 21 | "url": "https://github.com/robatwilliams/es-compat/issues" 22 | }, 23 | "repository": { 24 | "type": "git", 25 | "url": "https://github.com/robatwilliams/es-compat.git" 26 | }, 27 | "license": "MIT", 28 | "author": "Robat Williams", 29 | "type": "module", 30 | "bin": { 31 | "check-es-compat": "bin/cli.js" 32 | }, 33 | "dependencies": { 34 | "eslint": "^8.56.0", 35 | "eslint-plugin-ecmascript-compat": "^3.2.1" 36 | }, 37 | "engines": { 38 | "node": ">=16.0.0" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /packages/eslint-plugin-ecmascript-compat-example/.browserslistrc: -------------------------------------------------------------------------------- 1 | # 2 | # Docs: https://github.com/browserslist/browserslist 3 | # 4 | 5 | # Supports no ES2016 features 6 | Chrome >= 46 7 | -------------------------------------------------------------------------------- /packages/eslint-plugin-ecmascript-compat-example/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "plugins": ["ecmascript-compat"], 4 | "parserOptions": { 5 | "ecmaVersion": 2023, 6 | "sourceType": "module" 7 | }, 8 | "env": { "es2021": true }, 9 | "rules": { 10 | "ecmascript-compat/compat": "error" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/eslint-plugin-ecmascript-compat-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eslint-plugin-ecmascript-compat-example", 3 | "private": true, 4 | "scripts": { 5 | "lint": "eslint src/" 6 | }, 7 | "devDependencies": { 8 | "eslint": "^8.56.0", 9 | "eslint-plugin-ecmascript-compat": "^3.2.1" 10 | }, 11 | "version": "3.2.1" 12 | } 13 | -------------------------------------------------------------------------------- /packages/eslint-plugin-ecmascript-compat-example/src/app.js: -------------------------------------------------------------------------------- 1 | /** 2 | * ES2023 3 | */ 4 | [].findLast('a'); 5 | [].toReversed(); 6 | [].toSorted(); 7 | [].toSpliced(1); 8 | [].with(1, 'a'); 9 | 10 | /** 11 | * ES2022 12 | */ 13 | [].at(1); 14 | 'Foo'.at(1); 15 | 16 | class A { 17 | a = 0; 18 | } 19 | 20 | class B { 21 | static {} 22 | } 23 | 24 | Object.hasOwn({}, 'prop'); 25 | 26 | class C { 27 | #field; 28 | foo() { 29 | #field in this; 30 | } 31 | } 32 | 33 | new Error('message', { cause: new Error('originalError') }); 34 | 35 | /./d.test('d flag'); 36 | 37 | /** 38 | * ES2021 39 | */ 40 | foo = {}; 41 | foo.replaceAll; // no error 42 | 43 | String.prototype.replaceAll; 44 | 45 | foo = foo &&= null; 46 | foo = foo ??= ''; 47 | foo = foo ||= {}; 48 | 49 | Promise.any(); 50 | 51 | foo = 1_000_000_00; 52 | foo = new WeakRef(); 53 | foo = new FinalizationRegistry(() => {}); 54 | 55 | /** 56 | * ES2020 (all implemented, but these examples not complete) 57 | */ 58 | foo = 100n; 59 | BigInt(100); 60 | 61 | async function interestingBitIsInside2() { 62 | await import(''); 63 | } 64 | 65 | globalThis.foo; 66 | 67 | Promise.allSettled(); 68 | 69 | foo.matchAll(); 70 | String.prototype.matchAll; 71 | 72 | /** 73 | * ES2019 74 | */ 75 | foo.flat(); 76 | Array.prototype.flat; 77 | residentialAddress.flat; // no error please 78 | Array.prototype.flatMap; 79 | foo.flatMap(); 80 | 81 | const u2028 = '
'; // line separator character \u2028 is in this string 82 | 83 | Object.fromEntries(); 84 | 85 | try { 86 | } catch {} 87 | 88 | foo.trimLeft(); 89 | String.prototype.trimLeft; 90 | foo.trimRight(); 91 | String.prototype.trimRight; 92 | foo.trimStart(); 93 | String.prototype.trimStart; 94 | foo.trimEnd(); 95 | String.prototype.trimEnd; 96 | 97 | /** 98 | * ES2018 99 | */ 100 | async function* asyncGenerator() {} 101 | async function interestingBitIsInside1() { 102 | for await (const bar of bar) { 103 | } 104 | } 105 | 106 | foo = { ...bar }; 107 | const { a, ...rest } = foo; 108 | 109 | foo.finally(); 110 | Promise.prototype.finally; 111 | 112 | /(?<=a)b/.test('look-behind assertion'); 113 | 114 | /(?b)c/.test('named capture group'); 115 | 116 | /./s.test('dotAll flag'); 117 | 118 | /\p{Script=Hiragana}+/u.test('Unicode property escape'); 119 | 120 | /** 121 | * ES2017 122 | */ 123 | async function foo() {} 124 | 125 | Atomics.add(buffer, 0, 2); 126 | 127 | Object.getOwnPropertyDescriptors(); 128 | 129 | Object.entries(); 130 | 131 | Object.values(); 132 | 133 | new SharedArrayBuffer(); 134 | 135 | str.padStart(); 136 | String.prototype.padStart; 137 | str.padEnd(); 138 | String.prototype.padEnd; 139 | 140 | // prettier-ignore 141 | foo(bar,); 142 | 143 | /** 144 | * ES2016 145 | */ 146 | foo.includes(); 147 | Array.prototype.includes; 148 | 149 | foo ** bar; 150 | -------------------------------------------------------------------------------- /packages/eslint-plugin-ecmascript-compat/.gitignore: -------------------------------------------------------------------------------- 1 | /coverage 2 | -------------------------------------------------------------------------------- /packages/eslint-plugin-ecmascript-compat/README.md: -------------------------------------------------------------------------------- 1 | 2 | [![npm version](https://badge.fury.io/js/eslint-plugin-ecmascript-compat.svg)](https://badge.fury.io/js/eslint-plugin-ecmascript-compat) 3 | [![npm downloads](https://img.shields.io/npm/dm/eslint-plugin-ecmascript-compat.svg)](http://www.npmtrends.com/eslint-plugin-ecmascript-compat) 4 | 5 | 6 | # eslint-plugin-ecmascript-compat 7 | 8 | > ESLint plugin for checking JavaScript code compatibility with target browsers and Node.js versions 9 | 10 | ```bash 11 | npm install --save-dev eslint-plugin-ecmascript-compat 12 | ``` 13 | 14 | ```json 15 | // .eslintrc.json 16 | { 17 | "extends": ["plugin:ecmascript-compat/recommended"] 18 | } 19 | 20 | // Alternatively 21 | { 22 | "plugins": ["ecmascript-compat"], 23 | "rules": { 24 | "ecmascript-compat/compat": [ 25 | "error", 26 | { 27 | // Optionally, specify provided polyfills 28 | "polyfills": [ 29 | "Array.prototype.includes" 30 | ], 31 | // Optionally, provide a browserslist to use instead of the project one 32 | "overrideBrowserslist": "IE >= 11", 33 | // Optionally, specify browserslist options - see https://github.com/browserslist/browserslist#js-api 34 | "browserslistOptions": { "env": "legacy" } 35 | } 36 | ] 37 | } 38 | } 39 | ``` 40 | 41 | ``` 42 | // .browserslistrc 43 | Chrome >= 64 44 | Firefox >= 58 45 | ``` 46 | 47 | 48 | 49 | The optional `polyfills` option is used to specify polyfills that your application loads. These features are therefore considered supported in all browsers. Features that are polyfillable and can be specified here can be found in the [rule schema](https://github.com/robatwilliams/es-compat/blob/master/packages/eslint-plugin-ecmascript-compat/lib/rule.js). 50 | 51 | For example usage, see sibling directory: `eslint-plugin-ecmascript-compat-example` 52 | 53 | 54 | 55 | ➡ For more information, see the [main readme](https://github.com/robatwilliams/es-compat#readme). 56 | -------------------------------------------------------------------------------- /packages/eslint-plugin-ecmascript-compat/lib/compareVersions.js: -------------------------------------------------------------------------------- 1 | export default function compareVersions(a, b) { 2 | const aParts = a.split('.').map(Number); 3 | const bParts = b.split('.').map(Number); 4 | 5 | for (let i = 0; i < Math.max(aParts.length, bParts.length); i++) { 6 | if (aParts[i] === bParts[i]) { 7 | // eslint-disable-next-line no-continue 8 | continue; 9 | } 10 | 11 | return aParts[i] < bParts[i] ? -1 : 1; 12 | } 13 | 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /packages/eslint-plugin-ecmascript-compat/lib/compareVersions.test.js: -------------------------------------------------------------------------------- 1 | import assert from 'node:assert'; 2 | import { test } from 'node:test'; 3 | import compareVersions from './compareVersions.js'; 4 | 5 | test('equal', () => { 6 | assert.strictEqual(compareVersions('1.2.3', '1.2.3'), 0); 7 | }); 8 | 9 | test('smaller', () => { 10 | assert.strictEqual(compareVersions('1.2.0', '1.2.3'), -1); 11 | assert.strictEqual(compareVersions('1.2', '1.3'), -1); 12 | }); 13 | 14 | test('larger', () => { 15 | assert.strictEqual(compareVersions('1.2.3', '1.2.0'), 1); 16 | }); 17 | 18 | test('partial on one side', () => { 19 | assert.strictEqual(compareVersions('1.1', '1.2.3'), -1); 20 | assert.strictEqual(compareVersions('1.1.1', '1.2'), -1); 21 | }); 22 | 23 | test('when it matters to treat parts as numbers', () => { 24 | assert.strictEqual(compareVersions('9', '10'), -1); 25 | }); 26 | -------------------------------------------------------------------------------- /packages/eslint-plugin-ecmascript-compat/lib/compatibility.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase, no-underscore-dangle */ 2 | import compareVersions from './compareVersions.js'; 3 | 4 | export function unsupportedFeatures(features, targets) { 5 | return features.filter((feature) => !isFeatureSupportedByTargets(feature, targets)); 6 | } 7 | 8 | function isFeatureSupportedByTargets(feature, targets) { 9 | return targets.every((target) => isFeatureSupportedByTarget(feature, target)); 10 | } 11 | 12 | function isFeatureSupportedByTarget(feature, target) { 13 | if (feature.compatFeatures.includes(undefined)) { 14 | const summary = feature.compatFeatures.map((compatFeature) => typeof compatFeature); 15 | const ruleDescription = feature.ruleConfig.definition.meta.docs.description; 16 | 17 | throw new Error(`Sparse compatFeatures for rule '${ruleDescription}': ${summary}`); 18 | } 19 | 20 | return feature.compatFeatures.every((compatFeature) => 21 | isCompatFeatureSupportedByTarget(compatFeature, target) 22 | ); 23 | } 24 | 25 | function isCompatFeatureSupportedByTarget(compatFeature, target) { 26 | const versionAdded = getSimpleSupportStatement(compatFeature, target).version_added; 27 | const support = interpretSupport(versionAdded); 28 | 29 | if (support.isUnknown || support.isVersionUnknown) { 30 | // Assume optimistically; we can only be as good as the compatibility data 31 | return true; 32 | } 33 | 34 | return !support.isNone && compareVersions(target.version, versionAdded) >= 0; 35 | } 36 | 37 | function getSimpleSupportStatement(compatFeature, target) { 38 | const statement = compatFeature.__compat.support[target.name]; 39 | 40 | // Take the most relevant and general entry when there are ones for behind-a-flag etc. 41 | // https://github.com/mdn/browser-compat-data/blob/master/schemas/compat-data-schema.md#the-support_statement-object 42 | const simpleStatement = Array.isArray(statement) ? statement[0] : statement; 43 | 44 | // Only mandatory for desktop browsers 45 | // https://github.com/mdn/browser-compat-data/blob/master/schemas/compat-data-schema.md#browser-identifiers 46 | return simpleStatement || { version_added: null }; 47 | } 48 | 49 | function interpretSupport(versionAdded) { 50 | // https://github.com/mdn/browser-compat-data/blob/master/schemas/compat-data-schema.md#version_added 51 | return { 52 | isUnknown: versionAdded == null, 53 | isNone: versionAdded === false, 54 | isVersionUnknown: versionAdded === true, 55 | }; 56 | } 57 | -------------------------------------------------------------------------------- /packages/eslint-plugin-ecmascript-compat/lib/compatibility.test.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable camelcase */ 2 | import assert from 'node:assert'; 3 | import { it } from 'node:test'; 4 | import { unsupportedFeatures } from './compatibility.js'; 5 | import features from './features/index.js'; 6 | 7 | it('supports feature in version introduced', () => { 8 | const feature = { 9 | compatFeatures: [ 10 | { 11 | __compat: { 12 | support: { 13 | chrome: { version_added: '73' }, 14 | }, 15 | }, 16 | }, 17 | ], 18 | }; 19 | 20 | const unsupported = unsupportedFeatures([feature], [{ name: 'chrome', version: '73' }]); 21 | assert.deepStrictEqual(unsupported, []); 22 | }); 23 | 24 | it('supports feature in version later than introduced, treating versions as numbers', () => { 25 | const feature = { 26 | compatFeatures: [ 27 | { 28 | __compat: { 29 | support: { 30 | safari: { version_added: '9' }, 31 | }, 32 | }, 33 | }, 34 | ], 35 | }; 36 | 37 | const unsupported = unsupportedFeatures( 38 | [feature], 39 | [{ name: 'safari', version: '14.0' }] 40 | ); 41 | assert.deepStrictEqual(unsupported, []); 42 | }); 43 | 44 | it('doesnt support feature in version before introduced', () => { 45 | const feature = { 46 | compatFeatures: [ 47 | { 48 | __compat: { 49 | support: { 50 | chrome: { version_added: '73' }, 51 | }, 52 | }, 53 | }, 54 | ], 55 | }; 56 | 57 | const unsupported = unsupportedFeatures([feature], [{ name: 'chrome', version: '72' }]); 58 | assert.strictEqual(unsupported[0], feature); 59 | }); 60 | 61 | it('supports feature supported by family in unknown version', () => { 62 | const feature = { 63 | compatFeatures: [ 64 | { 65 | __compat: { 66 | support: { 67 | chrome: { version_added: true }, 68 | }, 69 | }, 70 | }, 71 | ], 72 | }; 73 | 74 | const unsupported = unsupportedFeatures([feature], [{ name: 'chrome', version: '73' }]); 75 | assert.deepStrictEqual(unsupported, []); 76 | }); 77 | 78 | it('doesnt support feature not supported in any version of family', () => { 79 | const feature = { 80 | compatFeatures: [ 81 | { 82 | __compat: { 83 | support: { 84 | chrome: { version_added: false }, 85 | }, 86 | }, 87 | }, 88 | ], 89 | }; 90 | 91 | const unsupported = unsupportedFeatures([feature], [{ name: 'chrome', version: '73' }]); 92 | assert.strictEqual(unsupported[0], feature); 93 | }); 94 | 95 | it('supports feature with unknown support by family', () => { 96 | const feature = { 97 | compatFeatures: [ 98 | { 99 | __compat: { 100 | support: { 101 | chrome: { version_added: null }, 102 | }, 103 | }, 104 | }, 105 | ], 106 | }; 107 | 108 | const unsupported = unsupportedFeatures([feature], [{ name: 'chrome', version: '73' }]); 109 | assert.deepStrictEqual(unsupported, []); 110 | }); 111 | 112 | it('supports feature with omitted support entry for mobile target', () => { 113 | const feature = { 114 | compatFeatures: [ 115 | { 116 | __compat: { 117 | support: { 118 | chrome: { version_added: '73' }, 119 | }, 120 | }, 121 | }, 122 | ], 123 | }; 124 | 125 | const unsupported = unsupportedFeatures( 126 | [feature], 127 | [{ name: 'chrome_android', version: '73' }] 128 | ); 129 | assert.deepStrictEqual(unsupported, []); 130 | }); 131 | 132 | it('doesnt support feature supported by one target but not another', () => { 133 | const feature = { 134 | compatFeatures: [ 135 | { 136 | __compat: { 137 | support: { 138 | chrome: { version_added: '60' }, 139 | firefox: { version_added: '55' }, 140 | }, 141 | }, 142 | }, 143 | ], 144 | }; 145 | 146 | const unsupported = unsupportedFeatures( 147 | [feature], 148 | [ 149 | { name: 'chrome', version: '73' }, 150 | { name: 'firefox', version: '50' }, 151 | ] 152 | ); 153 | assert.strictEqual(unsupported[0], feature); 154 | }); 155 | 156 | it('uses primary support record where multiple ones exist', () => { 157 | const feature = { 158 | compatFeatures: [ 159 | { 160 | __compat: { 161 | support: { 162 | nodejs: [ 163 | { version_added: '7.0.0' }, 164 | { 165 | version_added: '6.5.0', 166 | flags: [ 167 | { 168 | type: 'runtime_flag', 169 | name: '--harmony', 170 | }, 171 | ], 172 | }, 173 | ], 174 | }, 175 | }, 176 | }, 177 | ], 178 | }; 179 | 180 | const primaryUnsupported = unsupportedFeatures( 181 | [feature], 182 | [{ name: 'nodejs', version: '7.0.0' }] 183 | ); 184 | assert.deepStrictEqual(primaryUnsupported, []); 185 | 186 | const secondaryUnsupported = unsupportedFeatures( 187 | [feature], 188 | [{ name: 'nodejs', version: '6.7.0' }] 189 | ); 190 | assert.deepStrictEqual(secondaryUnsupported[0], feature); 191 | }); 192 | 193 | it('explains what the problem is when compat feature not found in MDN data', () => { 194 | const feature = { 195 | ruleConfig: { 196 | definition: { 197 | meta: { 198 | docs: { description: 'some rule' }, 199 | }, 200 | }, 201 | }, 202 | compatFeatures: [ 203 | // Unsupported compatFeature first, to test that validation does not short-circuit 204 | { 205 | __compat: { 206 | support: { 207 | chrome: { version_added: '72' }, 208 | }, 209 | }, 210 | }, 211 | // Typically when wrong path to compatData node used 212 | undefined, 213 | ], 214 | }; 215 | 216 | assert.throws( 217 | () => unsupportedFeatures([feature], [{ name: 'chrome', version: '73' }]), 218 | { message: "Sparse compatFeatures for rule 'some rule': object,undefined" } 219 | ); 220 | }); 221 | 222 | it('can rely on all the versions in the compatibility data used being semver or partial semver', () => { 223 | // We rely on this to avoid having to deal with ranged versions, for simplicity. 224 | // https://github.com/mdn/browser-compat-data/blob/main/schemas/compat-data-schema.md#ranged-versions 225 | 226 | for (const esFeature of features) { 227 | for (const compatFeature of esFeature.compatFeatures) { 228 | // eslint-disable-next-line no-underscore-dangle 229 | for (const supportStatement of Object.values(compatFeature.__compat.support)) { 230 | const simpleSupportStatement = Array.isArray(supportStatement) 231 | ? supportStatement[0] 232 | : supportStatement; 233 | 234 | if (simpleSupportStatement.version_added !== false) { 235 | assert.match( 236 | simpleSupportStatement.version_added, 237 | /\d+(?\.\d+(?\.\d+)?)?/u 238 | ); 239 | } 240 | } 241 | } 242 | } 243 | }); 244 | -------------------------------------------------------------------------------- /packages/eslint-plugin-ecmascript-compat/lib/delegation.js: -------------------------------------------------------------------------------- 1 | export function createDelegatee(config, rootContext) { 2 | const { definition, options } = config; 3 | 4 | if (!definition) { 5 | // May need to update the es-x dependency, or check that the lookup name is not 6 | // prefixed with es-x/ 7 | throw new Error('Rule instance not given'); 8 | } 9 | 10 | // All except report() are added later. Define necessary ones for used rules. 11 | // https://eslint.org/docs/latest/extend/custom-rules#the-context-object 12 | const contextLaterAdded = { 13 | getScope: () => rootContext.getScope(), 14 | getSourceCode: () => rootContext.getSourceCode(), 15 | 16 | get settings() { 17 | return rootContext.settings; 18 | }, 19 | 20 | get parserServices() { 21 | return rootContext.parserServices; 22 | }, 23 | }; 24 | 25 | // Would use ES Proxy, but context's properties aren't overridable 26 | const context = { 27 | ...rootContext, 28 | ...contextLaterAdded, 29 | options, 30 | report, 31 | }; 32 | 33 | function report(params) { 34 | // Discard fixer; we can't declare the rule as fixable because not all delegatees are. 35 | // Look up messageId on delegate meta; report() would look it up on root rule meta. 36 | const { fix, message, messageId, ...otherParams } = params; 37 | 38 | rootContext.report({ 39 | ...otherParams, 40 | message: messageId ? definition.meta.messages[messageId] : message, 41 | }); 42 | } 43 | 44 | return definition.create(context); 45 | } 46 | 47 | export function delegatingVisitor(delegatees) { 48 | const delegator = {}; 49 | 50 | delegatees.forEach((visitor) => { 51 | for (const [key] of Object.entries(visitor)) { 52 | delegator[key] = (...args) => delegate(key, args); 53 | } 54 | }); 55 | 56 | function delegate(key, args) { 57 | delegatees.forEach((visitor) => { 58 | if (visitor[key]) { 59 | visitor[key](...args); 60 | } 61 | }); 62 | } 63 | 64 | return delegator; 65 | } 66 | -------------------------------------------------------------------------------- /packages/eslint-plugin-ecmascript-compat/lib/delegation.test.js: -------------------------------------------------------------------------------- 1 | import eslint from 'eslint'; 2 | import { createDelegatee, delegatingVisitor } from './delegation.js'; 3 | 4 | const ruleTester = new eslint.RuleTester(); 5 | 6 | const noVarRule = new eslint.Linter().getRules().get('no-var'); 7 | 8 | const rule = { 9 | create(context) { 10 | return delegatingVisitor([ 11 | createDelegatee({ definition: noVarRule }, context), 12 | createDelegatee({ definition: noVarRule }, context), 13 | ]); 14 | }, 15 | }; 16 | 17 | ruleTester.run('allows delegatees to independently use the same AST selectors', rule, { 18 | valid: [], 19 | invalid: [ 20 | { 21 | code: 'var foo;', 22 | errors: [ 23 | { message: 'Unexpected var, use let or const instead.' }, 24 | { message: 'Unexpected var, use let or const instead.' }, 25 | ], 26 | }, 27 | ], 28 | }); 29 | -------------------------------------------------------------------------------- /packages/eslint-plugin-ecmascript-compat/lib/features/es-versions.md: -------------------------------------------------------------------------------- 1 | # ECMAScript features by version 2 | 3 | Static detectability of recently-added features 4 | 5 | - ❌ = not statically detectable 6 | - 😐 = statically detectable, but chance of false positives 7 | - 👎 = statically detectable, but not worth the false positives 8 | 9 | ### ES2023 10 | 11 | | Name | ESLint / eslint-plugin-es | Chrome since | 12 | | --- | --- | --- | 13 | | `{Array, TypedArray}.prototype.{findLast, findLastIndex}` | 😐 es-x/no-array-prototype-findlast-findlastindex | 97 | 14 | | `{Array, TypedArray}.prototype.toReversed` | 😐 es-x/no-array-prototype-toreversed | 110 | 15 | | `{Array, TypedArray}.prototype.toSorted` | 😐 es-x/no-array-prototype-tosorted | 110 | 16 | | `Array.prototype.toSpliced` | 😐 es-x/no-array-prototype-tospliced | 110 | 17 | | `{Array, TypedArray}.prototype.with` | 😐 es-x/no-array-prototype-with | 110 | 18 | | Hashbang Grammar | es-x/no-hashbang | 74 | 19 | | Symbols as WeakMap keys | ❌ | 108 | 20 | | RegExp Unicode property escapes (2023) | es-x/no-regexp-unicode-property-escapes-2023 | see issue #63 | 21 | 22 | ### ES2022 23 | 24 | | Name | ESLint / eslint-plugin-es | Chrome since | 25 | | -------------------------------------------- | -------------------------------------------- | ------------- | 26 | | Arbitrary module namespace names | es-x/no-arbitrary-module-namespace-names | see issue #62 | 27 | | `{Array, String, TypedArray}.prototype.at()` | 😐 es-x/no-array-string-prototype-at | 92 | 28 | | Class fields | es-x/no-class-fields | 72, 74 | 29 | | Class static initialization block | es-x/no-class-static-block | 94 | 30 | | Error `cause` | es-x/no-error-cause | 93 | 31 | | `Object.hasOwn` | es-x/no-object-hasown | 93 | 32 | | Private slot checks (`#x in obj`) | es-x/no-private-in | 91 | 33 | | RegExp match indices (`/d` flag) | es-x/no-regexp-d-flag | 90 | 34 | | RegExp Unicode property escapes (2022) | es-x/no-regexp-unicode-property-escapes-2022 | see issue #63 | 35 | | Top-level `await` | es-x/no-top-level-await | 89 | 36 | 37 | ### ES2021 38 | 39 | | Name | ESLint / eslint-plugin-es | Chrome since | 40 | | -------------------------------------- | -------------------------------------------- | ------------- | 41 | | Logical Assignment \|\|=, \&\&=, ??= | es/no-logical-assignment-operators | 85 | 42 | | Numeric separators | es/no-numeric-separators | 75 | 43 | | `Promise.any` | es/no-promise-any | 85 | 44 | | RegExp Unicode property escapes (2021) | es-x/no-regexp-unicode-property-escapes-2021 | see issue #63 | 45 | | `String.prototype.replaceAll` | 😐 no-restricted-properties | 85 | 46 | | `WeakRef` and `FinalizationRegistry` | es/no-weakrefs | 84 | 47 | 48 | ### ES2020 49 | 50 | | Name | ESLint / eslint-plugin-es | Chrome since | 51 | | -------------------------------------- | -------------------------------------------- | ------------- | 52 | | `Atomics.{notify, wait}` | no-restricted-properties | 68 | 53 | | `BigInt` | es/no-bigint | 67 | 54 | | Dynamic `import()` | es/no-dynamic-import | 63 | 55 | | `globalThis` | es/no-global-this | 71 | 56 | | `import.meta` | es/no-import-meta | 64 | 57 | | Module namespace exports | es/no-export-ns-from | 72 | 58 | | Nullish coalescing (`??`) | es/no-nullish-coalescing-operators | 80 | 59 | | Optional chaining (`?.`) | es/no-optional-chaining | 80 | 60 | | `Promise.allSettled` | es/no-promise-all-settled | 76 | 61 | | RegExp Unicode property escapes (2020) | es-x/no-regexp-unicode-property-escapes-2020 | see issue #63 | 62 | | `String.prototype.matchAll` | 😐 no-restricted-syntax | 73 | 63 | 64 | ### ES2019 65 | 66 | | Name | ESLint / eslint-plugin-es | Chrome since | 67 | | -------------------------------------- | -------------------------------------------- | ------------- | 68 | | `Array.prototype.{flat, flatMap}` | 😐 no-restricted-syntax | 69 | 69 | | JSON superset | es/no-json-superset | 66 | 70 | | `Object.fromEntries` | es/no-object-fromentries | 73 | 71 | | Optional `catch` binding | es/no-optional-catch-binding | 66 | 72 | | RegExp Unicode property escapes (2019) | es-x/no-regexp-unicode-property-escapes-2019 | see issue #63 | 73 | | Revised `Function.prototype.toString` | ❌ | 74 | | Stable `Array.prototype.sort` | ❌ | 75 | | `String.prototype.trimX` methods | 😐 no-restricted-syntax | 66 | 76 | | `Symbol.prototype.description` | 👎 no-restricted-syntax | 70 | 77 | | Well-formed `JSON.stringify` | ❌ | 78 | 79 | ### ES2018 80 | 81 | | Name | ESLint / eslint-plugin-es | Chrome since | 82 | | -------------------------------------- | ------------------------------------- | ------------ | 83 | | Async iteration (loop & generators) | es/no-async-iteration | 63 | 84 | | Object rest and spread operators | es/no-rest-spread-properties | 60 | 85 | | `Promise.prototype.finally` | 😐 no-restricted-syntax | 63 | 86 | | RegExp look-behind assertions | es/no-regexp-lookbehind-assertions | 62 | 87 | | RegExp named capture groups | es/no-regexp-named-capture-groups | 64 | 88 | | RegExp `/s` (dotAll) flag | es/no-regexp-s-flag | 62 | 89 | | RegExp Unicode property escapes (2018) | es/no-regexp-unicode-property-escapes | 64 | 90 | 91 | ### ES2017 92 | 93 | | Name | ESLint / eslint-plugin-es | Chrome since | 94 | | ------------------------------------- | -------------------------------------- | ------------ | 95 | | Async functions | es/no-async-functions | 55 | 96 | | Atomics | es/no-atomics | 68 | 97 | | `Object.entries` | es/no-object-entries | 54 | 98 | | `Object.getOwnPropertyDescriptors` | es/no-object-getownpropertydescriptors | 54 | 99 | | `Object.values` | es/no-object-values | 54 | 100 | | SharedArrayBuffer | es/no-shared-array-buffer | 68 | 101 | | `String.prototype.{padStart, padEnd}` | 😐 no-restricted-syntax | 57 | 102 | | Trailing commas in parameter lists | es/no-trailing-function-commas | 58 | 103 | 104 | ### ES2016 105 | 106 | | Name | ESLint / eslint-plugin-es | Chrome since | 107 | | -------------------------- | --------------------------- | ------------ | 108 | | `Array.prototype.includes` | 😐 no-restricted-syntax | 47 | 109 | | Exponentiation operator | es/no-exponential-operators | 52 | 110 | -------------------------------------------------------------------------------- /packages/eslint-plugin-ecmascript-compat/lib/features/es2016.js: -------------------------------------------------------------------------------- 1 | import eslint from 'eslint'; 2 | import esPlugin from 'eslint-plugin-es-x'; 3 | // Import assertions aren't yet stage 4 so aren't supported by ESLint 4 | import compatData from '@mdn/browser-compat-data/forLegacyNode'; 5 | import { noRestrictedSyntaxPrototypeMethod } from './ruleOptionsUtil.js'; 6 | 7 | const coreRules = new eslint.Linter().getRules(); 8 | 9 | export default [ 10 | { 11 | ruleConfig: { 12 | definition: coreRules.get('no-restricted-syntax'), 13 | options: noRestrictedSyntaxPrototypeMethod('Array.prototype.includes', 'ES2016'), 14 | }, 15 | compatFeatures: [compatData.javascript.builtins.Array.includes], 16 | polyfill: 'Array.prototype.includes', 17 | }, 18 | { 19 | ruleConfig: { definition: esPlugin.rules['no-exponential-operators'] }, 20 | compatFeatures: [compatData.javascript.operators.exponentiation], 21 | }, 22 | ]; 23 | -------------------------------------------------------------------------------- /packages/eslint-plugin-ecmascript-compat/lib/features/es2016.test.js: -------------------------------------------------------------------------------- 1 | import { RuleTester } from 'eslint'; 2 | import rule from '../rule.js'; 3 | 4 | // Browser that doesn't support any features of this version - see es-versions.md 5 | process.env.BROWSERSLIST = 'Chrome >= 46'; 6 | 7 | const ruleTester = new RuleTester({ 8 | parserOptions: { 9 | ecmaVersion: 2016, 10 | }, 11 | }); 12 | 13 | ruleTester.run('compat', rule, { 14 | valid: [ 15 | { 16 | code: 'foo.includes();', 17 | options: [{ polyfills: ['Array.prototype.includes'] }], 18 | }, 19 | ], 20 | invalid: [ 21 | { 22 | code: 'foo.includes();', 23 | errors: [{ message: "ES2016 method 'Array.prototype.includes' is forbidden" }], 24 | }, 25 | { 26 | code: 'Array.prototype.includes;', 27 | errors: [{ message: "ES2016 method 'Array.prototype.includes' is forbidden" }], 28 | }, 29 | { 30 | code: 'foo ** bar', 31 | errors: [{ message: 'ES2016 exponential operators are forbidden.' }], 32 | }, 33 | ], 34 | }); 35 | -------------------------------------------------------------------------------- /packages/eslint-plugin-ecmascript-compat/lib/features/es2017.js: -------------------------------------------------------------------------------- 1 | import eslint from 'eslint'; 2 | import esPlugin from 'eslint-plugin-es-x'; 3 | // Import assertions aren't yet stage 4 so aren't supported by ESLint 4 | import compatData from '@mdn/browser-compat-data/forLegacyNode'; 5 | import { noRestrictedSyntaxPrototypeMethod } from './ruleOptionsUtil.js'; 6 | 7 | const coreRules = new eslint.Linter().getRules(); 8 | 9 | export default [ 10 | { 11 | ruleConfig: { definition: esPlugin.rules['no-async-functions'] }, 12 | compatFeatures: [ 13 | compatData.javascript.operators.async_function, 14 | compatData.javascript.statements.async_function, 15 | ], 16 | }, 17 | { 18 | // Rule requires the ES2017 global, Atomics 19 | ruleConfig: { definition: esPlugin.rules['no-atomics'] }, 20 | compatFeatures: [compatData.javascript.builtins.Atomics], 21 | }, 22 | { 23 | ruleConfig: { definition: esPlugin.rules['no-object-getownpropertydescriptors'] }, 24 | compatFeatures: [compatData.javascript.builtins.Object.getOwnPropertyDescriptors], 25 | polyfill: 'Object.getOwnPropertyDescriptors', 26 | }, 27 | { 28 | ruleConfig: { definition: esPlugin.rules['no-object-entries'] }, 29 | compatFeatures: [compatData.javascript.builtins.Object.entries], 30 | polyfill: 'Object.entries', 31 | }, 32 | { 33 | ruleConfig: { definition: esPlugin.rules['no-object-values'] }, 34 | compatFeatures: [compatData.javascript.builtins.Object.values], 35 | polyfill: 'Object.values', 36 | }, 37 | { 38 | // Rule requires the ES2017 global, SharedArrayBuffer 39 | ruleConfig: { definition: esPlugin.rules['no-shared-array-buffer'] }, 40 | compatFeatures: [compatData.javascript.builtins.SharedArrayBuffer], 41 | }, 42 | { 43 | ruleConfig: { 44 | definition: coreRules.get('no-restricted-syntax'), 45 | options: noRestrictedSyntaxPrototypeMethod('String.prototype.padStart', 'ES2017'), 46 | }, 47 | compatFeatures: [compatData.javascript.builtins.String.padStart], 48 | polyfill: 'String.prototype.padStart', 49 | }, 50 | { 51 | ruleConfig: { 52 | definition: coreRules.get('no-restricted-syntax'), 53 | options: noRestrictedSyntaxPrototypeMethod('String.prototype.padEnd', 'ES2017'), 54 | }, 55 | compatFeatures: [compatData.javascript.builtins.String.padEnd], 56 | polyfill: 'String.prototype.padEnd', 57 | }, 58 | { 59 | ruleConfig: { definition: esPlugin.rules['no-trailing-function-commas'] }, 60 | compatFeatures: [ 61 | compatData.javascript.functions.arrow_functions.trailing_comma, 62 | compatData.javascript.operators.function.trailing_comma, 63 | compatData.javascript.operators.generator_function.trailing_comma, 64 | compatData.javascript.statements.generator_function.trailing_comma_in_parameters, 65 | compatData.javascript.statements.function.trailing_comma_in_parameters, 66 | ], 67 | }, 68 | ]; 69 | -------------------------------------------------------------------------------- /packages/eslint-plugin-ecmascript-compat/lib/features/es2017.test.js: -------------------------------------------------------------------------------- 1 | import { RuleTester } from 'eslint'; 2 | import rule from '../rule.js'; 3 | 4 | // Browser that doesn't support any features of this version - see es-versions.md 5 | process.env.BROWSERSLIST = 'Chrome >= 53'; 6 | 7 | const ruleTester = new RuleTester({ 8 | parserOptions: { 9 | ecmaVersion: 2017, 10 | }, 11 | globals: { 12 | // ES2017 global, required by es/no-atomics 13 | Atomics: 'readonly', 14 | 15 | // ES2017 global, required by es/no-shared-array-buffer 16 | SharedArrayBuffer: 'readonly', 17 | }, 18 | }); 19 | 20 | ruleTester.run('compat', rule, { 21 | valid: [ 22 | { 23 | code: 'Object.getOwnPropertyDescriptors();', 24 | options: [{ polyfills: ['Object.getOwnPropertyDescriptors'] }], 25 | }, 26 | { 27 | code: 'Object.entries();', 28 | options: [{ polyfills: ['Object.entries'] }], 29 | }, 30 | { 31 | code: 'Object.values();', 32 | options: [{ polyfills: ['Object.values'] }], 33 | }, 34 | { 35 | code: 'str.padStart();', 36 | options: [{ polyfills: ['String.prototype.padStart'] }], 37 | }, 38 | { 39 | code: 'str.padEnd();', 40 | options: [{ polyfills: ['String.prototype.padEnd'] }], 41 | }, 42 | ], 43 | invalid: [ 44 | { 45 | code: 'async function foo() {}', 46 | errors: [{ message: 'ES2017 async function declarations are forbidden.' }], 47 | }, 48 | { 49 | code: 'Atomics.add(buffer, 0, 2);', 50 | errors: [{ message: "ES2017 'Atomics' class is forbidden." }], 51 | }, 52 | { 53 | code: 'Object.getOwnPropertyDescriptors();', 54 | errors: [ 55 | { message: "ES2017 'Object.getOwnPropertyDescriptors' method is forbidden." }, 56 | ], 57 | }, 58 | { 59 | code: 'Object.entries();', 60 | errors: [{ message: "ES2017 'Object.entries' method is forbidden." }], 61 | }, 62 | { 63 | code: 'Object.values();', 64 | errors: [{ message: "ES2017 'Object.values' method is forbidden." }], 65 | }, 66 | { 67 | code: 'new SharedArrayBuffer();', 68 | errors: [{ message: "ES2017 'SharedArrayBuffer' class is forbidden." }], 69 | }, 70 | { 71 | code: 'str.padStart();', 72 | errors: [{ message: "ES2017 method 'String.prototype.padStart' is forbidden" }], 73 | }, 74 | { 75 | code: 'String.prototype.padStart;', 76 | errors: [{ message: "ES2017 method 'String.prototype.padStart' is forbidden" }], 77 | }, 78 | { 79 | code: 'str.padEnd();', 80 | errors: [{ message: "ES2017 method 'String.prototype.padEnd' is forbidden" }], 81 | }, 82 | { 83 | code: 'String.prototype.padEnd;', 84 | errors: [{ message: "ES2017 method 'String.prototype.padEnd' is forbidden" }], 85 | }, 86 | { 87 | code: 'foo(bar,);', 88 | errors: [ 89 | { message: 'ES2017 trailing commas in parameter/argument lists are forbidden.' }, 90 | ], 91 | }, 92 | ], 93 | }); 94 | -------------------------------------------------------------------------------- /packages/eslint-plugin-ecmascript-compat/lib/features/es2018.js: -------------------------------------------------------------------------------- 1 | import eslint from 'eslint'; 2 | import esPlugin from 'eslint-plugin-es-x'; 3 | // Import assertions aren't yet stage 4 so aren't supported by ESLint 4 | import compatData from '@mdn/browser-compat-data/forLegacyNode'; 5 | import { noRestrictedSyntaxPrototypeMethod } from './ruleOptionsUtil.js'; 6 | 7 | const coreRules = new eslint.Linter().getRules(); 8 | 9 | export default [ 10 | { 11 | ruleConfig: { definition: esPlugin.rules['no-async-iteration'] }, 12 | compatFeatures: [ 13 | compatData.javascript.statements.for_await_of, 14 | compatData.javascript.functions.method_definitions.async_generator_methods, 15 | ], 16 | }, 17 | { 18 | ruleConfig: { definition: esPlugin.rules['no-rest-spread-properties'] }, 19 | compatFeatures: [ 20 | compatData.javascript.operators.destructuring.rest_in_objects, 21 | compatData.javascript.operators.spread.spread_in_object_literals, 22 | ], 23 | }, 24 | { 25 | ruleConfig: { 26 | definition: coreRules.get('no-restricted-syntax'), 27 | options: noRestrictedSyntaxPrototypeMethod('Promise.prototype.finally', 'ES2018'), 28 | }, 29 | compatFeatures: [compatData.javascript.builtins.Promise.finally], 30 | polyfill: 'Promise.prototype.finally', 31 | }, 32 | { 33 | ruleConfig: { definition: esPlugin.rules['no-regexp-lookbehind-assertions'] }, 34 | compatFeatures: [compatData.javascript.regular_expressions.lookbehind_assertion], 35 | }, 36 | { 37 | ruleConfig: { definition: esPlugin.rules['no-regexp-named-capture-groups'] }, 38 | compatFeatures: [compatData.javascript.regular_expressions.named_capturing_group], 39 | }, 40 | { 41 | ruleConfig: { definition: esPlugin.rules['no-regexp-s-flag'] }, 42 | compatFeatures: [compatData.javascript.builtins.RegExp.dotAll], 43 | }, 44 | { 45 | ruleConfig: { 46 | /** 47 | * New values were added in the following ES2019. 48 | * The rule no-regexp-unicode-property-escapes-2019 accepts these, but is omitted 49 | * because the compatibility data doesn't distinguish the two. 50 | */ 51 | definition: esPlugin.rules['no-regexp-unicode-property-escapes'], 52 | }, 53 | compatFeatures: [ 54 | compatData.javascript.regular_expressions.unicode_character_class_escape, 55 | ], 56 | }, 57 | ]; 58 | -------------------------------------------------------------------------------- /packages/eslint-plugin-ecmascript-compat/lib/features/es2018.test.js: -------------------------------------------------------------------------------- 1 | import { RuleTester } from 'eslint'; 2 | import rule from '../rule.js'; 3 | 4 | // Browser that doesn't support any features of this version - see es-versions.md 5 | process.env.BROWSERSLIST = 'Chrome >= 59'; 6 | 7 | const ruleTester = new RuleTester({ 8 | parserOptions: { 9 | ecmaVersion: 2018, 10 | }, 11 | }); 12 | 13 | ruleTester.run('compat', rule, { 14 | valid: [ 15 | { 16 | code: 'foo.finally();', 17 | options: [{ polyfills: ['Promise.prototype.finally'] }], 18 | }, 19 | ], 20 | invalid: [ 21 | { 22 | code: 'async function* asyncGenerator() {}', 23 | errors: [{ message: 'ES2018 async iteration is forbidden.' }], 24 | }, 25 | { 26 | code: 'async () => { for await (const bar of bar) { } }', 27 | errors: [{ message: 'ES2018 async iteration is forbidden.' }], 28 | }, 29 | { 30 | code: 'const foo = { ...bar };', 31 | errors: [{ message: 'ES2018 rest/spread properties are forbidden.' }], 32 | }, 33 | { 34 | code: 'const { a, ...rest } = foo;', 35 | errors: [{ message: 'ES2018 rest/spread properties are forbidden.' }], 36 | }, 37 | { 38 | code: 'foo.finally();', 39 | errors: [{ message: "ES2018 method 'Promise.prototype.finally' is forbidden" }], 40 | }, 41 | { 42 | code: 'Promise.prototype.finally;', 43 | errors: [{ message: "ES2018 method 'Promise.prototype.finally' is forbidden" }], 44 | }, 45 | { 46 | code: "/(?<=a)b/.test('look-behind assertion');", 47 | errors: [{ message: 'ES2018 RegExp lookbehind assertions are forbidden.' }], 48 | }, 49 | { 50 | code: "/(?b)c/.test('named capture group');", 51 | errors: [{ message: 'ES2018 RegExp named capture groups are forbidden.' }], 52 | }, 53 | { 54 | code: "/./s.test('dotAll flag');", 55 | errors: [{ message: "ES2018 RegExp 's' flag is forbidden." }], 56 | }, 57 | { 58 | code: "/\\p{Script=Hiragana}+/u.test('Unicode property escape');", 59 | errors: [ 60 | { message: 'ES2018 RegExp Unicode property escape sequences are forbidden.' }, 61 | ], 62 | }, 63 | ], 64 | }); 65 | -------------------------------------------------------------------------------- /packages/eslint-plugin-ecmascript-compat/lib/features/es2019.js: -------------------------------------------------------------------------------- 1 | import eslint from 'eslint'; 2 | import esPlugin from 'eslint-plugin-es-x'; 3 | // Import assertions aren't yet stage 4 so aren't supported by ESLint 4 | import compatData from '@mdn/browser-compat-data/forLegacyNode'; 5 | import { noRestrictedSyntaxPrototypeMethod } from './ruleOptionsUtil.js'; 6 | 7 | const coreRules = new eslint.Linter().getRules(); 8 | 9 | export default [ 10 | { 11 | ruleConfig: { 12 | definition: coreRules.get('no-restricted-syntax'), 13 | options: noRestrictedSyntaxPrototypeMethod('Array.prototype.flat', 'ES2019'), 14 | }, 15 | compatFeatures: [compatData.javascript.builtins.Array.flat], 16 | polyfill: 'Array.prototype.flat', 17 | }, 18 | { 19 | ruleConfig: { 20 | definition: coreRules.get('no-restricted-syntax'), 21 | options: noRestrictedSyntaxPrototypeMethod('Array.prototype.flatMap', 'ES2019'), 22 | }, 23 | compatFeatures: [compatData.javascript.builtins.Array.flatMap], 24 | polyfill: 'Array.prototype.flatMap', 25 | }, 26 | { 27 | ruleConfig: { definition: esPlugin.rules['no-json-superset'] }, 28 | compatFeatures: [compatData.javascript.builtins.JSON.json_superset], 29 | }, 30 | { 31 | ruleConfig: { definition: esPlugin.rules['no-object-fromentries'] }, 32 | compatFeatures: [compatData.javascript.builtins.Object.fromEntries], 33 | polyfill: 'Object.fromEntries', 34 | }, 35 | { 36 | ruleConfig: { definition: esPlugin.rules['no-optional-catch-binding'] }, 37 | compatFeatures: [compatData.javascript.statements.try_catch.optional_catch_binding], 38 | }, 39 | { 40 | ruleConfig: { 41 | definition: coreRules.get('no-restricted-syntax'), 42 | options: noRestrictedSyntaxPrototypeMethod('String.prototype.trimStart', 'ES2019'), 43 | }, 44 | compatFeatures: [compatData.javascript.builtins.String.trimStart], 45 | polyfill: 'String.prototype.trimStart', 46 | }, 47 | { 48 | ruleConfig: { 49 | definition: coreRules.get('no-restricted-syntax'), 50 | options: noRestrictedSyntaxPrototypeMethod('String.prototype.trimLeft', 'ES2019'), 51 | }, 52 | compatFeatures: [compatData.javascript.builtins.String.trimStart], // not a mistake; trimLeft is an alias for trimStart 53 | polyfill: 'String.prototype.trimLeft', 54 | }, 55 | { 56 | ruleConfig: { 57 | definition: coreRules.get('no-restricted-syntax'), 58 | options: noRestrictedSyntaxPrototypeMethod('String.prototype.trimEnd', 'ES2019'), 59 | }, 60 | compatFeatures: [compatData.javascript.builtins.String.trimEnd], 61 | polyfill: 'String.prototype.trimEnd', 62 | }, 63 | { 64 | ruleConfig: { 65 | definition: coreRules.get('no-restricted-syntax'), 66 | options: noRestrictedSyntaxPrototypeMethod('String.prototype.trimRight', 'ES2019'), 67 | }, 68 | compatFeatures: [compatData.javascript.builtins.String.trimEnd], // not a mistake; trimRight is an alias for trimEnd 69 | polyfill: 'String.prototype.trimRight', 70 | }, 71 | ]; 72 | -------------------------------------------------------------------------------- /packages/eslint-plugin-ecmascript-compat/lib/features/es2019.test.js: -------------------------------------------------------------------------------- 1 | import { RuleTester } from 'eslint'; 2 | import rule from '../rule.js'; 3 | 4 | // Browser that doesn't support any features of this version - see es-versions.md 5 | process.env.BROWSERSLIST = 'Chrome >= 65'; 6 | 7 | const ruleTester = new RuleTester({ 8 | parserOptions: { 9 | ecmaVersion: 2019, 10 | }, 11 | }); 12 | 13 | ruleTester.run('compat', rule, { 14 | valid: [ 15 | { 16 | code: 'const flat = residentialAddress.flat;', 17 | }, 18 | { 19 | code: 'residentialAddress.flat = flat;', 20 | }, 21 | { 22 | code: 'foo.flat();', 23 | options: [{ polyfills: ['Array.prototype.flat'] }], 24 | }, 25 | { 26 | code: 'foo.flatMap();', 27 | options: [{ polyfills: ['Array.prototype.flatMap'] }], 28 | }, 29 | { 30 | code: 'Object.fromEntries();', 31 | options: [{ polyfills: ['Object.fromEntries'] }], 32 | }, 33 | { 34 | code: 'foo.trimLeft();', 35 | options: [{ polyfills: ['String.prototype.trimLeft'] }], 36 | }, 37 | { 38 | code: 'foo.trimRight();', 39 | options: [{ polyfills: ['String.prototype.trimRight'] }], 40 | }, 41 | { 42 | code: 'foo.trimStart();', 43 | options: [{ polyfills: ['String.prototype.trimStart'] }], 44 | }, 45 | { 46 | code: 'foo.trimEnd();', 47 | options: [{ polyfills: ['String.prototype.trimEnd'] }], 48 | }, 49 | ], 50 | invalid: [ 51 | { 52 | code: 'foo.flat();', 53 | errors: [{ message: "ES2019 method 'Array.prototype.flat' is forbidden" }], 54 | }, 55 | { 56 | code: 'Array.prototype.flatMap;', 57 | errors: [{ message: "ES2019 method 'Array.prototype.flatMap' is forbidden" }], 58 | }, 59 | { 60 | // eslint-disable-next-line no-irregular-whitespace 61 | code: `const u2028 = '
';`, // line separator character \u2028 is in this string 62 | errors: [{ message: "ES2019 '\\u2028' in string literals is forbidden." }], 63 | }, 64 | { 65 | code: 'Object.fromEntries();', 66 | errors: [{ message: "ES2019 'Object.fromEntries' method is forbidden." }], 67 | }, 68 | { 69 | code: 'try {} catch {}', 70 | errors: [{ message: "ES2019 optional 'catch' binding is forbidden." }], 71 | }, 72 | { 73 | code: 'foo.trimLeft();', 74 | errors: [{ message: "ES2019 method 'String.prototype.trimLeft' is forbidden" }], 75 | }, 76 | { 77 | code: 'String.prototype.trimRight;', 78 | errors: [{ message: "ES2019 method 'String.prototype.trimRight' is forbidden" }], 79 | }, 80 | { 81 | code: 'String.prototype.trimStart;', 82 | errors: [{ message: "ES2019 method 'String.prototype.trimStart' is forbidden" }], 83 | }, 84 | { 85 | code: 'foo.trimEnd();', 86 | errors: [{ message: "ES2019 method 'String.prototype.trimEnd' is forbidden" }], 87 | }, 88 | ], 89 | }); 90 | -------------------------------------------------------------------------------- /packages/eslint-plugin-ecmascript-compat/lib/features/es2020.js: -------------------------------------------------------------------------------- 1 | import eslint from 'eslint'; 2 | import esPlugin from 'eslint-plugin-es-x'; 3 | // Import assertions aren't yet stage 4 so aren't supported by ESLint 4 | import compatData from '@mdn/browser-compat-data/forLegacyNode'; 5 | import { noRestrictedSyntaxPrototypeMethod } from './ruleOptionsUtil.js'; 6 | 7 | const coreRules = new eslint.Linter().getRules(); 8 | 9 | export default [ 10 | { 11 | ruleConfig: { 12 | definition: coreRules.get('no-restricted-properties'), 13 | options: [{ object: 'Atomics', property: 'notify', message: '(ES2020)' }], 14 | }, 15 | compatFeatures: [compatData.javascript.builtins.Atomics.notify], 16 | }, 17 | { 18 | ruleConfig: { 19 | definition: coreRules.get('no-restricted-properties'), 20 | options: [{ object: 'Atomics', property: 'wait', message: '(ES2020)' }], 21 | }, 22 | compatFeatures: [compatData.javascript.builtins.Atomics.wait], 23 | }, 24 | { 25 | ruleConfig: { definition: esPlugin.rules['no-bigint'] }, 26 | compatFeatures: [compatData.javascript.builtins.BigInt], 27 | }, 28 | { 29 | ruleConfig: { definition: esPlugin.rules['no-dynamic-import'] }, 30 | compatFeatures: [compatData.javascript.operators.import], 31 | }, 32 | { 33 | ruleConfig: { definition: esPlugin.rules['no-global-this'] }, 34 | compatFeatures: [compatData.javascript.builtins.globalThis], 35 | polyfill: 'globalThis', 36 | }, 37 | { 38 | ruleConfig: { definition: esPlugin.rules['no-import-meta'] }, 39 | compatFeatures: [compatData.javascript.operators.import_meta], 40 | }, 41 | { 42 | ruleConfig: { definition: esPlugin.rules['no-export-ns-from'] }, 43 | compatFeatures: [compatData.javascript.statements.export.namespace], 44 | }, 45 | { 46 | ruleConfig: { definition: esPlugin.rules['no-nullish-coalescing-operators'] }, 47 | compatFeatures: [compatData.javascript.operators.nullish_coalescing], 48 | }, 49 | { 50 | ruleConfig: { definition: esPlugin.rules['no-optional-chaining'] }, 51 | compatFeatures: [compatData.javascript.operators.optional_chaining], 52 | }, 53 | { 54 | // Rule requires the ES6 global, Promise 55 | ruleConfig: { definition: esPlugin.rules['no-promise-all-settled'] }, 56 | compatFeatures: [compatData.javascript.builtins.Promise.allSettled], 57 | polyfill: 'Promise.prototype.allSettled', 58 | }, 59 | { 60 | // May false positive for Cache/Clients.matchAll() 61 | ruleConfig: { 62 | definition: coreRules.get('no-restricted-syntax'), 63 | options: noRestrictedSyntaxPrototypeMethod('String.prototype.matchAll', 'ES2020'), 64 | }, 65 | compatFeatures: [compatData.javascript.builtins.String.matchAll], 66 | polyfill: 'String.prototype.matchAll', 67 | }, 68 | ]; 69 | -------------------------------------------------------------------------------- /packages/eslint-plugin-ecmascript-compat/lib/features/es2020.test.js: -------------------------------------------------------------------------------- 1 | import { RuleTester } from 'eslint'; 2 | import rule from '../rule.js'; 3 | 4 | // Browser that doesn't support any features of this version - see es-versions.md 5 | process.env.BROWSERSLIST = 'Chrome >= 62'; 6 | 7 | const ruleTester = new RuleTester({ 8 | parserOptions: { 9 | ecmaVersion: 2020, 10 | sourceType: 'module', // import.meta and namespace exports can only be used in an ES module 11 | }, 12 | globals: { 13 | // ES2020 global, required by es/no-bigint 14 | BigInt: 'readonly', 15 | 16 | // ES2020 global, required by es/no-global-this 17 | globalThis: 'readonly', 18 | 19 | // ES6 global, required by es/no-promise-all-settled 20 | Promise: 'readonly', 21 | }, 22 | }); 23 | 24 | ruleTester.run('compat', rule, { 25 | valid: [ 26 | { 27 | code: 'globalThis.foo;', 28 | options: [{ polyfills: ['globalThis'] }], 29 | }, 30 | { 31 | code: 'Promise.allSettled();', 32 | options: [{ polyfills: ['Promise.prototype.allSettled'] }], 33 | }, 34 | { 35 | code: 'foo.matchAll();', 36 | options: [{ polyfills: ['String.prototype.matchAll'] }], 37 | }, 38 | ], 39 | invalid: [ 40 | { 41 | code: 'Atomics.notify();', 42 | errors: [{ message: "'Atomics.notify' is restricted from being used. (ES2020)" }], 43 | }, 44 | { 45 | code: 'Atomics.wait();', 46 | errors: [{ message: "'Atomics.wait' is restricted from being used. (ES2020)" }], 47 | }, 48 | { 49 | code: 'const foo = 100n;', 50 | errors: [{ message: 'ES2020 BigInt is forbidden.' }], 51 | }, 52 | { 53 | code: 'BigInt(100);', 54 | errors: [{ message: 'ES2020 BigInt is forbidden.' }], 55 | }, 56 | { 57 | code: "async function foo() { await import(''); }", 58 | errors: [{ message: "ES2020 'import()' syntax is forbidden." }], 59 | }, 60 | { 61 | code: 'globalThis.foo;', 62 | errors: [{ message: "ES2020 'globalThis' variable is forbidden." }], 63 | }, 64 | { 65 | code: 'import.meta;', 66 | errors: [{ message: "ES2020 'import.meta' meta property is forbidden." }], 67 | }, 68 | { 69 | code: 'export * as nmspace from "./other";', 70 | errors: [{ message: "ES2020 'export * as ns' are forbidden." }], 71 | }, 72 | { 73 | code: 'foo ?? fallback', 74 | errors: [{ message: 'ES2020 nullish coalescing operators are forbidden.' }], 75 | }, 76 | { 77 | code: 'fooMaybe?.something', 78 | errors: [{ message: 'ES2020 optional chaining is forbidden.' }], 79 | }, 80 | { 81 | code: 'Promise.allSettled();', 82 | errors: [{ message: "ES2020 'Promise.allSettled' function is forbidden." }], 83 | }, 84 | { 85 | code: 'foo.matchAll();', 86 | errors: [{ message: "ES2020 method 'String.prototype.matchAll' is forbidden" }], 87 | }, 88 | { 89 | code: 'String.prototype.matchAll;', 90 | errors: [{ message: "ES2020 method 'String.prototype.matchAll' is forbidden" }], 91 | }, 92 | ], 93 | }); 94 | -------------------------------------------------------------------------------- /packages/eslint-plugin-ecmascript-compat/lib/features/es2021.js: -------------------------------------------------------------------------------- 1 | import eslint from 'eslint'; 2 | // Import assertions aren't yet stage 4 so aren't supported by ESLint 3 | import compatData from '@mdn/browser-compat-data/forLegacyNode'; 4 | import esPlugin from 'eslint-plugin-es-x'; 5 | import { noRestrictedSyntaxPrototypeMethod } from './ruleOptionsUtil.js'; 6 | 7 | const coreRules = new eslint.Linter().getRules(); 8 | 9 | export default [ 10 | { 11 | ruleConfig: { 12 | definition: coreRules.get('no-restricted-syntax'), 13 | options: noRestrictedSyntaxPrototypeMethod('String.prototype.replaceAll', 'ES2021'), 14 | }, 15 | compatFeatures: [compatData.javascript.builtins.String.replaceAll], 16 | polyfill: 'String.prototype.replaceAll', 17 | }, 18 | { 19 | ruleConfig: { definition: esPlugin.rules['no-logical-assignment-operators'] }, 20 | compatFeatures: [ 21 | compatData.javascript.operators.logical_or_assignment, 22 | compatData.javascript.operators.logical_and_assignment, 23 | compatData.javascript.operators.nullish_coalescing_assignment, 24 | ], 25 | }, 26 | { 27 | ruleConfig: { definition: esPlugin.rules['no-numeric-separators'] }, 28 | compatFeatures: [compatData.javascript.grammar.numeric_separators], 29 | }, 30 | { 31 | ruleConfig: { definition: esPlugin.rules['no-promise-any'] }, 32 | compatFeatures: [compatData.javascript.builtins.Promise.any], 33 | polyfill: 'Promise.prototype.any', 34 | }, 35 | { 36 | ruleConfig: { definition: esPlugin.rules['no-weakrefs'] }, 37 | compatFeatures: [ 38 | compatData.javascript.builtins.WeakRef, 39 | compatData.javascript.builtins.FinalizationRegistry, 40 | ], 41 | }, 42 | ]; 43 | -------------------------------------------------------------------------------- /packages/eslint-plugin-ecmascript-compat/lib/features/es2021.test.js: -------------------------------------------------------------------------------- 1 | import { RuleTester } from 'eslint'; 2 | import rule from '../rule.js'; 3 | 4 | // Browser that doesn't support any features of this version - see es-versions.md 5 | process.env.BROWSERSLIST = 'Chrome >= 74'; 6 | 7 | const ruleTester = new RuleTester({ 8 | parserOptions: { 9 | ecmaVersion: 2021, 10 | }, 11 | globals: { 12 | // ES2021 global, required by es/no-weakrefs 13 | WeakRef: 'readonly', 14 | FinalizationRegistry: 'readonly', 15 | // ES6 global, required by es/no-promise-all-settled 16 | Promise: 'readonly', 17 | }, 18 | }); 19 | 20 | ruleTester.run('compat', rule, { 21 | valid: [ 22 | { 23 | code: '"A dog".replaceAll("dog", "monkey");', 24 | options: [{ polyfills: ['String.prototype.replaceAll'] }], 25 | }, 26 | { 27 | code: 'const a = Promise.any([]);', 28 | options: [{ polyfills: ['Promise.prototype.any'] }], 29 | }, 30 | ], 31 | invalid: [ 32 | { 33 | code: '"A dog".replaceAll("dog", "monkey");', 34 | errors: [{ message: "ES2021 method 'String.prototype.replaceAll' is forbidden" }], 35 | }, 36 | { 37 | code: 'a ||= 1;', 38 | errors: [{ message: 'ES2021 logical assignment operators are forbidden.' }], 39 | }, 40 | { 41 | code: 'a &&= 1;', 42 | errors: [{ message: 'ES2021 logical assignment operators are forbidden.' }], 43 | }, 44 | { 45 | code: 'a ??= 1;', 46 | errors: [{ message: 'ES2021 logical assignment operators are forbidden.' }], 47 | }, 48 | { 49 | code: 'const a = 1_000_00;', 50 | errors: [{ message: 'ES2021 numeric separators are forbidden.' }], 51 | }, 52 | { 53 | code: 'const a = Promise.any([]);', 54 | errors: [{ message: "ES2021 'Promise.any' is forbidden." }], 55 | }, 56 | { 57 | code: 'const a = new WeakRef();', 58 | errors: [{ message: "ES2021 'WeakRef' class is forbidden." }], 59 | }, 60 | { 61 | code: 'const a = new FinalizationRegistry(() => {});', 62 | errors: [{ message: "ES2021 'FinalizationRegistry' class is forbidden." }], 63 | }, 64 | ], 65 | }); 66 | -------------------------------------------------------------------------------- /packages/eslint-plugin-ecmascript-compat/lib/features/es2022.js: -------------------------------------------------------------------------------- 1 | // Import assertions aren't yet stage 4 so aren't supported by ESLint 2 | import compatData from '@mdn/browser-compat-data/forLegacyNode'; 3 | import esPlugin from 'eslint-plugin-es-x'; 4 | 5 | export default [ 6 | { 7 | ruleConfig: { 8 | definition: esPlugin.rules['no-array-string-prototype-at'], 9 | options: [{ aggressive: true }], 10 | }, 11 | compatFeatures: [ 12 | compatData.javascript.builtins.Array.at, 13 | compatData.javascript.builtins.TypedArray.at, 14 | compatData.javascript.builtins.String.at, 15 | ], 16 | polyfill: '{Array,String,TypedArray}.prototype.at', 17 | }, 18 | { 19 | ruleConfig: { definition: esPlugin.rules['no-class-fields'] }, 20 | compatFeatures: [ 21 | compatData.javascript.classes.public_class_fields, 22 | compatData.javascript.classes.private_class_fields, 23 | compatData.javascript.classes.static_class_fields, 24 | compatData.javascript.classes.private_class_methods, 25 | ], 26 | }, 27 | { 28 | ruleConfig: { definition: esPlugin.rules['no-class-static-block'] }, 29 | compatFeatures: [compatData.javascript.classes.static_initialization_blocks], 30 | }, 31 | { 32 | ruleConfig: { definition: esPlugin.rules['no-error-cause'] }, 33 | compatFeatures: [compatData.javascript.builtins.Error.Error.options_cause_parameter], 34 | polyfill: 'Error.cause', 35 | }, 36 | { 37 | ruleConfig: { definition: esPlugin.rules['no-object-hasown'] }, 38 | compatFeatures: [compatData.javascript.builtins.Object.hasOwn], 39 | polyfill: 'Object.hasOwn', 40 | }, 41 | { 42 | ruleConfig: { definition: esPlugin.rules['no-private-in'] }, 43 | compatFeatures: [compatData.javascript.classes.private_class_fields_in], 44 | }, 45 | { 46 | ruleConfig: { definition: esPlugin.rules['no-regexp-d-flag'] }, 47 | compatFeatures: [compatData.javascript.builtins.RegExp.hasIndices], 48 | }, 49 | { 50 | ruleConfig: { definition: esPlugin.rules['no-top-level-await'] }, 51 | compatFeatures: [compatData.javascript.operators.await.top_level], 52 | }, 53 | ]; 54 | -------------------------------------------------------------------------------- /packages/eslint-plugin-ecmascript-compat/lib/features/es2022.test.js: -------------------------------------------------------------------------------- 1 | import { RuleTester } from 'eslint'; 2 | import rule from '../rule.js'; 3 | 4 | // Browser that doesn't support any features of this version - see es-versions.md 5 | process.env.BROWSERSLIST = 'Chrome >= 71'; 6 | 7 | const ruleTester = new RuleTester({ 8 | parserOptions: { 9 | ecmaVersion: 2022, 10 | sourceType: 'module', // top level await can only be used in an ES module 11 | }, 12 | }); 13 | 14 | ruleTester.run('compat', rule, { 15 | valid: [ 16 | { 17 | code: '[].at(1);', 18 | options: [{ polyfills: ['{Array,String,TypedArray}.prototype.at'] }], 19 | }, 20 | { 21 | code: '"Foo".at(1);', 22 | options: [{ polyfills: ['{Array,String,TypedArray}.prototype.at'] }], 23 | }, 24 | { 25 | code: "new Error('message', { cause: originalError })", 26 | options: [{ polyfills: ['Error.cause'] }], 27 | }, 28 | { 29 | code: "Object.hasOwn(obj, 'prop');", 30 | options: [{ polyfills: ['Object.hasOwn'] }], 31 | }, 32 | ], 33 | invalid: [ 34 | { 35 | // Obvious array, doesn't need aggressive mode 36 | code: '[].at(1);', 37 | errors: [{ message: "ES2022 'Array.prototype.at' method is forbidden." }], 38 | }, 39 | { 40 | // Obvious string, doesn't need aggressive mode 41 | code: '"Foo".at(1);', 42 | errors: [{ message: "ES2022 'String.prototype.at' method is forbidden." }], 43 | }, 44 | { 45 | // Not obvious, needs aggressive mode 46 | code: 'foo.at(1);', 47 | errors: [{ message: "ES2022 'Array.prototype.at' method is forbidden." }], 48 | }, 49 | { 50 | code: 'class A { #a = 0 }', 51 | errors: [{ message: 'ES2022 private field #a is forbidden.' }], 52 | }, 53 | { 54 | code: 'class A { static { } }', 55 | errors: [{ message: 'ES2022 class static block is forbidden.' }], 56 | }, 57 | { 58 | code: "new Error('message', { cause: originalError })", 59 | errors: [{ message: 'ES2022 Error Cause is forbidden.' }], 60 | }, 61 | { 62 | code: "Object.hasOwn(obj, 'prop');", 63 | errors: [{ message: "ES2022 'Object.hasOwn' method is forbidden." }], 64 | }, 65 | { 66 | code: '/./d;', 67 | errors: [{ message: "ES2022 RegExp 'd' flag is forbidden." }], 68 | }, 69 | { 70 | code: 'await true;', 71 | errors: [{ message: "ES2022 top-level 'await' is forbidden." }], 72 | }, 73 | { 74 | code: 'class A { #field; foo() { #field in this; } }', 75 | // Browser that supports private fields but not `in` on them - see es-versions.md 76 | options: [{ overrideBrowserslist: 'Chrome >= 90' }], 77 | errors: [{ message: 'ES2022 private in (`#field in object`) is forbidden.' }], 78 | }, 79 | ], 80 | }); 81 | -------------------------------------------------------------------------------- /packages/eslint-plugin-ecmascript-compat/lib/features/es2023.js: -------------------------------------------------------------------------------- 1 | // Import assertions aren't yet stage 4 so aren't supported by ESLint 2 | import compatData from '@mdn/browser-compat-data/forLegacyNode'; 3 | import esPlugin from 'eslint-plugin-es-x'; 4 | 5 | export default [ 6 | { 7 | ruleConfig: { 8 | definition: esPlugin.rules['no-array-prototype-findlast-findlastindex'], 9 | options: [{ aggressive: true }], 10 | }, 11 | compatFeatures: [ 12 | compatData.javascript.builtins.Array.findLast, 13 | compatData.javascript.builtins.Array.findLastIndex, 14 | compatData.javascript.builtins.TypedArray.findLast, 15 | compatData.javascript.builtins.TypedArray.findLastIndex, 16 | ], 17 | polyfill: '{Array,TypedArray}.prototype.findLast', 18 | }, 19 | { 20 | ruleConfig: { 21 | definition: esPlugin.rules['no-array-prototype-toreversed'], 22 | options: [{ aggressive: true }], 23 | }, 24 | compatFeatures: [ 25 | compatData.javascript.builtins.Array.toReversed, 26 | compatData.javascript.builtins.TypedArray.toReversed, 27 | ], 28 | polyfill: '{Array,TypedArray}.prototype.toReversed', 29 | }, 30 | { 31 | ruleConfig: { 32 | definition: esPlugin.rules['no-array-prototype-tosorted'], 33 | options: [{ aggressive: true }], 34 | }, 35 | compatFeatures: [ 36 | compatData.javascript.builtins.Array.toSorted, 37 | compatData.javascript.builtins.TypedArray.toSorted, 38 | ], 39 | polyfill: '{Array,TypedArray}.prototype.toSorted', 40 | }, 41 | { 42 | ruleConfig: { 43 | definition: esPlugin.rules['no-array-prototype-tospliced'], 44 | options: [{ aggressive: true }], 45 | }, 46 | compatFeatures: [compatData.javascript.builtins.Array.toSpliced], 47 | polyfill: 'Array.prototype.toSpliced', 48 | }, 49 | { 50 | ruleConfig: { 51 | definition: esPlugin.rules['no-array-prototype-with'], 52 | options: [{ aggressive: true }], 53 | }, 54 | compatFeatures: [ 55 | compatData.javascript.builtins.Array.with, 56 | compatData.javascript.builtins.TypedArray.with, 57 | ], 58 | polyfill: '{Array,TypedArray}.prototype.with', 59 | }, 60 | { 61 | ruleConfig: { 62 | definition: esPlugin.rules['no-hashbang'], 63 | }, 64 | compatFeatures: [compatData.javascript.grammar.hashbang_comments], 65 | }, 66 | ]; 67 | -------------------------------------------------------------------------------- /packages/eslint-plugin-ecmascript-compat/lib/features/es2023.test.js: -------------------------------------------------------------------------------- 1 | import { RuleTester } from 'eslint'; 2 | import rule from '../rule.js'; 3 | 4 | // Browser that doesn't support any features of this version - see es-versions.md 5 | process.env.BROWSERSLIST = 'Chrome >= 73'; 6 | 7 | const ruleTester = new RuleTester({ 8 | parserOptions: { 9 | ecmaVersion: 2023, 10 | }, 11 | }); 12 | 13 | ruleTester.run('compat', rule, { 14 | valid: [ 15 | { 16 | code: '[].findLast("a");', 17 | options: [{ polyfills: ['{Array,TypedArray}.prototype.findLast'] }], 18 | }, 19 | { 20 | code: '[].toReversed();', 21 | options: [{ polyfills: ['{Array,TypedArray}.prototype.toReversed'] }], 22 | }, 23 | { 24 | code: '[].toSorted();', 25 | options: [{ polyfills: ['{Array,TypedArray}.prototype.toSorted'] }], 26 | }, 27 | { 28 | code: '[].toSpliced(1);', 29 | options: [{ polyfills: ['Array.prototype.toSpliced'] }], 30 | }, 31 | { 32 | code: '[].with(1, "a");', 33 | options: [{ polyfills: ['{Array,TypedArray}.prototype.with'] }], 34 | }, 35 | ], 36 | invalid: [ 37 | { 38 | // Obvious array, doesn't need aggressive mode 39 | code: '[].findLast("a");', 40 | errors: [{ message: "ES2023 'Array.prototype.findLast' method is forbidden." }], 41 | }, 42 | { 43 | // Not obvious, needs aggressive mode 44 | code: 'foo.findLast("a");', 45 | errors: [{ message: "ES2023 'Array.prototype.findLast' method is forbidden." }], 46 | }, 47 | { 48 | // Obvious array, doesn't need aggressive mode 49 | code: '[].toReversed();', 50 | errors: [{ message: "ES2023 'Array.prototype.toReversed' method is forbidden." }], 51 | }, 52 | { 53 | // Not obvious, needs aggressive mode 54 | code: 'foo.toReversed();', 55 | errors: [{ message: "ES2023 'Array.prototype.toReversed' method is forbidden." }], 56 | }, 57 | { 58 | // Obvious array, doesn't need aggressive mode 59 | code: '[].toSorted();', 60 | errors: [{ message: "ES2023 'Array.prototype.toSorted' method is forbidden." }], 61 | }, 62 | { 63 | // Not obvious, needs aggressive mode 64 | code: 'foo.toSorted();', 65 | errors: [{ message: "ES2023 'Array.prototype.toSorted' method is forbidden." }], 66 | }, 67 | { 68 | // Obvious array, doesn't need aggressive mode 69 | code: '[].toSpliced(1);', 70 | errors: [{ message: "ES2023 'Array.prototype.toSpliced' method is forbidden." }], 71 | }, 72 | { 73 | // Not obvious, needs aggressive mode 74 | code: 'foo.toSpliced(1);', 75 | errors: [{ message: "ES2023 'Array.prototype.toSpliced' method is forbidden." }], 76 | }, 77 | { 78 | // Obvious array, doesn't need aggressive mode 79 | code: '[].with(1, "a");', 80 | errors: [{ message: "ES2023 'Array.prototype.with' method is forbidden." }], 81 | }, 82 | { 83 | // Not obvious, needs aggressive mode 84 | code: 'foo.with(1, "a");', 85 | errors: [{ message: "ES2023 'Array.prototype.with' method is forbidden." }], 86 | }, 87 | { 88 | code: '#!/usr/bin/env node', 89 | errors: [{ message: 'ES2023 Hashbang comments are forbidden.' }], 90 | }, 91 | ], 92 | }); 93 | -------------------------------------------------------------------------------- /packages/eslint-plugin-ecmascript-compat/lib/features/index.js: -------------------------------------------------------------------------------- 1 | import es2016 from './es2016.js'; 2 | import es2017 from './es2017.js'; 3 | import es2018 from './es2018.js'; 4 | import es2019 from './es2019.js'; 5 | import es2020 from './es2020.js'; 6 | import es2021 from './es2021.js'; 7 | import es2022 from './es2022.js'; 8 | import es2023 from './es2023.js'; 9 | 10 | export default [ 11 | ...es2016, 12 | ...es2017, 13 | ...es2018, 14 | ...es2019, 15 | ...es2020, 16 | ...es2021, 17 | ...es2022, 18 | ...es2023, 19 | ]; 20 | -------------------------------------------------------------------------------- /packages/eslint-plugin-ecmascript-compat/lib/features/ruleOptionsUtil.js: -------------------------------------------------------------------------------- 1 | export function noRestrictedSyntaxPrototypeMethod(method, esVersionName) { 2 | const [builtin, , name] = method.split('.'); 3 | const message = `${esVersionName} method '${method}' is forbidden`; 4 | 5 | return [ 6 | { 7 | selector: `CallExpression[callee.property.name='${name}']`, 8 | message, 9 | }, 10 | { 11 | selector: `MemberExpression[object.object.name='${builtin}'][object.property.name='prototype'][property.name='${name}']`, 12 | message, 13 | }, 14 | ]; 15 | } 16 | -------------------------------------------------------------------------------- /packages/eslint-plugin-ecmascript-compat/lib/index.js: -------------------------------------------------------------------------------- 1 | import rule from './rule.js'; 2 | 3 | export default { 4 | configs: { 5 | recommended: { 6 | plugins: ['ecmascript-compat'], 7 | rules: { 8 | 'ecmascript-compat/compat': 'error', 9 | }, 10 | }, 11 | }, 12 | rules: { 13 | compat: rule, 14 | }, 15 | }; 16 | -------------------------------------------------------------------------------- /packages/eslint-plugin-ecmascript-compat/lib/rule.js: -------------------------------------------------------------------------------- 1 | import * as compatibility from './compatibility.js'; 2 | import { createDelegatee, delegatingVisitor } from './delegation.js'; 3 | import features from './features/index.js'; 4 | import targetRuntimes from './targetRuntimes.js'; 5 | 6 | export default { 7 | meta: { 8 | type: 'problem', 9 | schema: [ 10 | { 11 | type: 'object', 12 | properties: { 13 | polyfills: { 14 | type: 'array', 15 | items: { 16 | type: 'string', 17 | enum: [ 18 | // This list is hard-coded so it can serve as documentation 19 | 'globalThis', 20 | '{Array,String,TypedArray}.prototype.at', 21 | '{Array,TypedArray}.prototype.findLast', 22 | '{Array,TypedArray}.prototype.toReversed', 23 | '{Array,TypedArray}.prototype.toSorted', 24 | '{Array,TypedArray}.prototype.with', 25 | 'Array.prototype.flat', 26 | 'Array.prototype.flatMap', 27 | 'Array.prototype.includes', 28 | 'Array.prototype.toSpliced', 29 | 'Error.cause', 30 | 'Object.entries', 31 | 'Object.fromEntries', 32 | 'Object.getOwnPropertyDescriptors', 33 | 'Object.hasOwn', 34 | 'Object.values', 35 | 'Promise.prototype.allSettled', 36 | 'Promise.prototype.any', 37 | 'Promise.prototype.finally', 38 | 'String.prototype.matchAll', 39 | 'String.prototype.padEnd', 40 | 'String.prototype.padStart', 41 | 'String.prototype.replaceAll', 42 | 'String.prototype.trimEnd', 43 | 'String.prototype.trimLeft', 44 | 'String.prototype.trimRight', 45 | 'String.prototype.trimStart', 46 | ], 47 | }, 48 | }, 49 | overrideBrowserslist: { 50 | oneOf: [{ type: 'string' }, { type: 'array', items: { type: 'string' } }], 51 | }, 52 | browserslistOptions: { 53 | type: 'object', 54 | additionalProperties: true, 55 | }, 56 | }, 57 | additionalProperties: false, 58 | }, 59 | ], 60 | }, 61 | create(context) { 62 | const overrideBrowserslist = context.options?.[0]?.overrideBrowserslist; 63 | const browserslistOptions = context.options?.[0]?.browserslistOptions; 64 | const targets = targetRuntimes(overrideBrowserslist, browserslistOptions); 65 | const unsupportedFeatures = compatibility.unsupportedFeatures(features, targets); 66 | 67 | const polyfills = context.options?.[0]?.polyfills ?? []; 68 | 69 | const visitors = unsupportedFeatures 70 | .filter((feature) => !polyfills.includes(feature.polyfill)) 71 | .map((feature) => createDelegatee(feature.ruleConfig, context)); 72 | 73 | return delegatingVisitor(visitors); 74 | }, 75 | }; 76 | -------------------------------------------------------------------------------- /packages/eslint-plugin-ecmascript-compat/lib/rule.test.js: -------------------------------------------------------------------------------- 1 | import assert from 'node:assert'; 2 | import { test } from 'node:test'; 3 | import features from './features/index.js'; 4 | import rule from './rule.js'; 5 | 6 | test('polyfills accepted in the schema exactly match those supported', () => { 7 | const schemaPolyfills = rule.meta.schema[0].properties.polyfills.items.enum; 8 | const supportedPolyfills = features.flatMap((feature) => 9 | feature.polyfill ? [feature.polyfill] : [] 10 | ); 11 | 12 | assert.deepStrictEqual(schemaPolyfills.sort(), supportedPolyfills.sort()); 13 | }); 14 | -------------------------------------------------------------------------------- /packages/eslint-plugin-ecmascript-compat/lib/targetRuntimes.js: -------------------------------------------------------------------------------- 1 | import browserslist from 'browserslist'; 2 | import _ from 'lodash'; 3 | // Import assertions aren't yet stage 4 so aren't supported by ESLint 4 | import compatData from '@mdn/browser-compat-data/forLegacyNode'; 5 | import compareVersions from './compareVersions.js'; 6 | 7 | export default function targetRuntimes(overrideBrowserslist, browserslistOptions) { 8 | // ['chrome 50', ...] 9 | const allNamedVersions = browserslist(overrideBrowserslist, browserslistOptions); 10 | 11 | // [ { name, version }, ... ] 12 | const all = allNamedVersions.map((namedVersion) => { 13 | const [name, version] = namedVersion.split(' '); 14 | return { 15 | name, 16 | version: simplifyVersion(version), 17 | }; 18 | }); 19 | 20 | // { name: oldestVersion } 21 | const oldestOfEach = _.chain(all) 22 | .groupBy('name') 23 | .mapValues( 24 | (familyMember) => 25 | familyMember.sort((a, b) => compareVersions(a.version, b.version))[0].version 26 | ) 27 | .value(); 28 | 29 | const mapped = _.mapKeys(oldestOfEach, (version, name) => mapFamilyName(name)); 30 | const final = _.pickBy(mapped, (version, name) => isKnownFamily(name)); 31 | 32 | // [ { name, version } ] 33 | return Object.entries(final).map(([name, version]) => ({ name, version })); 34 | } 35 | 36 | function isKnownFamily(name) { 37 | return compatData.browsers[name] != null; 38 | } 39 | 40 | // browserslist -> @mdn/browser-compat-data (where necessary and available) 41 | /* eslint-disable camelcase */ 42 | const familyNameMapping = { 43 | and_chr: 'chrome_android', 44 | and_ff: 'firefox_android', 45 | android: 'webview_android', 46 | ios_saf: 'safari_ios', 47 | node: 'nodejs', 48 | op_mob: 'opera_android', 49 | samsung: 'samsunginternet_android', 50 | }; 51 | /* eslint-enable camelcase */ 52 | 53 | function mapFamilyName(browserslistName) { 54 | return familyNameMapping[browserslistName] || browserslistName; 55 | } 56 | 57 | function simplifyVersion(version) { 58 | return version.includes('-') ? version.split('-')[0] : version; 59 | } 60 | -------------------------------------------------------------------------------- /packages/eslint-plugin-ecmascript-compat/lib/targetRuntimes.test.js: -------------------------------------------------------------------------------- 1 | import assert from 'node:assert'; 2 | import { beforeEach, it } from 'node:test'; 3 | import browserslist from 'browserslist'; 4 | import targetRuntimes from './targetRuntimes.js'; 5 | 6 | beforeEach(() => { 7 | delete process.env.BROWSERSLIST; 8 | browserslist.clearCaches(); 9 | }); 10 | 11 | it('targets the oldest version of each family', () => { 12 | process.env.BROWSERSLIST = 'Chrome >= 50'; 13 | 14 | assert.deepStrictEqual(targetRuntimes(), [{ name: 'chrome', version: '50' }]); 15 | }); 16 | 17 | it('targets the oldest version of each family, treating versions as numbers', () => { 18 | process.env.BROWSERSLIST = 'chrome 9-10'; 19 | 20 | assert.deepStrictEqual(targetRuntimes(), [{ name: 'chrome', version: '9' }]); 21 | }); 22 | 23 | it('maps browserslist names to mdn names where necessary', () => { 24 | process.env.BROWSERSLIST = 'Android >= 0'; 25 | 26 | assert.deepStrictEqual(targetRuntimes(), [{ name: 'webview_android', version: '2.1' }]); 27 | }); 28 | 29 | it('discards families unknown to mdn', () => { 30 | process.env.BROWSERSLIST = 'kaios >= 0'; 31 | 32 | assert.deepStrictEqual(targetRuntimes(), []); 33 | }); 34 | 35 | it('handles multiple families', () => { 36 | process.env.BROWSERSLIST = 'Firefox >= 55,IE >= 10'; 37 | 38 | assert.deepStrictEqual(targetRuntimes(), [ 39 | { name: 'firefox', version: '55' }, 40 | { name: 'ie', version: '10' }, 41 | ]); 42 | }); 43 | 44 | it('accepts a override', () => { 45 | assert.deepStrictEqual(targetRuntimes('Firefox >= 55,IE >= 10'), [ 46 | { name: 'firefox', version: '55' }, 47 | { name: 'ie', version: '10' }, 48 | ]); 49 | }); 50 | 51 | it('preserves versions as strings to allow semver', () => { 52 | process.env.BROWSERSLIST = 'Node >= 0'; 53 | 54 | assert.deepStrictEqual(targetRuntimes(), [{ name: 'nodejs', version: '0.2.0' }]); 55 | }); 56 | 57 | it('simplifies version ranges to the start of the range', () => { 58 | assert.deepStrictEqual(browserslist('iOS 15'), ['ios_saf 15.0-15.1']); 59 | 60 | process.env.BROWSERSLIST = 'iOS 15'; 61 | 62 | assert.deepStrictEqual(targetRuntimes(), [{ name: 'safari_ios', version: '15.0' }]); 63 | }); 64 | -------------------------------------------------------------------------------- /packages/eslint-plugin-ecmascript-compat/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "eslint-plugin-ecmascript-compat", 3 | "version": "3.2.1", 4 | "description": "ESLint plugin for checking JavaScript code compatibility with target browsers and Node.js versions", 5 | "keywords": [ 6 | "browser", 7 | "compatibility", 8 | "compat", 9 | "support", 10 | "javascript", 11 | "ecmascript", 12 | "es", 13 | "lint", 14 | "eslint", 15 | "eslintplugin", 16 | "browserslist", 17 | "browser-compat-data", 18 | "caniuse", 19 | "kangax", 20 | "eslint-plugin-compat", 21 | "eslint-plugin-es", 22 | "eslint-plugin-es-x" 23 | ], 24 | "homepage": "https://github.com/robatwilliams/es-compat#readme", 25 | "bugs": { 26 | "url": "https://github.com/robatwilliams/es-compat/issues" 27 | }, 28 | "repository": { 29 | "type": "git", 30 | "url": "https://github.com/robatwilliams/es-compat.git" 31 | }, 32 | "license": "MIT", 33 | "author": "Robat Williams", 34 | "type": "module", 35 | "main": "lib/index.js", 36 | "scripts": { 37 | "test": "node --test" 38 | }, 39 | "dependencies": { 40 | "@mdn/browser-compat-data": "5.5.6", 41 | "browserslist": "^4.22.2", 42 | "eslint-plugin-es-x": "^7.5.0", 43 | "lodash": "^4.17.21" 44 | }, 45 | "devDependencies": { 46 | "eslint": "^8.56.0" 47 | }, 48 | "peerDependencies": { 49 | "eslint": ">=8" 50 | }, 51 | "engines": { 52 | "node": ">=16.0.0" 53 | } 54 | } 55 | --------------------------------------------------------------------------------