diff --git a/.nycrc b/.nycrc index b9d7b70b..27772eac 100644 --- a/.nycrc +++ b/.nycrc @@ -4,7 +4,6 @@ ], "exclude": [ "lib/rules/no-hide-core-modules.js", - "lib/rules/no-unsupported-features.js", "lib/converted-esm/*.js" ], "reporter": [ diff --git a/README.md b/README.md index 021ce524..60b4b531 100644 --- a/README.md +++ b/README.md @@ -133,7 +133,6 @@ For [Shareable Configs](https://eslint.org/docs/latest/developer-guide/shareable | [no-unpublished-bin](docs/rules/no-unpublished-bin.md) | disallow `bin` files that npm ignores | ☑️ 🟢 ✅ ☑️ 🟢 ✅ | | | | [no-unpublished-import](docs/rules/no-unpublished-import.md) | disallow `import` declarations which import private modules | ☑️ 🟢 ✅ ☑️ 🟢 ✅ | | | | [no-unpublished-require](docs/rules/no-unpublished-require.md) | disallow `require()` expressions which import private modules | ☑️ 🟢 ✅ ☑️ 🟢 ✅ | | | -| [no-unsupported-features](docs/rules/no-unsupported-features.md) | disallow unsupported ECMAScript features on the specified version | | | ❌ | | [no-unsupported-features/es-builtins](docs/rules/no-unsupported-features/es-builtins.md) | disallow unsupported ECMAScript built-ins on the specified version | ☑️ 🟢 ✅ ☑️ 🟢 ✅ | | | | [no-unsupported-features/es-syntax](docs/rules/no-unsupported-features/es-syntax.md) | disallow unsupported ECMAScript syntax on the specified version | ☑️ 🟢 ✅ ☑️ 🟢 ✅ | | | | [no-unsupported-features/node-builtins](docs/rules/no-unsupported-features/node-builtins.md) | disallow unsupported Node.js built-in APIs on the specified version | ☑️ 🟢 ✅ ☑️ 🟢 ✅ | | | diff --git a/docs/rules/no-unsupported-features.md b/docs/rules/no-unsupported-features.md deleted file mode 100644 index 69a62a27..00000000 --- a/docs/rules/no-unsupported-features.md +++ /dev/null @@ -1,308 +0,0 @@ -# Disallow unsupported ECMAScript features on the specified version (`n/no-unsupported-features`) - -❌ This rule is deprecated. It was replaced by [`n/no-unsupported-features/es-syntax`](no-unsupported-features/es-syntax.md),[`n/no-unsupported-features/es-builtins`](no-unsupported-features/es-builtins.md). - - - -Node.js doesn't support all ECMAScript standard features. -This rule reports when you used unsupported ECMAScript 2015-2018 features on the specified Node.js version. - -> ※ About ECMAScript 2018, this rule reports only features which have arrived at stage 4 until 2018-02-01. -> It needs a major version bump in order to cover newer features. - -## 📖 Rule Details - -⚠️ This rule expects to be used with the following configuration: - -```json -{ - "env": {"es6": true}, - "parserOptions": {"ecmaVersion": 2018} -} -``` - -⚠️ This rule reads the [engines] field of `package.json` to detect Node.js version. - -I recommend a use of the [engines] field since it's the official way to indicate what Node.js versions your module is supporting. -For example of `package.json`: - -```json -{ - "name": "your-module", - "version": "1.0.0", - "engines": { - "node": ">=6.0.0" - } -} -``` - -If the [engines] field is omitted, this rule chooses `4` since it's the minimum version the community is maintaining. - -Examples of 👎 **incorrect** code for this rule: - -```js -/*eslint n/no-unsupported-features: ["error", {version: 4}]*/ -/*eslint-env es6*/ - -function foo(a = 1) { /*error Default Parameters are not supported yet on Node v4.*/ - //... -} - -function foo(...a) { /*error Rest Parameters are not supported yet on Node v4.*/ - //... -} - -var a = [...b]; /*error Spread Operators are not supported yet on Node v4.*/ -var a = /foo/y; /*error RegExp 'y' Flags are not supported yet on Node v4.*/ -var a = /foo/u; /*error RegExp 'u' Flags are not supported yet on Node v4.*/ -var {a, b} = c; /*error Destructuring are not supported yet on Node v4.*/ -var {a, b} = c; /*error Destructuring are not supported yet on Node v4.*/ - -let a = 1; /*error 'let' Declarations in non-strict mode are not supported yet on Node v4.*/ -const a = 1; /*error 'const' Declarations in non-strict mode are not supported yet on Node v4.*/ -class A {} /*error Classes in non-strict mode are not supported yet on Node v4.*/ - -if (a) { - function foo() { /*error Block-Scoped Functions in non-strict mode are not supported yet on Node v4.*/ - //... - } -} - -var p = new Proxy(o, { /*error Proxy is not supported yet on Node v4.*/ - //... -}); -``` - -Examples of 👍 **correct** code for this rule: - -```js -/*eslint n/no-unsupported-features: ["error", {version: 4}]*/ -/*eslint-env es6*/ - -for (var a of list) { - //... -} - -var a = `hello, ${world}!`; - -function foo() { - "use strict"; - - let a = 1; - const b = 2; - - class A { - //... - } - - if (c) { - function bar() { - //... - } - } -} - -var p = new Promise((resolve, reject) => { - //... -}); -``` - -### Options - -```json -{ - "n/no-unsupported-features": ["error", { - "version": 4, - "ignores": [] - }] -} -``` - -#### version - -As mentioned above, this rule reads the [engines] field of `package.json` to detect Node.js version. -Also, you can overwrite the version by `version` option. -The `version` option accepts the following version number: - -- `0.10` -- `0.12` -- `4` -- `5` -- `6` -- `6.5` ... `Symbol.hasInstance` and `Symbol.species`. -- `7` ... Exponential operators, `Object.values`, `Object.entries`, and `Object.getOwnPropertyDescriptors`. -- `7.6` ... Async functions. -- `8` ... Trailing commas in functions. -- `8.3` ... Rest/Spread proeprties. -- `9.0` ... Illegal escape sequences in taggled templates, RegExp 's' flags, RegExp lookbehind assertions, `SharedArrayBuffer`, and `Atomics`. -- `10.0` ... RegExp named capture groups, RegExp Unicode property escapes, Async generators, and `for-await-of` loops. - -#### ignores - -If you are using transpilers, maybe you want to ignore the warnings about some features. -You can use this `ignores` option to ignore the given features. -The `"ignores"` option accepts an array of the following strings. - -- `"syntax"` (group) - - `"defaultParameters"` - - `"restParameters"` - - `"spreadOperators"` - - `"objectLiteralExtensions"` - - `"forOf"` - - `"binaryNumberLiterals"` - - `"octalNumberLiterals"` - - `"templateStrings"` - - `"regexpY"` - - `"regexpU"` - - `"destructuring"` - - `"unicodeCodePointEscapes"` - - `"new.target"` - - `"const"` - - `"let"` - - `"blockScopedFunctions"` - - `"arrowFunctions"` - - `"generatorFunctions"` - - `"classes"` - - `"modules"` - - `"exponentialOperators"` - - `"asyncAwait"` - - `"trailingCommasInFunctions"` - - `"templateLiteralRevision"` - - `"regexpS"` - - `"regexpNamedCaptureGroups"` - - `"regexpLookbehind"` - - `"regexpUnicodeProperties"` - - `"restProperties"` - - `"spreadProperties"` - - `"asyncGenerators"` - - `"forAwaitOf"` -- `"runtime"` (group) - - `"globalObjects"` (group) - - `"typedArrays"` (group) - - `"Int8Array"` - - `"Uint8Array"` - - `"Uint8ClampedArray"` - - `"Int16Array"` - - `"Uint16Array"` - - `"Int32Array"` - - `"Uint32Array"` - - `"Float32Array"` - - `"Float64Array"` - - `"DataView"` - - `"Map"` - - `"Set"` - - `"WeakMap"` - - `"WeakSet"` - - `"Proxy"` - - `"Reflect"` - - `"Promise"` - - `"Symbol"` - - `"SharedArrayBuffer"` - - `"Atomics"` - - `"staticMethods"` (group) - - `"Object.*"` (group) - - `"Object.assign"` - - `"Object.is"` - - `"Object.getOwnPropertySymbols"` - - `"Object.setPrototypeOf"` - - `"Object.values"` - - `"Object.entries"` - - `"Object.getOwnPropertyDescriptors"` - - `"String.*"` (group) - - `"String.raw"` - - `"String.fromCodePoint"` - - `"Array.*"` (group) - - `"Array.from"` - - `"Array.of"` - - `"Number.*"` (group) - - `"Number.isFinite"` - - `"Number.isInteger"` - - `"Number.isSafeInteger"` - - `"Number.isNaN"` - - `"Number.EPSILON"` - - `"Number.MIN_SAFE_INTEGER"` - - `"Number.MAX_SAFE_INTEGER"` - - `"Math.*"` (group) - - `"Math.clz32"` - - `"Math.imul"` - - `"Math.sign"` - - `"Math.log10"` - - `"Math.log2"` - - `"Math.log1p"` - - `"Math.expm1"` - - `"Math.cosh"` - - `"Math.sinh"` - - `"Math.tanh"` - - `"Math.acosh"` - - `"Math.asinh"` - - `"Math.atanh"` - - `"Math.trunc"` - - `"Math.fround"` - - `"Math.cbrt"` - - `"Math.hypot"` - - `"Symbol.*"` (group) - - `"Symbol.hasInstance"` - - `"Symbol.isConcatSpreadablec"` - - `"Symbol.iterator"` - - `"Symbol.species"` - - `"Symbol.replace"` - - `"Symbol.search"` - - `"Symbol.split"` - - `"Symbol.match"` - - `"Symbol.toPrimitive"` - - `"Symbol.toStringTag"` - - `"Symbol.unscopables"` - - `"Atomics.*"` (group) - - `"Atomics.add"` - - `"Atomics.and"` - - `"Atomics.compareExchange"` - - `"Atomics.exchange"` - - `"Atomics.wait"` - - `"Atomics.wake"` - - `"Atomics.isLockFree"` - - `"Atomics.load"` - - `"Atomics.or"` - - `"Atomics.store"` - - `"Atomics.sub"` - - `"Atomics.xor"` - - `"extends"` (group) - - `"extendsArray"` - - `"extendsRegExp"` - - `"extendsFunction"` - - `"extendsPromise"` - - `"extendsBoolean"` - - `"extendsNumber"` - - `"extendsString"` - - `"extendsMap"` - - `"extendsSet"` - - `"extendsNull"` - -If a group value is given, all sub items of the value are ignored. -e.g. if `"String.*"` is given then `"String.raw"` and `"String.fromCodePoint"` are ignored. - -Examples of 👍 **correct** code for the `"ignores"` option: - -```js -/*eslint n/no-unsupported-features: ["error", {version: 4, ignores: ["defaultParameters"]}]*/ -/*eslint-env es6*/ - -function foo(a = 1) { - //... -} -``` - -## ⚠️ Known Limitations - -This rule cannot report non-static things. -E.g., a use of instance methods. - -## 📚 Further Reading - -- - -[engines]: https://docs.npmjs.com/files/package.json#engines - -## 🔎 Implementation - -- [Rule source](../../lib/rules/no-unsupported-features.js) -- [Test source](../../tests/lib/rules/no-unsupported-features.js) diff --git a/lib/index.js b/lib/index.js index def1bbf6..23cd1937 100644 --- a/lib/index.js +++ b/lib/index.js @@ -46,7 +46,6 @@ const rules = { // Deprecated rules. "no-hide-core-modules": require("./rules/no-hide-core-modules"), - "no-unsupported-features": require("./rules/no-unsupported-features"), } const mod = { diff --git a/lib/rules/no-unsupported-features.js b/lib/rules/no-unsupported-features.js deleted file mode 100644 index 810945ef..00000000 --- a/lib/rules/no-unsupported-features.js +++ /dev/null @@ -1,1552 +0,0 @@ -/** - * @author Toru Nagashima - * See LICENSE file in root directory for full license. - */ -"use strict" - -const semver = require("semver") -const { - getInnermostScope, - getPropertyName, -} = require("@eslint-community/eslint-utils") -const getPackageJson = require("../util/get-package-json") - -const VERSION_MAP = new Map([ - [0.1, "0.10.0"], - [0.12, "0.12.0"], - [4, "4.0.0"], - [5, "5.0.0"], - [6, "6.0.0"], - [6.5, "6.5.0"], - [7, "7.0.0"], - [7.6, "7.6.0"], - [8, "8.0.0"], - [8.3, "8.3.0"], - [9, "9.0.0"], - [10, "10.0.0"], -]) -const VERSION_SCHEMA = { - anyOf: [ - { enum: Array.from(VERSION_MAP.keys()) }, - { - type: "string", - pattern: "^(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)$", - }, - ], -} -const DEFAULT_VERSION = "4.0.0" -const FUNC_TYPE = /^(?:Arrow)?Function(?:Declaration|Expression)$/u -const CLASS_TYPE = /^Class(?:Declaration|Expression)$/u -const DESTRUCTURING_PARENT_TYPE = - /^(?:Function(?:Declaration|Expression)|ArrowFunctionExpression|AssignmentExpression|VariableDeclarator)$/u -const TOPLEVEL_SCOPE_TYPE = /^(?:global|function|module)$/u -const BINARY_NUMBER = /^0[bB]/u -const OCTAL_NUMBER = /^0[oO]/u -const UNICODE_ESC = /(\\+)u\{[0-9a-fA-F]+?\}/gu -const GET_OR_SET = /^(?:g|s)et$/u -const NEW_BUILTIN_TYPES = [ - "Int8Array", - "Uint8Array", - "Uint8ClampedArray", - "Int16Array", - "Uint16Array", - "Int32Array", - "Uint32Array", - "Float32Array", - "Float64Array", - "DataView", - "Map", - "Set", - "WeakMap", - "WeakSet", - "Proxy", - "Reflect", - "Promise", - "Symbol", - "SharedArrayBuffer", - "Atomics", -] -const SUBCLASSING_TEST_TARGETS = [ - "Array", - "RegExp", - "Function", - "Promise", - "Boolean", - "Number", - "String", - "Map", - "Set", -] -const PROPERTY_TEST_TARGETS = { - Object: [ - "assign", - "is", - "getOwnPropertySymbols", - "setPrototypeOf", - "values", - "entries", - "getOwnPropertyDescriptors", - ], - String: ["raw", "fromCodePoint"], - Array: ["from", "of"], - Number: [ - "isFinite", - "isInteger", - "isSafeInteger", - "isNaN", - "EPSILON", - "MIN_SAFE_INTEGER", - "MAX_SAFE_INTEGER", - ], - Math: [ - "clz32", - "imul", - "sign", - "log10", - "log2", - "log1p", - "expm1", - "cosh", - "sinh", - "tanh", - "acosh", - "asinh", - "atanh", - "trunc", - "fround", - "cbrt", - "hypot", - ], - Symbol: [ - "hasInstance", - "isConcatSpreadablec", - "iterator", - "species", - "replace", - "search", - "split", - "match", - "toPrimitive", - "toStringTag", - "unscopables", - ], - Atomics: [ - "add", - "and", - "compareExchange", - "exchange", - "wait", - "wake", - "isLockFree", - "load", - "or", - "store", - "sub", - "xor", - ], -} -const REGEXP_NAMED_GROUP = /(\\*)\(\?<[_$\w]/u -const REGEXP_LOOKBEHIND = /(\\*)\(\?<[=!]/u -const REGEXP_UNICODE_PROPERTY = /(\\*)\\[pP]\{.+?\}/u -const FEATURES = { - defaultParameters: { - alias: ["syntax"], - name: "Default parameters", - node: "6.0.0", - }, - restParameters: { - alias: ["syntax"], - name: "Rest parameters", - node: "6.0.0", - }, - spreadOperators: { - alias: ["syntax"], - name: "Spread operators", - node: "5.0.0", - }, - objectLiteralExtensions: { - alias: ["syntax"], - name: "Object literal extensions", - node: "4.0.0", - }, - objectPropertyShorthandOfGetSet: { - alias: ["syntax", "objectLiteralExtensions"], - name: "Property shorthand of 'get' and 'set'", - node: "6.0.0", - }, - forOf: { - alias: ["syntax"], - name: "'for..of' loops", - node: "0.12.0", - }, - binaryNumberLiterals: { - alias: ["syntax"], - name: "Binary number literals", - node: "4.0.0", - }, - octalNumberLiterals: { - alias: ["syntax"], - name: "Octal number literals", - node: "4.0.0", - }, - templateStrings: { - alias: ["syntax"], - name: "Template strings", - node: "4.0.0", - }, - regexpY: { - alias: ["syntax"], - name: "RegExp 'y' flags", - node: "6.0.0", - }, - regexpU: { - alias: ["syntax"], - name: "RegExp 'u' flags", - node: "6.0.0", - }, - destructuring: { - alias: ["syntax"], - name: "Destructuring", - node: "6.0.0", - }, - unicodeCodePointEscapes: { - alias: ["syntax"], - name: "Unicode code point escapes", - node: "4.0.0", - }, - "new.target": { - alias: ["syntax"], - name: "'new.target'", - node: "5.0.0", - }, - const: { - alias: ["syntax"], - name: "'const' declarations", - node: { - sloppy: "6.0.0", - strict: "4.0.0", - }, - }, - let: { - alias: ["syntax"], - name: "'let' declarations", - node: { - sloppy: "6.0.0", - strict: "4.0.0", - }, - }, - blockScopedFunctions: { - alias: ["syntax"], - name: "Block-scoped functions", - node: { - sloppy: "6.0.0", - strict: "4.0.0", - }, - }, - arrowFunctions: { - alias: ["syntax"], - name: "Arrow functions", - node: "4.0.0", - }, - generatorFunctions: { - alias: ["syntax"], - name: "Generator functions", - node: "4.0.0", - }, - classes: { - alias: ["syntax"], - name: "Classes", - node: { - sloppy: "6.0.0", - strict: "4.0.0", - }, - }, - modules: { - alias: ["syntax"], - name: "Import and export declarations", - node: null, - }, - exponentialOperators: { - alias: ["syntax"], - name: "Exponential operators (**)", - node: "7.0.0", - }, - asyncAwait: { - alias: ["syntax"], - name: "Async functions", - node: "7.6.0", - }, - trailingCommasInFunctions: { - alias: ["syntax"], - name: "Trailing commas in functions", - node: "8.0.0", - }, - //------------------------------------------ - templateLiteralRevision: { - alias: ["syntax"], - name: "Illegal escape sequences in taggled templates", - node: "9.0.0", - }, - regexpS: { - alias: ["syntax"], - name: "RegExp 's' flags", - node: "9.0.0", - }, - regexpNamedCaptureGroups: { - alias: ["syntax"], - name: "RegExp named capture groups", - node: "10.0.0", - }, - regexpLookbehind: { - alias: ["syntax"], - name: "RegExp lookbehind assertions", - node: "9.0.0", - }, - regexpUnicodeProperties: { - alias: ["syntax"], - name: "RegExp Unicode property escapes", - node: "10.0.0", - }, - restProperties: { - alias: ["syntax"], - name: "Rest properties", - node: "8.3.0", - }, - spreadProperties: { - alias: ["syntax"], - name: "Spread properties", - node: "8.3.0", - }, - asyncGenerators: { - alias: ["syntax"], - name: "Async generators", - node: "10.0.0", - }, - forAwaitOf: { - alias: ["syntax"], - name: "for-await-of loops", - node: "10.0.0", - }, - - Int8Array: { - alias: ["runtime", "globalObjects", "typedArrays"], - name: "'Int8Array'", - singular: true, - node: "0.12.0", - }, - Uint8Array: { - alias: ["runtime", "globalObjects", "typedArrays"], - name: "'Uint8Array'", - singular: true, - node: "0.12.0", - }, - Uint8ClampedArray: { - alias: ["runtime", "globalObjects", "typedArrays"], - name: "'Uint8ClampedArray'", - singular: true, - node: "0.12.0", - }, - Int16Array: { - alias: ["runtime", "globalObjects", "typedArrays"], - name: "'Int16Array'", - singular: true, - node: "0.12.0", - }, - Uint16Array: { - alias: ["runtime", "globalObjects", "typedArrays"], - name: "'Uint16Array'", - singular: true, - node: "0.12.0", - }, - Int32Array: { - alias: ["runtime", "globalObjects", "typedArrays"], - name: "'Int32Array'", - singular: true, - node: "0.12.0", - }, - Uint32Array: { - alias: ["runtime", "globalObjects", "typedArrays"], - name: "'Uint32Array'", - singular: true, - node: "0.12.0", - }, - Float32Array: { - alias: ["runtime", "globalObjects", "typedArrays"], - name: "'Float32Array'", - singular: true, - node: "0.12.0", - }, - Float64Array: { - alias: ["runtime", "globalObjects", "typedArrays"], - name: "'Float64Array'", - singular: true, - node: "0.12.0", - }, - DataView: { - alias: ["runtime", "globalObjects", "typedArrays"], - name: "'DataView'", - singular: true, - node: "0.12.0", - }, - Map: { - alias: ["runtime", "globalObjects"], - name: "'Map'", - singular: true, - node: "0.12.0", - }, - Set: { - alias: ["runtime", "globalObjects"], - name: "'Set'", - singular: true, - node: "0.12.0", - }, - WeakMap: { - alias: ["runtime", "globalObjects"], - name: "'WeakMap'", - singular: true, - node: "0.12.0", - }, - WeakSet: { - alias: ["runtime", "globalObjects"], - name: "'WeakSet'", - singular: true, - node: "0.12.0", - }, - Proxy: { - alias: ["runtime", "globalObjects"], - name: "'Proxy'", - singular: true, - node: "6.0.0", - }, - Reflect: { - alias: ["runtime", "globalObjects"], - name: "'Reflect'", - singular: true, - node: "6.0.0", - }, - Promise: { - alias: ["runtime", "globalObjects"], - name: "'Promise'", - singular: true, - node: "0.12.0", - }, - Symbol: { - alias: ["runtime", "globalObjects"], - name: "'Symbol'", - singular: true, - node: "0.12.0", - }, - SharedArrayBuffer: { - alias: ["runtime", "globalObjects"], - name: "'SharedArrayBuffer'", - singular: true, - node: "9.0.0", - }, - Atomics: { - alias: ["runtime", "globalObjects"], - name: "'Atomics'", - singular: true, - node: "9.0.0", - }, - - "Object.assign": { - alias: ["runtime", "staticMethods", "Object.*"], - name: "'Object.assign'", - singular: true, - node: "4.0.0", - }, - "Object.is": { - alias: ["runtime", "staticMethods", "Object.*"], - name: "'Object.is'", - singular: true, - node: "0.12.0", - }, - "Object.getOwnPropertySymbols": { - alias: ["runtime", "staticMethods", "Object.*"], - name: "'Object.getOwnPropertySymbols'", - singular: true, - node: "0.12.0", - }, - "Object.setPrototypeOf": { - alias: ["runtime", "staticMethods", "Object.*"], - name: "'Object.setPrototypeOf'", - singular: true, - node: "0.12.0", - }, - "Object.values": { - alias: ["runtime", "staticMethods", "Object.*"], - name: "'Object.values'", - singular: true, - node: "7.0.0", - }, - "Object.entries": { - alias: ["runtime", "staticMethods", "Object.*"], - name: "'Object.entries'", - singular: true, - node: "7.0.0", - }, - "Object.getOwnPropertyDescriptors": { - alias: ["runtime", "staticMethods", "Object.*"], - name: "'Object.getOwnPropertyDescriptors'", - singular: true, - node: "7.0.0", - }, - - "String.raw": { - alias: ["runtime", "staticMethods", "String.*"], - name: "'String.raw'", - singular: true, - node: "4.0.0", - }, - "String.fromCodePoint": { - alias: ["runtime", "staticMethods", "String.*"], - name: "'String.fromCodePoint'", - singular: true, - node: "4.0.0", - }, - - "Array.from": { - alias: ["runtime", "staticMethods", "Array.*"], - name: "'Array.from'", - singular: true, - node: "4.0.0", - }, - "Array.of": { - alias: ["runtime", "staticMethods", "Array.*"], - name: "'Array.of'", - singular: true, - node: "4.0.0", - }, - - "Number.isFinite": { - alias: ["runtime", "staticMethods", "Number.*"], - name: "'Number.isFinite'", - singular: true, - node: "0.10.0", - }, - "Number.isInteger": { - alias: ["runtime", "staticMethods", "Number.*"], - name: "'Number.isInteger'", - singular: true, - node: "0.12.0", - }, - "Number.isSafeInteger": { - alias: ["runtime", "staticMethods", "Number.*"], - name: "'Number.isSafeInteger'", - singular: true, - node: "0.12.0", - }, - "Number.isNaN": { - alias: ["runtime", "staticMethods", "Number.*"], - name: "'Number.isNaN'", - singular: true, - node: "0.10.0", - }, - "Number.EPSILON": { - alias: ["runtime", "staticMethods", "Number.*"], - name: "'Number.EPSILON'", - singular: true, - node: "0.12.0", - }, - "Number.MIN_SAFE_INTEGER": { - alias: ["runtime", "staticMethods", "Number.*"], - name: "'Number.MIN_SAFE_INTEGER'", - singular: true, - node: "0.12.0", - }, - "Number.MAX_SAFE_INTEGER": { - alias: ["runtime", "staticMethods", "Number.*"], - name: "'Number.MAX_SAFE_INTEGER'", - singular: true, - node: "0.12.0", - }, - - "Math.clz32": { - alias: ["runtime", "staticMethods", "Math.*"], - name: "'Math.clz32'", - singular: true, - node: "0.12.0", - }, - "Math.imul": { - alias: ["runtime", "staticMethods", "Math.*"], - name: "'Math.imul'", - singular: true, - node: "0.12.0", - }, - "Math.sign": { - alias: ["runtime", "staticMethods", "Math.*"], - name: "'Math.sign'", - singular: true, - node: "0.12.0", - }, - "Math.log10": { - alias: ["runtime", "staticMethods", "Math.*"], - name: "'Math.log10'", - singular: true, - node: "0.12.0", - }, - "Math.log2": { - alias: ["runtime", "staticMethods", "Math.*"], - name: "'Math.log2'", - singular: true, - node: "0.12.0", - }, - "Math.log1p": { - alias: ["runtime", "staticMethods", "Math.*"], - name: "'Math.log1p'", - singular: true, - node: "0.12.0", - }, - "Math.expm1": { - alias: ["runtime", "staticMethods", "Math.*"], - name: "'Math.expm1'", - singular: true, - node: "0.12.0", - }, - "Math.cosh": { - alias: ["runtime", "staticMethods", "Math.*"], - name: "'Math.cosh'", - singular: true, - node: "0.12.0", - }, - "Math.sinh": { - alias: ["runtime", "staticMethods", "Math.*"], - name: "'Math.sinh'", - singular: true, - node: "0.12.0", - }, - "Math.tanh": { - alias: ["runtime", "staticMethods", "Math.*"], - name: "'Math.tanh'", - singular: true, - node: "0.12.0", - }, - "Math.acosh": { - alias: ["runtime", "staticMethods", "Math.*"], - name: "'Math.acosh'", - singular: true, - node: "0.12.0", - }, - "Math.asinh": { - alias: ["runtime", "staticMethods", "Math.*"], - name: "'Math.asinh'", - singular: true, - node: "0.12.0", - }, - "Math.atanh": { - alias: ["runtime", "staticMethods", "Math.*"], - name: "'Math.atanh'", - singular: true, - node: "0.12.0", - }, - "Math.trunc": { - alias: ["runtime", "staticMethods", "Math.*"], - name: "'Math.trunc'", - singular: true, - node: "0.12.0", - }, - "Math.fround": { - alias: ["runtime", "staticMethods", "Math.*"], - name: "'Math.fround'", - singular: true, - node: "0.12.0", - }, - "Math.cbrt": { - alias: ["runtime", "staticMethods", "Math.*"], - name: "'Math.cbrt'", - singular: true, - node: "0.12.0", - }, - "Math.hypot": { - alias: ["runtime", "staticMethods", "Math.*"], - name: "'Math.hypot'", - singular: true, - node: "0.12.0", - }, - - "Symbol.hasInstance": { - alias: ["runtime", "staticMethods", "Symbol.*"], - name: "'Symbol.hasInstance'", - singular: true, - node: "6.5.0", - }, - "Symbol.isConcatSpreadablec": { - alias: ["runtime", "staticMethods", "Symbol.*"], - name: "'Symbol.isConcatSpreadablec'", - singular: true, - node: "6.0.0", - }, - "Symbol.iterator": { - alias: ["runtime", "staticMethods", "Symbol.*"], - name: "'Symbol.iterator'", - singular: true, - node: "0.12.0", - }, - "Symbol.species": { - alias: ["runtime", "staticMethods", "Symbol.*"], - name: "'Symbol.species'", - singular: true, - node: "6.5.0", - }, - "Symbol.replace": { - alias: ["runtime", "staticMethods", "Symbol.*"], - name: "'Symbol.replace'", - singular: true, - node: "6.0.0", - }, - "Symbol.search": { - alias: ["runtime", "staticMethods", "Symbol.*"], - name: "'Symbol.search'", - singular: true, - node: "6.0.0", - }, - "Symbol.split": { - alias: ["runtime", "staticMethods", "Symbol.*"], - name: "'Symbol.split'", - singular: true, - node: "6.0.0", - }, - "Symbol.match": { - alias: ["runtime", "staticMethods", "Symbol.*"], - name: "'Symbol.match'", - singular: true, - node: "6.0.0", - }, - "Symbol.toPrimitive": { - alias: ["runtime", "staticMethods", "Symbol.*"], - name: "'Symbol.toPrimitive'", - singular: true, - node: "6.0.0", - }, - "Symbol.toStringTag": { - alias: ["runtime", "staticMethods", "Symbol.*"], - name: "'Symbol.toStringTag'", - singular: true, - node: "6.0.0", - }, - "Symbol.unscopables": { - alias: ["runtime", "staticMethods", "Symbol.*"], - name: "'Symbol.unscopables'", - singular: true, - node: "4.0.0", - }, - - "Atomics.add": { - alias: ["runtime", "staticMethods", "Atomics.*"], - name: "'Atomics.add'", - singular: true, - node: "9.0.0", - }, - "Atomics.and": { - alias: ["runtime", "staticMethods", "Atomics.*"], - name: "'Atomics.and'", - singular: true, - node: "9.0.0", - }, - "Atomics.compareExchange": { - alias: ["runtime", "staticMethods", "Atomics.*"], - name: "'Atomics.compareExchange'", - singular: true, - node: "9.0.0", - }, - "Atomics.exchange": { - alias: ["runtime", "staticMethods", "Atomics.*"], - name: "'Atomics.exchange'", - singular: true, - node: "9.0.0", - }, - "Atomics.wait": { - alias: ["runtime", "staticMethods", "Atomics.*"], - name: "'Atomics.wait'", - singular: true, - node: "9.0.0", - }, - "Atomics.wake": { - alias: ["runtime", "staticMethods", "Atomics.*"], - name: "'Atomics.wake'", - singular: true, - node: "9.0.0", - }, - "Atomics.isLockFree": { - alias: ["runtime", "staticMethods", "Atomics.*"], - name: "'Atomics.isLockFree'", - singular: true, - node: "9.0.0", - }, - "Atomics.load": { - alias: ["runtime", "staticMethods", "Atomics.*"], - name: "'Atomics.load'", - singular: true, - node: "9.0.0", - }, - "Atomics.or": { - alias: ["runtime", "staticMethods", "Atomics.*"], - name: "'Atomics.or'", - singular: true, - node: "9.0.0", - }, - "Atomics.store": { - alias: ["runtime", "staticMethods", "Atomics.*"], - name: "'Atomics.store'", - singular: true, - node: "9.0.0", - }, - "Atomics.sub": { - alias: ["runtime", "staticMethods", "Atomics.*"], - name: "'Atomics.sub'", - singular: true, - node: "9.0.0", - }, - "Atomics.xor": { - alias: ["runtime", "staticMethods", "Atomics.*"], - name: "'Atomics.xor'", - singular: true, - node: "9.0.0", - }, - - extendsArray: { - alias: ["runtime", "extends"], - name: "Subclassing of 'Array'", - singular: true, - node: "6.0.0", - }, - extendsRegExp: { - alias: ["runtime", "extends"], - name: "Subclassing of 'RegExp'", - singular: true, - node: "5.0.0", - }, - extendsFunction: { - alias: ["runtime", "extends"], - name: "Subclassing of 'Function'", - singular: true, - node: "6.0.0", - }, - extendsPromise: { - alias: ["runtime", "extends"], - name: "Subclassing of 'Promise'", - singular: true, - node: "5.0.0", - }, - extendsBoolean: { - alias: ["runtime", "extends"], - name: "Subclassing of 'Boolean'", - singular: true, - node: "4.0.0", - }, - extendsNumber: { - alias: ["runtime", "extends"], - name: "Subclassing of 'Number'", - singular: true, - node: "4.0.0", - }, - extendsString: { - alias: ["runtime", "extends"], - name: "Subclassing of 'String'", - singular: true, - node: "4.0.0", - }, - extendsMap: { - alias: ["runtime", "extends"], - name: "Subclassing of 'Map'", - singular: true, - node: "4.0.0", - }, - extendsSet: { - alias: ["runtime", "extends"], - name: "Subclassing of 'Set'", - singular: true, - node: "4.0.0", - }, - extendsNull: { - alias: ["runtime", "extends"], - name: "'extends null'", - singular: true, - node: null, - }, -} -const OPTIONS = Object.keys(FEATURES) - -/** - * Gets default version configuration of this rule. - * - * This finds and reads 'package.json' file, then parses 'engines.node' field. - * If it's nothing, this returns null. - * - * @param {string} filename - The file name of the current linting file. - * @returns {string} The default version configuration. - */ -function getDefaultVersion(filename) { - const info = getPackageJson(filename) - const nodeVersion = info && info.engines && info.engines.node - - return semver.validRange(nodeVersion) || DEFAULT_VERSION -} - -/** - * Gets values of the `ignores` option. - * - * @returns {string[]} Values of the `ignores` option. - */ -function getIgnoresEnum() { - return Object.keys( - OPTIONS.reduce((retv, key) => { - for (const alias of FEATURES[key].alias) { - retv[alias] = true - } - retv[key] = true - return retv - }, Object.create(null)) - ) -} - -/** - * Checks whether a given key should be ignored or not. - * - * @param {string} key - A key to check. - * @param {string[]} ignores - An array of keys and aliases to be ignored. - * @returns {boolean} `true` if the key should be ignored. - */ -function isIgnored(key, ignores) { - return ( - ignores.indexOf(key) !== -1 || - FEATURES[key].alias.some(alias => ignores.indexOf(alias) !== -1) - ) -} - -/** - * Parses the options. - * - * @param {number|string|object|undefined} options - An option object to parse. - * @param {number} defaultVersion - The default version to use if the version option was omitted. - * @returns {object} Parsed value. - */ -function parseOptions(options, defaultVersion) { - let version = null - let range = null - let ignores = [] - - if (typeof options === "number") { - version = VERSION_MAP.get(options) - } else if (typeof options === "string") { - version = options - } else if (typeof options === "object") { - version = - typeof options.version === "number" - ? VERSION_MAP.get(options.version) - : options.version - - ignores = options.ignores || [] - } - - range = semver.validRange(version ? `>=${version}` : defaultVersion) - if (!version) { - version = defaultVersion - } - - return Object.freeze({ - version, - features: Object.freeze( - OPTIONS.reduce((retv, key) => { - const feature = FEATURES[key] - - if (isIgnored(key, ignores)) { - retv[key] = Object.freeze({ - name: feature.name, - singular: Boolean(feature.singular), - supported: true, - supportedInStrict: true, - }) - } else if (typeof feature.node === "string") { - retv[key] = Object.freeze({ - name: feature.name, - singular: Boolean(feature.singular), - supported: !semver.intersects( - range, - `<${feature.node}` - ), - supportedInStrict: !semver.intersects( - range, - `<${feature.node}` - ), - }) - } else { - retv[key] = Object.freeze({ - name: feature.name, - singular: Boolean(feature.singular), - supported: - feature.node != null && - feature.node.sloppy != null && - !semver.intersects( - range, - `<${feature.node.sloppy}` - ), - supportedInStrict: - feature.node != null && - feature.node.strict != null && - !semver.intersects( - range, - `<${feature.node.strict}` - ), - }) - } - - return retv - }, Object.create(null)) - ), - }) -} - -/** - * Find the scope that a given node belongs to. - * @param {Scope} initialScope The initial scope to find. - * @param {Node} node The AST node. - * @returns {Scope} The scope that the node belongs to. - */ -function normalizeScope(initialScope, node) { - let scope = getInnermostScope(initialScope, node) - - while (scope && scope.block === node) { - scope = scope.upper - } - - return scope -} - -/** - * Checks whether the given string has `\u{90ABCDEF}`-like escapes. - * - * @param {string} raw - The string to check. - * @returns {boolean} `true` if the string has Unicode code point escapes. - */ -function hasUnicodeCodePointEscape(raw) { - let match = null - - UNICODE_ESC.lastIndex = 0 - while ((match = UNICODE_ESC.exec(raw)) != null) { - if (match[1].length % 2 === 1) { - return true - } - } - - return false -} - -/** - * Check a given string has a given pattern. - * @param {string} s A string to check. - * @param {RegExp} pattern A RegExp object to check. - * @returns {boolean} `true` if the string has the pattern. - */ -function hasPattern(s, pattern) { - const m = pattern.exec(s) - return m != null && (m[1] || "").length % 2 === 0 -} - -module.exports = { - meta: { - docs: { - description: - "disallow unsupported ECMAScript features on the specified version", - recommended: false, - - url: "https://github.com/eslint-community/eslint-plugin-n/blob/HEAD/docs/rules/no-unsupported-features.md", - }, - type: "problem", - deprecated: true, - replacedBy: [ - "n/no-unsupported-features/es-syntax", - "n/no-unsupported-features/es-builtins", - ], - fixable: null, - schema: [ - { - anyOf: [ - VERSION_SCHEMA.anyOf[0], - VERSION_SCHEMA.anyOf[1], - { - type: "object", - properties: { - version: VERSION_SCHEMA, - ignores: { - type: "array", - items: { enum: getIgnoresEnum() }, - uniqueItems: true, - }, - }, - additionalProperties: false, - }, - ], - }, - ], - messages: { - unsupported: - "{{feature}} {{be}} not supported yet on Node {{version}}.", - }, - }, - create(context) { - const sourceCode = context.sourceCode ?? context.getSourceCode() // TODO: just use context.sourceCode when dropping eslint < v9 - const supportInfo = parseOptions( - context.options[0], - getDefaultVersion(context.filename ?? context.getFilename()) - ) - - /** - * Gets the references of the specified global variables. - * - * @param {string[]} names - Variable names to get. - * @returns {void} - */ - function* getReferences(names) { - const globalScope = - sourceCode.getScope?.(sourceCode.ast) ?? context.getScope() //TODO: remove context.getScope() when dropping support for ESLint < v9 - - for (const name of names) { - const variable = globalScope.set.get(name) - - if (variable && variable.defs.length === 0) { - yield* variable.references - } - } - } - - /** - * Checks whether the given function has trailing commas or not. - * - * @param {ASTNode} node - The function node to check. - * @returns {boolean} `true` if the function has trailing commas. - */ - function hasTrailingCommaForFunction(node) { - const length = node.params.length - - return ( - length >= 1 && - sourceCode.getTokenAfter(node.params[length - 1]).value === "," - ) - } - - /** - * Checks whether the given call expression has trailing commas or not. - * - * @param {ASTNode} node - The call expression node to check. - * @returns {boolean} `true` if the call expression has trailing commas. - */ - function hasTrailingCommaForCall(node) { - return ( - node.arguments.length >= 1 && - sourceCode.getLastToken(node, 1).value === "," - ) - } - - /** - * Checks whether the given class extends from null or not. - * - * @param {ASTNode} node - The class node to check. - * @returns {boolean} `true` if the class extends from null. - */ - function extendsNull(node) { - return ( - node.superClass != null && - node.superClass.type === "Literal" && - node.superClass.value === null - ) - } - - /** - * Reports a given node if the specified feature is not supported. - * - * @param {ASTNode} node - A node to be reported. - * @param {string} key - A feature name to report. - * @returns {void} - */ - function report(node, key) { - const globalScope = - sourceCode.getScope?.(node) ?? context.getScope() //TODO: remove context.getScope() when dropping support for ESLint < v9 - const version = supportInfo.version - const feature = supportInfo.features[key] - if (feature.supported) { - return - } - - if (!feature.supportedInStrict) { - context.report({ - node, - messageId: "unsupported", - data: { - feature: feature.name, - be: feature.singular ? "is" : "are", - version, - }, - }) - } else if (!normalizeScope(globalScope, node).isStrict) { - context.report({ - node, - messageId: "unsupported", - data: { - feature: `${feature.name} in non-strict mode`, - be: feature.singular ? "is" : "are", - version, - }, - }) - } - } - - /** - * Validate RegExp syntax. - * @param {string} pattern A RegExp pattern to check. - * @param {string} flags A RegExp flags to check. - * @param {ASTNode} node A node to report. - * @returns {void} - */ - function validateRegExp(pattern, flags, node) { - if (typeof pattern === "string") { - if (hasPattern(pattern, REGEXP_NAMED_GROUP)) { - report(node, "regexpNamedCaptureGroups") - } - if (hasPattern(pattern, REGEXP_LOOKBEHIND)) { - report(node, "regexpLookbehind") - } - if (hasPattern(pattern, REGEXP_UNICODE_PROPERTY)) { - report(node, "regexpUnicodeProperties") - } - } - if (typeof flags === "string") { - if (flags.indexOf("y") !== -1) { - report(node, "regexpY") - } - if (flags.indexOf("u") !== -1) { - report(node, "regexpU") - } - if (flags.indexOf("s") !== -1) { - report(node, "regexpS") - } - } - } - - /** - * Validate RegExp syntax in a RegExp literal. - * @param {ASTNode} node A Literal node to check. - * @returns {void} - */ - function validateRegExpLiteral(node) { - validateRegExp(node.regex.pattern, node.regex.flags, node) - } - - /** - * Validate RegExp syntax in the first argument of `new RegExp()`. - * @param {ASTNode} node A NewExpression node to check. - * @returns {void} - */ - function validateRegExpString(node) { - const patternNode = node.arguments[0] - const flagsNode = node.arguments[1] - const pattern = - patternNode && - patternNode.type === "Literal" && - typeof patternNode.value === "string" - ? patternNode.value - : null - const flags = - flagsNode && - flagsNode.type === "Literal" && - typeof flagsNode.value === "string" - ? flagsNode.value - : null - validateRegExp(pattern, flags, node) - } - - return { - "Program:exit"() { - // Check new global variables. - for (const name of NEW_BUILTIN_TYPES) { - for (const reference of getReferences([name])) { - // Ignore if it's using new static methods. - const node = reference.identifier - const parentNode = node.parent - const properties = PROPERTY_TEST_TARGETS[name] - if ( - properties && - parentNode.type === "MemberExpression" - ) { - const propertyName = getPropertyName(parentNode) - if (properties.indexOf(propertyName) !== -1) { - continue - } - } - - report(reference.identifier, name) - } - } - - // Check static methods. - for (const reference of getReferences( - Object.keys(PROPERTY_TEST_TARGETS) - )) { - const node = reference.identifier - const parentNode = node.parent - if ( - parentNode.type !== "MemberExpression" || - parentNode.object !== node - ) { - continue - } - - const objectName = node.name - const properties = PROPERTY_TEST_TARGETS[objectName] - const propertyName = getPropertyName(parentNode) - if ( - propertyName && - properties.indexOf(propertyName) !== -1 - ) { - report(parentNode, `${objectName}.${propertyName}`) - } - } - - // Check subclassing - for (const reference of getReferences( - SUBCLASSING_TEST_TARGETS - )) { - const node = reference.identifier - const parentNode = node.parent - if ( - CLASS_TYPE.test(parentNode.type) && - parentNode.superClass === node - ) { - report(node, `extends${node.name}`) - } - } - }, - - ArrowFunctionExpression(node) { - report(node, "arrowFunctions") - if (node.async) { - report(node, "asyncAwait") - } - if (hasTrailingCommaForFunction(node)) { - report(node, "trailingCommasInFunctions") - } - }, - - AssignmentPattern(node) { - if (FUNC_TYPE.test(node.parent.type)) { - report(node, "defaultParameters") - } - }, - - FunctionDeclaration(node) { - const scope = ( - sourceCode.getScope?.(node) ?? context.getScope() - ).upper //TODO: remove context.getScope() when dropping support for ESLint < v9 - if (!TOPLEVEL_SCOPE_TYPE.test(scope.type)) { - report(node, "blockScopedFunctions") - } - if (node.generator) { - report(node, "generatorFunctions") - } - if (node.async) { - report(node, "asyncAwait") - } - if (hasTrailingCommaForFunction(node)) { - report(node, "trailingCommasInFunctions") - } - if (node.async && node.generator) { - report(node, "asyncGenerators") - } - }, - - FunctionExpression(node) { - if (node.generator) { - report(node, "generatorFunctions") - } - if (node.async) { - report(node, "asyncAwait") - } - if (hasTrailingCommaForFunction(node)) { - report(node, "trailingCommasInFunctions") - } - if (node.async && node.generator) { - report(node, "asyncGenerators") - } - }, - - MetaProperty(node) { - const meta = node.meta.name || node.meta - const property = node.property.name || node.property - if (meta === "new" && property === "target") { - report(node, "new.target") - } - }, - - ClassDeclaration(node) { - report(node, "classes") - - if (extendsNull(node)) { - report(node, "extendsNull") - } - }, - - ClassExpression(node) { - report(node, "classes") - - if (extendsNull(node)) { - report(node, "extendsNull") - } - }, - - ForOfStatement(node) { - report(node, "forOf") - if (node.await) { - report(node, "forAwaitOf") - } - }, - - VariableDeclaration(node) { - if (node.kind === "const") { - report(node, "const") - } else if (node.kind === "let") { - report(node, "let") - } - }, - - ArrayPattern(node) { - if (DESTRUCTURING_PARENT_TYPE.test(node.parent.type)) { - report(node, "destructuring") - } - }, - - AssignmentExpression(node) { - if (node.operator === "**=") { - report(node, "exponentialOperators") - } - }, - - AwaitExpression(node) { - report(node, "asyncAwait") - }, - - BinaryExpression(node) { - if (node.operator === "**") { - report(node, "exponentialOperators") - } - }, - - CallExpression(node) { - if (hasTrailingCommaForCall(node)) { - report(node, "trailingCommasInFunctions") - } - }, - - Identifier(node) { - const raw = sourceCode.getText(node) - if (hasUnicodeCodePointEscape(raw)) { - report(node, "unicodeCodePointEscapes") - } - }, - - Literal(node) { - if (typeof node.value === "number") { - if (BINARY_NUMBER.test(node.raw)) { - report(node, "binaryNumberLiterals") - } else if (OCTAL_NUMBER.test(node.raw)) { - report(node, "octalNumberLiterals") - } - } else if (typeof node.value === "string") { - if (hasUnicodeCodePointEscape(node.raw)) { - report(node, "unicodeCodePointEscapes") - } - } else if (node.regex) { - validateRegExpLiteral(node) - } - }, - - NewExpression(node) { - if ( - node.callee.type === "Identifier" && - node.callee.name === "RegExp" - ) { - validateRegExpString(node) - } - if (hasTrailingCommaForCall(node)) { - report(node, "trailingCommasInFunctions") - } - }, - - ObjectPattern(node) { - if (DESTRUCTURING_PARENT_TYPE.test(node.parent.type)) { - report(node, "destructuring") - } - }, - - Property(node) { - if ( - node.parent.type === "ObjectExpression" && - (node.computed || node.shorthand || node.method) - ) { - if (node.shorthand && GET_OR_SET.test(node.key.name)) { - report(node, "objectPropertyShorthandOfGetSet") - } else { - report(node, "objectLiteralExtensions") - } - } - }, - - RestElement(node) { - if (FUNC_TYPE.test(node.parent.type)) { - report(node, "restParameters") - } else if (node.parent.type === "ObjectPattern") { - report(node, "restProperties") - } - }, - - SpreadElement(node) { - if (node.parent.type === "ObjectExpression") { - report(node, "spreadProperties") - } else { - report(node, "spreadOperators") - } - }, - - TemplateElement(node) { - if (node.value.cooked == null) { - report(node, "templateLiteralRevision") - } - }, - - TemplateLiteral(node) { - report(node, "templateStrings") - }, - - ExperimentalRestProperty(node) { - report(node, "restProperties") - }, - - ExperimentalSpreadProperty(node) { - report(node, "spreadProperties") - }, - - RestProperty(node) { - report(node, "restProperties") - }, - - SpreadProperty(node) { - report(node, "spreadProperties") - }, - - ExportAllDeclaration(node) { - report(node, "modules") - }, - - ExportDefaultDeclaration(node) { - report(node, "modules") - }, - - ExportNamedDeclaration(node) { - report(node, "modules") - }, - - ImportDeclaration(node) { - report(node, "modules") - }, - } - }, -} diff --git a/tests/lib/rules/no-unsupported-features.js b/tests/lib/rules/no-unsupported-features.js deleted file mode 100644 index 8351e7f9..00000000 --- a/tests/lib/rules/no-unsupported-features.js +++ /dev/null @@ -1,1395 +0,0 @@ -/** - * @author Toru Nagashima - * See LICENSE file in root directory for full license. - */ -"use strict" - -const path = require("path") -const RuleTester = require("#eslint-rule-tester").RuleTester -const rule = require("../../../lib/rules/no-unsupported-features") - -const VERSION_MAP = new Map([ - [0.1, "0.10.0"], - [0.12, "0.12.0"], - [4, "4.0.0"], - [5, "5.0.0"], - [6, "6.0.0"], - [6.5, "6.5.0"], - [7, "7.0.0"], - [7.6, "7.6.0"], - [8, "8.0.0"], - [8.3, "8.3.0"], - [9, "9.0.0"], - [10, "10.0.0"], -]) - -/** - * Creates test pattern. - * - * @param {{valid: object[], invalid: object[]}} retv - Actual test patterns. - * @param {object} pattern - Original test pattern. - * @returns {{valid: object[], invalid: object[]}} retv. - */ -function convertPattern(retv, pattern) { - let i = 0 - - // If this test is on script mode, it should do this test on module mode as well. - if ( - !pattern.modules && - pattern.code.indexOf("'use strict'") !== 0 && - pattern.name.indexOf("non-strict") === -1 - ) { - convertPattern( - retv, - Object.create(pattern, { modules: { value: true } }) - ) - } - - // Creates error messages. - const errors = [] - for (i = 0; i < pattern.errors; ++i) { - errors.push( - `${pattern.name} ${ - pattern.singular ? "is" : "are" - } not supported yet on Node ` - ) - } - - // Creates each pattern of Node versions. - for (const version of VERSION_MAP.keys()) { - const versionText = VERSION_MAP.get(version) - - // Skips if ignored - if (pattern.ignores && pattern.ignores.indexOf(version) !== -1) { - continue - } - - if (version >= pattern.supported) { - // If this is supported, add to a valid pattern. - retv.valid.push({ - code: `/*${pattern.name}: ${versionText}*/ ${pattern.code}`, - options: [version], - languageOptions: { - ecmaVersion: 2018, - sourceType: pattern.modules ? "module" : "script", - globals: { SharedArrayBuffer: false, Atomics: false }, - }, - }) - } else { - // If this is not supported, add to a valid pattern with a "ignores" option. - ;[].push.apply( - retv.valid, - pattern.keys.map(key => ({ - code: `/*${pattern.name}: ${versionText}, ignores: ["${key}"]*/ ${pattern.code}`, - options: [{ version, ignores: [key] }], - languageOptions: { - ecmaVersion: 2018, - sourceType: pattern.modules ? "module" : "script", - globals: { SharedArrayBuffer: false, Atomics: false }, - }, - })) - ) - - // If this is not supported, add to a invalid pattern. - retv.invalid.push({ - code: `/*${pattern.name}: ${versionText}*/ ${pattern.code}`, - options: [version], - languageOptions: { - ecmaVersion: 2018, - sourceType: pattern.modules ? "module" : "script", - globals: { SharedArrayBuffer: false, Atomics: false }, - }, - errors: errors.map(message => `${message + versionText}.`), - }) - } - } - - return retv -} - -/** - * Makes a file path to a fixture. - * @param {string} name - A name. - * @returns {string} A file path to a fixture. - */ -function fixture(name) { - return path.resolve( - __dirname, - "../../fixtures/no-unsupported-features", - name - ) -} - -const ruleTester = new RuleTester() -ruleTester.run( - "no-unsupported-features", - rule, - [ - { - keys: ["defaultParameters", "syntax"], - name: "Default parameters", - code: "function foo(a = 1) {} ;(function(a = 1) {})()", - errors: 2, - supported: 6, - }, - { - keys: ["restParameters", "syntax"], - name: "Rest parameters", - code: "function foo(a, ...b) {} ;(function(a, ...b) {})()", - errors: 2, - supported: 6, - }, - { - keys: ["spreadOperators", "syntax"], - name: "Spread operators", - code: "foo(...a); foo([...a, ...b])", - errors: 3, - supported: 5, - }, - { - keys: ["objectLiteralExtensions", "syntax"], - name: "Object literal extensions", - code: "var obj = {[a]: 0, b, c() {}, get [d]() {}, set [d](v) {}}", - errors: 5, - supported: 4, - }, - { - keys: [ - "objectPropertyShorthandOfGetSet", - "objectLiteralExtensions", - "syntax", - ], - name: "Property shorthand of 'get' and 'set'", - code: "var obj = {get, set}", - errors: 2, - supported: 6, - }, - { - keys: ["forOf", "syntax"], - name: "'for..of' loops", - code: "for (var a of []) {}", - errors: 1, - supported: 0.12, - }, - { - keys: ["binaryNumberLiterals", "syntax"], - name: "Binary number literals", - code: "var a = 0b10 === 2 && 0B10 === 2", - errors: 2, - supported: 4, - }, - { - keys: ["octalNumberLiterals", "syntax"], - name: "Octal number literals", - code: "var a = 0o10 === 8 && 0O10 === 8", - errors: 2, - supported: 4, - }, - { - keys: ["templateStrings", "syntax"], - name: "Template strings", - code: "`hello, ${world}!`; foo`tagged`;", - errors: 2, - supported: 4, - }, - { - keys: ["regexpY", "syntax"], - name: "RegExp 'y' flags", - code: "new RegExp('', 'y'); (/a/y)", - errors: 2, - supported: 6, - }, - { - keys: ["regexpU", "syntax"], - name: "RegExp 'u' flags", - code: "new RegExp('', 'u'); (/a/u)", - errors: 2, - supported: 6, - }, - { - keys: ["destructuring", "syntax"], - name: "Destructuring", - code: "var [[a], [b = 1]] = [], {c: {c}, d: {d = 1}} = {};", - errors: 2, - supported: 6, - }, - { - keys: ["destructuring", "syntax"], - name: "Destructuring", - code: "[[a], [b = 1]] = []; ({c: {c}, d: {d = 1}} = {})", - errors: 2, - supported: 6, - }, - { - keys: ["destructuring", "syntax"], - name: "Destructuring", - code: "function foo([[a], [b = 1]], {c: {c}, d: {d = 1}}) {}", - errors: 2, - supported: 6, - }, - { - keys: ["unicodeCodePointEscapes", "syntax"], - name: "Unicode code point escapes", - code: "var \\u{102C0} = { \\u{102C0} : '\\u{1d306}' };", - errors: 3, - supported: 4, - }, - { - keys: ["new.target", "syntax"], - name: "'new.target'", - code: "function Foo() { new.target; } ;(function() { new.target; })()", - errors: 2, - supported: 5, - }, - { - keys: ["const", "syntax"], - name: "'const' declarations", - code: "'use strict'; const a = 0;", - errors: 1, - supported: 4, - }, - { - keys: ["const", "syntax"], - name: "'const' declarations", - code: "const a = 0;", - errors: 1, - supported: 4, - modules: true, - }, - { - keys: ["const", "syntax"], - name: "'const' declarations in non-strict mode", - code: "const a = 0;", - errors: 1, - supported: 6, - ignores: [0.1, 0.12], - }, - { - keys: ["let", "syntax"], - name: "'let' declarations", - code: "'use strict'; let a = 0;", - errors: 1, - supported: 4, - }, - { - keys: ["let", "syntax"], - name: "'let' declarations", - code: "let a = 0;", - errors: 1, - supported: 4, - modules: true, - }, - { - keys: ["let", "syntax"], - name: "'let' declarations in non-strict mode", - code: "let a = 0;", - errors: 1, - supported: 6, - ignores: [0.1, 0.12], - }, - { - keys: ["blockScopedFunctions", "syntax"], - name: "Block-scoped functions", - code: "'use strict'; { function foo() {} } if (a) { function foo() {} }", - errors: 2, - supported: 4, - }, - { - keys: ["blockScopedFunctions", "syntax"], - name: "Block-scoped functions", - code: "{ function foo() {} } if (a) { function foo() {} }", - errors: 2, - supported: 4, - modules: true, - }, - { - keys: ["blockScopedFunctions", "syntax"], - name: "Block-scoped functions in non-strict mode", - code: "{ function foo() {} } if (a) { function foo() {} }", - errors: 2, - supported: 6, - ignores: [0.1, 0.12], - }, - { - keys: ["arrowFunctions", "syntax"], - name: "Arrow functions", - code: "var a = () => 1", - errors: 1, - supported: 4, - }, - { - keys: ["classes", "syntax"], - name: "Classes", - code: "'use strict'; class A {} new (class{})()", - errors: 2, - supported: 4, - }, - { - keys: ["classes", "syntax"], - name: "Classes", - code: "class A {} new (class{})()", - errors: 2, - supported: 4, - modules: true, - }, - { - keys: ["classes", "syntax"], - name: "Classes in non-strict mode", - code: "class A {} new (class{})()", - errors: 2, - supported: 6, - ignores: [0.1, 0.12], - }, - { - keys: ["generatorFunctions", "syntax"], - name: "Generator functions", - code: "function* foo() {} ;(function*() {})();", - errors: 2, - supported: 4, - }, - { - keys: ["modules", "syntax"], - name: "Import and export declarations", - code: "import foo from 'foo'; export default 0; export {foo}; export * from 'foo';", - errors: 4, - supported: NaN, - modules: true, - }, - { - keys: ["exponentialOperators", "syntax"], - name: "Exponential operators (**)", - code: "var a = 2 ** 10; a **= 10;", - errors: 2, - supported: 7, - }, - { - keys: ["asyncAwait", "syntax"], - name: "Async functions", - code: [ - "async function foo() { await obj; };", - "(async function() { await obj; });", - "(async () => { await obj; });", - "({async foo() { await obj; }});", - "class A { async foo() { await obj; } };", - ].join("\n"), - errors: 10, - supported: 7.6, - ignores: [0.1, 0.12, 4, 5], - }, - { - keys: ["trailingCommasInFunctions", "syntax"], - name: "Trailing commas in functions", - code: [ - "function foo(a,) {}", - "(function(a,) {});", - "((a,) => {});", - "({ foo(a,) {} });", - "class A { foo(a,) {} };", - "foo(a,);", - "new Foo(a,);", - ].join("\n"), - errors: 7, - supported: 8, - ignores: [0.1, 0.12, 4, 5], - }, - { - keys: ["templateLiteralRevision", "syntax"], - name: "Illegal escape sequences in taggled templates", - code: [ - "tag`\\01\\1\\xg\\xAg\\u0\\u0g\\u00g\\u000g\\u{g\\u{0\\u{110000}${0}\\0`", - ].join("\n"), - errors: 1, - supported: 9, - ignores: [0.1, 0.12, 4, 5], - }, - { - keys: ["regexpS", "syntax"], - name: "RegExp 's' flags", - code: "new RegExp('', 's'); (/a/s)", - errors: 2, - supported: 9, - }, - { - keys: ["regexpNamedCaptureGroups", "syntax"], - name: "RegExp named capture groups", - code: [ - "new RegExp('(?b)');", - //TODO: Espree has not supported this syntax yet. - // ";(/(?b)/)", - ].join("\n"), - errors: 1, - supported: 10, - }, - { - keys: ["regexpLookbehind", "syntax"], - name: "RegExp lookbehind assertions", - code: [ - "new RegExp('(?<=a)b')", - "new RegExp('(? 1", - }, - { - filename: fixture("gte-4.4.0-lt-5.0.0/a.js"), - code: "var a = () => 1", - }, - { - filename: fixture("hat-4.1.2/a.js"), - code: "var a = () => 1", - }, - { - code: "'\\\\u{0123}'", - }, - { - filename: fixture("gte-4.0.0/a.js"), - code: "var a = async () => 1", - languageOptions: { ecmaVersion: 2017 }, - options: [{ ignores: ["asyncAwait"] }], - }, - { - filename: fixture("gte-7.6.0/a.js"), - code: "var a = async () => 1", - languageOptions: { ecmaVersion: 2017 }, - }, - { - filename: fixture("gte-7.10.0/a.js"), - code: "var a = async () => 1", - languageOptions: { ecmaVersion: 2017 }, - }, - { - filename: fixture("invalid/a.js"), - code: "var a = () => 1", - }, - { - filename: fixture("nothing/a.js"), - code: "var a = () => 1", - }, - { - code: "var a = async () => 1", - languageOptions: { ecmaVersion: 2017 }, - options: ["7.10.0"], - }, - { - filename: fixture("without-node/a.js"), - code: "var a = () => 1", - }, - ], - invalid: [ - { - filename: fixture("gte-0.12.8/a.js"), - code: "var a = () => 1", - errors: [ - "Arrow functions are not supported yet on Node >=0.12.8.", - ], - }, - { - filename: fixture("invalid/a.js"), - code: "var a = (b,) => 1", - languageOptions: { ecmaVersion: 2017 }, - errors: [ - "Trailing commas in functions are not supported yet on Node 4.0.0.", - ], - }, - { - filename: fixture("lt-6.0.0/a.js"), - code: "var a = () => 1", - languageOptions: { ecmaVersion: 2017 }, - errors: [ - "Arrow functions are not supported yet on Node <6.0.0.", - ], - }, - { - filename: fixture("nothing/a.js"), - code: "var a = (b,) => 1", - languageOptions: { ecmaVersion: 2017 }, - errors: [ - "Trailing commas in functions are not supported yet on Node 4.0.0.", - ], - }, - { - filename: fixture("gte-7.5.0/a.js"), - code: "var a = async () => 1", - languageOptions: { ecmaVersion: 2017 }, - errors: [ - "Async functions are not supported yet on Node >=7.5.0.", - ], - }, - { - code: "var a = async () => 1", - languageOptions: { ecmaVersion: 2017 }, - options: ["7.1.0"], - errors: [ - "Async functions are not supported yet on Node 7.1.0.", - ], - }, - ], - }) -)