UNPKG

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