UNPKG

4.19 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 * @param {Token} firstToken The first token to check.
68 * @returns {void}
69 */
70 function checkForPartOfClassBody(firstToken) {
71 for (let token = firstToken;
72 token.type === "Punctuator" && !astUtils.isClosingBraceToken(token);
73 token = sourceCode.getTokenAfter(token)
74 ) {
75 if (astUtils.isSemicolonToken(token)) {
76 report(token);
77 }
78 }
79 }
80
81 return {
82
83 /**
84 * Reports this empty statement, except if the parent node is a loop.
85 * @param {Node} node A EmptyStatement node to be reported.
86 * @returns {void}
87 */
88 EmptyStatement(node) {
89 const parent = node.parent,
90 allowedParentTypes = [
91 "ForStatement",
92 "ForInStatement",
93 "ForOfStatement",
94 "WhileStatement",
95 "DoWhileStatement",
96 "IfStatement",
97 "LabeledStatement",
98 "WithStatement"
99 ];
100
101 if (allowedParentTypes.indexOf(parent.type) === -1) {
102 report(node);
103 }
104 },
105
106 /**
107 * Checks tokens from the head of this class body to the first MethodDefinition or the end of this class body.
108 * @param {Node} node A ClassBody node to check.
109 * @returns {void}
110 */
111 ClassBody(node) {
112 checkForPartOfClassBody(sourceCode.getFirstToken(node, 1)); // 0 is `{`.
113 },
114
115 /**
116 * Checks tokens from this MethodDefinition to the next MethodDefinition or the end of this class body.
117 * @param {Node} node A MethodDefinition node of the start point.
118 * @returns {void}
119 */
120 MethodDefinition(node) {
121 checkForPartOfClassBody(sourceCode.getTokenAfter(node));
122 }
123 };
124
125 }
126};