/* * 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 , November 2020 */ 'use strict'; 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) { if (typeof filter.function !== 'undefined') return filter.function ({ ...e, ...carried_data }); const search_str = Array.isArray (filter.field) ? filter.field.map ((f) => get_element_field (e, carried_data, f)) .filter ((v) => typeof v !== 'undefined') .join (' ') : get_element_field (e, carried_data, filter.field); return filter.filter.test (search_str); } function check_filters (filters, e, carried_data, or = false) { for (const filter of filters) { let res = false; if (Array.isArray (filter.or)) res = check_filters (filter.or, e, carried_data, true); else res = check_filter (filter, e, carried_data); if (or && res) return true; if (!res && !or) return false; } return !or; } /** * @typedef Filter * @type {object} * @property {string|string[]} field - fields to apply filter on * @property {RegExp} filter - filter */ /** * @typedef FilterFunction * @type {object} * @property {function} function - function to test element for match */ /** * @typedef FilterOrGroup * @type {object} * @property {FilterType[]} or - create an OR group of filters */ /** * @typedef FilterType * @type {Filter|FilterFunction|FilterOrGroup} */ /** * filter nested objects * * @param {Array} input object to filter * @param {FilterType[]} filters filters * @param {string[]} carry carry data to children to match * @param {object} carried_data internal: carried data * @returns {Array} filtered data */ function recursive_filter ( input, filters, children_key = 'children', carry = [], carried_data = {} ) { const data = [ ...input ]; const filtered = []; for (const c of carry) { if (typeof carried_data[c] !== 'string') carried_data[c] = ''; } for (let i = 0; i < data.length; i++) { const e = { ...data[i] }; data[i] = e; 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)) { filtered.push (e); } else { if (typeof e[children_key] === 'undefined') continue; e[children_key] = recursive_filter ( e[children_key], filters, children_key, carry, sub_carry ); if (e[children_key].length > 0) filtered.push (e); } } return filtered; } module.exports = recursive_filter;