Compare commits
	
		
			2 Commits
		
	
	
		
			1162664263
			...
			291f011226
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					291f011226 | ||
| 
						 | 
					bbcd2050e7 | 
							
								
								
									
										121
									
								
								filter.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								filter.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,121 @@
 | 
			
		||||
/*
 | 
			
		||||
 * 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 <timo@scode.ovh>, 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<object>} 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<object>} 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;
 | 
			
		||||
							
								
								
									
										113
									
								
								index.js
									
									
									
									
									
								
							
							
						
						
									
										113
									
								
								index.js
									
									
									
									
									
								
							@@ -7,6 +7,8 @@
 | 
			
		||||
 | 
			
		||||
'use strict';
 | 
			
		||||
 | 
			
		||||
const recursive_filter = require ('./filter');
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * truncates a floating point number
 | 
			
		||||
 *
 | 
			
		||||
@@ -78,117 +80,6 @@ function is_nil (obj) {
 | 
			
		||||
      || (typeof obj === 'number' && isNaN (obj));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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<object>} 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<object>} 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 = {
 | 
			
		||||
  truncate_decimal,
 | 
			
		||||
  try_parse_json,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "@sapphirecode/utilities",
 | 
			
		||||
  "version": "1.8.7",
 | 
			
		||||
  "version": "1.8.8",
 | 
			
		||||
  "main": "index.js",
 | 
			
		||||
  "author": {
 | 
			
		||||
    "name": "Timo Hocker",
 | 
			
		||||
@@ -36,8 +36,8 @@
 | 
			
		||||
  },
 | 
			
		||||
  "files": [
 | 
			
		||||
    "LICENSE",
 | 
			
		||||
    "index.js",
 | 
			
		||||
    "index.d.ts"
 | 
			
		||||
    "*.js",
 | 
			
		||||
    "*.d.ts"
 | 
			
		||||
  ],
 | 
			
		||||
  "engines": {
 | 
			
		||||
    "node": ">=10"
 | 
			
		||||
 
 | 
			
		||||
@@ -19,5 +19,11 @@ module.exports = {
 | 
			
		||||
  testRunner:        'jasmine',
 | 
			
		||||
  jasmineConfigFile: 'jasmine.json',
 | 
			
		||||
  coverageAnalysis:  'perTest',
 | 
			
		||||
  mutate:            [ 'index.js' ]
 | 
			
		||||
  mutate:            [
 | 
			
		||||
    '**/*.js',
 | 
			
		||||
    '**/*.ts',
 | 
			
		||||
    '!**/test/**/*',
 | 
			
		||||
    '!**/spec/**/*',
 | 
			
		||||
    '!stryker.conf.js'
 | 
			
		||||
  ]
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user