All files / src/node-transformers/node-control-flow-transformers/control-flow-replacers LogicalExpressionControlFlowReplacer.ts

100% Statements 25/25
100% Branches 8/8
100% Functions 2/2
100% Lines 22/22
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 931x 1x                   1x   1x 1x 1x     1x       1x                   203x                           403x 1x     402x 402x   402x   402x             402x                           403x 805x   805x 803x   2x     805x              
import { injectable, inject } from 'inversify';
import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
 
import * as ESTree from 'estree';
 
import { TCustomNodeFactory } from '../../../types/container/TCustomNodeFactory';
 
import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
import { IOptions } from '../../../interfaces/options/IOptions';
import { IStorage } from '../../../interfaces/storages/IStorage';
 
import { CustomNodes } from '../../../enums/container/CustomNodes';
 
import { ExpressionWithOperatorControlFlowReplacer } from './ExpressionWithOperatorControlFlowReplacer';
import { Node } from '../../../node/Node';
import { NodeUtils } from '../../../node/NodeUtils';
 
@injectable()
export class LogicalExpressionControlFlowReplacer extends ExpressionWithOperatorControlFlowReplacer {
    /**
     * @type {number}
     */
    private static readonly usingExistingIdentifierChance: number = 0.5;
 
    /**
     * @param customNodeFactory
     * @param options
     */
    constructor (
        @inject(ServiceIdentifiers.Factory__ICustomNode) customNodeFactory: TCustomNodeFactory,
        @inject(ServiceIdentifiers.IOptions) options: IOptions
    ) {
        super(customNodeFactory, options);
    }
 
    /**
     * @param logicalExpressionNode
     * @param parentNode
     * @param controlFlowStorage
     * @returns {ESTree.Node}
     */
    public replace (
        logicalExpressionNode: ESTree.LogicalExpression,
        parentNode: ESTree.Node,
        controlFlowStorage: IStorage <ICustomNode>
    ): ESTree.Node {
        if (this.checkForProhibitedExpressions(logicalExpressionNode.left, logicalExpressionNode.right)) {
            return logicalExpressionNode;
        }
 
        const replacerId: string = logicalExpressionNode.operator;
        const logicalExpressionFunctionCustomNode: ICustomNode = this.customNodeFactory(CustomNodes.LogicalExpressionFunctionNode);
 
        logicalExpressionFunctionCustomNode.initialize(replacerId);
 
        const storageKey: string = this.insertCustomNodeToControlFlowStorage(
            logicalExpressionFunctionCustomNode,
            controlFlowStorage,
            replacerId,
            LogicalExpressionControlFlowReplacer.usingExistingIdentifierChance
        );
 
        return this.getControlFlowStorageCallNode(
            controlFlowStorage.getStorageId(),
            storageKey,
            logicalExpressionNode.left,
            logicalExpressionNode.right
        );
    }
 
    /**
     * @param leftExpression
     * @param rightExpression
     * @returns {boolean}
     */
    private checkForProhibitedExpressions (leftExpression: ESTree.Expression, rightExpression: ESTree.Expression): boolean {
        return [leftExpression, rightExpression].some((expressionNode: ESTree.Node | ESTree.Expression): boolean => {
            let nodeForCheck: ESTree.Node | ESTree.Expression;
 
            if (!Node.isUnaryExpressionNode(expressionNode)) {
                nodeForCheck = expressionNode;
            } else {
                nodeForCheck = NodeUtils.getUnaryExpressionArgumentNode(expressionNode);
            }
 
            return !Node.isLiteralNode(nodeForCheck) &&
                !Node.isIdentifierNode(nodeForCheck) &&
                !Node.isObjectExpressionNode(nodeForCheck) &&
                !Node.isExpressionStatementNode(nodeForCheck);
        });
    }
}