utilities/index.js

200 lines
4.4 KiB
JavaScript
Raw Normal View History

2020-03-04 12:13:28 +01:00
/*
* Copyright (C) Sapphirecode - All Rights Reserved
* This file is part of utilities which is released under MIT.
2020-03-25 17:01:22 +01:00
* See file 'LICENSE' for full license details.
* Created by Timo Hocker <timo@scode.ovh>, May 2020
2020-03-04 12:13:28 +01:00
*/
'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;
}
2020-03-10 10:46:12 +01:00
/**
* 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));
}
2020-03-30 11:00:52 +02:00
/**
* run a regular expression and callback for every result
*
2020-03-30 11:01:51 +02:00
* @param {any} regex regular expression
* @param {any} data data to run on
* @param {any} func function to execute
2020-03-30 11:00:52 +02:00
*/
function run_regex (regex, data, func) {
2020-03-30 11:21:05 +02:00
if (!regex.global) {
const result = regex.exec (data);
if (result)
func (result);
return;
}
2020-03-30 11:00:52 +02:00
let res = regex.exec (data);
while (res) {
func (res);
res = regex.exec (data);
}
}
2020-04-27 12:40:54 +02:00
/**
* 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));
}
2020-03-30 11:00:52 +02:00
2020-06-30 11:20:09 +02:00
function get_element_field (element, carried_data, field) {
if (typeof carried_data[field] !== 'undefined')
return carried_data[field];
return element[field];
}
function check_filter (filter, e, carried_data) {
2020-07-03 14:36:39 +02:00
if (typeof filter.function !== 'undefined')
return filter.function ({ ...e, ...carried_data });
2020-06-30 10:00:36 +02:00
const search_str = Array.isArray (filter.field)
2020-06-30 11:20:09 +02:00
? filter.field.map ((f) => get_element_field (e, carried_data, f))
2020-06-29 14:23:24 +02:00
.filter ((v) => typeof v !== 'undefined')
.join (' ')
2020-06-30 11:20:09 +02:00
: get_element_field (e, carried_data, filter.field);
2020-06-30 10:00:36 +02:00
return filter.filter.test (search_str);
}
2020-06-30 11:20:09 +02:00
function check_filters (filters, e, carried_data, or = false) {
2020-06-30 10:00:36 +02:00
for (const filter of filters) {
let res = false;
if (Array.isArray (filter.or))
2020-06-30 11:20:09 +02:00
res = check_filters (filter.or, e, carried_data, true);
2020-06-30 10:00:36 +02:00
else
2020-06-30 11:20:09 +02:00
res = check_filter (filter, e, carried_data);
2020-06-30 10:00:36 +02:00
if (or && res)
return true;
if (!res && !or)
return false;
}
return !or;
2020-06-29 14:23:24 +02:00
}
2020-06-30 10:00:36 +02:00
/**
* @typedef Filter
* @type {object}
* @property {string|string[]} field - fields to apply filter on
* @property {RegExp} filter - filter
2020-06-30 10:13:17 +02:00
*/
2020-07-03 14:42:37 +02:00
/**
* @typedef FilterFunction
* @type {object}
* @property {function} function - function to test element for match
*/
2020-06-30 10:13:17 +02:00
/**
* @typedef FilterOrGroup
* @type {object}
2020-07-03 14:42:37 +02:00
* @property {FilterType[]} or - create an OR group of filters
*/
/**
* @typedef FilterType
* @type {Filter|FilterFunction|FilterOrGroup}
2020-06-30 10:00:36 +02:00
*/
2020-06-08 14:44:09 +02:00
/**
* filter nested objects
*
2020-06-30 11:20:09 +02:00
* @param {Array<object>} input object to filter
2020-07-03 14:42:37 +02:00
* @param {FilterType[]} filters filters
2020-06-30 11:20:09 +02:00
* @param {string[]} carry carry data to children to match
* @param {object} carried_data internal: carried data
2020-06-08 14:44:09 +02:00
* @returns {Array<object>} filtered data
*/
2020-06-30 11:20:09 +02:00
function recursive_filter (
input,
filters,
children_key = 'children',
carry = [],
carried_data = {}
) {
2020-06-29 11:33:33 +02:00
const data = [ ...input ];
2020-06-08 14:44:09 +02:00
const filtered = [];
2020-06-30 11:20:09 +02:00
for (const c of carry) {
if (typeof carried_data[c] !== 'string')
carried_data[c] = '';
}
2020-06-29 11:33:33 +02:00
for (let i = 0; i < data.length; i++) {
const e = { ...data[i] };
data[i] = e;
2020-06-30 11:20:09 +02:00
const sub_carry = { ...carried_data };
for (const c of carry) {
if (typeof e[c] !== 'undefined')
sub_carry[c] += `${sub_carry[c].length > 0 ? ' ' : ''}${e[c]}`;
}
if (check_filters (filters, e, sub_carry)) {
2020-06-08 14:44:09 +02:00
filtered.push (e);
}
else {
if (typeof e[children_key] === 'undefined')
2020-06-08 14:44:09 +02:00
continue;
e[children_key] = recursive_filter (
e[children_key],
filters,
2020-06-30 11:20:09 +02:00
children_key,
carry,
sub_carry
2020-06-08 14:44:09 +02:00
);
if (e[children_key].length > 0)
filtered.push (e);
}
}
return filtered;
}
2020-03-04 12:13:28 +01:00
module.exports = {
truncate_decimal,
2020-03-10 10:46:12 +01:00
try_parse_json,
2020-03-30 11:00:52 +02:00
copy_object,
2020-04-27 12:40:54 +02:00
run_regex,
2020-06-08 14:44:09 +02:00
is_nil,
recursive_filter
2020-03-04 12:13:28 +01:00
};