no-hide-core-modules.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. /**
  2. * @author Toru Nagashima
  3. * See LICENSE file in root directory for full license.
  4. *
  5. * @deprecated since v4.2.0
  6. * This rule was based on an invalid assumption.
  7. * No meaning.
  8. */
  9. "use strict"
  10. const path = require("path")
  11. const resolve = require("resolve")
  12. const { pathToFileURL, fileURLToPath } = require("url")
  13. const {
  14. defaultResolve: importResolve,
  15. } = require("../converted-esm/import-meta-resolve")
  16. const getPackageJson = require("../util/get-package-json")
  17. const mergeVisitorsInPlace = require("../util/merge-visitors-in-place")
  18. const visitImport = require("../util/visit-import")
  19. const visitRequire = require("../util/visit-require")
  20. const CORE_MODULES = new Set([
  21. "assert",
  22. "buffer",
  23. "child_process",
  24. "cluster",
  25. "console",
  26. "constants",
  27. "crypto",
  28. "dgram",
  29. "dns",
  30. /* "domain", */ "events",
  31. "fs",
  32. "http",
  33. "https",
  34. "module",
  35. "net",
  36. "os",
  37. "path",
  38. /* "punycode", */ "querystring",
  39. "readline",
  40. "repl",
  41. "stream",
  42. "string_decoder",
  43. "timers",
  44. "tls",
  45. "tty",
  46. "url",
  47. "util",
  48. "vm",
  49. "zlib",
  50. ])
  51. const BACK_SLASH = /\\/gu
  52. module.exports = {
  53. meta: {
  54. docs: {
  55. description:
  56. "disallow third-party modules which are hiding core modules",
  57. category: "Possible Errors",
  58. recommended: false,
  59. url: "https://github.com/weiran-zsd/eslint-plugin-node/blob/HEAD/docs/rules/no-hide-core-modules.md",
  60. },
  61. type: "problem",
  62. deprecated: true,
  63. fixable: null,
  64. schema: [
  65. {
  66. type: "object",
  67. properties: {
  68. allow: {
  69. type: "array",
  70. items: { enum: Array.from(CORE_MODULES) },
  71. additionalItems: false,
  72. uniqueItems: true,
  73. },
  74. ignoreDirectDependencies: { type: "boolean" },
  75. ignoreIndirectDependencies: { type: "boolean" },
  76. },
  77. additionalProperties: false,
  78. },
  79. ],
  80. messages: {
  81. "unexpectedImport": "Unexpected import of third-party module '{{name}}'.",
  82. }
  83. },
  84. create(context) {
  85. if (context.getFilename() === "<input>") {
  86. return {}
  87. }
  88. const filePath = path.resolve(context.getFilename())
  89. const dirPath = path.dirname(filePath)
  90. const packageJson = getPackageJson(filePath)
  91. const deps = new Set(
  92. [].concat(
  93. Object.keys((packageJson && packageJson.dependencies) || {}),
  94. Object.keys((packageJson && packageJson.devDependencies) || {})
  95. )
  96. )
  97. const options = context.options[0] || {}
  98. const allow = options.allow || []
  99. const ignoreDirectDependencies = Boolean(
  100. options.ignoreDirectDependencies
  101. )
  102. const ignoreIndirectDependencies = Boolean(
  103. options.ignoreIndirectDependencies
  104. )
  105. const targets = []
  106. return [
  107. visitImport(context, { includeCore: true }, importTargets =>
  108. targets.push(...importTargets)
  109. ),
  110. visitRequire(context, { includeCore: true }, requireTargets =>
  111. targets.push(...requireTargets)
  112. ),
  113. {
  114. "Program:exit"() {
  115. for (const target of targets.filter(
  116. t =>
  117. CORE_MODULES.has(t.moduleName) &&
  118. t.moduleName === t.name
  119. )) {
  120. const name = target.moduleName
  121. const allowed =
  122. allow.indexOf(name) !== -1 ||
  123. (ignoreDirectDependencies && deps.has(name)) ||
  124. (ignoreIndirectDependencies && !deps.has(name))
  125. if (allowed) {
  126. continue
  127. }
  128. let resolved = ""
  129. const moduleId = `${name}/`
  130. try {
  131. resolved = resolve.sync(moduleId, {
  132. basedir: dirPath,
  133. })
  134. } catch (_error) {
  135. try {
  136. const { url } = importResolve(moduleId, {
  137. parentURL: pathToFileURL(dirPath).href,
  138. })
  139. resolved = fileURLToPath(url)
  140. } catch (_error) {
  141. continue
  142. }
  143. }
  144. context.report({
  145. node: target.node,
  146. loc: target.node.loc,
  147. messageId: "unexpectedImport",
  148. data: {
  149. name: path
  150. .relative(dirPath, resolved)
  151. .replace(BACK_SLASH, "/"),
  152. },
  153. })
  154. }
  155. },
  156. },
  157. ].reduce(
  158. (mergedVisitor, thisVisitor) =>
  159. mergeVisitorsInPlace(mergedVisitor, thisVisitor),
  160. {}
  161. )
  162. },
  163. }