UNPKG

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