UNPKG

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