Constnium/node_modules/eslint-plugin-n/lib/rules/no-deprecated-api.js
2022-06-23 02:27:43 +02:00

778 lines
22 KiB
JavaScript

/**
* @author Toru Nagashima
* See LICENSE file in root directory for full license.
*/
"use strict"
const { CALL, CONSTRUCT, READ, ReferenceTracker } = require("eslint-utils")
const enumeratePropertyNames = require("../util/enumerate-property-names")
const getConfiguredNodeVersion = require("../util/get-configured-node-version")
const getSemverRange = require("../util/get-semver-range")
const modules = {
_linklist: {
[READ]: { since: "5.0.0", replacedBy: null },
},
_stream_wrap: {
[READ]: { since: "12.0.0", replacedBy: null },
},
async_hooks: {
currentId: {
[READ]: {
since: "8.2.0",
replacedBy: [
{
name: "'async_hooks.executionAsyncId()'",
supported: "8.1.0",
},
],
},
},
triggerId: {
[READ]: {
since: "8.2.0",
replacedBy: "'async_hooks.triggerAsyncId()'",
},
},
},
buffer: {
Buffer: {
[CONSTRUCT]: {
since: "6.0.0",
replacedBy: [
{ name: "'buffer.Buffer.alloc()'", supported: "5.10.0" },
{ name: "'buffer.Buffer.from()'", supported: "5.10.0" },
],
},
[CALL]: {
since: "6.0.0",
replacedBy: [
{ name: "'buffer.Buffer.alloc()'", supported: "5.10.0" },
{ name: "'buffer.Buffer.from()'", supported: "5.10.0" },
],
},
},
SlowBuffer: {
[READ]: {
since: "6.0.0",
replacedBy: [
{
name: "'buffer.Buffer.allocUnsafeSlow()'",
supported: "5.12.0",
},
],
},
},
},
constants: {
[READ]: {
since: "6.3.0",
replacedBy: "'constants' property of each module",
},
},
crypto: {
_toBuf: {
[READ]: { since: "11.0.0", replacedBy: null },
},
Credentials: {
[READ]: { since: "0.12.0", replacedBy: "'tls.SecureContext'" },
},
DEFAULT_ENCODING: {
[READ]: { since: "10.0.0", replacedBy: null },
},
createCipher: {
[READ]: {
since: "10.0.0",
replacedBy: [
{ name: "'crypto.createCipheriv()'", supported: "0.1.94" },
],
},
},
createCredentials: {
[READ]: {
since: "0.12.0",
replacedBy: [
{
name: "'tls.createSecureContext()'",
supported: "0.11.13",
},
],
},
},
createDecipher: {
[READ]: {
since: "10.0.0",
replacedBy: [
{
name: "'crypto.createDecipheriv()'",
supported: "0.1.94",
},
],
},
},
fips: {
[READ]: {
since: "10.0.0",
replacedBy: [
{
name: "'crypto.getFips()' and 'crypto.setFips()'",
supported: "10.0.0",
},
],
},
},
prng: {
[READ]: {
since: "11.0.0",
replacedBy: [
{ name: "'crypto.randomBytes()'", supported: "0.5.8" },
],
},
},
pseudoRandomBytes: {
[READ]: {
since: "11.0.0",
replacedBy: [
{ name: "'crypto.randomBytes()'", supported: "0.5.8" },
],
},
},
rng: {
[READ]: {
since: "11.0.0",
replacedBy: [
{ name: "'crypto.randomBytes()'", supported: "0.5.8" },
],
},
},
},
domain: {
[READ]: { since: "4.0.0", replacedBy: null },
},
events: {
EventEmitter: {
listenerCount: {
[READ]: {
since: "4.0.0",
replacedBy: [
{
name: "'events.EventEmitter#listenerCount()'",
supported: "3.2.0",
},
],
},
},
},
listenerCount: {
[READ]: {
since: "4.0.0",
replacedBy: [
{
name: "'events.EventEmitter#listenerCount()'",
supported: "3.2.0",
},
],
},
},
},
freelist: {
[READ]: { since: "4.0.0", replacedBy: null },
},
fs: {
SyncWriteStream: {
[READ]: { since: "4.0.0", replacedBy: null },
},
exists: {
[READ]: {
since: "4.0.0",
replacedBy: [
{ name: "'fs.stat()'", supported: "0.0.2" },
{ name: "'fs.access()'", supported: "0.11.15" },
],
},
},
lchmod: {
[READ]: { since: "0.4.0", replacedBy: null },
},
lchmodSync: {
[READ]: { since: "0.4.0", replacedBy: null },
},
},
http: {
createClient: {
[READ]: {
since: "0.10.0",
replacedBy: [{ name: "'http.request()'", supported: "0.3.6" }],
},
},
},
module: {
Module: {
createRequireFromPath: {
[READ]: {
since: "12.2.0",
replacedBy: [
{
name: "'module.createRequire()'",
supported: "12.2.0",
},
],
},
},
requireRepl: {
[READ]: {
since: "6.0.0",
replacedBy: "'require(\"repl\")'",
},
},
_debug: {
[READ]: { since: "9.0.0", replacedBy: null },
},
},
createRequireFromPath: {
[READ]: {
since: "12.2.0",
replacedBy: [
{
name: "'module.createRequire()'",
supported: "12.2.0",
},
],
},
},
requireRepl: {
[READ]: {
since: "6.0.0",
replacedBy: "'require(\"repl\")'",
},
},
_debug: {
[READ]: { since: "9.0.0", replacedBy: null },
},
},
net: {
_setSimultaneousAccepts: {
[READ]: { since: "12.0.0", replacedBy: null },
},
},
os: {
getNetworkInterfaces: {
[READ]: {
since: "0.6.0",
replacedBy: [
{ name: "'os.networkInterfaces()'", supported: "0.6.0" },
],
},
},
tmpDir: {
[READ]: {
since: "7.0.0",
replacedBy: [{ name: "'os.tmpdir()'", supported: "0.9.9" }],
},
},
},
path: {
_makeLong: {
[READ]: {
since: "9.0.0",
replacedBy: [
{ name: "'path.toNamespacedPath()'", supported: "9.0.0" },
],
},
},
},
process: {
EventEmitter: {
[READ]: {
since: "0.6.0",
replacedBy: "'require(\"events\")'",
},
},
assert: {
[READ]: {
since: "10.0.0",
replacedBy: "'require(\"assert\")'",
},
},
binding: {
[READ]: { since: "10.9.0", replacedBy: null },
},
env: {
NODE_REPL_HISTORY_FILE: {
[READ]: {
since: "4.0.0",
replacedBy: "'NODE_REPL_HISTORY'",
},
},
},
report: {
triggerReport: {
[READ]: {
since: "11.12.0",
replacedBy: "'process.report.writeReport()'",
},
},
},
},
punycode: {
[READ]: {
since: "7.0.0",
replacedBy: "'https://www.npmjs.com/package/punycode'",
},
},
readline: {
codePointAt: {
[READ]: { since: "4.0.0", replacedBy: null },
},
getStringWidth: {
[READ]: { since: "6.0.0", replacedBy: null },
},
isFullWidthCodePoint: {
[READ]: { since: "6.0.0", replacedBy: null },
},
stripVTControlCharacters: {
[READ]: { since: "6.0.0", replacedBy: null },
},
},
// safe-buffer.Buffer function/constructror is just a re-export of buffer.Buffer
// and should be deprecated likewise.
"safe-buffer": {
Buffer: {
[CONSTRUCT]: {
since: "6.0.0",
replacedBy: [
{ name: "'buffer.Buffer.alloc()'", supported: "5.10.0" },
{ name: "'buffer.Buffer.from()'", supported: "5.10.0" },
],
},
[CALL]: {
since: "6.0.0",
replacedBy: [
{ name: "'buffer.Buffer.alloc()'", supported: "5.10.0" },
{ name: "'buffer.Buffer.from()'", supported: "5.10.0" },
],
},
},
SlowBuffer: {
[READ]: {
since: "6.0.0",
replacedBy: [
{
name: "'buffer.Buffer.allocUnsafeSlow()'",
supported: "5.12.0",
},
],
},
},
},
sys: {
[READ]: {
since: "0.3.0",
replacedBy: "'util' module",
},
},
timers: {
enroll: {
[READ]: {
since: "10.0.0",
replacedBy: [
{ name: "'setTimeout()'", supported: "0.0.1" },
{ name: "'setInterval()'", supported: "0.0.1" },
],
},
},
unenroll: {
[READ]: {
since: "10.0.0",
replacedBy: [
{ name: "'clearTimeout()'", supported: "0.0.1" },
{ name: "'clearInterval()'", supported: "0.0.1" },
],
},
},
},
tls: {
CleartextStream: {
[READ]: { since: "0.10.0", replacedBy: null },
},
CryptoStream: {
[READ]: {
since: "0.12.0",
replacedBy: [{ name: "'tls.TLSSocket'", supported: "0.11.4" }],
},
},
SecurePair: {
[READ]: {
since: "6.0.0",
replacedBy: [{ name: "'tls.TLSSocket'", supported: "0.11.4" }],
},
},
convertNPNProtocols: {
[READ]: { since: "10.0.0", replacedBy: null },
},
createSecurePair: {
[READ]: {
since: "6.0.0",
replacedBy: [{ name: "'tls.TLSSocket'", supported: "0.11.4" }],
},
},
parseCertString: {
[READ]: {
since: "8.6.0",
replacedBy: [
{ name: "'querystring.parse()'", supported: "0.1.25" },
],
},
},
},
tty: {
setRawMode: {
[READ]: {
since: "0.10.0",
replacedBy:
"'tty.ReadStream#setRawMode()' (e.g. 'process.stdin.setRawMode()')",
},
},
},
url: {
parse: {
[READ]: {
since: "11.0.0",
replacedBy: [
{ name: "'url.URL' constructor", supported: "6.13.0" },
],
},
},
resolve: {
[READ]: {
since: "11.0.0",
replacedBy: [
{ name: "'url.URL' constructor", supported: "6.13.0" },
],
},
},
},
util: {
debug: {
[READ]: {
since: "0.12.0",
replacedBy: [
{ name: "'console.error()'", supported: "0.1.100" },
],
},
},
error: {
[READ]: {
since: "0.12.0",
replacedBy: [
{ name: "'console.error()'", supported: "0.1.100" },
],
},
},
isArray: {
[READ]: {
since: "4.0.0",
replacedBy: [
{ name: "'Array.isArray()'", supported: "0.1.100" },
],
},
},
isBoolean: {
[READ]: { since: "4.0.0", replacedBy: null },
},
isBuffer: {
[READ]: {
since: "4.0.0",
replacedBy: [
{ name: "'Buffer.isBuffer()'", supported: "0.1.101" },
],
},
},
isDate: {
[READ]: { since: "4.0.0", replacedBy: null },
},
isError: {
[READ]: { since: "4.0.0", replacedBy: null },
},
isFunction: {
[READ]: { since: "4.0.0", replacedBy: null },
},
isNull: {
[READ]: { since: "4.0.0", replacedBy: null },
},
isNullOrUndefined: {
[READ]: { since: "4.0.0", replacedBy: null },
},
isNumber: {
[READ]: { since: "4.0.0", replacedBy: null },
},
isObject: {
[READ]: { since: "4.0.0", replacedBy: null },
},
isPrimitive: {
[READ]: { since: "4.0.0", replacedBy: null },
},
isRegExp: {
[READ]: { since: "4.0.0", replacedBy: null },
},
isString: {
[READ]: { since: "4.0.0", replacedBy: null },
},
isSymbol: {
[READ]: { since: "4.0.0", replacedBy: null },
},
isUndefined: {
[READ]: { since: "4.0.0", replacedBy: null },
},
log: {
[READ]: { since: "6.0.0", replacedBy: "a third party module" },
},
print: {
[READ]: {
since: "0.12.0",
replacedBy: [{ name: "'console.log()'", supported: "0.1.100" }],
},
},
pump: {
[READ]: {
since: "0.10.0",
replacedBy: [
{ name: "'stream.Readable#pipe()'", supported: "0.9.4" },
],
},
},
puts: {
[READ]: {
since: "0.12.0",
replacedBy: [{ name: "'console.log()'", supported: "0.1.100" }],
},
},
_extend: {
[READ]: {
since: "6.0.0",
replacedBy: [{ name: "'Object.assign()'", supported: "4.0.0" }],
},
},
},
vm: {
runInDebugContext: {
[READ]: { since: "8.0.0", replacedBy: null },
},
},
}
const globals = {
Buffer: {
[CONSTRUCT]: {
since: "6.0.0",
replacedBy: [
{ name: "'Buffer.alloc()'", supported: "5.10.0" },
{ name: "'Buffer.from()'", supported: "5.10.0" },
],
},
[CALL]: {
since: "6.0.0",
replacedBy: [
{ name: "'Buffer.alloc()'", supported: "5.10.0" },
{ name: "'Buffer.from()'", supported: "5.10.0" },
],
},
},
COUNTER_NET_SERVER_CONNECTION: {
[READ]: { since: "11.0.0", replacedBy: null },
},
COUNTER_NET_SERVER_CONNECTION_CLOSE: {
[READ]: { since: "11.0.0", replacedBy: null },
},
COUNTER_HTTP_SERVER_REQUEST: {
[READ]: { since: "11.0.0", replacedBy: null },
},
COUNTER_HTTP_SERVER_RESPONSE: {
[READ]: { since: "11.0.0", replacedBy: null },
},
COUNTER_HTTP_CLIENT_REQUEST: {
[READ]: { since: "11.0.0", replacedBy: null },
},
COUNTER_HTTP_CLIENT_RESPONSE: {
[READ]: { since: "11.0.0", replacedBy: null },
},
GLOBAL: {
[READ]: {
since: "6.0.0",
replacedBy: [{ name: "'global'", supported: "0.1.27" }],
},
},
Intl: {
v8BreakIterator: {
[READ]: { since: "7.0.0", replacedBy: null },
},
},
require: {
extensions: {
[READ]: {
since: "0.12.0",
replacedBy: "compiling them ahead of time",
},
},
},
root: {
[READ]: {
since: "6.0.0",
replacedBy: [{ name: "'global'", supported: "0.1.27" }],
},
},
process: modules.process,
}
/**
* Makes a replacement message.
*
* @param {string|array|null} replacedBy - The text of substitute way.
* @param {Range} version - The configured version range
* @returns {string} Replacement message.
*/
function toReplaceMessage(replacedBy, version) {
let message = replacedBy
if (Array.isArray(replacedBy)) {
message = replacedBy
.filter(
({ supported }) =>
!version.intersects(getSemverRange(`<${supported}`))
)
.map(({ name }) => name)
.join(" or ")
}
return message ? `. Use ${message} instead` : ""
}
/**
* Convert a given path to name.
* @param {symbol} type The report type.
* @param {string[]} path The property access path.
* @returns {string} The name.
*/
function toName(type, path) {
const baseName = path.join(".")
return type === ReferenceTracker.CALL
? `${baseName}()`
: type === ReferenceTracker.CONSTRUCT
? `new ${baseName}()`
: baseName
}
/**
* Parses the options.
* @param {RuleContext} context The rule context.
* @returns {{version:Range,ignoredGlobalItems:Set<string>,ignoredModuleItems:Set<string>}} Parsed
* value.
*/
function parseOptions(context) {
const raw = context.options[0] || {}
const filePath = context.getFilename()
const version = getConfiguredNodeVersion(raw.version, filePath)
const ignoredModuleItems = new Set(raw.ignoreModuleItems || [])
const ignoredGlobalItems = new Set(raw.ignoreGlobalItems || [])
return Object.freeze({ version, ignoredGlobalItems, ignoredModuleItems })
}
module.exports = {
meta: {
docs: {
description: "disallow deprecated APIs",
category: "Best Practices",
recommended: true,
url: "https://github.com/weiran-zsd/eslint-plugin-node/blob/HEAD/docs/rules/no-deprecated-api.md",
},
type: "problem",
fixable: null,
schema: [
{
type: "object",
properties: {
version: {
type: "string",
},
ignoreModuleItems: {
type: "array",
items: {
enum: Array.from(enumeratePropertyNames(modules)),
},
additionalItems: false,
uniqueItems: true,
},
ignoreGlobalItems: {
type: "array",
items: {
enum: Array.from(enumeratePropertyNames(globals)),
},
additionalItems: false,
uniqueItems: true,
},
// Deprecated since v4.2.0
ignoreIndirectDependencies: { type: "boolean" },
},
additionalProperties: false,
},
],
},
create(context) {
const { ignoredModuleItems, ignoredGlobalItems, version } =
parseOptions(context)
/**
* Reports a use of a deprecated API.
*
* @param {ASTNode} node - A node to report.
* @param {string} name - The name of a deprecated API.
* @param {{since: number, replacedBy: string}} info - Information of the API.
* @returns {void}
*/
function reportItem(node, name, info) {
context.report({
node,
loc: node.loc,
message:
"{{name}} was deprecated since v{{version}}{{replace}}.",
data: {
name,
version: info.since,
replace: toReplaceMessage(info.replacedBy, version),
},
})
}
return {
"Program:exit"() {
const tracker = new ReferenceTracker(context.getScope(), {
mode: "legacy",
})
for (const report of tracker.iterateGlobalReferences(globals)) {
const { node, path, type, info } = report
const name = toName(type, path)
if (!ignoredGlobalItems.has(name)) {
reportItem(node, `'${name}'`, info)
}
}
for (const report of [
...tracker.iterateCjsReferences(modules),
...tracker.iterateEsmReferences(modules),
]) {
const { node, path, type, info } = report
const name = toName(type, path)
const suffix = path.length === 1 ? " module" : ""
if (!ignoredModuleItems.has(name)) {
reportItem(node, `'${name}'${suffix}`, info)
}
}
},
}
},
}