All files / src/custom-nodes CustomNodeAppender.ts

94.12% Statements 16/17
93.75% Branches 15/16
100% Functions 0/0
94.12% Lines 16/17
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        1x 1x                                     1x                     1037x   1037x   1037x 24x   1013x     1037x             1063x 1063x       1063x                       2024x   2024x 1011x   1013x        
import * as ESTree from 'estree';
 
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 blockScopeBody
     * @param node
     * @param index
     */
    public static appendNode (
        blockScopeStackTraceData: IStackTraceData[],
        blockScopeBody: ESTree.Node[],
        node: ESTree.Node,
        index: number = 0
    ): void {
        let targetBlockScopeBody: ESTree.Node[];
 
        if (!blockScopeStackTraceData.length) {
            targetBlockScopeBody = blockScopeBody;
        } else {
            targetBlockScopeBody = CustomNodeAppender.getOptimalBlockScopeBody(blockScopeStackTraceData, index);
        }
 
        NodeUtils.prependNode(targetBlockScopeBody, node);
    }
 
    /**
     * @param blockStatementBodyLength
     * @param threshold
     */
    public static getIndexByThreshold (blockStatementBodyLength: number, threshold: number = 0.1): number {
        Iif (threshold < 0 || threshold > 1) {
            throw new RangeError('`threshold` parameter should has value between 0 and 1');
        }
 
        return Utils.getRandomGenerator().integer({
            min: 0,
            max: Math.round((blockStatementBodyLength - 1) * threshold)
        });
    }
 
    /**
     * @param blockScopeTraceData
     * @param index
     * @returns {ESTree.Node[]}
     */
    private static getOptimalBlockScopeBody (blockScopeTraceData: IStackTraceData[], index: number): ESTree.Node[] {
        const firstCall: IStackTraceData = blockScopeTraceData[index];
 
        if (firstCall.stackTrace.length) {
            return CustomNodeAppender.getOptimalBlockScopeBody(firstCall.stackTrace, 0);
        } else {
            return firstCall.callee.body;
        }
    }
}