/* * Copyright (C) Sapphirecode - All Rights Reserved * This file is part of utilities which is released under MIT. * See file 'LICENSE' for full license details. * Created by Timo Hocker , May 2020 */ 'use strict'; /** * truncates a floating point number * * @param {number} num number to truncate * @param {number} len length to truncate to * @returns {number} truncated number */ function truncate_decimal (num, len) { return Math.round (num * (10 ** len)) / (10 ** len); } /** * parse json and catch invalid strings * * @param {string} text input * @returns {any} parsed */ function try_parse_json (text) { try { return JSON.parse (text); } catch (e) { // noop } return null; } /** * copy an object to prevent modification to the original * * @param {object} obj object to copy * @returns {object} copy */ function copy_object (obj) { return JSON.parse (JSON.stringify (obj)); } /** * run a regular expression and callback for every result * * @param {any} regex regular expression * @param {any} data data to run on * @param {any} func function to execute */ function run_regex (regex, data, func) { if (!regex.global) { const result = regex.exec (data); if (result) func (result); return; } let res = regex.exec (data); while (res) { func (res); res = regex.exec (data); } } /** * check if an object is either undefined, null or NaN * * @param {any} obj object to check * @returns {boolean} true if nil */ function is_nil (obj) { return typeof obj === 'undefined' || obj === null || (typeof obj === 'number' && isNaN (obj)); } function to_search_string (element, field) { return Array.isArray (field) ? field.map ((f) => element[f]) .filter ((v) => typeof v !== 'undefined') .join (' ') : element[field]; } /** * filter nested objects * * @param {Array} input * @param {Array<{field: string|string[], filter: RegExp}>} filters * @param {string} children_key field where children are stored * @returns {Array} filtered data */ function recursive_filter (input, filters, children_key = 'children') { const data = [ ...input ]; const filtered = []; for (let i = 0; i < data.length; i++) { const e = { ...data[i] }; data[i] = e; let match = true; for (const filter of filters) { const search_str = to_search_string (e, filter.field); if (!filter.filter.test (search_str)) { match = false; break; } } if (match) { filtered.push (e); } else { if (typeof e[children_key] === 'undefined') continue; e[children_key] = recursive_filter ( e[children_key], filters, children_key ); if (e[children_key].length > 0) filtered.push (e); } } return filtered; } /** * create a search index on an object to speed up the recursive_filter function * * @param {Array} input input object * @param {string|string[]} field field or fields to index * @param {string} children_key field where children are stored * @param {string} index_field field to save index in */ function filter_index ( input, field, children_key = 'children', index_field = 'search_index' ) { for (const e of input) { let search_str = ''; if (Array.isArray (e[children_key])) { filter_index (e[children_key], field, children_key, index_field); search_str += e[children_key] .map ((v) => v[index_field]) .filter ((v) => typeof v !== 'undefined') .join (' '); } search_str += to_search_string (e, field); e[index_field] = search_str; } } module.exports = { truncate_decimal, try_parse_json, copy_object, run_regex, is_nil, recursive_filter, filter_index };