1 | /**
|
---|
2 | * @fileoverview Rule to require or disallow newlines between statements
|
---|
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 | // Helpers
|
---|
17 | //------------------------------------------------------------------------------
|
---|
18 |
|
---|
19 | const LT = `[${Array.from(astUtils.LINEBREAKS).join("")}]`;
|
---|
20 | const PADDING_LINE_SEQUENCE = new RegExp(
|
---|
21 | String.raw`^(\s*?${LT})\s*${LT}(\s*;?)$`,
|
---|
22 | "u"
|
---|
23 | );
|
---|
24 | const CJS_EXPORT = /^(?:module\s*\.\s*)?exports(?:\s*\.|\s*\[|$)/u;
|
---|
25 | const CJS_IMPORT = /^require\(/u;
|
---|
26 |
|
---|
27 | /**
|
---|
28 | * Creates tester which check if a node starts with specific keyword.
|
---|
29 | * @param {string} keyword The keyword to test.
|
---|
30 | * @returns {Object} the created tester.
|
---|
31 | * @private
|
---|
32 | */
|
---|
33 | function newKeywordTester(keyword) {
|
---|
34 | return {
|
---|
35 | test: (node, sourceCode) =>
|
---|
36 | sourceCode.getFirstToken(node).value === keyword
|
---|
37 | };
|
---|
38 | }
|
---|
39 |
|
---|
40 | /**
|
---|
41 | * Creates tester which check if a node starts with specific keyword and spans a single line.
|
---|
42 | * @param {string} keyword The keyword to test.
|
---|
43 | * @returns {Object} the created tester.
|
---|
44 | * @private
|
---|
45 | */
|
---|
46 | function newSinglelineKeywordTester(keyword) {
|
---|
47 | return {
|
---|
48 | test: (node, sourceCode) =>
|
---|
49 | node.loc.start.line === node.loc.end.line &&
|
---|
50 | sourceCode.getFirstToken(node).value === keyword
|
---|
51 | };
|
---|
52 | }
|
---|
53 |
|
---|
54 | /**
|
---|
55 | * Creates tester which check if a node starts with specific keyword and spans multiple lines.
|
---|
56 | * @param {string} keyword The keyword to test.
|
---|
57 | * @returns {Object} the created tester.
|
---|
58 | * @private
|
---|
59 | */
|
---|
60 | function newMultilineKeywordTester(keyword) {
|
---|
61 | return {
|
---|
62 | test: (node, sourceCode) =>
|
---|
63 | node.loc.start.line !== node.loc.end.line &&
|
---|
64 | sourceCode.getFirstToken(node).value === keyword
|
---|
65 | };
|
---|
66 | }
|
---|
67 |
|
---|
68 | /**
|
---|
69 | * Creates tester which check if a node is specific type.
|
---|
70 | * @param {string} type The node type to test.
|
---|
71 | * @returns {Object} the created tester.
|
---|
72 | * @private
|
---|
73 | */
|
---|
74 | function newNodeTypeTester(type) {
|
---|
75 | return {
|
---|
76 | test: node =>
|
---|
77 | node.type === type
|
---|
78 | };
|
---|
79 | }
|
---|
80 |
|
---|
81 | /**
|
---|
82 | * Checks the given node is an expression statement of IIFE.
|
---|
83 | * @param {ASTNode} node The node to check.
|
---|
84 | * @returns {boolean} `true` if the node is an expression statement of IIFE.
|
---|
85 | * @private
|
---|
86 | */
|
---|
87 | function isIIFEStatement(node) {
|
---|
88 | if (node.type === "ExpressionStatement") {
|
---|
89 | let call = astUtils.skipChainExpression(node.expression);
|
---|
90 |
|
---|
91 | if (call.type === "UnaryExpression") {
|
---|
92 | call = astUtils.skipChainExpression(call.argument);
|
---|
93 | }
|
---|
94 | return call.type === "CallExpression" && astUtils.isFunction(call.callee);
|
---|
95 | }
|
---|
96 | return false;
|
---|
97 | }
|
---|
98 |
|
---|
99 | /**
|
---|
100 | * Checks whether the given node is a block-like statement.
|
---|
101 | * This checks the last token of the node is the closing brace of a block.
|
---|
102 | * @param {SourceCode} sourceCode The source code to get tokens.
|
---|
103 | * @param {ASTNode} node The node to check.
|
---|
104 | * @returns {boolean} `true` if the node is a block-like statement.
|
---|
105 | * @private
|
---|
106 | */
|
---|
107 | function isBlockLikeStatement(sourceCode, node) {
|
---|
108 |
|
---|
109 | // do-while with a block is a block-like statement.
|
---|
110 | if (node.type === "DoWhileStatement" && node.body.type === "BlockStatement") {
|
---|
111 | return true;
|
---|
112 | }
|
---|
113 |
|
---|
114 | /*
|
---|
115 | * IIFE is a block-like statement specially from
|
---|
116 | * JSCS#disallowPaddingNewLinesAfterBlocks.
|
---|
117 | */
|
---|
118 | if (isIIFEStatement(node)) {
|
---|
119 | return true;
|
---|
120 | }
|
---|
121 |
|
---|
122 | // Checks the last token is a closing brace of blocks.
|
---|
123 | const lastToken = sourceCode.getLastToken(node, astUtils.isNotSemicolonToken);
|
---|
124 | const belongingNode = lastToken && astUtils.isClosingBraceToken(lastToken)
|
---|
125 | ? sourceCode.getNodeByRangeIndex(lastToken.range[0])
|
---|
126 | : null;
|
---|
127 |
|
---|
128 | return Boolean(belongingNode) && (
|
---|
129 | belongingNode.type === "BlockStatement" ||
|
---|
130 | belongingNode.type === "SwitchStatement"
|
---|
131 | );
|
---|
132 | }
|
---|
133 |
|
---|
134 | /**
|
---|
135 | * Gets the actual last token.
|
---|
136 | *
|
---|
137 | * If a semicolon is semicolon-less style's semicolon, this ignores it.
|
---|
138 | * For example:
|
---|
139 | *
|
---|
140 | * foo()
|
---|
141 | * ;[1, 2, 3].forEach(bar)
|
---|
142 | * @param {SourceCode} sourceCode The source code to get tokens.
|
---|
143 | * @param {ASTNode} node The node to get.
|
---|
144 | * @returns {Token} The actual last token.
|
---|
145 | * @private
|
---|
146 | */
|
---|
147 | function getActualLastToken(sourceCode, node) {
|
---|
148 | const semiToken = sourceCode.getLastToken(node);
|
---|
149 | const prevToken = sourceCode.getTokenBefore(semiToken);
|
---|
150 | const nextToken = sourceCode.getTokenAfter(semiToken);
|
---|
151 | const isSemicolonLessStyle = Boolean(
|
---|
152 | prevToken &&
|
---|
153 | nextToken &&
|
---|
154 | prevToken.range[0] >= node.range[0] &&
|
---|
155 | astUtils.isSemicolonToken(semiToken) &&
|
---|
156 | semiToken.loc.start.line !== prevToken.loc.end.line &&
|
---|
157 | semiToken.loc.end.line === nextToken.loc.start.line
|
---|
158 | );
|
---|
159 |
|
---|
160 | return isSemicolonLessStyle ? prevToken : semiToken;
|
---|
161 | }
|
---|
162 |
|
---|
163 | /**
|
---|
164 | * This returns the concatenation of the first 2 captured strings.
|
---|
165 | * @param {string} _ Unused. Whole matched string.
|
---|
166 | * @param {string} trailingSpaces The trailing spaces of the first line.
|
---|
167 | * @param {string} indentSpaces The indentation spaces of the last line.
|
---|
168 | * @returns {string} The concatenation of trailingSpaces and indentSpaces.
|
---|
169 | * @private
|
---|
170 | */
|
---|
171 | function replacerToRemovePaddingLines(_, trailingSpaces, indentSpaces) {
|
---|
172 | return trailingSpaces + indentSpaces;
|
---|
173 | }
|
---|
174 |
|
---|
175 | /**
|
---|
176 | * Check and report statements for `any` configuration.
|
---|
177 | * It does nothing.
|
---|
178 | * @returns {void}
|
---|
179 | * @private
|
---|
180 | */
|
---|
181 | function verifyForAny() {
|
---|
182 | }
|
---|
183 |
|
---|
184 | /**
|
---|
185 | * Check and report statements for `never` configuration.
|
---|
186 | * This autofix removes blank lines between the given 2 statements.
|
---|
187 | * However, if comments exist between 2 blank lines, it does not remove those
|
---|
188 | * blank lines automatically.
|
---|
189 | * @param {RuleContext} context The rule context to report.
|
---|
190 | * @param {ASTNode} _ Unused. The previous node to check.
|
---|
191 | * @param {ASTNode} nextNode The next node to check.
|
---|
192 | * @param {Array<Token[]>} paddingLines The array of token pairs that blank
|
---|
193 | * lines exist between the pair.
|
---|
194 | * @returns {void}
|
---|
195 | * @private
|
---|
196 | */
|
---|
197 | function verifyForNever(context, _, nextNode, paddingLines) {
|
---|
198 | if (paddingLines.length === 0) {
|
---|
199 | return;
|
---|
200 | }
|
---|
201 |
|
---|
202 | context.report({
|
---|
203 | node: nextNode,
|
---|
204 | messageId: "unexpectedBlankLine",
|
---|
205 | fix(fixer) {
|
---|
206 | if (paddingLines.length >= 2) {
|
---|
207 | return null;
|
---|
208 | }
|
---|
209 |
|
---|
210 | const prevToken = paddingLines[0][0];
|
---|
211 | const nextToken = paddingLines[0][1];
|
---|
212 | const start = prevToken.range[1];
|
---|
213 | const end = nextToken.range[0];
|
---|
214 | const text = context.sourceCode.text
|
---|
215 | .slice(start, end)
|
---|
216 | .replace(PADDING_LINE_SEQUENCE, replacerToRemovePaddingLines);
|
---|
217 |
|
---|
218 | return fixer.replaceTextRange([start, end], text);
|
---|
219 | }
|
---|
220 | });
|
---|
221 | }
|
---|
222 |
|
---|
223 | /**
|
---|
224 | * Check and report statements for `always` configuration.
|
---|
225 | * This autofix inserts a blank line between the given 2 statements.
|
---|
226 | * If the `prevNode` has trailing comments, it inserts a blank line after the
|
---|
227 | * trailing comments.
|
---|
228 | * @param {RuleContext} context The rule context to report.
|
---|
229 | * @param {ASTNode} prevNode The previous node to check.
|
---|
230 | * @param {ASTNode} nextNode The next node to check.
|
---|
231 | * @param {Array<Token[]>} paddingLines The array of token pairs that blank
|
---|
232 | * lines exist between the pair.
|
---|
233 | * @returns {void}
|
---|
234 | * @private
|
---|
235 | */
|
---|
236 | function verifyForAlways(context, prevNode, nextNode, paddingLines) {
|
---|
237 | if (paddingLines.length > 0) {
|
---|
238 | return;
|
---|
239 | }
|
---|
240 |
|
---|
241 | context.report({
|
---|
242 | node: nextNode,
|
---|
243 | messageId: "expectedBlankLine",
|
---|
244 | fix(fixer) {
|
---|
245 | const sourceCode = context.sourceCode;
|
---|
246 | let prevToken = getActualLastToken(sourceCode, prevNode);
|
---|
247 | const nextToken = sourceCode.getFirstTokenBetween(
|
---|
248 | prevToken,
|
---|
249 | nextNode,
|
---|
250 | {
|
---|
251 | includeComments: true,
|
---|
252 |
|
---|
253 | /**
|
---|
254 | * Skip the trailing comments of the previous node.
|
---|
255 | * This inserts a blank line after the last trailing comment.
|
---|
256 | *
|
---|
257 | * For example:
|
---|
258 | *
|
---|
259 | * foo(); // trailing comment.
|
---|
260 | * // comment.
|
---|
261 | * bar();
|
---|
262 | *
|
---|
263 | * Get fixed to:
|
---|
264 | *
|
---|
265 | * foo(); // trailing comment.
|
---|
266 | *
|
---|
267 | * // comment.
|
---|
268 | * bar();
|
---|
269 | * @param {Token} token The token to check.
|
---|
270 | * @returns {boolean} `true` if the token is not a trailing comment.
|
---|
271 | * @private
|
---|
272 | */
|
---|
273 | filter(token) {
|
---|
274 | if (astUtils.isTokenOnSameLine(prevToken, token)) {
|
---|
275 | prevToken = token;
|
---|
276 | return false;
|
---|
277 | }
|
---|
278 | return true;
|
---|
279 | }
|
---|
280 | }
|
---|
281 | ) || nextNode;
|
---|
282 | const insertText = astUtils.isTokenOnSameLine(prevToken, nextToken)
|
---|
283 | ? "\n\n"
|
---|
284 | : "\n";
|
---|
285 |
|
---|
286 | return fixer.insertTextAfter(prevToken, insertText);
|
---|
287 | }
|
---|
288 | });
|
---|
289 | }
|
---|
290 |
|
---|
291 | /**
|
---|
292 | * Types of blank lines.
|
---|
293 | * `any`, `never`, and `always` are defined.
|
---|
294 | * Those have `verify` method to check and report statements.
|
---|
295 | * @private
|
---|
296 | */
|
---|
297 | const PaddingTypes = {
|
---|
298 | any: { verify: verifyForAny },
|
---|
299 | never: { verify: verifyForNever },
|
---|
300 | always: { verify: verifyForAlways }
|
---|
301 | };
|
---|
302 |
|
---|
303 | /**
|
---|
304 | * Types of statements.
|
---|
305 | * Those have `test` method to check it matches to the given statement.
|
---|
306 | * @private
|
---|
307 | */
|
---|
308 | const StatementTypes = {
|
---|
309 | "*": { test: () => true },
|
---|
310 | "block-like": {
|
---|
311 | test: (node, sourceCode) => isBlockLikeStatement(sourceCode, node)
|
---|
312 | },
|
---|
313 | "cjs-export": {
|
---|
314 | test: (node, sourceCode) =>
|
---|
315 | node.type === "ExpressionStatement" &&
|
---|
316 | node.expression.type === "AssignmentExpression" &&
|
---|
317 | CJS_EXPORT.test(sourceCode.getText(node.expression.left))
|
---|
318 | },
|
---|
319 | "cjs-import": {
|
---|
320 | test: (node, sourceCode) =>
|
---|
321 | node.type === "VariableDeclaration" &&
|
---|
322 | node.declarations.length > 0 &&
|
---|
323 | Boolean(node.declarations[0].init) &&
|
---|
324 | CJS_IMPORT.test(sourceCode.getText(node.declarations[0].init))
|
---|
325 | },
|
---|
326 | directive: {
|
---|
327 | test: astUtils.isDirective
|
---|
328 | },
|
---|
329 | expression: {
|
---|
330 | test: node => node.type === "ExpressionStatement" && !astUtils.isDirective(node)
|
---|
331 | },
|
---|
332 | iife: {
|
---|
333 | test: isIIFEStatement
|
---|
334 | },
|
---|
335 | "multiline-block-like": {
|
---|
336 | test: (node, sourceCode) =>
|
---|
337 | node.loc.start.line !== node.loc.end.line &&
|
---|
338 | isBlockLikeStatement(sourceCode, node)
|
---|
339 | },
|
---|
340 | "multiline-expression": {
|
---|
341 | test: node =>
|
---|
342 | node.loc.start.line !== node.loc.end.line &&
|
---|
343 | node.type === "ExpressionStatement" &&
|
---|
344 | !astUtils.isDirective(node)
|
---|
345 | },
|
---|
346 |
|
---|
347 | "multiline-const": newMultilineKeywordTester("const"),
|
---|
348 | "multiline-let": newMultilineKeywordTester("let"),
|
---|
349 | "multiline-var": newMultilineKeywordTester("var"),
|
---|
350 | "singleline-const": newSinglelineKeywordTester("const"),
|
---|
351 | "singleline-let": newSinglelineKeywordTester("let"),
|
---|
352 | "singleline-var": newSinglelineKeywordTester("var"),
|
---|
353 |
|
---|
354 | block: newNodeTypeTester("BlockStatement"),
|
---|
355 | empty: newNodeTypeTester("EmptyStatement"),
|
---|
356 | function: newNodeTypeTester("FunctionDeclaration"),
|
---|
357 |
|
---|
358 | break: newKeywordTester("break"),
|
---|
359 | case: newKeywordTester("case"),
|
---|
360 | class: newKeywordTester("class"),
|
---|
361 | const: newKeywordTester("const"),
|
---|
362 | continue: newKeywordTester("continue"),
|
---|
363 | debugger: newKeywordTester("debugger"),
|
---|
364 | default: newKeywordTester("default"),
|
---|
365 | do: newKeywordTester("do"),
|
---|
366 | export: newKeywordTester("export"),
|
---|
367 | for: newKeywordTester("for"),
|
---|
368 | if: newKeywordTester("if"),
|
---|
369 | import: newKeywordTester("import"),
|
---|
370 | let: newKeywordTester("let"),
|
---|
371 | return: newKeywordTester("return"),
|
---|
372 | switch: newKeywordTester("switch"),
|
---|
373 | throw: newKeywordTester("throw"),
|
---|
374 | try: newKeywordTester("try"),
|
---|
375 | var: newKeywordTester("var"),
|
---|
376 | while: newKeywordTester("while"),
|
---|
377 | with: newKeywordTester("with")
|
---|
378 | };
|
---|
379 |
|
---|
380 | //------------------------------------------------------------------------------
|
---|
381 | // Rule Definition
|
---|
382 | //------------------------------------------------------------------------------
|
---|
383 |
|
---|
384 | /** @type {import('../shared/types').Rule} */
|
---|
385 | module.exports = {
|
---|
386 | meta: {
|
---|
387 | deprecated: true,
|
---|
388 | replacedBy: [],
|
---|
389 | type: "layout",
|
---|
390 |
|
---|
391 | docs: {
|
---|
392 | description: "Require or disallow padding lines between statements",
|
---|
393 | recommended: false,
|
---|
394 | url: "https://eslint.org/docs/latest/rules/padding-line-between-statements"
|
---|
395 | },
|
---|
396 |
|
---|
397 | fixable: "whitespace",
|
---|
398 |
|
---|
399 | schema: {
|
---|
400 | definitions: {
|
---|
401 | paddingType: {
|
---|
402 | enum: Object.keys(PaddingTypes)
|
---|
403 | },
|
---|
404 | statementType: {
|
---|
405 | anyOf: [
|
---|
406 | { enum: Object.keys(StatementTypes) },
|
---|
407 | {
|
---|
408 | type: "array",
|
---|
409 | items: { enum: Object.keys(StatementTypes) },
|
---|
410 | minItems: 1,
|
---|
411 | uniqueItems: true
|
---|
412 | }
|
---|
413 | ]
|
---|
414 | }
|
---|
415 | },
|
---|
416 | type: "array",
|
---|
417 | items: {
|
---|
418 | type: "object",
|
---|
419 | properties: {
|
---|
420 | blankLine: { $ref: "#/definitions/paddingType" },
|
---|
421 | prev: { $ref: "#/definitions/statementType" },
|
---|
422 | next: { $ref: "#/definitions/statementType" }
|
---|
423 | },
|
---|
424 | additionalProperties: false,
|
---|
425 | required: ["blankLine", "prev", "next"]
|
---|
426 | }
|
---|
427 | },
|
---|
428 |
|
---|
429 | messages: {
|
---|
430 | unexpectedBlankLine: "Unexpected blank line before this statement.",
|
---|
431 | expectedBlankLine: "Expected blank line before this statement."
|
---|
432 | }
|
---|
433 | },
|
---|
434 |
|
---|
435 | create(context) {
|
---|
436 | const sourceCode = context.sourceCode;
|
---|
437 | const configureList = context.options || [];
|
---|
438 | let scopeInfo = null;
|
---|
439 |
|
---|
440 | /**
|
---|
441 | * Processes to enter to new scope.
|
---|
442 | * This manages the current previous statement.
|
---|
443 | * @returns {void}
|
---|
444 | * @private
|
---|
445 | */
|
---|
446 | function enterScope() {
|
---|
447 | scopeInfo = {
|
---|
448 | upper: scopeInfo,
|
---|
449 | prevNode: null
|
---|
450 | };
|
---|
451 | }
|
---|
452 |
|
---|
453 | /**
|
---|
454 | * Processes to exit from the current scope.
|
---|
455 | * @returns {void}
|
---|
456 | * @private
|
---|
457 | */
|
---|
458 | function exitScope() {
|
---|
459 | scopeInfo = scopeInfo.upper;
|
---|
460 | }
|
---|
461 |
|
---|
462 | /**
|
---|
463 | * Checks whether the given node matches the given type.
|
---|
464 | * @param {ASTNode} node The statement node to check.
|
---|
465 | * @param {string|string[]} type The statement type to check.
|
---|
466 | * @returns {boolean} `true` if the statement node matched the type.
|
---|
467 | * @private
|
---|
468 | */
|
---|
469 | function match(node, type) {
|
---|
470 | let innerStatementNode = node;
|
---|
471 |
|
---|
472 | while (innerStatementNode.type === "LabeledStatement") {
|
---|
473 | innerStatementNode = innerStatementNode.body;
|
---|
474 | }
|
---|
475 | if (Array.isArray(type)) {
|
---|
476 | return type.some(match.bind(null, innerStatementNode));
|
---|
477 | }
|
---|
478 | return StatementTypes[type].test(innerStatementNode, sourceCode);
|
---|
479 | }
|
---|
480 |
|
---|
481 | /**
|
---|
482 | * Finds the last matched configure from configureList.
|
---|
483 | * @param {ASTNode} prevNode The previous statement to match.
|
---|
484 | * @param {ASTNode} nextNode The current statement to match.
|
---|
485 | * @returns {Object} The tester of the last matched configure.
|
---|
486 | * @private
|
---|
487 | */
|
---|
488 | function getPaddingType(prevNode, nextNode) {
|
---|
489 | for (let i = configureList.length - 1; i >= 0; --i) {
|
---|
490 | const configure = configureList[i];
|
---|
491 | const matched =
|
---|
492 | match(prevNode, configure.prev) &&
|
---|
493 | match(nextNode, configure.next);
|
---|
494 |
|
---|
495 | if (matched) {
|
---|
496 | return PaddingTypes[configure.blankLine];
|
---|
497 | }
|
---|
498 | }
|
---|
499 | return PaddingTypes.any;
|
---|
500 | }
|
---|
501 |
|
---|
502 | /**
|
---|
503 | * Gets padding line sequences between the given 2 statements.
|
---|
504 | * Comments are separators of the padding line sequences.
|
---|
505 | * @param {ASTNode} prevNode The previous statement to count.
|
---|
506 | * @param {ASTNode} nextNode The current statement to count.
|
---|
507 | * @returns {Array<Token[]>} The array of token pairs.
|
---|
508 | * @private
|
---|
509 | */
|
---|
510 | function getPaddingLineSequences(prevNode, nextNode) {
|
---|
511 | const pairs = [];
|
---|
512 | let prevToken = getActualLastToken(sourceCode, prevNode);
|
---|
513 |
|
---|
514 | if (nextNode.loc.start.line - prevToken.loc.end.line >= 2) {
|
---|
515 | do {
|
---|
516 | const token = sourceCode.getTokenAfter(
|
---|
517 | prevToken,
|
---|
518 | { includeComments: true }
|
---|
519 | );
|
---|
520 |
|
---|
521 | if (token.loc.start.line - prevToken.loc.end.line >= 2) {
|
---|
522 | pairs.push([prevToken, token]);
|
---|
523 | }
|
---|
524 | prevToken = token;
|
---|
525 |
|
---|
526 | } while (prevToken.range[0] < nextNode.range[0]);
|
---|
527 | }
|
---|
528 |
|
---|
529 | return pairs;
|
---|
530 | }
|
---|
531 |
|
---|
532 | /**
|
---|
533 | * Verify padding lines between the given node and the previous node.
|
---|
534 | * @param {ASTNode} node The node to verify.
|
---|
535 | * @returns {void}
|
---|
536 | * @private
|
---|
537 | */
|
---|
538 | function verify(node) {
|
---|
539 | const parentType = node.parent.type;
|
---|
540 | const validParent =
|
---|
541 | astUtils.STATEMENT_LIST_PARENTS.has(parentType) ||
|
---|
542 | parentType === "SwitchStatement";
|
---|
543 |
|
---|
544 | if (!validParent) {
|
---|
545 | return;
|
---|
546 | }
|
---|
547 |
|
---|
548 | // Save this node as the current previous statement.
|
---|
549 | const prevNode = scopeInfo.prevNode;
|
---|
550 |
|
---|
551 | // Verify.
|
---|
552 | if (prevNode) {
|
---|
553 | const type = getPaddingType(prevNode, node);
|
---|
554 | const paddingLines = getPaddingLineSequences(prevNode, node);
|
---|
555 |
|
---|
556 | type.verify(context, prevNode, node, paddingLines);
|
---|
557 | }
|
---|
558 |
|
---|
559 | scopeInfo.prevNode = node;
|
---|
560 | }
|
---|
561 |
|
---|
562 | /**
|
---|
563 | * Verify padding lines between the given node and the previous node.
|
---|
564 | * Then process to enter to new scope.
|
---|
565 | * @param {ASTNode} node The node to verify.
|
---|
566 | * @returns {void}
|
---|
567 | * @private
|
---|
568 | */
|
---|
569 | function verifyThenEnterScope(node) {
|
---|
570 | verify(node);
|
---|
571 | enterScope();
|
---|
572 | }
|
---|
573 |
|
---|
574 | return {
|
---|
575 | Program: enterScope,
|
---|
576 | BlockStatement: enterScope,
|
---|
577 | SwitchStatement: enterScope,
|
---|
578 | StaticBlock: enterScope,
|
---|
579 | "Program:exit": exitScope,
|
---|
580 | "BlockStatement:exit": exitScope,
|
---|
581 | "SwitchStatement:exit": exitScope,
|
---|
582 | "StaticBlock:exit": exitScope,
|
---|
583 |
|
---|
584 | ":statement": verify,
|
---|
585 |
|
---|
586 | SwitchCase: verifyThenEnterScope,
|
---|
587 | "SwitchCase:exit": exitScope
|
---|
588 | };
|
---|
589 | }
|
---|
590 | };
|
---|