necessary 14.3.2 → 14.4.1
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/README.md +160 -61
- package/lib/browser.js +18 -18
- package/lib/characters.js +36 -36
- package/lib/constants.js +12 -12
- package/lib/contentTypes.js +12 -12
- package/lib/defaults.js +9 -9
- package/lib/encodings.js +6 -6
- package/lib/headers.js +17 -17
- package/lib/keyCodes.js +13 -13
- package/lib/levels.js +9 -9
- package/lib/main.js +24 -24
- package/lib/methods.js +8 -8
- package/lib/statusCodes.js +18 -18
- package/lib/statusMessages.js +18 -18
- package/lib/utilities/ajax.js +6 -6
- package/lib/utilities/array.js +88 -60
- package/lib/utilities/asynchronous.js +10 -10
- package/lib/utilities/fileSystem.js +20 -20
- package/lib/utilities/http.js +10 -10
- package/lib/utilities/logging.js +4 -4
- package/lib/utilities/package.js +9 -9
- package/lib/utilities/path.js +15 -15
- package/lib/utilities/shell.js +4 -4
- package/lib/utilities/string.js +7 -7
- package/lib/utilities/template.js +6 -6
- package/lib/utilities/version.js +4 -4
- package/package.json +1 -1
- package/src/utilities/array.js +33 -1
package/README.md
CHANGED
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
A collection of utility functions.
|
|
4
4
|
|
|
5
|
-
This package was partly inspired by [lodash](https://lodash.com/), [async](https://caolan.github.io/async/) and the like.
|
|
5
|
+
This package was partly inspired by [lodash](https://lodash.com/), [async](https://caolan.github.io/async/) and the like.
|
|
6
|
+
The idea was to create utility functions that addressed some modest requirements and would result in a relatively small footprint.
|
|
7
|
+
That said, the bare bones implementations, especially the asynchronous functions, should provide some confidence whilst debugging.
|
|
6
8
|
|
|
7
9
|
These can only be used in the browser:
|
|
8
10
|
|
|
@@ -43,7 +45,8 @@ You can also clone the repository with [Git](https://git-scm.com/)...
|
|
|
43
45
|
|
|
44
46
|
## Usage
|
|
45
47
|
|
|
46
|
-
Each of the collections of utility functions described below is exported as a plain old JavaScript object.
|
|
48
|
+
Each of the collections of utility functions described below is exported as a plain old JavaScript object.
|
|
49
|
+
To get hold of them, import the requisite object and then destructure it:
|
|
47
50
|
|
|
48
51
|
```
|
|
49
52
|
import { arrayUtilities, asynchronousUtilities, fileSystemUtilities } from "necessary";
|
|
@@ -65,23 +68,28 @@ const { first, last } = arrayUtilities,
|
|
|
65
68
|
...
|
|
66
69
|
```
|
|
67
70
|
|
|
68
|
-
The miscellaneous functions are a special case.
|
|
71
|
+
The miscellaneous functions are a special case.
|
|
72
|
+
They can be treated as above but may well have other functions assigned to them.
|
|
73
|
+
See below.
|
|
69
74
|
|
|
70
75
|
## Ajax utilities
|
|
71
76
|
|
|
72
77
|
- `get()`
|
|
73
|
-
- `post()`
|
|
78
|
+
- `post()`
|
|
74
79
|
- `request()`
|
|
75
80
|
|
|
76
81
|
The first two `get()` and `post()` functions make use of the third `request()` function, which is more generic and can be used for arbitrary HTTP requests.
|
|
77
82
|
|
|
78
|
-
* The `get()` function sends a `GET` request, taking `host`, `uri
|
|
83
|
+
* The `get()` function sends a `GET` request, taking `host`, `uri` and `query` arguments, together with an optional `headers` argument after the `query` argument.
|
|
79
84
|
|
|
80
85
|
The `query` argument should be a plain old JavaScript object, the names and values of which are encoded and concatenated to form the query string.
|
|
81
86
|
|
|
82
|
-
The `headers` argument should also be a plain old JavaScript object.
|
|
87
|
+
The `headers` argument should also be a plain old JavaScript object.
|
|
88
|
+
If it does not have an `accept` property then one wil be provided with the value `application/json`.
|
|
83
89
|
|
|
84
|
-
The `callback` argument is expected to be a function taking `content` and `statusCode` arguments.
|
|
90
|
+
The `callback` argument is expected to be a function taking `content` and `statusCode` arguments.
|
|
91
|
+
If the `accept` property of the main `headers` argument is set to `application/json` then the function's `content` argument can be assumed to be JSON, or `null` if the request body cannot be parsed as such.
|
|
92
|
+
The `statusCode` argument will be the response status code, for example `200` for a successful `OK` response.
|
|
85
93
|
|
|
86
94
|
```
|
|
87
95
|
const host = "...",
|
|
@@ -101,7 +109,10 @@ Note that the `uri` argument must include a leading forward slash `/` since the
|
|
|
101
109
|
|
|
102
110
|
* The `post()` function behaves almost identically to the `get()` function, with the following differences.
|
|
103
111
|
|
|
104
|
-
It sends a `POST` rather than a `GET` request.
|
|
112
|
+
It sends a `POST` rather than a `GET` request.
|
|
113
|
+
There is an additional `content` argument that comes before the `callabck` argument and after the `headers` argument, which is again optional.
|
|
114
|
+
If the `headers` argument does not have a `content-type` property then one will be provided with the value of `application/json`.
|
|
115
|
+
If the `content-type` property of the `headers` argument is set to `application/json` then the `content` argument is assumed to be a plain old JavaScript object and is stringified as JSON.
|
|
105
116
|
|
|
106
117
|
```
|
|
107
118
|
const host = "...",
|
|
@@ -152,7 +163,8 @@ Note that the `headers` argument is not optional this time.
|
|
|
152
163
|
Functions for applications running on a shell such as Bash or ZSH.
|
|
153
164
|
In fact there is only one currently.
|
|
154
165
|
|
|
155
|
-
* The `prompt()` function is meant for use in shell applications.
|
|
166
|
+
* The `prompt()` function is meant for use in shell applications.
|
|
167
|
+
It takes a plain old JavaScript `options` object and a `callback` function as its first and second arguments, respectively:
|
|
156
168
|
|
|
157
169
|
```
|
|
158
170
|
const hidden = true,
|
|
@@ -173,13 +185,18 @@ prompt(options, (answer) => {
|
|
|
173
185
|
});
|
|
174
186
|
```
|
|
175
187
|
|
|
176
|
-
There are a range of properties available for the `options` object.
|
|
188
|
+
There are a range of properties available for the `options` object.
|
|
189
|
+
The `description` and `errorMessage` properties are mandatory.
|
|
190
|
+
The remaining properties are optional.
|
|
177
191
|
|
|
178
|
-
The default values of the `attempts` and `encoding` properties are `3` and `utf8`, respectively.
|
|
192
|
+
The default values of the `attempts` and `encoding` properties are `3` and `utf8`, respectively.
|
|
193
|
+
The default value of the `hidden` property is `false`. Setting it to `true` results in password-style input, that is, the characters remain hidden.
|
|
179
194
|
|
|
180
195
|
If no `validateFunction` property is given then you must set a `validatePattern` property instead, which must be a regular expression.
|
|
181
196
|
|
|
182
|
-
The `initialAnswer` property sets the initial answer at the prompt.
|
|
197
|
+
The `initialAnswer` property sets the initial answer at the prompt.
|
|
198
|
+
You might want to set it to `yes`, for example. Lastly, setting the `answer` property to anything other than `null` or `undefined` causes the `callback` function to be invoked immediately without any prompt being shown.
|
|
199
|
+
This can be useful for debugging.
|
|
183
200
|
|
|
184
201
|
## Logging utilities
|
|
185
202
|
|
|
@@ -195,7 +212,9 @@ log("...") // Results in '28-01-2018 15:44:47.363 bin/main.js(35) ...' being log
|
|
|
195
212
|
|
|
196
213
|
You can pass an error instead of a string to `log()`, in which case it will print the file path and line number of the place where the error was thrown along with the error message.
|
|
197
214
|
|
|
198
|
-
Additionally, it is possible to print to a log file if a log directory and, optionally, a base name for the log file are specified.
|
|
215
|
+
Additionally, it is possible to print to a log file if a log directory and, optionally, a base name for the log file are specified.
|
|
216
|
+
The base name here means the file name minus the extension and separator.
|
|
217
|
+
The default is `default`:
|
|
199
218
|
|
|
200
219
|
```
|
|
201
220
|
const { setLogFileBaseName, setLogDirectoryPath } = log;
|
|
@@ -218,7 +237,8 @@ log.error("...") // Printed to the console and optionally, to the log file.
|
|
|
218
237
|
log.trace("...") // Ignored, because the trace level is lower than the debug level.
|
|
219
238
|
```
|
|
220
239
|
|
|
221
|
-
There is also a `setLogOptions()` function which allows you to pass the log level, base file name and directory path as a plain old JavaScript object.
|
|
240
|
+
There is also a `setLogOptions()` function which allows you to pass the log level, base file name and directory path as a plain old JavaScript object.
|
|
241
|
+
See below for a usage example.
|
|
222
242
|
|
|
223
243
|
Finally, log files are rolled over every night. So `./log/example.log` would become `./log/example.28-01-2018.log` and a new `./log/example.log` file would be started at midnight.
|
|
224
244
|
|
|
@@ -228,11 +248,21 @@ Finally, log files are rolled over every night. So `./log/example.log` would bec
|
|
|
228
248
|
- `createGetRequest()`
|
|
229
249
|
- `createPostRequest()`
|
|
230
250
|
|
|
231
|
-
Functions that leverage Node's [HTTP](https://nodejs.org/api/http.html) nad [HTTPS](https://nodejs.org/api/https.html) inbuilt modules in order to provide HTTP request functionality.
|
|
251
|
+
Functions that leverage Node's [HTTP](https://nodejs.org/api/http.html) nad [HTTPS](https://nodejs.org/api/https.html) inbuilt modules in order to provide HTTP request functionality.
|
|
252
|
+
These functions are deliberately low level.
|
|
253
|
+
They will take away some of the pain of using the aforementioned modules but will not automatically set headers, parse responses, etc.
|
|
254
|
+
Specifically, methods have to be called on the instance of the [ClientRequest](https://nodejs.org/api/http.html#http_class_http_clientrequest) class that they each return in order to make the request and on the instance of the [IncomingMessage](https://nodejs.org/api/http.html#class-httpincomingmessage) passed to the callback function in order to parse the response.
|
|
232
255
|
|
|
233
|
-
* The `createRequest()` function provides a means to make arbitrary requests.
|
|
256
|
+
* The `createRequest()` function provides a means to make arbitrary requests.
|
|
257
|
+
* It takes `host`, `uri`, `query`, `method`, `headers` and `callback` arguments.
|
|
258
|
+
* It returns an instance of Node's ClientRequest class.
|
|
259
|
+
* The callback function must have an `error` argument, which will be `null` if the request is successful, and a `response` argument, which will be an instance of Node's IncomingMessage class.
|
|
260
|
+
* The `query` and `headers` arguments should be plain old JavaScript objects, with the former being converted into a query string.
|
|
261
|
+
* The other arguments bar the last callback argument should be strings.
|
|
234
262
|
|
|
235
|
-
In the following example a GET request is made.
|
|
263
|
+
In the following example a GET request is made.
|
|
264
|
+
Note that because the request body is empty, it is enough to call the request object's `end()` method in order to make the request.
|
|
265
|
+
Note also that the response is piped directly to a file.
|
|
236
266
|
|
|
237
267
|
```
|
|
238
268
|
const { createWriteStream } = require("fs");
|
|
@@ -257,7 +287,9 @@ const host = ...,
|
|
|
257
287
|
request.end();
|
|
258
288
|
```
|
|
259
289
|
|
|
260
|
-
In the following example the `queryStringFromQuery()` function from the HTTP utilities is used to encode the body of the request.
|
|
290
|
+
In the following example the `queryStringFromQuery()` function from the HTTP utilities is used to encode the body of the request.
|
|
291
|
+
Note that the `content-type` header is set explicitly.
|
|
292
|
+
Note that the request body is piped directly from a file:
|
|
261
293
|
|
|
262
294
|
```
|
|
263
295
|
const { createReadStream } = require("fs");
|
|
@@ -417,7 +449,8 @@ const line = "${name}, aged ${age}.",
|
|
|
417
449
|
- `renameEntry()`
|
|
418
450
|
- `removeEntry()`
|
|
419
451
|
|
|
420
|
-
An inglorious collection of functions which do no more than paper over some of Node's synchronous [native file system API](https://nodejs.org/api/fs.html) functions.
|
|
452
|
+
An inglorious collection of functions which do no more than paper over some of Node's synchronous [native file system API](https://nodejs.org/api/fs.html) functions.
|
|
453
|
+
All of the functions will throw native errors upon failure.
|
|
421
454
|
|
|
422
455
|
* The `getEntryStats()` function returns an instance of the [fs.Stats](https://nodejs.org/api/fs.html#fs_class_fs_stats) class:
|
|
423
456
|
|
|
@@ -447,25 +480,31 @@ isDirectoryEmpty("root/etc"); // returns true if the directory is empty
|
|
|
447
480
|
readDirectory("root/etc"); // returns the contents of the 'root/etc' directory
|
|
448
481
|
```
|
|
449
482
|
|
|
450
|
-
* The `readFile()` function takes the file encoding as an optional second string argument.
|
|
483
|
+
* The `readFile()` function takes the file encoding as an optional second string argument.
|
|
484
|
+
* The default is `utf8`.
|
|
485
|
+
* It returns the content of the file upon success:
|
|
451
486
|
|
|
452
487
|
```
|
|
453
488
|
readFile("root/etc/init.conf"); // returns the content of the 'root/etc/init.conf' file
|
|
454
489
|
```
|
|
455
490
|
|
|
456
|
-
* The `copyFile()` function takes as arguments the source and target file paths.
|
|
491
|
+
* The `copyFile()` function takes as arguments the source and target file paths.
|
|
492
|
+
* It will overwrite an existing file without throwing an error.
|
|
493
|
+
* It does not return anything upon success:
|
|
457
494
|
|
|
458
495
|
```
|
|
459
496
|
copyFile("root/etc/init.conf", "tmp/init.conf"); // copies the 'init.conf' file in the '/root/etc' folder to the '/tmp' folder
|
|
460
497
|
```
|
|
461
498
|
|
|
462
|
-
* The `writeFile()` function takes the content of the file as a second string argument.
|
|
499
|
+
* The `writeFile()` function takes the content of the file as a second string argument.
|
|
500
|
+
* It does not return anything upon success:
|
|
463
501
|
|
|
464
502
|
```
|
|
465
503
|
writeFile("root/etc/init.conf", ""); // writes '' to the 'root/etc/init.conf' file
|
|
466
504
|
```
|
|
467
505
|
|
|
468
|
-
* The `appendToFile()` function takes the content to append file as a second string argument.
|
|
506
|
+
* The `appendToFile()` function takes the content to append file as a second string argument.
|
|
507
|
+
* It will create teh file if necessary and does not return anything upon success:
|
|
469
508
|
|
|
470
509
|
```
|
|
471
510
|
appendToFile("root/etc/init.conf", ""); // appends '' to the 'root/etc/init.conf' file
|
|
@@ -477,7 +516,8 @@ appendToFile("root/etc/init.conf", ""); // appends '' to the 'root/etc/init.conf
|
|
|
477
516
|
createDirectory("root/etc/init"); // Creates the 'root/etc/init' directory
|
|
478
517
|
```
|
|
479
518
|
|
|
480
|
-
* The `createFile()` creates an empty file.
|
|
519
|
+
* The `createFile()` creates an empty file.
|
|
520
|
+
* It does not return anything upon success:
|
|
481
521
|
|
|
482
522
|
```
|
|
483
523
|
createFile("root/etc/init.conf"); // writes '' to the 'root/etc/init.conf' file
|
|
@@ -503,7 +543,8 @@ Note that in the case of a directory, all of its sub-entries will be removed as
|
|
|
503
543
|
renameFile("hosts", "host"); // Renames the 'hosts' file to 'host'
|
|
504
544
|
```
|
|
505
545
|
|
|
506
|
-
Note that if the parent directory of the newly named file or directory does not exist then this function will fail.
|
|
546
|
+
Note that if the parent directory of the newly named file or directory does not exist then this function will fail.
|
|
547
|
+
Instead use the `moveEntry()` function.
|
|
507
548
|
|
|
508
549
|
## Configuration utilities
|
|
509
550
|
|
|
@@ -521,7 +562,8 @@ const { logOptions } = rc;
|
|
|
521
562
|
setLogOptions(logOptions);
|
|
522
563
|
```
|
|
523
564
|
|
|
524
|
-
The default name for the file is `.rc` and it must be present in the current working directory.
|
|
565
|
+
The default name for the file is `.rc` and it must be present in the current working directory.
|
|
566
|
+
It must have the following format:
|
|
525
567
|
|
|
526
568
|
```
|
|
527
569
|
{
|
|
@@ -547,7 +589,9 @@ If neither of these checks are successful then it will return the first element
|
|
|
547
589
|
|
|
548
590
|
Note that it will not try to assign the `name` property of the chosen environment to itself, because functions already have a `name` property.
|
|
549
591
|
|
|
550
|
-
Before returning the JSON, it will search for uppercase strings.
|
|
592
|
+
Before returning the JSON, it will search for uppercase strings.
|
|
593
|
+
If such a string is the name of an environment variable, it will be replaced by the environment variable's value.
|
|
594
|
+
This means that you can choose to keep sensitive information out of the runtime configuration and therefore, for instance, safely commit it to the repository.
|
|
551
595
|
|
|
552
596
|
You can change the base extension of the file that is parsed, that is the part of the extension between the leading dot and `rc`, by making use of the `setRCBaseExtension()` function:
|
|
553
597
|
|
|
@@ -561,7 +605,10 @@ rc(); // Provides the first environment in the '.defaultrc' file
|
|
|
561
605
|
|
|
562
606
|
Note that the `rc()` function can be included in any file but only needs to be called once. But be careful that it is called before it is ever destructured.
|
|
563
607
|
|
|
564
|
-
Aside from the aforementioned `setRCBaseExtension()` functions, the `checkRCFileExists()`, `createVacuousRCFile()`, `readRCFile()` and `writeRCFile()` functions do as their names suggest.
|
|
608
|
+
Aside from the aforementioned `setRCBaseExtension()` functions, the `checkRCFileExists()`, `createVacuousRCFile()`, `readRCFile()` and `writeRCFile()` functions do as their names suggest.
|
|
609
|
+
The `updateRCFile()` function, if passed a plain old JavaScript object as the first argument, will add the properties therein, overwriting any existing properties.
|
|
610
|
+
Properties to be removed can be given as further arguments.
|
|
611
|
+
If you do not want to add as well as remove properties, set the first argument to a falsey value.
|
|
565
612
|
|
|
566
613
|
```
|
|
567
614
|
const { readRCFile, writeRCFile, updateRCFile, checkRCFileExists, createVacuousRCFile } = rc;
|
|
@@ -594,7 +641,8 @@ updateRCFile(null, "example"); // Updates the rc file, removing the 'example' p
|
|
|
594
641
|
- `pathWithoutBottommostNameFromPath()`
|
|
595
642
|
- `pathWithoutTopmostDirectoryNameFromPath()`
|
|
596
643
|
|
|
597
|
-
These functions manipulate or query strings that represent file and directory paths.
|
|
644
|
+
These functions manipulate or query strings that represent file and directory paths.
|
|
645
|
+
Note that only forward slash `/` delimiters are supported. Trailing delimiters are not needed, but tolerated.
|
|
598
646
|
|
|
599
647
|
* The `isPathName()` function returns `true` if the string argument contains no `/` delimiters apart from the first and last characters:
|
|
600
648
|
|
|
@@ -646,9 +694,11 @@ isTopmostNameInAbsolutePath("root", "/root/etc"); // returns false
|
|
|
646
694
|
isTopmostNameInAbsolutePath("etc", "/root/etc"); // returns false
|
|
647
695
|
```
|
|
648
696
|
|
|
649
|
-
Note that the function assumes that the first argument is a topmost name and that the second argument is an abolute path.
|
|
697
|
+
Note that the function assumes that the first argument is a topmost name and that the second argument is an abolute path.
|
|
698
|
+
It does not check, it simply compares the two arguments with a single regex.
|
|
650
699
|
|
|
651
|
-
* The `combinePaths()` function will combine the first string argument with the second string argument by successively removing the bottommost directory name of the former for each topmost parent directory `..` signifier it finds in the latter.
|
|
700
|
+
* The `combinePaths()` function will combine the first string argument with the second string argument by successively removing the bottommost directory name of the former for each topmost parent directory `..` signifier it finds in the latter.
|
|
701
|
+
* Current directory `.` signifiers are also removed:
|
|
652
702
|
|
|
653
703
|
```
|
|
654
704
|
combinePaths("etc/", "./init"); // returns 'etc/init'
|
|
@@ -668,7 +718,8 @@ concatenatePaths("root/", "etc/"); // returns 'root/etc/'
|
|
|
668
718
|
|
|
669
719
|
Note that the function assumes that the second argument is a relative name or path although without a leading current directory `.` or parent directory `..` signifier.
|
|
670
720
|
|
|
671
|
-
* The `bottommostNameFromPath()`, `topmostDirectoryPathFromPath()`, `topmostDirectoryNameFromPath()`, `pathWithoutBottommostNameFromPath()` and `pathWithoutTopmostDirectoryNameFromPath()` functions work as their names suggest.
|
|
721
|
+
* The `bottommostNameFromPath()`, `topmostDirectoryPathFromPath()`, `topmostDirectoryNameFromPath()`, `pathWithoutBottommostNameFromPath()` and `pathWithoutTopmostDirectoryNameFromPath()` functions work as their names suggest.
|
|
722
|
+
* Each expects there to be at least one delimiter, returning `null` otherwise:
|
|
672
723
|
|
|
673
724
|
```
|
|
674
725
|
bottommostNameFromPath("../etc"); // returns 'etc'
|
|
@@ -739,18 +790,24 @@ pathWithoutTopmostDirectoryNameFromPath("root/etc/init.conf"); // returns 'etc/i
|
|
|
739
790
|
- `backwardsReduce()`
|
|
740
791
|
- `forwardsForEach()`
|
|
741
792
|
- `backwardsForEach()`
|
|
793
|
+
- `forwardsFindIndex()`
|
|
794
|
+
- `backwardsFindIndex()`
|
|
742
795
|
|
|
743
796
|
Note that none of these functions take or pass on a `thisArg` argument when they might otherwise have done. Use `bind()`.
|
|
744
797
|
|
|
745
|
-
* The functions `first()` through to `last()` return the requisite element of the array argument, if passed an array of at least the required length.
|
|
798
|
+
* The functions `first()` through to `last()` return the requisite element of the array argument, if passed an array of at least the required length.
|
|
799
|
+
If the array is not long enough they return `undefined`.
|
|
746
800
|
|
|
747
|
-
* The `head()` function returns an array containing the first element of its array argument whilst the `tail()` function returns an array containing all but the first element of its array argument.
|
|
801
|
+
* The `head()` function returns an array containing the first element of its array argument whilst the `tail()` function returns an array containing all but the first element of its array argument.
|
|
802
|
+
|
|
803
|
+
* The `back()` function returns an array containing hte last element of its array argument whilst the `front()` function returns an array returning all but the last element of its array argument.
|
|
748
804
|
|
|
749
805
|
* The `push()` function is similar to its native counterpart but will push an array rather than a single element.
|
|
750
806
|
|
|
751
807
|
* The `unshift()` function is similar to its native counterpart but will unshift an array rather than a single element.
|
|
752
808
|
|
|
753
|
-
* The `concat()` function is similar to its native counterpart, however it alters the first array argument *in place*.
|
|
809
|
+
* The `concat()` function is similar to its native counterpart, however it alters the first array argument *in place*.
|
|
810
|
+
Like its native counterpart it will also take a single element as the second argument and convert it to an array.
|
|
754
811
|
|
|
755
812
|
```
|
|
756
813
|
concat([1, 2, 3], 4); // the array argument becomes [1, 2, 3, 4]
|
|
@@ -762,7 +819,8 @@ concat([1, 2, 3], 4); // the array argument becomes [1, 2, 3, 4]
|
|
|
762
819
|
clear([1, 2, 3]); // the array argument becomes []
|
|
763
820
|
```
|
|
764
821
|
|
|
765
|
-
* The `copy()` function copies the second array argument over the top of the first array argument, in other words it replaces each element of the first array argument with the corresponding element in the second array argument.
|
|
822
|
+
* The `copy()` function copies the second array argument over the top of the first array argument, in other words it replaces each element of the first array argument with the corresponding element in the second array argument.
|
|
823
|
+
If there are more elements in the second array argument that the first, the first is lengthened:
|
|
766
824
|
|
|
767
825
|
```
|
|
768
826
|
copy([1, 2, 3], [4, 5, 6, 7]); // the first array argument becomes [4, 5, 6, 7]
|
|
@@ -774,7 +832,8 @@ copy([1, 2, 3], [4, 5, 6, 7]); // the first array argument becomes [4, 5, 6, 7]
|
|
|
774
832
|
merge([1, 2, 3], [4, 5, 6, 7]); // the first array argument becomes [1, 2, 3, 4, 5, 6, 7]
|
|
775
833
|
```
|
|
776
834
|
|
|
777
|
-
* The `match()` function compares the first and second array arguments in order.
|
|
835
|
+
* The `match()` function compares the first and second array arguments in order.
|
|
836
|
+
If they are of the same length and the callback argument supplied returns a truthy value when invoked with each pair of elements then it returns true:
|
|
778
837
|
|
|
779
838
|
```
|
|
780
839
|
match([1, 2, 3], [-1, -2, -3], (valueA, valueB) => (valueA === -valueB)); // returns true
|
|
@@ -796,15 +855,21 @@ correlate([1, 2, 3], [-4, -2, -3, -1], (valueA, valueB) => (valueA === -valueB))
|
|
|
796
855
|
|
|
797
856
|
Again note that pairs of elements can match once and once only.
|
|
798
857
|
|
|
799
|
-
* The `resolve()` function repeatedly iterates over the elements of the first array argument, removing them and adding them to the second array argument if the callback function returns a truthy value.
|
|
858
|
+
* The `resolve()` function repeatedly iterates over the elements of the first array argument, removing them and adding them to the second array argument if the callback function returns a truthy value.
|
|
859
|
+
If the callback function does not return a truthy value for any of the elements of the first array argument or the length of the first array is zero, it terminates.
|
|
800
860
|
|
|
801
861
|
```
|
|
802
862
|
resolve([1, 2, 3], [], (value) => true); // moves the elemnts of the first array argument into the second array argument and returns true
|
|
803
863
|
```
|
|
804
864
|
|
|
805
|
-
The above code snippet is perhaps not very helpful so it is worth explaining this function's utility in the context of a use case.
|
|
865
|
+
The above code snippet is perhaps not very helpful so it is worth explaining this function's utility in the context of a use case.
|
|
866
|
+
Suppose a compiler has to compile all the files in a given directory.
|
|
867
|
+
There are inter-dependencies between the files, however, so some files will not compile until their dependents have compiled.
|
|
868
|
+
If there are orderings of files that allow them to all be compiled, this function will find one of them by trial and error, so to speak.
|
|
869
|
+
The second array argument will contain the elements according to this ordering.
|
|
806
870
|
|
|
807
|
-
The first array argument is left untouched whether or not the function succeeds.
|
|
871
|
+
The first array argument is left untouched whether or not the function succeeds.
|
|
872
|
+
The second array argument may contain elements if it has only been partially successful, however.
|
|
808
873
|
|
|
809
874
|
* The `find()` function is like its native counterpart, however it returns an array of all the elements for which the callback function returns a truthy value, rather than just the first:
|
|
810
875
|
|
|
@@ -818,13 +883,17 @@ find([1, 2, -1, -2], (element, index) => (element > 0)); // returns [1, 2]
|
|
|
818
883
|
replace([1, 0, -2], 3, (element, index) => (element === 0)); // the array argument becomes [1, 3, -2]
|
|
819
884
|
```
|
|
820
885
|
|
|
821
|
-
* The `splice()` function works in a similar vein to its native counterpart, however it takes an array as the optional fourth argument rather than a series of elements from the fourth argument onwards.
|
|
886
|
+
* The `splice()` function works in a similar vein to its native counterpart, however it takes an array as the optional fourth argument rather than a series of elements from the fourth argument onwards.
|
|
887
|
+
It mutates the first array argument and returns an array of the elements that have been deleted:
|
|
822
888
|
|
|
823
889
|
```
|
|
824
890
|
splice([1, 2, 3], 1, 2, [4, 5]); // the first array argument becomes [1, 4, 5]
|
|
825
891
|
```
|
|
826
892
|
|
|
827
|
-
* The `filter()` function is like its native counterpart, however it filters the first array argument *in place*.
|
|
893
|
+
* The `filter()` function is like its native counterpart, however it filters the first array argument *in place*.
|
|
894
|
+
The second argument should be a callback function that will be invoked for each element of the array.
|
|
895
|
+
If it does not return a truthy value, the corresponding element will be deleted.
|
|
896
|
+
The deleted elements are returned.
|
|
828
897
|
|
|
829
898
|
```
|
|
830
899
|
filter([1, 2, -2], (element, index) => (element > 0)); // returns [-2] and the array argument becomes [1, 2]
|
|
@@ -878,7 +947,9 @@ augment([1, 2, 3], [-1, 4, -2, 5], (element, index) => (element > 0)); // the ar
|
|
|
878
947
|
separate([1, -1, -2, 2, 3, -3], [], [], (element, index) => {(element > 0)); // the second and third array arguments become [1, 2, 3] and [-1, -2, 3], respectively.
|
|
879
948
|
```
|
|
880
949
|
|
|
881
|
-
The `forwardsXXX()` and `backwardsXXX()`functions do as their names suggest.
|
|
950
|
+
The `forwardsXXX()` and `backwardsXXX()`functions do as their names suggest.
|
|
951
|
+
The `fowardsXXX()` functions take an array for their first argument but otherwise behave identically to their native counterparts.
|
|
952
|
+
The `backwardsXXX()` functions behave similarly, only backwards.
|
|
882
953
|
|
|
883
954
|
## HTTP utilities
|
|
884
955
|
|
|
@@ -892,7 +963,9 @@ The `forwardsXXX()` and `backwardsXXX()`functions do as their names suggest. The
|
|
|
892
963
|
|
|
893
964
|
Helper functions to manipulate HTTP headers and URLs, build query strings and so on.
|
|
894
965
|
|
|
895
|
-
* The `overwrite()` function takes a plain old JavaScript object `headers` argument together with `name` and `value` string arguments.
|
|
966
|
+
* The `overwrite()` function takes a plain old JavaScript object `headers` argument together with `name` and `value` string arguments.
|
|
967
|
+
If the corresponding property of the `headers` object exists then it is replaced with the `value` value.
|
|
968
|
+
This function's utility lies in the fact that the name comparisons are case insensitive.
|
|
896
969
|
|
|
897
970
|
```
|
|
898
971
|
const headers = {
|
|
@@ -902,7 +975,9 @@ const headers = {
|
|
|
902
975
|
overwrite(headers, "content-type", "text/html"); // headers["Content-Type"] = "text/html"
|
|
903
976
|
```
|
|
904
977
|
|
|
905
|
-
* The `underwrite()` function takes a plain old JavaScript object `headers` argument together with `name` and `value` string arguments.
|
|
978
|
+
* The `underwrite()` function takes a plain old JavaScript object `headers` argument together with `name` and `value` string arguments.
|
|
979
|
+
If the corresponding property of the `headers` object does not exist then it is created with the `value` value.
|
|
980
|
+
This function's utility lies in the fact that the name comparisons are case insensitive.
|
|
906
981
|
|
|
907
982
|
```
|
|
908
983
|
const headers = {
|
|
@@ -940,7 +1015,8 @@ secureFromHost("https://site.com"); // returns true
|
|
|
940
1015
|
hostnameFromHost("http://site.com"); // returns "site.com"
|
|
941
1016
|
```
|
|
942
1017
|
|
|
943
|
-
* The `queryStringFromQuery()` function takes a plain old JavaScript object `query` argument and returns the corresponding URL encoded query string.
|
|
1018
|
+
* The `queryStringFromQuery()` function takes a plain old JavaScript object `query` argument and returns the corresponding URL encoded query string.
|
|
1019
|
+
It uses the [`encodeURIComponent`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent) to encode the names and values
|
|
944
1020
|
|
|
945
1021
|
```
|
|
946
1022
|
const query = {
|
|
@@ -950,7 +1026,8 @@ const query = {
|
|
|
950
1026
|
queryStringFromQuery(query); // returns John%20Doe
|
|
951
1027
|
```
|
|
952
1028
|
|
|
953
|
-
* The `urlFromHostURIAndQuery()` function takes `host` and `uri` string arguments together with a `query` plain old JavaScript object argument.
|
|
1029
|
+
* The `urlFromHostURIAndQuery()` function takes `host` and `uri` string arguments together with a `query` plain old JavaScript object argument.
|
|
1030
|
+
It creates a query string from the `query` object and concatenates this with the two other arguments in oder to create a fully qualified HTTP URL.
|
|
954
1031
|
|
|
955
1032
|
```
|
|
956
1033
|
const host = "https://site.com",
|
|
@@ -971,9 +1048,11 @@ Ideally the `host` argument should not include a trailing forward slash whereas
|
|
|
971
1048
|
- `indexOf()`
|
|
972
1049
|
- `substring()`
|
|
973
1050
|
|
|
974
|
-
String functions with support for Unicode.
|
|
1051
|
+
String functions with support for Unicode.
|
|
1052
|
+
Specifically, characters in Unicode astral plains are counted twice in native string functions and methods whereas these functions effectively count astral Unicode characters only once.
|
|
975
1053
|
|
|
976
|
-
* The `strlen()` function takes a single `string` argument.
|
|
1054
|
+
* The `strlen()` function takes a single `string` argument.
|
|
1055
|
+
It works in much the same way as the `length` property of the `String` prototype, however it is Unicode safe:
|
|
977
1056
|
|
|
978
1057
|
```
|
|
979
1058
|
"𝔸𝔹C".length = 5 // The 𝔹 and C characters are in an astral plane and count as two each.
|
|
@@ -982,7 +1061,10 @@ strlen("𝔸𝔹C") = 3 // The string is converted to an array whose length is 3
|
|
|
982
1061
|
|
|
983
1062
|
```
|
|
984
1063
|
|
|
985
|
-
* The `strcmp` function takes `stringA` and `stringB` arguments.
|
|
1064
|
+
* The `strcmp` function takes `stringA` and `stringB` arguments.
|
|
1065
|
+
It compares them character by character in order to find the lexicographically lesser of the two.
|
|
1066
|
+
Its return value is the difference between the code points of the first differing characters, with the code point of either string given as zero if it is empty.
|
|
1067
|
+
Some examples should clarify:
|
|
986
1068
|
|
|
987
1069
|
```
|
|
988
1070
|
strcmp("", "") = 0;
|
|
@@ -1012,7 +1094,8 @@ indexOf("𝔸b", "b"); // Returns 1.
|
|
|
1012
1094
|
|
|
1013
1095
|
In the above example the aforementioned native method would return 2.
|
|
1014
1096
|
|
|
1015
|
-
* The `substring()` function takes `string` and `start` arguments and an optional `end` argument.
|
|
1097
|
+
* The `substring()` function takes `string` and `start` arguments and an optional `end` argument.
|
|
1098
|
+
It works in much the same way as the `substring()` method of the `String` prototype, however it is Unicode safe:
|
|
1016
1099
|
|
|
1017
1100
|
```
|
|
1018
1101
|
"𝔸𝔹C".substring(3) = "C" // The 𝔹 character is in an astral plane and counts as two.
|
|
@@ -1026,7 +1109,8 @@ Note the native `substring()` method can be particularly egregious because the `
|
|
|
1026
1109
|
|
|
1027
1110
|
- `migrate()`
|
|
1028
1111
|
|
|
1029
|
-
A single `migrate()` function to handle the migration of JSON files with a required `version` entry.
|
|
1112
|
+
A single `migrate()` function to handle the migration of JSON files with a required `version` entry.
|
|
1113
|
+
This function can be used in conjunction with the configuration utilities but does not have to be.
|
|
1030
1114
|
|
|
1031
1115
|
* The `migrate` function takes `json`, `migrationMap` and `latestVersion` arguments. Perhaps the easiest way to demonstrate its use is by way of an extensive example.
|
|
1032
1116
|
|
|
@@ -1074,7 +1158,8 @@ function migrateConfigurationFile() {
|
|
|
1074
1158
|
}
|
|
1075
1159
|
```
|
|
1076
1160
|
|
|
1077
|
-
Note carefully the matching of the keys to their corresponding values. Each key matches the version that the `migrate()` function finds in the JSON.
|
|
1161
|
+
Note carefully the matching of the keys to their corresponding values. Each key matches the version that the `migrate()` function finds in the JSON.
|
|
1162
|
+
It therefore must apply the requisite migration function to migrate the JSON to the next version.
|
|
1078
1163
|
|
|
1079
1164
|
Lastly, the migration function must have the prescribed signature and return the migrated JSON. Again an example will suffice:
|
|
1080
1165
|
|
|
@@ -1092,7 +1177,8 @@ function migrateConfigurationToVersion_2_0(configuration) {
|
|
|
1092
1177
|
}
|
|
1093
1178
|
```
|
|
1094
1179
|
|
|
1095
|
-
In this admittedly somewhat trivial example, all the migration function does is to update the version number.
|
|
1180
|
+
In this admittedly somewhat trivial example, all the migration function does is to update the version number.
|
|
1181
|
+
Exactly how the JSON otherwise changes is immaterial but the version number must be updated in this way otherwise the `migrate()` function will loop indefinitely.
|
|
1096
1182
|
|
|
1097
1183
|
## Asynchronous utilities
|
|
1098
1184
|
|
|
@@ -1102,9 +1188,13 @@ In this admittedly somewhat trivial example, all the migration function does is
|
|
|
1102
1188
|
- `eventually()`
|
|
1103
1189
|
- `repeatedly()`
|
|
1104
1190
|
|
|
1105
|
-
These functions generally take either an operation or an array of operations, an operation being a function that mutates a context rather than returning a value.
|
|
1191
|
+
These functions generally take either an operation or an array of operations, an operation being a function that mutates a context rather than returning a value.
|
|
1192
|
+
They also take a `done()` function and an optional `context` argument.
|
|
1193
|
+
They all pass a `next()` function to the operations followed by the `done()` function, the `context` and then an `index` argument. Operations can call the `done()` function instead of the `next()` function in order to terminate early.
|
|
1106
1194
|
|
|
1107
|
-
* The `whilst()` function takes a single operation, which it calls each time the operation invokes the given `next()` function or until the operation invokes the given `done()` function.
|
|
1195
|
+
* The `whilst()` function takes a single operation, which it calls each time the operation invokes the given `next()` function or until the operation invokes the given `done()` function.
|
|
1196
|
+
The operation can also force termination by returning a truthy value, in which case it must *not* call the given `next()` or `done()` functions.
|
|
1197
|
+
In the example below the operation will be executed ten times:
|
|
1108
1198
|
|
|
1109
1199
|
```
|
|
1110
1200
|
const context = {}; ///
|
|
@@ -1126,7 +1216,9 @@ whilst(operation, () => {
|
|
|
1126
1216
|
}, context);
|
|
1127
1217
|
```
|
|
1128
1218
|
|
|
1129
|
-
* The `forEach()` function takes an array as the first argument followed by a single operation, which it calls for each element of the array unless the operation invokes the given `done()` function.
|
|
1219
|
+
* The `forEach()` function takes an array as the first argument followed by a single operation, which it calls for each element of the array unless the operation invokes the given `done()` function.
|
|
1220
|
+
If the `done()` function is never invoked by the operation, it is called once each of the array elements has been passed to the operation, provided the operation invokes the given `next ()` function each time.
|
|
1221
|
+
In the example below the operation will be executed four times:
|
|
1130
1222
|
|
|
1131
1223
|
```
|
|
1132
1224
|
const context = {};
|
|
@@ -1150,7 +1242,9 @@ forEach(array, operation, () => {
|
|
|
1150
1242
|
}, context);
|
|
1151
1243
|
```
|
|
1152
1244
|
|
|
1153
|
-
* The `sequence()` function takes an array of operations, which it calls in turn unless the operation invokes the given `done()` function.
|
|
1245
|
+
* The `sequence()` function takes an array of operations, which it calls in turn unless the operation invokes the given `done()` function.
|
|
1246
|
+
If the `done()` function is never invoked by a operation, it is called once each of the operations have been called, provided each operation invokes the given `next ()` function.
|
|
1247
|
+
In the example below each of the operations bar the last is executed:
|
|
1154
1248
|
|
|
1155
1249
|
```
|
|
1156
1250
|
const context = {};
|
|
@@ -1171,7 +1265,9 @@ sequence(operations, () => {
|
|
|
1171
1265
|
}, context);
|
|
1172
1266
|
```
|
|
1173
1267
|
|
|
1174
|
-
* The `eventually()` function takes an array of operations, each of which it calls immediately without waiting for the operations to invoke the given `next()` functions. When each of the operations has invoked the given `next()` function, it will call the `done()` function.
|
|
1268
|
+
* The `eventually()` function takes an array of operations, each of which it calls immediately without waiting for the operations to invoke the given `next()` functions. When each of the operations has invoked the given `next()` function, it will call the `done()` function.
|
|
1269
|
+
Note that in this case invoking the `done()` function from within a operation will not halt the execution of other operations, it is passed as an argument only for the sake of convention.
|
|
1270
|
+
In the example below each of the operations is executed:
|
|
1175
1271
|
|
|
1176
1272
|
```
|
|
1177
1273
|
const context = {};
|
|
@@ -1189,7 +1285,9 @@ eventually(operations, () => {
|
|
|
1189
1285
|
/// done
|
|
1190
1286
|
}, context);
|
|
1191
1287
|
```
|
|
1192
|
-
* The `repeatedly()` function takes a single operation and a `length` argument, immediately calling the operation a `length` number of times without waiting for it to invoke the given `next()` function each time. When the operation has invoked the given `next()` function a `length` number of times, it will call the `done()` function.
|
|
1288
|
+
* The `repeatedly()` function takes a single operation and a `length` argument, immediately calling the operation a `length` number of times without waiting for it to invoke the given `next()` function each time. When the operation has invoked the given `next()` function a `length` number of times, it will call the `done()` function.
|
|
1289
|
+
Note that in this case invoking the `done()` function from within the operation will not halt its execution the requisite number of times, it is passed as an argument only for the sake of convention.
|
|
1290
|
+
In the example below the operation is executed ten times:
|
|
1193
1291
|
|
|
1194
1292
|
```
|
|
1195
1293
|
const context = {};
|
|
@@ -1209,7 +1307,8 @@ repeatedly(operation, length, () => {
|
|
|
1209
1307
|
|
|
1210
1308
|
## Building
|
|
1211
1309
|
|
|
1212
|
-
Automation is done with [npm scripts](https://docs.npmjs.com/misc/scripts), have a look at the `package.json` file.
|
|
1310
|
+
Automation is done with [npm scripts](https://docs.npmjs.com/misc/scripts), have a look at the `package.json` file.
|
|
1311
|
+
The pertinent commands are:
|
|
1213
1312
|
|
|
1214
1313
|
npm run build-debug
|
|
1215
1314
|
npm run watch-debug
|