forbid-elements.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. /**
  2. * @fileoverview Forbid certain elements
  3. * @author Kenneth Chung
  4. */
  5. 'use strict';
  6. const has = require('object.hasown/polyfill')();
  7. const docsUrl = require('../util/docsUrl');
  8. const isCreateElement = require('../util/isCreateElement');
  9. const report = require('../util/report');
  10. // ------------------------------------------------------------------------------
  11. // Rule Definition
  12. // ------------------------------------------------------------------------------
  13. const messages = {
  14. forbiddenElement: '<{{element}}> is forbidden',
  15. forbiddenElement_message: '<{{element}}> is forbidden, {{message}}',
  16. };
  17. module.exports = {
  18. meta: {
  19. docs: {
  20. description: 'Disallow certain elements',
  21. category: 'Best Practices',
  22. recommended: false,
  23. url: docsUrl('forbid-elements'),
  24. },
  25. messages,
  26. schema: [{
  27. type: 'object',
  28. properties: {
  29. forbid: {
  30. type: 'array',
  31. items: {
  32. anyOf: [
  33. { type: 'string' },
  34. {
  35. type: 'object',
  36. properties: {
  37. element: { type: 'string' },
  38. message: { type: 'string' },
  39. },
  40. required: ['element'],
  41. additionalProperties: false,
  42. },
  43. ],
  44. },
  45. },
  46. },
  47. additionalProperties: false,
  48. }],
  49. },
  50. create(context) {
  51. const configuration = context.options[0] || {};
  52. const forbidConfiguration = configuration.forbid || [];
  53. const indexedForbidConfigs = {};
  54. forbidConfiguration.forEach((item) => {
  55. if (typeof item === 'string') {
  56. indexedForbidConfigs[item] = { element: item };
  57. } else {
  58. indexedForbidConfigs[item.element] = item;
  59. }
  60. });
  61. function reportIfForbidden(element, node) {
  62. if (has(indexedForbidConfigs, element)) {
  63. const message = indexedForbidConfigs[element].message;
  64. report(
  65. context,
  66. message ? messages.forbiddenElement_message : messages.forbiddenElement,
  67. message ? 'forbiddenElement_message' : 'forbiddenElement',
  68. {
  69. node,
  70. data: {
  71. element,
  72. message,
  73. },
  74. }
  75. );
  76. }
  77. }
  78. return {
  79. JSXOpeningElement(node) {
  80. reportIfForbidden(context.getSourceCode().getText(node.name), node.name);
  81. },
  82. CallExpression(node) {
  83. if (!isCreateElement(node, context)) {
  84. return;
  85. }
  86. const argument = node.arguments[0];
  87. const argType = argument.type;
  88. if (argType === 'Identifier' && /^[A-Z_]/.test(argument.name)) {
  89. reportIfForbidden(argument.name, argument);
  90. } else if (argType === 'Literal' && /^[a-z][^.]*$/.test(argument.value)) {
  91. reportIfForbidden(argument.value, argument);
  92. } else if (argType === 'MemberExpression') {
  93. reportIfForbidden(context.getSourceCode().getText(argument), argument);
  94. }
  95. },
  96. };
  97. },
  98. };