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