.
This commit is contained in:
		
							
								
								
									
										293
									
								
								qwen/nodejs/node_modules/eslint/lib/rules/no-unreachable.js
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										293
									
								
								qwen/nodejs/node_modules/eslint/lib/rules/no-unreachable.js
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,293 @@
 | 
			
		||||
/**
 | 
			
		||||
 * @fileoverview Checks for unreachable code due to return, throws, break, and continue.
 | 
			
		||||
 * @author Joel Feenstra
 | 
			
		||||
 */
 | 
			
		||||
"use strict";
 | 
			
		||||
 | 
			
		||||
//------------------------------------------------------------------------------
 | 
			
		||||
// Helpers
 | 
			
		||||
//------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @typedef {Object} ConstructorInfo
 | 
			
		||||
 * @property {ConstructorInfo | null} upper Info about the constructor that encloses this constructor.
 | 
			
		||||
 * @property {boolean} hasSuperCall The flag about having `super()` expressions.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Checks whether or not a given variable declarator has the initializer.
 | 
			
		||||
 * @param {ASTNode} node A VariableDeclarator node to check.
 | 
			
		||||
 * @returns {boolean} `true` if the node has the initializer.
 | 
			
		||||
 */
 | 
			
		||||
function isInitialized(node) {
 | 
			
		||||
    return Boolean(node.init);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Checks all segments in a set and returns true if all are unreachable.
 | 
			
		||||
 * @param {Set<CodePathSegment>} segments The segments to check.
 | 
			
		||||
 * @returns {boolean} True if all segments are unreachable; false otherwise.
 | 
			
		||||
 */
 | 
			
		||||
function areAllSegmentsUnreachable(segments) {
 | 
			
		||||
 | 
			
		||||
    for (const segment of segments) {
 | 
			
		||||
        if (segment.reachable) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The class to distinguish consecutive unreachable statements.
 | 
			
		||||
 */
 | 
			
		||||
class ConsecutiveRange {
 | 
			
		||||
    constructor(sourceCode) {
 | 
			
		||||
        this.sourceCode = sourceCode;
 | 
			
		||||
        this.startNode = null;
 | 
			
		||||
        this.endNode = null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The location object of this range.
 | 
			
		||||
     * @type {Object}
 | 
			
		||||
     */
 | 
			
		||||
    get location() {
 | 
			
		||||
        return {
 | 
			
		||||
            start: this.startNode.loc.start,
 | 
			
		||||
            end: this.endNode.loc.end
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * `true` if this range is empty.
 | 
			
		||||
     * @type {boolean}
 | 
			
		||||
     */
 | 
			
		||||
    get isEmpty() {
 | 
			
		||||
        return !(this.startNode && this.endNode);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks whether the given node is inside of this range.
 | 
			
		||||
     * @param {ASTNode|Token} node The node to check.
 | 
			
		||||
     * @returns {boolean} `true` if the node is inside of this range.
 | 
			
		||||
     */
 | 
			
		||||
    contains(node) {
 | 
			
		||||
        return (
 | 
			
		||||
            node.range[0] >= this.startNode.range[0] &&
 | 
			
		||||
            node.range[1] <= this.endNode.range[1]
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Checks whether the given node is consecutive to this range.
 | 
			
		||||
     * @param {ASTNode} node The node to check.
 | 
			
		||||
     * @returns {boolean} `true` if the node is consecutive to this range.
 | 
			
		||||
     */
 | 
			
		||||
    isConsecutive(node) {
 | 
			
		||||
        return this.contains(this.sourceCode.getTokenBefore(node));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Merges the given node to this range.
 | 
			
		||||
     * @param {ASTNode} node The node to merge.
 | 
			
		||||
     * @returns {void}
 | 
			
		||||
     */
 | 
			
		||||
    merge(node) {
 | 
			
		||||
        this.endNode = node;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Resets this range by the given node or null.
 | 
			
		||||
     * @param {ASTNode|null} node The node to reset, or null.
 | 
			
		||||
     * @returns {void}
 | 
			
		||||
     */
 | 
			
		||||
    reset(node) {
 | 
			
		||||
        this.startNode = this.endNode = node;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//------------------------------------------------------------------------------
 | 
			
		||||
// Rule Definition
 | 
			
		||||
//------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
/** @type {import('../shared/types').Rule} */
 | 
			
		||||
module.exports = {
 | 
			
		||||
    meta: {
 | 
			
		||||
        type: "problem",
 | 
			
		||||
 | 
			
		||||
        docs: {
 | 
			
		||||
            description: "Disallow unreachable code after `return`, `throw`, `continue`, and `break` statements",
 | 
			
		||||
            recommended: true,
 | 
			
		||||
            url: "https://eslint.org/docs/latest/rules/no-unreachable"
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        schema: [],
 | 
			
		||||
 | 
			
		||||
        messages: {
 | 
			
		||||
            unreachableCode: "Unreachable code."
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    create(context) {
 | 
			
		||||
 | 
			
		||||
        /** @type {ConstructorInfo | null} */
 | 
			
		||||
        let constructorInfo = null;
 | 
			
		||||
 | 
			
		||||
        /** @type {ConsecutiveRange} */
 | 
			
		||||
        const range = new ConsecutiveRange(context.sourceCode);
 | 
			
		||||
 | 
			
		||||
        /** @type {Array<Set<CodePathSegment>>} */
 | 
			
		||||
        const codePathSegments = [];
 | 
			
		||||
 | 
			
		||||
        /** @type {Set<CodePathSegment>} */
 | 
			
		||||
        let currentCodePathSegments = new Set();
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * Reports a given node if it's unreachable.
 | 
			
		||||
         * @param {ASTNode} node A statement node to report.
 | 
			
		||||
         * @returns {void}
 | 
			
		||||
         */
 | 
			
		||||
        function reportIfUnreachable(node) {
 | 
			
		||||
            let nextNode = null;
 | 
			
		||||
 | 
			
		||||
            if (node && (node.type === "PropertyDefinition" || areAllSegmentsUnreachable(currentCodePathSegments))) {
 | 
			
		||||
 | 
			
		||||
                // Store this statement to distinguish consecutive statements.
 | 
			
		||||
                if (range.isEmpty) {
 | 
			
		||||
                    range.reset(node);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Skip if this statement is inside of the current range.
 | 
			
		||||
                if (range.contains(node)) {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // Merge if this statement is consecutive to the current range.
 | 
			
		||||
                if (range.isConsecutive(node)) {
 | 
			
		||||
                    range.merge(node);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                nextNode = node;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            /*
 | 
			
		||||
             * Report the current range since this statement is reachable or is
 | 
			
		||||
             * not consecutive to the current range.
 | 
			
		||||
             */
 | 
			
		||||
            if (!range.isEmpty) {
 | 
			
		||||
                context.report({
 | 
			
		||||
                    messageId: "unreachableCode",
 | 
			
		||||
                    loc: range.location,
 | 
			
		||||
                    node: range.startNode
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Update the current range.
 | 
			
		||||
            range.reset(nextNode);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return {
 | 
			
		||||
 | 
			
		||||
            // Manages the current code path.
 | 
			
		||||
            onCodePathStart() {
 | 
			
		||||
                codePathSegments.push(currentCodePathSegments);
 | 
			
		||||
                currentCodePathSegments = new Set();
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            onCodePathEnd() {
 | 
			
		||||
                currentCodePathSegments = codePathSegments.pop();
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            onUnreachableCodePathSegmentStart(segment) {
 | 
			
		||||
                currentCodePathSegments.add(segment);
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            onUnreachableCodePathSegmentEnd(segment) {
 | 
			
		||||
                currentCodePathSegments.delete(segment);
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            onCodePathSegmentEnd(segment) {
 | 
			
		||||
                currentCodePathSegments.delete(segment);
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            onCodePathSegmentStart(segment) {
 | 
			
		||||
                currentCodePathSegments.add(segment);
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            // Registers for all statement nodes (excludes FunctionDeclaration).
 | 
			
		||||
            BlockStatement: reportIfUnreachable,
 | 
			
		||||
            BreakStatement: reportIfUnreachable,
 | 
			
		||||
            ClassDeclaration: reportIfUnreachable,
 | 
			
		||||
            ContinueStatement: reportIfUnreachable,
 | 
			
		||||
            DebuggerStatement: reportIfUnreachable,
 | 
			
		||||
            DoWhileStatement: reportIfUnreachable,
 | 
			
		||||
            ExpressionStatement: reportIfUnreachable,
 | 
			
		||||
            ForInStatement: reportIfUnreachable,
 | 
			
		||||
            ForOfStatement: reportIfUnreachable,
 | 
			
		||||
            ForStatement: reportIfUnreachable,
 | 
			
		||||
            IfStatement: reportIfUnreachable,
 | 
			
		||||
            ImportDeclaration: reportIfUnreachable,
 | 
			
		||||
            LabeledStatement: reportIfUnreachable,
 | 
			
		||||
            ReturnStatement: reportIfUnreachable,
 | 
			
		||||
            SwitchStatement: reportIfUnreachable,
 | 
			
		||||
            ThrowStatement: reportIfUnreachable,
 | 
			
		||||
            TryStatement: reportIfUnreachable,
 | 
			
		||||
 | 
			
		||||
            VariableDeclaration(node) {
 | 
			
		||||
                if (node.kind !== "var" || node.declarations.some(isInitialized)) {
 | 
			
		||||
                    reportIfUnreachable(node);
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            WhileStatement: reportIfUnreachable,
 | 
			
		||||
            WithStatement: reportIfUnreachable,
 | 
			
		||||
            ExportNamedDeclaration: reportIfUnreachable,
 | 
			
		||||
            ExportDefaultDeclaration: reportIfUnreachable,
 | 
			
		||||
            ExportAllDeclaration: reportIfUnreachable,
 | 
			
		||||
 | 
			
		||||
            "Program:exit"() {
 | 
			
		||||
                reportIfUnreachable();
 | 
			
		||||
            },
 | 
			
		||||
 | 
			
		||||
            /*
 | 
			
		||||
             * Instance fields defined in a subclass are never created if the constructor of the subclass
 | 
			
		||||
             * doesn't call `super()`, so their definitions are unreachable code.
 | 
			
		||||
             */
 | 
			
		||||
            "MethodDefinition[kind='constructor']"() {
 | 
			
		||||
                constructorInfo = {
 | 
			
		||||
                    upper: constructorInfo,
 | 
			
		||||
                    hasSuperCall: false
 | 
			
		||||
                };
 | 
			
		||||
            },
 | 
			
		||||
            "MethodDefinition[kind='constructor']:exit"(node) {
 | 
			
		||||
                const { hasSuperCall } = constructorInfo;
 | 
			
		||||
 | 
			
		||||
                constructorInfo = constructorInfo.upper;
 | 
			
		||||
 | 
			
		||||
                // skip typescript constructors without the body
 | 
			
		||||
                if (!node.value.body) {
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                const classDefinition = node.parent.parent;
 | 
			
		||||
 | 
			
		||||
                if (classDefinition.superClass && !hasSuperCall) {
 | 
			
		||||
                    for (const element of classDefinition.body.body) {
 | 
			
		||||
                        if (element.type === "PropertyDefinition" && !element.static) {
 | 
			
		||||
                            reportIfUnreachable(element);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            "CallExpression > Super.callee"() {
 | 
			
		||||
                if (constructorInfo) {
 | 
			
		||||
                    constructorInfo.hasSuperCall = true;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
		Reference in New Issue
	
	Block a user