| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108 | /** * @fileoverview Rule to flag unsafe statements in finally block * @author Onur Temizkan */"use strict";//------------------------------------------------------------------------------// Helpers//------------------------------------------------------------------------------const SENTINEL_NODE_TYPE_RETURN_THROW = /^(?:Program|(?:Function|Class)(?:Declaration|Expression)|ArrowFunctionExpression)$/;const SENTINEL_NODE_TYPE_BREAK = /^(?:Program|(?:Function|Class)(?:Declaration|Expression)|ArrowFunctionExpression|DoWhileStatement|WhileStatement|ForOfStatement|ForInStatement|ForStatement|SwitchStatement)$/;const SENTINEL_NODE_TYPE_CONTINUE = /^(?:Program|(?:Function|Class)(?:Declaration|Expression)|ArrowFunctionExpression|DoWhileStatement|WhileStatement|ForOfStatement|ForInStatement|ForStatement)$/;//------------------------------------------------------------------------------// Rule Definition//------------------------------------------------------------------------------module.exports = {    meta: {        docs: {            description: "disallow control flow statements in `finally` blocks",            category: "Possible Errors",            recommended: true,            url: "https://eslint.org/docs/rules/no-unsafe-finally"        },        schema: []    },    create(context) {        /**         * Checks if the node is the finalizer of a TryStatement         *         * @param {ASTNode} node - node to check.         * @returns {boolean} - true if the node is the finalizer of a TryStatement         */        function isFinallyBlock(node) {            return node.parent.type === "TryStatement" && node.parent.finalizer === node;        }        /**         * Climbs up the tree if the node is not a sentinel node         *         * @param {ASTNode} node - node to check.         * @param {string} label - label of the break or continue statement         * @returns {boolean} - return whether the node is a finally block or a sentinel node         */        function isInFinallyBlock(node, label) {            let labelInside = false;            let sentinelNodeType;            if (node.type === "BreakStatement" && !node.label) {                sentinelNodeType = SENTINEL_NODE_TYPE_BREAK;            } else if (node.type === "ContinueStatement") {                sentinelNodeType = SENTINEL_NODE_TYPE_CONTINUE;            } else {                sentinelNodeType = SENTINEL_NODE_TYPE_RETURN_THROW;            }            for (                let currentNode = node;                currentNode && !sentinelNodeType.test(currentNode.type);                currentNode = currentNode.parent            ) {                if (currentNode.parent.label && label && (currentNode.parent.label.name === label.name)) {                    labelInside = true;                }                if (isFinallyBlock(currentNode)) {                    if (label && labelInside) {                        return false;                    }                    return true;                }            }            return false;        }        /**         * Checks whether the possibly-unsafe statement is inside a finally block.         *         * @param {ASTNode} node - node to check.         * @returns {void}         */        function check(node) {            if (isInFinallyBlock(node, node.label)) {                context.report({                    message: "Unsafe usage of {{nodeType}}.",                    data: {                        nodeType: node.type                    },                    node,                    line: node.loc.line,                    column: node.loc.column                });            }        }        return {            ReturnStatement: check,            ThrowStatement: check,            BreakStatement: check,            ContinueStatement: check        };    }};
 |