From 092e84d8bb0b09a3e9920d57dfe1bc6fd90c1833 Mon Sep 17 00:00:00 2001 From: Timo Hocker Date: Tue, 30 Jun 2020 11:20:09 +0200 Subject: [PATCH] carry values between filter runs --- Jenkinsfile | 2 +- README.md | 38 +++++++++++++++++++++++++++++++++++--- index.js | 49 ++++++++++++++++++++++++++++++++++++++----------- test/index.js | 27 +++++++++++++++++++++++++++ 4 files changed, 101 insertions(+), 15 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 4f122e4..8c0fcda 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -5,7 +5,7 @@ pipeline { VERSION = VersionNumber([ versionNumberString: '${BUILDS_ALL_TIME}', - versionPrefix: '1.6.', + versionPrefix: '1.7.', worstResultForIncrement: 'SUCCESS' ]) } diff --git a/README.md b/README.md index 3a0adc4..bbdf448 100644 --- a/README.md +++ b/README.md @@ -118,9 +118,9 @@ const result = util.recursive_filter( [ { filter: /foo bar/iu, - field: ['name', 'name_2'] // fields will be joined with a space in between + field: ['name', 'name_2'], // fields will be joined with a space in between // {name: 'foo', name_2: 'bar'} will become 'foo bar' - } + }, ] ); ``` @@ -134,7 +134,7 @@ const result = util.recursive_filter( { filter: /foo bar/iu, field: 'name' - }, + }, { or: [ { filter: /foo/u, field: 'bar' }, @@ -145,6 +145,38 @@ const result = util.recursive_filter( ); ``` +field values can be carried to filter runs on children to filter over the entire tree instead of just one element + +```js + const to_filter = [ + { + name: 'foo', + children: [ + { name: 'bar' }, + { name: 'baz' }, + { foo: 'bar' } + ] + } + ]; + + const res = util.recursive_filter ( + to_filter, + [ { field: 'name', filter: /foo bar/ui } ], // values will be separaed by a space + 'children', + [ 'name' ] // specify which fields should be carried + // the filters will receive the carried values instead of the plain fields + ); + + /* result: + + [ + { + name: 'foo', + children: [ { name: 'bar' } ] + } + ] + */ +``` ## License diff --git a/index.js b/index.js index 98b6597..685d433 100644 --- a/index.js +++ b/index.js @@ -78,23 +78,29 @@ function is_nil (obj) { || (typeof obj === 'number' && isNaN (obj)); } -function check_filter (filter, e) { +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) { const search_str = Array.isArray (filter.field) - ? filter.field.map ((f) => e[f]) + ? filter.field.map ((f) => get_element_field (e, carried_data, f)) .filter ((v) => typeof v !== 'undefined') .join (' ') - : e[filter.field]; + : get_element_field (e, carried_data, filter.field); return filter.filter.test (search_str); } -function check_filters (filters, e, or = false) { +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, true); + res = check_filters (filter.or, e, carried_data, true); else - res = check_filter (filter, e); + res = check_filter (filter, e, carried_data); if (or && res) return true; @@ -120,17 +126,36 @@ function check_filters (filters, e, or = false) { /** * filter nested objects * - * @param {Array} input - * @param {(Filter|FilterOrGroup)[]} filters + * @param {Array} input object to filter + * @param {(Filter|FilterOrGroup)[]} 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') { +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; - if (check_filters (filters, 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 { @@ -139,7 +164,9 @@ function recursive_filter (input, filters, children_key = 'children') { e[children_key] = recursive_filter ( e[children_key], filters, - children_key + children_key, + carry, + sub_carry ); if (e[children_key].length > 0) filtered.push (e); diff --git a/test/index.js b/test/index.js index 5cb28e4..5614d7c 100644 --- a/test/index.js +++ b/test/index.js @@ -225,3 +225,30 @@ test ('recursive filter with or group', (t) => { t.deepEqual (res, to_filter.slice (0, 2)); }); + +test ('recursive filter carry field', (t) => { + const to_filter = [ + { + name: 'foo', + children: [ + { name: 'bar' }, + { name: 'baz' }, + { foo: 'bar' } + ] + } + ]; + + const res = util.recursive_filter ( + to_filter, + [ { field: 'name', filter: /foo bar/ui } ], + 'children', + [ 'name' ] + ); + + t.deepEqual (res, [ + { + name: 'foo', + children: [ { name: 'bar' } ] + } + ]); +});