591 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			591 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/**
 | 
						|
 * @fileoverview Rule to require or disallow newlines between statements
 | 
						|
 * @author Toru Nagashima
 | 
						|
 * @deprecated in ESLint v8.53.0
 | 
						|
 */
 | 
						|
 | 
						|
"use strict";
 | 
						|
 | 
						|
//------------------------------------------------------------------------------
 | 
						|
// Requirements
 | 
						|
//------------------------------------------------------------------------------
 | 
						|
 | 
						|
const astUtils = require("./utils/ast-utils");
 | 
						|
 | 
						|
//------------------------------------------------------------------------------
 | 
						|
// Helpers
 | 
						|
//------------------------------------------------------------------------------
 | 
						|
 | 
						|
const LT = `[${Array.from(astUtils.LINEBREAKS).join("")}]`;
 | 
						|
const PADDING_LINE_SEQUENCE = new RegExp(
 | 
						|
    String.raw`^(\s*?${LT})\s*${LT}(\s*;?)$`,
 | 
						|
    "u"
 | 
						|
);
 | 
						|
const CJS_EXPORT = /^(?:module\s*\.\s*)?exports(?:\s*\.|\s*\[|$)/u;
 | 
						|
const CJS_IMPORT = /^require\(/u;
 | 
						|
 | 
						|
/**
 | 
						|
 * Creates tester which check if a node starts with specific keyword.
 | 
						|
 * @param {string} keyword The keyword to test.
 | 
						|
 * @returns {Object} the created tester.
 | 
						|
 * @private
 | 
						|
 */
 | 
						|
function newKeywordTester(keyword) {
 | 
						|
    return {
 | 
						|
        test: (node, sourceCode) =>
 | 
						|
            sourceCode.getFirstToken(node).value === keyword
 | 
						|
    };
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Creates tester which check if a node starts with specific keyword and spans a single line.
 | 
						|
 * @param {string} keyword The keyword to test.
 | 
						|
 * @returns {Object} the created tester.
 | 
						|
 * @private
 | 
						|
 */
 | 
						|
function newSinglelineKeywordTester(keyword) {
 | 
						|
    return {
 | 
						|
        test: (node, sourceCode) =>
 | 
						|
            node.loc.start.line === node.loc.end.line &&
 | 
						|
            sourceCode.getFirstToken(node).value === keyword
 | 
						|
    };
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Creates tester which check if a node starts with specific keyword and spans multiple lines.
 | 
						|
 * @param {string} keyword The keyword to test.
 | 
						|
 * @returns {Object} the created tester.
 | 
						|
 * @private
 | 
						|
 */
 | 
						|
function newMultilineKeywordTester(keyword) {
 | 
						|
    return {
 | 
						|
        test: (node, sourceCode) =>
 | 
						|
            node.loc.start.line !== node.loc.end.line &&
 | 
						|
            sourceCode.getFirstToken(node).value === keyword
 | 
						|
    };
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Creates tester which check if a node is specific type.
 | 
						|
 * @param {string} type The node type to test.
 | 
						|
 * @returns {Object} the created tester.
 | 
						|
 * @private
 | 
						|
 */
 | 
						|
function newNodeTypeTester(type) {
 | 
						|
    return {
 | 
						|
        test: node =>
 | 
						|
            node.type === type
 | 
						|
    };
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Checks the given node is an expression statement of IIFE.
 | 
						|
 * @param {ASTNode} node The node to check.
 | 
						|
 * @returns {boolean} `true` if the node is an expression statement of IIFE.
 | 
						|
 * @private
 | 
						|
 */
 | 
						|
function isIIFEStatement(node) {
 | 
						|
    if (node.type === "ExpressionStatement") {
 | 
						|
        let call = astUtils.skipChainExpression(node.expression);
 | 
						|
 | 
						|
        if (call.type === "UnaryExpression") {
 | 
						|
            call = astUtils.skipChainExpression(call.argument);
 | 
						|
        }
 | 
						|
        return call.type === "CallExpression" && astUtils.isFunction(call.callee);
 | 
						|
    }
 | 
						|
    return false;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Checks whether the given node is a block-like statement.
 | 
						|
 * This checks the last token of the node is the closing brace of a block.
 | 
						|
 * @param {SourceCode} sourceCode The source code to get tokens.
 | 
						|
 * @param {ASTNode} node The node to check.
 | 
						|
 * @returns {boolean} `true` if the node is a block-like statement.
 | 
						|
 * @private
 | 
						|
 */
 | 
						|
function isBlockLikeStatement(sourceCode, node) {
 | 
						|
 | 
						|
    // do-while with a block is a block-like statement.
 | 
						|
    if (node.type === "DoWhileStatement" && node.body.type === "BlockStatement") {
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    /*
 | 
						|
     * IIFE is a block-like statement specially from
 | 
						|
     * JSCS#disallowPaddingNewLinesAfterBlocks.
 | 
						|
     */
 | 
						|
    if (isIIFEStatement(node)) {
 | 
						|
        return true;
 | 
						|
    }
 | 
						|
 | 
						|
    // Checks the last token is a closing brace of blocks.
 | 
						|
    const lastToken = sourceCode.getLastToken(node, astUtils.isNotSemicolonToken);
 | 
						|
    const belongingNode = lastToken && astUtils.isClosingBraceToken(lastToken)
 | 
						|
        ? sourceCode.getNodeByRangeIndex(lastToken.range[0])
 | 
						|
        : null;
 | 
						|
 | 
						|
    return Boolean(belongingNode) && (
 | 
						|
        belongingNode.type === "BlockStatement" ||
 | 
						|
        belongingNode.type === "SwitchStatement"
 | 
						|
    );
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Gets the actual last token.
 | 
						|
 *
 | 
						|
 * If a semicolon is semicolon-less style's semicolon, this ignores it.
 | 
						|
 * For example:
 | 
						|
 *
 | 
						|
 *     foo()
 | 
						|
 *     ;[1, 2, 3].forEach(bar)
 | 
						|
 * @param {SourceCode} sourceCode The source code to get tokens.
 | 
						|
 * @param {ASTNode} node The node to get.
 | 
						|
 * @returns {Token} The actual last token.
 | 
						|
 * @private
 | 
						|
 */
 | 
						|
function getActualLastToken(sourceCode, node) {
 | 
						|
    const semiToken = sourceCode.getLastToken(node);
 | 
						|
    const prevToken = sourceCode.getTokenBefore(semiToken);
 | 
						|
    const nextToken = sourceCode.getTokenAfter(semiToken);
 | 
						|
    const isSemicolonLessStyle = Boolean(
 | 
						|
        prevToken &&
 | 
						|
        nextToken &&
 | 
						|
        prevToken.range[0] >= node.range[0] &&
 | 
						|
        astUtils.isSemicolonToken(semiToken) &&
 | 
						|
        semiToken.loc.start.line !== prevToken.loc.end.line &&
 | 
						|
        semiToken.loc.end.line === nextToken.loc.start.line
 | 
						|
    );
 | 
						|
 | 
						|
    return isSemicolonLessStyle ? prevToken : semiToken;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * This returns the concatenation of the first 2 captured strings.
 | 
						|
 * @param {string} _ Unused. Whole matched string.
 | 
						|
 * @param {string} trailingSpaces The trailing spaces of the first line.
 | 
						|
 * @param {string} indentSpaces The indentation spaces of the last line.
 | 
						|
 * @returns {string} The concatenation of trailingSpaces and indentSpaces.
 | 
						|
 * @private
 | 
						|
 */
 | 
						|
function replacerToRemovePaddingLines(_, trailingSpaces, indentSpaces) {
 | 
						|
    return trailingSpaces + indentSpaces;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Check and report statements for `any` configuration.
 | 
						|
 * It does nothing.
 | 
						|
 * @returns {void}
 | 
						|
 * @private
 | 
						|
 */
 | 
						|
function verifyForAny() {
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Check and report statements for `never` configuration.
 | 
						|
 * This autofix removes blank lines between the given 2 statements.
 | 
						|
 * However, if comments exist between 2 blank lines, it does not remove those
 | 
						|
 * blank lines automatically.
 | 
						|
 * @param {RuleContext} context The rule context to report.
 | 
						|
 * @param {ASTNode} _ Unused. The previous node to check.
 | 
						|
 * @param {ASTNode} nextNode The next node to check.
 | 
						|
 * @param {Array<Token[]>} paddingLines The array of token pairs that blank
 | 
						|
 * lines exist between the pair.
 | 
						|
 * @returns {void}
 | 
						|
 * @private
 | 
						|
 */
 | 
						|
function verifyForNever(context, _, nextNode, paddingLines) {
 | 
						|
    if (paddingLines.length === 0) {
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    context.report({
 | 
						|
        node: nextNode,
 | 
						|
        messageId: "unexpectedBlankLine",
 | 
						|
        fix(fixer) {
 | 
						|
            if (paddingLines.length >= 2) {
 | 
						|
                return null;
 | 
						|
            }
 | 
						|
 | 
						|
            const prevToken = paddingLines[0][0];
 | 
						|
            const nextToken = paddingLines[0][1];
 | 
						|
            const start = prevToken.range[1];
 | 
						|
            const end = nextToken.range[0];
 | 
						|
            const text = context.sourceCode.text
 | 
						|
                .slice(start, end)
 | 
						|
                .replace(PADDING_LINE_SEQUENCE, replacerToRemovePaddingLines);
 | 
						|
 | 
						|
            return fixer.replaceTextRange([start, end], text);
 | 
						|
        }
 | 
						|
    });
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Check and report statements for `always` configuration.
 | 
						|
 * This autofix inserts a blank line between the given 2 statements.
 | 
						|
 * If the `prevNode` has trailing comments, it inserts a blank line after the
 | 
						|
 * trailing comments.
 | 
						|
 * @param {RuleContext} context The rule context to report.
 | 
						|
 * @param {ASTNode} prevNode The previous node to check.
 | 
						|
 * @param {ASTNode} nextNode The next node to check.
 | 
						|
 * @param {Array<Token[]>} paddingLines The array of token pairs that blank
 | 
						|
 * lines exist between the pair.
 | 
						|
 * @returns {void}
 | 
						|
 * @private
 | 
						|
 */
 | 
						|
function verifyForAlways(context, prevNode, nextNode, paddingLines) {
 | 
						|
    if (paddingLines.length > 0) {
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    context.report({
 | 
						|
        node: nextNode,
 | 
						|
        messageId: "expectedBlankLine",
 | 
						|
        fix(fixer) {
 | 
						|
            const sourceCode = context.sourceCode;
 | 
						|
            let prevToken = getActualLastToken(sourceCode, prevNode);
 | 
						|
            const nextToken = sourceCode.getFirstTokenBetween(
 | 
						|
                prevToken,
 | 
						|
                nextNode,
 | 
						|
                {
 | 
						|
                    includeComments: true,
 | 
						|
 | 
						|
                    /**
 | 
						|
                     * Skip the trailing comments of the previous node.
 | 
						|
                     * This inserts a blank line after the last trailing comment.
 | 
						|
                     *
 | 
						|
                     * For example:
 | 
						|
                     *
 | 
						|
                     *     foo(); // trailing comment.
 | 
						|
                     *     // comment.
 | 
						|
                     *     bar();
 | 
						|
                     *
 | 
						|
                     * Get fixed to:
 | 
						|
                     *
 | 
						|
                     *     foo(); // trailing comment.
 | 
						|
                     *
 | 
						|
                     *     // comment.
 | 
						|
                     *     bar();
 | 
						|
                     * @param {Token} token The token to check.
 | 
						|
                     * @returns {boolean} `true` if the token is not a trailing comment.
 | 
						|
                     * @private
 | 
						|
                     */
 | 
						|
                    filter(token) {
 | 
						|
                        if (astUtils.isTokenOnSameLine(prevToken, token)) {
 | 
						|
                            prevToken = token;
 | 
						|
                            return false;
 | 
						|
                        }
 | 
						|
                        return true;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            ) || nextNode;
 | 
						|
            const insertText = astUtils.isTokenOnSameLine(prevToken, nextToken)
 | 
						|
                ? "\n\n"
 | 
						|
                : "\n";
 | 
						|
 | 
						|
            return fixer.insertTextAfter(prevToken, insertText);
 | 
						|
        }
 | 
						|
    });
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Types of blank lines.
 | 
						|
 * `any`, `never`, and `always` are defined.
 | 
						|
 * Those have `verify` method to check and report statements.
 | 
						|
 * @private
 | 
						|
 */
 | 
						|
const PaddingTypes = {
 | 
						|
    any: { verify: verifyForAny },
 | 
						|
    never: { verify: verifyForNever },
 | 
						|
    always: { verify: verifyForAlways }
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * Types of statements.
 | 
						|
 * Those have `test` method to check it matches to the given statement.
 | 
						|
 * @private
 | 
						|
 */
 | 
						|
const StatementTypes = {
 | 
						|
    "*": { test: () => true },
 | 
						|
    "block-like": {
 | 
						|
        test: (node, sourceCode) => isBlockLikeStatement(sourceCode, node)
 | 
						|
    },
 | 
						|
    "cjs-export": {
 | 
						|
        test: (node, sourceCode) =>
 | 
						|
            node.type === "ExpressionStatement" &&
 | 
						|
            node.expression.type === "AssignmentExpression" &&
 | 
						|
            CJS_EXPORT.test(sourceCode.getText(node.expression.left))
 | 
						|
    },
 | 
						|
    "cjs-import": {
 | 
						|
        test: (node, sourceCode) =>
 | 
						|
            node.type === "VariableDeclaration" &&
 | 
						|
            node.declarations.length > 0 &&
 | 
						|
            Boolean(node.declarations[0].init) &&
 | 
						|
            CJS_IMPORT.test(sourceCode.getText(node.declarations[0].init))
 | 
						|
    },
 | 
						|
    directive: {
 | 
						|
        test: astUtils.isDirective
 | 
						|
    },
 | 
						|
    expression: {
 | 
						|
        test: node => node.type === "ExpressionStatement" && !astUtils.isDirective(node)
 | 
						|
    },
 | 
						|
    iife: {
 | 
						|
        test: isIIFEStatement
 | 
						|
    },
 | 
						|
    "multiline-block-like": {
 | 
						|
        test: (node, sourceCode) =>
 | 
						|
            node.loc.start.line !== node.loc.end.line &&
 | 
						|
            isBlockLikeStatement(sourceCode, node)
 | 
						|
    },
 | 
						|
    "multiline-expression": {
 | 
						|
        test: node =>
 | 
						|
            node.loc.start.line !== node.loc.end.line &&
 | 
						|
            node.type === "ExpressionStatement" &&
 | 
						|
            !astUtils.isDirective(node)
 | 
						|
    },
 | 
						|
 | 
						|
    "multiline-const": newMultilineKeywordTester("const"),
 | 
						|
    "multiline-let": newMultilineKeywordTester("let"),
 | 
						|
    "multiline-var": newMultilineKeywordTester("var"),
 | 
						|
    "singleline-const": newSinglelineKeywordTester("const"),
 | 
						|
    "singleline-let": newSinglelineKeywordTester("let"),
 | 
						|
    "singleline-var": newSinglelineKeywordTester("var"),
 | 
						|
 | 
						|
    block: newNodeTypeTester("BlockStatement"),
 | 
						|
    empty: newNodeTypeTester("EmptyStatement"),
 | 
						|
    function: newNodeTypeTester("FunctionDeclaration"),
 | 
						|
 | 
						|
    break: newKeywordTester("break"),
 | 
						|
    case: newKeywordTester("case"),
 | 
						|
    class: newKeywordTester("class"),
 | 
						|
    const: newKeywordTester("const"),
 | 
						|
    continue: newKeywordTester("continue"),
 | 
						|
    debugger: newKeywordTester("debugger"),
 | 
						|
    default: newKeywordTester("default"),
 | 
						|
    do: newKeywordTester("do"),
 | 
						|
    export: newKeywordTester("export"),
 | 
						|
    for: newKeywordTester("for"),
 | 
						|
    if: newKeywordTester("if"),
 | 
						|
    import: newKeywordTester("import"),
 | 
						|
    let: newKeywordTester("let"),
 | 
						|
    return: newKeywordTester("return"),
 | 
						|
    switch: newKeywordTester("switch"),
 | 
						|
    throw: newKeywordTester("throw"),
 | 
						|
    try: newKeywordTester("try"),
 | 
						|
    var: newKeywordTester("var"),
 | 
						|
    while: newKeywordTester("while"),
 | 
						|
    with: newKeywordTester("with")
 | 
						|
};
 | 
						|
 | 
						|
//------------------------------------------------------------------------------
 | 
						|
// Rule Definition
 | 
						|
//------------------------------------------------------------------------------
 | 
						|
 | 
						|
/** @type {import('../shared/types').Rule} */
 | 
						|
module.exports = {
 | 
						|
    meta: {
 | 
						|
        deprecated: true,
 | 
						|
        replacedBy: [],
 | 
						|
        type: "layout",
 | 
						|
 | 
						|
        docs: {
 | 
						|
            description: "Require or disallow padding lines between statements",
 | 
						|
            recommended: false,
 | 
						|
            url: "https://eslint.org/docs/latest/rules/padding-line-between-statements"
 | 
						|
        },
 | 
						|
 | 
						|
        fixable: "whitespace",
 | 
						|
 | 
						|
        schema: {
 | 
						|
            definitions: {
 | 
						|
                paddingType: {
 | 
						|
                    enum: Object.keys(PaddingTypes)
 | 
						|
                },
 | 
						|
                statementType: {
 | 
						|
                    anyOf: [
 | 
						|
                        { enum: Object.keys(StatementTypes) },
 | 
						|
                        {
 | 
						|
                            type: "array",
 | 
						|
                            items: { enum: Object.keys(StatementTypes) },
 | 
						|
                            minItems: 1,
 | 
						|
                            uniqueItems: true
 | 
						|
                        }
 | 
						|
                    ]
 | 
						|
                }
 | 
						|
            },
 | 
						|
            type: "array",
 | 
						|
            items: {
 | 
						|
                type: "object",
 | 
						|
                properties: {
 | 
						|
                    blankLine: { $ref: "#/definitions/paddingType" },
 | 
						|
                    prev: { $ref: "#/definitions/statementType" },
 | 
						|
                    next: { $ref: "#/definitions/statementType" }
 | 
						|
                },
 | 
						|
                additionalProperties: false,
 | 
						|
                required: ["blankLine", "prev", "next"]
 | 
						|
            }
 | 
						|
        },
 | 
						|
 | 
						|
        messages: {
 | 
						|
            unexpectedBlankLine: "Unexpected blank line before this statement.",
 | 
						|
            expectedBlankLine: "Expected blank line before this statement."
 | 
						|
        }
 | 
						|
    },
 | 
						|
 | 
						|
    create(context) {
 | 
						|
        const sourceCode = context.sourceCode;
 | 
						|
        const configureList = context.options || [];
 | 
						|
        let scopeInfo = null;
 | 
						|
 | 
						|
        /**
 | 
						|
         * Processes to enter to new scope.
 | 
						|
         * This manages the current previous statement.
 | 
						|
         * @returns {void}
 | 
						|
         * @private
 | 
						|
         */
 | 
						|
        function enterScope() {
 | 
						|
            scopeInfo = {
 | 
						|
                upper: scopeInfo,
 | 
						|
                prevNode: null
 | 
						|
            };
 | 
						|
        }
 | 
						|
 | 
						|
        /**
 | 
						|
         * Processes to exit from the current scope.
 | 
						|
         * @returns {void}
 | 
						|
         * @private
 | 
						|
         */
 | 
						|
        function exitScope() {
 | 
						|
            scopeInfo = scopeInfo.upper;
 | 
						|
        }
 | 
						|
 | 
						|
        /**
 | 
						|
         * Checks whether the given node matches the given type.
 | 
						|
         * @param {ASTNode} node The statement node to check.
 | 
						|
         * @param {string|string[]} type The statement type to check.
 | 
						|
         * @returns {boolean} `true` if the statement node matched the type.
 | 
						|
         * @private
 | 
						|
         */
 | 
						|
        function match(node, type) {
 | 
						|
            let innerStatementNode = node;
 | 
						|
 | 
						|
            while (innerStatementNode.type === "LabeledStatement") {
 | 
						|
                innerStatementNode = innerStatementNode.body;
 | 
						|
            }
 | 
						|
            if (Array.isArray(type)) {
 | 
						|
                return type.some(match.bind(null, innerStatementNode));
 | 
						|
            }
 | 
						|
            return StatementTypes[type].test(innerStatementNode, sourceCode);
 | 
						|
        }
 | 
						|
 | 
						|
        /**
 | 
						|
         * Finds the last matched configure from configureList.
 | 
						|
         * @param {ASTNode} prevNode The previous statement to match.
 | 
						|
         * @param {ASTNode} nextNode The current statement to match.
 | 
						|
         * @returns {Object} The tester of the last matched configure.
 | 
						|
         * @private
 | 
						|
         */
 | 
						|
        function getPaddingType(prevNode, nextNode) {
 | 
						|
            for (let i = configureList.length - 1; i >= 0; --i) {
 | 
						|
                const configure = configureList[i];
 | 
						|
                const matched =
 | 
						|
                    match(prevNode, configure.prev) &&
 | 
						|
                    match(nextNode, configure.next);
 | 
						|
 | 
						|
                if (matched) {
 | 
						|
                    return PaddingTypes[configure.blankLine];
 | 
						|
                }
 | 
						|
            }
 | 
						|
            return PaddingTypes.any;
 | 
						|
        }
 | 
						|
 | 
						|
        /**
 | 
						|
         * Gets padding line sequences between the given 2 statements.
 | 
						|
         * Comments are separators of the padding line sequences.
 | 
						|
         * @param {ASTNode} prevNode The previous statement to count.
 | 
						|
         * @param {ASTNode} nextNode The current statement to count.
 | 
						|
         * @returns {Array<Token[]>} The array of token pairs.
 | 
						|
         * @private
 | 
						|
         */
 | 
						|
        function getPaddingLineSequences(prevNode, nextNode) {
 | 
						|
            const pairs = [];
 | 
						|
            let prevToken = getActualLastToken(sourceCode, prevNode);
 | 
						|
 | 
						|
            if (nextNode.loc.start.line - prevToken.loc.end.line >= 2) {
 | 
						|
                do {
 | 
						|
                    const token = sourceCode.getTokenAfter(
 | 
						|
                        prevToken,
 | 
						|
                        { includeComments: true }
 | 
						|
                    );
 | 
						|
 | 
						|
                    if (token.loc.start.line - prevToken.loc.end.line >= 2) {
 | 
						|
                        pairs.push([prevToken, token]);
 | 
						|
                    }
 | 
						|
                    prevToken = token;
 | 
						|
 | 
						|
                } while (prevToken.range[0] < nextNode.range[0]);
 | 
						|
            }
 | 
						|
 | 
						|
            return pairs;
 | 
						|
        }
 | 
						|
 | 
						|
        /**
 | 
						|
         * Verify padding lines between the given node and the previous node.
 | 
						|
         * @param {ASTNode} node The node to verify.
 | 
						|
         * @returns {void}
 | 
						|
         * @private
 | 
						|
         */
 | 
						|
        function verify(node) {
 | 
						|
            const parentType = node.parent.type;
 | 
						|
            const validParent =
 | 
						|
                astUtils.STATEMENT_LIST_PARENTS.has(parentType) ||
 | 
						|
                parentType === "SwitchStatement";
 | 
						|
 | 
						|
            if (!validParent) {
 | 
						|
                return;
 | 
						|
            }
 | 
						|
 | 
						|
            // Save this node as the current previous statement.
 | 
						|
            const prevNode = scopeInfo.prevNode;
 | 
						|
 | 
						|
            // Verify.
 | 
						|
            if (prevNode) {
 | 
						|
                const type = getPaddingType(prevNode, node);
 | 
						|
                const paddingLines = getPaddingLineSequences(prevNode, node);
 | 
						|
 | 
						|
                type.verify(context, prevNode, node, paddingLines);
 | 
						|
            }
 | 
						|
 | 
						|
            scopeInfo.prevNode = node;
 | 
						|
        }
 | 
						|
 | 
						|
        /**
 | 
						|
         * Verify padding lines between the given node and the previous node.
 | 
						|
         * Then process to enter to new scope.
 | 
						|
         * @param {ASTNode} node The node to verify.
 | 
						|
         * @returns {void}
 | 
						|
         * @private
 | 
						|
         */
 | 
						|
        function verifyThenEnterScope(node) {
 | 
						|
            verify(node);
 | 
						|
            enterScope();
 | 
						|
        }
 | 
						|
 | 
						|
        return {
 | 
						|
            Program: enterScope,
 | 
						|
            BlockStatement: enterScope,
 | 
						|
            SwitchStatement: enterScope,
 | 
						|
            StaticBlock: enterScope,
 | 
						|
            "Program:exit": exitScope,
 | 
						|
            "BlockStatement:exit": exitScope,
 | 
						|
            "SwitchStatement:exit": exitScope,
 | 
						|
            "StaticBlock:exit": exitScope,
 | 
						|
 | 
						|
            ":statement": verify,
 | 
						|
 | 
						|
            SwitchCase: verifyThenEnterScope,
 | 
						|
            "SwitchCase:exit": exitScope
 | 
						|
        };
 | 
						|
    }
 | 
						|
};
 |