'use strict'; var utils = require('../utils.js'); require('eslint-visitor-keys'); require('espree'); require('estraverse'); const messages = { require: "JSX element should start in a new line", prevent: "JSX element should not start in a new line", allowMultilines: "Multiline JSX elements should start in a new line" }; function isMultilined(node) { return node && node.loc.start.line !== node.loc.end.line; } var jsxNewline = utils.createRule({ name: "jsx-newline", package: "jsx", meta: { type: "layout", docs: { description: "Require or prevent a new line after jsx elements and expressions." }, fixable: "code", messages, schema: [ { type: "object", properties: { prevent: { default: false, type: "boolean" }, allowMultilines: { default: false, type: "boolean" } }, additionalProperties: false, // @ts-expect-error Missing in type definition if: { properties: { allowMultilines: { const: true } } }, then: { properties: { prevent: { const: true } }, required: [ "prevent" ] } } ] }, create(context) { const jsxElementParents = /* @__PURE__ */ new Set(); const sourceCode = context.sourceCode; function isBlockCommentInCurlyBraces(element) { const elementRawValue = sourceCode.getText(element); return /^\s*\{\/\*/.test(elementRawValue); } function isNonBlockComment(element) { return !isBlockCommentInCurlyBraces(element) && (element.type === "JSXElement" || element.type === "JSXExpressionContainer"); } return { "Program:exit": function() { jsxElementParents.forEach((parent) => { parent.children.forEach((element, index, elements) => { if (element.type === "JSXElement" || element.type === "JSXExpressionContainer") { const configuration = context.options[0] || {}; const prevent = configuration.prevent || false; const allowMultilines = configuration.allowMultilines || false; const firstAdjacentSibling = elements[index + 1]; const secondAdjacentSibling = elements[index + 2]; const hasSibling = firstAdjacentSibling && secondAdjacentSibling && (firstAdjacentSibling.type === "Literal" || firstAdjacentSibling.type === "JSXText"); if (!hasSibling) return; const isWithoutNewLine = !/\n\s*\n/.test(firstAdjacentSibling.value); if (isBlockCommentInCurlyBraces(element)) return; if (allowMultilines && (isMultilined(element) || isMultilined(elements.slice(index + 2).find(isNonBlockComment)))) { if (!isWithoutNewLine) return; const regex2 = /(\n)(?!.*\1)/g; const replacement2 = "\n\n"; const messageId2 = "allowMultilines"; context.report({ messageId: messageId2, node: secondAdjacentSibling, fix(fixer) { return fixer.replaceText( firstAdjacentSibling, sourceCode.getText(firstAdjacentSibling).replace(regex2, replacement2) ); } }); return; } if (isWithoutNewLine === prevent) return; const messageId = prevent ? "prevent" : "require"; const regex = prevent ? /(\n\n)(?!.*\1)/g : /(\n)(?!.*\1)/g; const replacement = prevent ? "\n" : "\n\n"; context.report({ messageId, node: secondAdjacentSibling, fix(fixer) { return fixer.replaceText( firstAdjacentSibling, // double or remove the last newline sourceCode.getText(firstAdjacentSibling).replace(regex, replacement) ); } }); } }); }); }, ":matches(JSXElement, JSXFragment) > :matches(JSXElement, JSXExpressionContainer)": (node) => { jsxElementParents.add(node.parent); } }; } }); module.exports = jsxNewline;