You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					1142 lines
				
				44 KiB
			
		
		
			
		
	
	
					1142 lines
				
				44 KiB
			| 
								 
											4 years ago
										 
									 | 
							
								/**
							 | 
						||
| 
								 | 
							
								 * @fileoverview This option sets a specific tab width for your code
							 | 
						||
| 
								 | 
							
								 *
							 | 
						||
| 
								 | 
							
								 * This rule has been ported and modified from nodeca.
							 | 
						||
| 
								 | 
							
								 * @author Vitaly Puzrin
							 | 
						||
| 
								 | 
							
								 * @author Gyandeep Singh
							 | 
						||
| 
								 | 
							
								 */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								"use strict";
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//------------------------------------------------------------------------------
							 | 
						||
| 
								 | 
							
								// Requirements
							 | 
						||
| 
								 | 
							
								//------------------------------------------------------------------------------
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const astUtils = require("./utils/ast-utils");
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//------------------------------------------------------------------------------
							 | 
						||
| 
								 | 
							
								// Rule Definition
							 | 
						||
| 
								 | 
							
								//------------------------------------------------------------------------------
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								/* istanbul ignore next: this rule has known coverage issues, but it's deprecated and shouldn't be updated in the future anyway. */
							 | 
						||
| 
								 | 
							
								module.exports = {
							 | 
						||
| 
								 | 
							
								    meta: {
							 | 
						||
| 
								 | 
							
								        type: "layout",
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        docs: {
							 | 
						||
| 
								 | 
							
								            description: "enforce consistent indentation",
							 | 
						||
| 
								 | 
							
								            category: "Stylistic Issues",
							 | 
						||
| 
								 | 
							
								            recommended: false,
							 | 
						||
| 
								 | 
							
								            url: "https://eslint.org/docs/rules/indent-legacy"
							 | 
						||
| 
								 | 
							
								        },
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        deprecated: true,
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        replacedBy: ["indent"],
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        fixable: "whitespace",
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        schema: [
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                oneOf: [
							 | 
						||
| 
								 | 
							
								                    {
							 | 
						||
| 
								 | 
							
								                        enum: ["tab"]
							 | 
						||
| 
								 | 
							
								                    },
							 | 
						||
| 
								 | 
							
								                    {
							 | 
						||
| 
								 | 
							
								                        type: "integer",
							 | 
						||
| 
								 | 
							
								                        minimum: 0
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								                ]
							 | 
						||
| 
								 | 
							
								            },
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								                type: "object",
							 | 
						||
| 
								 | 
							
								                properties: {
							 | 
						||
| 
								 | 
							
								                    SwitchCase: {
							 | 
						||
| 
								 | 
							
								                        type: "integer",
							 | 
						||
| 
								 | 
							
								                        minimum: 0
							 | 
						||
| 
								 | 
							
								                    },
							 | 
						||
| 
								 | 
							
								                    VariableDeclarator: {
							 | 
						||
| 
								 | 
							
								                        oneOf: [
							 | 
						||
| 
								 | 
							
								                            {
							 | 
						||
| 
								 | 
							
								                                type: "integer",
							 | 
						||
| 
								 | 
							
								                                minimum: 0
							 | 
						||
| 
								 | 
							
								                            },
							 | 
						||
| 
								 | 
							
								                            {
							 | 
						||
| 
								 | 
							
								                                type: "object",
							 | 
						||
| 
								 | 
							
								                                properties: {
							 | 
						||
| 
								 | 
							
								                                    var: {
							 | 
						||
| 
								 | 
							
								                                        type: "integer",
							 | 
						||
| 
								 | 
							
								                                        minimum: 0
							 | 
						||
| 
								 | 
							
								                                    },
							 | 
						||
| 
								 | 
							
								                                    let: {
							 | 
						||
| 
								 | 
							
								                                        type: "integer",
							 | 
						||
| 
								 | 
							
								                                        minimum: 0
							 | 
						||
| 
								 | 
							
								                                    },
							 | 
						||
| 
								 | 
							
								                                    const: {
							 | 
						||
| 
								 | 
							
								                                        type: "integer",
							 | 
						||
| 
								 | 
							
								                                        minimum: 0
							 | 
						||
| 
								 | 
							
								                                    }
							 | 
						||
| 
								 | 
							
								                                }
							 | 
						||
| 
								 | 
							
								                            }
							 | 
						||
| 
								 | 
							
								                        ]
							 | 
						||
| 
								 | 
							
								                    },
							 | 
						||
| 
								 | 
							
								                    outerIIFEBody: {
							 | 
						||
| 
								 | 
							
								                        type: "integer",
							 | 
						||
| 
								 | 
							
								                        minimum: 0
							 | 
						||
| 
								 | 
							
								                    },
							 | 
						||
| 
								 | 
							
								                    MemberExpression: {
							 | 
						||
| 
								 | 
							
								                        type: "integer",
							 | 
						||
| 
								 | 
							
								                        minimum: 0
							 | 
						||
| 
								 | 
							
								                    },
							 | 
						||
| 
								 | 
							
								                    FunctionDeclaration: {
							 | 
						||
| 
								 | 
							
								                        type: "object",
							 | 
						||
| 
								 | 
							
								                        properties: {
							 | 
						||
| 
								 | 
							
								                            parameters: {
							 | 
						||
| 
								 | 
							
								                                oneOf: [
							 | 
						||
| 
								 | 
							
								                                    {
							 | 
						||
| 
								 | 
							
								                                        type: "integer",
							 | 
						||
| 
								 | 
							
								                                        minimum: 0
							 | 
						||
| 
								 | 
							
								                                    },
							 | 
						||
| 
								 | 
							
								                                    {
							 | 
						||
| 
								 | 
							
								                                        enum: ["first"]
							 | 
						||
| 
								 | 
							
								                                    }
							 | 
						||
| 
								 | 
							
								                                ]
							 | 
						||
| 
								 | 
							
								                            },
							 | 
						||
| 
								 | 
							
								                            body: {
							 | 
						||
| 
								 | 
							
								                                type: "integer",
							 | 
						||
| 
								 | 
							
								                                minimum: 0
							 | 
						||
| 
								 | 
							
								                            }
							 | 
						||
| 
								 | 
							
								                        }
							 | 
						||
| 
								 | 
							
								                    },
							 | 
						||
| 
								 | 
							
								                    FunctionExpression: {
							 | 
						||
| 
								 | 
							
								                        type: "object",
							 | 
						||
| 
								 | 
							
								                        properties: {
							 | 
						||
| 
								 | 
							
								                            parameters: {
							 | 
						||
| 
								 | 
							
								                                oneOf: [
							 | 
						||
| 
								 | 
							
								                                    {
							 | 
						||
| 
								 | 
							
								                                        type: "integer",
							 | 
						||
| 
								 | 
							
								                                        minimum: 0
							 | 
						||
| 
								 | 
							
								                                    },
							 | 
						||
| 
								 | 
							
								                                    {
							 | 
						||
| 
								 | 
							
								                                        enum: ["first"]
							 | 
						||
| 
								 | 
							
								                                    }
							 | 
						||
| 
								 | 
							
								                                ]
							 | 
						||
| 
								 | 
							
								                            },
							 | 
						||
| 
								 | 
							
								                            body: {
							 | 
						||
| 
								 | 
							
								                                type: "integer",
							 | 
						||
| 
								 | 
							
								                                minimum: 0
							 | 
						||
| 
								 | 
							
								                            }
							 | 
						||
| 
								 | 
							
								                        }
							 | 
						||
| 
								 | 
							
								                    },
							 | 
						||
| 
								 | 
							
								                    CallExpression: {
							 | 
						||
| 
								 | 
							
								                        type: "object",
							 | 
						||
| 
								 | 
							
								                        properties: {
							 | 
						||
| 
								 | 
							
								                            parameters: {
							 | 
						||
| 
								 | 
							
								                                oneOf: [
							 | 
						||
| 
								 | 
							
								                                    {
							 | 
						||
| 
								 | 
							
								                                        type: "integer",
							 | 
						||
| 
								 | 
							
								                                        minimum: 0
							 | 
						||
| 
								 | 
							
								                                    },
							 | 
						||
| 
								 | 
							
								                                    {
							 | 
						||
| 
								 | 
							
								                                        enum: ["first"]
							 | 
						||
| 
								 | 
							
								                                    }
							 | 
						||
| 
								 | 
							
								                                ]
							 | 
						||
| 
								 | 
							
								                            }
							 | 
						||
| 
								 | 
							
								                        }
							 | 
						||
| 
								 | 
							
								                    },
							 | 
						||
| 
								 | 
							
								                    ArrayExpression: {
							 | 
						||
| 
								 | 
							
								                        oneOf: [
							 | 
						||
| 
								 | 
							
								                            {
							 | 
						||
| 
								 | 
							
								                                type: "integer",
							 | 
						||
| 
								 | 
							
								                                minimum: 0
							 | 
						||
| 
								 | 
							
								                            },
							 | 
						||
| 
								 | 
							
								                            {
							 | 
						||
| 
								 | 
							
								                                enum: ["first"]
							 | 
						||
| 
								 | 
							
								                            }
							 | 
						||
| 
								 | 
							
								                        ]
							 | 
						||
| 
								 | 
							
								                    },
							 | 
						||
| 
								 | 
							
								                    ObjectExpression: {
							 | 
						||
| 
								 | 
							
								                        oneOf: [
							 | 
						||
| 
								 | 
							
								                            {
							 | 
						||
| 
								 | 
							
								                                type: "integer",
							 | 
						||
| 
								 | 
							
								                                minimum: 0
							 | 
						||
| 
								 | 
							
								                            },
							 | 
						||
| 
								 | 
							
								                            {
							 | 
						||
| 
								 | 
							
								                                enum: ["first"]
							 | 
						||
| 
								 | 
							
								                            }
							 | 
						||
| 
								 | 
							
								                        ]
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								                },
							 | 
						||
| 
								 | 
							
								                additionalProperties: false
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        ],
							 | 
						||
| 
								 | 
							
								        messages: {
							 | 
						||
| 
								 | 
							
								            expected: "Expected indentation of {{expected}} but found {{actual}}."
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								    },
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    create(context) {
							 | 
						||
| 
								 | 
							
								        const DEFAULT_VARIABLE_INDENT = 1;
							 | 
						||
| 
								 | 
							
								        const DEFAULT_PARAMETER_INDENT = null; // For backwards compatibility, don't check parameter indentation unless specified in the config
							 | 
						||
| 
								 | 
							
								        const DEFAULT_FUNCTION_BODY_INDENT = 1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        let indentType = "space";
							 | 
						||
| 
								 | 
							
								        let indentSize = 4;
							 | 
						||
| 
								 | 
							
								        const options = {
							 | 
						||
| 
								 | 
							
								            SwitchCase: 0,
							 | 
						||
| 
								 | 
							
								            VariableDeclarator: {
							 | 
						||
| 
								 | 
							
								                var: DEFAULT_VARIABLE_INDENT,
							 | 
						||
| 
								 | 
							
								                let: DEFAULT_VARIABLE_INDENT,
							 | 
						||
| 
								 | 
							
								                const: DEFAULT_VARIABLE_INDENT
							 | 
						||
| 
								 | 
							
								            },
							 | 
						||
| 
								 | 
							
								            outerIIFEBody: null,
							 | 
						||
| 
								 | 
							
								            FunctionDeclaration: {
							 | 
						||
| 
								 | 
							
								                parameters: DEFAULT_PARAMETER_INDENT,
							 | 
						||
| 
								 | 
							
								                body: DEFAULT_FUNCTION_BODY_INDENT
							 | 
						||
| 
								 | 
							
								            },
							 | 
						||
| 
								 | 
							
								            FunctionExpression: {
							 | 
						||
| 
								 | 
							
								                parameters: DEFAULT_PARAMETER_INDENT,
							 | 
						||
| 
								 | 
							
								                body: DEFAULT_FUNCTION_BODY_INDENT
							 | 
						||
| 
								 | 
							
								            },
							 | 
						||
| 
								 | 
							
								            CallExpression: {
							 | 
						||
| 
								 | 
							
								                arguments: DEFAULT_PARAMETER_INDENT
							 | 
						||
| 
								 | 
							
								            },
							 | 
						||
| 
								 | 
							
								            ArrayExpression: 1,
							 | 
						||
| 
								 | 
							
								            ObjectExpression: 1
							 | 
						||
| 
								 | 
							
								        };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        const sourceCode = context.getSourceCode();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if (context.options.length) {
							 | 
						||
| 
								 | 
							
								            if (context.options[0] === "tab") {
							 | 
						||
| 
								 | 
							
								                indentSize = 1;
							 | 
						||
| 
								 | 
							
								                indentType = "tab";
							 | 
						||
| 
								 | 
							
								            } else /* istanbul ignore else : this will be caught by options validation */ if (typeof context.options[0] === "number") {
							 | 
						||
| 
								 | 
							
								                indentSize = context.options[0];
							 | 
						||
| 
								 | 
							
								                indentType = "space";
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (context.options[1]) {
							 | 
						||
| 
								 | 
							
								                const opts = context.options[1];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                options.SwitchCase = opts.SwitchCase || 0;
							 | 
						||
| 
								 | 
							
								                const variableDeclaratorRules = opts.VariableDeclarator;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                if (typeof variableDeclaratorRules === "number") {
							 | 
						||
| 
								 | 
							
								                    options.VariableDeclarator = {
							 | 
						||
| 
								 | 
							
								                        var: variableDeclaratorRules,
							 | 
						||
| 
								 | 
							
								                        let: variableDeclaratorRules,
							 | 
						||
| 
								 | 
							
								                        const: variableDeclaratorRules
							 | 
						||
| 
								 | 
							
								                    };
							 | 
						||
| 
								 | 
							
								                } else if (typeof variableDeclaratorRules === "object") {
							 | 
						||
| 
								 | 
							
								                    Object.assign(options.VariableDeclarator, variableDeclaratorRules);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                if (typeof opts.outerIIFEBody === "number") {
							 | 
						||
| 
								 | 
							
								                    options.outerIIFEBody = opts.outerIIFEBody;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                if (typeof opts.MemberExpression === "number") {
							 | 
						||
| 
								 | 
							
								                    options.MemberExpression = opts.MemberExpression;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                if (typeof opts.FunctionDeclaration === "object") {
							 | 
						||
| 
								 | 
							
								                    Object.assign(options.FunctionDeclaration, opts.FunctionDeclaration);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                if (typeof opts.FunctionExpression === "object") {
							 | 
						||
| 
								 | 
							
								                    Object.assign(options.FunctionExpression, opts.FunctionExpression);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                if (typeof opts.CallExpression === "object") {
							 | 
						||
| 
								 | 
							
								                    Object.assign(options.CallExpression, opts.CallExpression);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                if (typeof opts.ArrayExpression === "number" || typeof opts.ArrayExpression === "string") {
							 | 
						||
| 
								 | 
							
								                    options.ArrayExpression = opts.ArrayExpression;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                if (typeof opts.ObjectExpression === "number" || typeof opts.ObjectExpression === "string") {
							 | 
						||
| 
								 | 
							
								                    options.ObjectExpression = opts.ObjectExpression;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        const caseIndentStore = {};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /**
							 | 
						||
| 
								 | 
							
								         * Creates an error message for a line, given the expected/actual indentation.
							 | 
						||
| 
								 | 
							
								         * @param {int} expectedAmount The expected amount of indentation characters for this line
							 | 
						||
| 
								 | 
							
								         * @param {int} actualSpaces The actual number of indentation spaces that were found on this line
							 | 
						||
| 
								 | 
							
								         * @param {int} actualTabs The actual number of indentation tabs that were found on this line
							 | 
						||
| 
								 | 
							
								         * @returns {string} An error message for this line
							 | 
						||
| 
								 | 
							
								         */
							 | 
						||
| 
								 | 
							
								        function createErrorMessageData(expectedAmount, actualSpaces, actualTabs) {
							 | 
						||
| 
								 | 
							
								            const expectedStatement = `${expectedAmount} ${indentType}${expectedAmount === 1 ? "" : "s"}`; // e.g. "2 tabs"
							 | 
						||
| 
								 | 
							
								            const foundSpacesWord = `space${actualSpaces === 1 ? "" : "s"}`; // e.g. "space"
							 | 
						||
| 
								 | 
							
								            const foundTabsWord = `tab${actualTabs === 1 ? "" : "s"}`; // e.g. "tabs"
							 | 
						||
| 
								 | 
							
								            let foundStatement;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (actualSpaces > 0 && actualTabs > 0) {
							 | 
						||
| 
								 | 
							
								                foundStatement = `${actualSpaces} ${foundSpacesWord} and ${actualTabs} ${foundTabsWord}`; // e.g. "1 space and 2 tabs"
							 | 
						||
| 
								 | 
							
								            } else if (actualSpaces > 0) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                /*
							 | 
						||
| 
								 | 
							
								                 * Abbreviate the message if the expected indentation is also spaces.
							 | 
						||
| 
								 | 
							
								                 * e.g. 'Expected 4 spaces but found 2' rather than 'Expected 4 spaces but found 2 spaces'
							 | 
						||
| 
								 | 
							
								                 */
							 | 
						||
| 
								 | 
							
								                foundStatement = indentType === "space" ? actualSpaces : `${actualSpaces} ${foundSpacesWord}`;
							 | 
						||
| 
								 | 
							
								            } else if (actualTabs > 0) {
							 | 
						||
| 
								 | 
							
								                foundStatement = indentType === "tab" ? actualTabs : `${actualTabs} ${foundTabsWord}`;
							 | 
						||
| 
								 | 
							
								            } else {
							 | 
						||
| 
								 | 
							
								                foundStatement = "0";
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            return {
							 | 
						||
| 
								 | 
							
								                expected: expectedStatement,
							 | 
						||
| 
								 | 
							
								                actual: foundStatement
							 | 
						||
| 
								 | 
							
								            };
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /**
							 | 
						||
| 
								 | 
							
								         * Reports a given indent violation
							 | 
						||
| 
								 | 
							
								         * @param {ASTNode} node Node violating the indent rule
							 | 
						||
| 
								 | 
							
								         * @param {int} needed Expected indentation character count
							 | 
						||
| 
								 | 
							
								         * @param {int} gottenSpaces Indentation space count in the actual node/code
							 | 
						||
| 
								 | 
							
								         * @param {int} gottenTabs Indentation tab count in the actual node/code
							 | 
						||
| 
								 | 
							
								         * @param {Object} [loc] Error line and column location
							 | 
						||
| 
								 | 
							
								         * @param {boolean} isLastNodeCheck Is the error for last node check
							 | 
						||
| 
								 | 
							
								         * @returns {void}
							 | 
						||
| 
								 | 
							
								         */
							 | 
						||
| 
								 | 
							
								        function report(node, needed, gottenSpaces, gottenTabs, loc, isLastNodeCheck) {
							 | 
						||
| 
								 | 
							
								            if (gottenSpaces && gottenTabs) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                // To avoid conflicts with `no-mixed-spaces-and-tabs`, don't report lines that have both spaces and tabs.
							 | 
						||
| 
								 | 
							
								                return;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            const desiredIndent = (indentType === "space" ? " " : "\t").repeat(needed);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            const textRange = isLastNodeCheck
							 | 
						||
| 
								 | 
							
								                ? [node.range[1] - node.loc.end.column, node.range[1] - node.loc.end.column + gottenSpaces + gottenTabs]
							 | 
						||
| 
								 | 
							
								                : [node.range[0] - node.loc.start.column, node.range[0] - node.loc.start.column + gottenSpaces + gottenTabs];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            context.report({
							 | 
						||
| 
								 | 
							
								                node,
							 | 
						||
| 
								 | 
							
								                loc,
							 | 
						||
| 
								 | 
							
								                messageId: "expected",
							 | 
						||
| 
								 | 
							
								                data: createErrorMessageData(needed, gottenSpaces, gottenTabs),
							 | 
						||
| 
								 | 
							
								                fix: fixer => fixer.replaceTextRange(textRange, desiredIndent)
							 | 
						||
| 
								 | 
							
								            });
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /**
							 | 
						||
| 
								 | 
							
								         * Get the actual indent of node
							 | 
						||
| 
								 | 
							
								         * @param {ASTNode|Token} node Node to examine
							 | 
						||
| 
								 | 
							
								         * @param {boolean} [byLastLine=false] get indent of node's last line
							 | 
						||
| 
								 | 
							
								         * @returns {Object} The node's indent. Contains keys `space` and `tab`, representing the indent of each character. Also
							 | 
						||
| 
								 | 
							
								         * contains keys `goodChar` and `badChar`, where `goodChar` is the amount of the user's desired indentation character, and
							 | 
						||
| 
								 | 
							
								         * `badChar` is the amount of the other indentation character.
							 | 
						||
| 
								 | 
							
								         */
							 | 
						||
| 
								 | 
							
								        function getNodeIndent(node, byLastLine) {
							 | 
						||
| 
								 | 
							
								            const token = byLastLine ? sourceCode.getLastToken(node) : sourceCode.getFirstToken(node);
							 | 
						||
| 
								 | 
							
								            const srcCharsBeforeNode = sourceCode.getText(token, token.loc.start.column).split("");
							 | 
						||
| 
								 | 
							
								            const indentChars = srcCharsBeforeNode.slice(0, srcCharsBeforeNode.findIndex(char => char !== " " && char !== "\t"));
							 | 
						||
| 
								 | 
							
								            const spaces = indentChars.filter(char => char === " ").length;
							 | 
						||
| 
								 | 
							
								            const tabs = indentChars.filter(char => char === "\t").length;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            return {
							 | 
						||
| 
								 | 
							
								                space: spaces,
							 | 
						||
| 
								 | 
							
								                tab: tabs,
							 | 
						||
| 
								 | 
							
								                goodChar: indentType === "space" ? spaces : tabs,
							 | 
						||
| 
								 | 
							
								                badChar: indentType === "space" ? tabs : spaces
							 | 
						||
| 
								 | 
							
								            };
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /**
							 | 
						||
| 
								 | 
							
								         * Checks node is the first in its own start line. By default it looks by start line.
							 | 
						||
| 
								 | 
							
								         * @param {ASTNode} node The node to check
							 | 
						||
| 
								 | 
							
								         * @param {boolean} [byEndLocation=false] Lookup based on start position or end
							 | 
						||
| 
								 | 
							
								         * @returns {boolean} true if its the first in the its start line
							 | 
						||
| 
								 | 
							
								         */
							 | 
						||
| 
								 | 
							
								        function isNodeFirstInLine(node, byEndLocation) {
							 | 
						||
| 
								 | 
							
								            const firstToken = byEndLocation === true ? sourceCode.getLastToken(node, 1) : sourceCode.getTokenBefore(node),
							 | 
						||
| 
								 | 
							
								                startLine = byEndLocation === true ? node.loc.end.line : node.loc.start.line,
							 | 
						||
| 
								 | 
							
								                endLine = firstToken ? firstToken.loc.end.line : -1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            return startLine !== endLine;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /**
							 | 
						||
| 
								 | 
							
								         * Check indent for node
							 | 
						||
| 
								 | 
							
								         * @param {ASTNode} node Node to check
							 | 
						||
| 
								 | 
							
								         * @param {int} neededIndent needed indent
							 | 
						||
| 
								 | 
							
								         * @returns {void}
							 | 
						||
| 
								 | 
							
								         */
							 | 
						||
| 
								 | 
							
								        function checkNodeIndent(node, neededIndent) {
							 | 
						||
| 
								 | 
							
								            const actualIndent = getNodeIndent(node, false);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (
							 | 
						||
| 
								 | 
							
								                node.type !== "ArrayExpression" &&
							 | 
						||
| 
								 | 
							
								                node.type !== "ObjectExpression" &&
							 | 
						||
| 
								 | 
							
								                (actualIndent.goodChar !== neededIndent || actualIndent.badChar !== 0) &&
							 | 
						||
| 
								 | 
							
								                isNodeFirstInLine(node)
							 | 
						||
| 
								 | 
							
								            ) {
							 | 
						||
| 
								 | 
							
								                report(node, neededIndent, actualIndent.space, actualIndent.tab);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (node.type === "IfStatement" && node.alternate) {
							 | 
						||
| 
								 | 
							
								                const elseToken = sourceCode.getTokenBefore(node.alternate);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                checkNodeIndent(elseToken, neededIndent);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                if (!isNodeFirstInLine(node.alternate)) {
							 | 
						||
| 
								 | 
							
								                    checkNodeIndent(node.alternate, neededIndent);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (node.type === "TryStatement" && node.handler) {
							 | 
						||
| 
								 | 
							
								                const catchToken = sourceCode.getFirstToken(node.handler);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                checkNodeIndent(catchToken, neededIndent);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (node.type === "TryStatement" && node.finalizer) {
							 | 
						||
| 
								 | 
							
								                const finallyToken = sourceCode.getTokenBefore(node.finalizer);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                checkNodeIndent(finallyToken, neededIndent);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (node.type === "DoWhileStatement") {
							 | 
						||
| 
								 | 
							
								                const whileToken = sourceCode.getTokenAfter(node.body);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                checkNodeIndent(whileToken, neededIndent);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /**
							 | 
						||
| 
								 | 
							
								         * Check indent for nodes list
							 | 
						||
| 
								 | 
							
								         * @param {ASTNode[]} nodes list of node objects
							 | 
						||
| 
								 | 
							
								         * @param {int} indent needed indent
							 | 
						||
| 
								 | 
							
								         * @returns {void}
							 | 
						||
| 
								 | 
							
								         */
							 | 
						||
| 
								 | 
							
								        function checkNodesIndent(nodes, indent) {
							 | 
						||
| 
								 | 
							
								            nodes.forEach(node => checkNodeIndent(node, indent));
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /**
							 | 
						||
| 
								 | 
							
								         * Check last node line indent this detects, that block closed correctly
							 | 
						||
| 
								 | 
							
								         * @param {ASTNode} node Node to examine
							 | 
						||
| 
								 | 
							
								         * @param {int} lastLineIndent needed indent
							 | 
						||
| 
								 | 
							
								         * @returns {void}
							 | 
						||
| 
								 | 
							
								         */
							 | 
						||
| 
								 | 
							
								        function checkLastNodeLineIndent(node, lastLineIndent) {
							 | 
						||
| 
								 | 
							
								            const lastToken = sourceCode.getLastToken(node);
							 | 
						||
| 
								 | 
							
								            const endIndent = getNodeIndent(lastToken, true);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if ((endIndent.goodChar !== lastLineIndent || endIndent.badChar !== 0) && isNodeFirstInLine(node, true)) {
							 | 
						||
| 
								 | 
							
								                report(
							 | 
						||
| 
								 | 
							
								                    node,
							 | 
						||
| 
								 | 
							
								                    lastLineIndent,
							 | 
						||
| 
								 | 
							
								                    endIndent.space,
							 | 
						||
| 
								 | 
							
								                    endIndent.tab,
							 | 
						||
| 
								 | 
							
								                    { line: lastToken.loc.start.line, column: lastToken.loc.start.column },
							 | 
						||
| 
								 | 
							
								                    true
							 | 
						||
| 
								 | 
							
								                );
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /**
							 | 
						||
| 
								 | 
							
								         * Check last node line indent this detects, that block closed correctly
							 | 
						||
| 
								 | 
							
								         * This function for more complicated return statement case, where closing parenthesis may be followed by ';'
							 | 
						||
| 
								 | 
							
								         * @param {ASTNode} node Node to examine
							 | 
						||
| 
								 | 
							
								         * @param {int} firstLineIndent first line needed indent
							 | 
						||
| 
								 | 
							
								         * @returns {void}
							 | 
						||
| 
								 | 
							
								         */
							 | 
						||
| 
								 | 
							
								        function checkLastReturnStatementLineIndent(node, firstLineIndent) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            /*
							 | 
						||
| 
								 | 
							
								             * in case if return statement ends with ');' we have traverse back to ')'
							 | 
						||
| 
								 | 
							
								             * otherwise we'll measure indent for ';' and replace ')'
							 | 
						||
| 
								 | 
							
								             */
							 | 
						||
| 
								 | 
							
								            const lastToken = sourceCode.getLastToken(node, astUtils.isClosingParenToken);
							 | 
						||
| 
								 | 
							
								            const textBeforeClosingParenthesis = sourceCode.getText(lastToken, lastToken.loc.start.column).slice(0, -1);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (textBeforeClosingParenthesis.trim()) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                // There are tokens before the closing paren, don't report this case
							 | 
						||
| 
								 | 
							
								                return;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            const endIndent = getNodeIndent(lastToken, true);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (endIndent.goodChar !== firstLineIndent) {
							 | 
						||
| 
								 | 
							
								                report(
							 | 
						||
| 
								 | 
							
								                    node,
							 | 
						||
| 
								 | 
							
								                    firstLineIndent,
							 | 
						||
| 
								 | 
							
								                    endIndent.space,
							 | 
						||
| 
								 | 
							
								                    endIndent.tab,
							 | 
						||
| 
								 | 
							
								                    { line: lastToken.loc.start.line, column: lastToken.loc.start.column },
							 | 
						||
| 
								 | 
							
								                    true
							 | 
						||
| 
								 | 
							
								                );
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /**
							 | 
						||
| 
								 | 
							
								         * Check first node line indent is correct
							 | 
						||
| 
								 | 
							
								         * @param {ASTNode} node Node to examine
							 | 
						||
| 
								 | 
							
								         * @param {int} firstLineIndent needed indent
							 | 
						||
| 
								 | 
							
								         * @returns {void}
							 | 
						||
| 
								 | 
							
								         */
							 | 
						||
| 
								 | 
							
								        function checkFirstNodeLineIndent(node, firstLineIndent) {
							 | 
						||
| 
								 | 
							
								            const startIndent = getNodeIndent(node, false);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if ((startIndent.goodChar !== firstLineIndent || startIndent.badChar !== 0) && isNodeFirstInLine(node)) {
							 | 
						||
| 
								 | 
							
								                report(
							 | 
						||
| 
								 | 
							
								                    node,
							 | 
						||
| 
								 | 
							
								                    firstLineIndent,
							 | 
						||
| 
								 | 
							
								                    startIndent.space,
							 | 
						||
| 
								 | 
							
								                    startIndent.tab,
							 | 
						||
| 
								 | 
							
								                    { line: node.loc.start.line, column: node.loc.start.column }
							 | 
						||
| 
								 | 
							
								                );
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /**
							 | 
						||
| 
								 | 
							
								         * Returns a parent node of given node based on a specified type
							 | 
						||
| 
								 | 
							
								         * if not present then return null
							 | 
						||
| 
								 | 
							
								         * @param {ASTNode} node node to examine
							 | 
						||
| 
								 | 
							
								         * @param {string} type type that is being looked for
							 | 
						||
| 
								 | 
							
								         * @param {string} stopAtList end points for the evaluating code
							 | 
						||
| 
								 | 
							
								         * @returns {ASTNode|void} if found then node otherwise null
							 | 
						||
| 
								 | 
							
								         */
							 | 
						||
| 
								 | 
							
								        function getParentNodeByType(node, type, stopAtList) {
							 | 
						||
| 
								 | 
							
								            let parent = node.parent;
							 | 
						||
| 
								 | 
							
								            const stopAtSet = new Set(stopAtList || ["Program"]);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            while (parent.type !== type && !stopAtSet.has(parent.type) && parent.type !== "Program") {
							 | 
						||
| 
								 | 
							
								                parent = parent.parent;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            return parent.type === type ? parent : null;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /**
							 | 
						||
| 
								 | 
							
								         * Returns the VariableDeclarator based on the current node
							 | 
						||
| 
								 | 
							
								         * if not present then return null
							 | 
						||
| 
								 | 
							
								         * @param {ASTNode} node node to examine
							 | 
						||
| 
								 | 
							
								         * @returns {ASTNode|void} if found then node otherwise null
							 | 
						||
| 
								 | 
							
								         */
							 | 
						||
| 
								 | 
							
								        function getVariableDeclaratorNode(node) {
							 | 
						||
| 
								 | 
							
								            return getParentNodeByType(node, "VariableDeclarator");
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /**
							 | 
						||
| 
								 | 
							
								         * Check to see if the node is part of the multi-line variable declaration.
							 | 
						||
| 
								 | 
							
								         * Also if its on the same line as the varNode
							 | 
						||
| 
								 | 
							
								         * @param {ASTNode} node node to check
							 | 
						||
| 
								 | 
							
								         * @param {ASTNode} varNode variable declaration node to check against
							 | 
						||
| 
								 | 
							
								         * @returns {boolean} True if all the above condition satisfy
							 | 
						||
| 
								 | 
							
								         */
							 | 
						||
| 
								 | 
							
								        function isNodeInVarOnTop(node, varNode) {
							 | 
						||
| 
								 | 
							
								            return varNode &&
							 | 
						||
| 
								 | 
							
								                varNode.parent.loc.start.line === node.loc.start.line &&
							 | 
						||
| 
								 | 
							
								                varNode.parent.declarations.length > 1;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /**
							 | 
						||
| 
								 | 
							
								         * Check to see if the argument before the callee node is multi-line and
							 | 
						||
| 
								 | 
							
								         * there should only be 1 argument before the callee node
							 | 
						||
| 
								 | 
							
								         * @param {ASTNode} node node to check
							 | 
						||
| 
								 | 
							
								         * @returns {boolean} True if arguments are multi-line
							 | 
						||
| 
								 | 
							
								         */
							 | 
						||
| 
								 | 
							
								        function isArgBeforeCalleeNodeMultiline(node) {
							 | 
						||
| 
								 | 
							
								            const parent = node.parent;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (parent.arguments.length >= 2 && parent.arguments[1] === node) {
							 | 
						||
| 
								 | 
							
								                return parent.arguments[0].loc.end.line > parent.arguments[0].loc.start.line;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            return false;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /**
							 | 
						||
| 
								 | 
							
								         * Check to see if the node is a file level IIFE
							 | 
						||
| 
								 | 
							
								         * @param {ASTNode} node The function node to check.
							 | 
						||
| 
								 | 
							
								         * @returns {boolean} True if the node is the outer IIFE
							 | 
						||
| 
								 | 
							
								         */
							 | 
						||
| 
								 | 
							
								        function isOuterIIFE(node) {
							 | 
						||
| 
								 | 
							
								            const parent = node.parent;
							 | 
						||
| 
								 | 
							
								            let stmt = parent.parent;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            /*
							 | 
						||
| 
								 | 
							
								             * Verify that the node is an IIEF
							 | 
						||
| 
								 | 
							
								             */
							 | 
						||
| 
								 | 
							
								            if (
							 | 
						||
| 
								 | 
							
								                parent.type !== "CallExpression" ||
							 | 
						||
| 
								 | 
							
								                parent.callee !== node) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                return false;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            /*
							 | 
						||
| 
								 | 
							
								             * Navigate legal ancestors to determine whether this IIEF is outer
							 | 
						||
| 
								 | 
							
								             */
							 | 
						||
| 
								 | 
							
								            while (
							 | 
						||
| 
								 | 
							
								                stmt.type === "UnaryExpression" && (
							 | 
						||
| 
								 | 
							
								                    stmt.operator === "!" ||
							 | 
						||
| 
								 | 
							
								                    stmt.operator === "~" ||
							 | 
						||
| 
								 | 
							
								                    stmt.operator === "+" ||
							 | 
						||
| 
								 | 
							
								                    stmt.operator === "-") ||
							 | 
						||
| 
								 | 
							
								                stmt.type === "AssignmentExpression" ||
							 | 
						||
| 
								 | 
							
								                stmt.type === "LogicalExpression" ||
							 | 
						||
| 
								 | 
							
								                stmt.type === "SequenceExpression" ||
							 | 
						||
| 
								 | 
							
								                stmt.type === "VariableDeclarator") {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                stmt = stmt.parent;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            return ((
							 | 
						||
| 
								 | 
							
								                stmt.type === "ExpressionStatement" ||
							 | 
						||
| 
								 | 
							
								                stmt.type === "VariableDeclaration") &&
							 | 
						||
| 
								 | 
							
								                stmt.parent && stmt.parent.type === "Program"
							 | 
						||
| 
								 | 
							
								            );
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /**
							 | 
						||
| 
								 | 
							
								         * Check indent for function block content
							 | 
						||
| 
								 | 
							
								         * @param {ASTNode} node A BlockStatement node that is inside of a function.
							 | 
						||
| 
								 | 
							
								         * @returns {void}
							 | 
						||
| 
								 | 
							
								         */
							 | 
						||
| 
								 | 
							
								        function checkIndentInFunctionBlock(node) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            /*
							 | 
						||
| 
								 | 
							
								             * Search first caller in chain.
							 | 
						||
| 
								 | 
							
								             * Ex.:
							 | 
						||
| 
								 | 
							
								             *
							 | 
						||
| 
								 | 
							
								             * Models <- Identifier
							 | 
						||
| 
								 | 
							
								             *   .User
							 | 
						||
| 
								 | 
							
								             *   .find()
							 | 
						||
| 
								 | 
							
								             *   .exec(function() {
							 | 
						||
| 
								 | 
							
								             *   // function body
							 | 
						||
| 
								 | 
							
								             * });
							 | 
						||
| 
								 | 
							
								             *
							 | 
						||
| 
								 | 
							
								             * Looks for 'Models'
							 | 
						||
| 
								 | 
							
								             */
							 | 
						||
| 
								 | 
							
								            const calleeNode = node.parent; // FunctionExpression
							 | 
						||
| 
								 | 
							
								            let indent;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (calleeNode.parent &&
							 | 
						||
| 
								 | 
							
								                (calleeNode.parent.type === "Property" ||
							 | 
						||
| 
								 | 
							
								                calleeNode.parent.type === "ArrayExpression")) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                // If function is part of array or object, comma can be put at left
							 | 
						||
| 
								 | 
							
								                indent = getNodeIndent(calleeNode, false).goodChar;
							 | 
						||
| 
								 | 
							
								            } else {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                // If function is standalone, simple calculate indent
							 | 
						||
| 
								 | 
							
								                indent = getNodeIndent(calleeNode).goodChar;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (calleeNode.parent.type === "CallExpression") {
							 | 
						||
| 
								 | 
							
								                const calleeParent = calleeNode.parent;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                if (calleeNode.type !== "FunctionExpression" && calleeNode.type !== "ArrowFunctionExpression") {
							 | 
						||
| 
								 | 
							
								                    if (calleeParent && calleeParent.loc.start.line < node.loc.start.line) {
							 | 
						||
| 
								 | 
							
								                        indent = getNodeIndent(calleeParent).goodChar;
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								                } else {
							 | 
						||
| 
								 | 
							
								                    if (isArgBeforeCalleeNodeMultiline(calleeNode) &&
							 | 
						||
| 
								 | 
							
								                        calleeParent.callee.loc.start.line === calleeParent.callee.loc.end.line &&
							 | 
						||
| 
								 | 
							
								                        !isNodeFirstInLine(calleeNode)) {
							 | 
						||
| 
								 | 
							
								                        indent = getNodeIndent(calleeParent).goodChar;
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            /*
							 | 
						||
| 
								 | 
							
								             * function body indent should be indent + indent size, unless this
							 | 
						||
| 
								 | 
							
								             * is a FunctionDeclaration, FunctionExpression, or outer IIFE and the corresponding options are enabled.
							 | 
						||
| 
								 | 
							
								             */
							 | 
						||
| 
								 | 
							
								            let functionOffset = indentSize;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (options.outerIIFEBody !== null && isOuterIIFE(calleeNode)) {
							 | 
						||
| 
								 | 
							
								                functionOffset = options.outerIIFEBody * indentSize;
							 | 
						||
| 
								 | 
							
								            } else if (calleeNode.type === "FunctionExpression") {
							 | 
						||
| 
								 | 
							
								                functionOffset = options.FunctionExpression.body * indentSize;
							 | 
						||
| 
								 | 
							
								            } else if (calleeNode.type === "FunctionDeclaration") {
							 | 
						||
| 
								 | 
							
								                functionOffset = options.FunctionDeclaration.body * indentSize;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            indent += functionOffset;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            // check if the node is inside a variable
							 | 
						||
| 
								 | 
							
								            const parentVarNode = getVariableDeclaratorNode(node);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (parentVarNode && isNodeInVarOnTop(node, parentVarNode)) {
							 | 
						||
| 
								 | 
							
								                indent += indentSize * options.VariableDeclarator[parentVarNode.parent.kind];
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (node.body.length > 0) {
							 | 
						||
| 
								 | 
							
								                checkNodesIndent(node.body, indent);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            checkLastNodeLineIndent(node, indent - functionOffset);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /**
							 | 
						||
| 
								 | 
							
								         * Checks if the given node starts and ends on the same line
							 | 
						||
| 
								 | 
							
								         * @param {ASTNode} node The node to check
							 | 
						||
| 
								 | 
							
								         * @returns {boolean} Whether or not the block starts and ends on the same line.
							 | 
						||
| 
								 | 
							
								         */
							 | 
						||
| 
								 | 
							
								        function isSingleLineNode(node) {
							 | 
						||
| 
								 | 
							
								            const lastToken = sourceCode.getLastToken(node),
							 | 
						||
| 
								 | 
							
								                startLine = node.loc.start.line,
							 | 
						||
| 
								 | 
							
								                endLine = lastToken.loc.end.line;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            return startLine === endLine;
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /**
							 | 
						||
| 
								 | 
							
								         * Check to see if the first element inside an array is an object and on the same line as the node
							 | 
						||
| 
								 | 
							
								         * If the node is not an array then it will return false.
							 | 
						||
| 
								 | 
							
								         * @param {ASTNode} node node to check
							 | 
						||
| 
								 | 
							
								         * @returns {boolean} success/failure
							 | 
						||
| 
								 | 
							
								         */
							 | 
						||
| 
								 | 
							
								        function isFirstArrayElementOnSameLine(node) {
							 | 
						||
| 
								 | 
							
								            if (node.type === "ArrayExpression" && node.elements[0]) {
							 | 
						||
| 
								 | 
							
								                return node.elements[0].loc.start.line === node.loc.start.line && node.elements[0].type === "ObjectExpression";
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            return false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /**
							 | 
						||
| 
								 | 
							
								         * Check indent for array block content or object block content
							 | 
						||
| 
								 | 
							
								         * @param {ASTNode} node node to examine
							 | 
						||
| 
								 | 
							
								         * @returns {void}
							 | 
						||
| 
								 | 
							
								         */
							 | 
						||
| 
								 | 
							
								        function checkIndentInArrayOrObjectBlock(node) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            // Skip inline
							 | 
						||
| 
								 | 
							
								            if (isSingleLineNode(node)) {
							 | 
						||
| 
								 | 
							
								                return;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            let elements = (node.type === "ArrayExpression") ? node.elements : node.properties;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            // filter out empty elements example would be [ , 2] so remove first element as espree considers it as null
							 | 
						||
| 
								 | 
							
								            elements = elements.filter(elem => elem !== null);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            let nodeIndent;
							 | 
						||
| 
								 | 
							
								            let elementsIndent;
							 | 
						||
| 
								 | 
							
								            const parentVarNode = getVariableDeclaratorNode(node);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            // TODO - come up with a better strategy in future
							 | 
						||
| 
								 | 
							
								            if (isNodeFirstInLine(node)) {
							 | 
						||
| 
								 | 
							
								                const parent = node.parent;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                nodeIndent = getNodeIndent(parent).goodChar;
							 | 
						||
| 
								 | 
							
								                if (!parentVarNode || parentVarNode.loc.start.line !== node.loc.start.line) {
							 | 
						||
| 
								 | 
							
								                    if (parent.type !== "VariableDeclarator" || parentVarNode === parentVarNode.parent.declarations[0]) {
							 | 
						||
| 
								 | 
							
								                        if (parent.type === "VariableDeclarator" && parentVarNode.loc.start.line === parent.loc.start.line) {
							 | 
						||
| 
								 | 
							
								                            nodeIndent += (indentSize * options.VariableDeclarator[parentVarNode.parent.kind]);
							 | 
						||
| 
								 | 
							
								                        } else if (parent.type === "ObjectExpression" || parent.type === "ArrayExpression") {
							 | 
						||
| 
								 | 
							
								                            const parentElements = node.parent.type === "ObjectExpression" ? node.parent.properties : node.parent.elements;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                            if (parentElements[0] &&
							 | 
						||
| 
								 | 
							
								                                    parentElements[0].loc.start.line === parent.loc.start.line &&
							 | 
						||
| 
								 | 
							
								                                    parentElements[0].loc.end.line !== parent.loc.start.line) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                                /*
							 | 
						||
| 
								 | 
							
								                                 * If the first element of the array spans multiple lines, don't increase the expected indentation of the rest.
							 | 
						||
| 
								 | 
							
								                                 * e.g. [{
							 | 
						||
| 
								 | 
							
								                                 *        foo: 1
							 | 
						||
| 
								 | 
							
								                                 *      },
							 | 
						||
| 
								 | 
							
								                                 *      {
							 | 
						||
| 
								 | 
							
								                                 *        bar: 1
							 | 
						||
| 
								 | 
							
								                                 *      }]
							 | 
						||
| 
								 | 
							
								                                 * the second object is not indented.
							 | 
						||
| 
								 | 
							
								                                 */
							 | 
						||
| 
								 | 
							
								                            } else if (typeof options[parent.type] === "number") {
							 | 
						||
| 
								 | 
							
								                                nodeIndent += options[parent.type] * indentSize;
							 | 
						||
| 
								 | 
							
								                            } else {
							 | 
						||
| 
								 | 
							
								                                nodeIndent = parentElements[0].loc.start.column;
							 | 
						||
| 
								 | 
							
								                            }
							 | 
						||
| 
								 | 
							
								                        } else if (parent.type === "CallExpression" || parent.type === "NewExpression") {
							 | 
						||
| 
								 | 
							
								                            if (typeof options.CallExpression.arguments === "number") {
							 | 
						||
| 
								 | 
							
								                                nodeIndent += options.CallExpression.arguments * indentSize;
							 | 
						||
| 
								 | 
							
								                            } else if (options.CallExpression.arguments === "first") {
							 | 
						||
| 
								 | 
							
								                                if (parent.arguments.indexOf(node) !== -1) {
							 | 
						||
| 
								 | 
							
								                                    nodeIndent = parent.arguments[0].loc.start.column;
							 | 
						||
| 
								 | 
							
								                                }
							 | 
						||
| 
								 | 
							
								                            } else {
							 | 
						||
| 
								 | 
							
								                                nodeIndent += indentSize;
							 | 
						||
| 
								 | 
							
								                            }
							 | 
						||
| 
								 | 
							
								                        } else if (parent.type === "LogicalExpression" || parent.type === "ArrowFunctionExpression") {
							 | 
						||
| 
								 | 
							
								                            nodeIndent += indentSize;
							 | 
						||
| 
								 | 
							
								                        }
							 | 
						||
| 
								 | 
							
								                    }
							 | 
						||
| 
								 | 
							
								                } else if (!parentVarNode && !isFirstArrayElementOnSameLine(parent) && parent.type !== "MemberExpression" && parent.type !== "ExpressionStatement" && parent.type !== "AssignmentExpression" && parent.type !== "Property") {
							 | 
						||
| 
								 | 
							
								                    nodeIndent += indentSize;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                checkFirstNodeLineIndent(node, nodeIndent);
							 | 
						||
| 
								 | 
							
								            } else {
							 | 
						||
| 
								 | 
							
								                nodeIndent = getNodeIndent(node).goodChar;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (options[node.type] === "first") {
							 | 
						||
| 
								 | 
							
								                elementsIndent = elements.length ? elements[0].loc.start.column : 0; // If there are no elements, elementsIndent doesn't matter.
							 | 
						||
| 
								 | 
							
								            } else {
							 | 
						||
| 
								 | 
							
								                elementsIndent = nodeIndent + indentSize * options[node.type];
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            /*
							 | 
						||
| 
								 | 
							
								             * Check if the node is a multiple variable declaration; if so, then
							 | 
						||
| 
								 | 
							
								             * make sure indentation takes that into account.
							 | 
						||
| 
								 | 
							
								             */
							 | 
						||
| 
								 | 
							
								            if (isNodeInVarOnTop(node, parentVarNode)) {
							 | 
						||
| 
								 | 
							
								                elementsIndent += indentSize * options.VariableDeclarator[parentVarNode.parent.kind];
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            checkNodesIndent(elements, elementsIndent);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (elements.length > 0) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                // Skip last block line check if last item in same line
							 | 
						||
| 
								 | 
							
								                if (elements[elements.length - 1].loc.end.line === node.loc.end.line) {
							 | 
						||
| 
								 | 
							
								                    return;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            checkLastNodeLineIndent(node, nodeIndent +
							 | 
						||
| 
								 | 
							
								                (isNodeInVarOnTop(node, parentVarNode) ? options.VariableDeclarator[parentVarNode.parent.kind] * indentSize : 0));
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /**
							 | 
						||
| 
								 | 
							
								         * Check if the node or node body is a BlockStatement or not
							 | 
						||
| 
								 | 
							
								         * @param {ASTNode} node node to test
							 | 
						||
| 
								 | 
							
								         * @returns {boolean} True if it or its body is a block statement
							 | 
						||
| 
								 | 
							
								         */
							 | 
						||
| 
								 | 
							
								        function isNodeBodyBlock(node) {
							 | 
						||
| 
								 | 
							
								            return node.type === "BlockStatement" || node.type === "ClassBody" || (node.body && node.body.type === "BlockStatement") ||
							 | 
						||
| 
								 | 
							
								                (node.consequent && node.consequent.type === "BlockStatement");
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /**
							 | 
						||
| 
								 | 
							
								         * Check indentation for blocks
							 | 
						||
| 
								 | 
							
								         * @param {ASTNode} node node to check
							 | 
						||
| 
								 | 
							
								         * @returns {void}
							 | 
						||
| 
								 | 
							
								         */
							 | 
						||
| 
								 | 
							
								        function blockIndentationCheck(node) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            // Skip inline blocks
							 | 
						||
| 
								 | 
							
								            if (isSingleLineNode(node)) {
							 | 
						||
| 
								 | 
							
								                return;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (node.parent && (
							 | 
						||
| 
								 | 
							
								                node.parent.type === "FunctionExpression" ||
							 | 
						||
| 
								 | 
							
								                node.parent.type === "FunctionDeclaration" ||
							 | 
						||
| 
								 | 
							
								                node.parent.type === "ArrowFunctionExpression")
							 | 
						||
| 
								 | 
							
								            ) {
							 | 
						||
| 
								 | 
							
								                checkIndentInFunctionBlock(node);
							 | 
						||
| 
								 | 
							
								                return;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            let indent;
							 | 
						||
| 
								 | 
							
								            let nodesToCheck = [];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            /*
							 | 
						||
| 
								 | 
							
								             * For this statements we should check indent from statement beginning,
							 | 
						||
| 
								 | 
							
								             * not from the beginning of the block.
							 | 
						||
| 
								 | 
							
								             */
							 | 
						||
| 
								 | 
							
								            const statementsWithProperties = [
							 | 
						||
| 
								 | 
							
								                "IfStatement", "WhileStatement", "ForStatement", "ForInStatement", "ForOfStatement", "DoWhileStatement", "ClassDeclaration", "TryStatement"
							 | 
						||
| 
								 | 
							
								            ];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (node.parent && statementsWithProperties.indexOf(node.parent.type) !== -1 && isNodeBodyBlock(node)) {
							 | 
						||
| 
								 | 
							
								                indent = getNodeIndent(node.parent).goodChar;
							 | 
						||
| 
								 | 
							
								            } else if (node.parent && node.parent.type === "CatchClause") {
							 | 
						||
| 
								 | 
							
								                indent = getNodeIndent(node.parent.parent).goodChar;
							 | 
						||
| 
								 | 
							
								            } else {
							 | 
						||
| 
								 | 
							
								                indent = getNodeIndent(node).goodChar;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (node.type === "IfStatement" && node.consequent.type !== "BlockStatement") {
							 | 
						||
| 
								 | 
							
								                nodesToCheck = [node.consequent];
							 | 
						||
| 
								 | 
							
								            } else if (Array.isArray(node.body)) {
							 | 
						||
| 
								 | 
							
								                nodesToCheck = node.body;
							 | 
						||
| 
								 | 
							
								            } else {
							 | 
						||
| 
								 | 
							
								                nodesToCheck = [node.body];
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (nodesToCheck.length > 0) {
							 | 
						||
| 
								 | 
							
								                checkNodesIndent(nodesToCheck, indent + indentSize);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (node.type === "BlockStatement") {
							 | 
						||
| 
								 | 
							
								                checkLastNodeLineIndent(node, indent);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /**
							 | 
						||
| 
								 | 
							
								         * Filter out the elements which are on the same line of each other or the node.
							 | 
						||
| 
								 | 
							
								         * basically have only 1 elements from each line except the variable declaration line.
							 | 
						||
| 
								 | 
							
								         * @param {ASTNode} node Variable declaration node
							 | 
						||
| 
								 | 
							
								         * @returns {ASTNode[]} Filtered elements
							 | 
						||
| 
								 | 
							
								         */
							 | 
						||
| 
								 | 
							
								        function filterOutSameLineVars(node) {
							 | 
						||
| 
								 | 
							
								            return node.declarations.reduce((finalCollection, elem) => {
							 | 
						||
| 
								 | 
							
								                const lastElem = finalCollection[finalCollection.length - 1];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                if ((elem.loc.start.line !== node.loc.start.line && !lastElem) ||
							 | 
						||
| 
								 | 
							
								                    (lastElem && lastElem.loc.start.line !== elem.loc.start.line)) {
							 | 
						||
| 
								 | 
							
								                    finalCollection.push(elem);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                return finalCollection;
							 | 
						||
| 
								 | 
							
								            }, []);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /**
							 | 
						||
| 
								 | 
							
								         * Check indentation for variable declarations
							 | 
						||
| 
								 | 
							
								         * @param {ASTNode} node node to examine
							 | 
						||
| 
								 | 
							
								         * @returns {void}
							 | 
						||
| 
								 | 
							
								         */
							 | 
						||
| 
								 | 
							
								        function checkIndentInVariableDeclarations(node) {
							 | 
						||
| 
								 | 
							
								            const elements = filterOutSameLineVars(node);
							 | 
						||
| 
								 | 
							
								            const nodeIndent = getNodeIndent(node).goodChar;
							 | 
						||
| 
								 | 
							
								            const lastElement = elements[elements.length - 1];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            const elementsIndent = nodeIndent + indentSize * options.VariableDeclarator[node.kind];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            checkNodesIndent(elements, elementsIndent);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            // Only check the last line if there is any token after the last item
							 | 
						||
| 
								 | 
							
								            if (sourceCode.getLastToken(node).loc.end.line <= lastElement.loc.end.line) {
							 | 
						||
| 
								 | 
							
								                return;
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            const tokenBeforeLastElement = sourceCode.getTokenBefore(lastElement);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (tokenBeforeLastElement.value === ",") {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                // Special case for comma-first syntax where the semicolon is indented
							 | 
						||
| 
								 | 
							
								                checkLastNodeLineIndent(node, getNodeIndent(tokenBeforeLastElement).goodChar);
							 | 
						||
| 
								 | 
							
								            } else {
							 | 
						||
| 
								 | 
							
								                checkLastNodeLineIndent(node, elementsIndent - indentSize);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /**
							 | 
						||
| 
								 | 
							
								         * Check and decide whether to check for indentation for blockless nodes
							 | 
						||
| 
								 | 
							
								         * Scenarios are for or while statements without braces around them
							 | 
						||
| 
								 | 
							
								         * @param {ASTNode} node node to examine
							 | 
						||
| 
								 | 
							
								         * @returns {void}
							 | 
						||
| 
								 | 
							
								         */
							 | 
						||
| 
								 | 
							
								        function blockLessNodes(node) {
							 | 
						||
| 
								 | 
							
								            if (node.body.type !== "BlockStatement") {
							 | 
						||
| 
								 | 
							
								                blockIndentationCheck(node);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /**
							 | 
						||
| 
								 | 
							
								         * Returns the expected indentation for the case statement
							 | 
						||
| 
								 | 
							
								         * @param {ASTNode} node node to examine
							 | 
						||
| 
								 | 
							
								         * @param {int} [providedSwitchIndent] indent for switch statement
							 | 
						||
| 
								 | 
							
								         * @returns {int} indent size
							 | 
						||
| 
								 | 
							
								         */
							 | 
						||
| 
								 | 
							
								        function expectedCaseIndent(node, providedSwitchIndent) {
							 | 
						||
| 
								 | 
							
								            const switchNode = (node.type === "SwitchStatement") ? node : node.parent;
							 | 
						||
| 
								 | 
							
								            const switchIndent = typeof providedSwitchIndent === "undefined"
							 | 
						||
| 
								 | 
							
								                ? getNodeIndent(switchNode).goodChar
							 | 
						||
| 
								 | 
							
								                : providedSwitchIndent;
							 | 
						||
| 
								 | 
							
								            let caseIndent;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (caseIndentStore[switchNode.loc.start.line]) {
							 | 
						||
| 
								 | 
							
								                return caseIndentStore[switchNode.loc.start.line];
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if (switchNode.cases.length > 0 && options.SwitchCase === 0) {
							 | 
						||
| 
								 | 
							
								                caseIndent = switchIndent;
							 | 
						||
| 
								 | 
							
								            } else {
							 | 
						||
| 
								 | 
							
								                caseIndent = switchIndent + (indentSize * options.SwitchCase);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            caseIndentStore[switchNode.loc.start.line] = caseIndent;
							 | 
						||
| 
								 | 
							
								            return caseIndent;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        /**
							 | 
						||
| 
								 | 
							
								         * Checks wether a return statement is wrapped in ()
							 | 
						||
| 
								 | 
							
								         * @param {ASTNode} node node to examine
							 | 
						||
| 
								 | 
							
								         * @returns {boolean} the result
							 | 
						||
| 
								 | 
							
								         */
							 | 
						||
| 
								 | 
							
								        function isWrappedInParenthesis(node) {
							 | 
						||
| 
								 | 
							
								            const regex = /^return\s*?\(\s*?\);*?/u;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            const statementWithoutArgument = sourceCode.getText(node).replace(
							 | 
						||
| 
								 | 
							
								                sourceCode.getText(node.argument), ""
							 | 
						||
| 
								 | 
							
								            );
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            return regex.test(statementWithoutArgument);
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return {
							 | 
						||
| 
								 | 
							
								            Program(node) {
							 | 
						||
| 
								 | 
							
								                if (node.body.length > 0) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                    // Root nodes should have no indent
							 | 
						||
| 
								 | 
							
								                    checkNodesIndent(node.body, getNodeIndent(node).goodChar);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            },
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            ClassBody: blockIndentationCheck,
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            BlockStatement: blockIndentationCheck,
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            WhileStatement: blockLessNodes,
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            ForStatement: blockLessNodes,
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            ForInStatement: blockLessNodes,
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            ForOfStatement: blockLessNodes,
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            DoWhileStatement: blockLessNodes,
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            IfStatement(node) {
							 | 
						||
| 
								 | 
							
								                if (node.consequent.type !== "BlockStatement" && node.consequent.loc.start.line > node.loc.start.line) {
							 | 
						||
| 
								 | 
							
								                    blockIndentationCheck(node);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            },
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            VariableDeclaration(node) {
							 | 
						||
| 
								 | 
							
								                if (node.declarations[node.declarations.length - 1].loc.start.line > node.declarations[0].loc.start.line) {
							 | 
						||
| 
								 | 
							
								                    checkIndentInVariableDeclarations(node);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            },
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            ObjectExpression(node) {
							 | 
						||
| 
								 | 
							
								                checkIndentInArrayOrObjectBlock(node);
							 | 
						||
| 
								 | 
							
								            },
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            ArrayExpression(node) {
							 | 
						||
| 
								 | 
							
								                checkIndentInArrayOrObjectBlock(node);
							 | 
						||
| 
								 | 
							
								            },
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            MemberExpression(node) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                if (typeof options.MemberExpression === "undefined") {
							 | 
						||
| 
								 | 
							
								                    return;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                if (isSingleLineNode(node)) {
							 | 
						||
| 
								 | 
							
								                    return;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                /*
							 | 
						||
| 
								 | 
							
								                 * The typical layout of variable declarations and assignments
							 | 
						||
| 
								 | 
							
								                 * alter the expectation of correct indentation. Skip them.
							 | 
						||
| 
								 | 
							
								                 * TODO: Add appropriate configuration options for variable
							 | 
						||
| 
								 | 
							
								                 * declarations and assignments.
							 | 
						||
| 
								 | 
							
								                 */
							 | 
						||
| 
								 | 
							
								                if (getParentNodeByType(node, "VariableDeclarator", ["FunctionExpression", "ArrowFunctionExpression"])) {
							 | 
						||
| 
								 | 
							
								                    return;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                if (getParentNodeByType(node, "AssignmentExpression", ["FunctionExpression"])) {
							 | 
						||
| 
								 | 
							
								                    return;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                const propertyIndent = getNodeIndent(node).goodChar + indentSize * options.MemberExpression;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                const checkNodes = [node.property];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                const dot = sourceCode.getTokenBefore(node.property);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                if (dot.type === "Punctuator" && dot.value === ".") {
							 | 
						||
| 
								 | 
							
								                    checkNodes.push(dot);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                checkNodesIndent(checkNodes, propertyIndent);
							 | 
						||
| 
								 | 
							
								            },
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            SwitchStatement(node) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                // Switch is not a 'BlockStatement'
							 | 
						||
| 
								 | 
							
								                const switchIndent = getNodeIndent(node).goodChar;
							 | 
						||
| 
								 | 
							
								                const caseIndent = expectedCaseIndent(node, switchIndent);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                checkNodesIndent(node.cases, caseIndent);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                checkLastNodeLineIndent(node, switchIndent);
							 | 
						||
| 
								 | 
							
								            },
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            SwitchCase(node) {
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                // Skip inline cases
							 | 
						||
| 
								 | 
							
								                if (isSingleLineNode(node)) {
							 | 
						||
| 
								 | 
							
								                    return;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                const caseIndent = expectedCaseIndent(node);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                checkNodesIndent(node.consequent, caseIndent + indentSize);
							 | 
						||
| 
								 | 
							
								            },
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            FunctionDeclaration(node) {
							 | 
						||
| 
								 | 
							
								                if (isSingleLineNode(node)) {
							 | 
						||
| 
								 | 
							
								                    return;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                if (options.FunctionDeclaration.parameters === "first" && node.params.length) {
							 | 
						||
| 
								 | 
							
								                    checkNodesIndent(node.params.slice(1), node.params[0].loc.start.column);
							 | 
						||
| 
								 | 
							
								                } else if (options.FunctionDeclaration.parameters !== null) {
							 | 
						||
| 
								 | 
							
								                    checkNodesIndent(node.params, getNodeIndent(node).goodChar + indentSize * options.FunctionDeclaration.parameters);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            },
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            FunctionExpression(node) {
							 | 
						||
| 
								 | 
							
								                if (isSingleLineNode(node)) {
							 | 
						||
| 
								 | 
							
								                    return;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                if (options.FunctionExpression.parameters === "first" && node.params.length) {
							 | 
						||
| 
								 | 
							
								                    checkNodesIndent(node.params.slice(1), node.params[0].loc.start.column);
							 | 
						||
| 
								 | 
							
								                } else if (options.FunctionExpression.parameters !== null) {
							 | 
						||
| 
								 | 
							
								                    checkNodesIndent(node.params, getNodeIndent(node).goodChar + indentSize * options.FunctionExpression.parameters);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            },
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            ReturnStatement(node) {
							 | 
						||
| 
								 | 
							
								                if (isSingleLineNode(node)) {
							 | 
						||
| 
								 | 
							
								                    return;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                const firstLineIndent = getNodeIndent(node).goodChar;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								                // in case if return statement is wrapped in parenthesis
							 | 
						||
| 
								 | 
							
								                if (isWrappedInParenthesis(node)) {
							 | 
						||
| 
								 | 
							
								                    checkLastReturnStatementLineIndent(node, firstLineIndent);
							 | 
						||
| 
								 | 
							
								                } else {
							 | 
						||
| 
								 | 
							
								                    checkNodeIndent(node, firstLineIndent);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            },
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            CallExpression(node) {
							 | 
						||
| 
								 | 
							
								                if (isSingleLineNode(node)) {
							 | 
						||
| 
								 | 
							
								                    return;
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								                if (options.CallExpression.arguments === "first" && node.arguments.length) {
							 | 
						||
| 
								 | 
							
								                    checkNodesIndent(node.arguments.slice(1), node.arguments[0].loc.start.column);
							 | 
						||
| 
								 | 
							
								                } else if (options.CallExpression.arguments !== null) {
							 | 
						||
| 
								 | 
							
								                    checkNodesIndent(node.arguments, getNodeIndent(node).goodChar + indentSize * options.CallExpression.arguments);
							 | 
						||
| 
								 | 
							
								                }
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        };
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								};
							 |