123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253 |
- "use strict";
- const astUtils = require("./utils/ast-utils");
- module.exports = {
- meta: {
- deprecated: true,
- replacedBy: [],
- type: "layout",
- docs: {
- description: "Enforce consistent linebreak style for operators",
- recommended: false,
- url: "https://eslint.org/docs/latest/rules/operator-linebreak"
- },
- schema: [
- {
- enum: ["after", "before", "none", null]
- },
- {
- type: "object",
- properties: {
- overrides: {
- type: "object",
- additionalProperties: {
- enum: ["after", "before", "none", "ignore"]
- }
- }
- },
- additionalProperties: false
- }
- ],
- fixable: "code",
- messages: {
- operatorAtBeginning: "'{{operator}}' should be placed at the beginning of the line.",
- operatorAtEnd: "'{{operator}}' should be placed at the end of the line.",
- badLinebreak: "Bad line breaking before and after '{{operator}}'.",
- noLinebreak: "There should be no line break before or after '{{operator}}'."
- }
- },
- create(context) {
- const usedDefaultGlobal = !context.options[0];
- const globalStyle = context.options[0] || "after";
- const options = context.options[1] || {};
- const styleOverrides = options.overrides ? Object.assign({}, options.overrides) : {};
- if (usedDefaultGlobal && !styleOverrides["?"]) {
- styleOverrides["?"] = "before";
- }
- if (usedDefaultGlobal && !styleOverrides[":"]) {
- styleOverrides[":"] = "before";
- }
- const sourceCode = context.sourceCode;
-
-
-
-
- function getFixer(operatorToken, desiredStyle) {
- return fixer => {
- const tokenBefore = sourceCode.getTokenBefore(operatorToken);
- const tokenAfter = sourceCode.getTokenAfter(operatorToken);
- const textBefore = sourceCode.text.slice(tokenBefore.range[1], operatorToken.range[0]);
- const textAfter = sourceCode.text.slice(operatorToken.range[1], tokenAfter.range[0]);
- const hasLinebreakBefore = !astUtils.isTokenOnSameLine(tokenBefore, operatorToken);
- const hasLinebreakAfter = !astUtils.isTokenOnSameLine(operatorToken, tokenAfter);
- let newTextBefore, newTextAfter;
- if (hasLinebreakBefore !== hasLinebreakAfter && desiredStyle !== "none") {
-
- if (sourceCode.getTokenBefore(operatorToken, { includeComments: true }) !== tokenBefore &&
- sourceCode.getTokenAfter(operatorToken, { includeComments: true }) !== tokenAfter) {
- return null;
- }
-
- newTextBefore = textAfter;
- newTextAfter = textBefore;
- } else {
- const LINEBREAK_REGEX = astUtils.createGlobalLinebreakMatcher();
-
- newTextBefore = desiredStyle === "before" || textBefore.trim() ? textBefore : textBefore.replace(LINEBREAK_REGEX, "");
- newTextAfter = desiredStyle === "after" || textAfter.trim() ? textAfter : textAfter.replace(LINEBREAK_REGEX, "");
-
- if (newTextBefore === textBefore && newTextAfter === textAfter) {
- return null;
- }
- }
- if (newTextAfter === "" && tokenAfter.type === "Punctuator" && "+-".includes(operatorToken.value) && tokenAfter.value === operatorToken.value) {
-
- newTextAfter += " ";
- }
- return fixer.replaceTextRange([tokenBefore.range[1], tokenAfter.range[0]], newTextBefore + operatorToken.value + newTextAfter);
- };
- }
-
- function validateNode(node, rightSide, operator) {
-
- const operatorToken = sourceCode.getTokenBefore(rightSide, token => token.value === operator);
- const leftToken = sourceCode.getTokenBefore(operatorToken);
- const rightToken = sourceCode.getTokenAfter(operatorToken);
- const operatorStyleOverride = styleOverrides[operator];
- const style = operatorStyleOverride || globalStyle;
- const fix = getFixer(operatorToken, style);
-
- if (astUtils.isTokenOnSameLine(leftToken, operatorToken) &&
- astUtils.isTokenOnSameLine(operatorToken, rightToken)) {
-
- } else if (operatorStyleOverride !== "ignore" && !astUtils.isTokenOnSameLine(leftToken, operatorToken) &&
- !astUtils.isTokenOnSameLine(operatorToken, rightToken)) {
-
- context.report({
- node,
- loc: operatorToken.loc,
- messageId: "badLinebreak",
- data: {
- operator
- },
- fix
- });
- } else if (style === "before" && astUtils.isTokenOnSameLine(leftToken, operatorToken)) {
- context.report({
- node,
- loc: operatorToken.loc,
- messageId: "operatorAtBeginning",
- data: {
- operator
- },
- fix
- });
- } else if (style === "after" && astUtils.isTokenOnSameLine(operatorToken, rightToken)) {
- context.report({
- node,
- loc: operatorToken.loc,
- messageId: "operatorAtEnd",
- data: {
- operator
- },
- fix
- });
- } else if (style === "none") {
- context.report({
- node,
- loc: operatorToken.loc,
- messageId: "noLinebreak",
- data: {
- operator
- },
- fix
- });
- }
- }
-
- function validateBinaryExpression(node) {
- validateNode(node, node.right, node.operator);
- }
-
-
-
- return {
- BinaryExpression: validateBinaryExpression,
- LogicalExpression: validateBinaryExpression,
- AssignmentExpression: validateBinaryExpression,
- VariableDeclarator(node) {
- if (node.init) {
- validateNode(node, node.init, "=");
- }
- },
- PropertyDefinition(node) {
- if (node.value) {
- validateNode(node, node.value, "=");
- }
- },
- ConditionalExpression(node) {
- validateNode(node, node.consequent, "?");
- validateNode(node, node.alternate, ":");
- }
- };
- }
- };
|