function isStrictScope(scope, block, isMethodDefinition) {
    let body;

    // When upper scope is exists and strict, inner scope is also strict.
    if (scope.upper && scope.upper.isStrict) {
        return true;
    }

    if (isMethodDefinition) {
        return true;
    }

    if (scope.type === "class" || scope.type === "module") {
        return true;
    }

    if (scope.type === "block" || scope.type === "switch") {
        return false;
    }

    if (scope.type === "function") {
        if (block.type === Syntax.ArrowFunctionExpression && block.body.type !== Syntax.BlockStatement) {
            return false;
        }

        if (block.type === Syntax.Program) {
            body = block;
        } else {
            body = block.body;
        }

        if (!body) {
            return false;
        }
    } else if (scope.type === "global") {
        body = block;
    } else {
        return false;
    }

    // Search for a 'use strict' directive.
    for (let i = 0, iz = body.body.length; i < iz; ++i) {
        const stmt = body.body[i];

        /*
         * Check if the current statement is a directive.
         * If it isn't, then we're past the directive prologue
         * so stop the search because directives cannot
         * appear after this point.
         *
         * Some parsers set `directive:null` on non-directive
         * statements, so the `typeof` check is safer than
         * checking for property existence.
         */
        if (typeof stmt.directive !== "string") {
            break;
        }

        if (stmt.directive === "use strict") {
            return true;
        }
    }

    return false;
}
Test if scope is struct
@param {Scope} scope scope
@param {Block} block block
@param {boolean} isMethodDefinition is method definition
@returns {boolean} is strict scope