| 'use strict'; |
| |
| const docsUrl = require('../util/docsUrl'); |
| |
| // This list is taken from https://developer.mozilla.org/en-US/docs/Web/HTML/Inline_elements |
| const INLINE_ELEMENTS = new Set([ |
| 'a', |
| 'abbr', |
| 'acronym', |
| 'b', |
| 'bdo', |
| 'big', |
| 'br', |
| 'button', |
| 'cite', |
| 'code', |
| 'dfn', |
| 'em', |
| 'i', |
| 'img', |
| 'input', |
| 'kbd', |
| 'label', |
| 'map', |
| 'object', |
| 'q', |
| 'samp', |
| 'script', |
| 'select', |
| 'small', |
| 'span', |
| 'strong', |
| 'sub', |
| 'sup', |
| 'textarea', |
| 'tt', |
| 'var' |
| ]); |
| |
| module.exports = { |
| meta: { |
| docs: { |
| description: 'Ensures inline tags are not rendered without spaces between them', |
| category: 'Stylistic Issues', |
| recommended: false, |
| url: docsUrl('jsx-child-element-spacing') |
| }, |
| fixable: false, |
| schema: [ |
| { |
| type: 'object', |
| properties: {}, |
| default: {}, |
| additionalProperties: false |
| } |
| ] |
| }, |
| create(context) { |
| const TEXT_FOLLOWING_ELEMENT_PATTERN = /^\s*\n\s*\S/; |
| const TEXT_PRECEDING_ELEMENT_PATTERN = /\S\s*\n\s*$/; |
| |
| const elementName = node => ( |
| node.openingElement && |
| node.openingElement.name && |
| node.openingElement.name.type === 'JSXIdentifier' && |
| node.openingElement.name.name |
| ); |
| |
| const isInlineElement = node => ( |
| node.type === 'JSXElement' && |
| INLINE_ELEMENTS.has(elementName(node)) |
| ); |
| |
| const handleJSX = (node) => { |
| let lastChild = null; |
| let child = null; |
| (node.children.concat([null])).forEach((nextChild) => { |
| if ( |
| (lastChild || nextChild) && |
| (!lastChild || isInlineElement(lastChild)) && |
| (child && (child.type === 'Literal' || child.type === 'JSXText')) && |
| (!nextChild || isInlineElement(nextChild)) && |
| true |
| ) { |
| if (lastChild && child.value.match(TEXT_FOLLOWING_ELEMENT_PATTERN)) { |
| context.report({ |
| node: lastChild, |
| loc: lastChild.loc.end, |
| message: `Ambiguous spacing after previous element ${elementName(lastChild)}` |
| }); |
| } else if (nextChild && child.value.match(TEXT_PRECEDING_ELEMENT_PATTERN)) { |
| context.report({ |
| node: nextChild, |
| loc: nextChild.loc.start, |
| message: `Ambiguous spacing before next element ${elementName(nextChild)}` |
| }); |
| } |
| } |
| lastChild = child; |
| child = nextChild; |
| }); |
| }; |
| |
| return { |
| JSXElement: handleJSX, |
| JSXFragment: handleJSX |
| }; |
| } |
| }; |