UNPKG

2.55 kBJavaScriptView Raw
1'use strict';
2
3const docsUrl = require('../util/docsUrl');
4
5// This list is taken from https://developer.mozilla.org/en-US/docs/Web/HTML/Inline_elements
6const INLINE_ELEMENTS = new Set([
7 'a',
8 'abbr',
9 'acronym',
10 'b',
11 'bdo',
12 'big',
13 'br',
14 'button',
15 'cite',
16 'code',
17 'dfn',
18 'em',
19 'i',
20 'img',
21 'input',
22 'kbd',
23 'label',
24 'map',
25 'object',
26 'q',
27 'samp',
28 'script',
29 'select',
30 'small',
31 'span',
32 'strong',
33 'sub',
34 'sup',
35 'textarea',
36 'tt',
37 'var'
38]);
39
40module.exports = {
41 meta: {
42 docs: {
43 description: 'Ensures inline tags are not rendered without spaces between them',
44 category: 'Stylistic Issues',
45 recommended: false,
46 url: docsUrl('jsx-child-element-spacing')
47 },
48 fixable: null,
49 schema: [
50 {
51 type: 'object',
52 properties: {},
53 default: {},
54 additionalProperties: false
55 }
56 ]
57 },
58 create(context) {
59 const TEXT_FOLLOWING_ELEMENT_PATTERN = /^\s*\n\s*\S/;
60 const TEXT_PRECEDING_ELEMENT_PATTERN = /\S\s*\n\s*$/;
61
62 const elementName = (node) => (
63 node.openingElement
64 && node.openingElement.name
65 && node.openingElement.name.type === 'JSXIdentifier'
66 && node.openingElement.name.name
67 );
68
69 const isInlineElement = (node) => (
70 node.type === 'JSXElement'
71 && INLINE_ELEMENTS.has(elementName(node))
72 );
73
74 const handleJSX = (node) => {
75 let lastChild = null;
76 let child = null;
77 (node.children.concat([null])).forEach((nextChild) => {
78 if (
79 (lastChild || nextChild)
80 && (!lastChild || isInlineElement(lastChild))
81 && (child && (child.type === 'Literal' || child.type === 'JSXText'))
82 && (!nextChild || isInlineElement(nextChild))
83 && true
84 ) {
85 if (lastChild && child.value.match(TEXT_FOLLOWING_ELEMENT_PATTERN)) {
86 context.report({
87 node: lastChild,
88 loc: lastChild.loc.end,
89 message: `Ambiguous spacing after previous element ${elementName(lastChild)}`
90 });
91 } else if (nextChild && child.value.match(TEXT_PRECEDING_ELEMENT_PATTERN)) {
92 context.report({
93 node: nextChild,
94 loc: nextChild.loc.start,
95 message: `Ambiguous spacing before next element ${elementName(nextChild)}`
96 });
97 }
98 }
99 lastChild = child;
100 child = nextChild;
101 });
102 };
103
104 return {
105 JSXElement: handleJSX,
106 JSXFragment: handleJSX
107 };
108 }
109};