no-deprecated-api.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782
  1. /**
  2. * @author Toru Nagashima
  3. * See LICENSE file in root directory for full license.
  4. */
  5. "use strict"
  6. const { CALL, CONSTRUCT, READ, ReferenceTracker } = require("eslint-utils")
  7. const enumeratePropertyNames = require("../util/enumerate-property-names")
  8. const getConfiguredNodeVersion = require("../util/get-configured-node-version")
  9. const getSemverRange = require("../util/get-semver-range")
  10. const modules = {
  11. _linklist: {
  12. [READ]: { since: "5.0.0", replacedBy: null },
  13. },
  14. //eslint-disable-next-line camelcase
  15. _stream_wrap: {
  16. [READ]: { since: "12.0.0", replacedBy: null },
  17. },
  18. //eslint-disable-next-line camelcase
  19. async_hooks: {
  20. currentId: {
  21. [READ]: {
  22. since: "8.2.0",
  23. replacedBy: [
  24. {
  25. name: "'async_hooks.executionAsyncId()'",
  26. supported: "8.1.0",
  27. },
  28. ],
  29. },
  30. },
  31. triggerId: {
  32. [READ]: {
  33. since: "8.2.0",
  34. replacedBy: "'async_hooks.triggerAsyncId()'",
  35. },
  36. },
  37. },
  38. buffer: {
  39. Buffer: {
  40. [CONSTRUCT]: {
  41. since: "6.0.0",
  42. replacedBy: [
  43. { name: "'buffer.Buffer.alloc()'", supported: "5.10.0" },
  44. { name: "'buffer.Buffer.from()'", supported: "5.10.0" },
  45. ],
  46. },
  47. [CALL]: {
  48. since: "6.0.0",
  49. replacedBy: [
  50. { name: "'buffer.Buffer.alloc()'", supported: "5.10.0" },
  51. { name: "'buffer.Buffer.from()'", supported: "5.10.0" },
  52. ],
  53. },
  54. },
  55. SlowBuffer: {
  56. [READ]: {
  57. since: "6.0.0",
  58. replacedBy: [
  59. {
  60. name: "'buffer.Buffer.allocUnsafeSlow()'",
  61. supported: "5.12.0",
  62. },
  63. ],
  64. },
  65. },
  66. },
  67. constants: {
  68. [READ]: {
  69. since: "6.3.0",
  70. replacedBy: "'constants' property of each module",
  71. },
  72. },
  73. crypto: {
  74. _toBuf: {
  75. [READ]: { since: "11.0.0", replacedBy: null },
  76. },
  77. Credentials: {
  78. [READ]: { since: "0.12.0", replacedBy: "'tls.SecureContext'" },
  79. },
  80. DEFAULT_ENCODING: {
  81. [READ]: { since: "10.0.0", replacedBy: null },
  82. },
  83. createCipher: {
  84. [READ]: {
  85. since: "10.0.0",
  86. replacedBy: [
  87. { name: "'crypto.createCipheriv()'", supported: "0.1.94" },
  88. ],
  89. },
  90. },
  91. createCredentials: {
  92. [READ]: {
  93. since: "0.12.0",
  94. replacedBy: [
  95. {
  96. name: "'tls.createSecureContext()'",
  97. supported: "0.11.13",
  98. },
  99. ],
  100. },
  101. },
  102. createDecipher: {
  103. [READ]: {
  104. since: "10.0.0",
  105. replacedBy: [
  106. {
  107. name: "'crypto.createDecipheriv()'",
  108. supported: "0.1.94",
  109. },
  110. ],
  111. },
  112. },
  113. fips: {
  114. [READ]: {
  115. since: "10.0.0",
  116. replacedBy: [
  117. {
  118. name: "'crypto.getFips()' and 'crypto.setFips()'",
  119. supported: "10.0.0",
  120. },
  121. ],
  122. },
  123. },
  124. prng: {
  125. [READ]: {
  126. since: "11.0.0",
  127. replacedBy: [
  128. { name: "'crypto.randomBytes()'", supported: "0.5.8" },
  129. ],
  130. },
  131. },
  132. pseudoRandomBytes: {
  133. [READ]: {
  134. since: "11.0.0",
  135. replacedBy: [
  136. { name: "'crypto.randomBytes()'", supported: "0.5.8" },
  137. ],
  138. },
  139. },
  140. rng: {
  141. [READ]: {
  142. since: "11.0.0",
  143. replacedBy: [
  144. { name: "'crypto.randomBytes()'", supported: "0.5.8" },
  145. ],
  146. },
  147. },
  148. },
  149. domain: {
  150. [READ]: { since: "4.0.0", replacedBy: null },
  151. },
  152. events: {
  153. EventEmitter: {
  154. listenerCount: {
  155. [READ]: {
  156. since: "4.0.0",
  157. replacedBy: [
  158. {
  159. name: "'events.EventEmitter#listenerCount()'",
  160. supported: "3.2.0",
  161. },
  162. ],
  163. },
  164. },
  165. },
  166. listenerCount: {
  167. [READ]: {
  168. since: "4.0.0",
  169. replacedBy: [
  170. {
  171. name: "'events.EventEmitter#listenerCount()'",
  172. supported: "3.2.0",
  173. },
  174. ],
  175. },
  176. },
  177. },
  178. freelist: {
  179. [READ]: { since: "4.0.0", replacedBy: null },
  180. },
  181. fs: {
  182. SyncWriteStream: {
  183. [READ]: { since: "4.0.0", replacedBy: null },
  184. },
  185. exists: {
  186. [READ]: {
  187. since: "4.0.0",
  188. replacedBy: [
  189. { name: "'fs.stat()'", supported: "0.0.2" },
  190. { name: "'fs.access()'", supported: "0.11.15" },
  191. ],
  192. },
  193. },
  194. lchmod: {
  195. [READ]: { since: "0.4.0", replacedBy: null },
  196. },
  197. lchmodSync: {
  198. [READ]: { since: "0.4.0", replacedBy: null },
  199. },
  200. },
  201. http: {
  202. createClient: {
  203. [READ]: {
  204. since: "0.10.0",
  205. replacedBy: [{ name: "'http.request()'", supported: "0.3.6" }],
  206. },
  207. },
  208. },
  209. module: {
  210. Module: {
  211. createRequireFromPath: {
  212. [READ]: {
  213. since: "12.2.0",
  214. replacedBy: [
  215. {
  216. name: "'module.createRequire()'",
  217. supported: "12.2.0",
  218. },
  219. ],
  220. },
  221. },
  222. requireRepl: {
  223. [READ]: {
  224. since: "6.0.0",
  225. replacedBy: "'require(\"repl\")'",
  226. },
  227. },
  228. _debug: {
  229. [READ]: { since: "9.0.0", replacedBy: null },
  230. },
  231. },
  232. createRequireFromPath: {
  233. [READ]: {
  234. since: "12.2.0",
  235. replacedBy: [
  236. {
  237. name: "'module.createRequire()'",
  238. supported: "12.2.0",
  239. },
  240. ],
  241. },
  242. },
  243. requireRepl: {
  244. [READ]: {
  245. since: "6.0.0",
  246. replacedBy: "'require(\"repl\")'",
  247. },
  248. },
  249. _debug: {
  250. [READ]: { since: "9.0.0", replacedBy: null },
  251. },
  252. },
  253. net: {
  254. _setSimultaneousAccepts: {
  255. [READ]: { since: "12.0.0", replacedBy: null },
  256. },
  257. },
  258. os: {
  259. getNetworkInterfaces: {
  260. [READ]: {
  261. since: "0.6.0",
  262. replacedBy: [
  263. { name: "'os.networkInterfaces()'", supported: "0.6.0" },
  264. ],
  265. },
  266. },
  267. tmpDir: {
  268. [READ]: {
  269. since: "7.0.0",
  270. replacedBy: [{ name: "'os.tmpdir()'", supported: "0.9.9" }],
  271. },
  272. },
  273. },
  274. path: {
  275. _makeLong: {
  276. [READ]: {
  277. since: "9.0.0",
  278. replacedBy: [
  279. { name: "'path.toNamespacedPath()'", supported: "9.0.0" },
  280. ],
  281. },
  282. },
  283. },
  284. process: {
  285. EventEmitter: {
  286. [READ]: {
  287. since: "0.6.0",
  288. replacedBy: "'require(\"events\")'",
  289. },
  290. },
  291. assert: {
  292. [READ]: {
  293. since: "10.0.0",
  294. replacedBy: "'require(\"assert\")'",
  295. },
  296. },
  297. binding: {
  298. [READ]: { since: "10.9.0", replacedBy: null },
  299. },
  300. env: {
  301. NODE_REPL_HISTORY_FILE: {
  302. [READ]: {
  303. since: "4.0.0",
  304. replacedBy: "'NODE_REPL_HISTORY'",
  305. },
  306. },
  307. },
  308. report: {
  309. triggerReport: {
  310. [READ]: {
  311. since: "11.12.0",
  312. replacedBy: "'process.report.writeReport()'",
  313. },
  314. },
  315. },
  316. },
  317. punycode: {
  318. [READ]: {
  319. since: "7.0.0",
  320. replacedBy: "'https://www.npmjs.com/package/punycode'",
  321. },
  322. },
  323. readline: {
  324. codePointAt: {
  325. [READ]: { since: "4.0.0", replacedBy: null },
  326. },
  327. getStringWidth: {
  328. [READ]: { since: "6.0.0", replacedBy: null },
  329. },
  330. isFullWidthCodePoint: {
  331. [READ]: { since: "6.0.0", replacedBy: null },
  332. },
  333. stripVTControlCharacters: {
  334. [READ]: { since: "6.0.0", replacedBy: null },
  335. },
  336. },
  337. // safe-buffer.Buffer function/constructror is just a re-export of buffer.Buffer
  338. // and should be deprecated likewise.
  339. "safe-buffer": {
  340. Buffer: {
  341. [CONSTRUCT]: {
  342. since: "6.0.0",
  343. replacedBy: [
  344. { name: "'buffer.Buffer.alloc()'", supported: "5.10.0" },
  345. { name: "'buffer.Buffer.from()'", supported: "5.10.0" },
  346. ],
  347. },
  348. [CALL]: {
  349. since: "6.0.0",
  350. replacedBy: [
  351. { name: "'buffer.Buffer.alloc()'", supported: "5.10.0" },
  352. { name: "'buffer.Buffer.from()'", supported: "5.10.0" },
  353. ],
  354. },
  355. },
  356. SlowBuffer: {
  357. [READ]: {
  358. since: "6.0.0",
  359. replacedBy: [
  360. {
  361. name: "'buffer.Buffer.allocUnsafeSlow()'",
  362. supported: "5.12.0",
  363. },
  364. ],
  365. },
  366. },
  367. },
  368. sys: {
  369. [READ]: {
  370. since: "0.3.0",
  371. replacedBy: "'util' module",
  372. },
  373. },
  374. timers: {
  375. enroll: {
  376. [READ]: {
  377. since: "10.0.0",
  378. replacedBy: [
  379. { name: "'setTimeout()'", supported: "0.0.1" },
  380. { name: "'setInterval()'", supported: "0.0.1" },
  381. ],
  382. },
  383. },
  384. unenroll: {
  385. [READ]: {
  386. since: "10.0.0",
  387. replacedBy: [
  388. { name: "'clearTimeout()'", supported: "0.0.1" },
  389. { name: "'clearInterval()'", supported: "0.0.1" },
  390. ],
  391. },
  392. },
  393. },
  394. tls: {
  395. CleartextStream: {
  396. [READ]: { since: "0.10.0", replacedBy: null },
  397. },
  398. CryptoStream: {
  399. [READ]: {
  400. since: "0.12.0",
  401. replacedBy: [{ name: "'tls.TLSSocket'", supported: "0.11.4" }],
  402. },
  403. },
  404. SecurePair: {
  405. [READ]: {
  406. since: "6.0.0",
  407. replacedBy: [{ name: "'tls.TLSSocket'", supported: "0.11.4" }],
  408. },
  409. },
  410. convertNPNProtocols: {
  411. [READ]: { since: "10.0.0", replacedBy: null },
  412. },
  413. createSecurePair: {
  414. [READ]: {
  415. since: "6.0.0",
  416. replacedBy: [{ name: "'tls.TLSSocket'", supported: "0.11.4" }],
  417. },
  418. },
  419. parseCertString: {
  420. [READ]: {
  421. since: "8.6.0",
  422. replacedBy: [
  423. { name: "'querystring.parse()'", supported: "0.1.25" },
  424. ],
  425. },
  426. },
  427. },
  428. tty: {
  429. setRawMode: {
  430. [READ]: {
  431. since: "0.10.0",
  432. replacedBy:
  433. "'tty.ReadStream#setRawMode()' (e.g. 'process.stdin.setRawMode()')",
  434. },
  435. },
  436. },
  437. url: {
  438. parse: {
  439. [READ]: {
  440. since: "11.0.0",
  441. replacedBy: [
  442. { name: "'url.URL' constructor", supported: "6.13.0" },
  443. ],
  444. },
  445. },
  446. resolve: {
  447. [READ]: {
  448. since: "11.0.0",
  449. replacedBy: [
  450. { name: "'url.URL' constructor", supported: "6.13.0" },
  451. ],
  452. },
  453. },
  454. },
  455. util: {
  456. debug: {
  457. [READ]: {
  458. since: "0.12.0",
  459. replacedBy: [
  460. { name: "'console.error()'", supported: "0.1.100" },
  461. ],
  462. },
  463. },
  464. error: {
  465. [READ]: {
  466. since: "0.12.0",
  467. replacedBy: [
  468. { name: "'console.error()'", supported: "0.1.100" },
  469. ],
  470. },
  471. },
  472. isArray: {
  473. [READ]: {
  474. since: "4.0.0",
  475. replacedBy: [
  476. { name: "'Array.isArray()'", supported: "0.1.100" },
  477. ],
  478. },
  479. },
  480. isBoolean: {
  481. [READ]: { since: "4.0.0", replacedBy: null },
  482. },
  483. isBuffer: {
  484. [READ]: {
  485. since: "4.0.0",
  486. replacedBy: [
  487. { name: "'Buffer.isBuffer()'", supported: "0.1.101" },
  488. ],
  489. },
  490. },
  491. isDate: {
  492. [READ]: { since: "4.0.0", replacedBy: null },
  493. },
  494. isError: {
  495. [READ]: { since: "4.0.0", replacedBy: null },
  496. },
  497. isFunction: {
  498. [READ]: { since: "4.0.0", replacedBy: null },
  499. },
  500. isNull: {
  501. [READ]: { since: "4.0.0", replacedBy: null },
  502. },
  503. isNullOrUndefined: {
  504. [READ]: { since: "4.0.0", replacedBy: null },
  505. },
  506. isNumber: {
  507. [READ]: { since: "4.0.0", replacedBy: null },
  508. },
  509. isObject: {
  510. [READ]: { since: "4.0.0", replacedBy: null },
  511. },
  512. isPrimitive: {
  513. [READ]: { since: "4.0.0", replacedBy: null },
  514. },
  515. isRegExp: {
  516. [READ]: { since: "4.0.0", replacedBy: null },
  517. },
  518. isString: {
  519. [READ]: { since: "4.0.0", replacedBy: null },
  520. },
  521. isSymbol: {
  522. [READ]: { since: "4.0.0", replacedBy: null },
  523. },
  524. isUndefined: {
  525. [READ]: { since: "4.0.0", replacedBy: null },
  526. },
  527. log: {
  528. [READ]: { since: "6.0.0", replacedBy: "a third party module" },
  529. },
  530. print: {
  531. [READ]: {
  532. since: "0.12.0",
  533. replacedBy: [{ name: "'console.log()'", supported: "0.1.100" }],
  534. },
  535. },
  536. pump: {
  537. [READ]: {
  538. since: "0.10.0",
  539. replacedBy: [
  540. { name: "'stream.Readable#pipe()'", supported: "0.9.4" },
  541. ],
  542. },
  543. },
  544. puts: {
  545. [READ]: {
  546. since: "0.12.0",
  547. replacedBy: [{ name: "'console.log()'", supported: "0.1.100" }],
  548. },
  549. },
  550. _extend: {
  551. [READ]: {
  552. since: "6.0.0",
  553. replacedBy: [{ name: "'Object.assign()'", supported: "4.0.0" }],
  554. },
  555. },
  556. },
  557. vm: {
  558. runInDebugContext: {
  559. [READ]: { since: "8.0.0", replacedBy: null },
  560. },
  561. },
  562. }
  563. const globals = {
  564. Buffer: {
  565. [CONSTRUCT]: {
  566. since: "6.0.0",
  567. replacedBy: [
  568. { name: "'Buffer.alloc()'", supported: "5.10.0" },
  569. { name: "'Buffer.from()'", supported: "5.10.0" },
  570. ],
  571. },
  572. [CALL]: {
  573. since: "6.0.0",
  574. replacedBy: [
  575. { name: "'Buffer.alloc()'", supported: "5.10.0" },
  576. { name: "'Buffer.from()'", supported: "5.10.0" },
  577. ],
  578. },
  579. },
  580. COUNTER_NET_SERVER_CONNECTION: {
  581. [READ]: { since: "11.0.0", replacedBy: null },
  582. },
  583. COUNTER_NET_SERVER_CONNECTION_CLOSE: {
  584. [READ]: { since: "11.0.0", replacedBy: null },
  585. },
  586. COUNTER_HTTP_SERVER_REQUEST: {
  587. [READ]: { since: "11.0.0", replacedBy: null },
  588. },
  589. COUNTER_HTTP_SERVER_RESPONSE: {
  590. [READ]: { since: "11.0.0", replacedBy: null },
  591. },
  592. COUNTER_HTTP_CLIENT_REQUEST: {
  593. [READ]: { since: "11.0.0", replacedBy: null },
  594. },
  595. COUNTER_HTTP_CLIENT_RESPONSE: {
  596. [READ]: { since: "11.0.0", replacedBy: null },
  597. },
  598. GLOBAL: {
  599. [READ]: {
  600. since: "6.0.0",
  601. replacedBy: [{ name: "'global'", supported: "0.1.27" }],
  602. },
  603. },
  604. Intl: {
  605. v8BreakIterator: {
  606. [READ]: { since: "7.0.0", replacedBy: null },
  607. },
  608. },
  609. require: {
  610. extensions: {
  611. [READ]: {
  612. since: "0.12.0",
  613. replacedBy: "compiling them ahead of time",
  614. },
  615. },
  616. },
  617. root: {
  618. [READ]: {
  619. since: "6.0.0",
  620. replacedBy: [{ name: "'global'", supported: "0.1.27" }],
  621. },
  622. },
  623. process: modules.process,
  624. }
  625. /**
  626. * Makes a replacement message.
  627. *
  628. * @param {string|array|null} replacedBy - The text of substitute way.
  629. * @param {Range} version - The configured version range
  630. * @returns {string} Replacement message.
  631. */
  632. function toReplaceMessage(replacedBy, version) {
  633. let message = replacedBy
  634. if (Array.isArray(replacedBy)) {
  635. message = replacedBy
  636. .filter(
  637. ({ supported }) =>
  638. !version.intersects(getSemverRange(`<${supported}`))
  639. )
  640. .map(({ name }) => name)
  641. .join(" or ")
  642. }
  643. return message ? `. Use ${message} instead` : ""
  644. }
  645. /**
  646. * Convert a given path to name.
  647. * @param {symbol} type The report type.
  648. * @param {string[]} path The property access path.
  649. * @returns {string} The name.
  650. */
  651. function toName(type, path) {
  652. const baseName = path.join(".")
  653. return type === ReferenceTracker.CALL
  654. ? `${baseName}()`
  655. : type === ReferenceTracker.CONSTRUCT
  656. ? `new ${baseName}()`
  657. : baseName
  658. }
  659. /**
  660. * Parses the options.
  661. * @param {RuleContext} context The rule context.
  662. * @returns {{version:Range,ignoredGlobalItems:Set<string>,ignoredModuleItems:Set<string>}} Parsed
  663. * value.
  664. */
  665. function parseOptions(context) {
  666. const raw = context.options[0] || {}
  667. const filePath = context.getFilename()
  668. const version = getConfiguredNodeVersion(raw.version, filePath)
  669. const ignoredModuleItems = new Set(raw.ignoreModuleItems || [])
  670. const ignoredGlobalItems = new Set(raw.ignoreGlobalItems || [])
  671. return Object.freeze({ version, ignoredGlobalItems, ignoredModuleItems })
  672. }
  673. module.exports = {
  674. meta: {
  675. docs: {
  676. description: "disallow deprecated APIs",
  677. category: "Best Practices",
  678. recommended: true,
  679. url:
  680. "https://github.com/mysticatea/eslint-plugin-node/blob/v11.1.0/docs/rules/no-deprecated-api.md",
  681. },
  682. type: "problem",
  683. fixable: null,
  684. schema: [
  685. {
  686. type: "object",
  687. properties: {
  688. version: {
  689. type: "string",
  690. },
  691. ignoreModuleItems: {
  692. type: "array",
  693. items: {
  694. enum: Array.from(enumeratePropertyNames(modules)),
  695. },
  696. additionalItems: false,
  697. uniqueItems: true,
  698. },
  699. ignoreGlobalItems: {
  700. type: "array",
  701. items: {
  702. enum: Array.from(enumeratePropertyNames(globals)),
  703. },
  704. additionalItems: false,
  705. uniqueItems: true,
  706. },
  707. // Deprecated since v4.2.0
  708. ignoreIndirectDependencies: { type: "boolean" },
  709. },
  710. additionalProperties: false,
  711. },
  712. ],
  713. },
  714. create(context) {
  715. const {
  716. ignoredModuleItems,
  717. ignoredGlobalItems,
  718. version,
  719. } = parseOptions(context)
  720. /**
  721. * Reports a use of a deprecated API.
  722. *
  723. * @param {ASTNode} node - A node to report.
  724. * @param {string} name - The name of a deprecated API.
  725. * @param {{since: number, replacedBy: string}} info - Information of the API.
  726. * @returns {void}
  727. */
  728. function reportItem(node, name, info) {
  729. context.report({
  730. node,
  731. loc: node.loc,
  732. message:
  733. "{{name}} was deprecated since v{{version}}{{replace}}.",
  734. data: {
  735. name,
  736. version: info.since,
  737. replace: toReplaceMessage(info.replacedBy, version),
  738. },
  739. })
  740. }
  741. return {
  742. "Program:exit"() {
  743. const tracker = new ReferenceTracker(context.getScope(), {
  744. mode: "legacy",
  745. })
  746. for (const report of tracker.iterateGlobalReferences(globals)) {
  747. const { node, path, type, info } = report
  748. const name = toName(type, path)
  749. if (!ignoredGlobalItems.has(name)) {
  750. reportItem(node, `'${name}'`, info)
  751. }
  752. }
  753. for (const report of [
  754. ...tracker.iterateCjsReferences(modules),
  755. ...tracker.iterateEsmReferences(modules),
  756. ]) {
  757. const { node, path, type, info } = report
  758. const name = toName(type, path)
  759. const suffix = path.length === 1 ? " module" : ""
  760. if (!ignoredModuleItems.has(name)) {
  761. reportItem(node, `'${name}'${suffix}`, info)
  762. }
  763. }
  764. },
  765. }
  766. },
  767. }