123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637 |
- /**
- * @author Toru Nagashima
- * See LICENSE file in root directory for full license.
- */
- "use strict"
- const { rules: esRules } = require("eslint-plugin-es")
- const { getInnermostScope } = require("eslint-utils")
- const { Range } = require("semver") //eslint-disable-line no-unused-vars
- const getConfiguredNodeVersion = require("../../util/get-configured-node-version")
- const getSemverRange = require("../../util/get-semver-range")
- const mergeVisitorsInPlace = require("../../util/merge-visitors-in-place")
- const getOrSet = /^(?:g|s)et$/u
- const features = {
- //--------------------------------------------------------------------------
- // ES2015
- //--------------------------------------------------------------------------
- arrowFunctions: {
- ruleId: "no-arrow-functions",
- cases: [
- {
- supported: "4.0.0",
- messageId: "no-arrow-functions",
- },
- ],
- },
- binaryNumericLiterals: {
- ruleId: "no-binary-numeric-literals",
- cases: [
- {
- supported: "4.0.0",
- messageId: "no-binary-numeric-literals",
- },
- ],
- },
- blockScopedFunctions: {
- ruleId: "no-block-scoped-functions",
- cases: [
- {
- supported: "6.0.0",
- test: info => !info.isStrict,
- messageId: "no-block-scoped-functions-sloppy",
- },
- {
- supported: "4.0.0",
- messageId: "no-block-scoped-functions-strict",
- },
- ],
- },
- blockScopedVariables: {
- ruleId: "no-block-scoped-variables",
- cases: [
- {
- supported: "6.0.0",
- test: info => !info.isStrict,
- messageId: "no-block-scoped-variables-sloppy",
- },
- {
- supported: "4.0.0",
- messageId: "no-block-scoped-variables-strict",
- },
- ],
- },
- classes: {
- ruleId: "no-classes",
- cases: [
- {
- supported: "6.0.0",
- test: info => !info.isStrict,
- messageId: "no-classes-sloppy",
- },
- {
- supported: "4.0.0",
- messageId: "no-classes-strict",
- },
- ],
- },
- computedProperties: {
- ruleId: "no-computed-properties",
- cases: [
- {
- supported: "4.0.0",
- messageId: "no-computed-properties",
- },
- ],
- },
- defaultParameters: {
- ruleId: "no-default-parameters",
- cases: [
- {
- supported: "6.0.0",
- messageId: "no-default-parameters",
- },
- ],
- },
- destructuring: {
- ruleId: "no-destructuring",
- cases: [
- {
- supported: "6.0.0",
- messageId: "no-destructuring",
- },
- ],
- },
- forOfLoops: {
- ruleId: "no-for-of-loops",
- cases: [
- {
- supported: "0.12.0",
- messageId: "no-for-of-loops",
- },
- ],
- },
- generators: {
- ruleId: "no-generators",
- cases: [
- {
- supported: "4.0.0",
- messageId: "no-generators",
- },
- ],
- },
- modules: {
- ruleId: "no-modules",
- cases: [
- {
- supported: null,
- messageId: "no-modules",
- },
- ],
- },
- "new.target": {
- ruleId: "no-new-target",
- cases: [
- {
- supported: "5.0.0",
- messageId: "no-new-target",
- },
- ],
- },
- objectSuperProperties: {
- ruleId: "no-object-super-properties",
- cases: [
- {
- supported: "4.0.0",
- messageId: "no-object-super-properties",
- },
- ],
- },
- octalNumericLiterals: {
- ruleId: "no-octal-numeric-literals",
- cases: [
- {
- supported: "4.0.0",
- messageId: "no-octal-numeric-literals",
- },
- ],
- },
- propertyShorthands: {
- ruleId: "no-property-shorthands",
- cases: [
- {
- supported: "6.0.0",
- test: info =>
- info.node.shorthand && getOrSet.test(info.node.key.name),
- messageId: "no-property-shorthands-getset",
- },
- {
- supported: "4.0.0",
- messageId: "no-property-shorthands",
- },
- ],
- },
- regexpU: {
- ruleId: "no-regexp-u-flag",
- cases: [
- {
- supported: "6.0.0",
- messageId: "no-regexp-u-flag",
- },
- ],
- },
- regexpY: {
- ruleId: "no-regexp-y-flag",
- cases: [
- {
- supported: "6.0.0",
- messageId: "no-regexp-y-flag",
- },
- ],
- },
- restParameters: {
- ruleId: "no-rest-parameters",
- cases: [
- {
- supported: "6.0.0",
- messageId: "no-rest-parameters",
- },
- ],
- },
- spreadElements: {
- ruleId: "no-spread-elements",
- cases: [
- {
- supported: "5.0.0",
- messageId: "no-spread-elements",
- },
- ],
- },
- templateLiterals: {
- ruleId: "no-template-literals",
- cases: [
- {
- supported: "4.0.0",
- messageId: "no-template-literals",
- },
- ],
- },
- unicodeCodePointEscapes: {
- ruleId: "no-unicode-codepoint-escapes",
- cases: [
- {
- supported: "4.0.0",
- messageId: "no-unicode-codepoint-escapes",
- },
- ],
- },
- //--------------------------------------------------------------------------
- // ES2016
- //--------------------------------------------------------------------------
- exponentialOperators: {
- ruleId: "no-exponential-operators",
- cases: [
- {
- supported: "7.0.0",
- messageId: "no-exponential-operators",
- },
- ],
- },
- //--------------------------------------------------------------------------
- // ES2017
- //--------------------------------------------------------------------------
- asyncFunctions: {
- ruleId: "no-async-functions",
- cases: [
- {
- supported: "7.6.0",
- messageId: "no-async-functions",
- },
- ],
- },
- trailingCommasInFunctions: {
- ruleId: "no-trailing-function-commas",
- cases: [
- {
- supported: "8.0.0",
- messageId: "no-trailing-function-commas",
- },
- ],
- },
- //--------------------------------------------------------------------------
- // ES2018
- //--------------------------------------------------------------------------
- asyncIteration: {
- ruleId: "no-async-iteration",
- cases: [
- {
- supported: "10.0.0",
- messageId: "no-async-iteration",
- },
- ],
- },
- malformedTemplateLiterals: {
- ruleId: "no-malformed-template-literals",
- cases: [
- {
- supported: "8.10.0",
- messageId: "no-malformed-template-literals",
- },
- ],
- },
- regexpLookbehind: {
- ruleId: "no-regexp-lookbehind-assertions",
- cases: [
- {
- supported: "8.10.0",
- messageId: "no-regexp-lookbehind-assertions",
- },
- ],
- },
- regexpNamedCaptureGroups: {
- ruleId: "no-regexp-named-capture-groups",
- cases: [
- {
- supported: "10.0.0",
- messageId: "no-regexp-named-capture-groups",
- },
- ],
- },
- regexpS: {
- ruleId: "no-regexp-s-flag",
- cases: [
- {
- supported: "8.10.0",
- messageId: "no-regexp-s-flag",
- },
- ],
- },
- regexpUnicodeProperties: {
- ruleId: "no-regexp-unicode-property-escapes",
- cases: [
- {
- supported: "10.0.0",
- messageId: "no-regexp-unicode-property-escapes",
- },
- ],
- },
- restSpreadProperties: {
- ruleId: "no-rest-spread-properties",
- cases: [
- {
- supported: "8.3.0",
- messageId: "no-rest-spread-properties",
- },
- ],
- },
- //--------------------------------------------------------------------------
- // ES2019
- //--------------------------------------------------------------------------
- jsonSuperset: {
- ruleId: "no-json-superset",
- cases: [
- {
- supported: "10.0.0",
- messageId: "no-json-superset",
- },
- ],
- },
- optionalCatchBinding: {
- ruleId: "no-optional-catch-binding",
- cases: [
- {
- supported: "10.0.0",
- messageId: "no-optional-catch-binding",
- },
- ],
- },
- //--------------------------------------------------------------------------
- // ES2020
- //--------------------------------------------------------------------------
- bigint: {
- ruleId: "no-bigint",
- cases: [
- {
- supported: "10.4.0",
- test: info => info.node.type === "Literal",
- messageId: "no-bigint",
- },
- {
- supported: null,
- test: ({ node }) =>
- node.type === "Literal" &&
- (node.parent.type === "Property" ||
- node.parent.type === "MethodDefinition") &&
- !node.parent.computed &&
- node.parent.key === node,
- messageId: "no-bigint-property-names",
- },
- ],
- },
- dynamicImport: {
- ruleId: "no-dynamic-import",
- cases: [
- {
- supported: null,
- messageId: "no-dynamic-import",
- },
- ],
- },
- }
- const keywords = Object.keys(features)
- /**
- * Parses the options.
- * @param {RuleContext} context The rule context.
- * @returns {{version:Range,ignores:Set<string>}} Parsed value.
- */
- function parseOptions(context) {
- const raw = context.options[0] || {}
- const filePath = context.getFilename()
- const version = getConfiguredNodeVersion(raw.version, filePath)
- const ignores = new Set(raw.ignores || [])
- return Object.freeze({ version, ignores })
- }
- /**
- * 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
- }
- /**
- * Define the visitor object as merging the rules of eslint-plugin-es.
- * @param {RuleContext} context The rule context.
- * @param {{version:Range,ignores:Set<string>}} options The options.
- * @returns {object} The defined visitor.
- */
- function defineVisitor(context, options) {
- const testInfoPrototype = {
- get isStrict() {
- return normalizeScope(context.getScope(), this.node).isStrict
- },
- }
- /**
- * Check whether a given case object is full-supported on the configured node version.
- * @param {{supported:string}} aCase The case object to check.
- * @returns {boolean} `true` if it's supporting.
- */
- function isNotSupportingVersion(aCase) {
- return (
- !aCase.supported ||
- options.version.intersects(getSemverRange(`<${aCase.supported}`))
- )
- }
- /**
- * Define the predicate function to check whether a given case object is supported on the configured node version.
- * @param {Node} node The node which is reported.
- * @returns {function(aCase:{supported:string}):boolean} The predicate function.
- */
- function isNotSupportingOn(node) {
- return aCase =>
- isNotSupportingVersion(aCase) &&
- (!aCase.test || aCase.test({ node, __proto__: testInfoPrototype }))
- }
- return (
- keywords
- // Omit full-supported features and ignored features by options
- // because this rule never reports those.
- .filter(
- keyword =>
- !options.ignores.has(keyword) &&
- features[keyword].cases.some(isNotSupportingVersion)
- )
- // Merge remaining features with overriding `context.report()`.
- .reduce((visitor, keyword) => {
- const { ruleId, cases } = features[keyword]
- const rule = esRules[ruleId]
- const thisContext = {
- __proto__: context,
- // Override `context.report()` then:
- // - ignore if it's supported.
- // - override reporting messages.
- report(descriptor) {
- // Set additional information.
- if (descriptor.data) {
- descriptor.data.version = options.version.raw
- } else {
- descriptor.data = { version: options.version.raw }
- }
- descriptor.fix = undefined
- // Test and report.
- const node = descriptor.node
- const hitCase = cases.find(isNotSupportingOn(node))
- if (hitCase) {
- descriptor.messageId = hitCase.messageId
- descriptor.data.supported = hitCase.supported
- super.report(descriptor)
- }
- },
- }
- return mergeVisitorsInPlace(visitor, rule.create(thisContext))
- }, {})
- )
- }
- module.exports = {
- meta: {
- docs: {
- description:
- "disallow unsupported ECMAScript syntax on the specified version",
- category: "Possible Errors",
- recommended: true,
- url:
- "https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-unsupported-features/es-syntax.md",
- },
- type: "problem",
- fixable: null,
- schema: [
- {
- type: "object",
- properties: {
- version: {
- type: "string",
- },
- ignores: {
- type: "array",
- items: {
- enum: Object.keys(features),
- },
- uniqueItems: true,
- },
- },
- additionalProperties: false,
- },
- ],
- messages: {
- //------------------------------------------------------------------
- // ES2015
- //------------------------------------------------------------------
- "no-arrow-functions":
- "Arrow functions are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
- "no-binary-numeric-literals":
- "Binary numeric literals are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
- "no-block-scoped-functions-strict":
- "Block-scoped functions in strict mode are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
- "no-block-scoped-functions-sloppy":
- "Block-scoped functions in non-strict mode are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
- "no-block-scoped-variables-strict":
- "Block-scoped variables in strict mode are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
- "no-block-scoped-variables-sloppy":
- "Block-scoped variables in non-strict mode are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
- "no-classes-strict":
- "Classes in strict mode are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
- "no-classes-sloppy":
- "Classes in non-strict mode are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
- "no-computed-properties":
- "Computed properties are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
- "no-default-parameters":
- "Default parameters are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
- "no-destructuring":
- "Destructuring is not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
- "no-for-of-loops":
- "'for-of' loops are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
- "no-generators":
- "Generator functions are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
- "no-modules":
- "Import and export declarations are not supported yet.",
- "no-new-target":
- "'new.target' is not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
- "no-object-super-properties":
- "'super' in object literals is not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
- "no-octal-numeric-literals":
- "Octal numeric literals are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
- "no-property-shorthands":
- "Property shorthands are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
- "no-property-shorthands-getset":
- "Property shorthands of 'get' and 'set' are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
- "no-regexp-u-flag":
- "RegExp 'u' flag is not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
- "no-regexp-y-flag":
- "RegExp 'y' flag is not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
- "no-rest-parameters":
- "Rest parameters are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
- "no-spread-elements":
- "Spread elements are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
- "no-template-literals":
- "Template literals are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
- "no-unicode-codepoint-escapes":
- "Unicode code point escapes are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
- //------------------------------------------------------------------
- // ES2016
- //------------------------------------------------------------------
- "no-exponential-operators":
- "Exponential operators are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
- //------------------------------------------------------------------
- // ES2017
- //------------------------------------------------------------------
- "no-async-functions":
- "Async functions are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
- "no-trailing-function-commas":
- "Trailing commas in function syntax are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
- //------------------------------------------------------------------
- // ES2018
- //------------------------------------------------------------------
- "no-async-iteration":
- "Async iteration is not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
- "no-malformed-template-literals":
- "Malformed template literals are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
- "no-regexp-lookbehind-assertions":
- "RegExp lookbehind assertions are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
- "no-regexp-named-capture-groups":
- "RegExp named capture groups are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
- "no-regexp-s-flag":
- "RegExp 's' flag is not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
- "no-regexp-unicode-property-escapes":
- "RegExp Unicode property escapes are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
- "no-rest-spread-properties":
- "Rest/spread properties are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
- //------------------------------------------------------------------
- // ES2019
- //------------------------------------------------------------------
- "no-json-superset":
- "'\\u{{code}}' in string literals is not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
- "no-optional-catch-binding":
- "The omission of 'catch' binding is not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
- //------------------------------------------------------------------
- // ES2020
- //------------------------------------------------------------------
- "no-bigint":
- "Bigint literals are not supported until Node.js {{supported}}. The configured version range is '{{version}}'.",
- "no-bigint-property-names":
- "Bigint literal property names are not supported yet.",
- "no-dynamic-import":
- "'import()' expressions are not supported yet.",
- },
- },
- create(context) {
- return defineVisitor(context, parseOptions(context))
- },
- }
|