Ohm-Management - Projektarbeit B-ME
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

space-unary-ops.js 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. /**
  2. * @fileoverview This rule shoud require or disallow spaces before or after unary operations.
  3. * @author Marcin Kumorek
  4. */
  5. "use strict";
  6. //------------------------------------------------------------------------------
  7. // Requirements
  8. //------------------------------------------------------------------------------
  9. const astUtils = require("../util/ast-utils");
  10. //------------------------------------------------------------------------------
  11. // Rule Definition
  12. //------------------------------------------------------------------------------
  13. module.exports = {
  14. meta: {
  15. type: "layout",
  16. docs: {
  17. description: "enforce consistent spacing before or after unary operators",
  18. category: "Stylistic Issues",
  19. recommended: false,
  20. url: "https://eslint.org/docs/rules/space-unary-ops"
  21. },
  22. fixable: "whitespace",
  23. schema: [
  24. {
  25. type: "object",
  26. properties: {
  27. words: {
  28. type: "boolean"
  29. },
  30. nonwords: {
  31. type: "boolean"
  32. },
  33. overrides: {
  34. type: "object",
  35. additionalProperties: {
  36. type: "boolean"
  37. }
  38. }
  39. },
  40. additionalProperties: false
  41. }
  42. ]
  43. },
  44. create(context) {
  45. const options = context.options && Array.isArray(context.options) && context.options[0] || { words: true, nonwords: false };
  46. const sourceCode = context.getSourceCode();
  47. //--------------------------------------------------------------------------
  48. // Helpers
  49. //--------------------------------------------------------------------------
  50. /**
  51. * Check if the node is the first "!" in a "!!" convert to Boolean expression
  52. * @param {ASTnode} node AST node
  53. * @returns {boolean} Whether or not the node is first "!" in "!!"
  54. */
  55. function isFirstBangInBangBangExpression(node) {
  56. return node && node.type === "UnaryExpression" && node.argument.operator === "!" &&
  57. node.argument && node.argument.type === "UnaryExpression" && node.argument.operator === "!";
  58. }
  59. /**
  60. * Checks if an override exists for a given operator.
  61. * @param {string} operator Operator
  62. * @returns {boolean} Whether or not an override has been provided for the operator
  63. */
  64. function overrideExistsForOperator(operator) {
  65. return options.overrides && Object.prototype.hasOwnProperty.call(options.overrides, operator);
  66. }
  67. /**
  68. * Gets the value that the override was set to for this operator
  69. * @param {string} operator Operator
  70. * @returns {boolean} Whether or not an override enforces a space with this operator
  71. */
  72. function overrideEnforcesSpaces(operator) {
  73. return options.overrides[operator];
  74. }
  75. /**
  76. * Verify Unary Word Operator has spaces after the word operator
  77. * @param {ASTnode} node AST node
  78. * @param {Object} firstToken first token from the AST node
  79. * @param {Object} secondToken second token from the AST node
  80. * @param {string} word The word to be used for reporting
  81. * @returns {void}
  82. */
  83. function verifyWordHasSpaces(node, firstToken, secondToken, word) {
  84. if (secondToken.range[0] === firstToken.range[1]) {
  85. context.report({
  86. node,
  87. message: "Unary word operator '{{word}}' must be followed by whitespace.",
  88. data: {
  89. word
  90. },
  91. fix(fixer) {
  92. return fixer.insertTextAfter(firstToken, " ");
  93. }
  94. });
  95. }
  96. }
  97. /**
  98. * Verify Unary Word Operator doesn't have spaces after the word operator
  99. * @param {ASTnode} node AST node
  100. * @param {Object} firstToken first token from the AST node
  101. * @param {Object} secondToken second token from the AST node
  102. * @param {string} word The word to be used for reporting
  103. * @returns {void}
  104. */
  105. function verifyWordDoesntHaveSpaces(node, firstToken, secondToken, word) {
  106. if (astUtils.canTokensBeAdjacent(firstToken, secondToken)) {
  107. if (secondToken.range[0] > firstToken.range[1]) {
  108. context.report({
  109. node,
  110. message: "Unexpected space after unary word operator '{{word}}'.",
  111. data: {
  112. word
  113. },
  114. fix(fixer) {
  115. return fixer.removeRange([firstToken.range[1], secondToken.range[0]]);
  116. }
  117. });
  118. }
  119. }
  120. }
  121. /**
  122. * Check Unary Word Operators for spaces after the word operator
  123. * @param {ASTnode} node AST node
  124. * @param {Object} firstToken first token from the AST node
  125. * @param {Object} secondToken second token from the AST node
  126. * @param {string} word The word to be used for reporting
  127. * @returns {void}
  128. */
  129. function checkUnaryWordOperatorForSpaces(node, firstToken, secondToken, word) {
  130. if (overrideExistsForOperator(word)) {
  131. if (overrideEnforcesSpaces(word)) {
  132. verifyWordHasSpaces(node, firstToken, secondToken, word);
  133. } else {
  134. verifyWordDoesntHaveSpaces(node, firstToken, secondToken, word);
  135. }
  136. } else if (options.words) {
  137. verifyWordHasSpaces(node, firstToken, secondToken, word);
  138. } else {
  139. verifyWordDoesntHaveSpaces(node, firstToken, secondToken, word);
  140. }
  141. }
  142. /**
  143. * Verifies YieldExpressions satisfy spacing requirements
  144. * @param {ASTnode} node AST node
  145. * @returns {void}
  146. */
  147. function checkForSpacesAfterYield(node) {
  148. const tokens = sourceCode.getFirstTokens(node, 3),
  149. word = "yield";
  150. if (!node.argument || node.delegate) {
  151. return;
  152. }
  153. checkUnaryWordOperatorForSpaces(node, tokens[0], tokens[1], word);
  154. }
  155. /**
  156. * Verifies AwaitExpressions satisfy spacing requirements
  157. * @param {ASTNode} node AwaitExpression AST node
  158. * @returns {void}
  159. */
  160. function checkForSpacesAfterAwait(node) {
  161. const tokens = sourceCode.getFirstTokens(node, 3);
  162. checkUnaryWordOperatorForSpaces(node, tokens[0], tokens[1], "await");
  163. }
  164. /**
  165. * Verifies UnaryExpression, UpdateExpression and NewExpression have spaces before or after the operator
  166. * @param {ASTnode} node AST node
  167. * @param {Object} firstToken First token in the expression
  168. * @param {Object} secondToken Second token in the expression
  169. * @returns {void}
  170. */
  171. function verifyNonWordsHaveSpaces(node, firstToken, secondToken) {
  172. if (node.prefix) {
  173. if (isFirstBangInBangBangExpression(node)) {
  174. return;
  175. }
  176. if (firstToken.range[1] === secondToken.range[0]) {
  177. context.report({
  178. node,
  179. message: "Unary operator '{{operator}}' must be followed by whitespace.",
  180. data: {
  181. operator: firstToken.value
  182. },
  183. fix(fixer) {
  184. return fixer.insertTextAfter(firstToken, " ");
  185. }
  186. });
  187. }
  188. } else {
  189. if (firstToken.range[1] === secondToken.range[0]) {
  190. context.report({
  191. node,
  192. message: "Space is required before unary expressions '{{token}}'.",
  193. data: {
  194. token: secondToken.value
  195. },
  196. fix(fixer) {
  197. return fixer.insertTextBefore(secondToken, " ");
  198. }
  199. });
  200. }
  201. }
  202. }
  203. /**
  204. * Verifies UnaryExpression, UpdateExpression and NewExpression don't have spaces before or after the operator
  205. * @param {ASTnode} node AST node
  206. * @param {Object} firstToken First token in the expression
  207. * @param {Object} secondToken Second token in the expression
  208. * @returns {void}
  209. */
  210. function verifyNonWordsDontHaveSpaces(node, firstToken, secondToken) {
  211. if (node.prefix) {
  212. if (secondToken.range[0] > firstToken.range[1]) {
  213. context.report({
  214. node,
  215. message: "Unexpected space after unary operator '{{operator}}'.",
  216. data: {
  217. operator: firstToken.value
  218. },
  219. fix(fixer) {
  220. if (astUtils.canTokensBeAdjacent(firstToken, secondToken)) {
  221. return fixer.removeRange([firstToken.range[1], secondToken.range[0]]);
  222. }
  223. return null;
  224. }
  225. });
  226. }
  227. } else {
  228. if (secondToken.range[0] > firstToken.range[1]) {
  229. context.report({
  230. node,
  231. message: "Unexpected space before unary operator '{{operator}}'.",
  232. data: {
  233. operator: secondToken.value
  234. },
  235. fix(fixer) {
  236. return fixer.removeRange([firstToken.range[1], secondToken.range[0]]);
  237. }
  238. });
  239. }
  240. }
  241. }
  242. /**
  243. * Verifies UnaryExpression, UpdateExpression and NewExpression satisfy spacing requirements
  244. * @param {ASTnode} node AST node
  245. * @returns {void}
  246. */
  247. function checkForSpaces(node) {
  248. const tokens = node.type === "UpdateExpression" && !node.prefix
  249. ? sourceCode.getLastTokens(node, 2)
  250. : sourceCode.getFirstTokens(node, 2);
  251. const firstToken = tokens[0];
  252. const secondToken = tokens[1];
  253. if ((node.type === "NewExpression" || node.prefix) && firstToken.type === "Keyword") {
  254. checkUnaryWordOperatorForSpaces(node, firstToken, secondToken, firstToken.value);
  255. return;
  256. }
  257. const operator = node.prefix ? tokens[0].value : tokens[1].value;
  258. if (overrideExistsForOperator(operator)) {
  259. if (overrideEnforcesSpaces(operator)) {
  260. verifyNonWordsHaveSpaces(node, firstToken, secondToken);
  261. } else {
  262. verifyNonWordsDontHaveSpaces(node, firstToken, secondToken);
  263. }
  264. } else if (options.nonwords) {
  265. verifyNonWordsHaveSpaces(node, firstToken, secondToken);
  266. } else {
  267. verifyNonWordsDontHaveSpaces(node, firstToken, secondToken);
  268. }
  269. }
  270. //--------------------------------------------------------------------------
  271. // Public
  272. //--------------------------------------------------------------------------
  273. return {
  274. UnaryExpression: checkForSpaces,
  275. UpdateExpression: checkForSpaces,
  276. NewExpression: checkForSpaces,
  277. YieldExpression: checkForSpacesAfterYield,
  278. AwaitExpression: checkForSpacesAfterAwait
  279. };
  280. }
  281. };