<commit_before>import * as myWalker from './util/myWalker'
import * as types from './domains/types'

/**
 * Get types of expression at the given range
 * @param ast
 * @param Ĉ
 * @param start
 * @param end
 * @returns {{hasType: boolean, typeString: string, nodeStart: number, nodeEnd: number}}
 */
export function getTypeAtRange(ast, Ĉ, start, end) {
    'use strict';
    const node = myWalker.findSurroundingNode(ast, start, end);
    const nodeTypes = Ĉ.getTypeOfLoc(node);
    let hasType;
    let typeString = '';
    if (!nodeTypes) {
        hasType = false;
        typeString = 'No expression at the given range';
    } else {
        hasType = true;
        typeString = '';
        nodeTypes.forEach(function (tp, i) {
            typeString += tp.getName();
            if (i !== nodeTypes.length - 1) {
                typeString += ', ';
            }
        });
    }
    return {
        hasType: hasType,
        typeString: typeString,
        nodeStart: node.start,
        nodeEnd: node.end
    };
}

function computeIconOfProp(propMap) {
    const iconMap = new Map();

    function isObject(icon) {
        return icon === 'object' || icon === 'array' || icon === 'fn';
    }

    propMap.forEach((tps, p) => {
        for (let tp of tps) {
            let icon;
            if (tp === types.PrimNumber) icon = 'number';
            else if (tp === types.PrimBoolean) icon = 'boolean';
            else if (tp === types.PrimString) icon = 'string';
            else if (tp instanceof types.FnType) icon = 'fn';
            else if (tp instanceof types.ArrType) icon = 'array';
            else if (tp instanceof types.ObjType) icon = 'object';

            if (!iconMap.has(p) || iconMap.get(p) === icon) {
                iconMap.set(p, icon);
                continue;
            }

            if (isObject(icon) && isObject(iconMap.get(p))) {
                iconMap.set(p, 'object');
            } else {
                iconMap.set(p, 'unknown');
                break;
            }
        }
    });
    return iconMap;
}

/**
 * Get prop to icon map from given node
 * @param Ĉ - AbsCache
 * @param node - expression node
 * @returns {Map.<string, string>} - Mapping from prop to icon
 */
export function getPropFromNode(Ĉ, node) {
    const nodeTypes = Ĉ.getTypeOfLoc(node);
    //console.info(getReadablePropMap(nodeTypes));
    const propMap = getReadablePropMap(nodeTypes);
    return computeIconOfProp(propMap);<commit_msg>[BUGFiX] Should show properties with empty AVal Before this fix, if null or undefined value is assigned to a property, the propery does not show in the completion list.<commit_after>import * as myWalker from './util/myWalker'
import * as types from './domains/types'

/**
 * Get types of expression at the given range
 * @param ast
 * @param Ĉ
 * @param start
 * @param end
 * @returns {{hasType: boolean, typeString: string, nodeStart: number, nodeEnd: number}}
 */
export function getTypeAtRange(ast, Ĉ, start, end) {
    'use strict';
    const node = myWalker.findSurroundingNode(ast, start, end);
    const nodeTypes = Ĉ.getTypeOfLoc(node);
    let hasType;
    let typeString = '';
    if (!nodeTypes) {
        hasType = false;
        typeString = 'No expression at the given range';
    } else {
        hasType = true;
        typeString = '';
        nodeTypes.forEach(function (tp, i) {
            typeString += tp.getName();
            if (i !== nodeTypes.length - 1) {
                typeString += ', ';
            }
        });
    }
    return {
        hasType: hasType,
        typeString: typeString,
        nodeStart: node.start,
        nodeEnd: node.end
    };
}

function computeIconOfProp(propMap) {
    const iconMap = new Map();

    function isObject(icon) {
        return icon === 'object' || icon === 'array' || icon === 'fn';
    }

    propMap.forEach((tps, p) => {
        for (let tp of tps) {
            let icon;
            if (tp === types.PrimNumber) icon = 'number';
            else if (tp === types.PrimBoolean) icon = 'boolean';
            else if (tp === types.PrimString) icon = 'string';
            else if (tp instanceof types.FnType) icon = 'fn';
            else if (tp instanceof types.ArrType) icon = 'array';
            else if (tp instanceof types.ObjType) icon = 'object';

            if (!iconMap.has(p) || iconMap.get(p) === icon) {
                iconMap.set(p, icon);
                continue;
            }

            if (isObject(icon) && isObject(iconMap.get(p))) {
                iconMap.set(p, 'object');
            } else {
                iconMap.set(p, 'unknown');
                break;
            }
        }
        console.info(p);
        if (tps.size === 0) {
            iconMap.set(p, 'unknown');
        }
    });
    return iconMap;
}

/**
 * Get prop to icon map from given node
 * @param Ĉ - AbsCache
 * @param node - expression node
 * @returns {Map.<string, string>} - Mapping from prop to icon
 */
export function getPropFromNode(Ĉ, node) {
    const nodeTypes = Ĉ.getTypeOfLoc(node);
    //console.info(getReadablePropMap(nodeTypes));
    const propMap = getReadablePropMap(nodeTypes);
    return computeIconOfProp(propMap);
{'fraction_non_alphanumeric': 0.13076181292189007, 'fraction_numerical': 0.0005785920925747348, 'mean_word_length': 2.0759193357058128, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7346983', 'n_tokens_mistral': 1561, 'n_tokens_neox': 1527, 'n_words': 443}