jupyter-ijavascript-utils 1.24.0 → 1.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DOCS.md +2 -0
- package/Dockerfile +1 -1
- package/README.md +2 -0
- package/package.json +1 -1
- package/src/chain.js +251 -29
- package/src/file.js +57 -13
package/DOCS.md
CHANGED
|
@@ -75,6 +75,8 @@ Give it a try here:
|
|
|
75
75
|
|
|
76
76
|
## What's New
|
|
77
77
|
|
|
78
|
+
* 1.26 - Support for file.writeFile and file.writeJSON to append
|
|
79
|
+
* 1.25 - Additional chain methods and documentation
|
|
78
80
|
* 1.24 - format.stripHtmlTags, TableGenerator.offset, chain.chainFlatMap, chain.chainFilter
|
|
79
81
|
* 1.23 - add format.parseNumber and TableGenerator.styleColumn, align group.separateByFields to vega-lite fold transform
|
|
80
82
|
* 1.22 - make chain iJavaScript aware, but still able to work outside of Jupyter
|
package/Dockerfile
CHANGED
package/README.md
CHANGED
|
@@ -55,6 +55,8 @@ This is not intended to be the only way to accomplish many of these tasks, and a
|
|
|
55
55
|
|
|
56
56
|
# What's New
|
|
57
57
|
|
|
58
|
+
* 1.26 - Support for file.writeFile and file.writeJSON to append
|
|
59
|
+
* 1.25 - Additional chain methods and documentation
|
|
58
60
|
* 1.24 - format.stripHtmlTags, TableGenerator.offset, chain.chainFlatMap, chain.chainFilter
|
|
59
61
|
* 1.23 - add format.parseNumber and TableGenerator.styleColumn, align group.separateByFields to vega-lite fold transform
|
|
60
62
|
* 1.22 - make chain iJavaScript aware, but still able to work outside of Jupyter
|
package/package.json
CHANGED
package/src/chain.js
CHANGED
|
@@ -8,17 +8,129 @@
|
|
|
8
8
|
* Very helpful for taking values and then progressively working on them,
|
|
9
9
|
* instead of continually wrapping deeper in method calls.
|
|
10
10
|
*
|
|
11
|
-
* Calling `chain(3)` - gives an object
|
|
11
|
+
* Calling `chain(3)` - gives an object you can then chain calls against:
|
|
12
12
|
*
|
|
13
13
|
* * {@link ChainContainer#close|.close()} - gets the value of the current chain
|
|
14
14
|
* * {@link ChainContainer#chain|.chain(function)} - where it is passed the value, and returns a new Chain with that value.
|
|
15
|
-
* * {@link ChainContainer#chainMap|.chainMap(function)} - where it treats value as an array, and maps function on every item in the array
|
|
16
|
-
* * {@link ChainContainer#chainFlatMap|.chainFlatMap(function)} - where it treats value as an array, and maps function on every item in the array,
|
|
17
|
-
* flattening the results
|
|
18
|
-
* * {@link ChainContainer#chainFilter|.chainFilter(function)} - where it treats the value as an array, and filters values based on the result
|
|
19
|
-
* * {@link ChainContainer#chainReduce|.chainReduce(function, initialValue)} - where it treats value as an array, and reduces the value array
|
|
20
15
|
* * {@link ChainContainer#errorHandler|.errorHandler(fn)} - custom function called if an error is ever thrown
|
|
21
16
|
* * {@link ChainContainer#debug|.debug()} - console.logs the current value, and continues the chain with that value
|
|
17
|
+
*
|
|
18
|
+
* Along with methods that can iterate on each element, assuming the value in the chain is an Array.
|
|
19
|
+
*
|
|
20
|
+
* * {@link ChainContainer#chainMap|.chainMap(function)} - where it calls the `.map` on value, and applies the function on every item in the array,
|
|
21
|
+
* storing the result from the function. <br /> <b>(Useful for changing values without changing the original object))</b>
|
|
22
|
+
* * {@link ChainContainer#chainForEach|.chainForEach(function)} - where calls `.forEach` on value, and applies the function on every item,
|
|
23
|
+
* without storing the result from the function. <br /> <b>(Useful for changing objects in-place)</b>
|
|
24
|
+
* * {@link ChainContainer#chainFlatMap|.chainFlatMap(function)} - where it calls `.flatMap` on value, and applies the function on every item,
|
|
25
|
+
* flattening the results. <br /> <b>(Useful for expanding an array based on values in the array)</b>
|
|
26
|
+
* * {@link ChainContainer#chainFilter|.chainFilter(function)} - where it calls `.filter` on value, using the function on every item,
|
|
27
|
+
* keeping the item in the list if the function returns true.
|
|
28
|
+
* <br /> <b>(Useful for removing items from an array)</b>
|
|
29
|
+
* * {@link ChainContainer#chainReduce|.chainReduce(function, initialValue)} - where it calls `.reduce` on value, and reduces the value
|
|
30
|
+
* to a single result.
|
|
31
|
+
* <br /> <b>(Useful for reducing the array to a single value <br /> - like a concatenated string or sum total)</b>
|
|
32
|
+
*
|
|
33
|
+
* There may be times you want to run side effects, or replace the value entirely. (This isn't common, but may be useful on occasion)
|
|
34
|
+
*
|
|
35
|
+
* * {@link ChainContainer#execute|.execute(function)} - where it calls a function, but doesn't pass on the result.
|
|
36
|
+
* <br /> (This is useful for side-effects, like writing to files)
|
|
37
|
+
* * {@link ChainContainer#replace|.replace(value)} - replaces the value in the chain with a literal value,
|
|
38
|
+
* regardless of the previous value.
|
|
39
|
+
*
|
|
40
|
+
* For example:
|
|
41
|
+
*
|
|
42
|
+
* ```
|
|
43
|
+
* addTwo = (value) => value + 2;
|
|
44
|
+
*
|
|
45
|
+
* //-- we can always get the value
|
|
46
|
+
* utils.chain(3).close(); // 3
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* but this is much easier if we continue to chain it
|
|
50
|
+
*
|
|
51
|
+
* ```
|
|
52
|
+
* addTwo = (value) => value + 2;
|
|
53
|
+
* addTwo(3); // 5
|
|
54
|
+
*
|
|
55
|
+
* utils.chain(3)
|
|
56
|
+
* .chain(addTwo) // (3 + 2)
|
|
57
|
+
* .chain(addTwo) // (5 + 2)
|
|
58
|
+
* .debug() // consoles 7 and passes the value along
|
|
59
|
+
* // define a function inline
|
|
60
|
+
* .chain((value) => value + 3) // (7 + 3)
|
|
61
|
+
* .close()
|
|
62
|
+
*
|
|
63
|
+
* // consoles out value `7`
|
|
64
|
+
* // returns value 10
|
|
65
|
+
* ```
|
|
66
|
+
*
|
|
67
|
+
* Note that we can also map against values in the array
|
|
68
|
+
*
|
|
69
|
+
* ```
|
|
70
|
+
* initializeArray = (size) => Array.from(Array(size)).map((val, index) => index);
|
|
71
|
+
* initializeArray(3); // [0, 1, 2]
|
|
72
|
+
*
|
|
73
|
+
* addTwo = (value) => value + 2;
|
|
74
|
+
* addTwo(3); // 5
|
|
75
|
+
*
|
|
76
|
+
* utils.chain(3)
|
|
77
|
+
* .chain(initializeArray) // [0, 1, 2]
|
|
78
|
+
* .chainMap(addTwo) // [2, 3, 4] or [0 + 2, 1 + 2, 2 + 2]
|
|
79
|
+
* .chainMap(addTwo)
|
|
80
|
+
* .close();
|
|
81
|
+
* // [4, 5, 6]
|
|
82
|
+
* ```
|
|
83
|
+
*
|
|
84
|
+
* Chain to log results while transforming values
|
|
85
|
+
*
|
|
86
|
+
* ```
|
|
87
|
+
* results = [{ userId: 'abc123' }, { userId: 'xyz987' }];
|
|
88
|
+
*
|
|
89
|
+
* activeUsers = chain(results)
|
|
90
|
+
* .chainMap((record) => users.get(record.userId))
|
|
91
|
+
* .chainForEach(record => record.status = 'active')
|
|
92
|
+
* .chain(records => d3.csv.format(records))
|
|
93
|
+
* .execute(records => utils.file.writeFile('./log', d3.csv.format(records)))
|
|
94
|
+
* .close()
|
|
95
|
+
* ```
|
|
96
|
+
*
|
|
97
|
+
* Or even combine with other utility methods
|
|
98
|
+
*
|
|
99
|
+
* ```
|
|
100
|
+
* badStr = 'I%20am%20the%20very%20model%20of%20a%20modern%20Major'
|
|
101
|
+
* + '-General%0AI\'ve%20information%20vegetable%2C%20animal%2C%20'
|
|
102
|
+
* + 'and%20mineral%0AI%20know%20the%20kings%20of%20England%2C%20'
|
|
103
|
+
* + 'and%20I%20quote%20the%20fights%0AHistorical%0AFrom%20Marath'
|
|
104
|
+
* + 'on%20to%20Waterloo%2C%20in%20order%20categorical';
|
|
105
|
+
*
|
|
106
|
+
* chain(badStr)
|
|
107
|
+
* .chain(decodeURIComponent)
|
|
108
|
+
* .chain(v => v.split('\n'))
|
|
109
|
+
* // .debug() // check the values along the way
|
|
110
|
+
* .chainMap(line => ({ line, length: line.length }))
|
|
111
|
+
* .chain(values => utils.table(values).render());
|
|
112
|
+
* ```
|
|
113
|
+
*
|
|
114
|
+
* this can be more legible than the normal way to write this, <br />
|
|
115
|
+
* especially if you need to troubleshoot the value halfway through.
|
|
116
|
+
*
|
|
117
|
+
* ```
|
|
118
|
+
* utils.table(
|
|
119
|
+
* decodeURIComponent(badStr)
|
|
120
|
+
* .split('\n')
|
|
121
|
+
* .map(line => ({ line, length: line.length }))
|
|
122
|
+
* ).render()
|
|
123
|
+
* ```
|
|
124
|
+
*
|
|
125
|
+
* and it renders out a lovely table like this:
|
|
126
|
+
*
|
|
127
|
+
* line |length
|
|
128
|
+
* -- |--
|
|
129
|
+
* I am the very model of a modern Major-General |45
|
|
130
|
+
* I've information vegetable, animal, and mineral |47
|
|
131
|
+
* I know the kings of England, and I quote the fights|51
|
|
132
|
+
* Historical |10
|
|
133
|
+
* From Marathon to Waterloo, in order categorical |47
|
|
22
134
|
*/
|
|
23
135
|
class ChainContainer {
|
|
24
136
|
/**
|
|
@@ -134,7 +246,9 @@ class ChainContainer {
|
|
|
134
246
|
}
|
|
135
247
|
|
|
136
248
|
/**
|
|
137
|
-
* Assuming that value is an array, this
|
|
249
|
+
* Assuming that value is an array, this does a
|
|
250
|
+
* [javascript array.map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map)
|
|
251
|
+
* and applies `fn` to every value in the array.
|
|
138
252
|
*
|
|
139
253
|
* ```
|
|
140
254
|
* initializeArray = (size) => Array.from(Array(size)).map((val, index) => index);
|
|
@@ -152,6 +266,8 @@ class ChainContainer {
|
|
|
152
266
|
* // [4, 5, 6]
|
|
153
267
|
* ```
|
|
154
268
|
*
|
|
269
|
+
* This is in contrast to {@link ChainContainer#chainForEach|chainForEach}
|
|
270
|
+
*
|
|
155
271
|
* @param {Function} fn - applies function under every index of this.value
|
|
156
272
|
* @returns {ChainContainer}
|
|
157
273
|
*/
|
|
@@ -161,6 +277,39 @@ class ChainContainer {
|
|
|
161
277
|
return this.chain((value) => value.map(fn));
|
|
162
278
|
}
|
|
163
279
|
|
|
280
|
+
/**
|
|
281
|
+
* Assuming that value is an array, performs a
|
|
282
|
+
* [javaScript forEach](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach)
|
|
283
|
+
* against the results.
|
|
284
|
+
*
|
|
285
|
+
* This will run the passed function against every element in the result,
|
|
286
|
+
* without replacing the element with the returned value and makes inline editing simpler.
|
|
287
|
+
*
|
|
288
|
+
* ```
|
|
289
|
+
* list = [{ first: 'john', last: 'doe' }, { first: 'jane', last: 'doe' }];
|
|
290
|
+
* utils.chain(list)
|
|
291
|
+
* .mapForEach((entry) => entry.name = `${entry.first} ${entry.last})
|
|
292
|
+
* .close();
|
|
293
|
+
* // [{ first: 'john', last: 'doe', name: 'john doe' }, { first: 'jane', last: 'doe', name: 'jane doe' }]
|
|
294
|
+
* ```
|
|
295
|
+
*
|
|
296
|
+
* This is in contrast to {@link ChainContainer#chainMap|chainMap}, that replaces the element with the value returned.
|
|
297
|
+
* @param {Function(any):any} fn - function to execute on each element
|
|
298
|
+
* @returns {ChainContainer} - chainable container
|
|
299
|
+
*/
|
|
300
|
+
chainForEach(fn) {
|
|
301
|
+
if (!Array.isArray(this.value)
|
|
302
|
+
&& !(this.value instanceof Set)
|
|
303
|
+
&& !(this.value instanceof Map)
|
|
304
|
+
) {
|
|
305
|
+
throw Error(`chainForEach expects an array, but was passed:${this.value}`);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
this.value.forEach(fn);
|
|
309
|
+
|
|
310
|
+
return this;
|
|
311
|
+
}
|
|
312
|
+
|
|
164
313
|
/**
|
|
165
314
|
* Assuming that value is an array, performs a
|
|
166
315
|
* [javaScript flatMap](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flatMap)
|
|
@@ -287,6 +436,28 @@ class ChainContainer {
|
|
|
287
436
|
return this;
|
|
288
437
|
}
|
|
289
438
|
|
|
439
|
+
/**
|
|
440
|
+
* Applies a function against the current value, while not passing the results along the chain.
|
|
441
|
+
*
|
|
442
|
+
* ```
|
|
443
|
+
* results = [{ userId: 'abc123' }, { userId: 'xyz987' }];
|
|
444
|
+
*
|
|
445
|
+
* activeUsers = chain(results)
|
|
446
|
+
* .chainMap((record) => users.get(record.userId))
|
|
447
|
+
* .chainForEach(record => record.status = 'active')
|
|
448
|
+
* .chain(records => d3.csv.format(records))
|
|
449
|
+
* .execute(records => utils.file.writeFile('./log', d3.csv.format(records)))
|
|
450
|
+
* .close()
|
|
451
|
+
* ```
|
|
452
|
+
*
|
|
453
|
+
* @param {Function} fn - function to execute against the current value
|
|
454
|
+
* @returns {ChainContainer}
|
|
455
|
+
*/
|
|
456
|
+
execute(fn) {
|
|
457
|
+
fn(this.value);
|
|
458
|
+
return this;
|
|
459
|
+
}
|
|
460
|
+
|
|
290
461
|
/**
|
|
291
462
|
* Function to call if an error occurs anywhere on the chain.
|
|
292
463
|
*
|
|
@@ -325,6 +496,20 @@ class ChainContainer {
|
|
|
325
496
|
return this;
|
|
326
497
|
}
|
|
327
498
|
|
|
499
|
+
/**
|
|
500
|
+
* Normally, you will want to replace the value in the chain
|
|
501
|
+
* based on the current value.
|
|
502
|
+
*
|
|
503
|
+
* This replaces the value regardless, and is rarely used.
|
|
504
|
+
*
|
|
505
|
+
* @param {any} value - new value in the chain.
|
|
506
|
+
* @returns {ChainContainer}
|
|
507
|
+
*/
|
|
508
|
+
replace(value) {
|
|
509
|
+
this.value = value;
|
|
510
|
+
return this;
|
|
511
|
+
}
|
|
512
|
+
|
|
328
513
|
/**
|
|
329
514
|
* Closes the chain and returns the current value.
|
|
330
515
|
* @returns {any}
|
|
@@ -422,27 +607,42 @@ class ChainContainer {
|
|
|
422
607
|
* Very helpful for taking values and then progressively working on them,
|
|
423
608
|
* instead of continually wrapping deeper in method calls.
|
|
424
609
|
*
|
|
425
|
-
* Calling `chain(3)` - gives an object you can
|
|
610
|
+
* Calling `chain(3)` - gives an object you can then chain calls against:
|
|
426
611
|
*
|
|
427
612
|
* * {@link ChainContainer#close|.close()} - gets the value of the current chain
|
|
428
613
|
* * {@link ChainContainer#chain|.chain(function)} - where it is passed the value, and returns a new Chain with that value.
|
|
429
|
-
* * {@link ChainContainer#chainMap|.chainMap(function)} - where it treats value as an array, and maps function on every item in the array
|
|
430
|
-
* * {@link ChainContainer#chainFlatMap|.chainFlatMap(function)} - where it treats value as an array, and maps function on every item in the array,
|
|
431
|
-
* flattening the results
|
|
432
|
-
* * {@link ChainContainer#chainFilter|.chainFilter(function)} - where it treats the value as an array, and filters values based on the result
|
|
433
|
-
* * {@link ChainContainer#chainReduce|.chainReduce(function, initialValue)} - where it treats value as an array, and reduces the value array
|
|
434
614
|
* * {@link ChainContainer#errorHandler|.errorHandler(fn)} - custom function called if an error is ever thrown
|
|
435
615
|
* * {@link ChainContainer#debug|.debug()} - console.logs the current value, and continues the chain with that value
|
|
436
616
|
*
|
|
617
|
+
* Along with methods that can iterate on each element, assuming the value in the chain is an Array.
|
|
618
|
+
*
|
|
619
|
+
* * {@link ChainContainer#chainMap|.chainMap(function)} - where it calls the `.map` on value, and applies the function on every item in the array,
|
|
620
|
+
* storing the result from the function. <br /> <b>(Useful for changing values without changing the original object))</b>
|
|
621
|
+
* * {@link ChainContainer#chainForEach|.chainForEach(function)} - where calls `.forEach` on value, and applies the function on every item,
|
|
622
|
+
* without storing the result from the function. <br /> <b>(Useful for changing objects in-place)</b>
|
|
623
|
+
* * {@link ChainContainer#chainFlatMap|.chainFlatMap(function)} - where it calls `.flatMap` on value, and applies the function on every item,
|
|
624
|
+
* flattening the results. <br /> <b>(Useful for expanding an array based on values in the array)</b>
|
|
625
|
+
* * {@link ChainContainer#chainFilter|.chainFilter(function)} - where it calls `.filter` on value, using the function on every item,
|
|
626
|
+
* keeping the item in the list if the function returns true.
|
|
627
|
+
* <br /> <b>(Useful for removing items from an array)</b>
|
|
628
|
+
* * {@link ChainContainer#chainReduce|.chainReduce(function, initialValue)} - where it calls `.reduce` on value, and reduces the value
|
|
629
|
+
* to a single result.
|
|
630
|
+
* <br /> <b>(Useful for reducing the array to a single value <br /> - like a concatenated string or sum total)</b>
|
|
631
|
+
*
|
|
632
|
+
* There may be times you want to run side effects, or replace the value entirely. (This isn't common, but may be useful on occasion)
|
|
633
|
+
*
|
|
634
|
+
* * {@link ChainContainer#execute|.execute(function)} - where it calls a function, but doesn't pass on the result.
|
|
635
|
+
* <br /> (This is useful for side-effects, like writing to files)
|
|
636
|
+
* * {@link ChainContainer#replace|.replace(value)} - replaces the value in the chain with a literal value,
|
|
637
|
+
* regardless of the previous value.
|
|
638
|
+
*
|
|
437
639
|
* For example:
|
|
438
640
|
*
|
|
439
641
|
* ```
|
|
440
642
|
* addTwo = (value) => value + 2;
|
|
441
643
|
*
|
|
442
644
|
* //-- we can always get the value
|
|
443
|
-
*
|
|
444
|
-
* utils.chain(3).value
|
|
445
|
-
* ); // 3
|
|
645
|
+
* utils.chain(3).close(); // 3
|
|
446
646
|
* ```
|
|
447
647
|
*
|
|
448
648
|
* but this is much easier if we continue to chain it
|
|
@@ -451,18 +651,16 @@ class ChainContainer {
|
|
|
451
651
|
* addTwo = (value) => value + 2;
|
|
452
652
|
* addTwo(3); // 5
|
|
453
653
|
*
|
|
454
|
-
*
|
|
455
|
-
*
|
|
456
|
-
*
|
|
457
|
-
*
|
|
458
|
-
*
|
|
459
|
-
*
|
|
460
|
-
*
|
|
461
|
-
*
|
|
462
|
-
*
|
|
463
|
-
*
|
|
464
|
-
* // 7
|
|
465
|
-
* // 10
|
|
654
|
+
* utils.chain(3)
|
|
655
|
+
* .chain(addTwo) // (3 + 2)
|
|
656
|
+
* .chain(addTwo) // (5 + 2)
|
|
657
|
+
* .debug() // consoles 7 and passes the value along
|
|
658
|
+
* // define a function inline
|
|
659
|
+
* .chain((value) => value + 3) // (7 + 3)
|
|
660
|
+
* .close()
|
|
661
|
+
*
|
|
662
|
+
* // consoles out value `7`
|
|
663
|
+
* // returns value 10
|
|
466
664
|
* ```
|
|
467
665
|
*
|
|
468
666
|
* Note that we can also map against values in the array
|
|
@@ -478,10 +676,23 @@ class ChainContainer {
|
|
|
478
676
|
* .chain(initializeArray) // [0, 1, 2]
|
|
479
677
|
* .chainMap(addTwo) // [2, 3, 4] or [0 + 2, 1 + 2, 2 + 2]
|
|
480
678
|
* .chainMap(addTwo)
|
|
481
|
-
* .
|
|
679
|
+
* .close();
|
|
482
680
|
* // [4, 5, 6]
|
|
483
681
|
* ```
|
|
484
682
|
*
|
|
683
|
+
* Chain to log results while transforming values
|
|
684
|
+
*
|
|
685
|
+
* ```
|
|
686
|
+
* results = [{ userId: 'abc123' }, { userId: 'xyz987' }];
|
|
687
|
+
*
|
|
688
|
+
* activeUsers = chain(results)
|
|
689
|
+
* .chainMap((record) => users.get(record.userId))
|
|
690
|
+
* .chainForEach(record => record.status = 'active')
|
|
691
|
+
* .chain(records => d3.csv.format(records))
|
|
692
|
+
* .execute(records => utils.file.writeFile('./log', d3.csv.format(records)))
|
|
693
|
+
* .close()
|
|
694
|
+
* ```
|
|
695
|
+
*
|
|
485
696
|
* Or even combine with other utility methods
|
|
486
697
|
*
|
|
487
698
|
* ```
|
|
@@ -499,6 +710,17 @@ class ChainContainer {
|
|
|
499
710
|
* .chain(values => utils.table(values).render());
|
|
500
711
|
* ```
|
|
501
712
|
*
|
|
713
|
+
* this can be more legible than the normal way to write this, <br />
|
|
714
|
+
* especially if you need to troubleshoot the value halfway through.
|
|
715
|
+
*
|
|
716
|
+
* ```
|
|
717
|
+
* utils.table(
|
|
718
|
+
* decodeURIComponent(badStr)
|
|
719
|
+
* .split('\n')
|
|
720
|
+
* .map(line => ({ line, length: line.length }))
|
|
721
|
+
* ).render()
|
|
722
|
+
* ```
|
|
723
|
+
*
|
|
502
724
|
* and it renders out a lovely table like this:
|
|
503
725
|
*
|
|
504
726
|
* line |length
|
package/src/file.js
CHANGED
|
@@ -18,8 +18,8 @@ const logger = require('./logger');
|
|
|
18
18
|
* (or storing and loading json data)
|
|
19
19
|
*
|
|
20
20
|
* * Writing files
|
|
21
|
-
* * {@link module:file.writeFile|writeFile(path, string)} - write
|
|
22
|
-
* * {@link module:file.writeJSON|writeJSON(path, any)} - write
|
|
21
|
+
* * {@link module:file.writeFile|writeFile(path, string)} - write or append to file with plain text
|
|
22
|
+
* * {@link module:file.writeJSON|writeJSON(path, any)} - write or append to a file with objects converted to JSON
|
|
23
23
|
* * reading files
|
|
24
24
|
* * {@link module:file.readFile|readFile(path, string)} - read a file as plain text
|
|
25
25
|
* * {@link module:file.readJSON|readJSON(path, any)} - read data as JSON
|
|
@@ -179,11 +179,7 @@ module.exports.readFile = function readFile(filePath, fsOptions = {}) {
|
|
|
179
179
|
*
|
|
180
180
|
* NOTE that this uses `utf-8` as the default encoding
|
|
181
181
|
*
|
|
182
|
-
*
|
|
183
|
-
* @param {Object} fsOptions - options to pass for fsRead (ex: { encoding: 'utf-8' })
|
|
184
|
-
* @param {string} contents - contents of the file
|
|
185
|
-
* @see {@link module:file.readJSON|readJSON(filePath, fsOptions)} - for reading
|
|
186
|
-
* @example
|
|
182
|
+
* ```
|
|
187
183
|
* const weather = [
|
|
188
184
|
* { id: 1, city: 'Seattle', month: 'Aug', precip: 0.87 },
|
|
189
185
|
* { id: 0, city: 'Seattle', month: 'Apr', precip: 2.68 },
|
|
@@ -199,16 +195,52 @@ module.exports.readFile = function readFile(filePath, fsOptions = {}) {
|
|
|
199
195
|
*
|
|
200
196
|
* const myWeather = utils.file.readJSON('./data/weather.json');
|
|
201
197
|
* myWeather.length; // 9
|
|
198
|
+
* ```
|
|
199
|
+
*
|
|
200
|
+
* Note, passing `append:true` in the options, will let you append text before writing,
|
|
201
|
+
* useful for dealing with large and complex files.
|
|
202
|
+
*
|
|
203
|
+
* ```
|
|
204
|
+
* weatherEntry1 = { id: 1, city: 'Seattle', month: 'Aug', precip: 0.87 };
|
|
205
|
+
* weatherEntry2 = { id: 0, city: 'Seattle', month: 'Apr', precip: 2.68 };
|
|
206
|
+
* weatherEntry3 = { id: 2, city: 'Seattle', month: 'Dec', precip: 5.31 };
|
|
207
|
+
*
|
|
208
|
+
* utils.file.writeJSON('./data/weather2.json', weatherEntry1, { prefix: '[' });
|
|
209
|
+
* utils.file.writeJSON('./data/weather2.json', weatherEntry2, { append: true, prefix: ', ' });
|
|
210
|
+
* utils.file.writeJSON('./data/weather2.json', weatherEntry3, { append: true, prefix: ', ', suffix: ']' });
|
|
211
|
+
*
|
|
212
|
+
* utils.file.readJSON('./data/weather.json');
|
|
213
|
+
*
|
|
214
|
+
* //-- single line shown here on multiple lines for clarity
|
|
215
|
+
* // [{"id":1,"city":"Seattle","month":"Aug","precip":0.87}
|
|
216
|
+
* // ,{"id":0,"city":"Seattle","month":"Apr","precip":2.68}
|
|
217
|
+
* // ,{"id":2,"city":"Seattle","month":"Dec","precip":5.31}]
|
|
218
|
+
*
|
|
219
|
+
* @param {string} filePath - path of the file to write
|
|
220
|
+
* @param {string} contents - contents of the file
|
|
221
|
+
* @param {Object} fsOptions - [nodejs fs writeFileSync, appendFileSync options](https://nodejs.org/api/fs.html)
|
|
222
|
+
* @param {Boolean} fsOptions.append - if true, will append the text to the file
|
|
223
|
+
* @param {Boolean} fsOptions.prefix - string to add before writing the json, like an opening bracket '[' or comma ','
|
|
224
|
+
* @param {Boolean} fsOptions.prefix - string to add before writing the json, like a closing bracket ']'
|
|
225
|
+
* @param {String} fsOptions.encoding - encoding to use when writing the file.
|
|
226
|
+
* @see {@link module:file.readJSON|readJSON(filePath, fsOptions)} - for reading
|
|
202
227
|
*/
|
|
203
228
|
module.exports.writeJSON = function writeJSON(filePath, contents, fsOptions = {}) {
|
|
204
229
|
//-- if it isn't desired, simply pass as a string.
|
|
205
230
|
const jsonContents = JSON.stringify(contents, null, 2);
|
|
206
231
|
const optionsDefaults = { encoding: 'utf-8' };
|
|
207
232
|
const cleanedOptions = { ...optionsDefaults, ...fsOptions };
|
|
233
|
+
const isAppend = cleanedOptions.append === true;
|
|
234
|
+
const prefix = cleanedOptions.prefix || '';
|
|
235
|
+
const suffix = cleanedOptions.suffix || '';
|
|
208
236
|
|
|
209
237
|
// const resolvedPath = path.resolve(filePath);
|
|
210
238
|
try {
|
|
211
|
-
|
|
239
|
+
if (isAppend) {
|
|
240
|
+
fs.appendFileSync(filePath, prefix + jsonContents + suffix, cleanedOptions);
|
|
241
|
+
} else {
|
|
242
|
+
fs.writeFileSync(filePath, prefix + jsonContents + suffix, cleanedOptions);
|
|
243
|
+
}
|
|
212
244
|
} catch (err) {
|
|
213
245
|
logger.error(`unable to write to file: ${filePath}`);
|
|
214
246
|
}
|
|
@@ -219,23 +251,35 @@ module.exports.writeJSON = function writeJSON(filePath, contents, fsOptions = {}
|
|
|
219
251
|
*
|
|
220
252
|
* Note that this uses `utf-8` as the encoding by default
|
|
221
253
|
*
|
|
222
|
-
*
|
|
223
|
-
* @param {string} contents - contents of the file
|
|
224
|
-
* @see {@link module:file.readFile|readFile(filePath, fsOptions)} - for reading
|
|
225
|
-
* @example
|
|
254
|
+
* ```
|
|
226
255
|
* const myString = `hello`;
|
|
227
256
|
* utils.file.writeFile('./tmp', myString);
|
|
228
257
|
* const newString = utils.file.readFile('./tmp');
|
|
229
258
|
* newString; // 'hello';
|
|
259
|
+
* ```
|
|
260
|
+
*
|
|
261
|
+
* Note, you can append to the file by passing `{append:true}` in the options.
|
|
262
|
+
*
|
|
263
|
+
* @param {string} filePath - path of the file to write
|
|
264
|
+
* @param {string} contents - contents of the file
|
|
265
|
+
* @param {Object} fsOptions - [nodejs fs writeFileSync, appendFileSync options](https://nodejs.org/api/fs.html)
|
|
266
|
+
* @param {Boolean} fsOptions.append - if true, will append the text to the file
|
|
267
|
+
* @param {String} fsOptions.encoding - encoding to use when writing the file.
|
|
268
|
+
* @see {@link module:file.readFile|readFile(filePath, fsOptions)} - for reading
|
|
230
269
|
*/
|
|
231
270
|
module.exports.writeFile = function writeFile(filePath, contents, fsOptions = {}) {
|
|
232
271
|
const resolvedPath = path.resolve(filePath);
|
|
233
272
|
const optionsDefaults = { encoding: 'utf-8' };
|
|
234
273
|
const cleanedOptions = { ...optionsDefaults, ...fsOptions };
|
|
274
|
+
const isAppend = cleanedOptions.append === true;
|
|
235
275
|
|
|
236
276
|
try {
|
|
237
277
|
// fsStd.writeFileSync(resolvedPath, contents, { encoding: 'utf-8' });
|
|
238
|
-
|
|
278
|
+
if (isAppend) {
|
|
279
|
+
fs.appendFileSync(resolvedPath, contents, cleanedOptions);
|
|
280
|
+
} else {
|
|
281
|
+
fs.writeFileSync(resolvedPath, contents, cleanedOptions);
|
|
282
|
+
}
|
|
239
283
|
} catch (err) {
|
|
240
284
|
logger.error(`unable to write to file: ${filePath}`);
|
|
241
285
|
logger.error('err.message', err.message);
|