All files / src/custom-nodes NodeAppender.ts

100% Statements 14/14
100% Branches 8/8
100% Functions 0/0
100% Lines 14/14
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83              1x 1x                                     1x                     1016x   1016x   1016x 2x   1014x           1016x             1112x                             2028x   2028x 1014x   1014x        
import * as ESTree from 'estree';
 
import { TNodeWithBlockStatement } from '../types/TNodeWithBlockStatement';
import { TStatement } from '../types/TStatement';
 
import { IStackTraceData } from '../interfaces/stack-trace-analyzer/IStackTraceData';
 
import { NodeUtils } from '../NodeUtils';
import { Utils } from '../Utils';
 
/**
 * This class appends node into a first deepest BlockStatement in order of function calls
 *
 * For example:
 *
 * function Foo () {
 *     var baz = function () {
 *
 *     }
 *
 *     baz();
 * }
 *
 * foo();
 *
 * Appends node into block statement of `baz` function expression.
 */
export class CustomNodeAppender {
    /**
     * @param blockScopeStackTraceData
     * @param blockScopeNode
     * @param nodeBodyStatements
     * @param index
     */
    public static appendNode (
        blockScopeStackTraceData: IStackTraceData[],
        blockScopeNode: TNodeWithBlockStatement,
        nodeBodyStatements: TStatement[],
        index: number = 0
    ): void {
        let targetBlockScope: TNodeWithBlockStatement;
 
        if (!blockScopeStackTraceData.length) {
            targetBlockScope = blockScopeNode;
        } else {
            targetBlockScope = CustomNodeAppender.getOptimalBlockScope(
                blockScopeStackTraceData,
                index
            );
        }
 
        NodeUtils.prependNode(targetBlockScope, nodeBodyStatements);
    }
 
    /**
     * @param stackTraceRootLength
     */
    public static getRandomStackTraceIndex (stackTraceRootLength: number): number {
        return Utils.getRandomGenerator().integer({
            min: 0,
            max: Math.max(0, Math.round(stackTraceRootLength - 1))
        });
    }
 
    /**
     * @param blockScopeTraceData
     * @param index
     * @returns {ESTree.BlockStatement}
     */
    private static getOptimalBlockScope (
        blockScopeTraceData: IStackTraceData[],
        index: number
    ): ESTree.BlockStatement {
        const firstCall: IStackTraceData = blockScopeTraceData[index];
 
        if (firstCall.stackTrace.length) {
            return CustomNodeAppender.getOptimalBlockScope(firstCall.stackTrace, 0);
        } else {
            return firstCall.callee;
        }
    }
}