jsx-first-prop-new-line.js 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. /**
  2. * @fileoverview Ensure proper position of the first property in JSX
  3. * @author Joachim Seminck
  4. */
  5. 'use strict';
  6. const docsUrl = require('../util/docsUrl');
  7. const report = require('../util/report');
  8. // ------------------------------------------------------------------------------
  9. // Rule Definition
  10. // ------------------------------------------------------------------------------
  11. const messages = {
  12. propOnNewLine: 'Property should be placed on a new line',
  13. propOnSameLine: 'Property should be placed on the same line as the component declaration',
  14. };
  15. module.exports = {
  16. meta: {
  17. docs: {
  18. description: 'Enforce proper position of the first property in JSX',
  19. category: 'Stylistic Issues',
  20. recommended: false,
  21. url: docsUrl('jsx-first-prop-new-line'),
  22. },
  23. fixable: 'code',
  24. messages,
  25. schema: [{
  26. enum: ['always', 'never', 'multiline', 'multiline-multiprop'],
  27. }],
  28. },
  29. create(context) {
  30. const configuration = context.options[0] || 'multiline-multiprop';
  31. function isMultilineJSX(jsxNode) {
  32. return jsxNode.loc.start.line < jsxNode.loc.end.line;
  33. }
  34. return {
  35. JSXOpeningElement(node) {
  36. if (
  37. (configuration === 'multiline' && isMultilineJSX(node))
  38. || (configuration === 'multiline-multiprop' && isMultilineJSX(node) && node.attributes.length > 1)
  39. || (configuration === 'always')
  40. ) {
  41. node.attributes.some((decl) => {
  42. if (decl.loc.start.line === node.loc.start.line) {
  43. report(context, messages.propOnNewLine, 'propOnNewLine', {
  44. node: decl,
  45. fix(fixer) {
  46. return fixer.replaceTextRange([node.name.range[1], decl.range[0]], '\n');
  47. },
  48. });
  49. }
  50. return true;
  51. });
  52. } else if (configuration === 'never' && node.attributes.length > 0) {
  53. const firstNode = node.attributes[0];
  54. if (node.loc.start.line < firstNode.loc.start.line) {
  55. report(context, messages.propOnSameLine, 'propOnSameLine', {
  56. node: firstNode,
  57. fix(fixer) {
  58. return fixer.replaceTextRange([node.name.range[1], firstNode.range[0]], ' ');
  59. },
  60. });
  61. }
  62. }
  63. },
  64. };
  65. },
  66. };