No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.
 
 
 
 

130 líneas
3.5 KiB

  1. /**
  2. * @fileoverview Enforce boolean attributes notation in JSX
  3. * @author Yannick Croissant
  4. */
  5. 'use strict';
  6. const docsUrl = require('../util/docsUrl');
  7. // ------------------------------------------------------------------------------
  8. // Rule Definition
  9. // ------------------------------------------------------------------------------
  10. const exceptionsSchema = {
  11. type: 'array',
  12. items: {type: 'string', minLength: 1},
  13. uniqueItems: true
  14. };
  15. const ALWAYS = 'always';
  16. const NEVER = 'never';
  17. const errorData = new WeakMap();
  18. function getErrorData(exceptions) {
  19. if (!errorData.has(exceptions)) {
  20. const exceptionProps = Array.from(exceptions, name => `\`${name}\``).join(', ');
  21. const exceptionsMessage = exceptions.size > 0 ? ` for the following props: ${exceptionProps}` : '';
  22. errorData.set(exceptions, {exceptionsMessage: exceptionsMessage});
  23. }
  24. return errorData.get(exceptions);
  25. }
  26. function isAlways(configuration, exceptions, propName) {
  27. const isException = exceptions.has(propName);
  28. if (configuration === ALWAYS) {
  29. return !isException;
  30. }
  31. return isException;
  32. }
  33. function isNever(configuration, exceptions, propName) {
  34. const isException = exceptions.has(propName);
  35. if (configuration === NEVER) {
  36. return !isException;
  37. }
  38. return isException;
  39. }
  40. module.exports = {
  41. meta: {
  42. docs: {
  43. description: 'Enforce boolean attributes notation in JSX',
  44. category: 'Stylistic Issues',
  45. recommended: false,
  46. url: docsUrl('jsx-boolean-value')
  47. },
  48. fixable: 'code',
  49. schema: {
  50. anyOf: [{
  51. type: 'array',
  52. items: [{enum: [ALWAYS, NEVER]}],
  53. additionalItems: false
  54. }, {
  55. type: 'array',
  56. items: [{
  57. enum: [ALWAYS]
  58. }, {
  59. type: 'object',
  60. additionalProperties: false,
  61. properties: {
  62. [NEVER]: exceptionsSchema
  63. }
  64. }],
  65. additionalItems: false
  66. }, {
  67. type: 'array',
  68. items: [{
  69. enum: [NEVER]
  70. }, {
  71. type: 'object',
  72. additionalProperties: false,
  73. properties: {
  74. [ALWAYS]: exceptionsSchema
  75. }
  76. }],
  77. additionalItems: false
  78. }]
  79. }
  80. },
  81. create(context) {
  82. const configuration = context.options[0] || NEVER;
  83. const configObject = context.options[1] || {};
  84. const exceptions = new Set((configuration === ALWAYS ? configObject[NEVER] : configObject[ALWAYS]) || []);
  85. const NEVER_MESSAGE = 'Value must be omitted for boolean attributes{{exceptionsMessage}}';
  86. const ALWAYS_MESSAGE = 'Value must be set for boolean attributes{{exceptionsMessage}}';
  87. return {
  88. JSXAttribute(node) {
  89. const propName = node.name && node.name.name;
  90. const value = node.value;
  91. if (isAlways(configuration, exceptions, propName) && value === null) {
  92. const data = getErrorData(exceptions);
  93. context.report({
  94. node: node,
  95. message: ALWAYS_MESSAGE,
  96. data: data,
  97. fix(fixer) {
  98. return fixer.insertTextAfter(node, '={true}');
  99. }
  100. });
  101. }
  102. if (isNever(configuration, exceptions, propName) && value && value.type === 'JSXExpressionContainer' && value.expression.value === true) {
  103. const data = getErrorData(exceptions);
  104. context.report({
  105. node: node,
  106. message: NEVER_MESSAGE,
  107. data: data,
  108. fix(fixer) {
  109. return fixer.removeRange([node.name.range[1], value.range[1]]);
  110. }
  111. });
  112. }
  113. }
  114. };
  115. }
  116. };