diff --git a/lib/rules/no-unsupported-features/node-builtins.js b/lib/rules/no-unsupported-features/node-builtins.js index a3fd4c4b..27cc2437 100644 --- a/lib/rules/no-unsupported-features/node-builtins.js +++ b/lib/rules/no-unsupported-features/node-builtins.js @@ -23,7 +23,7 @@ const trackMap = { modules: { assert: { strict: { - [READ]: { supported: "9.9.0" }, + [READ]: { supported: "9.9.0", backported: ["8.13.0"] }, doesNotReject: { [READ]: { supported: "10.0.0" } }, rejects: { [READ]: { supported: "10.0.0" } }, }, @@ -51,9 +51,11 @@ const trackMap = { ChildProcess: { [READ]: { supported: "2.2.0" } }, }, console: { - clear: { [READ]: { supported: "8.3.0" } }, - count: { [READ]: { supported: "8.3.0" } }, - countReset: { [READ]: { supported: "8.3.0" } }, + clear: { [READ]: { supported: "8.3.0", backported: ["6.13.0"] } }, + count: { [READ]: { supported: "8.3.0", backported: ["6.13.0"] } }, + countReset: { + [READ]: { supported: "8.3.0", backported: ["6.13.0"] }, + }, debug: { [READ]: { supported: "8.0.0" } }, dirxml: { [READ]: { supported: "8.0.0" } }, group: { [READ]: { supported: "8.5.0" } }, @@ -74,6 +76,7 @@ const trackMap = { exportPublicKey: { [READ]: { supported: "9.0.0" } }, verifySpkac: { [READ]: { supported: "9.0.0" } }, }, + ECDH: { [READ]: { supported: "8.8.0", backported: ["6.13.0"] } }, KeyObject: { [READ]: { supported: "11.6.0" } }, createPrivateKey: { [READ]: { supported: "11.6.0" } }, createPublicKey: { [READ]: { supported: "11.6.0" } }, @@ -86,8 +89,12 @@ const trackMap = { getFips: { [READ]: { supported: "10.0.0" } }, privateEncrypt: { [READ]: { supported: "1.1.0" } }, publicDecrypt: { [READ]: { supported: "1.1.0" } }, - randomFillSync: { [READ]: { supported: "7.10.0" } }, - randomFill: { [READ]: { supported: "7.10.0" } }, + randomFillSync: { + [READ]: { supported: "7.10.0", backported: ["6.13.0"] }, + }, + randomFill: { + [READ]: { supported: "7.10.0", backported: ["6.13.0"] }, + }, scrypt: { [READ]: { supported: "10.5.0" } }, scryptSync: { [READ]: { supported: "10.5.0" } }, setFips: { [READ]: { supported: "10.0.0" } }, @@ -99,14 +106,20 @@ const trackMap = { Resolver: { [READ]: { supported: "8.3.0" } }, resolvePtr: { [READ]: { supported: "6.0.0" } }, promises: { - [READ]: { supported: "11.14.0", experimental: "10.6.0" }, + [READ]: { + supported: "11.14.0", + backported: ["10.17.0"], + experimental: "10.6.0", + }, }, }, events: { EventEmitter: { - once: { [READ]: { supported: "11.13.0" } }, + once: { + [READ]: { supported: "11.13.0", backported: ["10.16.0"] }, + }, }, - once: { [READ]: { supported: "11.13.0" } }, + once: { [READ]: { supported: "11.13.0", backported: ["10.16.0"] } }, }, fs: { Dirent: { [READ]: { supported: "10.10.0" } }, @@ -121,25 +134,43 @@ const trackMap = { native: { [READ]: { supported: "9.2.0" } }, }, promises: { - [READ]: { supported: "11.14.0", experimental: "10.1.0" }, + [READ]: { + supported: "11.14.0", + backported: ["10.17.0"], + experimental: "10.1.0", + }, }, writev: { [READ]: { supported: "12.9.0" } }, writevSync: { [READ]: { supported: "12.9.0" } }, }, http2: { - [READ]: { supported: "10.10.0", experimental: "8.4.0" }, + [READ]: { + supported: "10.10.0", + backported: ["8.13.0"], + experimental: "8.4.0", + }, }, inspector: { [READ]: { supported: null, experimental: "8.0.0" }, }, module: { Module: { - builtinModules: { [READ]: { supported: "9.3.0" } }, + builtinModules: { + [READ]: { + supported: "9.3.0", + backported: ["6.13.0", "8.10.0"], + }, + }, createRequireFromPath: { [READ]: { supported: "10.12.0" } }, createRequire: { [READ]: { supported: "12.2.0" } }, syncBuiltinESMExports: { [READ]: { supported: "12.12.0" } }, }, - builtinModules: { [READ]: { supported: "9.3.0" } }, + builtinModules: { + [READ]: { + supported: "9.3.0", + backported: ["6.13.0", "8.10.0"], + }, + }, createRequireFromPath: { [READ]: { supported: "10.12.0" } }, createRequire: { [READ]: { supported: "12.2.0" } }, syncBuiltinESMExports: { [READ]: { supported: "12.12.0" } }, @@ -175,7 +206,12 @@ const trackMap = { hrtime: { bigint: { [READ]: { supported: "10.7.0" } }, }, - ppid: { [READ]: { supported: "9.2.0" } }, + ppid: { + [READ]: { + supported: "9.2.0", + backported: ["6.13.0", "8.10.0"], + }, + }, release: { [READ]: { supported: "3.0.0" } }, report: { [READ]: { supported: null, experimental: "11.8.0" } }, resourceUsage: { [READ]: { supported: "12.6.0" } }, @@ -195,7 +231,9 @@ const trackMap = { }, stream: { Readable: { - from: { [READ]: { supported: "12.3.0" } }, + from: { + [READ]: { supported: "12.3.0", backported: ["10.17.0"] }, + }, }, finished: { [READ]: { supported: "10.0.0" } }, pipeline: { [READ]: { supported: "10.0.0" } }, @@ -204,15 +242,19 @@ const trackMap = { [READ]: { supported: "10.0.0" }, }, url: { - URL: { [READ]: { supported: "7.0.0" } }, - URLSearchParams: { [READ]: { supported: "7.5.0" } }, + URL: { [READ]: { supported: "7.0.0", backported: ["6.13.0"] } }, + URLSearchParams: { + [READ]: { supported: "7.5.0", backported: ["6.13.0"] }, + }, domainToASCII: { [READ]: { supported: "7.4.0" } }, domainToUnicode: { [READ]: { supported: "7.4.0" } }, }, util: { callbackify: { [READ]: { supported: "8.2.0" } }, formatWithOptions: { [READ]: { supported: "10.0.0" } }, - getSystemErrorName: { [READ]: { supported: "9.7.0" } }, + getSystemErrorName: { + [READ]: { supported: "9.7.0", backported: ["8.12.0"] }, + }, inspect: { custom: { [READ]: { supported: "6.6.0" } }, defaultOptions: { [READ]: { supported: "6.4.0" } }, @@ -220,8 +262,12 @@ const trackMap = { }, isDeepStrictEqual: { [READ]: { supported: "9.0.0" } }, promisify: { [READ]: { supported: "8.0.0" } }, - TextDecoder: { [READ]: { supported: "8.3.0" } }, - TextEncoder: { [READ]: { supported: "8.3.0" } }, + TextDecoder: { + [READ]: { supported: "8.9.0", experimental: "8.3.0" }, + }, + TextEncoder: { + [READ]: { supported: "8.9.0", experimental: "8.3.0" }, + }, types: { [READ]: { supported: "10.0.0" }, isBoxedPrimitive: { [READ]: { supported: "10.11.0" } }, diff --git a/lib/util/check-unsupported-builtins.js b/lib/util/check-unsupported-builtins.js index d830c5c5..15d27a83 100644 --- a/lib/util/check-unsupported-builtins.js +++ b/lib/util/check-unsupported-builtins.js @@ -4,11 +4,18 @@ */ "use strict" -const { Range } = require("semver") //eslint-disable-line no-unused-vars +const { Range, lt, major } = require("semver") //eslint-disable-line no-unused-vars const { ReferenceTracker } = require("eslint-utils") const getConfiguredNodeVersion = require("./get-configured-node-version") const getSemverRange = require("./get-semver-range") +/** + * @typedef {Object} SupportInfo + * @property {string | null} supported The stably supported version. If `null` is present, it hasn't been supported yet. + * @property {string[]} [backported] The backported versions. + * @property {string} [experimental] The added version as experimental. + */ + /** * Parses the options. * @param {RuleContext} context The rule context. @@ -23,6 +30,50 @@ function parseOptions(context) { return Object.freeze({ version, ignores }) } +/** + * Check if it has been supported. + * @param {SupportInfo} info The support info. + * @param {Range} configured The configured version range. + */ +function isSupported({ backported, supported }, configured) { + if ( + backported && + backported.length >= 2 && + !backported.every((v, i) => i === 0 || lt(backported[i - 1], v)) + ) { + throw new Error("Invalid BackportConfiguration") + } + + if (supported == null) { + return false + } + if (backported == null || backported.length === 0) { + return !configured.intersects(getSemverRange(`<${supported}`)) + } + + return !configured.intersects( + getSemverRange( + [...backported, supported] + .map((v, i) => (i === 0 ? `<${v}` : `>=${major(v)}.0.0 <${v}`)) + .join(" || ") + ) + ) +} + +/** + * Get the formatted text of a given supported version. + * @param {SupportInfo} info The support info. + */ +function supportedVersionToString({ backported, supported }) { + if (supported == null) { + return "(none yet)" + } + if (backported == null || backported.length === 0) { + return supported + } + return `${supported} (backported: ^${backported.join(", ^")})` +} + /** * Verify the code to report unsupported APIs. * @param {RuleContext} context The rule context. @@ -40,9 +91,7 @@ module.exports = function checkUnsupportedBuiltins(context, trackMap) { for (const { node, path, info } of references) { const name = path.join(".") - const supported = - Boolean(info.supported) && - !options.version.intersects(getSemverRange(`<${info.supported}`)) + const supported = isSupported(info, options.version) if (!supported && !options.ignores.has(name)) { context.report({ @@ -50,7 +99,7 @@ module.exports = function checkUnsupportedBuiltins(context, trackMap) { messageId: "unsupported", data: { name, - supported: info.supported || "???", + supported: supportedVersionToString(info), version: options.version.raw, }, }) diff --git a/tests/lib/rules/no-unsupported-features/node-builtins.js b/tests/lib/rules/no-unsupported-features/node-builtins.js index 3caf2162..39abd122 100644 --- a/tests/lib/rules/no-unsupported-features/node-builtins.js +++ b/tests/lib/rules/no-unsupported-features/node-builtins.js @@ -366,7 +366,7 @@ new RuleTester({ messageId: "unsupported", data: { name: "assert.strict", - supported: "9.9.0", + supported: "9.9.0 (backported: ^8.13.0)", version: "9.8.9", }, }, @@ -381,7 +381,7 @@ new RuleTester({ messageId: "unsupported", data: { name: "assert.strict", - supported: "9.9.0", + supported: "9.9.0 (backported: ^8.13.0)", version: "9.8.9", }, }, @@ -1353,7 +1353,7 @@ new RuleTester({ messageId: "unsupported", data: { name: "console.clear", - supported: "8.3.0", + supported: "8.3.0 (backported: ^6.13.0)", version: "8.2.9", }, }, @@ -1367,7 +1367,7 @@ new RuleTester({ messageId: "unsupported", data: { name: "console.clear", - supported: "8.3.0", + supported: "8.3.0 (backported: ^6.13.0)", version: "8.2.9", }, }, @@ -1381,7 +1381,7 @@ new RuleTester({ messageId: "unsupported", data: { name: "console.clear", - supported: "8.3.0", + supported: "8.3.0 (backported: ^6.13.0)", version: "8.2.9", }, }, @@ -1395,7 +1395,7 @@ new RuleTester({ messageId: "unsupported", data: { name: "console.clear", - supported: "8.3.0", + supported: "8.3.0 (backported: ^6.13.0)", version: "8.2.9", }, }, @@ -1409,7 +1409,7 @@ new RuleTester({ messageId: "unsupported", data: { name: "console.clear", - supported: "8.3.0", + supported: "8.3.0 (backported: ^6.13.0)", version: "8.2.9", }, }, @@ -1423,7 +1423,7 @@ new RuleTester({ messageId: "unsupported", data: { name: "console.count", - supported: "8.3.0", + supported: "8.3.0 (backported: ^6.13.0)", version: "8.2.9", }, }, @@ -1437,7 +1437,7 @@ new RuleTester({ messageId: "unsupported", data: { name: "console.countReset", - supported: "8.3.0", + supported: "8.3.0 (backported: ^6.13.0)", version: "8.2.9", }, }, @@ -2055,7 +2055,7 @@ new RuleTester({ messageId: "unsupported", data: { name: "crypto.randomFillSync", - supported: "7.10.0", + supported: "7.10.0 (backported: ^6.13.0)", version: "7.9.9", }, }, @@ -2069,7 +2069,7 @@ new RuleTester({ messageId: "unsupported", data: { name: "crypto.randomFill", - supported: "7.10.0", + supported: "7.10.0 (backported: ^6.13.0)", version: "7.9.9", }, }, @@ -2295,7 +2295,7 @@ new RuleTester({ messageId: "unsupported", data: { name: "dns.promises", - supported: "11.14.0", + supported: "11.14.0 (backported: ^10.17.0)", version: "11.13.9", }, }, @@ -2420,7 +2420,7 @@ new RuleTester({ messageId: "unsupported", data: { name: "fs.promises", - supported: "11.14.0", + supported: "11.14.0 (backported: ^10.17.0)", version: "11.13.9", }, }, @@ -2434,7 +2434,7 @@ new RuleTester({ messageId: "unsupported", data: { name: "fs.promises", - supported: "11.14.0", + supported: "11.14.0 (backported: ^10.17.0)", version: "11.13.9", }, }, @@ -2448,7 +2448,7 @@ new RuleTester({ messageId: "unsupported", data: { name: "fs.promises", - supported: "11.14.0", + supported: "11.14.0 (backported: ^10.17.0)", version: "11.13.9", }, }, @@ -2462,7 +2462,7 @@ new RuleTester({ messageId: "unsupported", data: { name: "fs.promises", - supported: "11.14.0", + supported: "11.14.0 (backported: ^10.17.0)", version: "11.13.9", }, }, @@ -2476,7 +2476,7 @@ new RuleTester({ messageId: "unsupported", data: { name: "fs.promises", - supported: "11.14.0", + supported: "11.14.0 (backported: ^10.17.0)", version: "11.13.9", }, }, @@ -2600,7 +2600,7 @@ new RuleTester({ messageId: "unsupported", data: { name: "http2", - supported: "10.10.0", + supported: "10.10.0 (backported: ^8.13.0)", version: "8.3.9", }, }, @@ -2614,7 +2614,7 @@ new RuleTester({ messageId: "unsupported", data: { name: "http2", - supported: "10.10.0", + supported: "10.10.0 (backported: ^8.13.0)", version: "8.3.9", }, }, @@ -2628,7 +2628,7 @@ new RuleTester({ messageId: "unsupported", data: { name: "http2", - supported: "10.10.0", + supported: "10.10.0 (backported: ^8.13.0)", version: "8.3.9", }, }, @@ -2660,7 +2660,7 @@ new RuleTester({ messageId: "unsupported", data: { name: "inspector", - supported: "???", + supported: "(none yet)", version: "7.9.9", }, }, @@ -2674,7 +2674,7 @@ new RuleTester({ messageId: "unsupported", data: { name: "inspector", - supported: "???", + supported: "(none yet)", version: "7.9.9", }, }, @@ -2688,7 +2688,7 @@ new RuleTester({ messageId: "unsupported", data: { name: "inspector", - supported: "???", + supported: "(none yet)", version: "7.9.9", }, }, @@ -2752,7 +2752,8 @@ new RuleTester({ messageId: "unsupported", data: { name: "module.builtinModules", - supported: "9.3.0", + supported: + "9.3.0 (backported: ^6.13.0, ^8.10.0)", version: "9.2.9", }, }, @@ -3478,7 +3479,8 @@ new RuleTester({ messageId: "unsupported", data: { name: "process.ppid", - supported: "9.2.0", + supported: + "9.2.0 (backported: ^6.13.0, ^8.10.0)", version: "9.1.9", }, }, @@ -3785,6 +3787,10 @@ new RuleTester({ code: "require('url').URL", options: [{ version: "7.0.0" }], }, + { + code: "require('url').URL", + options: [{ version: "6.13.0" }], + }, { code: "var cp = require('url'); cp.URL", options: [{ version: "7.0.0" }], @@ -3805,6 +3811,10 @@ new RuleTester({ code: "require('url').URLSearchParams", options: [{ version: "7.5.0" }], }, + { + code: "require('url').URLSearchParams", + options: [{ version: "6.13.0" }], + }, { code: "require('url').domainToASCII", options: [{ version: "7.4.0" }], @@ -3901,7 +3911,7 @@ new RuleTester({ messageId: "unsupported", data: { name: "url.URL", - supported: "7.0.0", + supported: "7.0.0 (backported: ^6.13.0)", version: "6.9.9", }, }, @@ -3915,7 +3925,7 @@ new RuleTester({ messageId: "unsupported", data: { name: "url.URL", - supported: "7.0.0", + supported: "7.0.0 (backported: ^6.13.0)", version: "6.9.9", }, }, @@ -3929,7 +3939,7 @@ new RuleTester({ messageId: "unsupported", data: { name: "url.URL", - supported: "7.0.0", + supported: "7.0.0 (backported: ^6.13.0)", version: "6.9.9", }, }, @@ -3943,7 +3953,7 @@ new RuleTester({ messageId: "unsupported", data: { name: "url.URL", - supported: "7.0.0", + supported: "7.0.0 (backported: ^6.13.0)", version: "6.9.9", }, }, @@ -3957,7 +3967,7 @@ new RuleTester({ messageId: "unsupported", data: { name: "url.URL", - supported: "7.0.0", + supported: "7.0.0 (backported: ^6.13.0)", version: "6.9.9", }, }, @@ -3971,7 +3981,7 @@ new RuleTester({ messageId: "unsupported", data: { name: "url.URLSearchParams", - supported: "7.5.0", + supported: "7.5.0 (backported: ^6.13.0)", version: "7.4.9", }, }, @@ -4059,11 +4069,11 @@ new RuleTester({ }, { code: "require('util').TextDecoder", - options: [{ version: "8.3.0" }], + options: [{ version: "8.9.0" }], }, { code: "require('util').TextEncoder", - options: [{ version: "8.3.0" }], + options: [{ version: "8.9.0" }], }, { code: "require('util').types", @@ -4259,7 +4269,7 @@ new RuleTester({ messageId: "unsupported", data: { name: "util.getSystemErrorName", - supported: "9.7.0", + supported: "9.7.0 (backported: ^8.12.0)", version: "9.6.9", }, }, @@ -4323,28 +4333,28 @@ new RuleTester({ }, { code: "require('util').TextDecoder", - options: [{ version: "8.2.9" }], + options: [{ version: "8.8.9" }], errors: [ { messageId: "unsupported", data: { name: "util.TextDecoder", - supported: "8.3.0", - version: "8.2.9", + supported: "8.9.0", + version: "8.8.9", }, }, ], }, { code: "require('util').TextEncoder", - options: [{ version: "8.2.9" }], + options: [{ version: "8.8.9" }], errors: [ { messageId: "unsupported", data: { name: "util.TextEncoder", - supported: "8.3.0", - version: "8.2.9", + supported: "8.9.0", + version: "8.8.9", }, }, ],