jsx-no-duplicate-props.js 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. /**
  2. * @fileoverview Enforce no duplicate props
  3. * @author Markus Ånöstam
  4. */
  5. 'use strict';
  6. const has = require('hasown');
  7. const docsUrl = require('../util/docsUrl');
  8. const report = require('../util/report');
  9. // ------------------------------------------------------------------------------
  10. // Rule Definition
  11. // ------------------------------------------------------------------------------
  12. const messages = {
  13. noDuplicateProps: 'No duplicate props allowed',
  14. };
  15. /** @type {import('eslint').Rule.RuleModule} */
  16. module.exports = {
  17. meta: {
  18. docs: {
  19. description: 'Disallow duplicate properties in JSX',
  20. category: 'Possible Errors',
  21. recommended: true,
  22. url: docsUrl('jsx-no-duplicate-props'),
  23. },
  24. messages,
  25. schema: [{
  26. type: 'object',
  27. properties: {
  28. ignoreCase: {
  29. type: 'boolean',
  30. },
  31. },
  32. additionalProperties: false,
  33. }],
  34. },
  35. create(context) {
  36. const configuration = context.options[0] || {};
  37. const ignoreCase = configuration.ignoreCase || false;
  38. return {
  39. JSXOpeningElement(node) {
  40. const props = {};
  41. node.attributes.forEach((decl) => {
  42. if (decl.type === 'JSXSpreadAttribute') {
  43. return;
  44. }
  45. let name = decl.name.name;
  46. if (typeof name !== 'string') {
  47. return;
  48. }
  49. if (ignoreCase) {
  50. name = name.toLowerCase();
  51. }
  52. if (has(props, name)) {
  53. report(context, messages.noDuplicateProps, 'noDuplicateProps', {
  54. node: decl,
  55. });
  56. } else {
  57. props[name] = 1;
  58. }
  59. });
  60. },
  61. };
  62. },
  63. };