Ohm-Management - Projektarbeit B-ME
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

no-restricted-imports.js 9.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. /**
  2. * @fileoverview Restrict usage of specified node imports.
  3. * @author Guy Ellis
  4. */
  5. "use strict";
  6. //------------------------------------------------------------------------------
  7. // Helpers
  8. //------------------------------------------------------------------------------
  9. const DEFAULT_MESSAGE_TEMPLATE = "'{{importSource}}' import is restricted from being used.";
  10. const CUSTOM_MESSAGE_TEMPLATE = "'{{importSource}}' import is restricted from being used. {{customMessage}}";
  11. //------------------------------------------------------------------------------
  12. // Rule Definition
  13. //------------------------------------------------------------------------------
  14. const ignore = require("ignore");
  15. const arrayOfStrings = {
  16. type: "array",
  17. items: { type: "string" },
  18. uniqueItems: true
  19. };
  20. const arrayOfStringsOrObjects = {
  21. type: "array",
  22. items: {
  23. anyOf: [
  24. { type: "string" },
  25. {
  26. type: "object",
  27. properties: {
  28. name: { type: "string" },
  29. message: {
  30. type: "string",
  31. minLength: 1
  32. },
  33. importNames: {
  34. type: "array",
  35. items: {
  36. type: "string"
  37. }
  38. }
  39. },
  40. additionalProperties: false,
  41. required: ["name"]
  42. }
  43. ]
  44. },
  45. uniqueItems: true
  46. };
  47. module.exports = {
  48. meta: {
  49. type: "suggestion",
  50. docs: {
  51. description: "disallow specified modules when loaded by `import`",
  52. category: "ECMAScript 6",
  53. recommended: false,
  54. url: "https://eslint.org/docs/rules/no-restricted-imports"
  55. },
  56. schema: {
  57. anyOf: [
  58. arrayOfStringsOrObjects,
  59. {
  60. type: "array",
  61. items: {
  62. type: "object",
  63. properties: {
  64. paths: arrayOfStringsOrObjects,
  65. patterns: arrayOfStrings
  66. },
  67. additionalProperties: false
  68. },
  69. additionalItems: false
  70. }
  71. ]
  72. }
  73. },
  74. create(context) {
  75. const options = Array.isArray(context.options) ? context.options : [];
  76. const isPathAndPatternsObject =
  77. typeof options[0] === "object" &&
  78. (Object.prototype.hasOwnProperty.call(options[0], "paths") || Object.prototype.hasOwnProperty.call(options[0], "patterns"));
  79. const restrictedPaths = (isPathAndPatternsObject ? options[0].paths : context.options) || [];
  80. const restrictedPatterns = (isPathAndPatternsObject ? options[0].patterns : []) || [];
  81. const restrictedPathMessages = restrictedPaths.reduce((memo, importSource) => {
  82. if (typeof importSource === "string") {
  83. memo[importSource] = { message: null };
  84. } else {
  85. memo[importSource.name] = {
  86. message: importSource.message,
  87. importNames: importSource.importNames
  88. };
  89. }
  90. return memo;
  91. }, {});
  92. // if no imports are restricted we don"t need to check
  93. if (Object.keys(restrictedPaths).length === 0 && restrictedPatterns.length === 0) {
  94. return {};
  95. }
  96. const restrictedPatternsMatcher = ignore().add(restrictedPatterns);
  97. /**
  98. * Checks to see if "*" is being used to import everything.
  99. * @param {Set.<string>} importNames - Set of import names that are being imported
  100. * @returns {boolean} whether everything is imported or not
  101. */
  102. function isEverythingImported(importNames) {
  103. return importNames.has("*");
  104. }
  105. /**
  106. * Report a restricted path.
  107. * @param {node} node representing the restricted path reference
  108. * @returns {void}
  109. * @private
  110. */
  111. function reportPath(node) {
  112. const importSource = node.source.value.trim();
  113. const customMessage = restrictedPathMessages[importSource] && restrictedPathMessages[importSource].message;
  114. const message = customMessage
  115. ? CUSTOM_MESSAGE_TEMPLATE
  116. : DEFAULT_MESSAGE_TEMPLATE;
  117. context.report({
  118. node,
  119. message,
  120. data: {
  121. importSource,
  122. customMessage
  123. }
  124. });
  125. }
  126. /**
  127. * Report a restricted path specifically for patterns.
  128. * @param {node} node - representing the restricted path reference
  129. * @returns {void}
  130. * @private
  131. */
  132. function reportPathForPatterns(node) {
  133. const importSource = node.source.value.trim();
  134. context.report({
  135. node,
  136. message: "'{{importSource}}' import is restricted from being used by a pattern.",
  137. data: {
  138. importSource
  139. }
  140. });
  141. }
  142. /**
  143. * Report a restricted path specifically when using the '*' import.
  144. * @param {string} importSource - path of the import
  145. * @param {node} node - representing the restricted path reference
  146. * @returns {void}
  147. * @private
  148. */
  149. function reportPathForEverythingImported(importSource, node) {
  150. const importNames = restrictedPathMessages[importSource].importNames;
  151. context.report({
  152. node,
  153. message: "* import is invalid because '{{importNames}}' from '{{importSource}}' is restricted.",
  154. data: {
  155. importSource,
  156. importNames
  157. }
  158. });
  159. }
  160. /**
  161. * Check if the given importSource is restricted because '*' is being imported.
  162. * @param {string} importSource - path of the import
  163. * @param {Set.<string>} importNames - Set of import names that are being imported
  164. * @returns {boolean} whether the path is restricted
  165. * @private
  166. */
  167. function isRestrictedForEverythingImported(importSource, importNames) {
  168. return Object.prototype.hasOwnProperty.call(restrictedPathMessages, importSource) &&
  169. restrictedPathMessages[importSource].importNames &&
  170. isEverythingImported(importNames);
  171. }
  172. /**
  173. * Check if the given importNames are restricted given a list of restrictedImportNames.
  174. * @param {Set.<string>} importNames - Set of import names that are being imported
  175. * @param {[string]} restrictedImportNames - array of import names that are restricted for this import
  176. * @returns {boolean} whether the objectName is restricted
  177. * @private
  178. */
  179. function isRestrictedObject(importNames, restrictedImportNames) {
  180. return restrictedImportNames.some(restrictedObjectName => (
  181. importNames.has(restrictedObjectName)
  182. ));
  183. }
  184. /**
  185. * Check if the given importSource is a restricted path.
  186. * @param {string} importSource - path of the import
  187. * @param {Set.<string>} importNames - Set of import names that are being imported
  188. * @returns {boolean} whether the variable is a restricted path or not
  189. * @private
  190. */
  191. function isRestrictedPath(importSource, importNames) {
  192. let isRestricted = false;
  193. if (Object.prototype.hasOwnProperty.call(restrictedPathMessages, importSource)) {
  194. if (restrictedPathMessages[importSource].importNames) {
  195. isRestricted = isRestrictedObject(importNames, restrictedPathMessages[importSource].importNames);
  196. } else {
  197. isRestricted = true;
  198. }
  199. }
  200. return isRestricted;
  201. }
  202. /**
  203. * Check if the given importSource is restricted by a pattern.
  204. * @param {string} importSource - path of the import
  205. * @returns {boolean} whether the variable is a restricted pattern or not
  206. * @private
  207. */
  208. function isRestrictedPattern(importSource) {
  209. return restrictedPatterns.length > 0 && restrictedPatternsMatcher.ignores(importSource);
  210. }
  211. /**
  212. * Checks a node to see if any problems should be reported.
  213. * @param {ASTNode} node The node to check.
  214. * @returns {void}
  215. * @private
  216. */
  217. function checkNode(node) {
  218. const importSource = node.source.value.trim();
  219. const importNames = node.specifiers ? node.specifiers.reduce((set, specifier) => {
  220. if (specifier.type === "ImportDefaultSpecifier") {
  221. set.add("default");
  222. } else if (specifier.type === "ImportNamespaceSpecifier") {
  223. set.add("*");
  224. } else if (specifier.imported) {
  225. set.add(specifier.imported.name);
  226. } else if (specifier.local) {
  227. set.add(specifier.local.name);
  228. }
  229. return set;
  230. }, new Set()) : new Set();
  231. if (isRestrictedForEverythingImported(importSource, importNames)) {
  232. reportPathForEverythingImported(importSource, node);
  233. }
  234. if (isRestrictedPath(importSource, importNames)) {
  235. reportPath(node);
  236. }
  237. if (isRestrictedPattern(importSource)) {
  238. reportPathForPatterns(node);
  239. }
  240. }
  241. return {
  242. ImportDeclaration: checkNode,
  243. ExportNamedDeclaration(node) {
  244. if (node.source) {
  245. checkNode(node);
  246. }
  247. },
  248. ExportAllDeclaration: checkNode
  249. };
  250. }
  251. };