UNPKG

4.21 kBJavaScriptView Raw
1/**
2 * @fileoverview Rule to flag use of unnecessary semicolons
3 * @author Nicholas C. Zakas
4 */
5
6"use strict";
7
8//------------------------------------------------------------------------------
9// Requirements
10//------------------------------------------------------------------------------
11
12const FixTracker = require("./utils/fix-tracker");
13const astUtils = require("./utils/ast-utils");
14
15//------------------------------------------------------------------------------
16// Rule Definition
17//------------------------------------------------------------------------------
18
19module.exports = {
20 meta: {
21 type: "suggestion",
22
23 docs: {
24 description: "disallow unnecessary semicolons",
25 category: "Possible Errors",
26 recommended: true,
27 url: "https://eslint.org/docs/rules/no-extra-semi"
28 },
29
30 fixable: "code",
31 schema: [],
32
33 messages: {
34 unexpected: "Unnecessary semicolon."
35 }
36 },
37
38 create(context) {
39 const sourceCode = context.getSourceCode();
40
41 /**
42 * Reports an unnecessary semicolon error.
43 * @param {Node|Token} nodeOrToken - A node or a token to be reported.
44 * @returns {void}
45 */
46 function report(nodeOrToken) {
47 context.report({
48 node: nodeOrToken,
49 messageId: "unexpected",
50 fix(fixer) {
51
52 /*
53 * Expand the replacement range to include the surrounding
54 * tokens to avoid conflicting with semi.
55 * https://github.com/eslint/eslint/issues/7928
56 */
57 return new FixTracker(fixer, context.getSourceCode())
58 .retainSurroundingTokens(nodeOrToken)
59 .remove(nodeOrToken);
60 }
61 });
62 }
63
64 /**
65 * Checks for a part of a class body.
66 * This checks tokens from a specified token to a next MethodDefinition or the end of class body.
67 *
68 * @param {Token} firstToken - The first token to check.
69 * @returns {void}
70 */
71 function checkForPartOfClassBody(firstToken) {
72 for (let token = firstToken;
73 token.type === "Punctuator" && !astUtils.isClosingBraceToken(token);
74 token = sourceCode.getTokenAfter(token)
75 ) {
76 if (astUtils.isSemicolonToken(token)) {
77 report(token);
78 }
79 }
80 }
81
82 return {
83
84 /**
85 * Reports this empty statement, except if the parent node is a loop.
86 * @param {Node} node - A EmptyStatement node to be reported.
87 * @returns {void}
88 */
89 EmptyStatement(node) {
90 const parent = node.parent,
91 allowedParentTypes = [
92 "ForStatement",
93 "ForInStatement",
94 "ForOfStatement",
95 "WhileStatement",
96 "DoWhileStatement",
97 "IfStatement",
98 "LabeledStatement",
99 "WithStatement"
100 ];
101
102 if (allowedParentTypes.indexOf(parent.type) === -1) {
103 report(node);
104 }
105 },
106
107 /**
108 * Checks tokens from the head of this class body to the first MethodDefinition or the end of this class body.
109 * @param {Node} node - A ClassBody node to check.
110 * @returns {void}
111 */
112 ClassBody(node) {
113 checkForPartOfClassBody(sourceCode.getFirstToken(node, 1)); // 0 is `{`.
114 },
115
116 /**
117 * Checks tokens from this MethodDefinition to the next MethodDefinition or the end of this class body.
118 * @param {Node} node - A MethodDefinition node of the start point.
119 * @returns {void}
120 */
121 MethodDefinition(node) {
122 checkForPartOfClassBody(sourceCode.getTokenAfter(node));
123 }
124 };
125
126 }
127};