All files / generator abstract-synthax-tree-builder.ts

100% Statements 45/45
100% Branches 14/14
100% Functions 10/10
100% Lines 42/42

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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 801x 1x 1x     1x   1x 139x 139x 139x   139x     1x 31x   31x 31x 31x   31x 28x 89x   61x       31x     1x 25x 25x     25x 72x   25x 72x 72x 35x   37x 37x       25x         25x 25x   25x               1x 179x   179x 28x 151x 20x   131x       1x
import { Utils } from './utils';
import { ValueTypeEnum } from './enums/value-type.enum';
import * as _ from 'lodash';
import { AbstractSyntaxTreeModel } from './models/abstract-syntax-tree.model';
 
export class AbstractSyntaxTreeBuilder {
 
    static buildPrimitive(node: any): AbstractSyntaxTreeModel {
        const type = Utils.getType(node);
        const required = type === ValueTypeEnum.STRING ? !!node : true;
        const values = [node];
 
        return {type, required, values};
    }
 
    static buildObject(node: any): AbstractSyntaxTreeModel {
        const type = Utils.getType(node);
 
        const keys = Object.keys(node);
        const required = keys.length > 0;
        let children = {};
 
        if (required) {
            children = keys.map(k => {
                return {[k]: AbstractSyntaxTreeBuilder.buildNode(node[k])};
            }).reduce((previousValue, currentValue) => {
                return _.assign(previousValue, currentValue);
            });
        }
 
        return {type, required, children};
    }
 
    static buildArray(node: Array<any>): AbstractSyntaxTreeModel {
        const type = Utils.getType(node);
        const required = node.length > 0;
 
        // build children.
        const arrayWithDuplicates = node.map((value) => {
            return AbstractSyntaxTreeBuilder.buildNode(value);
        });
        const uniqArray = _.transform(arrayWithDuplicates, (acc: AbstractSyntaxTreeModel[], curr: AbstractSyntaxTreeModel) => {
            const similarEntry = _.filter(acc, value => Utils.isEqualWithout(value, curr, 'values'));
            if (similarEntry.length === 0) {
                acc.push(curr);
            } else {
                const ast = similarEntry[0] as AbstractSyntaxTreeModel;
                if (ast.values && curr.values) ast.values.push(...curr.values);
            }
        });
 
        const children = {
            ...uniqArray
        };
 
        // get uniqueItems
        const uniqueValueLength = _.uniqWith(node, _.isEqual).length;
        const uniqueItems = uniqueValueLength === node.length;
 
        return {type, required, children, uniqueItems};
    }
 
    /**
     * Orchestrator
     * @param node
     * @return {AbstractSyntaxTreeModel}
     */
    static buildNode(node: any) {
        const type = Utils.getType(node);
 
        if (type === ValueTypeEnum.OBJECT) {
            return AbstractSyntaxTreeBuilder.buildObject(node);
        } else if (type === ValueTypeEnum.ARRAY) {
            return AbstractSyntaxTreeBuilder.buildArray(node);
        } else {
            return AbstractSyntaxTreeBuilder.buildPrimitive(node);
        }
    }
 
}