UNPKG

9.48 kBMarkdownView Raw
1[![Build Status](https://travis-ci.org/BlueT/obj-filter.svg?branch=master)](https://travis-ci.org/BlueT/obj-filter) [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fbluet%2Fobj-filter.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fbluet%2Fobj-filter?ref=badge_shield)
2
3[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=obj-filter&metric=alert_status)](https://sonarcloud.io/dashboard?id=obj-filter)
4[![Open Source Helpers](https://www.codetriage.com/bluet/obj-filter/badges/users.svg)](https://www.codetriage.com/bluet/obj-filter)
5[![npm version](https://img.shields.io/npm/v/obj-filter.svg)](https://www.npmjs.org/package/obj-filter)
6[![install size](https://packagephobia.now.sh/badge?p=obj-filter)](https://packagephobia.now.sh/result?p=obj-filter)
7[![npm downloads](https://img.shields.io/npm/dm/obj-filter.svg)](http://npm-stat.com/charts.html?package=obj-filter)
8[![GitHub license](https://img.shields.io/github/license/BlueT/obj-filter.svg)](https://github.com/BlueT/obj-filter/blob/master/LICENSE)
9
10# obj-filter - JavaScript Object Filter / Merger.
11
12JavaScript Object Filter. **Deep** filtering key/content *recursively*.
13Support **type checking**, **wildcard**, **nested**, and **filter function** in *template*.
14
15## INSTALL
16
17`npm i obj-filter`
18
19Or find help from:
20- https://www.npmjs.com/package/obj-filter
21- https://github.com/BlueT/obj-filter
22
23## SYNOPSIS
24
25~~~~ js
26"use strict";
27
28const {filter, merge, exist, ArrayIter} = require('obj-filter');
29
30const template = {
31 "runtime": {
32 "connectionState": undefined, // excluded
33 "powerState": function (args) {return "HELLO WORLD " + args}, // pass into the checker function
34 "bootTime": "my boot time", // included
35 "paused": false,
36 "snapshotInBackground": 1111111,
37 "numbers": ArrayIter(filter, Number), // value of "numbers" must be an array, and will check all elements in the array
38 },
39 "running": Boolean
40};
41
42let clean_data = filter( template, fetchData() );
43let updated_data = filter.merge( clean_data, newUpdates() );
44let clean_full_data = filter.exist( template, fetchData() );
45~~~~
46
47## Template Object
48According to the **Template Object structure**, `obj-filter` supports the following types of value with different behaviors to build the result object.
49
50### undefined
51If the *value* of the key is `undefined`, the key will be **filtered** (skipped) and will not included in result object.
52
53### object
54If the *value* of the key is an `object`, `obj-filter` will _dive into it and check the **deeper** level of keys_.
55
56### function
57If the *value* of the key is an `function`, `obj-filter` will _pass the **value** of the same key in **input data** to the **function**_, and includes it's returned data in result.
58So it's your call to customize how you would like to handle, define what you want to do with the input data. Be sure to **return something** from your function.
59
60- If return `undefined`, the key will be **filtered** (skipped).
61- If return anything else, the key will be **included**.
62
63### DataTypes / Constructors
64`String`, `Number`, `Boolean`, `Array`, `Symbol`, `Map`, `Set`, `WeakMap`, `WeakSet`, `Object`, `Function` in template will do type checking on target object.
65
66Success if type matches and fails if they don't.
67
68### Anything else (string, array, number, etc)
69The value of the key will be **included**.
70
71### onException callback function
72You can pass an additional `onException` callback function into `filter()`, `filter.merge()`, and `filter.exist()` to handle exceptions.
73
74`onException(template, input, error_msg)` will be called when data expected but type mismatch or undefined.
75
76~~~~ js
77filter(template, data, (tpl, obj, err) => { console.dir({tpl, obj, err}); return undefined; });
78~~~~
79
80
81## ArrayIter Check Array Elements
82
83If you want to check `values of array`, use `ArrayIter`. It makes sure that value must be an Array and checks all elements in the array.
84
85The first two arguments are required:
86- (required) filter / merge / exist
87- (required) template
88- (optional) option
89 - min: an Integer, default `0`. indicates at least how many elements must be valid. If the result array contains elements fewer than that number, the whole result will be `undefined`.
90 - onException: a Function, will be called when exception occurred.
91
92~~~~ js
93const template = {
94 "a1": ArrayIter(filter, {
95 "a": String,
96 "a11": ArrayIter(
97 exist,
98 Number,
99 {"onException": () => undefined}
100 ),
101 "a12": ArrayIter(merge, {
102 "a121": filter.ArrayIter(filter, Number, {"min": 3})
103 }),
104 }),
105 "a2": ArrayIter(filter, Number)
106};
107~~~~
108
109
110## Default Function
111
112### Keep only wanted data
113
114When fetching data through API, sometimes the returned data could be Huge. You need many of them, but there are also too many trash included in returned data.
115Copying with `result[xxx] = input[xxx];` each by each, line by line, is a hell.
116Now you can copy one returned data structure (in JSON) to your favorite text editor, delete all unwanted lines, paste it back to your code, and use it as template.
117
118~~~~ js
119"use strict";
120
121var filter = require('obj-filter');
122
123var template = {
124 "runtime": {
125 "connectionState": undefined, // In Template, when the value is undefined, the key will be ignored.
126 "powerState": function (args) {return "HELLO WORLD " + args}, // pass data into your function, and use it as result value
127 "bootTime": "my boot time", // The string is just for your own note. Will keep whatever input is in result.
128 "paused": false, // Will keep whatever input is in result.
129 "snapshotInBackground": 1111111 // Will keep whatever input is in result.
130 }
131};
132
133var data = function_or_somewhere();
134
135// Assume:
136// var data = {
137// "vm": {
138// "type": "VirtualMachine"
139// },
140// "runtime": {
141// "device": 9999,
142// "connectionState": "connected",
143// "powerState": "poweredOn",
144// "bootTime": "2017-04-20T13:56:19.377Z",
145// "paused": false,
146// "snapshotInBackground": true
147// }
148//};
149
150
151var clean_data = filter(template, data);
152
153// clean_data is:
154{
155 "runtime": {
156 "powerState": "HELLO WORLD poweredOn",
157 "bootTime": "2017-04-20T13:56:19.377Z",
158 "paused": false,
159 "snapshotInBackground": true
160 }
161};
162~~~~
163
164### User Data Checks
165
166Validate user input data in browser (before send to server), or check them at server-side.
167
168~~~~ js
169var template = {
170 email: validateEmail(email), // call function validateEmail and use it's return value as value
171 username: function (username) {
172 if (/^[a-zA-Z_]+$/.test(username)) { // check if username contains only a-z or underscore
173 return username;
174 } else {
175 throw new Error('Invalid username');
176 }
177 },
178 password: "original password" // keep whatever user inputs
179}
180
181save_or_send( filter(template, inputData) );
182~~~~
183
184### Separated template file
185
186You can save template into separated files.
187
188Say _data_template/vmInfo.js_
189
190~~~~ js
191{
192 "runtime": {
193 "connectionState": undefined,
194 "powerState": function (args) {return "HELLO WORLD " + args},
195 "bootTime": "my boot time",
196 "paused": false,
197 "snapshotInBackground": 1111111
198 }
199};
200~~~~
201
202Require it as template
203
204~~~~ js
205var vm_tpl = require('data_template/vmInfo.js');
206
207var vmData = filter(vm_tpl, yourData)
208~~~~
209
210## `merge` Function
211
212### Keep template keys when not provided in input data.
213
214~~~~ js
215"use strict";
216
217var filter = require('obj-filter');
218
219var template = {
220 "runtime": {
221 "connectionState": undefined,
222 "powerState": function (args) {return "HELLO WORLD " + args},
223 "CoffeeTeaOrMe": "Me"
224 }
225};
226
227var newUpdates = fetchChanges();
228
229// Assume:
230// var newUpdates = {
231// "runtime": {
232// "connectionState": "connected",
233// "powerState": "poweredOn"
234// }
235//};
236
237
238var updated_data = filter.merge(template, newUpdates);
239
240// updated_data is:
241{
242 "runtime": {
243 "powerState": "HELLO WORLD poweredOn",
244 "bootTime": "2017-04-20T13:56:19.377Z",
245 "CoffeeTeaOrMe": "Me"
246 }
247};
248~~~~
249
250
251## `exist` Function
252
253### Similar to default `filter`, but All Keys in template must also exists in input data.
254
255~~~~ js
256"use strict";
257
258var filter = require('obj-filter');
259
260var template = {
261 "vm": undefined,
262 "runtime": {
263 "connectionState": undefined,
264 "powerState": function (args) {return "HELLO WORLD " + args},
265 "bootTime": "my boot time",
266 "obj jj": { "kk": "yy" }
267 }
268};
269
270var data = fetch_from_somewhere();
271
272// Assume:
273// var data = {
274// "runtime": {
275// "device": 9999,
276// "connectionState": "connected",
277// "powerState": "poweredOn",
278// "bootTime": 2,
279// "obj jj": { "kk": "zz" }
280// }
281// };
282
283
284var clean_full_data = filter.exist(template, data);
285
286// clean_full_data is:
287{
288 "runtime": {
289 "powerState": "HELLO WORLD poweredOn",
290 "bootTime": 2,
291 "obj jj": { "kk": "zz" }
292 }
293};
294~~~~
295
296## Contribute
297
298PRs welcome!
299If you use/like this module, please don't hesitate to give me a **Star**. I'll be happy whole day!
300
301_Hope this module can save your time, a tree, and a kitten._
302
303
304## License
305[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fbluet%2Fobj-filter.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fbluet%2Fobj-filter?ref=badge_large)
\No newline at end of file