1 | # starscream
|
2 | Asynchronous JSON transformation
|
3 |
|
4 | ![starscream](https://upload.wikimedia.org/wikipedia/en/2/2d/Armada_Starscream.PNG)
|
5 |
|
6 | ## Installation
|
7 |
|
8 | ```
|
9 | npm install starscream --save
|
10 | ```
|
11 |
|
12 | ## Usage
|
13 |
|
14 | ```js
|
15 | var starscream = require('starscream')
|
16 | var original = {
|
17 | source: {
|
18 | path: "robots in disguise"
|
19 | }
|
20 | }
|
21 | var options = {
|
22 | mapping: [{
|
23 | reader: {
|
24 | type: "jsonPointer",
|
25 | path: "/source/path"
|
26 | },
|
27 | transformer: {
|
28 | type: "uppercase"
|
29 | },
|
30 | writer: {
|
31 | type: "jsonPointer",
|
32 | path: "destination/path"
|
33 | }
|
34 | }]
|
35 | }
|
36 | starscream(options, original, function(err, transformed) {
|
37 | assert.equal(transformed.destination.path, 'ROBOTS IN DISGUISE')
|
38 | })
|
39 | ```
|
40 |
|
41 | #### Mapping Shorthand (Array Based)
|
42 |
|
43 | ```js
|
44 | var options = {
|
45 | mapping: [
|
46 | "/source/path/a",
|
47 | "/source/path/b",
|
48 | ]
|
49 | }
|
50 | ```
|
51 | Reads the value at ```/source/path/a``` in the original document, and writes it to ```/source/path/a``` in the transformed document
|
52 |
|
53 |
|
54 | ```js
|
55 | var options = {
|
56 | mapping: [{
|
57 | "/source/path/a": "/destination/path/a"
|
58 | }]
|
59 | }
|
60 | ```
|
61 | Reads the value at ```/source/path/a``` in the original document, and writes it to ```/destination/path/a``` in the transformed document
|
62 |
|
63 |
|
64 | ```js
|
65 | var options = {
|
66 | mapping: [{
|
67 | reader: "/source/path/a",
|
68 | transformer: "uppercase",
|
69 | writer: "/destination/path/a"
|
70 | }, {
|
71 | reader: "/source/path/b",
|
72 | transformer: "uppercase",
|
73 | writer: "/destination/path/b"
|
74 | }
|
75 | }]
|
76 | ```
|
77 | Reads the value at ```/source/path/a``` in the original document, transforms it to uppercase, and writes it to ```/destination/path/a``` in the transformed document
|
78 |
|
79 |
|
80 | #### Mapping Shorthand (Object Based)
|
81 |
|
82 | ```js
|
83 | var options = {
|
84 | mapping: {
|
85 | "/source/path/a": "/destination/path/a",
|
86 | "/source/path/b": "/destination/path/b"
|
87 | }
|
88 | }
|
89 | ```
|
90 | Reads the value at ```/source/path/a``` in the original document, and writes it to ```/destination/path/a``` in the transformed document
|
91 |
|
92 | ```js
|
93 | var options = {
|
94 | mapping: {
|
95 | "/source/path/a": {
|
96 | transformer: "uppercase"
|
97 | },
|
98 | "/source/path/b": {
|
99 | transformer: "lowercase"
|
100 | }
|
101 | }
|
102 | }
|
103 | ```
|
104 | Reads the value at ```/source/path/a``` in the original document, transforms it to uppercase, and writes it to ```/source/path/a``` in the transformed document
|
105 |
|
106 | ```js
|
107 | var options = {
|
108 | mapping: {
|
109 | "/source/path/a": {
|
110 | transformer: "uppercase",
|
111 | writer: "/destination/path/a"
|
112 | },
|
113 | "/source/path/b": {
|
114 | transformer: "lowercase",
|
115 | writer: "/destination/path/b"
|
116 | },
|
117 | }
|
118 | }
|
119 | ```
|
120 | Reads the value at ```/source/path/a``` in the original document, transforms it to uppercase, and writes it to ```/destination/path/b``` in the transformed document
|
121 |
|
122 |
|
123 | ## Using multiple sources for a single mapping
|
124 | ```js
|
125 | var options = {
|
126 | mapping: [{
|
127 | reader: {
|
128 | type: "serial",
|
129 | reader": [{
|
130 | type: "jsonPointer",
|
131 | path: "/source/path/a"
|
132 | }, {
|
133 | type: "jsonPointer",
|
134 | path: "/source/path/b"
|
135 | }],
|
136 | },
|
137 | writer": {
|
138 | type: "jsonPointer",
|
139 | path: "/destination/path"
|
140 | }
|
141 | }]
|
142 | }
|
143 | ```
|
144 | Reads the values at ```/source/path/a``` and ```/source/path/b``` in the original document, and inserts them as an array into the transformed document at '/desination/path'
|
145 |
|
146 | #### Shorthand
|
147 | ```js
|
148 | var options = {
|
149 | mapping: [{
|
150 | reade": {
|
151 | type: "serial",
|
152 | reader: [
|
153 | "/source/path/a",
|
154 | "/source/path/b"
|
155 | }]
|
156 | },
|
157 | writer: {
|
158 | type: "jsonPointer",
|
159 | path: "/destination/path"
|
160 | }
|
161 | }]
|
162 | }
|
163 | ```
|
164 | The same shorthand rules apply
|
165 |
|
166 | ## Aggregating Transformers
|
167 | ```js
|
168 | var options = {
|
169 | mapping: [{
|
170 | reader: {
|
171 | type: "serial",
|
172 | readers: [{
|
173 | type: "jsonPointer",
|
174 | path: "/source/path/a"
|
175 | }, {
|
176 | type: "jsonPointer",
|
177 | path: "/source/path/b"
|
178 | }],
|
179 | },
|
180 | transformer: {
|
181 | type: "concatenate",
|
182 | separator: "_"
|
183 | },
|
184 | writer: {
|
185 | type: "jsonPointer",
|
186 | path: "/destination/path"
|
187 | }
|
188 | }]
|
189 | }
|
190 | ```
|
191 | Reads the values at ```/source/path/a``` and ```/source/path/b``` from the original document, combines them with a underscore (```_```) and writes them to ```/destination/path``` in the transformed document
|
192 |
|
193 | ## Chaining Transformers
|
194 | ```js
|
195 | var options = {
|
196 | mapping: [{
|
197 | reader: "/source/path"
|
198 | transformer: {
|
199 | type: "serial",
|
200 | transformers: [{
|
201 | type: "uppercase"
|
202 | }, {
|
203 | type: "prefix",
|
204 | text: "foo-"
|
205 | }]
|
206 | },
|
207 | writer": {
|
208 | type: "jsonPointer",
|
209 | path: "/destination/path"
|
210 | }
|
211 | }]
|
212 | }
|
213 | ```
|
214 | Reads the values at ```/source/path```in the original document, transforms it to uppercase, adds the ```foo-``` prefix and writes it to ```/destination/path``` in the transformed document
|
215 |
|
216 |
|
217 | ## Iteration
|
218 |
|
219 | You can iterate over arrays using the ```mapSeries``` transformer
|
220 |
|
221 | ```js
|
222 | [
|
223 | {
|
224 | "reader": "/source/path",
|
225 | "transformer": {
|
226 | "type": "mapSeries",
|
227 | "transformer": "uppercase"
|
228 | },
|
229 | "writer": "/destination/path"
|
230 | }
|
231 | ]
|
232 | ```
|
233 | Reads the array at ```/source/path``` and transforms each element to upper case before writing the array to ```/destination/path```
|
234 |
|
235 | ## Out of the box readers
|
236 |
|
237 | #### jsonPointer (default)
|
238 |
|
239 | ```js
|
240 | var options = {
|
241 | mapping: [{
|
242 | reader: {
|
243 | "path": "/source/path"
|
244 | "ignoreMissing": "true"
|
245 | }
|
246 | writer: "/destination/path"
|
247 | }]
|
248 | }
|
249 | ```
|
250 | Reads the value at ```/source/path```. If the path is missing and ignoreMissing is false (the defult) return undefined instead of erroring
|
251 |
|
252 |
|
253 | #### property
|
254 |
|
255 | ```js
|
256 | var options = {
|
257 | mapping: [{
|
258 | reader: {
|
259 | "type": "property",
|
260 | "path": "source.path",
|
261 | "ignoreMissing": "true"
|
262 | }
|
263 | writer: "/destination/path"
|
264 | }]
|
265 | }
|
266 | ```
|
267 | Reads the value at ```source.path```. If the path is missing and ignoreMissing is false (the defult) return undefined instead of erroring
|
268 |
|
269 | ## Writers of the box readers
|
270 |
|
271 | #### jsonPointer
|
272 |
|
273 | ```js
|
274 | var options = {
|
275 | mapping: [{
|
276 | reader: {
|
277 | "/source/path"
|
278 | writer: {
|
279 | "path": "/destination/path",
|
280 | "ignoreMissing": "true"
|
281 | }
|
282 | }]
|
283 | }
|
284 | ```
|
285 | Writes the value to ```/destination/path```. If the value is undefined and ignoreMissing is true (the default) will not write anything, otherwise writes the value as undefined
|
286 |
|
287 | #### property
|
288 |
|
289 | ```js
|
290 | var options = {
|
291 | mapping: [{
|
292 | reader: "/source/path"
|
293 | writer: {
|
294 | "type": "property",
|
295 | "path": "destination.path",
|
296 | "ignoreMissing": "true"
|
297 | }
|
298 | }]
|
299 | }
|
300 | ```
|
301 | Writes the value to ```/destination/path```. If the value is undefined and ignoreMissing is true (the default) will not write anything, otherwise writes the value as undefined
|
302 |
|
303 | ## Out of the box transformers
|
304 |
|
305 | #### mapSeries
|
306 |
|
307 | ```js
|
308 | var options = {
|
309 | mapping: [{
|
310 | reader: "/source/path"
|
311 | transformer: {
|
312 | "type": "mapSeries",
|
313 | "transformer": "uppercase"
|
314 | }
|
315 | "toggle",
|
316 | writer: "/destination/path"
|
317 | }]
|
318 | }
|
319 | ```
|
320 |
|
321 | #### toggle
|
322 |
|
323 | ```js
|
324 | var options = {
|
325 | mapping: [{
|
326 | reader: "/source/path"
|
327 | transformer: "toggle",
|
328 | writer: "/destination/path"
|
329 | }]
|
330 | }
|
331 | ```
|
332 |
|
333 | #### uppercase
|
334 |
|
335 | ```js
|
336 | var options = {
|
337 | mapping: [{
|
338 | reader: "/source/path"
|
339 | transformer: "uppercase",
|
340 | writer: "/destination/path"
|
341 | }]
|
342 | }
|
343 | ```
|
344 |
|
345 | #### lowercase
|
346 | ```js
|
347 | var options = {
|
348 | mapping: [{
|
349 | reader: "/source/path"
|
350 | transformer: "lowercase",
|
351 | writer: "/destination/path"
|
352 | }]
|
353 | }
|
354 | ```
|
355 |
|
356 | #### mutualExclusion
|
357 | ```js
|
358 | var options = {
|
359 | mapping: [{
|
360 | readers: [
|
361 | "/source/path/a",
|
362 | "/source/path/b"
|
363 | ],
|
364 | transformer: "mutualExclusion",
|
365 | writer: "/destination/path"
|
366 | }]
|
367 | }
|
368 | ```
|
369 | Writes either ```/source/path/a``` or ```/source/path/b``` (with preference for a)
|
370 |
|
371 | #### conditional
|
372 | ```js
|
373 | var options = {
|
374 | mapping: [{
|
375 | readers: [
|
376 | "/source/path/a",
|
377 | "/source/path/b"
|
378 | ],
|
379 | transformer: "mutualExclusion",
|
380 | writer: "/destination/path"
|
381 | }]
|
382 | }
|
383 | ```
|
384 | Writes ```/source/path/b``` if ```/source/path/a``` is truthy
|
385 |
|
386 | #### guard
|
387 | ```js
|
388 | var options = {
|
389 | mapping: [{
|
390 | readers: [
|
391 | "/source/path/a",
|
392 | "/source/path/b"
|
393 | ],
|
394 | transformer: "mutualExclusion",
|
395 | writer: "/destination/path"
|
396 | }]
|
397 | }
|
398 | ```
|
399 | Writes ```/source/path/b``` if ```/source/path/a``` is falsey
|
400 |
|
401 | ## Custom Transformers
|
402 | ```js
|
403 | var options = {
|
404 | mapping: [{
|
405 | reader: "/source/path"
|
406 | transformer: {
|
407 | type: "dbLookup",
|
408 | collection: "refdata"
|
409 | },
|
410 | writer: {
|
411 | type: "jsonPointer",
|
412 | path: "/destination/path"
|
413 | }
|
414 | }],
|
415 | transformers: {
|
416 | dbLookup: function(config, value, cb) {
|
417 | db.collections(config.collection).findOne({ code: value }, cb)
|
418 | })
|
419 | }
|
420 | }
|
421 | ```
|
422 | Reads the value at ```/source/path``` in the original document, and cross references it an item of refdata. The same mechanism can be used for writing your own readers and writers too.
|
423 |
|
\ | No newline at end of file |