All files NodeUtils.ts

90% Statements 36/40
76.92% Branches 20/26
100% Functions 8/8
90% Lines 36/40
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 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 1481x           1x   1x 1x   1x       1x                       1x   1x 1x                     1x       1x                 4x 3x 1x     2x     1x                 10x   10x 1x     9x 3x   3x 1x     2x     6x 4x     2x                 1x       1x             7x   7x   37x             37x                   3x       3x               5x      
import * as estraverse from 'estraverse';
 
import { INode } from './interfaces/nodes/INode';
 
import { TNodeWithBlockStatement } from "./types/TNodeWithBlockStatement";
 
import { NodeType } from "./enums/NodeType";
 
import { Nodes } from "./Nodes";
import { Utils } from "./Utils";
 
export class NodeUtils {
    /**
     * @type {string[]}
     */
    private static nodesWithBlockScope: string[] = [
        NodeType.ArrowFunctionExpression,
        NodeType.FunctionDeclaration,
        NodeType.FunctionExpression,
        NodeType.MethodDefinition,
        NodeType.Program
    ];
 
    /**
     * @param node
     */
    public static addXVerbatimPropertyToLiterals (node: INode): void {
        estraverse.replace(node, {
            enter: (node: INode, parentNode: INode): any => {
                Eif (Nodes.isLiteralNode(node)) {
                   node['x-verbatim-property'] = node.raw;
                }
            }
        });
    }
 
    /**
     * @param blockScopeBody
     * @param node
     */
    public static appendNode (blockScopeBody: INode[], node: INode): void {
        Iif (!NodeUtils.validateNode(node)) {
            return;
        }
 
        blockScopeBody.push(node);
    }
 
    /**
     * @param node
     * @param index
     * @returns {INode}
     */
    public static getBlockStatementNodeByIndex (node: INode, index: number = 0): INode {
        if (Nodes.isNodeHasBlockStatement(node)) {
            if (node.body[index] === undefined) {
                throw new ReferenceError(`Wrong index \`${index}\`. Block-statement body length is \`${node.body.length}\``);
            }
 
            return node.body[index];
        }
 
        throw new TypeError('The specified node have no a block-statement');
    }
 
    /**
     * @param node
     * @param depth
     * @returns {INode}
     */
    public static getBlockScopeOfNode (node: INode, depth: number = 0): TNodeWithBlockStatement {
        let parentNode: INode = node.parentNode;
 
        if (!parentNode) {
            throw new ReferenceError('`parentNode` property of given node is `undefined`');
        }
 
        if (Nodes.isBlockStatementNode(parentNode)) {
            Iif (!Utils.arrayContains(NodeUtils.nodesWithBlockScope, parentNode['parentNode'].type)) {
                return NodeUtils.getBlockScopeOfNode(parentNode, depth);
            } else if (depth > 0) {
                return NodeUtils.getBlockScopeOfNode(parentNode, --depth);
            }
 
            return parentNode;
        }
 
        if (Nodes.isProgramNode(parentNode)) {
            return parentNode;
        }
 
        return NodeUtils.getBlockScopeOfNode(parentNode);
    }
 
    /**
     * @param blockScopeBody
     * @param node
     * @param index
     */
    public static insertNodeAtIndex (blockScopeBody: INode[], node: INode, index: number): void {
        Iif (!NodeUtils.validateNode(node)) {
            return;
        }
 
        blockScopeBody.splice(index, 0, node);
    }
 
    /**
     * @param node
     */
    public static parentize (node: INode): void {
        let isRootNode: boolean = true;
 
        estraverse.replace(node, {
            enter: (node: INode, parentNode: INode): any => {
                Object.defineProperty(node, 'parentNode', {
                    configurable: true,
                    enumerable: true,
                    value: isRootNode ? Nodes.getProgramNode([node]) : parentNode || node,
                    writable: true
                });
 
                isRootNode = false;
            }
        });
    }
 
    /**
     * @param blockScopeBody
     * @param node
     */
    public static prependNode (blockScopeBody: INode[], node: INode): void {
        Iif (!NodeUtils.validateNode(node)) {
            return;
        }
 
        blockScopeBody.unshift(node);
    }
 
    /**
     * @param node
     * @returns {boolean}
     */
    private static validateNode (node: INode): boolean {
        return !!node;
    }
}