[d565449] | 1 | /**
|
---|
| 2 | * @fileoverview Rule to enforce location of semicolons.
|
---|
| 3 | * @author Toru Nagashima
|
---|
| 4 | * @deprecated in ESLint v8.53.0
|
---|
| 5 | */
|
---|
| 6 |
|
---|
| 7 | "use strict";
|
---|
| 8 |
|
---|
| 9 | //------------------------------------------------------------------------------
|
---|
| 10 | // Requirements
|
---|
| 11 | //------------------------------------------------------------------------------
|
---|
| 12 |
|
---|
| 13 | const astUtils = require("./utils/ast-utils");
|
---|
| 14 |
|
---|
| 15 | //------------------------------------------------------------------------------
|
---|
| 16 | // Rule Definition
|
---|
| 17 | //------------------------------------------------------------------------------
|
---|
| 18 |
|
---|
| 19 | const SELECTOR = [
|
---|
| 20 | "BreakStatement", "ContinueStatement", "DebuggerStatement",
|
---|
| 21 | "DoWhileStatement", "ExportAllDeclaration",
|
---|
| 22 | "ExportDefaultDeclaration", "ExportNamedDeclaration",
|
---|
| 23 | "ExpressionStatement", "ImportDeclaration", "ReturnStatement",
|
---|
| 24 | "ThrowStatement", "VariableDeclaration", "PropertyDefinition"
|
---|
| 25 | ].join(",");
|
---|
| 26 |
|
---|
| 27 | /**
|
---|
| 28 | * Get the child node list of a given node.
|
---|
| 29 | * This returns `BlockStatement#body`, `StaticBlock#body`, `Program#body`,
|
---|
| 30 | * `ClassBody#body`, or `SwitchCase#consequent`.
|
---|
| 31 | * This is used to check whether a node is the first/last child.
|
---|
| 32 | * @param {Node} node A node to get child node list.
|
---|
| 33 | * @returns {Node[]|null} The child node list.
|
---|
| 34 | */
|
---|
| 35 | function getChildren(node) {
|
---|
| 36 | const t = node.type;
|
---|
| 37 |
|
---|
| 38 | if (
|
---|
| 39 | t === "BlockStatement" ||
|
---|
| 40 | t === "StaticBlock" ||
|
---|
| 41 | t === "Program" ||
|
---|
| 42 | t === "ClassBody"
|
---|
| 43 | ) {
|
---|
| 44 | return node.body;
|
---|
| 45 | }
|
---|
| 46 | if (t === "SwitchCase") {
|
---|
| 47 | return node.consequent;
|
---|
| 48 | }
|
---|
| 49 | return null;
|
---|
| 50 | }
|
---|
| 51 |
|
---|
| 52 | /**
|
---|
| 53 | * Check whether a given node is the last statement in the parent block.
|
---|
| 54 | * @param {Node} node A node to check.
|
---|
| 55 | * @returns {boolean} `true` if the node is the last statement in the parent block.
|
---|
| 56 | */
|
---|
| 57 | function isLastChild(node) {
|
---|
| 58 | const t = node.parent.type;
|
---|
| 59 |
|
---|
| 60 | if (t === "IfStatement" && node.parent.consequent === node && node.parent.alternate) { // before `else` keyword.
|
---|
| 61 | return true;
|
---|
| 62 | }
|
---|
| 63 | if (t === "DoWhileStatement") { // before `while` keyword.
|
---|
| 64 | return true;
|
---|
| 65 | }
|
---|
| 66 | const nodeList = getChildren(node.parent);
|
---|
| 67 |
|
---|
| 68 | return nodeList !== null && nodeList[nodeList.length - 1] === node; // before `}` or etc.
|
---|
| 69 | }
|
---|
| 70 |
|
---|
| 71 | /** @type {import('../shared/types').Rule} */
|
---|
| 72 | module.exports = {
|
---|
| 73 | meta: {
|
---|
| 74 | deprecated: true,
|
---|
| 75 | replacedBy: [],
|
---|
| 76 | type: "layout",
|
---|
| 77 |
|
---|
| 78 | docs: {
|
---|
| 79 | description: "Enforce location of semicolons",
|
---|
| 80 | recommended: false,
|
---|
| 81 | url: "https://eslint.org/docs/latest/rules/semi-style"
|
---|
| 82 | },
|
---|
| 83 |
|
---|
| 84 | schema: [{ enum: ["last", "first"] }],
|
---|
| 85 | fixable: "whitespace",
|
---|
| 86 |
|
---|
| 87 | messages: {
|
---|
| 88 | expectedSemiColon: "Expected this semicolon to be at {{pos}}."
|
---|
| 89 | }
|
---|
| 90 | },
|
---|
| 91 |
|
---|
| 92 | create(context) {
|
---|
| 93 | const sourceCode = context.sourceCode;
|
---|
| 94 | const option = context.options[0] || "last";
|
---|
| 95 |
|
---|
| 96 | /**
|
---|
| 97 | * Check the given semicolon token.
|
---|
| 98 | * @param {Token} semiToken The semicolon token to check.
|
---|
| 99 | * @param {"first"|"last"} expected The expected location to check.
|
---|
| 100 | * @returns {void}
|
---|
| 101 | */
|
---|
| 102 | function check(semiToken, expected) {
|
---|
| 103 | const prevToken = sourceCode.getTokenBefore(semiToken);
|
---|
| 104 | const nextToken = sourceCode.getTokenAfter(semiToken);
|
---|
| 105 | const prevIsSameLine = !prevToken || astUtils.isTokenOnSameLine(prevToken, semiToken);
|
---|
| 106 | const nextIsSameLine = !nextToken || astUtils.isTokenOnSameLine(semiToken, nextToken);
|
---|
| 107 |
|
---|
| 108 | if ((expected === "last" && !prevIsSameLine) || (expected === "first" && !nextIsSameLine)) {
|
---|
| 109 | context.report({
|
---|
| 110 | loc: semiToken.loc,
|
---|
| 111 | messageId: "expectedSemiColon",
|
---|
| 112 | data: {
|
---|
| 113 | pos: (expected === "last")
|
---|
| 114 | ? "the end of the previous line"
|
---|
| 115 | : "the beginning of the next line"
|
---|
| 116 | },
|
---|
| 117 | fix(fixer) {
|
---|
| 118 | if (prevToken && nextToken && sourceCode.commentsExistBetween(prevToken, nextToken)) {
|
---|
| 119 | return null;
|
---|
| 120 | }
|
---|
| 121 |
|
---|
| 122 | const start = prevToken ? prevToken.range[1] : semiToken.range[0];
|
---|
| 123 | const end = nextToken ? nextToken.range[0] : semiToken.range[1];
|
---|
| 124 | const text = (expected === "last") ? ";\n" : "\n;";
|
---|
| 125 |
|
---|
| 126 | return fixer.replaceTextRange([start, end], text);
|
---|
| 127 | }
|
---|
| 128 | });
|
---|
| 129 | }
|
---|
| 130 | }
|
---|
| 131 |
|
---|
| 132 | return {
|
---|
| 133 | [SELECTOR](node) {
|
---|
| 134 | if (option === "first" && isLastChild(node)) {
|
---|
| 135 | return;
|
---|
| 136 | }
|
---|
| 137 |
|
---|
| 138 | const lastToken = sourceCode.getLastToken(node);
|
---|
| 139 |
|
---|
| 140 | if (astUtils.isSemicolonToken(lastToken)) {
|
---|
| 141 | check(lastToken, option);
|
---|
| 142 | }
|
---|
| 143 | },
|
---|
| 144 |
|
---|
| 145 | ForStatement(node) {
|
---|
| 146 | const firstSemi = node.init && sourceCode.getTokenAfter(node.init, astUtils.isSemicolonToken);
|
---|
| 147 | const secondSemi = node.test && sourceCode.getTokenAfter(node.test, astUtils.isSemicolonToken);
|
---|
| 148 |
|
---|
| 149 | if (firstSemi) {
|
---|
| 150 | check(firstSemi, "last");
|
---|
| 151 | }
|
---|
| 152 | if (secondSemi) {
|
---|
| 153 | check(secondSemi, "last");
|
---|
| 154 | }
|
---|
| 155 | }
|
---|
| 156 | };
|
---|
| 157 | }
|
---|
| 158 | };
|
---|