UNPKG

4.59 kBJavaScriptView Raw
1/**
2 * @fileoverview A rule to ensure whitespace before blocks.
3 * @author Mathias Schreck <https://github.com/lo1tuma>
4 * @copyright 2014 Mathias Schreck. All rights reserved.
5 */
6
7"use strict";
8
9var astUtils = require("../ast-utils");
10
11//------------------------------------------------------------------------------
12// Rule Definition
13//------------------------------------------------------------------------------
14
15module.exports = function(context) {
16 var config = context.options[0],
17 sourceCode = context.getSourceCode(),
18 checkFunctions = true,
19 checkKeywords = true,
20 checkClasses = true;
21
22 if (typeof config === "object") {
23 checkFunctions = config.functions !== "never";
24 checkKeywords = config.keywords !== "never";
25 checkClasses = config.classes !== "never";
26 } else if (config === "never") {
27 checkFunctions = false;
28 checkKeywords = false;
29 checkClasses = false;
30 }
31
32 /**
33 * Checks whether or not a given token is an arrow operator (=>) or a keyword
34 * in order to avoid to conflict with `arrow-spacing` and `keyword-spacing`.
35 *
36 * @param {Token} token - A token to check.
37 * @returns {boolean} `true` if the token is an arrow operator.
38 */
39 function isConflicted(token) {
40 return (token.type === "Punctuator" && token.value === "=>") || token.type === "Keyword";
41 }
42
43 /**
44 * Checks the given BlockStatement node has a preceding space if it doesn’t start on a new line.
45 * @param {ASTNode|Token} node The AST node of a BlockStatement.
46 * @returns {void} undefined.
47 */
48 function checkPrecedingSpace(node) {
49 var precedingToken = context.getTokenBefore(node),
50 hasSpace,
51 parent,
52 requireSpace;
53
54 if (precedingToken && !isConflicted(precedingToken) && astUtils.isTokenOnSameLine(precedingToken, node)) {
55 hasSpace = sourceCode.isSpaceBetweenTokens(precedingToken, node);
56 parent = context.getAncestors().pop();
57 if (parent.type === "FunctionExpression" || parent.type === "FunctionDeclaration") {
58 requireSpace = checkFunctions;
59 } else if (node.type === "ClassBody") {
60 requireSpace = checkClasses;
61 } else {
62 requireSpace = checkKeywords;
63 }
64
65 if (requireSpace) {
66 if (!hasSpace) {
67 context.report({
68 node: node,
69 message: "Missing space before opening brace.",
70 fix: function(fixer) {
71 return fixer.insertTextBefore(node, " ");
72 }
73 });
74 }
75 } else {
76 if (hasSpace) {
77 context.report({
78 node: node,
79 message: "Unexpected space before opening brace.",
80 fix: function(fixer) {
81 return fixer.removeRange([precedingToken.range[1], node.range[0]]);
82 }
83 });
84 }
85 }
86 }
87 }
88
89 /**
90 * Checks if the CaseBlock of an given SwitchStatement node has a preceding space.
91 * @param {ASTNode} node The node of a SwitchStatement.
92 * @returns {void} undefined.
93 */
94 function checkSpaceBeforeCaseBlock(node) {
95 var cases = node.cases,
96 firstCase,
97 openingBrace;
98
99 if (cases.length > 0) {
100 firstCase = cases[0];
101 openingBrace = context.getTokenBefore(firstCase);
102 } else {
103 openingBrace = context.getLastToken(node, 1);
104 }
105
106 checkPrecedingSpace(openingBrace);
107 }
108
109 return {
110 "BlockStatement": checkPrecedingSpace,
111 "ClassBody": checkPrecedingSpace,
112 "SwitchStatement": checkSpaceBeforeCaseBlock
113 };
114
115};
116
117module.exports.schema = [
118 {
119 "oneOf": [
120 {
121 "enum": ["always", "never"]
122 },
123 {
124 "type": "object",
125 "properties": {
126 "keywords": {
127 "enum": ["always", "never"]
128 },
129 "functions": {
130 "enum": ["always", "never"]
131 },
132 "classes": {
133 "enum": ["always", "never"]
134 }
135 },
136 "additionalProperties": false
137 }
138 ]
139 }
140];