UNPKG

apphouse

Version:

Component library for React that uses observable state management and theme-able components.

302 lines (284 loc) 8.55 kB
import orderedJson from 'json-order'; import beautify_js from 'js-beautify'; interface JSResponse<T> { /** results wanted, it will always be of the desired type */ response: T | undefined; /** if true, response if valid, if false: response was forced * casted clean and it will not be correct, expect error */ valid: boolean; /** * it will contain the error message if valid is false */ error: string | undefined; /** * original value being operated on */ value: any; } export default class JS { /** * @param srcObj an object with the properties in any order * @param map [optional]: the property map generated by parse above. * @param separator [optional]: a non-empty string that controls what the key separator is in the generated map. Defaults to ~. * If the map is unset, the response is a standard JSON.stringify. * @param space [optional]: a number used to insert white space into the output JSON string * for readability purposes, as per the JSON.stringify * @returns */ static jsonStringify = (srcObj: object, map?: any, separator?: string) => { return orderedJson.stringify(srcObj, map, separator); }; static jsonParse = (src: string) => { return orderedJson.parse(src); }; static stringify( value: object, pretty?: boolean, jsonNotation?: boolean ): JSResponse<string> { if (typeof value === 'object') { try { const objectString = JS.objectToString(value, jsonNotation); // remove last dangling comma const str = objectString.replace(/,\s*$/, ''); const prettyStr = JS.prettify(str); return { response: pretty ? prettyStr : str.replaceAll('\\', ' '), valid: true, error: undefined, value }; } catch (e) { return { response: undefined, valid: false, error: JSON.stringify(e), value }; } } return { response: undefined, valid: false, error: 'value is not an object', value }; } static jsSingleQuotesToDouble(value: string): string { return value.replace(/'/g, '"'); } static jsStringObjectToJSONObject(value: string) { const jsonStr = value.replace(/(\w+:)|(\w+ :)/g, function (matchedStr) { return '"' + matchedStr.substring(0, matchedStr.length - 1) + '":'; }); if (!jsonStr) { return ''; } if (jsonStr.startsWith('{')) { return jsonStr; } else { return `{${jsonStr}}`; } } /** * Check if a string has valid JSON object syntax * @param text string to check if valid json * @returns false if not valid json, true if valid json */ static testJSON = (text: string): boolean => { if (typeof text !== 'string') { return false; } try { JSON.parse(text); return true; } catch (error) { return false; } }; static jsStringToObject(value: string, retry?: boolean): JSResponse<object> { if (typeof value === 'string') { const jsonStr = value.replace(/(\w+:)|(\w+ :)/g, function (matchedStr) { return '"' + matchedStr.substring(0, matchedStr.length - 1) + '":'; }); try { //converts to a regular object const response = { response: JSON.parse(jsonStr), valid: true, error: undefined, value }; return response; } catch (error: any) { if (retry) { // has already tried to fix the string return { response: undefined, valid: false, error: String(error), value }; } else { // retrying return JS.jsStringToObject(JS.escapeJSON(value), true); } } } return { response: undefined, valid: false, error: 'value is not a string', value }; } static prettify(value: string): string { if (!value) { return ''; } if (value.startsWith('{')) { return beautify_js(value, { indent_size: 2, js: { preserve_newlines: true, escape_quotes: true } }); } return beautify_js(`{${value}}`, { indent_size: 2, quote_keys: true, js: { preserve_newlines: true, escape_quotes: true, quote_keys: true } }); } static objectToString(obj: any, jsonNotation?: boolean) { var str = ''; var i = 0; for (var key in obj) { if (obj.hasOwnProperty(key)) { if (typeof obj[key] == 'object') { if (obj[key] instanceof Array) { if (jsonNotation) { str += `"${key}":[`; } else { //let's check if the key has special characters //so we can keep the quotes if (key.match(/[^a-zA-Z0-9]/)) { str += `"${key}": [`; } else { str += `${key}:[`; } } for (var j = 0; j < obj[key].length; j++) { const item = obj[key][j]; if (typeof item == 'object') { const strObj = JS.objectToString(item, jsonNotation) + (j <= item.length - 1 ? ',' : ''); const newStr = strObj.replace(/,\s*$/, ''); // substitute string with cleaned up string str += '{' + newStr + '},'; } else if (typeof item == 'string') { // let's double quote it str += `"${item}",`; //non objects would be represented as strings } else { str += `${item},`; } } // remove last comma const newStr = str.replace(/,\s*$/, ''); // substitute string with cleaned up string str = newStr; str += '],'; } else { const objStr = JS.objectToString(obj[key], jsonNotation); // remove last comma const newStr = objStr.replace(/,\s*$/, ''); // substitute string with cleaned up string str += `"${key}"` + ':{' + newStr + '},'; } } else { const item = obj[key]; if (typeof item == 'string') { // let's double quote it if (jsonNotation) { str += `"${key}":"${obj[key]}",`; } else { //let's check if the key has special characters //so we can keep the quotes if (key.match(/[^a-zA-Z0-9]/)) { str += `"${key}":"${obj[key]}",`; } else { str += `${key}:"${obj[key]}",`; } } } else { if (jsonNotation) { str += `"${key}":${obj[key]},`; } else { //let's check if the key has special characters //so we can keep the quotes if (key.match(/[^a-zA-Z0-9]/)) { str += `"${key}":${obj[key]},`; } else { str += `${key}:${obj[key]},`; } } } } i++; } } return str; } static escapeJSON(string: string) { return string.replace(/[\n"\&\r\t\b\f\\\/]/g, '\\$&'); } static stringToObject(str: string): { [id: string]: any } { const obj: { [id: string]: any } = {}; const markers: number[] = []; const chars = str.split(''); chars.forEach((char, index) => { if (char === ':') { markers.push(index); } }); markers.forEach((marker) => { // detect if : is indeed a marker if (chars[marker + 1] !== '\\') { // it is a marker const key = str.substring(0, marker); const value = str.substring(marker + 1); obj[key] = value; } }); return obj; } /** * Order the CSSProperties by applying a map to it * @param obj CSS Properties object * @param map map with the css properties in sequence to render * @returns obj, if no Map is provided, it will return the same object */ static applyMapToObj(obj: any, map?: any) { if (!map) { return obj; } const newObj: any = {}; for (const key in obj) { if (obj.hasOwnProperty(key)) { const element = obj[key]; if (map[key]) { newObj[map[key]] = element; } else { newObj[key] = element; } } } return newObj; } }