import { Teq } from '../api/extjs/new-api/types/ej-types'; export const getDebugMode = function() { return false; }; export function copyObject(obj: any) { const result: { [index: string]: any; [index: number]: any } = {}; for (const prop in obj) { result[prop] = obj[prop]; } return result; } export const optsToJson = function optsToJson(options: any) { if (typeof options === 'undefined') { options = null; } return JSON.stringify(options); }; /** * Merges src options with default ones. * @param {object} src * @param {function} def - factory for default object. * Arrays are not supportetd. * @returns - object with merged options. * @throws - exception if there are options which are not presented in default options. * Note: this means that default options must contain all possible options. * */ export function mergeOptions(src: any, def: any) { const dst = def(); if (typeof dst !== 'object' && typeof src === 'undefined') { return dst; } function handleObj(src: any, dst: any) { const props = Object.getOwnPropertyNames(src); for (const prop of props) { if (typeof src[prop] === 'undefined') { continue; } if (typeof dst[prop] !== 'undefined' && typeof dst[prop] !== typeof src[prop]) { throw Error( 'Unexpected type for prop: ' + prop + ', expected: ' + typeof dst[prop] + ', actual: ' + typeof src[prop] ); } if (typeof dst[prop] === 'object') { handleObj(src[prop], dst[prop]); } else { dst[prop] = src[prop]; } } } if (!src) { src = {}; } handleObj(src, dst); return dst; } // Behaviour for access to property of undefined object. export enum dumpObjErrMode { exception = 0, // Generate exception. showNA = 1, // Show N/A for erroneous path. omitString = 2, // Omit the string. omitStringIfUndefined = 3, // Omit the string if object exists but property is undefined. } export interface PathsForDump { path: string; /** * Note - only arrays are supported. * when function is met in path, next argument from args array is used. */ args?: any[][]; /** * name to log, instead of funcName. */ alias?: string; /** * if true - values will be wrapped in double quotes. */ quotes?: boolean; } /** * Prints given object properties to string. * @param obj - Object which properties to print. * @param {Array} propPaths - Names for properties to print. * @param dstArr - Destination array to place strings to. * @param [errMode] - dumpObjErrMode */ export function dumpObj( obj: any, propPaths: Array, dstArr: string[], errMode: dumpObjErrMode ) { if (typeof errMode === 'undefined') { errMode = dumpObjErrMode.showNA; } if (typeof dstArr === 'undefined' || dstArr === null) { dstArr = []; } let actualPropPathArr = []; let actPropPathStr; try { outerLoop: for (let i = 0, len1 = propPaths.length; i < len1; i++) { let propPath = propPaths[i]; let argsArr: any[][] | undefined; let alias: string | undefined; let quotes: boolean | undefined; if (typeof propPath === 'object') { argsArr = propPath.args; alias = propPath.alias; quotes = propPath.quotes; propPath = propPath.path; } const subPropNames = propPath.split('.'); let propPathVal = obj; let argsIndex = 0; actualPropPathArr = []; for (let j = 0, len2 = subPropNames.length; j < len2; j++) { const subPropName = subPropNames[j]; if (!propPathVal) { if (errMode === dumpObjErrMode.showNA) { propPathVal = 'N/A'; break; } if (errMode >= dumpObjErrMode.omitString) { continue outerLoop; } } let braceCount = (subPropName.match(/\(\)/g) || []).length; if (braceCount) { const funcName = subPropName.slice(0, subPropName.indexOf('(')); let thisObj = propPathVal; propPathVal = propPathVal[funcName]; actPropPathStr = funcName; while (braceCount--) { if (!propPathVal) { if (errMode === dumpObjErrMode.showNA) { propPathVal = 'N/A'; break; } if (errMode >= dumpObjErrMode.omitString) { continue outerLoop; } } let args: any[] | undefined; if (argsArr) { args = argsArr[argsIndex]; argsIndex++; } let argsStr = ''; if (typeof args !== 'undefined' && args !== null) { argsStr = JSON.stringify(args).slice(1, -1); } actPropPathStr += '(' + argsStr + ')'; propPathVal = propPathVal.apply(thisObj, args); thisObj = propPathVal; } actualPropPathArr.push(actPropPathStr); actPropPathStr = ''; } else { propPathVal = propPathVal[subPropName]; actualPropPathArr.push(subPropName); } } if (typeof propPathVal === 'object') { propPathVal = JSON.stringify(propPathVal); } if (typeof propPathVal === 'undefined' && errMode === dumpObjErrMode.omitStringIfUndefined) { continue; } dstArr.push( (alias ? alias : actualPropPathArr.join('.')) + ': ' + (quotes ? '"' + propPathVal + '"' : propPathVal) ); } } catch (e) { actualPropPathArr.push(actPropPathStr); e.message += '; Path: ' + actualPropPathArr.join('.'); if (getDebugMode()) { console.log(e.stack); } throw e; } return dstArr; } // Gets object property by path. // If some property is function - it will be called without arguments. export function result(origVal: any, path: string, defaultValue: any) { let val = origVal; try { if (val == null) { return defaultValue; } const pathArr = path.split('.'); const len = pathArr.length; for (let i = 0; i < len; i++) { const key = pathArr[i]; const prevVal = val; val = val[key]; if (typeof val === 'function') { val = val.call(prevVal); } else if (val == null) { return defaultValue; } } return val; } catch (err) { console.error('Invalid path: ' + path); console.dir(origVal); throw err; } } export interface CUMap { [index: string]: string; } /** * Inverted object {'key': 'value'} -> {'value': 'key'} * @param {Object} map * @return {Object} - inverted maps. * { * invertedMapFirst, - object where for not unique values of input object, * only first key will be used as a value. * invertedMapAll, object where for not unique values of input object, * all keys, separated by comma, will be used as a value. * } */ export function invertMapObj(map: CUMap) { const invertedMapFirstKey: { [index: string]: string } = Object.create(null); const invertedMapArrAllKeys: { [index: string]: string[] } = Object.create(null); const mapEntries = Object.entries(map); mapEntries.forEach(([key, value]) => { if (typeof invertedMapFirstKey[value] === 'undefined') { invertedMapFirstKey[value] = key; invertedMapArrAllKeys[value] = [key]; } else { invertedMapArrAllKeys[value].push(key); } }); const invertedMapAllKeys: { [index: string]: string } = Object.create(null); const invertedMapEntries = Object.entries(invertedMapArrAllKeys); invertedMapEntries.forEach(([key, value]) => { invertedMapAllKeys[key] = value.join(', '); }); return { invertedMapFirstKey: invertedMapFirstKey, invertedMapAllKeys: invertedMapAllKeys, }; } /** * Replaces xtype by xtype(true) in TEQ string. * @param tEQ * @return {String} */ export function replaceXTypesInTeq(tEQ: Teq) { const re = /((^|[)\],\s}>])[\w\d\-_\\.]+)/g; return tEQ.replace(re, '$&(true)'); }