123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122 |
- 'use strict';
- const docsUrl = require('../util/docsUrl');
- // This list is taken from https://developer.mozilla.org/en-US/docs/Web/HTML/Inline_elements
- // Note: 'br' is not included because whitespace around br tags is inconsequential to the rendered output
- const INLINE_ELEMENTS = new Set([
- 'a',
- 'abbr',
- 'acronym',
- 'b',
- 'bdo',
- 'big',
- '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: null,
- messages: {
- spacingAfterPrev: 'Ambiguous spacing after previous element {{element}}',
- spacingBeforeNext: 'Ambiguous spacing before next element {{element}}'
- },
- 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,
- messageId: 'spacingAfterPrev',
- data: {
- element: elementName(lastChild)
- }
- });
- } else if (nextChild && child.value.match(TEXT_PRECEDING_ELEMENT_PATTERN)) {
- context.report({
- node: nextChild,
- loc: nextChild.loc.start,
- messageId: 'spacingBeforeNext',
- data: {
- element: elementName(nextChild)
- }
- });
- }
- }
- lastChild = child;
- child = nextChild;
- });
- };
- return {
- JSXElement: handleJSX,
- JSXFragment: handleJSX
- };
- }
- };
|