damon-utils
Version:
A post-processing library for DAMON
1,017 lines (1,003 loc) • 163 kB
JavaScript
const DOMPurify = require('dompurify');
const Papa = require('papaparse');
const jsonLogic = require('json-logic-js');
//#### Utils
module.exports =
class DamonUtils {
/**
* Creates an instance of DamonUtils.
* @param {object} damon
*/
constructor(damon) {
let $ = this;
$.damon = damon;
$.domPurify = DOMPurify;
$.websiteRegex = /^(https?:\/\/)?[-a-zA-Z0-9]*[a-zA-Z0-9]+(\.[-a-zA-Z0-9]*[a-zA-Z0-9]+)+/;
$.httpRegex = /^https?:\/\//;
$.pathRegex = /^\.*\//;
}
/**
* @param {string} damonString
* @returns {string}
*/
damonToHtmlTable(damonString) {
const $ = this;
return $.mapToHtmlTable($.damon.damonToMap(damonString, 0, true));
}
/**
* @param {string} damonString
* @returns {string}
*/
damonToSExpression(damonString) {
const $ = this;
return $.prefixedKeysMapToSExpression($.damon.damonToMap(damonString, 0, true));
}
/**
* @param {string} jsonString
* @returns {string}
*/
sExpressionToDamon(jsonString) {
const $ = this;
return $.damon.mapToDamon($.sExpressionToPrefixedKeysMap(jsonString), false, true);
}
/**
* @param {string} string
* @returns {string}
*/
escape(string) {
return string
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
/**
* @typedef {Map<string, damonValue>} damonMap
* @typedef {Array<damonValue>} damonArray
* @typedef {damonMap|damonArray|string|number|boolean|null} damonValue
* @param {damonValue} jsonMap
* @param {boolean} safeHTML
* @param {string} jsonContext
* @returns {object} DOM
*/
mapToHtmlList(jsonMap, safeHTML = false, jsonContext = undefined) {
let $ = this;
// Parsing check
try {
$.damon.mapToJSON(jsonMap);
} catch (error) {
throw new Error("Provided map value doesn't passes JSON.parse()");
}
var jsonItemIndex = 0,
list = document.createElement('ul'),
schema;
if (jsonContext !== undefined) {
schema = JSON.parse(jsonContext);
}
list.className = 'DAMON-List';
recurse(jsonMap, list);
return list;
/**
* @param {damonValue} jsonMap
* @param {object} listItem
* @returns {object} DOM
*/
function recurse(jsonMap, listItem, path = []) {// imitate renderDiff
if (
typeof listItem !== 'object'
|| listItem == null
|| Array.isArray(listItem)
) {
throw new Error("Error List Item number " + jsonItemIndex + ": @param { {} } list");
}
if (
typeof jsonMap === 'object'
&& jsonMap !== null
&& !Array.isArray(jsonMap)
&& jsonMap instanceof Map
&& jsonMap.constructor === Map
) {
if (listItem.tagName == "UL") {
for (const [key, value] of jsonMap) {
let newList = document.createElement('ul'),
newDiv = document.createElement('code'),
keySpan = document.createElement('span'),
newListItem = document.createElement('li');
newListItem.dataset.graphArbo = Array.from(jsonMap.keys()).indexOf(key);
if (path.length > 0)
newListItem.dataset.graphArbo =
path.join('-') + '-' + Array.from(jsonMap.keys()).indexOf(key);
keySpan.className = "type-key";
if (
$.websiteRegex.test(key)
|| $.pathRegex.test(key)
) {
let fullUrl = key;
if (
$.websiteRegex.test(key)
&& !$.httpRegex.test(key)
)
fullUrl = ('https://' + key);
let keyLink = DOMPurify.sanitize(`<a href="${ fullUrl }"><span>${ fullUrl }</span></a>`);
keySpan.innerHTML = keyLink;
} else {
if (
jsonContext !== undefined
&& key in schema['@context']
) {
keySpan.innerHTML =
DOMPurify.sanitize(
`<a href="${ schema['@context'][key]['@id'] }"><span>${ key }</span></a>`
);
} else {
keySpan.textContent = key;
}
}
if (
typeof value === 'object'
&& value !== null
) {
if (Array.isArray(value)) {
if (
jsonMap.damonInlineArrays !== undefined
&& jsonMap.damonInlineArrays.indexOf(key) > -1
) {
newDiv.innerHTML = keySpan.outerHTML + '<span class="operator">: </span>[';
for (let j = 0, k = value.length; j < k; j++) {
let childValueSpan = document.createElement('span'),
childValue = value[j];
if (childValue === true) {
childValueSpan.textContent = "true";
childValueSpan.className = "type-boolean";
} else if (childValue === false) {
childValueSpan.textContent = "false";
childValueSpan.className = "type-boolean";
} else if (childValue === null) {
childValueSpan.textContent = "null";
childValueSpan.className = "type-null";
} else if (
Number.isFinite(childValue)
&& !Number.isNaN(childValue)
) {
childValueSpan.textContent = childValue + "";
childValueSpan.className = "type-number";
} else {
if (safeHTML) {
if (
$.websiteRegex.test(childValue)
|| $.pathRegex.test(childValue)
) {
let fullUrl = childValue;
if (
$.websiteRegex.test(childValue)
&& !$.httpRegex.test(childValue)
)
fullUrl = 'https://' + childValue;
childValueSpan.innerHTML =
DOMPurify.sanitize(`<a href="${ fullUrl }">"${ fullUrl }"</a>`);
} else {
childValueSpan.innerHTML = `"${childValue}"`;
}
} else {
if (
$.websiteRegex.test(childValue)
|| $.pathRegex.test(childValue)
) {
let fullUrl = childValue;
if (
!$.httpRegex.test(childValue)
&& $.websiteRegex.test(childValue)
)
fullUrl = 'https://' + childValue;
childValueSpan.innerHTML =
DOMPurify.sanitize(`<a href="${ fullUrl }">"${ fullUrl }"</a>`);
} else {
childValueSpan.textContent = `"${childValue}"`;
}
}
childValueSpan.className = "type-string";
}
if (j !== 0) {
newDiv.innerHTML += ', ';
}
newDiv.appendChild(childValueSpan);
}
newDiv.innerHTML += ']';
newListItem.appendChild(newDiv);
newListItem.appendChild(newList);
listItem.appendChild(newListItem);
} else {
newDiv.innerHTML = keySpan.outerHTML + '<span class="operator">: </span>[]';
newListItem.appendChild(newDiv);
newListItem.appendChild(newList);
listItem.appendChild(newListItem);
recurse(value, newList, path.concat([Array.from(jsonMap.keys()).indexOf(key)]));
}
} else {
if (
jsonMap.implicitMaps !== undefined
&& jsonMap.implicitMaps.indexOf(key) > -1
) {
newDiv.innerHTML = keySpan.outerHTML;
} else {
newDiv.innerHTML = keySpan.outerHTML + '<span class="operator">: </span>{}';
}
newListItem.appendChild(newDiv);
newListItem.appendChild(newList);
listItem.appendChild(newListItem);
recurse(value, newList, path.concat([Array.from(jsonMap.keys()).indexOf(key)]));
}
} else {
jsonItemIndex++;
newDiv.innerHTML = keySpan.outerHTML + '<span class="operator">: </span>';
let valueSpan = document.createElement('span');
let childText = value;
if (childText === true) {
valueSpan.textContent = "true";
valueSpan.className = "type-boolean";
} else if (childText === false) {
valueSpan.textContent = "false";
valueSpan.className = "type-boolean";
} else if (childText === null) {
valueSpan.textContent = "null";
valueSpan.className = "type-null";
} else if (
Number.isFinite(childText)
&& !Number.isNaN(childText)
) {
valueSpan.textContent = childText + "";
valueSpan.className = "type-number";
} else {
if (safeHTML) {
if (
$.websiteRegex.test(childText)
|| $.pathRegex.test(childText)
) {
let fullUrl = childText;
if (
!$.httpRegex.test(childText)
&& $.websiteRegex.test(childText)
)
fullUrl = 'https://' + childText;
valueSpan.innerHTML =
DOMPurify.sanitize(`<a href="${ fullUrl }">"${ fullUrl }"</a>`);
} else {
valueSpan.innerHTML = `"${childText}"`;
}
} else {
if (
$.websiteRegex.test(childText)
|| $.pathRegex.test(childText)
) {
let fullUrl = childText;
if (
!$.httpRegex.test(childText)
&& $.websiteRegex.test(childText)
)
fullUrl = 'https://' + childText;
valueSpan.innerHTML =
DOMPurify.sanitize(`<a href="${ fullUrl }">"${ fullUrl }"</a>`);
} else {
valueSpan.textContent = `"${childText}"`;
}
}
valueSpan.className = "type-string";
}
if (
jsonMap.implicitNulls === undefined
|| jsonMap.implicitNulls.indexOf(key) == -1
) {
newDiv.appendChild(valueSpan);
} else {
newDiv.innerHTML = newDiv.innerHTML.slice(0, -2);
}
newListItem.appendChild(newDiv);
listItem.appendChild(newListItem);
}
}
}
} else if (Array.isArray(jsonMap)) {
for (var i = 0, c = jsonMap.length; i < c; i++) {
let newList = document.createElement('ul'),
newDiv = document.createElement('code'),
newListItem = document.createElement('li');
newListItem.dataset.graphArbo = i;
if (path.length > 0)
newListItem.dataset.graphArbo = path.join('-') + '-' + i;
if (
typeof jsonMap[i] === 'object'
&& jsonMap[i] !== null
) {
if (Array.isArray(jsonMap[i])) {
if (
jsonMap.damonInlineArrays !== undefined
&& jsonMap.damonInlineArrays.indexOf(i) > -1
) {
newDiv.innerHTML += '[';
for (let j = 0, k = jsonMap[i].length; j < k; j++) {
let valueSpan = document.createElement('span'),
value = jsonMap[i][j];
if (value === true) {
valueSpan.textContent = "true";
valueSpan.className = "type-boolean";
} else if (value === false) {
valueSpan.textContent = "false";
valueSpan.className = "type-boolean";
} else if (value === null) {
valueSpan.textContent = "null";
valueSpan.className = "type-null";
} else if (
Number.isFinite(value)
&& !Number.isNaN(value)
) {
valueSpan.textContent = value + "";
valueSpan.className = "type-number";
} else {
if (safeHTML) {
if (
$.websiteRegex.test(value)
|| $.pathRegex.test(value)
) {
let fullUrl = value;
if (
!$.httpRegex.test(value)
&& $.websiteRegex.test(value)
)
fullUrl = ('https://' + value);
valueSpan.innerHTML =
DOMPurify.sanitize(`<a href="${ fullUrl }">"${ fullUrl }"</a>`);
} else {
valueSpan.innerHTML = `"${value}"`;
}
} else {
if (
$.websiteRegex.test(value)
|| $.pathRegex.test(value)
) {
let fullUrl = value;
if (
!$.httpRegex.test(value)
&& $.websiteRegex.test(value)
)
fullUrl = ('https://' + value);
valueSpan.innerHTML =
DOMPurify.sanitize(`<a href="${ fullUrl }">"${ fullUrl }"</a>`);
} else {
valueSpan.textContent = `"${value}"`;
}
}
valueSpan.className = "type-string";
}
if (j !== 0) {
newDiv.innerHTML += ', ';
}
newDiv.appendChild(valueSpan);
}
newDiv.innerHTML += ']';
newListItem.appendChild(newDiv);
newListItem.appendChild(newList);
listItem.appendChild(newListItem);
} else {
newDiv.textContent = "[]";
newListItem.appendChild(newDiv);
newListItem.appendChild(newList);
listItem.appendChild(newListItem);
recurse(jsonMap[i], newList, path.concat(i));
}
} else {
newDiv.textContent = "{}";
newListItem.appendChild(newDiv);
newListItem.appendChild(newList);
listItem.appendChild(newListItem);
recurse(jsonMap[i], newList, path.concat(i));
}
} else {
jsonItemIndex++;
let childText = jsonMap[i];
if (childText === true) {
newDiv.textContent = "true";
newDiv.className = "type-boolean";
} else if (childText === false) {
newDiv.textContent = "false";
newDiv.className = "type-boolean";
} else if (childText === null) {
newDiv.textContent = "null";
newDiv.className = "type-null";
} else if (
Number.isFinite(childText)
&& !Number.isNaN(childText)
) {
newDiv.textContent = childText + "";
newDiv.className = "type-number";
} else {
if (safeHTML) {
if (
$.websiteRegex.test(childText)
|| $.pathRegex.test(childText)
) {
let fullUrl = childText;
if (
!$.httpRegex.test(childText)
&& $.websiteRegex.test(childText)
)
fullUrl = 'https://' + childText;
newDiv.innerHTML =
DOMPurify.sanitize(`<a href="${ fullUrl }">"${ fullUrl }"</a>`);
} else {
newDiv.innerHTML = `"${childText}"`;
}
} else {
if (
$.websiteRegex.test(childText)
|| $.pathRegex.test(childText)
) {
let fullUrl = childText;
if (
!$.httpRegex.test(childText)
&& $.websiteRegex.test(childText)
)
fullUrl = 'https://' + childText;
newDiv.innerHTML =
DOMPurify.sanitize(`<a href="${ fullUrl }">"${ fullUrl }"</a>`);
} else {
newDiv.textContent = `"${childText}"`;
}
}
newDiv.className = "type-string";
}
newListItem.appendChild(newDiv);
newListItem.appendChild(newList);
listItem.appendChild(newListItem);
}
}
}
}
}
sliceIjsonKey(key) {
let indexPrefixMatch = key.match(/^[0-9]+-/);
if (indexPrefixMatch[0] !== null) {
return key.slice(indexPrefixMatch[0].length);
} else {
throw new Error(`Key "${ key }" fails IJSON validation.`);
}
}
/**
* @param {damonValue} jsonMap
* @param {boolean} [safeHTML=false]
* @returns {object} DOM
*/
mapToHtmlTable(jsonMap, safeHTML = false) {
let $ = this;
// Parsing check
try {
$.damon.mapToJSON(jsonMap);
} catch (error) {
throw new Error("Provided value doesn't passes JSON.parse().");
}
var jsonItemIndex = 0,
table = document.createElement('table'),
tHead = document.createElement('thead'),
tBody = document.createElement('tbody'),
headingsEncountered = false,
columnsLength = 0;
table.className = 'DAMON-Table';
if (
typeof jsonMap !== 'object'
|| jsonMap == null
|| Array.isArray(jsonMap)
|| !(jsonMap instanceof Map)
|| jsonMap.constructor !== Map
) {
throw new Error("Error: expected an Object value, saw otherwise.");
}
for (const [key, value] of jsonMap) {
if (
typeof value === 'object'
&& value !== null
&& !Array.isArray(value)
&& value instanceof Map
&& value.constructor === Map
) {
if (jsonItemIndex == 0) {
let slicedSubMapKeys = Array.from(value.keys()).map($.sliceIjsonKey),
slicedSubMapKeysSet = new Set(slicedSubMapKeys);
if (slicedSubMapKeys.length !== slicedSubMapKeysSet.size) {
throw new Error('Duplicate in headings.');
}
let row = document.createElement('tr');
columnsLength = value.length;
for (const [cK, childValue] of value) {
let childKey = $.sliceIjsonKey(cK);
if (childValue === null) {
let headerCell = document.createElement('th');
headerCell.dataset.graphArbo = jsonItemIndex + '-' + row.children.length;
if (safeHTML) {
if (
$.websiteRegex.test(childKey)
|| $.pathRegex.test(childKey)
) {
headerCell.innerHTML =
DOMPurify.sanitize(`<a href="${ childKey }">${ childKey }</a>`);
} else {
headerCell.innerHTML = `${childKey}`;
}
} else {
if (
$.websiteRegex.test(childKey)
|| $.pathRegex.test(childKey)
) {
headerCell.innerHTML =
DOMPurify.sanitize(`<a href="${ childKey }">${ childKey }</a>`);
} else {
headerCell.textContent = `${childKey}`;
}
}
row.appendChild(headerCell);
} else {
throw new Error(
"Error row " + jsonItemIndex + ": expected implicit null property, saw otherwise."
);
}
}
tHead.appendChild(row);
headingsEncountered = true;
} else {
if (value.length != columnsLength) {
// unmatching columns length
throw new Error(
"Error row " + jsonItemIndex + ": cells total doesn't match the header's."
);
}
let row = document.createElement('tr');
for (const [cK, childValue] of value) {
let childKey = $.sliceIjsonKey(cK);
if (childValue === null) {
let dataCell = document.createElement('td');
dataCell.dataset.graphArbo = jsonItemIndex + '-' + row.children.length;
if (safeHTML) {
if (
$.websiteRegex.test(childKey)
|| $.pathRegex.test(childKey)
) {
dataCell.innerHTML =
DOMPurify.sanitize(`<a href="${ childKey }">${ childKey }</a>`);
} else {
dataCell.innerHTML = `${childKey}`;
}
} else {
if (
$.websiteRegex.test(childKey)
|| $.pathRegex.test(childKey)
) {
dataCell.innerHTML =
DOMPurify.sanitize(`<a href="${ childKey }">${ childKey }</a>`);
} else {
dataCell.textContent = `${childKey}`;
}
}
row.appendChild(dataCell);
} else {
throw new Error(
"Error row " + jsonItemIndex + ": expected implicit null property, saw otherwise."
);
}
}
tBody.appendChild(row);
}
} else {
throw new Error("Error row " + jsonItemIndex + ": expected an Object value, saw otherwise.");
}
jsonItemIndex++;
}
if (headingsEncountered) {
table.appendChild(tHead);
}
table.appendChild(tBody);
return table;
}
/**
* @param {damonMap} jsonMap
* @returns {string}
*/
prefixedKeysMapToSExpression(jsonMap) {
const $ = this;
var list = ``;
if (
typeof jsonMap === 'object'
&& jsonMap !== null
&& jsonMap instanceof Map
&& jsonMap.constructor === Map
) {
list += "[\r\n";
_recurse(jsonMap);
list += "]";
JSON.parse(list);
return list;
} else {
if (typeof jsonMap == 'string') {
jsonMap = '"' + jsonMap + '"';
}
JSON.parse(jsonMap);
return jsonMap;
}
/**
* @param {Map<string, any>|Array<any>} jsonMap
* @param {number} [level=1]
* @returns {string}
*/
function _recurse(jsonMap, level = 1) {
if (
typeof jsonMap === 'object'
&& jsonMap !== null
&& !Array.isArray(jsonMap)
&& jsonMap instanceof Map
&& jsonMap.constructor === Map
) {
let i = -1;
for (const [k, value] of jsonMap) {
i++;
let key = $.sliceIjsonKey(k);
if (
typeof value === 'object'
&& value !== null
) {
if (Array.isArray(value)) {
if (value.length > 0) {
list += ' '.repeat(level) + `${JSON.stringify(key)}, [\r\n`;
_recurse(value, level + 1);
list += ' '.repeat(level) + `]`;
} else {
list += ' '.repeat(level) + `${JSON.stringify(key)}, []`;
}
} else {
if (Array.from(value.keys()).length > 0) {
if (level == 1) {
if (i == 0) {
list = "";
} else {
throw new Error("Multiple S-Expression roots");
}
}
list += ' '.repeat(level) + `[${JSON.stringify(key)}, \r\n`;
_recurse(value, level + 1);
if (level != 1) {
list += ' '.repeat(level) + `]`;
}
} else {
list += ' '.repeat(level) + `${JSON.stringify(key)}, []`;
}
}
} else {
if (value === true) {
throw new Error('Booleans require quotes');
} else if (value === false) {
throw new Error('Booleans require quotes');
} else if (value === null) {
list += ' '.repeat(level) + `${JSON.stringify(key)}`;
} else if (
Number.isFinite(value)
&& !Number.isNaN(value)
) {
list += ' '.repeat(level) + `${JSON.stringify(key)}` + ', ' + value;
} else {
list += ' '.repeat(level) + `${JSON.stringify(key)}` + ', ' + JSON.stringify(value);
}
}
let lastKey = Array.from(jsonMap.keys())[Array.from(jsonMap.keys()).length - 1];
if (k != lastKey) {
list += ",\r\n";
} else {
list += "\r\n";
}
}
} else if (Array.isArray(jsonMap)) {
for (var i = 0, c = jsonMap.length; i < c; i++) {
if (
typeof jsonMap[i] === 'object'
&& jsonMap[i] !== null
) {
if (Array.isArray(jsonMap[i])) {
if (jsonMap[i].length > 0) {
list += ' '.repeat(level) + `[\r\n`;
_recurse(jsonMap[i], level + 1);
list += ' '.repeat(level) + `]`;
} else {
list += ' '.repeat(level) + `[]`;
}
} else {
if (Array.from(jsonMap[i].keys()).length > 0) {
list += ' '.repeat(level) + `[\r\n`;
_recurse(jsonMap[i], level + 1);
list += ' '.repeat(level) + `]`;
} else {
list += ' '.repeat(level) + `[]`;
}
}
} else {
if (jsonMap[i] === true) {
throw new Error('Booleans require quotes');
} else if (jsonMap[i] === false) {
throw new Error('Booleans require quotes');
} else if (jsonMap[i] === null) {
throw new Error('Array-nulls require quotes');
} else if (
Number.isFinite(jsonMap[i])
&& !Number.isNaN(jsonMap[i])
) {
list += ' '.repeat(level) + jsonMap[i];
} else {
list += ' '.repeat(level) + JSON.stringify(jsonMap[i]);
}
}
if (i != c - 1) {
list += ",\r\n";
} else {
list += "\r\n";
}
}
}
}
}
/**
*
*
* @param {String} sExpression
* @returns {Map}
*/
sExpressionToPrefixedKeysMap(sExpression) {
const $ = this;
let damonMap = new Map();
damonMap.headless = true;
_recurse(JSON.parse(sExpression), damonMap, 0);
return damonMap;
function _recurse(sExpressionArray, map, i) {
let childMap = new Map();
map.set(i + '-' + sExpressionArray[0], childMap);
for (let i = 1, c = sExpressionArray.length; i < c; i++) {
if (Array.isArray(sExpressionArray[i])) {
_recurse(sExpressionArray[i], childMap, i - 1);
} else {
let indexPrefixedKey = (i - 1) + '-' + sExpressionArray[i];
childMap.set(indexPrefixedKey, null);
}
}
}
}
/**
* Arrays of inline-arrays produce array-parameters
* @param {string} damonString
* @return {string} mathJs
*/
prefixedKeysMapToMathJs(damonMap) {
const $ = this;
let mathJs = '';
if (Array.isArray(damonMap)) {
_recurse(damonMap);
return mathJs.slice(0, -1);
} else if (
typeof damonMap === 'object'
&& damonMap !== null
&& damonMap instanceof Map
&& damonMap.constructor === Map
) {
_recurse(damonMap);
return mathJs.slice(0, -1);
} else {8
if (typeof damonMap == 'string') {
damonMap = JSON.stringify(damonMap);
}
JSON.parse(damonMap);
return damonMap;
}
function _minusculize(string) {
return string[0].toLowerCase() + string.slice(1);
}
/**
* @param {Map<string, any>|Array<any>} damonMap
* @param {number} [level=1]
* @returns {string}
*/
function _recurse(damonMap, level = 0) {
if (
typeof damonMap === 'object'
&& damonMap !== null
&& !Array.isArray(damonMap)
&& damonMap instanceof Map
&& damonMap.constructor === Map
) {
for (const [k, value] of damonMap) {
let key = $.sliceIjsonKey(k);
// Normalizing to katex
if (key == 'Power')
key = 'Pow';
if (key == 'e')
key = '2.718281828459045';
if (key == 'i')
key = 'sqrt(-1)';
if (key == 'LN2')
key = '0.6931471805599453';
if (key == 'LN10')
key = '2.302585092994046';
if (key == 'LOG2E')
key = '1.4426950408889634';
if (key == 'LOG10E')
key = '0.4342944819032518';
if (key == 'phi')
key = '1.618033988749895';
if (key == 'pi')
key = '3.141592653589793';
if (key == 'SQRT1_2')
key = '0.7071067811865476';
if (key == 'SQRT2')
key = '1.4142135623730951';
if (key == 'tau')
key = '6.283185307179586';
if (
typeof value === 'object'
&& value !== null
) {
if (Array.isArray(value)) {
if (value.length > 0) {
mathJs += ' '.repeat(level) + `${JSON.stringify(_minusculize(key)).slice(1, -1)}(\n`;
_recurse(value, level + 1);
mathJs += ' '.repeat(level) + `)`;
} else {
mathJs += ' '.repeat(level) + `${JSON.stringify(_minusculize(key)).slice(1, -1)}()`;
}
} else {
if (Array.from(value.keys()).length > 0) {
mathJs += ' '.repeat(level) + `${JSON.stringify(_minusculize(key)).slice(1, -1)}(\n`;
_recurse(value, level + 1);
mathJs += ' '.repeat(level) + `)`;
} else {
mathJs += ' '.repeat(level) + `${JSON.stringify(_minusculize(key)).slice(1, -1)}()`;
}
}
} else {
if (value === true) {
mathJs += ' '.repeat(level) + `${JSON.stringify(_minusculize(key)).slice(1, -1)}` + "(true)";
} else if (value === false) {
mathJs += ' '.repeat(level) + `${JSON.stringify(_minusculize(key)).slice(1, -1)}` + "(false)";
} else if (value === null) {
mathJs += ' '.repeat(level) + `${JSON.stringify(_minusculize(key)).slice(1, -1)}`;
} else if (
Number.isFinite(value)
&& !Number.isNaN(value)
) {
mathJs += ' '.repeat(level) + `${JSON.stringify(_minusculize(key)).slice(1, -1)}` + '(' + value + ')';
} else {
mathJs +=
' '.repeat(level)
+ `${JSON.stringify(_minusculize(key)).slice(1, -1)}`
+ '(' + JSON.stringify(value) + ')';
}
}
let lastKey = Array.from(damonMap.keys())[Array.from(damonMap.keys()).length - 1];
if (k != lastKey) {
mathJs += ",\n";
} else {
mathJs += "\n";
}
}
} else if (Array.isArray(damonMap)) {
for (var i = 0, c = damonMap.length; i < c; i++) {
if (
typeof damonMap[i] === 'object'
&& damonMap[i] !== null
) {
if (Array.isArray(damonMap[i])) {
if (damonMap[i].length > 0) {
if (
damonMap.damonInlineArrays !== undefined
&& damonMap.damonInlineArrays.indexOf(i) > -1
) {
if (damonMap[i] === true) {
mathJs += ' '.repeat(level) + "true";
} else if (damonMap[i] === false) {
mathJs += ' '.repeat(level) + "false";
} else if (damonMap[i] === null) {
mathJs += ' '.repeat(level) + "null";
} else if (
Number.isFinite(damonMap[i])
&& !Number.isNaN(damonMap[i])
) {
mathJs += ' '.repeat(level) + damonMap[i];
} else {
mathJs += ' '.repeat(level) + JSON.stringify(damonMap[i]).slice(1, -1);
}
} else {
mathJs += ' '.repeat(level) + `(\n`;
_recurse(damonMap[i], level + 1);
mathJs += ' '.repeat(level) + `)`;
}
} else {
mathJs += ' '.repeat(level) + `()`;
}
} else {
if (Array.from(damonMap[i].keys()).length > 0) {
mathJs += ' '.repeat(level) + `(\n`;
_recurse(damonMap[i], level + 1);
mathJs += ' '.repeat(level) + `)`;
} else {
mathJs += ' '.repeat(level) + `()`;
}
}
} else {
if (damonMap[i] === true) {
mathJs += ' '.repeat(level) + "true";
} else if (damonMap[i] === false) {
mathJs += ' '.repeat(level) + "false";
} else if (damonMap[i] === null) {
mathJs += ' '.repeat(level) + "null";
} else if (
Number.isFinite(damonMap[i])
&& !Number.isNaN(damonMap[i])
) {
mathJs += ' '.repeat(level) + damonMap[i];
} else {
mathJs += ' '.repeat(level) + JSON.stringify(damonMap[i]).slice(1, -1);
}
}
if (i != c - 1) {
mathJs += ",\n";
} else {
mathJs += "\n";
}
}
}
}
}
/**
* @param {damonValue} firstMap
* @param {damonValue} secondMap
*/
_mapsDiff(firstMap, secondMap) {
let $ = this;
// Parsing check
try {
$.damon.mapToJSON(firstMap);
$.damon.mapToJSON(secondMap);
} catch (error) {
throw new Error("Provided map value doesn't passes JSON.parse()");
}
if (
typeof firstMap !== typeof secondMap
|| (
(
typeof firstMap === 'object'
&& firstMap !== null
&& !Array.isArray(firstMap)
&& firstMap instanceof Map
&& firstMap.constructor === Map
) && (
secondMap == null
|| Array.isArray(secondMap)
|| !(secondMap instanceof Map)
|| secondMap.constructor !== Map
)
)
) {
// fully red render
throw new Error("Different root types.");
}
var diffMap;
if (
typeof firstMap === 'object'
&& firstMap !== null
&& !Array.isArray(firstMap)
&& firstMap instanceof Map
&& firstMap.constructor === Map
) {
diffMap = new Map();
_walkAndDiff(firstMap);
return diffMap;
// # Red-Green-Yellow diffMap
// - Checks key, value-structure and position: "green" && recurse
// - Fails key or value-structure: red
// - Fails position: yellow
// - Check value structure: green
// # Rendering
// - Render from Red-Green-Yellow
// - optimization: lookahead and group
// Intersecti