325 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			325 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /**
 | |
|  * @fileoverview This rule should require or disallow spaces before or after unary operations.
 | |
|  * @author Marcin Kumorek
 | |
|  * @deprecated in ESLint v8.53.0
 | |
|  */
 | |
| "use strict";
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| // Requirements
 | |
| //------------------------------------------------------------------------------
 | |
| 
 | |
| const astUtils = require("./utils/ast-utils");
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| // Rule Definition
 | |
| //------------------------------------------------------------------------------
 | |
| 
 | |
| /** @type {import('../shared/types').Rule} */
 | |
| module.exports = {
 | |
|     meta: {
 | |
|         deprecated: true,
 | |
|         replacedBy: [],
 | |
|         type: "layout",
 | |
| 
 | |
|         docs: {
 | |
|             description: "Enforce consistent spacing before or after unary operators",
 | |
|             recommended: false,
 | |
|             url: "https://eslint.org/docs/latest/rules/space-unary-ops"
 | |
|         },
 | |
| 
 | |
|         fixable: "whitespace",
 | |
| 
 | |
|         schema: [
 | |
|             {
 | |
|                 type: "object",
 | |
|                 properties: {
 | |
|                     words: {
 | |
|                         type: "boolean",
 | |
|                         default: true
 | |
|                     },
 | |
|                     nonwords: {
 | |
|                         type: "boolean",
 | |
|                         default: false
 | |
|                     },
 | |
|                     overrides: {
 | |
|                         type: "object",
 | |
|                         additionalProperties: {
 | |
|                             type: "boolean"
 | |
|                         }
 | |
|                     }
 | |
|                 },
 | |
|                 additionalProperties: false
 | |
|             }
 | |
|         ],
 | |
|         messages: {
 | |
|             unexpectedBefore: "Unexpected space before unary operator '{{operator}}'.",
 | |
|             unexpectedAfter: "Unexpected space after unary operator '{{operator}}'.",
 | |
|             unexpectedAfterWord: "Unexpected space after unary word operator '{{word}}'.",
 | |
|             wordOperator: "Unary word operator '{{word}}' must be followed by whitespace.",
 | |
|             operator: "Unary operator '{{operator}}' must be followed by whitespace.",
 | |
|             beforeUnaryExpressions: "Space is required before unary expressions '{{token}}'."
 | |
|         }
 | |
|     },
 | |
| 
 | |
|     create(context) {
 | |
|         const options = context.options[0] || { words: true, nonwords: false };
 | |
| 
 | |
|         const sourceCode = context.sourceCode;
 | |
| 
 | |
|         //--------------------------------------------------------------------------
 | |
|         // Helpers
 | |
|         //--------------------------------------------------------------------------
 | |
| 
 | |
|         /**
 | |
|          * Check if the node is the first "!" in a "!!" convert to Boolean expression
 | |
|          * @param {ASTnode} node AST node
 | |
|          * @returns {boolean} Whether or not the node is first "!" in "!!"
 | |
|          */
 | |
|         function isFirstBangInBangBangExpression(node) {
 | |
|             return node && node.type === "UnaryExpression" && node.argument.operator === "!" &&
 | |
|                 node.argument && node.argument.type === "UnaryExpression" && node.argument.operator === "!";
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Checks if an override exists for a given operator.
 | |
|          * @param {string} operator Operator
 | |
|          * @returns {boolean} Whether or not an override has been provided for the operator
 | |
|          */
 | |
|         function overrideExistsForOperator(operator) {
 | |
|             return options.overrides && Object.prototype.hasOwnProperty.call(options.overrides, operator);
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Gets the value that the override was set to for this operator
 | |
|          * @param {string} operator Operator
 | |
|          * @returns {boolean} Whether or not an override enforces a space with this operator
 | |
|          */
 | |
|         function overrideEnforcesSpaces(operator) {
 | |
|             return options.overrides[operator];
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Verify Unary Word Operator has spaces after the word operator
 | |
|          * @param {ASTnode} node AST node
 | |
|          * @param {Object} firstToken first token from the AST node
 | |
|          * @param {Object} secondToken second token from the AST node
 | |
|          * @param {string} word The word to be used for reporting
 | |
|          * @returns {void}
 | |
|          */
 | |
|         function verifyWordHasSpaces(node, firstToken, secondToken, word) {
 | |
|             if (secondToken.range[0] === firstToken.range[1]) {
 | |
|                 context.report({
 | |
|                     node,
 | |
|                     messageId: "wordOperator",
 | |
|                     data: {
 | |
|                         word
 | |
|                     },
 | |
|                     fix(fixer) {
 | |
|                         return fixer.insertTextAfter(firstToken, " ");
 | |
|                     }
 | |
|                 });
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Verify Unary Word Operator doesn't have spaces after the word operator
 | |
|          * @param {ASTnode} node AST node
 | |
|          * @param {Object} firstToken first token from the AST node
 | |
|          * @param {Object} secondToken second token from the AST node
 | |
|          * @param {string} word The word to be used for reporting
 | |
|          * @returns {void}
 | |
|          */
 | |
|         function verifyWordDoesntHaveSpaces(node, firstToken, secondToken, word) {
 | |
|             if (astUtils.canTokensBeAdjacent(firstToken, secondToken)) {
 | |
|                 if (secondToken.range[0] > firstToken.range[1]) {
 | |
|                     context.report({
 | |
|                         node,
 | |
|                         messageId: "unexpectedAfterWord",
 | |
|                         data: {
 | |
|                             word
 | |
|                         },
 | |
|                         fix(fixer) {
 | |
|                             return fixer.removeRange([firstToken.range[1], secondToken.range[0]]);
 | |
|                         }
 | |
|                     });
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Check Unary Word Operators for spaces after the word operator
 | |
|          * @param {ASTnode} node AST node
 | |
|          * @param {Object} firstToken first token from the AST node
 | |
|          * @param {Object} secondToken second token from the AST node
 | |
|          * @param {string} word The word to be used for reporting
 | |
|          * @returns {void}
 | |
|          */
 | |
|         function checkUnaryWordOperatorForSpaces(node, firstToken, secondToken, word) {
 | |
|             if (overrideExistsForOperator(word)) {
 | |
|                 if (overrideEnforcesSpaces(word)) {
 | |
|                     verifyWordHasSpaces(node, firstToken, secondToken, word);
 | |
|                 } else {
 | |
|                     verifyWordDoesntHaveSpaces(node, firstToken, secondToken, word);
 | |
|                 }
 | |
|             } else if (options.words) {
 | |
|                 verifyWordHasSpaces(node, firstToken, secondToken, word);
 | |
|             } else {
 | |
|                 verifyWordDoesntHaveSpaces(node, firstToken, secondToken, word);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Verifies YieldExpressions satisfy spacing requirements
 | |
|          * @param {ASTnode} node AST node
 | |
|          * @returns {void}
 | |
|          */
 | |
|         function checkForSpacesAfterYield(node) {
 | |
|             const tokens = sourceCode.getFirstTokens(node, 3),
 | |
|                 word = "yield";
 | |
| 
 | |
|             if (!node.argument || node.delegate) {
 | |
|                 return;
 | |
|             }
 | |
| 
 | |
|             checkUnaryWordOperatorForSpaces(node, tokens[0], tokens[1], word);
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Verifies AwaitExpressions satisfy spacing requirements
 | |
|          * @param {ASTNode} node AwaitExpression AST node
 | |
|          * @returns {void}
 | |
|          */
 | |
|         function checkForSpacesAfterAwait(node) {
 | |
|             const tokens = sourceCode.getFirstTokens(node, 3);
 | |
| 
 | |
|             checkUnaryWordOperatorForSpaces(node, tokens[0], tokens[1], "await");
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Verifies UnaryExpression, UpdateExpression and NewExpression have spaces before or after the operator
 | |
|          * @param {ASTnode} node AST node
 | |
|          * @param {Object} firstToken First token in the expression
 | |
|          * @param {Object} secondToken Second token in the expression
 | |
|          * @returns {void}
 | |
|          */
 | |
|         function verifyNonWordsHaveSpaces(node, firstToken, secondToken) {
 | |
|             if (node.prefix) {
 | |
|                 if (isFirstBangInBangBangExpression(node)) {
 | |
|                     return;
 | |
|                 }
 | |
|                 if (firstToken.range[1] === secondToken.range[0]) {
 | |
|                     context.report({
 | |
|                         node,
 | |
|                         messageId: "operator",
 | |
|                         data: {
 | |
|                             operator: firstToken.value
 | |
|                         },
 | |
|                         fix(fixer) {
 | |
|                             return fixer.insertTextAfter(firstToken, " ");
 | |
|                         }
 | |
|                     });
 | |
|                 }
 | |
|             } else {
 | |
|                 if (firstToken.range[1] === secondToken.range[0]) {
 | |
|                     context.report({
 | |
|                         node,
 | |
|                         messageId: "beforeUnaryExpressions",
 | |
|                         data: {
 | |
|                             token: secondToken.value
 | |
|                         },
 | |
|                         fix(fixer) {
 | |
|                             return fixer.insertTextBefore(secondToken, " ");
 | |
|                         }
 | |
|                     });
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Verifies UnaryExpression, UpdateExpression and NewExpression don't have spaces before or after the operator
 | |
|          * @param {ASTnode} node AST node
 | |
|          * @param {Object} firstToken First token in the expression
 | |
|          * @param {Object} secondToken Second token in the expression
 | |
|          * @returns {void}
 | |
|          */
 | |
|         function verifyNonWordsDontHaveSpaces(node, firstToken, secondToken) {
 | |
|             if (node.prefix) {
 | |
|                 if (secondToken.range[0] > firstToken.range[1]) {
 | |
|                     context.report({
 | |
|                         node,
 | |
|                         messageId: "unexpectedAfter",
 | |
|                         data: {
 | |
|                             operator: firstToken.value
 | |
|                         },
 | |
|                         fix(fixer) {
 | |
|                             if (astUtils.canTokensBeAdjacent(firstToken, secondToken)) {
 | |
|                                 return fixer.removeRange([firstToken.range[1], secondToken.range[0]]);
 | |
|                             }
 | |
|                             return null;
 | |
|                         }
 | |
|                     });
 | |
|                 }
 | |
|             } else {
 | |
|                 if (secondToken.range[0] > firstToken.range[1]) {
 | |
|                     context.report({
 | |
|                         node,
 | |
|                         messageId: "unexpectedBefore",
 | |
|                         data: {
 | |
|                             operator: secondToken.value
 | |
|                         },
 | |
|                         fix(fixer) {
 | |
|                             return fixer.removeRange([firstToken.range[1], secondToken.range[0]]);
 | |
|                         }
 | |
|                     });
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /**
 | |
|          * Verifies UnaryExpression, UpdateExpression and NewExpression satisfy spacing requirements
 | |
|          * @param {ASTnode} node AST node
 | |
|          * @returns {void}
 | |
|          */
 | |
|         function checkForSpaces(node) {
 | |
|             const tokens = node.type === "UpdateExpression" && !node.prefix
 | |
|                 ? sourceCode.getLastTokens(node, 2)
 | |
|                 : sourceCode.getFirstTokens(node, 2);
 | |
|             const firstToken = tokens[0];
 | |
|             const secondToken = tokens[1];
 | |
| 
 | |
|             if ((node.type === "NewExpression" || node.prefix) && firstToken.type === "Keyword") {
 | |
|                 checkUnaryWordOperatorForSpaces(node, firstToken, secondToken, firstToken.value);
 | |
|                 return;
 | |
|             }
 | |
| 
 | |
|             const operator = node.prefix ? tokens[0].value : tokens[1].value;
 | |
| 
 | |
|             if (overrideExistsForOperator(operator)) {
 | |
|                 if (overrideEnforcesSpaces(operator)) {
 | |
|                     verifyNonWordsHaveSpaces(node, firstToken, secondToken);
 | |
|                 } else {
 | |
|                     verifyNonWordsDontHaveSpaces(node, firstToken, secondToken);
 | |
|                 }
 | |
|             } else if (options.nonwords) {
 | |
|                 verifyNonWordsHaveSpaces(node, firstToken, secondToken);
 | |
|             } else {
 | |
|                 verifyNonWordsDontHaveSpaces(node, firstToken, secondToken);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         //--------------------------------------------------------------------------
 | |
|         // Public
 | |
|         //--------------------------------------------------------------------------
 | |
| 
 | |
|         return {
 | |
|             UnaryExpression: checkForSpaces,
 | |
|             UpdateExpression: checkForSpaces,
 | |
|             NewExpression: checkForSpaces,
 | |
|             YieldExpression: checkForSpacesAfterYield,
 | |
|             AwaitExpression: checkForSpacesAfterAwait
 | |
|         };
 | |
| 
 | |
|     }
 | |
| };
 |