tia
Version:
Time is All (logs driven test engine with ExtJs support)
302 lines (262 loc) • 8.07 kB
text/typescript
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<string | PathsForDump>,
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)');
}