jsx-closing-tag-location.js 1.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. /**
  2. * @fileoverview Validate closing tag location in JSX
  3. * @author Ross Solomon
  4. */
  5. 'use strict';
  6. const astUtil = require('../util/ast');
  7. const docsUrl = require('../util/docsUrl');
  8. // ------------------------------------------------------------------------------
  9. // Rule Definition
  10. // ------------------------------------------------------------------------------
  11. module.exports = {
  12. meta: {
  13. docs: {
  14. description: 'Validate closing tag location for multiline JSX',
  15. category: 'Stylistic Issues',
  16. recommended: false,
  17. url: docsUrl('jsx-closing-tag-location')
  18. },
  19. fixable: 'whitespace'
  20. },
  21. create: function(context) {
  22. return {
  23. JSXClosingElement: function(node) {
  24. if (!node.parent) {
  25. return;
  26. }
  27. const opening = node.parent.openingElement;
  28. if (opening.loc.start.line === node.loc.start.line) {
  29. return;
  30. }
  31. if (opening.loc.start.column === node.loc.start.column) {
  32. return;
  33. }
  34. let message;
  35. if (!astUtil.isNodeFirstInLine(context, node)) {
  36. message = 'Closing tag of a multiline JSX expression must be on its own line.';
  37. } else {
  38. message = 'Expected closing tag to match indentation of opening.';
  39. }
  40. context.report({
  41. node: node,
  42. loc: node.loc,
  43. message,
  44. fix: function(fixer) {
  45. const indent = Array(opening.loc.start.column + 1).join(' ');
  46. if (astUtil.isNodeFirstInLine(context, node)) {
  47. return fixer.replaceTextRange(
  48. [node.range[0] - node.loc.start.column, node.range[0]],
  49. indent
  50. );
  51. }
  52. return fixer.insertTextBefore(node, `\n${indent}`);
  53. }
  54. });
  55. }
  56. };
  57. }
  58. };