├── .dockerignore
├── .github
├── FUNDING.yml
└── workflows
│ └── test.yml
├── .gitignore
├── Dockerfile
├── LICENSE.txt
├── README.md
├── docker-compose.yml
├── index.d.ts
├── index.js
├── index.test.js
├── libqp
├── LICENSE
├── README.md
├── index.d.ts
└── index.js
├── mail
├── 01.eml
├── 02.eml
├── 03.eml
└── 04.eml
├── package-lock.json
├── package.json
├── sendmail.sh
├── tsconfig.d.json
├── tsconfig.json
└── wait-for-hosts.sh
/.dockerignore:
--------------------------------------------------------------------------------
1 | *
2 | !/wait-for-hosts.sh
3 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: [blueimp]
2 |
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: Test
2 |
3 | on: [push, pull_request]
4 |
5 | jobs:
6 | test:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - uses: actions/checkout@v2
10 | - name: Setup Node.js
11 | uses: actions/setup-node@v1
12 | with:
13 | node-version: 12.x
14 | - name: docker-compose build
15 | run: docker-compose build
16 | - name: npm install
17 | run: npm install
18 | env:
19 | CI: true
20 | - name: npm test
21 | run: npm test
22 | env:
23 | CI: true
24 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM alpine:3.14
2 |
3 | RUN apk --no-cache add \
4 | tini \
5 | nodejs \
6 | npm \
7 | && npm install -g \
8 | npm@latest \
9 | mocha@9 \
10 | # Clean up obsolete files:
11 | && rm -rf \
12 | /tmp/* \
13 | /root/.npm
14 |
15 | USER nobody
16 |
17 | WORKDIR /opt
18 |
19 | COPY wait-for-hosts.sh /usr/local/bin/wait-for-hosts
20 |
21 | ENTRYPOINT ["tini", "-g", "--", "wait-for-hosts", "--", "mocha"]
22 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright © 2016 Sebastian Tschan, https://blueimp.net
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # mailhog
2 |
3 | > A NodeJS library to interact with the
4 | > [MailHog](https://github.com/mailhog/MailHog) API.
5 |
6 | ## Contents
7 |
8 | - [Installation](#installation)
9 | - [Initialization](#initialization)
10 | - [Description](#description)
11 | - [Parameters](#parameters)
12 | - [Returns](#returns)
13 | - [Example](#example)
14 | - [API](#api)
15 | - [messages](#messages)
16 | - [Description](#description-1)
17 | - [Parameters](#parameters-1)
18 | - [Returns](#returns-1)
19 | - [Example](#example-1)
20 | - [search](#search)
21 | - [Description](#description-2)
22 | - [Parameters](#parameters-2)
23 | - [Returns](#returns-2)
24 | - [Example](#example-2)
25 | - [latestFrom](#latestfrom)
26 | - [Description](#description-3)
27 | - [Parameters](#parameters-3)
28 | - [Returns](#returns-3)
29 | - [Example](#example-3)
30 | - [latestTo](#latestto)
31 | - [Description](#description-4)
32 | - [Parameters](#parameters-4)
33 | - [Returns](#returns-4)
34 | - [Example](#example-4)
35 | - [latestContaining](#latestcontaining)
36 | - [Description](#description-5)
37 | - [Parameters](#parameters-5)
38 | - [Returns](#returns-5)
39 | - [Example](#example-5)
40 | - [releaseMessage](#releasemessage)
41 | - [Description](#description-6)
42 | - [Parameters](#parameters-6)
43 | - [Returns](#returns-6)
44 | - [Example](#example-6)
45 | - [deleteMessage](#deletemessage)
46 | - [Description](#description-7)
47 | - [Parameters](#parameters-7)
48 | - [Returns](#returns-7)
49 | - [Example](#example-7)
50 | - [deleteAll](#deleteall)
51 | - [Description](#description-8)
52 | - [Parameters](#parameters-8)
53 | - [Returns](#returns-8)
54 | - [Example](#example-8)
55 | - [encode](#encode)
56 | - [Description](#description-9)
57 | - [Parameters](#parameters-9)
58 | - [Returns](#returns-9)
59 | - [Example](#example-9)
60 | - [decode](#decode)
61 | - [Description](#description-10)
62 | - [Parameters](#parameters-10)
63 | - [Returns](#returns-10)
64 | - [Example](#example-10)
65 | - [Testing](#testing)
66 | - [License](#license)
67 | - [Author](#author)
68 |
69 | ## Installation
70 |
71 | ```sh
72 | npm install mailhog
73 | ```
74 |
75 | ## Initialization
76 |
77 | ```
78 | require('mailhog')(options) → Object
79 | ```
80 |
81 | ### Description
82 |
83 | The `mailhog` module returns an initialization function.
84 | This function accepts an optional `options` object that is used for
85 | [http.request](https://nodejs.org/api/http.html#http_http_request_options_callback)
86 | calls to the MailHog API and returns the `mailhog` API object.
87 |
88 | ### Parameters
89 |
90 | | Name | Type | Required | Default | Description |
91 | | ---------------- | ------ | -------- | --------- | ------------------------ |
92 | | options.protocol | String | no | http: | API protocol |
93 | | options.host | String | no | localhost | API host |
94 | | options.port | Number | no | 8025 | API port |
95 | | options.auth | String | no | | API basic authentication |
96 | | options.basePath | String | no | /api | API base path |
97 |
98 | ### Returns
99 |
100 | Returns the `mailhog` API object with the following properties:
101 |
102 | ```js
103 | {
104 | options: Object,
105 | messages: Function,
106 | search: Function,
107 | latestFrom: Function,
108 | latestTo: Function,
109 | latestContaining: Function,
110 | releaseMessage: Function,
111 | deleteMessage: Function,
112 | deleteAll: Function,
113 | encode: Function,
114 | decode: Function
115 | }
116 | ```
117 |
118 | ### Example
119 |
120 | ```js
121 | const mailhog = require('mailhog')({
122 | host: 'mailhog'
123 | })
124 |
125 | mailhog.messages().then(result => console.log(result))
126 | ```
127 |
128 | ## API
129 |
130 | The following API descriptions assume that the `mailhog` API object has been
131 | initialized.
132 |
133 | ### messages
134 |
135 | ```
136 | mailhog.messages(start, limit) → Promise
137 | ```
138 |
139 | #### Description
140 |
141 | Retrieves a list of mail objects, sorted from latest to earliest.
142 |
143 | #### Parameters
144 |
145 | | Name | Type | Required | Default | Description |
146 | | ----- | ------ | -------- | ------- | --------------------------------- |
147 | | start | Number | no | 0 | defines the messages query offset |
148 | | limit | Number | no | 50 | defines the max number of results |
149 |
150 | #### Returns
151 |
152 | Returns a `Promise` that resolves with an `Object`.
153 |
154 | The resolved result has the following properties:
155 |
156 | ```js
157 | {
158 | total: Number, // Number of results available
159 | count: Number, // Number of results returned
160 | start: Number, // Offset for the range of results returned
161 | items: Array // List of mail object items
162 | }
163 | ```
164 |
165 | The individual mail object items have the following properties:
166 |
167 | ```js
168 | {
169 | ID: String, // Mail ID
170 | text: String, // Decoded mail text content
171 | html: String, // Decoded mail HTML content
172 | subject: String, // Decoded mail Subject header
173 | from: String, // Decoded mail From header
174 | to: String, // Decoded mail To header
175 | cc: String, // Decoded mail Cc header
176 | bcc: String, // Decoded mail Bcc header
177 | replyTo: String, // Decoded mail Reply-To header
178 | date: Date, // Mail Date header
179 | deliveryDate: Date, // Mail Delivery-Date header
180 | attachments: Array // List of mail attachments
181 | }
182 | ```
183 |
184 | The individual attachments have the following properties:
185 |
186 | ```js
187 | {
188 | name: String, // Filename
189 | type: String, // Content-Type
190 | encoding: String, // Content-Transfer-Encoding
191 | Body: String // Encoded content
192 | }
193 | ```
194 |
195 | #### Example
196 |
197 | ```js
198 | async function example() {
199 | // Retrieve the latest 10 messages:
200 | const result = await mailhog.messages(0, 10)
201 |
202 | // Log the details of each message to the console:
203 | for (let item of result.items) {
204 | console.log('From: ', item.from)
205 | console.log('To: ', item.to)
206 | console.log('Subject: ', item.subject)
207 | console.log('Content: ', item.text)
208 | }
209 | }
210 | ```
211 |
212 | ### search
213 |
214 | ```
215 | mailhog.search(query, kind, start, limit) → Promise
216 | ```
217 |
218 | #### Description
219 |
220 | Retrieves a list of mail objects for the given query, sorted from latest to
221 | earliest.
222 |
223 | #### Parameters
224 |
225 | | Name | Type | Required | Default | Description |
226 | | ----- | ------ | -------- | ---------- | --------------------------------- |
227 | | query | String | yes | | search query |
228 | | kind | String | no | containing | query kind (from/to/containing) |
229 | | start | Number | no | 0 | defines the search query offset |
230 | | limit | Number | no | 50 | defines the max number of results |
231 |
232 | #### Returns
233 |
234 | Returns a `Promise` that resolves with an `Object`.
235 |
236 | The resolved result has the following properties:
237 |
238 | ```js
239 | {
240 | total: Number, // Number of results available
241 | count: Number, // Number of results returned
242 | start: Number, // Offset for the range of results returned
243 | items: Array // List of mail object items
244 | }
245 | ```
246 |
247 | The individual mail object items have the following properties:
248 |
249 | ```js
250 | {
251 | ID: String, // Mail ID
252 | text: String, // Decoded mail text content
253 | html: String, // Decoded mail HTML content
254 | subject: String, // Decoded mail Subject header
255 | from: String, // Decoded mail From header
256 | to: String, // Decoded mail To header
257 | cc: String, // Decoded mail Cc header
258 | bcc: String, // Decoded mail Bcc header
259 | replyTo: String, // Decoded mail Reply-To header
260 | date: Date, // Mail Date header
261 | deliveryDate: Date, // Mail Delivery-Date header
262 | attachments: Array // List of mail attachments
263 | }
264 | ```
265 |
266 | The individual attachments have the following properties:
267 |
268 | ```js
269 | {
270 | name: String, // Filename
271 | type: String, // Content-Type
272 | encoding: String, // Content-Transfer-Encoding
273 | Body: String // Encoded content
274 | }
275 | ```
276 |
277 | #### Example
278 |
279 | ```js
280 | async function example() {
281 | // Search the latest 10 messages containing "banana":
282 | const result = await mailhog.search('banana', 'containing', 0, 10)
283 |
284 | // Log the details of each message to the console:
285 | for (let item of result.items) {
286 | console.log('From: ', item.from)
287 | console.log('To: ', item.to)
288 | console.log('Subject: ', item.subject)
289 | console.log('Content: ', item.text)
290 | }
291 | }
292 | ```
293 |
294 | ### latestFrom
295 |
296 | ```
297 | mailhog.latestFrom(query) → Promise
298 | ```
299 |
300 | #### Description
301 |
302 | Retrieves the latest mail object sent from the given address.
303 |
304 | #### Parameters
305 |
306 | | Name | Type | Required | Description |
307 | | ----- | ------ | -------- | ------------ |
308 | | query | String | yes | from address |
309 |
310 | #### Returns
311 |
312 | Returns a `Promise` that resolves with an `Object`.
313 |
314 | The resolved mail object has the following properties:
315 |
316 | ```js
317 | {
318 | ID: String, // Mail ID
319 | text: String, // Decoded mail text content
320 | html: String, // Decoded mail HTML content
321 | subject: String, // Decoded mail Subject header
322 | from: String, // Decoded mail From header
323 | to: String, // Decoded mail To header
324 | cc: String, // Decoded mail Cc header
325 | bcc: String, // Decoded mail Bcc header
326 | replyTo: String, // Decoded mail Reply-To header
327 | date: Date, // Mail Date header
328 | deliveryDate: Date, // Mail Delivery-Date header
329 | attachments: Array // List of mail attachments
330 | }
331 | ```
332 |
333 | The individual attachments have the following properties:
334 |
335 | ```js
336 | {
337 | name: String, // Filename
338 | type: String, // Content-Type
339 | encoding: String, // Content-Transfer-Encoding
340 | Body: String // Encoded content
341 | }
342 | ```
343 |
344 | #### Example
345 |
346 | ```js
347 | async function example() {
348 | // Search the latest message from "test@example.org":
349 | const result = await mailhog.latestFrom('test@example.org')
350 |
351 | // Log the details of this message to the console:
352 | console.log('From: ', result.from)
353 | console.log('To: ', result.to)
354 | console.log('Subject: ', result.subject)
355 | console.log('Content: ', result.text)
356 | }
357 | ```
358 |
359 | ### latestTo
360 |
361 | ```
362 | mailhog.latestTo(query) → Promise
363 | ```
364 |
365 | #### Description
366 |
367 | Retrieves the latest mail object sent to the given address.
368 |
369 | #### Parameters
370 |
371 | | Name | Type | Required | Description |
372 | | ----- | ------ | -------- | ----------- |
373 | | query | String | yes | to address |
374 |
375 | #### Returns
376 |
377 | Returns a `Promise` that resolves with an `Object`.
378 |
379 | The resolved mail object has the following properties:
380 |
381 | ```js
382 | {
383 | ID: String, // Mail ID
384 | text: String, // Decoded mail text content
385 | html: String, // Decoded mail HTML content
386 | subject: String, // Decoded mail Subject header
387 | from: String, // Decoded mail From header
388 | to: String, // Decoded mail To header
389 | cc: String, // Decoded mail Cc header
390 | bcc: String, // Decoded mail Bcc header
391 | replyTo: String, // Decoded mail Reply-To header
392 | date: Date, // Mail Date header
393 | deliveryDate: Date, // Mail Delivery-Date header
394 | attachments: Array // List of mail attachments
395 | }
396 | ```
397 |
398 | The individual attachments have the following properties:
399 |
400 | ```js
401 | {
402 | name: String, // Filename
403 | type: String, // Content-Type
404 | encoding: String, // Content-Transfer-Encoding
405 | Body: String // Encoded content
406 | }
407 | ```
408 |
409 | #### Example
410 |
411 | ```js
412 | async function example() {
413 | // Search the latest message to "test@example.org":
414 | const result = await mailhog.latestTo('test@example.org')
415 |
416 | // Log the details of this message to the console:
417 | console.log('From: ', result.from)
418 | console.log('To: ', result.to)
419 | console.log('Subject: ', result.subject)
420 | console.log('Content: ', result.text)
421 | }
422 | ```
423 |
424 | ### latestContaining
425 |
426 | ```
427 | mailhog.latestContaining(query) → Promise
428 | ```
429 |
430 | #### Description
431 |
432 | Retrieves the latest mail object containing the given query.
433 |
434 | #### Parameters
435 |
436 | | Name | Type | Required | Description |
437 | | ----- | ------ | -------- | ------------ |
438 | | query | String | yes | search query |
439 |
440 | #### Returns
441 |
442 | Returns a `Promise` that resolves with an `Object`.
443 |
444 | The resolved mail object has the following properties:
445 |
446 | ```js
447 | {
448 | ID: String, // Mail ID
449 | text: String, // Decoded mail text content
450 | html: String, // Decoded mail HTML content
451 | subject: String, // Decoded mail Subject header
452 | from: String, // Decoded mail From header
453 | to: String, // Decoded mail To header
454 | cc: String, // Decoded mail Cc header
455 | bcc: String, // Decoded mail Bcc header
456 | replyTo: String, // Decoded mail Reply-To header
457 | date: Date, // Mail Date header
458 | deliveryDate: Date, // Mail Delivery-Date header
459 | attachments: Array // List of mail attachments
460 | }
461 | ```
462 |
463 | The individual attachments have the following properties:
464 |
465 | ```js
466 | {
467 | name: String, // Filename
468 | type: String, // Content-Type
469 | encoding: String, // Content-Transfer-Encoding
470 | Body: String // Encoded content
471 | }
472 | ```
473 |
474 | #### Example
475 |
476 | ```js
477 | async function example() {
478 | // Search the latest message containing "banana":
479 | const result = await mailhog.latestContaining('banana')
480 |
481 | // Log the details of this message to the console:
482 | console.log('From: ', result.from)
483 | console.log('To: ', result.to)
484 | console.log('Subject: ', result.subject)
485 | console.log('Content: ', result.text)
486 | }
487 | ```
488 |
489 | ### releaseMessage
490 |
491 | ```
492 | mailhog.releaseMessage(id, config) → Promise
493 | ```
494 |
495 | #### Description
496 |
497 | Releases the mail with the given ID using the provided SMTP config.
498 |
499 | #### Parameters
500 |
501 | | Name | Type | Required | Description |
502 | | ---------------- | ------ | -------- | ---------------------------------- |
503 | | id | String | yes | message ID |
504 | | config | Object | yes | SMTP configuration |
505 | | config.host | String | yes | SMTP host |
506 | | config.port | String | yes | SMTP port |
507 | | config.email | String | yes | recipient email |
508 | | config.username | String | no | SMTP username |
509 | | config.password | String | no | SMTP password |
510 | | config.mechanism | String | no | SMTP auth type (PLAIN or CRAM-MD5) |
511 |
512 | #### Returns
513 |
514 | Returns a `Promise` that resolves with an
515 | [http.IncomingMessage](https://nodejs.org/api/http.html#http_class_http_incomingmessage)
516 | object.
517 |
518 | #### Example
519 |
520 | ```js
521 | async function example() {
522 | const result = await mailhog.latestTo('test@example.org')
523 |
524 | const response = await mailhog.releaseMessage(result.ID, {
525 | host: 'localhost',
526 | port: '1025',
527 | email: 'test@example.org'
528 | })
529 | }
530 | ```
531 |
532 | ### deleteMessage
533 |
534 | ```
535 | mailhog.deleteMessage(id) → Promise
536 | ```
537 |
538 | #### Description
539 |
540 | Deletes the mail with the given ID from MailHog.
541 |
542 | #### Parameters
543 |
544 | | Name | Type | Required | Description |
545 | | ---- | ------ | -------- | ----------- |
546 | | id | String | yes | message ID |
547 |
548 | #### Returns
549 |
550 | Returns a `Promise` that resolves with an
551 | [http.IncomingMessage](https://nodejs.org/api/http.html#http_class_http_incomingmessage)
552 | object.
553 |
554 | #### Example
555 |
556 | ```js
557 | async function example() {
558 | const result = await mailhog.latestTo('test@example.org')
559 |
560 | const response = await mailhog.deleteMessage(result.ID)
561 |
562 | console.log('Status code: ', response.statusCode)
563 | }
564 | ```
565 |
566 | ### deleteAll
567 |
568 | ```
569 | mailhog.deleteAll() → Promise
570 | ```
571 |
572 | #### Description
573 |
574 | Deletes all mails stored in MailHog.
575 |
576 | #### Parameters
577 |
578 | None
579 |
580 | #### Returns
581 |
582 | Returns a `Promise` that resolves with an
583 | [http.IncomingMessage](https://nodejs.org/api/http.html#http_class_http_incomingmessage)
584 | object.
585 |
586 | #### Example
587 |
588 | ```js
589 | async function example() {
590 | const response = await mailhog.deleteAll()
591 |
592 | console.log('Status code: ', response.statusCode)
593 | }
594 | ```
595 |
596 | ### encode
597 |
598 | ```
599 | mailhog.encode(str, encoding, charset, lineLength) → String
600 | ```
601 |
602 | #### Description
603 |
604 | Encodes a String in the given charset to base64 or quoted-printable encoding.
605 |
606 | #### Parameters
607 |
608 | | Name | Type | Required | Default | Description |
609 | | ---------- | ------ | -------- | ------- | --------------------------- |
610 | | str | String | yes | | String to encode |
611 | | encoding | String | yes | utf8 | base64/quoted-printable |
612 | | charset | String | no | utf8 | Charset of the input string |
613 | | lineLength | Number | no | 76 | Soft line break limit |
614 |
615 | #### Returns
616 |
617 | Returns a `String` in the target encoding.
618 |
619 | #### Example
620 |
621 | ```js
622 | const query = mailhog.encode('üäö', 'quoted-printable')
623 | // =C3=BC=C3=A4=C3=B6
624 |
625 | async function example() {
626 | // Search for "üäö" in quoted-printable encoding:
627 | const result = await mailhog.search(query)
628 | }
629 | ```
630 |
631 | ### decode
632 |
633 | ```
634 | mailhog.decode(str, encoding, charset) → String
635 | ```
636 |
637 | #### Description
638 |
639 | Decodes a String from the given encoding and outputs it in the given charset.
640 |
641 | #### Parameters
642 |
643 | | Name | Type | Required | Default | Description |
644 | | -------- | ------ | -------- | ------- | ----------------------------- |
645 | | str | String | yes | | String to decode |
646 | | encoding | String | yes | | base64/quoted-printable |
647 | | charset | String | no | utf8 | Charset to use for the output |
648 |
649 | #### Returns
650 |
651 | Returns a `String` in the target charset.
652 |
653 | #### Example
654 |
655 | ```js
656 | const output = mailhog.decode('5pel5pys', 'base64')
657 | // 日本
658 | ```
659 |
660 | ## Testing
661 |
662 | 1. Start [Docker](https://docs.docker.com/).
663 | 2. Install development dependencies:
664 | ```sh
665 | npm install
666 | ```
667 | 3. Run the tests:
668 | ```sh
669 | npm test
670 | ```
671 |
672 | ## License
673 |
674 | Released under the [MIT license](https://opensource.org/licenses/MIT).
675 |
676 | ## Author
677 |
678 | [Sebastian Tschan](https://blueimp.net/)
679 |
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3.7'
2 | services:
3 | mailhog:
4 | image: blueimp/mailhog
5 | read_only: true
6 | test:
7 | build: .
8 | command: index.test.js
9 | read_only: true
10 | environment:
11 | - WAIT_FOR_HOSTS=mailhog:1025
12 | - MAILHOG_HOST=mailhog
13 | volumes:
14 | - .:/opt:ro
15 | depends_on:
16 | - mailhog
17 |
--------------------------------------------------------------------------------
/index.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | export = mailhog;
3 | /**
4 | * Returns the mailhog API interface.
5 | *
6 | * @param {Options} [options] API options
7 | * @returns {API} API object
8 | */
9 | declare function mailhog(options?: Options): API;
10 | declare namespace mailhog {
11 | export { Attachment, MIME, Message, Messages, Options, API, SMTPConfig };
12 | }
13 | /**
14 | * API options
15 | */
16 | type Options = {
17 | /**
18 | * API protocol
19 | */
20 | protocol?: string;
21 | /**
22 | * API host
23 | */
24 | host?: string;
25 | /**
26 | * API port
27 | */
28 | port?: number;
29 | /**
30 | * API basic authentication
31 | */
32 | auth?: string;
33 | /**
34 | * API base path
35 | */
36 | basePath?: string;
37 | };
38 | type API = {
39 | /**
40 | * API options
41 | */
42 | options: Options;
43 | /**
44 | * Gets all messages
45 | */
46 | messages: typeof messages;
47 | /**
48 | * Gets messages matching a query
49 | */
50 | search: typeof search;
51 | /**
52 | * Gets latest message from sender
53 | */
54 | latestFrom: typeof latestFrom;
55 | /**
56 | * Gets latest message to recipient
57 | */
58 | latestTo: typeof latestTo;
59 | /**
60 | * Gets latest with content
61 | */
62 | latestContaining: typeof latestContaining;
63 | /**
64 | * Releases given message
65 | */
66 | releaseMessage: typeof releaseMessage;
67 | /**
68 | * Deletes given message
69 | */
70 | deleteMessage: typeof deleteMessage;
71 | /**
72 | * Deletes all messages
73 | */
74 | deleteAll: typeof deleteAll;
75 | /**
76 | * Encodes given content
77 | */
78 | encode: typeof encode;
79 | /**
80 | * Decodes given content
81 | */
82 | decode: typeof decode;
83 | };
84 | type Attachment = {
85 | /**
86 | * Filename
87 | */
88 | name: string;
89 | /**
90 | * Content-Type
91 | */
92 | type: string;
93 | /**
94 | * Content-Transfer-Encoding
95 | */
96 | encoding: string;
97 | /**
98 | * Encoded content
99 | */
100 | Body: string;
101 | /**
102 | * Encoded headers
103 | */
104 | Headers: Array;
105 | };
106 | type MIME = {
107 | /**
108 | * Attachment parts
109 | */
110 | Parts: Array;
111 | };
112 | type Message = {
113 | /**
114 | * Message ID
115 | */
116 | ID: string;
117 | /**
118 | * Decoded mail text content
119 | */
120 | text: string;
121 | /**
122 | * Decoded mail HTML content
123 | */
124 | html: string;
125 | /**
126 | * Decoded mail Subject header
127 | */
128 | subject: string;
129 | /**
130 | * Decoded mail From header
131 | */
132 | from: string;
133 | /**
134 | * Decoded mail To header
135 | */
136 | to: string;
137 | /**
138 | * Decoded mail Cc header
139 | */
140 | cc: string;
141 | /**
142 | * Decoded mail Bcc header
143 | */
144 | bcc: string;
145 | /**
146 | * Decoded mail Reply-To header
147 | */
148 | replyTo: string;
149 | /**
150 | * Mail Date header
151 | */
152 | date: Date;
153 | /**
154 | * Mail Delivery-Date header
155 | */
156 | deliveryDate: Date;
157 | /**
158 | * List of mail attachments
159 | */
160 | attachments: Array;
161 | /**
162 | * Mail Created property
163 | */
164 | Created: string;
165 | /**
166 | * Mail Mime property
167 | */
168 | MIME: MIME;
169 | };
170 | type Messages = {
171 | /**
172 | * Number of results available
173 | */
174 | total: number;
175 | /**
176 | * Number of results returned
177 | */
178 | count: number;
179 | /**
180 | * Offset for the range of results returned
181 | */
182 | start: number;
183 | /**
184 | * List of mail object items
185 | */
186 | items: Array;
187 | };
188 | type SMTPConfig = {
189 | /**
190 | * SMTP host
191 | */
192 | host: string;
193 | /**
194 | * SMTP port
195 | */
196 | port: string;
197 | /**
198 | * recipient email
199 | */
200 | email: string;
201 | /**
202 | * SMTP username
203 | */
204 | username?: string;
205 | /**
206 | * SMTP password
207 | */
208 | password?: string;
209 | /**
210 | * SMTP auth mechanism (PLAIN or CRAM-MD5)
211 | */
212 | mechanism?: string;
213 | };
214 | /**
215 | * Requests mail objects from the MailHog API.
216 | *
217 | * @param {number} [start=0] defines the offset for the messages query
218 | * @param {number} [limit=50] defines the max number of results
219 | * @returns {Promise} resolves with object listing the mail items
220 | */
221 | declare function messages(start?: number, limit?: number): Promise;
222 | /**
223 | * Sends a search request to the MailHog API.
224 | *
225 | * @param {string} query search query
226 | * @param {string} [kind=containing] query kind, can be from|to|containing
227 | * @param {number} [start=0] defines the offset for the search query
228 | * @param {number} [limit=50] defines the max number of results
229 | * @returns {Promise} resolves with object listing the mail items
230 | */
231 | declare function search(query: string, kind?: string, start?: number, limit?: number): Promise;
232 | /**
233 | * Sends a search request for the latest mail matching the "from" query.
234 | *
235 | * @param {string} query from address
236 | * @returns {Promise} resolves latest mail object for the "from" query
237 | */
238 | declare function latestFrom(query: string): Promise;
239 | /**
240 | * Sends a search request for the latest mail matching the "to" query.
241 | *
242 | * @param {string} query to address
243 | * @returns {Promise} resolves latest mail object for the "to" query
244 | */
245 | declare function latestTo(query: string): Promise;
246 | /**
247 | * Sends a search request for the latest mail matching the "containing" query.
248 | *
249 | * @param {string} query search query
250 | * @returns {Promise} resolves latest mail object "containing" query
251 | */
252 | declare function latestContaining(query: string): Promise;
253 | /**
254 | * Releases the mail with the given ID using the provided SMTP config.
255 | *
256 | * @param {string} id message ID
257 | * @param {SMTPConfig} config SMTP configuration
258 | * @returns {Promise} resolves with http.IncomingMessage
259 | */
260 | declare function releaseMessage(id: string, config: SMTPConfig): Promise;
261 | /**
262 | * Deletes the mail with the given ID from MailHog.
263 | *
264 | * @param {string} id message ID
265 | * @returns {Promise} resolves with http.IncomingMessage
266 | */
267 | declare function deleteMessage(id: string): Promise;
268 | /**
269 | * Deletes all mails stored in MailHog.
270 | *
271 | * @returns {Promise} resolves with http.IncomingMessage
272 | */
273 | declare function deleteAll(): Promise;
274 | /**
275 | * Encodes a String in the given charset to base64 or quoted-printable encoding.
276 | *
277 | * @param {string} str String to encode
278 | * @param {string} [encoding] base64|quoted-printable
279 | * @param {string} [charset=utf8] Charset of the input string
280 | * @param {number} [lineLength=76] Soft line break limit
281 | * @returns {string} Encoded String
282 | */
283 | declare function encode(str: string, encoding?: string, charset?: string, lineLength?: number): string;
284 | /**
285 | * Decodes a String from the given encoding and outputs it in the given charset.
286 | *
287 | * @param {string} str String to decode
288 | * @param {string} [encoding=utf8] input encoding, e.g. base64|quoted-printable
289 | * @param {string} [charset=utf8] Charset to use for the output
290 | * @returns {string} Decoded String
291 | */
292 | declare function decode(str: string, encoding?: string, charset?: string): string;
293 | import http = require("http");
294 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | /*
2 | * NodeJS library to interact with the MailHog API.
3 | * https://github.com/blueimp/mailhog-node
4 | *
5 | * Copyright 2016, Sebastian Tschan
6 | * https://blueimp.net
7 | *
8 | * Licensed under the MIT license:
9 | * https://opensource.org/licenses/MIT
10 | */
11 |
12 | 'use strict'
13 |
14 | /**
15 | * @typedef {object} Attachment
16 | * @property {string} name Filename
17 | * @property {string} type Content-Type
18 | * @property {string} encoding Content-Transfer-Encoding
19 | * @property {string} Body Encoded content
20 | * @property {Array} Headers Encoded headers
21 | */
22 |
23 | /**
24 | * @typedef {object} MIME
25 | * @property {Array} Parts Attachment parts
26 | */
27 |
28 | /**
29 | * @typedef {object} Message
30 | * @property {string} ID Message ID
31 | * @property {string} text Decoded mail text content
32 | * @property {string} html Decoded mail HTML content
33 | * @property {string} subject Decoded mail Subject header
34 | * @property {string} from Decoded mail From header
35 | * @property {string} to Decoded mail To header
36 | * @property {string} cc Decoded mail Cc header
37 | * @property {string} bcc Decoded mail Bcc header
38 | * @property {string} replyTo Decoded mail Reply-To header
39 | * @property {Date} date Mail Date header
40 | * @property {Date} deliveryDate Mail Delivery-Date header
41 | * @property {Array} attachments List of mail attachments
42 | * @property {string} Created Mail Created property
43 | * @property {MIME} MIME Mail Mime property
44 | */
45 |
46 | /**
47 | * @typedef {object} Messages
48 | * @property {number} total Number of results available
49 | * @property {number} count Number of results returned
50 | * @property {number} start Offset for the range of results returned
51 | * @property {Array} items List of mail object items
52 | */
53 |
54 | /**
55 | * @typedef {object} Options API options
56 | * @property {string} [protocol="http:"] API protocol
57 | * @property {string} [host=localhost] API host
58 | * @property {number} [port=8025] API port
59 | * @property {string} [auth] API basic authentication
60 | * @property {string} [basePath="/api"] API base path
61 | */
62 |
63 | /* eslint-disable jsdoc/valid-types */
64 |
65 | /**
66 | * @typedef {object} API
67 | * @property {Options} options API options
68 | * @property {typeof messages} messages Gets all messages
69 | * @property {typeof search} search Gets messages matching a query
70 | * @property {typeof latestFrom} latestFrom Gets latest message from sender
71 | * @property {typeof latestTo} latestTo Gets latest message to recipient
72 | * @property {typeof latestContaining} latestContaining Gets latest with content
73 | * @property {typeof releaseMessage} releaseMessage Releases given message
74 | * @property {typeof deleteMessage} deleteMessage Deletes given message
75 | * @property {typeof deleteAll} deleteAll Deletes all messages
76 | * @property {typeof encode} encode Encodes given content
77 | * @property {typeof decode} decode Decodes given content
78 | */
79 |
80 | /* eslint-enable jsdoc/valid-types */
81 |
82 | /**
83 | * @typedef {object} SMTPConfig
84 | * @property {string} host SMTP host
85 | * @property {string} port SMTP port
86 | * @property {string} email recipient email
87 | * @property {string} [username] SMTP username
88 | * @property {string} [password] SMTP password
89 | * @property {string} [mechanism] SMTP auth mechanism (PLAIN or CRAM-MD5)
90 | */
91 |
92 | /* global BufferEncoding */
93 |
94 | const http = require('http')
95 | const https = require('https')
96 | const libqp = require('./libqp')
97 |
98 | /**
99 | * Adds soft line breaks to a given String
100 | *
101 | * @param {string} str String to wrap
102 | * @param {number} [lineLength=76] Maximum allowed length for a line
103 | * @returns {string} Soft-wrapped String using `\r\n` as line breaks
104 | */
105 | function wrap(str, lineLength) {
106 | const maxLength = lineLength || 76
107 | const lines = Math.ceil(str.length / maxLength)
108 | let output = ''
109 | for (let i = 0, offset = 0; i < lines; ++i, offset += maxLength) {
110 | output += str.substr(offset, maxLength) + '\r\n'
111 | }
112 | return output.trim()
113 | }
114 |
115 | /**
116 | * Encodes a String in the given charset to base64 or quoted-printable encoding.
117 | *
118 | * @param {string} str String to encode
119 | * @param {string} [encoding] base64|quoted-printable
120 | * @param {string} [charset=utf8] Charset of the input string
121 | * @param {number} [lineLength=76] Soft line break limit
122 | * @returns {string} Encoded String
123 | */
124 | function encode(str, encoding, charset, lineLength) {
125 | const maxLength = lineLength === undefined ? 76 : lineLength
126 | const outputEncoding = encoding && encoding.toLowerCase()
127 | let output = str
128 | if (outputEncoding === 'quoted-printable' || outputEncoding === 'base64') {
129 | const isUTF8Input = !charset || /^utf-?8$/.test(charset.toLowerCase())
130 | let buffer
131 | if (isUTF8Input) {
132 | buffer = Buffer.from(str)
133 | } else {
134 | buffer = require('iconv-lite').encode(str, charset)
135 | }
136 | if (outputEncoding === 'quoted-printable') {
137 | const output = libqp.encode(buffer)
138 | return maxLength ? libqp.wrap(output, maxLength) : output
139 | }
140 | output = buffer.toString('base64')
141 | }
142 | return maxLength ? wrap(output, maxLength) : output
143 | }
144 |
145 | /**
146 | * Decodes a String from the given encoding and outputs it in the given charset.
147 | *
148 | * @param {string} str String to decode
149 | * @param {string} [encoding=utf8] input encoding, e.g. base64|quoted-printable
150 | * @param {string} [charset=utf8] Charset to use for the output
151 | * @returns {string} Decoded String
152 | */
153 | function decode(str, encoding, charset) {
154 | const inputEncoding = encoding && encoding.toLowerCase()
155 | const utf8Regexp = /^utf-?8$/
156 | const isUTF8Input = !inputEncoding || utf8Regexp.test(inputEncoding)
157 | const isUTF8Output = !charset || utf8Regexp.test(charset.toLowerCase())
158 | if (isUTF8Input && isUTF8Output) return str
159 | // 7bit|8bit|binary are not encoded, x-token has an unknown encoding, see:
160 | // https://www.w3.org/Protocols/rfc1341/5_Content-Transfer-Encoding.html
161 | if (/^(7|8)bit|binary|x-.+$/.test(inputEncoding)) return str
162 | let buffer
163 | if (inputEncoding === 'quoted-printable') {
164 | buffer = libqp.decode(str)
165 | } else {
166 | buffer = Buffer.from(
167 | str,
168 | /** @type {BufferEncoding} */
169 | (inputEncoding)
170 | )
171 | }
172 | if (isUTF8Output) return buffer.toString()
173 | return require('iconv-lite').decode(buffer, charset)
174 | }
175 |
176 | /**
177 | * Returns the content part matching the given content-type regular expression.
178 | *
179 | * @param {object} mail MailHog mail object
180 | * @param {RegExp} typeRegExp Regular expression matching the content-type
181 | * @returns {string} Decoded content with a type matching the content-type
182 | */
183 | function getContent(mail, typeRegExp) {
184 | let parts = [mail.Content]
185 | if (mail.MIME) parts = parts.concat(mail.MIME.Parts)
186 | for (const part of parts) {
187 | const type = (part.Headers['Content-Type'] || '').toString()
188 | if (typeRegExp.test(type)) {
189 | const match = /\bcharset=([\w_-]+)(?:;|$)/.exec(type)
190 | const charset = match ? match[1] : undefined
191 | return decode(
192 | part.Body,
193 | (part.Headers['Content-Transfer-Encoding'] || '').toString(),
194 | charset
195 | )
196 | }
197 | }
198 | }
199 |
200 | /**
201 | * Matches encoded Strings in mail headers and returns decoded content.
202 | *
203 | * @param {string} _ Matched substring (unused)
204 | * @param {string} charset Charset to use for the output
205 | * @param {string} encoding B|Q, which stands for base64 or quoted-printable
206 | * @param {string} data Encoded String data
207 | * @returns {string} Decoded header content
208 | */
209 | function headerDecoder(_, charset, encoding, data) {
210 | switch (encoding) {
211 | case 'b':
212 | case 'B':
213 | return decode(data, 'base64', charset)
214 | case 'q':
215 | case 'Q':
216 | return decode(data, 'quoted-printable', charset)
217 | }
218 | }
219 |
220 | /**
221 | * Returns header content for the given mail object and header key.
222 | *
223 | * @param {object} mail MailHog mail object
224 | * @param {string} key Header key
225 | * @returns {string} Header content
226 | */
227 | function getHeader(mail, key) {
228 | const header = (mail.Content || mail).Headers[key]
229 | if (!header || !header.length) return
230 | // Encoded header parts have the following form:
231 | // =?charset?encoding?data?=
232 | return header[0].replace(/=\?([^?]+)\?([BbQq])\?([^?]+)\?=/g, headerDecoder)
233 | }
234 |
235 | /**
236 | * Memoized getter for mail text content.
237 | *
238 | * @this Message
239 | * @returns {string} Decoded mail text content
240 | */
241 | function getText() {
242 | delete this.text
243 | return (this.text = getContent(this, /^text\/plain($|;)/i))
244 | }
245 |
246 | /**
247 | * Memoized getter for mail HTML content.
248 | *
249 | * @this Message
250 | * @returns {string} Decoded mail HTML content
251 | */
252 | function getHTML() {
253 | delete this.html
254 | return (this.html = getContent(this, /^text\/html($|;)/i))
255 | }
256 |
257 | /**
258 | * Memoized getter for mail Subject header.
259 | *
260 | * @this Message
261 | * @returns {string} Decoded mail Subject header
262 | */
263 | function getSubject() {
264 | delete this.subject
265 | return (this.subject = getHeader(this, 'Subject'))
266 | }
267 |
268 | /**
269 | * Memoized getter for mail From header.
270 | *
271 | * @this Message
272 | * @returns {string} Decoded mail From header
273 | */
274 | function getFrom() {
275 | delete this.from
276 | return (this.from = getHeader(this, 'From'))
277 | }
278 |
279 | /**
280 | * Memoized getter for mail To header.
281 | *
282 | * @this Message
283 | * @returns {string} Decoded mail To header
284 | */
285 | function getTo() {
286 | delete this.to
287 | return (this.to = getHeader(this, 'To'))
288 | }
289 |
290 | /**
291 | * Memoized getter for mail Cc header.
292 | *
293 | * @this Message
294 | * @returns {string} Decoded mail Cc header
295 | */
296 | function getCc() {
297 | delete this.cc
298 | return (this.cc = getHeader(this, 'Cc'))
299 | }
300 |
301 | /**
302 | * Memoized getter for mail Bcc header.
303 | *
304 | * @this Message
305 | * @returns {string} Decoded mail Bcc header
306 | */
307 | function getBcc() {
308 | delete this.bcc
309 | return (this.bcc = getHeader(this, 'Bcc'))
310 | }
311 |
312 | /**
313 | * Memoized getter for mail Reply-To header.
314 | *
315 | * @this Message
316 | * @returns {string} Decoded mail Reply-To header
317 | */
318 | function getReplyTo() {
319 | delete this.replyTo
320 | return (this.replyTo = getHeader(this, 'Reply-To'))
321 | }
322 |
323 | /**
324 | * Memoized getter for mail Date header.
325 | *
326 | * @this Message
327 | * @returns {Date} Mail Date header
328 | */
329 | function getDate() {
330 | delete this.date
331 | const dateString = getHeader(this, 'Date')
332 | if (dateString) this.date = new Date(Date.parse(dateString))
333 | return this.date
334 | }
335 |
336 | /**
337 | * Memoized getter for mail Delivery-Date header.
338 | *
339 | * @this Message
340 | * @returns {Date} Mail Delivery-Date header
341 | */
342 | function getDeliveryDate() {
343 | delete this.deliveryDate
344 | // MailHog does not set the Delivery-Date header, but it sets a Created
345 | // property that serves the same purpose (delivery date to application):
346 | return (this.deliveryDate = new Date(Date.parse(this.Created)))
347 | }
348 |
349 | /**
350 | * Memoized getter for mail Content-Type header.
351 | *
352 | * @this Attachment
353 | * @returns {string} Decoded mail Content-Type header
354 | */
355 | function getContentType() {
356 | delete this.type
357 | return (this.type = getHeader(this, 'Content-Type'))
358 | }
359 |
360 | /**
361 | * Memoized getter for mail Content-Transfer-Encoding header.
362 | *
363 | * @this Attachment
364 | * @returns {string} Decoded mail Content-Transfer-Encoding header
365 | */
366 | function getContentTransferEncoding() {
367 | delete this.encoding
368 | return (this.encoding = getHeader(this, 'Content-Transfer-Encoding'))
369 | }
370 |
371 | /**
372 | * Memoized getter for mail attachments.
373 | *
374 | * @this Message
375 | * @returns {Array} List of mail attachments
376 | */
377 | function getAttachments() {
378 | delete this.attachments
379 | const attachments = []
380 | if (this.MIME && this.MIME.Parts) {
381 | for (const part of this.MIME.Parts) {
382 | const match = /^attachment;\s*filename="?([^"]+)"?$/.exec(
383 | part.Headers['Content-Disposition']
384 | )
385 | if (!match) continue
386 | part.name = match[1]
387 | Object.defineProperty(part, 'type', {
388 | get: getContentType,
389 | configurable: true
390 | })
391 | Object.defineProperty(part, 'encoding', {
392 | get: getContentTransferEncoding,
393 | configurable: true
394 | })
395 | attachments.push(part)
396 | }
397 | }
398 | return (this.attachments = attachments)
399 | }
400 |
401 | /**
402 | * Injects convenience properties for each mail item in the given result.
403 | *
404 | * @param {object} result Result object for a MailHog API search/messages query
405 | * @returns {object} Result object with injected properties for each mail item
406 | */
407 | function injectProperties(result) {
408 | if (!result.count) return result
409 | for (const item of result.items) {
410 | // Define memoized getter for contents and headers:
411 | Object.defineProperty(item, 'text', { get: getText, configurable: true })
412 | Object.defineProperty(item, 'html', { get: getHTML, configurable: true })
413 | Object.defineProperty(item, 'subject', {
414 | get: getSubject,
415 | configurable: true
416 | })
417 | Object.defineProperty(item, 'from', { get: getFrom, configurable: true })
418 | Object.defineProperty(item, 'to', { get: getTo, configurable: true })
419 | Object.defineProperty(item, 'cc', { get: getCc, configurable: true })
420 | Object.defineProperty(item, 'bcc', { get: getBcc, configurable: true })
421 | Object.defineProperty(item, 'replyTo', {
422 | get: getReplyTo,
423 | configurable: true
424 | })
425 | Object.defineProperty(item, 'date', { get: getDate, configurable: true })
426 | Object.defineProperty(item, 'deliveryDate', {
427 | get: getDeliveryDate,
428 | configurable: true
429 | })
430 | Object.defineProperty(item, 'attachments', {
431 | get: getAttachments,
432 | configurable: true
433 | })
434 | }
435 | return result
436 | }
437 |
438 | /**
439 | * Sends a http.request and resolves with the parsed JSON response.
440 | *
441 | * @param {object} options http.request options
442 | * @param {string} [data] POST data
443 | * @returns {Promise} resolves with JSON or http.IncomingMessage if no body
444 | */
445 | function request(options, data) {
446 | const client = options.protocol === 'https:' ? https : http
447 | return new Promise((resolve, reject) => {
448 | const req = client
449 | .request(options, response => {
450 | let body = ''
451 | response
452 | .on('data', chunk => (body += chunk))
453 | .on('end', () => {
454 | if (!body) return resolve(response)
455 | try {
456 | resolve(JSON.parse(body))
457 | } catch (error) {
458 | reject(error)
459 | }
460 | })
461 | })
462 | .on('error', reject)
463 | if (data) req.write(data)
464 | req.end()
465 | })
466 | }
467 |
468 | /**
469 | * Requests mail objects from the MailHog API.
470 | *
471 | * @param {number} [start=0] defines the offset for the messages query
472 | * @param {number} [limit=50] defines the max number of results
473 | * @returns {Promise} resolves with object listing the mail items
474 | */
475 | function messages(start, limit) {
476 | let path = `${this.options.basePath}/v2/messages`
477 | if (start) path += `?start=${start}`
478 | if (limit) path += `${start ? '&' : '?'}limit=${limit}`
479 | const options = Object.assign({}, this.options, { path })
480 | return request(options).then(result => injectProperties(result))
481 | }
482 |
483 | /**
484 | * Sends a search request to the MailHog API.
485 | *
486 | * @param {string} query search query
487 | * @param {string} [kind=containing] query kind, can be from|to|containing
488 | * @param {number} [start=0] defines the offset for the search query
489 | * @param {number} [limit=50] defines the max number of results
490 | * @returns {Promise} resolves with object listing the mail items
491 | */
492 | function search(query, kind, start, limit) {
493 | const basePath = this.options.basePath
494 | const kindParam = kind || 'containing'
495 | const encodedQuery = encodeURIComponent(query)
496 | let path = `${basePath}/v2/search?kind=${kindParam}&query=${encodedQuery}`
497 | if (start) path += `&start=${start}`
498 | if (limit) path += `&limit=${limit}`
499 | const options = Object.assign({}, this.options, { path })
500 | return request(options).then(result => injectProperties(result))
501 | }
502 |
503 | /**
504 | * Sends a search request for the latest mail matching the "from" query.
505 | *
506 | * @param {string} query from address
507 | * @returns {Promise} resolves latest mail object for the "from" query
508 | */
509 | function latestFrom(query) {
510 | return this.search(query, 'from', 0, 1).then(
511 | result => result.count && result.items[0]
512 | )
513 | }
514 |
515 | /**
516 | * Sends a search request for the latest mail matching the "to" query.
517 | *
518 | * @param {string} query to address
519 | * @returns {Promise} resolves latest mail object for the "to" query
520 | */
521 | function latestTo(query) {
522 | return this.search(query, 'to', 0, 1).then(
523 | result => result.count && result.items[0]
524 | )
525 | }
526 |
527 | /**
528 | * Sends a search request for the latest mail matching the "containing" query.
529 | *
530 | * @param {string} query search query
531 | * @returns {Promise} resolves latest mail object "containing" query
532 | */
533 | function latestContaining(query) {
534 | return this.search(query, 'containing', 0, 1).then(
535 | result => result.count && result.items[0]
536 | )
537 | }
538 |
539 | /**
540 | * Releases the mail with the given ID using the provided SMTP config.
541 | *
542 | * @param {string} id message ID
543 | * @param {SMTPConfig} config SMTP configuration
544 | * @returns {Promise} resolves with http.IncomingMessage
545 | */
546 | function releaseMessage(id, config) {
547 | const basePath = this.options.basePath
548 | const options = Object.assign({}, this.options, {
549 | method: 'POST',
550 | path: `${basePath}/v1/messages/${encodeURIComponent(id)}/release`
551 | })
552 | return request(options, JSON.stringify(config))
553 | }
554 |
555 | /**
556 | * Deletes the mail with the given ID from MailHog.
557 | *
558 | * @param {string} id message ID
559 | * @returns {Promise} resolves with http.IncomingMessage
560 | */
561 | function deleteMessage(id) {
562 | const options = Object.assign({}, this.options, {
563 | method: 'DELETE',
564 | path: `${this.options.basePath}/v1/messages/${encodeURIComponent(id)}`
565 | })
566 | return request(options)
567 | }
568 |
569 | /**
570 | * Deletes all mails stored in MailHog.
571 | *
572 | * @returns {Promise} resolves with http.IncomingMessage
573 | */
574 | function deleteAll() {
575 | const options = Object.assign({}, this.options, {
576 | method: 'DELETE',
577 | path: `${this.options.basePath}/v1/messages`
578 | })
579 | return request(options)
580 | }
581 |
582 | /**
583 | * Returns the mailhog API interface.
584 | *
585 | * @param {Options} [options] API options
586 | * @returns {API} API object
587 | */
588 | function mailhog(options) {
589 | const api = {
590 | options: Object.assign({ port: 8025, basePath: '/api' }, options),
591 | encode,
592 | decode
593 | }
594 | return Object.assign(api, {
595 | messages: messages.bind(api),
596 | search: search.bind(api),
597 | latestFrom: latestFrom.bind(api),
598 | latestTo: latestTo.bind(api),
599 | latestContaining: latestContaining.bind(api),
600 | releaseMessage: releaseMessage.bind(api),
601 | deleteMessage: deleteMessage.bind(api),
602 | deleteAll: deleteAll.bind(api)
603 | })
604 | }
605 |
606 | module.exports = mailhog
607 |
--------------------------------------------------------------------------------
/index.test.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | /* global before, after, describe, it, BufferEncoding */
4 |
5 | /** @type {object} */
6 | const assert = require('assert')
7 | const path = require('path')
8 | const util = require('util')
9 | const exec = util.promisify(require('child_process').exec)
10 | const env = process.env
11 |
12 | const mailhog = require('.')({
13 | host: env.MAILHOG_HOST
14 | })
15 |
16 | /**
17 | * Sends all mail configured in the mail directory.
18 | *
19 | * @returns {Promise} Resolves when executing sucessfully, rejects otherwise
20 | */
21 | async function sendAllMail() {
22 | const sendmailScript = path.join(__dirname, 'sendmail.sh')
23 | await exec(`${sendmailScript} -S ${env.MAILHOG_HOST}:1025`)
24 | }
25 |
26 | /**
27 | * Deletes all mail from MailHog.
28 | *
29 | * @returns {Promise} Resolves when executing sucessfully, rejects otherwise
30 | */
31 | async function deleteAllMail() {
32 | const result = await mailhog.deleteAll()
33 | assert.strictEqual(result.statusCode, 200, 'Responds with status code 200')
34 | }
35 |
36 | before(sendAllMail)
37 | after(deleteAllMail)
38 |
39 | describe('encode', function () {
40 | it('quoted-printable encoding of utf8 string', function () {
41 | assert.strictEqual(
42 | mailhog.encode('üäö', 'quoted-printable'),
43 | '=C3=BC=C3=A4=C3=B6',
44 | 'Returns quoted-printable encoding of utf8 string'
45 | )
46 | })
47 |
48 | it('quoted-printable encoding of iso-8859-1 string', function () {
49 | assert.strictEqual(
50 | mailhog.encode('üäö', 'quoted-printable', 'iso-8859-1'),
51 | '=C3=BC=C3=A4=C3=B6',
52 | 'Returns quoted-printable encoding of iso-8859-1 string'
53 | )
54 | })
55 |
56 | it('quoted-printable encoding of long utf8 string', function () {
57 | assert.strictEqual(
58 | mailhog.encode('üäö'.repeat(10), 'quoted-printable', 'utf8'),
59 | [
60 | '=C3=BC=C3=A4=C3=B6'.repeat(4),
61 | '=C3=BC=C3=A4=C3=B6'.repeat(4),
62 | '=C3=BC=C3=A4=C3=B6'.repeat(2)
63 | ].join('=\r\n'),
64 | 'Returns wrapped quoted-printable encoding of utf8 string'
65 | )
66 | })
67 |
68 | it('quoted-printable encoding of utf8 string, linelength:10', function () {
69 | assert.strictEqual(
70 | mailhog.encode('üäöüäö', 'quoted-printable', 'utf8', 10),
71 | '=C3=BC=C3=\r\n=A4=C3=B6=\r\n=C3=BC=C3=\r\n=A4=C3=B6',
72 | 'Returns wrapped quoted-printable encoding of utf8 string'
73 | )
74 | })
75 |
76 | it('base64 encoding of utf8 string', function () {
77 | assert.strictEqual(
78 | mailhog.encode('üäö', 'base64'),
79 | 'w7zDpMO2',
80 | 'Returns base64 encoding of utf8 string'
81 | )
82 | })
83 |
84 | it('base64 encoding of iso-8859-1 string', function () {
85 | assert.strictEqual(
86 | mailhog.encode('üäö', 'base64', 'iso-8859-1'),
87 | 'w7zDpMO2',
88 | 'Returns base64 encoding of iso-8859-1 string'
89 | )
90 | })
91 |
92 | it('base64 encoding of long utf8 string', function () {
93 | assert.strictEqual(
94 | mailhog.encode('üäö'.repeat(10), 'base64', 'utf8'),
95 | 'w7zDpMO2'.repeat(9) + 'w7zD\r\npMO2',
96 | 'Returns wrapped base64 encoding of utf8 string'
97 | )
98 | })
99 |
100 | it('base64 encoding of utf8 string, linelength:10', function () {
101 | assert.strictEqual(
102 | mailhog.encode('üäöüäö', 'base64', 'utf8', 10),
103 | 'w7zDpMO2w7\r\nzDpMO2',
104 | 'Returns wrapped base64 encoding of utf8 string'
105 | )
106 | })
107 | })
108 |
109 | describe('decode', function () {
110 | it('quoted-printable decoding to utf8 string', function () {
111 | assert.strictEqual(
112 | mailhog.decode('=C3=BC=C3=A4=C3=B6', 'quoted-printable'),
113 | 'üäö',
114 | 'Returns utf8 string from quoted-printable input string'
115 | )
116 | })
117 |
118 | it('quoted-printable decoding to iso-8859-1 string', function () {
119 | assert.strictEqual(
120 | mailhog.decode('=C3=BC=C3=A4=C3=B6', 'quoted-printable', 'iso-8859-1'),
121 | 'üäö',
122 | 'Returns iso-8859-1 string from quoted-printable input string'
123 | )
124 | })
125 |
126 | it('quoted-printable decoding of wrapped string to utf8 string', function () {
127 | assert.strictEqual(
128 | mailhog.decode(
129 | [
130 | '=C3=BC=C3=A4=C3=B6'.repeat(4),
131 | '=C3=BC=C3=A4=C3=B6'.repeat(4),
132 | '=C3=BC=C3=A4=C3=B6'.repeat(2)
133 | ].join('=\r\n'),
134 | 'quoted-printable'
135 | ),
136 | 'üäö'.repeat(10),
137 | 'Returns utf8 string from wrapped quoted-printable input string'
138 | )
139 | })
140 |
141 | it('base64 decoding to utf8 string', function () {
142 | assert.strictEqual(
143 | mailhog.decode('w7zDpMO2', 'base64'),
144 | 'üäö',
145 | 'Returns utf8 string from base64 input string'
146 | )
147 | })
148 |
149 | it('base64 decoding to iso-8859-1 string', function () {
150 | assert.strictEqual(
151 | mailhog.decode('w7zDpMO2', 'base64', 'iso-8859-1'),
152 | 'üäö',
153 | 'Returns iso-8859-1 string from base64 input string'
154 | )
155 | })
156 |
157 | it('base64 decoding of wrapped string to utf8 string', function () {
158 | assert.strictEqual(
159 | mailhog.decode('w7zDpMO2'.repeat(9) + 'w7zD\r\npMO2', 'base64'),
160 | 'üäö'.repeat(10),
161 | 'Returns utf8 string from wrapped base64 input string'
162 | )
163 | })
164 | })
165 |
166 | describe('multipart', function () {
167 | it('parses quoted-printable encoded text content', async function () {
168 | const result = await mailhog.latestTo('ueaeoe@example.org')
169 | assert.strictEqual(result.text, 'ü\r\näö', 'Returns plain text content')
170 | })
171 |
172 | it('parses quoted-printable encoded HTML content', async function () {
173 | const result = await mailhog.latestTo('ueaeoe@example.org')
174 | assert.strictEqual(
175 | result.html,
176 | 'ü
äö',
177 | 'Returns HTML content'
178 | )
179 | })
180 |
181 | it('parses attachments', async function () {
182 | const result = await mailhog.latestTo('ueaeoe@example.org')
183 | assert.strictEqual(result.attachments.length, 2, 'Returns attachments')
184 | assert.strictEqual(result.attachments[0].name, 'black-80x60.gif')
185 | assert.strictEqual(result.attachments[0].type, 'image/gif')
186 | assert.strictEqual(
187 | Buffer.from(
188 | result.attachments[0].Body,
189 | /** @type {BufferEncoding} */
190 | (result.attachments[0].encoding)
191 | ).toString('base64'),
192 | 'R0lGODdhUAA8AIABAAAAAP///ywAAAAAUAA8AAACS4SPqcvtD6OctNqLs968+w+G4kiW5o' +
193 | 'mm6sq27gvH8kzX9o3n+s73/g8MCofEovGITCqXzKbzCY1Kp9Sq9YrNarfcrvcLDovH5P' +
194 | 'KsAAA7'
195 | )
196 | assert.strictEqual(result.attachments[1].name, 'white-2x1.jpg')
197 | assert.strictEqual(result.attachments[1].type, 'image/jpeg')
198 | assert.strictEqual(
199 | Buffer.from(
200 | result.attachments[1].Body,
201 | /** @type {BufferEncoding} */
202 | (result.attachments[1].encoding)
203 | ).toString('base64'),
204 | '/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAASUkqAAgAAAABABIBAwABAAAABgASAA' +
205 | 'AAAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNBAQAAAAAAA8cAgUACm9iamVjdG5hbWUA/9' +
206 | 'sAQwABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQ' +
207 | 'EBAQEBAQEBAQEBAQEBAQEB/9sAQwEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQ' +
208 | 'EBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB/8AAEQgAAQACAwEiAAIRAQ' +
209 | 'MRAf/EAB8AAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKC//EALUQAAIBAwMCBAMFBQ' +
210 | 'QEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJS' +
211 | 'YnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiY' +
212 | 'qSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5e' +
213 | 'bn6Onq8fLz9PX29/j5+v/EAB8BAAMBAQEBAQEBAQEAAAAAAAABAgMEBQYHCAkKC//EAL' +
214 | 'URAAIBAgQEAwQHBQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM1LwFW' +
215 | 'Jy0QoWJDThJfEXGBkaJicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdH' +
216 | 'V2d3h5eoKDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJyt' +
217 | 'LT1NXW19jZ2uLj5OXm5+jp6vLz9PX29/j5+v/aAAwDAQACEQMRAD8A/v4ooooA/9k='
218 | )
219 | })
220 | })
221 |
222 | describe('charset', function () {
223 | it('parses mail with utf8 charset', async function () {
224 | const result = await mailhog.latestTo('nihon@example.org')
225 | assert.strictEqual(result.text, '日本\n', 'Parses mail with utf8 charset')
226 | })
227 |
228 | it('parses mail with ISO-8859-1 charset', async function () {
229 | const result = await mailhog.latestTo('iso-8859-1@example.org')
230 | assert.strictEqual(result.text, 'üäö', 'Returns plain text content')
231 | })
232 |
233 | it('parses mail without charset definition', async function () {
234 | const result = await mailhog.latestTo('no-charset@example.org')
235 | assert.strictEqual(
236 | result.text,
237 | 'text content',
238 | 'Returns plain text content'
239 | )
240 | })
241 | })
242 |
243 | describe('headers', function () {
244 | it('parses the mail Cc header', async function () {
245 | const result = await mailhog.latestTo('nihon@example.org')
246 | assert.strictEqual(
247 | result.cc,
248 | '日本 ',
249 | 'Returns the decoded mail Cc header'
250 | )
251 | })
252 |
253 | it('parses the mail Bcc header', async function () {
254 | const result = await mailhog.latestTo('nihon@example.org')
255 | assert.strictEqual(
256 | result.bcc,
257 | '日本 ',
258 | 'Returns the decoded mail Bcc header'
259 | )
260 | })
261 |
262 | it('parses the mail Reply-To header', async function () {
263 | const result = await mailhog.latestTo('nihon@example.org')
264 | assert.strictEqual(
265 | result.replyTo,
266 | '日本 ',
267 | 'Returns the decoded mail Reply-To header'
268 | )
269 | })
270 |
271 | it('parses the mail Date header', async function () {
272 | const result = await mailhog.latestTo('nihon@example.org')
273 | assert.ok(
274 | result.deliveryDate instanceof Date,
275 | 'Returns mail Date header as Date object'
276 | )
277 | assert.strictEqual(
278 | result.date.getTime(),
279 | Date.parse('2016-10-23T18:59:40.000Z'),
280 | 'Returns mail Date header as defined in the composed mail'
281 | )
282 | })
283 |
284 | it('parses the mail Delivery-Date header', async function () {
285 | const result = await mailhog.latestTo('nihon@example.org')
286 | assert.ok(
287 | result.deliveryDate instanceof Date,
288 | 'Returns mail Delivery-Date header as Date object'
289 | )
290 | assert.ok(
291 | result.deliveryDate > result.date,
292 | 'Returns mail with Delivery-Date later than Date'
293 | )
294 | })
295 | })
296 |
297 | describe('messages', function () {
298 | it('retrieve mails', async function () {
299 | const result = await mailhog.messages()
300 | assert.strictEqual(result.count, 4, 'Returns all emails')
301 | assert.strictEqual(
302 | result.items[0].subject,
303 | 'Mail without charset',
304 | 'Returns the decoded mail Subject header for the first mail in the set'
305 | )
306 | assert.strictEqual(
307 | result.items[1].subject,
308 | 'ISO-8859-1',
309 | 'Returns the decoded mail Subject header for the second mail in the set'
310 | )
311 | assert.strictEqual(
312 | result.items[2].subject,
313 | '日本',
314 | 'Returns the decoded mail Subject header for the third mail in the set'
315 | )
316 | assert.strictEqual(
317 | result.items[3].subject,
318 | 'üäö',
319 | 'Returns the decoded mail Subject header for the fourth mail in the set'
320 | )
321 | })
322 |
323 | it('limit the messages range', async function () {
324 | const result = await mailhog.messages(3, 1)
325 | assert.strictEqual(result.count, 1, 'Returns a set for the given range')
326 | assert.strictEqual(
327 | result.items[0].subject,
328 | 'üäö',
329 | 'Returns the decoded mail Subject header for mail from the given range'
330 | )
331 | })
332 | })
333 |
334 | describe('search', function () {
335 | it('search mails containing the query', async function () {
336 | const result = await mailhog.search(
337 | mailhog.encode('üäö', 'quoted-printable')
338 | )
339 | assert.strictEqual(result.count, 1, 'Returns a list of matching emails')
340 | assert.strictEqual(
341 | result.items[0].subject,
342 | 'üäö',
343 | 'Returns the decoded mail Subject header'
344 | )
345 | })
346 |
347 | it('search mails from the given user', async function () {
348 | const result = await mailhog.search('test@example.org', 'from')
349 | assert.strictEqual(result.count, 4, 'Returns a list of matching emails')
350 | assert.strictEqual(
351 | result.items[0].subject,
352 | 'Mail without charset',
353 | 'Returns the decoded mail Subject header sent from the given user'
354 | )
355 | })
356 |
357 | it('search mails to the given user', async function () {
358 | const result = await mailhog.search('nihon@example.org', 'to')
359 | assert.strictEqual(result.count, 1, 'Returns a list of matching emails')
360 | assert.strictEqual(
361 | result.items[0].subject,
362 | '日本',
363 | 'Returns the decoded mail Subject header sent to the given user'
364 | )
365 | })
366 |
367 | it('limit the search results range', async function () {
368 | const result = await mailhog.search('example.org', undefined, 3, 1)
369 | assert.strictEqual(result.count, 1, 'Returns a set for the given range')
370 | assert.strictEqual(
371 | result.items[0].subject,
372 | 'üäö',
373 | 'Returns the decoded mail Subject header for mail from the given range'
374 | )
375 | })
376 | })
377 |
378 | describe('latestFrom', function () {
379 | it('latest mail from a given user', async function () {
380 | const result = await mailhog.latestFrom('test@example.org')
381 | assert.strictEqual(
382 | result.from,
383 | 'Test ',
384 | 'Returns the decoded mail From header sent from the given user'
385 | )
386 | })
387 | })
388 |
389 | describe('latestTo', function () {
390 | it('latest mail to a given user', async function () {
391 | const result = await mailhog.latestTo('nihon@example.org')
392 | assert.strictEqual(
393 | result.to,
394 | '日本 ',
395 | 'Returns the decoded mail To header sent to the given user'
396 | )
397 | })
398 | })
399 |
400 | describe('latestContaining', function () {
401 | it('latest mail with the query text in the body content', async function () {
402 | const result = await mailhog.latestContaining('text content')
403 | assert.strictEqual(
404 | result.text,
405 | 'text content',
406 | 'Returns the decoded plain text mail content containing the given query'
407 | )
408 | })
409 |
410 | it('latest mail with query text in the Subject header', async function () {
411 | const result = await mailhog.latestContaining('ISO-8859-1')
412 | assert.strictEqual(
413 | result.subject,
414 | 'ISO-8859-1',
415 | 'Returns the decoded mail Subject header containing the given query'
416 | )
417 | })
418 |
419 | it('latest mail with the query text in the From header', async function () {
420 | const result = await mailhog.latestContaining('test@example.org')
421 | assert.strictEqual(
422 | result.from,
423 | 'Test ',
424 | 'Returns the decoded mail From header containing the given query'
425 | )
426 | })
427 |
428 | it('latest mail with the query text in the To header', async function () {
429 | const result = await mailhog.latestContaining('nihon@example.org')
430 | assert.strictEqual(
431 | result.to,
432 | '日本 ',
433 | 'Returns the decoded mail To header containing the given query'
434 | )
435 | })
436 |
437 | it('latest mail with query text in attachment filename', async function () {
438 | const result = await mailhog.latestContaining('black-80x60.gif')
439 | assert.strictEqual(
440 | result.attachments[0].name,
441 | 'black-80x60.gif',
442 | 'Finds mail for a given attachment filename'
443 | )
444 | })
445 | })
446 |
447 | describe('releaseMessage', function () {
448 | after(deleteAllMail)
449 | after(sendAllMail)
450 |
451 | it('releases the given mail to an outgoing SMTP server', async function () {
452 | const result = await mailhog.latestTo('nihon@example.org')
453 | const response = await mailhog.releaseMessage(result.ID, {
454 | host: 'localhost',
455 | port: '1025',
456 | email: 'nihon@example.org'
457 | })
458 | assert.strictEqual(
459 | response.statusCode,
460 | 200,
461 | 'Responds with status code 200'
462 | )
463 | const newResult = await mailhog.latestTo('nihon@example.org')
464 | assert.notStrictEqual(
465 | result.ID,
466 | newResult.ID,
467 | 'New search for the same query returns a new ID'
468 | )
469 | const listResult = await mailhog.messages()
470 | assert.strictEqual(
471 | listResult.count,
472 | 5,
473 | 'Number of mails stored has increased by 1'
474 | )
475 | })
476 | })
477 |
478 | describe('deleteMessage', function () {
479 | after(deleteAllMail)
480 | after(sendAllMail)
481 |
482 | it('deletes the given mail from MailHog storage', async function () {
483 | const result = await mailhog.latestTo('nihon@example.org')
484 | const response = await mailhog.deleteMessage(result.ID)
485 | assert.strictEqual(
486 | response.statusCode,
487 | 200,
488 | 'Responds with status code 200'
489 | )
490 | const newResult = await mailhog.latestTo('nihon@example.org')
491 | assert.strictEqual(
492 | newResult,
493 | 0,
494 | 'New search for the deleted mail returns 0'
495 | )
496 | const listResult = await mailhog.messages()
497 | assert.strictEqual(
498 | listResult.count,
499 | 3,
500 | 'Number of mails stored has decreased by 1'
501 | )
502 | })
503 | })
504 |
505 | describe('deleteAll', function () {
506 | after(deleteAllMail)
507 | after(sendAllMail)
508 |
509 | it('deletes all mail from MailHog storage', async function () {
510 | const response = await mailhog.deleteAll()
511 | assert.strictEqual(
512 | response.statusCode,
513 | 200,
514 | 'Responds with status code 200'
515 | )
516 | const listResult = await mailhog.messages()
517 | assert.strictEqual(
518 | listResult.count,
519 | 0,
520 | 'Number of mails stored has decreased to 0'
521 | )
522 | })
523 | })
524 |
--------------------------------------------------------------------------------
/libqp/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2014 Andris Reinman
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/libqp/README.md:
--------------------------------------------------------------------------------
1 | # libqp
2 | Encode and decode quoted-printable strings according to
3 | [RFC2045](http://tools.ietf.org/html/rfc2045#section-6.7).
4 |
5 | ## Installation
6 | ```sh
7 | npm install mailhog
8 | ```
9 |
10 | ## Usage
11 | ```js
12 | const libqp = require('mailhog/libqp')
13 | ```
14 |
15 | ### Encode values
16 | Encode Buffer objects or unicode strings with
17 |
18 | ```js
19 | libqp.encode(val)
20 | ```
21 |
22 | Where
23 | * **val** is a Buffer or an unicode string
24 |
25 | **Example**
26 |
27 | ```js
28 | libqp.encode('jõgeva')
29 | // j=C3=B5geva
30 | ```
31 |
32 | ### Wrap encoded values
33 | Quoted-Printable encoded lines are limited to 76 characters but `encode` method
34 | might return lines longer than the limit.
35 |
36 | To enforce soft line breaks on lines longer than 76 (or any other length)
37 | characters, use `wrap`
38 |
39 | ```js
40 | llibqp.wrap(str[, lineLength])
41 | ```
42 |
43 | Where
44 | * **str** is a Quoted-Printable encoded string
45 | * **lineLength** (defaults to `76`) is the maximum allowed line length.
46 | Any longer line will be soft wrapped
47 |
48 | **Example**
49 |
50 | ```js
51 | libqp.wrap('abc j=C3=B5geva', 10)
52 | // abc j=\r\n
53 | // =C3=B5geva
54 | ```
55 |
56 | ## License
57 | Released under the [MIT license](https://opensource.org/licenses/MIT).
58 |
59 | ## Author
60 | [Andris Reinman](https://github.com/andris9) with minor edits from
61 | [Sebastian Tschan](https://blueimp.net/).
62 |
--------------------------------------------------------------------------------
/libqp/index.d.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Encodes a Buffer or String into a Quoted-Printable encoded string
3 | *
4 | * @param {Buffer|string} buffer Buffer or String to convert
5 | * @returns {string} Quoted-Printable encoded string
6 | */
7 | export function encode(buffer: Buffer | string): string;
8 | /**
9 | * Decodes a Quoted-Printable encoded string to a Buffer object
10 | *
11 | * @param {string} input Quoted-Printable encoded string
12 | * @returns {Buffer} Decoded value
13 | */
14 | export function decode(input: string): Buffer;
15 | /**
16 | * Adds soft line breaks to a Quoted-Printable string
17 | *
18 | * @param {string} str Quoted-Printable encoded string
19 | * @param {number} [lineLength=76] Maximum allowed length for a line
20 | * @returns {string} Soft-wrapped Quoted-Printable encoded string
21 | */
22 | export function wrap(str: string, lineLength?: number): string;
23 |
--------------------------------------------------------------------------------
/libqp/index.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | /* eslint-disable no-useless-escape */
4 |
5 | /**
6 | * Helper function to check if a number is inside provided ranges
7 | *
8 | * @param {number} nr Number to check for
9 | * @param {Array} ranges An Array of allowed values
10 | * @returns {boolean} True if value was found inside allowed ranges, else false
11 | */
12 | function checkRanges(nr, ranges) {
13 | for (let i = ranges.length - 1; i >= 0; i--) {
14 | if (!ranges[i].length) {
15 | continue
16 | }
17 | if (ranges[i].length === 1 && nr === ranges[i][0]) {
18 | return true
19 | }
20 | if (ranges[i].length === 2 && nr >= ranges[i][0] && nr <= ranges[i][1]) {
21 | return true
22 | }
23 | }
24 | return false
25 | }
26 |
27 | /**
28 | * Encodes a Buffer or String into a Quoted-Printable encoded string
29 | *
30 | * @param {Buffer|string} buffer Buffer or String to convert
31 | * @returns {string} Quoted-Printable encoded string
32 | */
33 | function encode(buffer) {
34 | const buf = typeof buffer === 'string' ? Buffer.from(buffer) : buffer
35 | // usable characters that do not need encoding
36 | const ranges = [
37 | // https://tools.ietf.org/html/rfc2045#section-6.7
38 | [0x09], //
39 | [0x0a], //
40 | [0x0d], //
41 | [0x20, 0x3c], // !"#$%&'()*+,-./0123456789:;
42 | // >?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}
43 | [0x3e, 0x7e]
44 | ]
45 | let result = ''
46 | let ord
47 |
48 | for (let i = 0, len = buf.length; i < len; i++) {
49 | ord = buf[i]
50 | // if the char is in allowed range, then keep as is,
51 | // unless it is a ws in the end of a line
52 | if (
53 | checkRanges(ord, ranges) &&
54 | !(
55 | (ord === 0x20 || ord === 0x09) &&
56 | (i === len - 1 || buf[i + 1] === 0x0a || buf[i + 1] === 0x0d)
57 | )
58 | ) {
59 | result += String.fromCharCode(ord)
60 | continue
61 | }
62 | result += '=' + (ord < 0x10 ? '0' : '') + ord.toString(16).toUpperCase()
63 | }
64 |
65 | return result
66 | }
67 |
68 | /**
69 | * Decodes a Quoted-Printable encoded string to a Buffer object
70 | *
71 | * @param {string} input Quoted-Printable encoded string
72 | * @returns {Buffer} Decoded value
73 | */
74 | function decode(input) {
75 | const str = (input || '')
76 | .toString()
77 | // remove invalid whitespace from the end of lines
78 | .replace(/[\t ]+$/gm, '')
79 | // remove soft line breaks
80 | .replace(/\=(?:\r?\n|$)/g, '')
81 |
82 | const encodedBytesCount = (str.match(/\=[\da-fA-F]{2}/g) || []).length
83 | const bufferLength = str.length - encodedBytesCount * 2
84 | const buffer = Buffer.alloc(bufferLength)
85 | let bufferPos = 0
86 | let chr
87 | let hex
88 |
89 | for (let i = 0, len = str.length; i < len; i++) {
90 | chr = str.charAt(i)
91 | if (
92 | chr === '=' &&
93 | (hex = str.substr(i + 1, 2)) &&
94 | /[\da-fA-F]{2}/.test(hex)
95 | ) {
96 | buffer[bufferPos++] = parseInt(hex, 16)
97 | i += 2
98 | continue
99 | }
100 | buffer[bufferPos++] = chr.charCodeAt(0)
101 | }
102 |
103 | return buffer
104 | }
105 |
106 | /**
107 | * Adds soft line breaks to a Quoted-Printable string
108 | *
109 | * @param {string} str Quoted-Printable encoded string
110 | * @param {number} [lineLength=76] Maximum allowed length for a line
111 | * @returns {string} Soft-wrapped Quoted-Printable encoded string
112 | */
113 | function wrap(str, lineLength) {
114 | const input = (str || '').toString()
115 | const maxLength = lineLength || 76
116 |
117 | if (input.length <= maxLength) {
118 | return input
119 | }
120 |
121 | const lineMargin = Math.floor(maxLength / 3)
122 | const len = input.length
123 | let pos = 0
124 | let match
125 | let code
126 | let line
127 | let result = ''
128 |
129 | // insert soft linebreaks where needed
130 | while (pos < len) {
131 | line = input.substr(pos, maxLength)
132 | if ((match = line.match(/\r\n/))) {
133 | line = line.substr(0, match.index + match[0].length)
134 | result += line
135 | pos += line.length
136 | continue
137 | }
138 |
139 | if (line.substr(-1) === '\n') {
140 | // nothing to change here
141 | result += line
142 | pos += line.length
143 | continue
144 | } else if ((match = line.substr(-lineMargin).match(/\n.*?$/))) {
145 | // truncate to nearest line break
146 | line = line.substr(0, line.length - (match[0].length - 1))
147 | result += line
148 | pos += line.length
149 | continue
150 | } else if (
151 | line.length > maxLength - lineMargin &&
152 | (match = line.substr(-lineMargin).match(/[ \t\.,!\?][^ \t\.,!\?]*$/))
153 | ) {
154 | // truncate to nearest space
155 | line = line.substr(0, line.length - (match[0].length - 1))
156 | } else {
157 | if (line.match(/\=[\da-f]{0,2}$/i)) {
158 | // push incomplete encoding sequences to the next line
159 | if ((match = line.match(/\=[\da-f]{0,1}$/i))) {
160 | line = line.substr(0, line.length - match[0].length)
161 | }
162 |
163 | // ensure that utf-8 sequences are not split
164 | while (
165 | line.length > 3 &&
166 | line.length < len - pos &&
167 | !line.match(/^(?:=[\da-f]{2}){1,4}$/i) &&
168 | (match = line.match(/\=[\da-f]{2}$/gi))
169 | ) {
170 | code = parseInt(match[0].substr(1, 2), 16)
171 | if (code < 128) {
172 | break
173 | }
174 |
175 | line = line.substr(0, line.length - 3)
176 |
177 | if (code >= 0xc0) {
178 | break
179 | }
180 | }
181 | }
182 | }
183 |
184 | if (pos + line.length < len && line.substr(-1) !== '\n') {
185 | if (line.length === maxLength && line.match(/\=[\da-f]{2}$/i)) {
186 | line = line.substr(0, line.length - 3)
187 | } else if (line.length === maxLength) {
188 | line = line.substr(0, line.length - 1)
189 | }
190 | pos += line.length
191 | line += '=\r\n'
192 | } else {
193 | pos += line.length
194 | }
195 |
196 | result += line
197 | }
198 |
199 | return result
200 | }
201 |
202 | module.exports = {
203 | encode: encode,
204 | decode: decode,
205 | wrap: wrap
206 | }
207 |
--------------------------------------------------------------------------------
/mail/01.eml:
--------------------------------------------------------------------------------
1 | Content-Type: multipart/mixed; boundary=next-part-zuB0VEK66qG0M6t4
2 | Date: Sun, 23 Oct 2016 20:59:40 +0200
3 | From: Test
4 | To: =?utf-8?Q?=C3=BC=C3=A4=C3=B6?=
5 | Subject: =?utf-8?Q?=C3=BC=C3=A4=C3=B6?=
6 |
7 | This is a message with multiple parts in MIME format.
8 | --next-part-zuB0VEK66qG0M6t4
9 | Content-Type: text/plain; charset=utf-8
10 | MIME-Version: 1.0
11 | Content-Transfer-Encoding: quoted-printable
12 |
13 | =C3=BC
14 | =C3=A4=C3=B6
15 | --next-part-zuB0VEK66qG0M6t4
16 | Content-Type: text/html; charset=utf-8
17 | MIME-Version: 1.0
18 | Content-Transfer-Encoding: quoted-printable
19 |
20 | =C3=BC
=C3=A4=C3=B6
21 | --next-part-zuB0VEK66qG0M6t4
22 | Content-Transfer-Encoding: base64
23 | MIME-Version: 1.0
24 | Content-Type: image/gif
25 | Content-Disposition: attachment; filename="black-80x60.gif"
26 |
27 | R0lGODdhUAA8AIABAAAAAP///ywAAAAAUAA8AAACS4SPqcvtD6OctNqLs968+w+G4kiW5omm6sq2
28 | 7gvH8kzX9o3n+s73/g8MCofEovGITCqXzKbzCY1Kp9Sq9YrNarfcrvcLDovH5PKsAAA7
29 | --next-part-zuB0VEK66qG0M6t4
30 | Content-Transfer-Encoding: base64
31 | MIME-Version: 1.0
32 | Content-Type: image/jpeg
33 | Content-Disposition: attachment; filename="white-2x1.jpg"
34 |
35 | /9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAASUkqAAgAAAABABIBAwABAAAABgASAAAAAAD/
36 | 7QAsUGhvdG9zaG9wIDMuMAA4QklNBAQAAAAAAA8cAgUACm9iamVjdG5hbWUA/9sAQwABAQEBAQEB
37 | AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB
38 | /9sAQwEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB
39 | AQEBAQEBAQEBAQEB/8AAEQgAAQACAwEiAAIRAQMRAf/EAB8AAAEFAQEBAQEBAAAAAAAAAAABAgME
40 | BQYHCAkKC//EALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEV
41 | UtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3
42 | eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh
43 | 4uPk5ebn6Onq8fLz9PX29/j5+v/EAB8BAAMBAQEBAQEBAQEAAAAAAAABAgMEBQYHCAkKC//EALUR
44 | AAIBAgQEAwQHBQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM1LwFWJy0QoWJDTh
45 | JfEXGBkaJicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJ
46 | ipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz
47 | 9PX29/j5+v/aAAwDAQACEQMRAD8A/v4ooooA/9k=
48 | --next-part-zuB0VEK66qG0M6t4--
49 |
--------------------------------------------------------------------------------
/mail/02.eml:
--------------------------------------------------------------------------------
1 | Content-Transfer-Encoding: base64
2 | Content-Type: text/plain; charset=utf-8
3 | Date: Sun, 23 Oct 2016 20:59:40 +0200
4 | From: Test
5 | To: =?utf-8?B?5pel5pys?=
6 | Cc: =?utf-8?B?5pel5pys?=
7 | Bcc: =?utf-8?B?5pel5pys?=
8 | Reply-To: =?utf-8?B?5pel5pys?=
9 | Subject: =?utf-8?B?5pel5pys?=
10 |
11 | 5pel5pysCg==
12 |
--------------------------------------------------------------------------------
/mail/03.eml:
--------------------------------------------------------------------------------
1 | Content-Transfer-Encoding: quoted-printable
2 | Content-Type: text/plain; charset=ISO-8859-1
3 | Date: Sun, 23 Oct 2016 20:59:40 +0200
4 | From: Test
5 | To: ISO-8859-1
6 | Subject: ISO-8859-1
7 |
8 | =FC=E4=F6=
9 |
--------------------------------------------------------------------------------
/mail/04.eml:
--------------------------------------------------------------------------------
1 | Content-Transfer-Encoding: 7bit
2 | Content-Type: text/plain
3 | Date: Tue, 04 Dec 2018 15:54:33 +0000
4 | From: Test
5 | To: no-charset@example.org
6 | Subject: Mail without charset
7 |
8 | text content
9 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mailhog",
3 | "version": "4.16.0",
4 | "lockfileVersion": 2,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "mailhog",
9 | "version": "4.16.0",
10 | "license": "MIT",
11 | "devDependencies": {
12 | "@types/mocha": "9",
13 | "@types/node": "16",
14 | "eslint": "7",
15 | "eslint-config-blueimp": "2",
16 | "eslint-config-prettier": "8",
17 | "eslint-plugin-jsdoc": "36",
18 | "eslint-plugin-node": "11",
19 | "eslint-plugin-prettier": "4",
20 | "prettier": "2",
21 | "typescript": "4"
22 | },
23 | "engines": {
24 | "node": ">=10.0.0"
25 | },
26 | "optionalDependencies": {
27 | "iconv-lite": "^0.6"
28 | }
29 | },
30 | "node_modules/@babel/code-frame": {
31 | "version": "7.12.11",
32 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz",
33 | "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==",
34 | "dev": true,
35 | "dependencies": {
36 | "@babel/highlight": "^7.10.4"
37 | }
38 | },
39 | "node_modules/@babel/helper-validator-identifier": {
40 | "version": "7.15.7",
41 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz",
42 | "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==",
43 | "dev": true,
44 | "engines": {
45 | "node": ">=6.9.0"
46 | }
47 | },
48 | "node_modules/@babel/highlight": {
49 | "version": "7.14.5",
50 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz",
51 | "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==",
52 | "dev": true,
53 | "dependencies": {
54 | "@babel/helper-validator-identifier": "^7.14.5",
55 | "chalk": "^2.0.0",
56 | "js-tokens": "^4.0.0"
57 | },
58 | "engines": {
59 | "node": ">=6.9.0"
60 | }
61 | },
62 | "node_modules/@babel/highlight/node_modules/ansi-styles": {
63 | "version": "3.2.1",
64 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
65 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
66 | "dev": true,
67 | "dependencies": {
68 | "color-convert": "^1.9.0"
69 | },
70 | "engines": {
71 | "node": ">=4"
72 | }
73 | },
74 | "node_modules/@babel/highlight/node_modules/chalk": {
75 | "version": "2.4.2",
76 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
77 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
78 | "dev": true,
79 | "dependencies": {
80 | "ansi-styles": "^3.2.1",
81 | "escape-string-regexp": "^1.0.5",
82 | "supports-color": "^5.3.0"
83 | },
84 | "engines": {
85 | "node": ">=4"
86 | }
87 | },
88 | "node_modules/@babel/highlight/node_modules/color-convert": {
89 | "version": "1.9.3",
90 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
91 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
92 | "dev": true,
93 | "dependencies": {
94 | "color-name": "1.1.3"
95 | }
96 | },
97 | "node_modules/@babel/highlight/node_modules/color-name": {
98 | "version": "1.1.3",
99 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
100 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
101 | "dev": true
102 | },
103 | "node_modules/@babel/highlight/node_modules/escape-string-regexp": {
104 | "version": "1.0.5",
105 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
106 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
107 | "dev": true,
108 | "engines": {
109 | "node": ">=0.8.0"
110 | }
111 | },
112 | "node_modules/@babel/highlight/node_modules/has-flag": {
113 | "version": "3.0.0",
114 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
115 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
116 | "dev": true,
117 | "engines": {
118 | "node": ">=4"
119 | }
120 | },
121 | "node_modules/@babel/highlight/node_modules/supports-color": {
122 | "version": "5.5.0",
123 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
124 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
125 | "dev": true,
126 | "dependencies": {
127 | "has-flag": "^3.0.0"
128 | },
129 | "engines": {
130 | "node": ">=4"
131 | }
132 | },
133 | "node_modules/@es-joy/jsdoccomment": {
134 | "version": "0.10.8",
135 | "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.10.8.tgz",
136 | "integrity": "sha512-3P1JiGL4xaR9PoTKUHa2N/LKwa2/eUdRqGwijMWWgBqbFEqJUVpmaOi2TcjcemrsRMgFLBzQCK4ToPhrSVDiFQ==",
137 | "dev": true,
138 | "dependencies": {
139 | "comment-parser": "1.2.4",
140 | "esquery": "^1.4.0",
141 | "jsdoc-type-pratt-parser": "1.1.1"
142 | },
143 | "engines": {
144 | "node": "^12 || ^14 || ^16"
145 | }
146 | },
147 | "node_modules/@eslint/eslintrc": {
148 | "version": "0.4.3",
149 | "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz",
150 | "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==",
151 | "dev": true,
152 | "dependencies": {
153 | "ajv": "^6.12.4",
154 | "debug": "^4.1.1",
155 | "espree": "^7.3.0",
156 | "globals": "^13.9.0",
157 | "ignore": "^4.0.6",
158 | "import-fresh": "^3.2.1",
159 | "js-yaml": "^3.13.1",
160 | "minimatch": "^3.0.4",
161 | "strip-json-comments": "^3.1.1"
162 | },
163 | "engines": {
164 | "node": "^10.12.0 || >=12.0.0"
165 | }
166 | },
167 | "node_modules/@humanwhocodes/config-array": {
168 | "version": "0.5.0",
169 | "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz",
170 | "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==",
171 | "dev": true,
172 | "dependencies": {
173 | "@humanwhocodes/object-schema": "^1.2.0",
174 | "debug": "^4.1.1",
175 | "minimatch": "^3.0.4"
176 | },
177 | "engines": {
178 | "node": ">=10.10.0"
179 | }
180 | },
181 | "node_modules/@humanwhocodes/object-schema": {
182 | "version": "1.2.0",
183 | "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz",
184 | "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==",
185 | "dev": true
186 | },
187 | "node_modules/@types/mocha": {
188 | "version": "9.0.0",
189 | "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.0.0.tgz",
190 | "integrity": "sha512-scN0hAWyLVAvLR9AyW7HoFF5sJZglyBsbPuHO4fv7JRvfmPBMfp1ozWqOf/e4wwPNxezBZXRfWzMb6iFLgEVRA==",
191 | "dev": true
192 | },
193 | "node_modules/@types/node": {
194 | "version": "16.9.6",
195 | "resolved": "https://registry.npmjs.org/@types/node/-/node-16.9.6.tgz",
196 | "integrity": "sha512-YHUZhBOMTM3mjFkXVcK+WwAcYmyhe1wL4lfqNtzI0b3qAy7yuSetnM7QJazgE5PFmgVTNGiLOgRFfJMqW7XpSQ==",
197 | "dev": true
198 | },
199 | "node_modules/acorn": {
200 | "version": "7.4.1",
201 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
202 | "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
203 | "dev": true,
204 | "bin": {
205 | "acorn": "bin/acorn"
206 | },
207 | "engines": {
208 | "node": ">=0.4.0"
209 | }
210 | },
211 | "node_modules/acorn-jsx": {
212 | "version": "5.3.2",
213 | "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
214 | "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
215 | "dev": true,
216 | "peerDependencies": {
217 | "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
218 | }
219 | },
220 | "node_modules/ajv": {
221 | "version": "6.12.6",
222 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
223 | "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
224 | "dev": true,
225 | "dependencies": {
226 | "fast-deep-equal": "^3.1.1",
227 | "fast-json-stable-stringify": "^2.0.0",
228 | "json-schema-traverse": "^0.4.1",
229 | "uri-js": "^4.2.2"
230 | },
231 | "funding": {
232 | "type": "github",
233 | "url": "https://github.com/sponsors/epoberezkin"
234 | }
235 | },
236 | "node_modules/ansi-colors": {
237 | "version": "4.1.1",
238 | "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
239 | "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
240 | "dev": true,
241 | "engines": {
242 | "node": ">=6"
243 | }
244 | },
245 | "node_modules/ansi-regex": {
246 | "version": "5.0.1",
247 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
248 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
249 | "dev": true,
250 | "engines": {
251 | "node": ">=8"
252 | }
253 | },
254 | "node_modules/ansi-styles": {
255 | "version": "4.3.0",
256 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
257 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
258 | "dev": true,
259 | "dependencies": {
260 | "color-convert": "^2.0.1"
261 | },
262 | "engines": {
263 | "node": ">=8"
264 | },
265 | "funding": {
266 | "url": "https://github.com/chalk/ansi-styles?sponsor=1"
267 | }
268 | },
269 | "node_modules/argparse": {
270 | "version": "1.0.10",
271 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
272 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
273 | "dev": true,
274 | "dependencies": {
275 | "sprintf-js": "~1.0.2"
276 | }
277 | },
278 | "node_modules/astral-regex": {
279 | "version": "2.0.0",
280 | "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
281 | "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
282 | "dev": true,
283 | "engines": {
284 | "node": ">=8"
285 | }
286 | },
287 | "node_modules/balanced-match": {
288 | "version": "1.0.2",
289 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
290 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
291 | "dev": true
292 | },
293 | "node_modules/brace-expansion": {
294 | "version": "1.1.11",
295 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
296 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
297 | "dev": true,
298 | "dependencies": {
299 | "balanced-match": "^1.0.0",
300 | "concat-map": "0.0.1"
301 | }
302 | },
303 | "node_modules/callsites": {
304 | "version": "3.1.0",
305 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
306 | "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
307 | "dev": true,
308 | "engines": {
309 | "node": ">=6"
310 | }
311 | },
312 | "node_modules/chalk": {
313 | "version": "4.1.2",
314 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
315 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
316 | "dev": true,
317 | "dependencies": {
318 | "ansi-styles": "^4.1.0",
319 | "supports-color": "^7.1.0"
320 | },
321 | "engines": {
322 | "node": ">=10"
323 | },
324 | "funding": {
325 | "url": "https://github.com/chalk/chalk?sponsor=1"
326 | }
327 | },
328 | "node_modules/color-convert": {
329 | "version": "2.0.1",
330 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
331 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
332 | "dev": true,
333 | "dependencies": {
334 | "color-name": "~1.1.4"
335 | },
336 | "engines": {
337 | "node": ">=7.0.0"
338 | }
339 | },
340 | "node_modules/color-name": {
341 | "version": "1.1.4",
342 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
343 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
344 | "dev": true
345 | },
346 | "node_modules/comment-parser": {
347 | "version": "1.2.4",
348 | "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.2.4.tgz",
349 | "integrity": "sha512-pm0b+qv+CkWNriSTMsfnjChF9kH0kxz55y44Wo5le9qLxMj5xDQAaEd9ZN1ovSuk9CsrncWaFwgpOMg7ClJwkw==",
350 | "dev": true,
351 | "engines": {
352 | "node": ">= 12.0.0"
353 | }
354 | },
355 | "node_modules/concat-map": {
356 | "version": "0.0.1",
357 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
358 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
359 | "dev": true
360 | },
361 | "node_modules/cross-spawn": {
362 | "version": "7.0.3",
363 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
364 | "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
365 | "dev": true,
366 | "dependencies": {
367 | "path-key": "^3.1.0",
368 | "shebang-command": "^2.0.0",
369 | "which": "^2.0.1"
370 | },
371 | "engines": {
372 | "node": ">= 8"
373 | }
374 | },
375 | "node_modules/debug": {
376 | "version": "4.3.2",
377 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
378 | "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
379 | "dev": true,
380 | "dependencies": {
381 | "ms": "2.1.2"
382 | },
383 | "engines": {
384 | "node": ">=6.0"
385 | },
386 | "peerDependenciesMeta": {
387 | "supports-color": {
388 | "optional": true
389 | }
390 | }
391 | },
392 | "node_modules/deep-is": {
393 | "version": "0.1.4",
394 | "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
395 | "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
396 | "dev": true
397 | },
398 | "node_modules/doctrine": {
399 | "version": "3.0.0",
400 | "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
401 | "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
402 | "dev": true,
403 | "dependencies": {
404 | "esutils": "^2.0.2"
405 | },
406 | "engines": {
407 | "node": ">=6.0.0"
408 | }
409 | },
410 | "node_modules/emoji-regex": {
411 | "version": "8.0.0",
412 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
413 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
414 | "dev": true
415 | },
416 | "node_modules/enquirer": {
417 | "version": "2.3.6",
418 | "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz",
419 | "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==",
420 | "dev": true,
421 | "dependencies": {
422 | "ansi-colors": "^4.1.1"
423 | },
424 | "engines": {
425 | "node": ">=8.6"
426 | }
427 | },
428 | "node_modules/escape-string-regexp": {
429 | "version": "4.0.0",
430 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
431 | "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
432 | "dev": true,
433 | "engines": {
434 | "node": ">=10"
435 | },
436 | "funding": {
437 | "url": "https://github.com/sponsors/sindresorhus"
438 | }
439 | },
440 | "node_modules/eslint": {
441 | "version": "7.32.0",
442 | "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz",
443 | "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==",
444 | "dev": true,
445 | "dependencies": {
446 | "@babel/code-frame": "7.12.11",
447 | "@eslint/eslintrc": "^0.4.3",
448 | "@humanwhocodes/config-array": "^0.5.0",
449 | "ajv": "^6.10.0",
450 | "chalk": "^4.0.0",
451 | "cross-spawn": "^7.0.2",
452 | "debug": "^4.0.1",
453 | "doctrine": "^3.0.0",
454 | "enquirer": "^2.3.5",
455 | "escape-string-regexp": "^4.0.0",
456 | "eslint-scope": "^5.1.1",
457 | "eslint-utils": "^2.1.0",
458 | "eslint-visitor-keys": "^2.0.0",
459 | "espree": "^7.3.1",
460 | "esquery": "^1.4.0",
461 | "esutils": "^2.0.2",
462 | "fast-deep-equal": "^3.1.3",
463 | "file-entry-cache": "^6.0.1",
464 | "functional-red-black-tree": "^1.0.1",
465 | "glob-parent": "^5.1.2",
466 | "globals": "^13.6.0",
467 | "ignore": "^4.0.6",
468 | "import-fresh": "^3.0.0",
469 | "imurmurhash": "^0.1.4",
470 | "is-glob": "^4.0.0",
471 | "js-yaml": "^3.13.1",
472 | "json-stable-stringify-without-jsonify": "^1.0.1",
473 | "levn": "^0.4.1",
474 | "lodash.merge": "^4.6.2",
475 | "minimatch": "^3.0.4",
476 | "natural-compare": "^1.4.0",
477 | "optionator": "^0.9.1",
478 | "progress": "^2.0.0",
479 | "regexpp": "^3.1.0",
480 | "semver": "^7.2.1",
481 | "strip-ansi": "^6.0.0",
482 | "strip-json-comments": "^3.1.0",
483 | "table": "^6.0.9",
484 | "text-table": "^0.2.0",
485 | "v8-compile-cache": "^2.0.3"
486 | },
487 | "bin": {
488 | "eslint": "bin/eslint.js"
489 | },
490 | "engines": {
491 | "node": "^10.12.0 || >=12.0.0"
492 | },
493 | "funding": {
494 | "url": "https://opencollective.com/eslint"
495 | }
496 | },
497 | "node_modules/eslint-config-blueimp": {
498 | "version": "2.3.0",
499 | "resolved": "https://registry.npmjs.org/eslint-config-blueimp/-/eslint-config-blueimp-2.3.0.tgz",
500 | "integrity": "sha512-OC1+7YHBpXYdl/Jt2PZMpIPAUogHf4iDnqf8vVMlmkKls1Xemu7DAZqdFgdYhZxgaJ/d+qXH8b66L/D/pU4btA==",
501 | "dev": true,
502 | "engines": {
503 | "node": ">=10.0.0"
504 | },
505 | "peerDependencies": {
506 | "eslint": ">=7"
507 | }
508 | },
509 | "node_modules/eslint-config-prettier": {
510 | "version": "8.3.0",
511 | "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz",
512 | "integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==",
513 | "dev": true,
514 | "bin": {
515 | "eslint-config-prettier": "bin/cli.js"
516 | },
517 | "peerDependencies": {
518 | "eslint": ">=7.0.0"
519 | }
520 | },
521 | "node_modules/eslint-plugin-es": {
522 | "version": "3.0.1",
523 | "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz",
524 | "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==",
525 | "dev": true,
526 | "dependencies": {
527 | "eslint-utils": "^2.0.0",
528 | "regexpp": "^3.0.0"
529 | },
530 | "engines": {
531 | "node": ">=8.10.0"
532 | },
533 | "funding": {
534 | "url": "https://github.com/sponsors/mysticatea"
535 | },
536 | "peerDependencies": {
537 | "eslint": ">=4.19.1"
538 | }
539 | },
540 | "node_modules/eslint-plugin-jsdoc": {
541 | "version": "36.1.0",
542 | "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-36.1.0.tgz",
543 | "integrity": "sha512-Qpied2AJCQcScxfzTObLKRiP5QgLXjMU/ITjBagEV5p2Q/HpumD1EQtazdRYdjDSwPmXhwOl2yquwOGQ4HOJNw==",
544 | "dev": true,
545 | "dependencies": {
546 | "@es-joy/jsdoccomment": "0.10.8",
547 | "comment-parser": "1.2.4",
548 | "debug": "^4.3.2",
549 | "esquery": "^1.4.0",
550 | "jsdoc-type-pratt-parser": "^1.1.1",
551 | "lodash": "^4.17.21",
552 | "regextras": "^0.8.0",
553 | "semver": "^7.3.5",
554 | "spdx-expression-parse": "^3.0.1"
555 | },
556 | "engines": {
557 | "node": "^12 || ^14 || ^16"
558 | },
559 | "peerDependencies": {
560 | "eslint": "^6.0.0 || ^7.0.0"
561 | }
562 | },
563 | "node_modules/eslint-plugin-node": {
564 | "version": "11.1.0",
565 | "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz",
566 | "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==",
567 | "dev": true,
568 | "dependencies": {
569 | "eslint-plugin-es": "^3.0.0",
570 | "eslint-utils": "^2.0.0",
571 | "ignore": "^5.1.1",
572 | "minimatch": "^3.0.4",
573 | "resolve": "^1.10.1",
574 | "semver": "^6.1.0"
575 | },
576 | "engines": {
577 | "node": ">=8.10.0"
578 | },
579 | "peerDependencies": {
580 | "eslint": ">=5.16.0"
581 | }
582 | },
583 | "node_modules/eslint-plugin-node/node_modules/ignore": {
584 | "version": "5.1.8",
585 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz",
586 | "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==",
587 | "dev": true,
588 | "engines": {
589 | "node": ">= 4"
590 | }
591 | },
592 | "node_modules/eslint-plugin-node/node_modules/semver": {
593 | "version": "6.3.0",
594 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
595 | "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
596 | "dev": true,
597 | "bin": {
598 | "semver": "bin/semver.js"
599 | }
600 | },
601 | "node_modules/eslint-plugin-prettier": {
602 | "version": "4.0.0",
603 | "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.0.0.tgz",
604 | "integrity": "sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ==",
605 | "dev": true,
606 | "dependencies": {
607 | "prettier-linter-helpers": "^1.0.0"
608 | },
609 | "engines": {
610 | "node": ">=6.0.0"
611 | },
612 | "peerDependencies": {
613 | "eslint": ">=7.28.0",
614 | "prettier": ">=2.0.0"
615 | },
616 | "peerDependenciesMeta": {
617 | "eslint-config-prettier": {
618 | "optional": true
619 | }
620 | }
621 | },
622 | "node_modules/eslint-scope": {
623 | "version": "5.1.1",
624 | "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
625 | "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
626 | "dev": true,
627 | "dependencies": {
628 | "esrecurse": "^4.3.0",
629 | "estraverse": "^4.1.1"
630 | },
631 | "engines": {
632 | "node": ">=8.0.0"
633 | }
634 | },
635 | "node_modules/eslint-utils": {
636 | "version": "2.1.0",
637 | "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz",
638 | "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==",
639 | "dev": true,
640 | "dependencies": {
641 | "eslint-visitor-keys": "^1.1.0"
642 | },
643 | "engines": {
644 | "node": ">=6"
645 | },
646 | "funding": {
647 | "url": "https://github.com/sponsors/mysticatea"
648 | }
649 | },
650 | "node_modules/eslint-utils/node_modules/eslint-visitor-keys": {
651 | "version": "1.3.0",
652 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
653 | "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
654 | "dev": true,
655 | "engines": {
656 | "node": ">=4"
657 | }
658 | },
659 | "node_modules/eslint-visitor-keys": {
660 | "version": "2.1.0",
661 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
662 | "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
663 | "dev": true,
664 | "engines": {
665 | "node": ">=10"
666 | }
667 | },
668 | "node_modules/espree": {
669 | "version": "7.3.1",
670 | "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz",
671 | "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==",
672 | "dev": true,
673 | "dependencies": {
674 | "acorn": "^7.4.0",
675 | "acorn-jsx": "^5.3.1",
676 | "eslint-visitor-keys": "^1.3.0"
677 | },
678 | "engines": {
679 | "node": "^10.12.0 || >=12.0.0"
680 | }
681 | },
682 | "node_modules/espree/node_modules/eslint-visitor-keys": {
683 | "version": "1.3.0",
684 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
685 | "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
686 | "dev": true,
687 | "engines": {
688 | "node": ">=4"
689 | }
690 | },
691 | "node_modules/esprima": {
692 | "version": "4.0.1",
693 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
694 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
695 | "dev": true,
696 | "bin": {
697 | "esparse": "bin/esparse.js",
698 | "esvalidate": "bin/esvalidate.js"
699 | },
700 | "engines": {
701 | "node": ">=4"
702 | }
703 | },
704 | "node_modules/esquery": {
705 | "version": "1.4.0",
706 | "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
707 | "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==",
708 | "dev": true,
709 | "dependencies": {
710 | "estraverse": "^5.1.0"
711 | },
712 | "engines": {
713 | "node": ">=0.10"
714 | }
715 | },
716 | "node_modules/esquery/node_modules/estraverse": {
717 | "version": "5.2.0",
718 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
719 | "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
720 | "dev": true,
721 | "engines": {
722 | "node": ">=4.0"
723 | }
724 | },
725 | "node_modules/esrecurse": {
726 | "version": "4.3.0",
727 | "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
728 | "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
729 | "dev": true,
730 | "dependencies": {
731 | "estraverse": "^5.2.0"
732 | },
733 | "engines": {
734 | "node": ">=4.0"
735 | }
736 | },
737 | "node_modules/esrecurse/node_modules/estraverse": {
738 | "version": "5.2.0",
739 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
740 | "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
741 | "dev": true,
742 | "engines": {
743 | "node": ">=4.0"
744 | }
745 | },
746 | "node_modules/estraverse": {
747 | "version": "4.3.0",
748 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
749 | "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
750 | "dev": true,
751 | "engines": {
752 | "node": ">=4.0"
753 | }
754 | },
755 | "node_modules/esutils": {
756 | "version": "2.0.3",
757 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
758 | "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
759 | "dev": true,
760 | "engines": {
761 | "node": ">=0.10.0"
762 | }
763 | },
764 | "node_modules/fast-deep-equal": {
765 | "version": "3.1.3",
766 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
767 | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
768 | "dev": true
769 | },
770 | "node_modules/fast-diff": {
771 | "version": "1.2.0",
772 | "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz",
773 | "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==",
774 | "dev": true
775 | },
776 | "node_modules/fast-json-stable-stringify": {
777 | "version": "2.1.0",
778 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
779 | "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
780 | "dev": true
781 | },
782 | "node_modules/fast-levenshtein": {
783 | "version": "2.0.6",
784 | "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
785 | "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
786 | "dev": true
787 | },
788 | "node_modules/file-entry-cache": {
789 | "version": "6.0.1",
790 | "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
791 | "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
792 | "dev": true,
793 | "dependencies": {
794 | "flat-cache": "^3.0.4"
795 | },
796 | "engines": {
797 | "node": "^10.12.0 || >=12.0.0"
798 | }
799 | },
800 | "node_modules/flat-cache": {
801 | "version": "3.0.4",
802 | "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
803 | "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
804 | "dev": true,
805 | "dependencies": {
806 | "flatted": "^3.1.0",
807 | "rimraf": "^3.0.2"
808 | },
809 | "engines": {
810 | "node": "^10.12.0 || >=12.0.0"
811 | }
812 | },
813 | "node_modules/flatted": {
814 | "version": "3.2.2",
815 | "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.2.tgz",
816 | "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==",
817 | "dev": true
818 | },
819 | "node_modules/fs.realpath": {
820 | "version": "1.0.0",
821 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
822 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
823 | "dev": true
824 | },
825 | "node_modules/function-bind": {
826 | "version": "1.1.1",
827 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
828 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
829 | "dev": true
830 | },
831 | "node_modules/functional-red-black-tree": {
832 | "version": "1.0.1",
833 | "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
834 | "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
835 | "dev": true
836 | },
837 | "node_modules/glob": {
838 | "version": "7.2.0",
839 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
840 | "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
841 | "dev": true,
842 | "dependencies": {
843 | "fs.realpath": "^1.0.0",
844 | "inflight": "^1.0.4",
845 | "inherits": "2",
846 | "minimatch": "^3.0.4",
847 | "once": "^1.3.0",
848 | "path-is-absolute": "^1.0.0"
849 | },
850 | "engines": {
851 | "node": "*"
852 | },
853 | "funding": {
854 | "url": "https://github.com/sponsors/isaacs"
855 | }
856 | },
857 | "node_modules/glob-parent": {
858 | "version": "5.1.2",
859 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
860 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
861 | "dev": true,
862 | "dependencies": {
863 | "is-glob": "^4.0.1"
864 | },
865 | "engines": {
866 | "node": ">= 6"
867 | }
868 | },
869 | "node_modules/globals": {
870 | "version": "13.11.0",
871 | "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz",
872 | "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==",
873 | "dev": true,
874 | "dependencies": {
875 | "type-fest": "^0.20.2"
876 | },
877 | "engines": {
878 | "node": ">=8"
879 | },
880 | "funding": {
881 | "url": "https://github.com/sponsors/sindresorhus"
882 | }
883 | },
884 | "node_modules/has": {
885 | "version": "1.0.3",
886 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
887 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
888 | "dev": true,
889 | "dependencies": {
890 | "function-bind": "^1.1.1"
891 | },
892 | "engines": {
893 | "node": ">= 0.4.0"
894 | }
895 | },
896 | "node_modules/has-flag": {
897 | "version": "4.0.0",
898 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
899 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
900 | "dev": true,
901 | "engines": {
902 | "node": ">=8"
903 | }
904 | },
905 | "node_modules/iconv-lite": {
906 | "version": "0.6.3",
907 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
908 | "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
909 | "optional": true,
910 | "dependencies": {
911 | "safer-buffer": ">= 2.1.2 < 3.0.0"
912 | },
913 | "engines": {
914 | "node": ">=0.10.0"
915 | }
916 | },
917 | "node_modules/ignore": {
918 | "version": "4.0.6",
919 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
920 | "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
921 | "dev": true,
922 | "engines": {
923 | "node": ">= 4"
924 | }
925 | },
926 | "node_modules/import-fresh": {
927 | "version": "3.3.0",
928 | "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
929 | "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
930 | "dev": true,
931 | "dependencies": {
932 | "parent-module": "^1.0.0",
933 | "resolve-from": "^4.0.0"
934 | },
935 | "engines": {
936 | "node": ">=6"
937 | },
938 | "funding": {
939 | "url": "https://github.com/sponsors/sindresorhus"
940 | }
941 | },
942 | "node_modules/imurmurhash": {
943 | "version": "0.1.4",
944 | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
945 | "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
946 | "dev": true,
947 | "engines": {
948 | "node": ">=0.8.19"
949 | }
950 | },
951 | "node_modules/inflight": {
952 | "version": "1.0.6",
953 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
954 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
955 | "dev": true,
956 | "dependencies": {
957 | "once": "^1.3.0",
958 | "wrappy": "1"
959 | }
960 | },
961 | "node_modules/inherits": {
962 | "version": "2.0.4",
963 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
964 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
965 | "dev": true
966 | },
967 | "node_modules/is-core-module": {
968 | "version": "2.6.0",
969 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.6.0.tgz",
970 | "integrity": "sha512-wShG8vs60jKfPWpF2KZRaAtvt3a20OAn7+IJ6hLPECpSABLcKtFKTTI4ZtH5QcBruBHlq+WsdHWyz0BCZW7svQ==",
971 | "dev": true,
972 | "dependencies": {
973 | "has": "^1.0.3"
974 | },
975 | "funding": {
976 | "url": "https://github.com/sponsors/ljharb"
977 | }
978 | },
979 | "node_modules/is-extglob": {
980 | "version": "2.1.1",
981 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
982 | "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
983 | "dev": true,
984 | "engines": {
985 | "node": ">=0.10.0"
986 | }
987 | },
988 | "node_modules/is-fullwidth-code-point": {
989 | "version": "3.0.0",
990 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
991 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
992 | "dev": true,
993 | "engines": {
994 | "node": ">=8"
995 | }
996 | },
997 | "node_modules/is-glob": {
998 | "version": "4.0.1",
999 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
1000 | "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
1001 | "dev": true,
1002 | "dependencies": {
1003 | "is-extglob": "^2.1.1"
1004 | },
1005 | "engines": {
1006 | "node": ">=0.10.0"
1007 | }
1008 | },
1009 | "node_modules/isexe": {
1010 | "version": "2.0.0",
1011 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
1012 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
1013 | "dev": true
1014 | },
1015 | "node_modules/js-tokens": {
1016 | "version": "4.0.0",
1017 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
1018 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
1019 | "dev": true
1020 | },
1021 | "node_modules/js-yaml": {
1022 | "version": "3.14.1",
1023 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
1024 | "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
1025 | "dev": true,
1026 | "dependencies": {
1027 | "argparse": "^1.0.7",
1028 | "esprima": "^4.0.0"
1029 | },
1030 | "bin": {
1031 | "js-yaml": "bin/js-yaml.js"
1032 | }
1033 | },
1034 | "node_modules/jsdoc-type-pratt-parser": {
1035 | "version": "1.1.1",
1036 | "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-1.1.1.tgz",
1037 | "integrity": "sha512-uelRmpghNwPBuZScwgBG/OzodaFk5RbO5xaivBdsAY70icWfShwZ7PCMO0x1zSkOa8T1FzHThmrdoyg/0AwV5g==",
1038 | "dev": true,
1039 | "engines": {
1040 | "node": ">=12.0.0"
1041 | }
1042 | },
1043 | "node_modules/json-schema-traverse": {
1044 | "version": "0.4.1",
1045 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
1046 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
1047 | "dev": true
1048 | },
1049 | "node_modules/json-stable-stringify-without-jsonify": {
1050 | "version": "1.0.1",
1051 | "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
1052 | "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
1053 | "dev": true
1054 | },
1055 | "node_modules/levn": {
1056 | "version": "0.4.1",
1057 | "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
1058 | "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
1059 | "dev": true,
1060 | "dependencies": {
1061 | "prelude-ls": "^1.2.1",
1062 | "type-check": "~0.4.0"
1063 | },
1064 | "engines": {
1065 | "node": ">= 0.8.0"
1066 | }
1067 | },
1068 | "node_modules/lodash": {
1069 | "version": "4.17.21",
1070 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
1071 | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
1072 | "dev": true
1073 | },
1074 | "node_modules/lodash.clonedeep": {
1075 | "version": "4.5.0",
1076 | "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
1077 | "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=",
1078 | "dev": true
1079 | },
1080 | "node_modules/lodash.merge": {
1081 | "version": "4.6.2",
1082 | "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
1083 | "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
1084 | "dev": true
1085 | },
1086 | "node_modules/lodash.truncate": {
1087 | "version": "4.4.2",
1088 | "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz",
1089 | "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=",
1090 | "dev": true
1091 | },
1092 | "node_modules/lru-cache": {
1093 | "version": "6.0.0",
1094 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
1095 | "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
1096 | "dev": true,
1097 | "dependencies": {
1098 | "yallist": "^4.0.0"
1099 | },
1100 | "engines": {
1101 | "node": ">=10"
1102 | }
1103 | },
1104 | "node_modules/minimatch": {
1105 | "version": "3.0.4",
1106 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
1107 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
1108 | "dev": true,
1109 | "dependencies": {
1110 | "brace-expansion": "^1.1.7"
1111 | },
1112 | "engines": {
1113 | "node": "*"
1114 | }
1115 | },
1116 | "node_modules/ms": {
1117 | "version": "2.1.2",
1118 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
1119 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
1120 | "dev": true
1121 | },
1122 | "node_modules/natural-compare": {
1123 | "version": "1.4.0",
1124 | "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
1125 | "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
1126 | "dev": true
1127 | },
1128 | "node_modules/once": {
1129 | "version": "1.4.0",
1130 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
1131 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
1132 | "dev": true,
1133 | "dependencies": {
1134 | "wrappy": "1"
1135 | }
1136 | },
1137 | "node_modules/optionator": {
1138 | "version": "0.9.1",
1139 | "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
1140 | "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
1141 | "dev": true,
1142 | "dependencies": {
1143 | "deep-is": "^0.1.3",
1144 | "fast-levenshtein": "^2.0.6",
1145 | "levn": "^0.4.1",
1146 | "prelude-ls": "^1.2.1",
1147 | "type-check": "^0.4.0",
1148 | "word-wrap": "^1.2.3"
1149 | },
1150 | "engines": {
1151 | "node": ">= 0.8.0"
1152 | }
1153 | },
1154 | "node_modules/parent-module": {
1155 | "version": "1.0.1",
1156 | "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
1157 | "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
1158 | "dev": true,
1159 | "dependencies": {
1160 | "callsites": "^3.0.0"
1161 | },
1162 | "engines": {
1163 | "node": ">=6"
1164 | }
1165 | },
1166 | "node_modules/path-is-absolute": {
1167 | "version": "1.0.1",
1168 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
1169 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
1170 | "dev": true,
1171 | "engines": {
1172 | "node": ">=0.10.0"
1173 | }
1174 | },
1175 | "node_modules/path-key": {
1176 | "version": "3.1.1",
1177 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
1178 | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
1179 | "dev": true,
1180 | "engines": {
1181 | "node": ">=8"
1182 | }
1183 | },
1184 | "node_modules/path-parse": {
1185 | "version": "1.0.7",
1186 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
1187 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
1188 | "dev": true
1189 | },
1190 | "node_modules/prelude-ls": {
1191 | "version": "1.2.1",
1192 | "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
1193 | "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
1194 | "dev": true,
1195 | "engines": {
1196 | "node": ">= 0.8.0"
1197 | }
1198 | },
1199 | "node_modules/prettier": {
1200 | "version": "2.4.1",
1201 | "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.4.1.tgz",
1202 | "integrity": "sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA==",
1203 | "dev": true,
1204 | "bin": {
1205 | "prettier": "bin-prettier.js"
1206 | },
1207 | "engines": {
1208 | "node": ">=10.13.0"
1209 | }
1210 | },
1211 | "node_modules/prettier-linter-helpers": {
1212 | "version": "1.0.0",
1213 | "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz",
1214 | "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==",
1215 | "dev": true,
1216 | "dependencies": {
1217 | "fast-diff": "^1.1.2"
1218 | },
1219 | "engines": {
1220 | "node": ">=6.0.0"
1221 | }
1222 | },
1223 | "node_modules/progress": {
1224 | "version": "2.0.3",
1225 | "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
1226 | "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
1227 | "dev": true,
1228 | "engines": {
1229 | "node": ">=0.4.0"
1230 | }
1231 | },
1232 | "node_modules/punycode": {
1233 | "version": "2.1.1",
1234 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
1235 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
1236 | "dev": true,
1237 | "engines": {
1238 | "node": ">=6"
1239 | }
1240 | },
1241 | "node_modules/regexpp": {
1242 | "version": "3.2.0",
1243 | "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
1244 | "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
1245 | "dev": true,
1246 | "engines": {
1247 | "node": ">=8"
1248 | },
1249 | "funding": {
1250 | "url": "https://github.com/sponsors/mysticatea"
1251 | }
1252 | },
1253 | "node_modules/regextras": {
1254 | "version": "0.8.0",
1255 | "resolved": "https://registry.npmjs.org/regextras/-/regextras-0.8.0.tgz",
1256 | "integrity": "sha512-k519uI04Z3SaY0fLX843MRXnDeG2+vHOFsyhiPZvNLe7r8rD2YNRjq4BQLZZ0oAr2NrtvZlICsXysGNFPGa3CQ==",
1257 | "dev": true,
1258 | "engines": {
1259 | "node": ">=0.1.14"
1260 | }
1261 | },
1262 | "node_modules/require-from-string": {
1263 | "version": "2.0.2",
1264 | "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
1265 | "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
1266 | "dev": true,
1267 | "engines": {
1268 | "node": ">=0.10.0"
1269 | }
1270 | },
1271 | "node_modules/resolve": {
1272 | "version": "1.20.0",
1273 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",
1274 | "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==",
1275 | "dev": true,
1276 | "dependencies": {
1277 | "is-core-module": "^2.2.0",
1278 | "path-parse": "^1.0.6"
1279 | },
1280 | "funding": {
1281 | "url": "https://github.com/sponsors/ljharb"
1282 | }
1283 | },
1284 | "node_modules/resolve-from": {
1285 | "version": "4.0.0",
1286 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
1287 | "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
1288 | "dev": true,
1289 | "engines": {
1290 | "node": ">=4"
1291 | }
1292 | },
1293 | "node_modules/rimraf": {
1294 | "version": "3.0.2",
1295 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
1296 | "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
1297 | "dev": true,
1298 | "dependencies": {
1299 | "glob": "^7.1.3"
1300 | },
1301 | "bin": {
1302 | "rimraf": "bin.js"
1303 | },
1304 | "funding": {
1305 | "url": "https://github.com/sponsors/isaacs"
1306 | }
1307 | },
1308 | "node_modules/safer-buffer": {
1309 | "version": "2.1.2",
1310 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
1311 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
1312 | "optional": true
1313 | },
1314 | "node_modules/semver": {
1315 | "version": "7.3.5",
1316 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
1317 | "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
1318 | "dev": true,
1319 | "dependencies": {
1320 | "lru-cache": "^6.0.0"
1321 | },
1322 | "bin": {
1323 | "semver": "bin/semver.js"
1324 | },
1325 | "engines": {
1326 | "node": ">=10"
1327 | }
1328 | },
1329 | "node_modules/shebang-command": {
1330 | "version": "2.0.0",
1331 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
1332 | "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
1333 | "dev": true,
1334 | "dependencies": {
1335 | "shebang-regex": "^3.0.0"
1336 | },
1337 | "engines": {
1338 | "node": ">=8"
1339 | }
1340 | },
1341 | "node_modules/shebang-regex": {
1342 | "version": "3.0.0",
1343 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
1344 | "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
1345 | "dev": true,
1346 | "engines": {
1347 | "node": ">=8"
1348 | }
1349 | },
1350 | "node_modules/slice-ansi": {
1351 | "version": "4.0.0",
1352 | "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
1353 | "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==",
1354 | "dev": true,
1355 | "dependencies": {
1356 | "ansi-styles": "^4.0.0",
1357 | "astral-regex": "^2.0.0",
1358 | "is-fullwidth-code-point": "^3.0.0"
1359 | },
1360 | "engines": {
1361 | "node": ">=10"
1362 | },
1363 | "funding": {
1364 | "url": "https://github.com/chalk/slice-ansi?sponsor=1"
1365 | }
1366 | },
1367 | "node_modules/spdx-exceptions": {
1368 | "version": "2.3.0",
1369 | "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz",
1370 | "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==",
1371 | "dev": true
1372 | },
1373 | "node_modules/spdx-expression-parse": {
1374 | "version": "3.0.1",
1375 | "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
1376 | "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
1377 | "dev": true,
1378 | "dependencies": {
1379 | "spdx-exceptions": "^2.1.0",
1380 | "spdx-license-ids": "^3.0.0"
1381 | }
1382 | },
1383 | "node_modules/spdx-license-ids": {
1384 | "version": "3.0.10",
1385 | "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.10.tgz",
1386 | "integrity": "sha512-oie3/+gKf7QtpitB0LYLETe+k8SifzsX4KixvpOsbI6S0kRiRQ5MKOio8eMSAKQ17N06+wdEOXRiId+zOxo0hA==",
1387 | "dev": true
1388 | },
1389 | "node_modules/sprintf-js": {
1390 | "version": "1.0.3",
1391 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
1392 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
1393 | "dev": true
1394 | },
1395 | "node_modules/string-width": {
1396 | "version": "4.2.3",
1397 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
1398 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
1399 | "dev": true,
1400 | "dependencies": {
1401 | "emoji-regex": "^8.0.0",
1402 | "is-fullwidth-code-point": "^3.0.0",
1403 | "strip-ansi": "^6.0.1"
1404 | },
1405 | "engines": {
1406 | "node": ">=8"
1407 | }
1408 | },
1409 | "node_modules/strip-ansi": {
1410 | "version": "6.0.1",
1411 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
1412 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
1413 | "dev": true,
1414 | "dependencies": {
1415 | "ansi-regex": "^5.0.1"
1416 | },
1417 | "engines": {
1418 | "node": ">=8"
1419 | }
1420 | },
1421 | "node_modules/strip-json-comments": {
1422 | "version": "3.1.1",
1423 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
1424 | "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
1425 | "dev": true,
1426 | "engines": {
1427 | "node": ">=8"
1428 | },
1429 | "funding": {
1430 | "url": "https://github.com/sponsors/sindresorhus"
1431 | }
1432 | },
1433 | "node_modules/supports-color": {
1434 | "version": "7.2.0",
1435 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
1436 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
1437 | "dev": true,
1438 | "dependencies": {
1439 | "has-flag": "^4.0.0"
1440 | },
1441 | "engines": {
1442 | "node": ">=8"
1443 | }
1444 | },
1445 | "node_modules/table": {
1446 | "version": "6.7.1",
1447 | "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz",
1448 | "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==",
1449 | "dev": true,
1450 | "dependencies": {
1451 | "ajv": "^8.0.1",
1452 | "lodash.clonedeep": "^4.5.0",
1453 | "lodash.truncate": "^4.4.2",
1454 | "slice-ansi": "^4.0.0",
1455 | "string-width": "^4.2.0",
1456 | "strip-ansi": "^6.0.0"
1457 | },
1458 | "engines": {
1459 | "node": ">=10.0.0"
1460 | }
1461 | },
1462 | "node_modules/table/node_modules/ajv": {
1463 | "version": "8.6.3",
1464 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.3.tgz",
1465 | "integrity": "sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==",
1466 | "dev": true,
1467 | "dependencies": {
1468 | "fast-deep-equal": "^3.1.1",
1469 | "json-schema-traverse": "^1.0.0",
1470 | "require-from-string": "^2.0.2",
1471 | "uri-js": "^4.2.2"
1472 | },
1473 | "funding": {
1474 | "type": "github",
1475 | "url": "https://github.com/sponsors/epoberezkin"
1476 | }
1477 | },
1478 | "node_modules/table/node_modules/json-schema-traverse": {
1479 | "version": "1.0.0",
1480 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
1481 | "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
1482 | "dev": true
1483 | },
1484 | "node_modules/text-table": {
1485 | "version": "0.2.0",
1486 | "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
1487 | "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
1488 | "dev": true
1489 | },
1490 | "node_modules/type-check": {
1491 | "version": "0.4.0",
1492 | "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
1493 | "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
1494 | "dev": true,
1495 | "dependencies": {
1496 | "prelude-ls": "^1.2.1"
1497 | },
1498 | "engines": {
1499 | "node": ">= 0.8.0"
1500 | }
1501 | },
1502 | "node_modules/type-fest": {
1503 | "version": "0.20.2",
1504 | "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
1505 | "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
1506 | "dev": true,
1507 | "engines": {
1508 | "node": ">=10"
1509 | },
1510 | "funding": {
1511 | "url": "https://github.com/sponsors/sindresorhus"
1512 | }
1513 | },
1514 | "node_modules/typescript": {
1515 | "version": "4.4.3",
1516 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.3.tgz",
1517 | "integrity": "sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA==",
1518 | "dev": true,
1519 | "bin": {
1520 | "tsc": "bin/tsc",
1521 | "tsserver": "bin/tsserver"
1522 | },
1523 | "engines": {
1524 | "node": ">=4.2.0"
1525 | }
1526 | },
1527 | "node_modules/uri-js": {
1528 | "version": "4.4.1",
1529 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
1530 | "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
1531 | "dev": true,
1532 | "dependencies": {
1533 | "punycode": "^2.1.0"
1534 | }
1535 | },
1536 | "node_modules/v8-compile-cache": {
1537 | "version": "2.3.0",
1538 | "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz",
1539 | "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==",
1540 | "dev": true
1541 | },
1542 | "node_modules/which": {
1543 | "version": "2.0.2",
1544 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
1545 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
1546 | "dev": true,
1547 | "dependencies": {
1548 | "isexe": "^2.0.0"
1549 | },
1550 | "bin": {
1551 | "node-which": "bin/node-which"
1552 | },
1553 | "engines": {
1554 | "node": ">= 8"
1555 | }
1556 | },
1557 | "node_modules/word-wrap": {
1558 | "version": "1.2.3",
1559 | "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
1560 | "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
1561 | "dev": true,
1562 | "engines": {
1563 | "node": ">=0.10.0"
1564 | }
1565 | },
1566 | "node_modules/wrappy": {
1567 | "version": "1.0.2",
1568 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
1569 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
1570 | "dev": true
1571 | },
1572 | "node_modules/yallist": {
1573 | "version": "4.0.0",
1574 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
1575 | "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
1576 | "dev": true
1577 | }
1578 | },
1579 | "dependencies": {
1580 | "@babel/code-frame": {
1581 | "version": "7.12.11",
1582 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz",
1583 | "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==",
1584 | "dev": true,
1585 | "requires": {
1586 | "@babel/highlight": "^7.10.4"
1587 | }
1588 | },
1589 | "@babel/helper-validator-identifier": {
1590 | "version": "7.15.7",
1591 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz",
1592 | "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==",
1593 | "dev": true
1594 | },
1595 | "@babel/highlight": {
1596 | "version": "7.14.5",
1597 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz",
1598 | "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==",
1599 | "dev": true,
1600 | "requires": {
1601 | "@babel/helper-validator-identifier": "^7.14.5",
1602 | "chalk": "^2.0.0",
1603 | "js-tokens": "^4.0.0"
1604 | },
1605 | "dependencies": {
1606 | "ansi-styles": {
1607 | "version": "3.2.1",
1608 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
1609 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
1610 | "dev": true,
1611 | "requires": {
1612 | "color-convert": "^1.9.0"
1613 | }
1614 | },
1615 | "chalk": {
1616 | "version": "2.4.2",
1617 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
1618 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
1619 | "dev": true,
1620 | "requires": {
1621 | "ansi-styles": "^3.2.1",
1622 | "escape-string-regexp": "^1.0.5",
1623 | "supports-color": "^5.3.0"
1624 | }
1625 | },
1626 | "color-convert": {
1627 | "version": "1.9.3",
1628 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
1629 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
1630 | "dev": true,
1631 | "requires": {
1632 | "color-name": "1.1.3"
1633 | }
1634 | },
1635 | "color-name": {
1636 | "version": "1.1.3",
1637 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
1638 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
1639 | "dev": true
1640 | },
1641 | "escape-string-regexp": {
1642 | "version": "1.0.5",
1643 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
1644 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
1645 | "dev": true
1646 | },
1647 | "has-flag": {
1648 | "version": "3.0.0",
1649 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
1650 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
1651 | "dev": true
1652 | },
1653 | "supports-color": {
1654 | "version": "5.5.0",
1655 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
1656 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
1657 | "dev": true,
1658 | "requires": {
1659 | "has-flag": "^3.0.0"
1660 | }
1661 | }
1662 | }
1663 | },
1664 | "@es-joy/jsdoccomment": {
1665 | "version": "0.10.8",
1666 | "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.10.8.tgz",
1667 | "integrity": "sha512-3P1JiGL4xaR9PoTKUHa2N/LKwa2/eUdRqGwijMWWgBqbFEqJUVpmaOi2TcjcemrsRMgFLBzQCK4ToPhrSVDiFQ==",
1668 | "dev": true,
1669 | "requires": {
1670 | "comment-parser": "1.2.4",
1671 | "esquery": "^1.4.0",
1672 | "jsdoc-type-pratt-parser": "1.1.1"
1673 | }
1674 | },
1675 | "@eslint/eslintrc": {
1676 | "version": "0.4.3",
1677 | "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz",
1678 | "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==",
1679 | "dev": true,
1680 | "requires": {
1681 | "ajv": "^6.12.4",
1682 | "debug": "^4.1.1",
1683 | "espree": "^7.3.0",
1684 | "globals": "^13.9.0",
1685 | "ignore": "^4.0.6",
1686 | "import-fresh": "^3.2.1",
1687 | "js-yaml": "^3.13.1",
1688 | "minimatch": "^3.0.4",
1689 | "strip-json-comments": "^3.1.1"
1690 | }
1691 | },
1692 | "@humanwhocodes/config-array": {
1693 | "version": "0.5.0",
1694 | "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz",
1695 | "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==",
1696 | "dev": true,
1697 | "requires": {
1698 | "@humanwhocodes/object-schema": "^1.2.0",
1699 | "debug": "^4.1.1",
1700 | "minimatch": "^3.0.4"
1701 | }
1702 | },
1703 | "@humanwhocodes/object-schema": {
1704 | "version": "1.2.0",
1705 | "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz",
1706 | "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==",
1707 | "dev": true
1708 | },
1709 | "@types/mocha": {
1710 | "version": "9.0.0",
1711 | "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.0.0.tgz",
1712 | "integrity": "sha512-scN0hAWyLVAvLR9AyW7HoFF5sJZglyBsbPuHO4fv7JRvfmPBMfp1ozWqOf/e4wwPNxezBZXRfWzMb6iFLgEVRA==",
1713 | "dev": true
1714 | },
1715 | "@types/node": {
1716 | "version": "16.9.6",
1717 | "resolved": "https://registry.npmjs.org/@types/node/-/node-16.9.6.tgz",
1718 | "integrity": "sha512-YHUZhBOMTM3mjFkXVcK+WwAcYmyhe1wL4lfqNtzI0b3qAy7yuSetnM7QJazgE5PFmgVTNGiLOgRFfJMqW7XpSQ==",
1719 | "dev": true
1720 | },
1721 | "acorn": {
1722 | "version": "7.4.1",
1723 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
1724 | "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
1725 | "dev": true
1726 | },
1727 | "acorn-jsx": {
1728 | "version": "5.3.2",
1729 | "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
1730 | "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
1731 | "dev": true,
1732 | "requires": {}
1733 | },
1734 | "ajv": {
1735 | "version": "6.12.6",
1736 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
1737 | "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
1738 | "dev": true,
1739 | "requires": {
1740 | "fast-deep-equal": "^3.1.1",
1741 | "fast-json-stable-stringify": "^2.0.0",
1742 | "json-schema-traverse": "^0.4.1",
1743 | "uri-js": "^4.2.2"
1744 | }
1745 | },
1746 | "ansi-colors": {
1747 | "version": "4.1.1",
1748 | "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz",
1749 | "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
1750 | "dev": true
1751 | },
1752 | "ansi-regex": {
1753 | "version": "5.0.1",
1754 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
1755 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
1756 | "dev": true
1757 | },
1758 | "ansi-styles": {
1759 | "version": "4.3.0",
1760 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
1761 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
1762 | "dev": true,
1763 | "requires": {
1764 | "color-convert": "^2.0.1"
1765 | }
1766 | },
1767 | "argparse": {
1768 | "version": "1.0.10",
1769 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
1770 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
1771 | "dev": true,
1772 | "requires": {
1773 | "sprintf-js": "~1.0.2"
1774 | }
1775 | },
1776 | "astral-regex": {
1777 | "version": "2.0.0",
1778 | "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz",
1779 | "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==",
1780 | "dev": true
1781 | },
1782 | "balanced-match": {
1783 | "version": "1.0.2",
1784 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
1785 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
1786 | "dev": true
1787 | },
1788 | "brace-expansion": {
1789 | "version": "1.1.11",
1790 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
1791 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
1792 | "dev": true,
1793 | "requires": {
1794 | "balanced-match": "^1.0.0",
1795 | "concat-map": "0.0.1"
1796 | }
1797 | },
1798 | "callsites": {
1799 | "version": "3.1.0",
1800 | "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
1801 | "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
1802 | "dev": true
1803 | },
1804 | "chalk": {
1805 | "version": "4.1.2",
1806 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
1807 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
1808 | "dev": true,
1809 | "requires": {
1810 | "ansi-styles": "^4.1.0",
1811 | "supports-color": "^7.1.0"
1812 | }
1813 | },
1814 | "color-convert": {
1815 | "version": "2.0.1",
1816 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
1817 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
1818 | "dev": true,
1819 | "requires": {
1820 | "color-name": "~1.1.4"
1821 | }
1822 | },
1823 | "color-name": {
1824 | "version": "1.1.4",
1825 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
1826 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
1827 | "dev": true
1828 | },
1829 | "comment-parser": {
1830 | "version": "1.2.4",
1831 | "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.2.4.tgz",
1832 | "integrity": "sha512-pm0b+qv+CkWNriSTMsfnjChF9kH0kxz55y44Wo5le9qLxMj5xDQAaEd9ZN1ovSuk9CsrncWaFwgpOMg7ClJwkw==",
1833 | "dev": true
1834 | },
1835 | "concat-map": {
1836 | "version": "0.0.1",
1837 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
1838 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
1839 | "dev": true
1840 | },
1841 | "cross-spawn": {
1842 | "version": "7.0.3",
1843 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
1844 | "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
1845 | "dev": true,
1846 | "requires": {
1847 | "path-key": "^3.1.0",
1848 | "shebang-command": "^2.0.0",
1849 | "which": "^2.0.1"
1850 | }
1851 | },
1852 | "debug": {
1853 | "version": "4.3.2",
1854 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
1855 | "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
1856 | "dev": true,
1857 | "requires": {
1858 | "ms": "2.1.2"
1859 | }
1860 | },
1861 | "deep-is": {
1862 | "version": "0.1.4",
1863 | "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
1864 | "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
1865 | "dev": true
1866 | },
1867 | "doctrine": {
1868 | "version": "3.0.0",
1869 | "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
1870 | "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
1871 | "dev": true,
1872 | "requires": {
1873 | "esutils": "^2.0.2"
1874 | }
1875 | },
1876 | "emoji-regex": {
1877 | "version": "8.0.0",
1878 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
1879 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
1880 | "dev": true
1881 | },
1882 | "enquirer": {
1883 | "version": "2.3.6",
1884 | "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz",
1885 | "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==",
1886 | "dev": true,
1887 | "requires": {
1888 | "ansi-colors": "^4.1.1"
1889 | }
1890 | },
1891 | "escape-string-regexp": {
1892 | "version": "4.0.0",
1893 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
1894 | "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
1895 | "dev": true
1896 | },
1897 | "eslint": {
1898 | "version": "7.32.0",
1899 | "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz",
1900 | "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==",
1901 | "dev": true,
1902 | "requires": {
1903 | "@babel/code-frame": "7.12.11",
1904 | "@eslint/eslintrc": "^0.4.3",
1905 | "@humanwhocodes/config-array": "^0.5.0",
1906 | "ajv": "^6.10.0",
1907 | "chalk": "^4.0.0",
1908 | "cross-spawn": "^7.0.2",
1909 | "debug": "^4.0.1",
1910 | "doctrine": "^3.0.0",
1911 | "enquirer": "^2.3.5",
1912 | "escape-string-regexp": "^4.0.0",
1913 | "eslint-scope": "^5.1.1",
1914 | "eslint-utils": "^2.1.0",
1915 | "eslint-visitor-keys": "^2.0.0",
1916 | "espree": "^7.3.1",
1917 | "esquery": "^1.4.0",
1918 | "esutils": "^2.0.2",
1919 | "fast-deep-equal": "^3.1.3",
1920 | "file-entry-cache": "^6.0.1",
1921 | "functional-red-black-tree": "^1.0.1",
1922 | "glob-parent": "^5.1.2",
1923 | "globals": "^13.6.0",
1924 | "ignore": "^4.0.6",
1925 | "import-fresh": "^3.0.0",
1926 | "imurmurhash": "^0.1.4",
1927 | "is-glob": "^4.0.0",
1928 | "js-yaml": "^3.13.1",
1929 | "json-stable-stringify-without-jsonify": "^1.0.1",
1930 | "levn": "^0.4.1",
1931 | "lodash.merge": "^4.6.2",
1932 | "minimatch": "^3.0.4",
1933 | "natural-compare": "^1.4.0",
1934 | "optionator": "^0.9.1",
1935 | "progress": "^2.0.0",
1936 | "regexpp": "^3.1.0",
1937 | "semver": "^7.2.1",
1938 | "strip-ansi": "^6.0.0",
1939 | "strip-json-comments": "^3.1.0",
1940 | "table": "^6.0.9",
1941 | "text-table": "^0.2.0",
1942 | "v8-compile-cache": "^2.0.3"
1943 | }
1944 | },
1945 | "eslint-config-blueimp": {
1946 | "version": "2.3.0",
1947 | "resolved": "https://registry.npmjs.org/eslint-config-blueimp/-/eslint-config-blueimp-2.3.0.tgz",
1948 | "integrity": "sha512-OC1+7YHBpXYdl/Jt2PZMpIPAUogHf4iDnqf8vVMlmkKls1Xemu7DAZqdFgdYhZxgaJ/d+qXH8b66L/D/pU4btA==",
1949 | "dev": true,
1950 | "requires": {}
1951 | },
1952 | "eslint-config-prettier": {
1953 | "version": "8.3.0",
1954 | "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz",
1955 | "integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==",
1956 | "dev": true,
1957 | "requires": {}
1958 | },
1959 | "eslint-plugin-es": {
1960 | "version": "3.0.1",
1961 | "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz",
1962 | "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==",
1963 | "dev": true,
1964 | "requires": {
1965 | "eslint-utils": "^2.0.0",
1966 | "regexpp": "^3.0.0"
1967 | }
1968 | },
1969 | "eslint-plugin-jsdoc": {
1970 | "version": "36.1.0",
1971 | "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-36.1.0.tgz",
1972 | "integrity": "sha512-Qpied2AJCQcScxfzTObLKRiP5QgLXjMU/ITjBagEV5p2Q/HpumD1EQtazdRYdjDSwPmXhwOl2yquwOGQ4HOJNw==",
1973 | "dev": true,
1974 | "requires": {
1975 | "@es-joy/jsdoccomment": "0.10.8",
1976 | "comment-parser": "1.2.4",
1977 | "debug": "^4.3.2",
1978 | "esquery": "^1.4.0",
1979 | "jsdoc-type-pratt-parser": "^1.1.1",
1980 | "lodash": "^4.17.21",
1981 | "regextras": "^0.8.0",
1982 | "semver": "^7.3.5",
1983 | "spdx-expression-parse": "^3.0.1"
1984 | }
1985 | },
1986 | "eslint-plugin-node": {
1987 | "version": "11.1.0",
1988 | "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz",
1989 | "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==",
1990 | "dev": true,
1991 | "requires": {
1992 | "eslint-plugin-es": "^3.0.0",
1993 | "eslint-utils": "^2.0.0",
1994 | "ignore": "^5.1.1",
1995 | "minimatch": "^3.0.4",
1996 | "resolve": "^1.10.1",
1997 | "semver": "^6.1.0"
1998 | },
1999 | "dependencies": {
2000 | "ignore": {
2001 | "version": "5.1.8",
2002 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz",
2003 | "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==",
2004 | "dev": true
2005 | },
2006 | "semver": {
2007 | "version": "6.3.0",
2008 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
2009 | "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
2010 | "dev": true
2011 | }
2012 | }
2013 | },
2014 | "eslint-plugin-prettier": {
2015 | "version": "4.0.0",
2016 | "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.0.0.tgz",
2017 | "integrity": "sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ==",
2018 | "dev": true,
2019 | "requires": {
2020 | "prettier-linter-helpers": "^1.0.0"
2021 | }
2022 | },
2023 | "eslint-scope": {
2024 | "version": "5.1.1",
2025 | "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
2026 | "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
2027 | "dev": true,
2028 | "requires": {
2029 | "esrecurse": "^4.3.0",
2030 | "estraverse": "^4.1.1"
2031 | }
2032 | },
2033 | "eslint-utils": {
2034 | "version": "2.1.0",
2035 | "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz",
2036 | "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==",
2037 | "dev": true,
2038 | "requires": {
2039 | "eslint-visitor-keys": "^1.1.0"
2040 | },
2041 | "dependencies": {
2042 | "eslint-visitor-keys": {
2043 | "version": "1.3.0",
2044 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
2045 | "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
2046 | "dev": true
2047 | }
2048 | }
2049 | },
2050 | "eslint-visitor-keys": {
2051 | "version": "2.1.0",
2052 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz",
2053 | "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==",
2054 | "dev": true
2055 | },
2056 | "espree": {
2057 | "version": "7.3.1",
2058 | "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz",
2059 | "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==",
2060 | "dev": true,
2061 | "requires": {
2062 | "acorn": "^7.4.0",
2063 | "acorn-jsx": "^5.3.1",
2064 | "eslint-visitor-keys": "^1.3.0"
2065 | },
2066 | "dependencies": {
2067 | "eslint-visitor-keys": {
2068 | "version": "1.3.0",
2069 | "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
2070 | "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==",
2071 | "dev": true
2072 | }
2073 | }
2074 | },
2075 | "esprima": {
2076 | "version": "4.0.1",
2077 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
2078 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
2079 | "dev": true
2080 | },
2081 | "esquery": {
2082 | "version": "1.4.0",
2083 | "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
2084 | "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==",
2085 | "dev": true,
2086 | "requires": {
2087 | "estraverse": "^5.1.0"
2088 | },
2089 | "dependencies": {
2090 | "estraverse": {
2091 | "version": "5.2.0",
2092 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
2093 | "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
2094 | "dev": true
2095 | }
2096 | }
2097 | },
2098 | "esrecurse": {
2099 | "version": "4.3.0",
2100 | "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
2101 | "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
2102 | "dev": true,
2103 | "requires": {
2104 | "estraverse": "^5.2.0"
2105 | },
2106 | "dependencies": {
2107 | "estraverse": {
2108 | "version": "5.2.0",
2109 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz",
2110 | "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==",
2111 | "dev": true
2112 | }
2113 | }
2114 | },
2115 | "estraverse": {
2116 | "version": "4.3.0",
2117 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
2118 | "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
2119 | "dev": true
2120 | },
2121 | "esutils": {
2122 | "version": "2.0.3",
2123 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
2124 | "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
2125 | "dev": true
2126 | },
2127 | "fast-deep-equal": {
2128 | "version": "3.1.3",
2129 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
2130 | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
2131 | "dev": true
2132 | },
2133 | "fast-diff": {
2134 | "version": "1.2.0",
2135 | "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz",
2136 | "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==",
2137 | "dev": true
2138 | },
2139 | "fast-json-stable-stringify": {
2140 | "version": "2.1.0",
2141 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
2142 | "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
2143 | "dev": true
2144 | },
2145 | "fast-levenshtein": {
2146 | "version": "2.0.6",
2147 | "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
2148 | "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
2149 | "dev": true
2150 | },
2151 | "file-entry-cache": {
2152 | "version": "6.0.1",
2153 | "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
2154 | "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
2155 | "dev": true,
2156 | "requires": {
2157 | "flat-cache": "^3.0.4"
2158 | }
2159 | },
2160 | "flat-cache": {
2161 | "version": "3.0.4",
2162 | "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz",
2163 | "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==",
2164 | "dev": true,
2165 | "requires": {
2166 | "flatted": "^3.1.0",
2167 | "rimraf": "^3.0.2"
2168 | }
2169 | },
2170 | "flatted": {
2171 | "version": "3.2.2",
2172 | "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.2.tgz",
2173 | "integrity": "sha512-JaTY/wtrcSyvXJl4IMFHPKyFur1sE9AUqc0QnhOaJ0CxHtAoIV8pYDzeEfAaNEtGkOfq4gr3LBFmdXW5mOQFnA==",
2174 | "dev": true
2175 | },
2176 | "fs.realpath": {
2177 | "version": "1.0.0",
2178 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
2179 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
2180 | "dev": true
2181 | },
2182 | "function-bind": {
2183 | "version": "1.1.1",
2184 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
2185 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
2186 | "dev": true
2187 | },
2188 | "functional-red-black-tree": {
2189 | "version": "1.0.1",
2190 | "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
2191 | "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
2192 | "dev": true
2193 | },
2194 | "glob": {
2195 | "version": "7.2.0",
2196 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz",
2197 | "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==",
2198 | "dev": true,
2199 | "requires": {
2200 | "fs.realpath": "^1.0.0",
2201 | "inflight": "^1.0.4",
2202 | "inherits": "2",
2203 | "minimatch": "^3.0.4",
2204 | "once": "^1.3.0",
2205 | "path-is-absolute": "^1.0.0"
2206 | }
2207 | },
2208 | "glob-parent": {
2209 | "version": "5.1.2",
2210 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
2211 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
2212 | "dev": true,
2213 | "requires": {
2214 | "is-glob": "^4.0.1"
2215 | }
2216 | },
2217 | "globals": {
2218 | "version": "13.11.0",
2219 | "resolved": "https://registry.npmjs.org/globals/-/globals-13.11.0.tgz",
2220 | "integrity": "sha512-08/xrJ7wQjK9kkkRoI3OFUBbLx4f+6x3SGwcPvQ0QH6goFDrOU2oyAWrmh3dJezu65buo+HBMzAMQy6rovVC3g==",
2221 | "dev": true,
2222 | "requires": {
2223 | "type-fest": "^0.20.2"
2224 | }
2225 | },
2226 | "has": {
2227 | "version": "1.0.3",
2228 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
2229 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
2230 | "dev": true,
2231 | "requires": {
2232 | "function-bind": "^1.1.1"
2233 | }
2234 | },
2235 | "has-flag": {
2236 | "version": "4.0.0",
2237 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
2238 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
2239 | "dev": true
2240 | },
2241 | "iconv-lite": {
2242 | "version": "0.6.3",
2243 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
2244 | "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
2245 | "optional": true,
2246 | "requires": {
2247 | "safer-buffer": ">= 2.1.2 < 3.0.0"
2248 | }
2249 | },
2250 | "ignore": {
2251 | "version": "4.0.6",
2252 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
2253 | "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
2254 | "dev": true
2255 | },
2256 | "import-fresh": {
2257 | "version": "3.3.0",
2258 | "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
2259 | "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
2260 | "dev": true,
2261 | "requires": {
2262 | "parent-module": "^1.0.0",
2263 | "resolve-from": "^4.0.0"
2264 | }
2265 | },
2266 | "imurmurhash": {
2267 | "version": "0.1.4",
2268 | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
2269 | "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
2270 | "dev": true
2271 | },
2272 | "inflight": {
2273 | "version": "1.0.6",
2274 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
2275 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
2276 | "dev": true,
2277 | "requires": {
2278 | "once": "^1.3.0",
2279 | "wrappy": "1"
2280 | }
2281 | },
2282 | "inherits": {
2283 | "version": "2.0.4",
2284 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
2285 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
2286 | "dev": true
2287 | },
2288 | "is-core-module": {
2289 | "version": "2.6.0",
2290 | "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.6.0.tgz",
2291 | "integrity": "sha512-wShG8vs60jKfPWpF2KZRaAtvt3a20OAn7+IJ6hLPECpSABLcKtFKTTI4ZtH5QcBruBHlq+WsdHWyz0BCZW7svQ==",
2292 | "dev": true,
2293 | "requires": {
2294 | "has": "^1.0.3"
2295 | }
2296 | },
2297 | "is-extglob": {
2298 | "version": "2.1.1",
2299 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
2300 | "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
2301 | "dev": true
2302 | },
2303 | "is-fullwidth-code-point": {
2304 | "version": "3.0.0",
2305 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
2306 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
2307 | "dev": true
2308 | },
2309 | "is-glob": {
2310 | "version": "4.0.1",
2311 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
2312 | "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
2313 | "dev": true,
2314 | "requires": {
2315 | "is-extglob": "^2.1.1"
2316 | }
2317 | },
2318 | "isexe": {
2319 | "version": "2.0.0",
2320 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
2321 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
2322 | "dev": true
2323 | },
2324 | "js-tokens": {
2325 | "version": "4.0.0",
2326 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
2327 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
2328 | "dev": true
2329 | },
2330 | "js-yaml": {
2331 | "version": "3.14.1",
2332 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
2333 | "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
2334 | "dev": true,
2335 | "requires": {
2336 | "argparse": "^1.0.7",
2337 | "esprima": "^4.0.0"
2338 | }
2339 | },
2340 | "jsdoc-type-pratt-parser": {
2341 | "version": "1.1.1",
2342 | "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-1.1.1.tgz",
2343 | "integrity": "sha512-uelRmpghNwPBuZScwgBG/OzodaFk5RbO5xaivBdsAY70icWfShwZ7PCMO0x1zSkOa8T1FzHThmrdoyg/0AwV5g==",
2344 | "dev": true
2345 | },
2346 | "json-schema-traverse": {
2347 | "version": "0.4.1",
2348 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
2349 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
2350 | "dev": true
2351 | },
2352 | "json-stable-stringify-without-jsonify": {
2353 | "version": "1.0.1",
2354 | "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
2355 | "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
2356 | "dev": true
2357 | },
2358 | "levn": {
2359 | "version": "0.4.1",
2360 | "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
2361 | "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
2362 | "dev": true,
2363 | "requires": {
2364 | "prelude-ls": "^1.2.1",
2365 | "type-check": "~0.4.0"
2366 | }
2367 | },
2368 | "lodash": {
2369 | "version": "4.17.21",
2370 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
2371 | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
2372 | "dev": true
2373 | },
2374 | "lodash.clonedeep": {
2375 | "version": "4.5.0",
2376 | "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
2377 | "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=",
2378 | "dev": true
2379 | },
2380 | "lodash.merge": {
2381 | "version": "4.6.2",
2382 | "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
2383 | "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
2384 | "dev": true
2385 | },
2386 | "lodash.truncate": {
2387 | "version": "4.4.2",
2388 | "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz",
2389 | "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=",
2390 | "dev": true
2391 | },
2392 | "lru-cache": {
2393 | "version": "6.0.0",
2394 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
2395 | "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
2396 | "dev": true,
2397 | "requires": {
2398 | "yallist": "^4.0.0"
2399 | }
2400 | },
2401 | "minimatch": {
2402 | "version": "3.0.4",
2403 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
2404 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
2405 | "dev": true,
2406 | "requires": {
2407 | "brace-expansion": "^1.1.7"
2408 | }
2409 | },
2410 | "ms": {
2411 | "version": "2.1.2",
2412 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
2413 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
2414 | "dev": true
2415 | },
2416 | "natural-compare": {
2417 | "version": "1.4.0",
2418 | "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
2419 | "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
2420 | "dev": true
2421 | },
2422 | "once": {
2423 | "version": "1.4.0",
2424 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
2425 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
2426 | "dev": true,
2427 | "requires": {
2428 | "wrappy": "1"
2429 | }
2430 | },
2431 | "optionator": {
2432 | "version": "0.9.1",
2433 | "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz",
2434 | "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==",
2435 | "dev": true,
2436 | "requires": {
2437 | "deep-is": "^0.1.3",
2438 | "fast-levenshtein": "^2.0.6",
2439 | "levn": "^0.4.1",
2440 | "prelude-ls": "^1.2.1",
2441 | "type-check": "^0.4.0",
2442 | "word-wrap": "^1.2.3"
2443 | }
2444 | },
2445 | "parent-module": {
2446 | "version": "1.0.1",
2447 | "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
2448 | "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
2449 | "dev": true,
2450 | "requires": {
2451 | "callsites": "^3.0.0"
2452 | }
2453 | },
2454 | "path-is-absolute": {
2455 | "version": "1.0.1",
2456 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
2457 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
2458 | "dev": true
2459 | },
2460 | "path-key": {
2461 | "version": "3.1.1",
2462 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
2463 | "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
2464 | "dev": true
2465 | },
2466 | "path-parse": {
2467 | "version": "1.0.7",
2468 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
2469 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
2470 | "dev": true
2471 | },
2472 | "prelude-ls": {
2473 | "version": "1.2.1",
2474 | "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
2475 | "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
2476 | "dev": true
2477 | },
2478 | "prettier": {
2479 | "version": "2.4.1",
2480 | "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.4.1.tgz",
2481 | "integrity": "sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA==",
2482 | "dev": true
2483 | },
2484 | "prettier-linter-helpers": {
2485 | "version": "1.0.0",
2486 | "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz",
2487 | "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==",
2488 | "dev": true,
2489 | "requires": {
2490 | "fast-diff": "^1.1.2"
2491 | }
2492 | },
2493 | "progress": {
2494 | "version": "2.0.3",
2495 | "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
2496 | "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
2497 | "dev": true
2498 | },
2499 | "punycode": {
2500 | "version": "2.1.1",
2501 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
2502 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
2503 | "dev": true
2504 | },
2505 | "regexpp": {
2506 | "version": "3.2.0",
2507 | "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz",
2508 | "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==",
2509 | "dev": true
2510 | },
2511 | "regextras": {
2512 | "version": "0.8.0",
2513 | "resolved": "https://registry.npmjs.org/regextras/-/regextras-0.8.0.tgz",
2514 | "integrity": "sha512-k519uI04Z3SaY0fLX843MRXnDeG2+vHOFsyhiPZvNLe7r8rD2YNRjq4BQLZZ0oAr2NrtvZlICsXysGNFPGa3CQ==",
2515 | "dev": true
2516 | },
2517 | "require-from-string": {
2518 | "version": "2.0.2",
2519 | "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
2520 | "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
2521 | "dev": true
2522 | },
2523 | "resolve": {
2524 | "version": "1.20.0",
2525 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",
2526 | "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==",
2527 | "dev": true,
2528 | "requires": {
2529 | "is-core-module": "^2.2.0",
2530 | "path-parse": "^1.0.6"
2531 | }
2532 | },
2533 | "resolve-from": {
2534 | "version": "4.0.0",
2535 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
2536 | "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
2537 | "dev": true
2538 | },
2539 | "rimraf": {
2540 | "version": "3.0.2",
2541 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
2542 | "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
2543 | "dev": true,
2544 | "requires": {
2545 | "glob": "^7.1.3"
2546 | }
2547 | },
2548 | "safer-buffer": {
2549 | "version": "2.1.2",
2550 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
2551 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
2552 | "optional": true
2553 | },
2554 | "semver": {
2555 | "version": "7.3.5",
2556 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz",
2557 | "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==",
2558 | "dev": true,
2559 | "requires": {
2560 | "lru-cache": "^6.0.0"
2561 | }
2562 | },
2563 | "shebang-command": {
2564 | "version": "2.0.0",
2565 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
2566 | "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
2567 | "dev": true,
2568 | "requires": {
2569 | "shebang-regex": "^3.0.0"
2570 | }
2571 | },
2572 | "shebang-regex": {
2573 | "version": "3.0.0",
2574 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
2575 | "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
2576 | "dev": true
2577 | },
2578 | "slice-ansi": {
2579 | "version": "4.0.0",
2580 | "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz",
2581 | "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==",
2582 | "dev": true,
2583 | "requires": {
2584 | "ansi-styles": "^4.0.0",
2585 | "astral-regex": "^2.0.0",
2586 | "is-fullwidth-code-point": "^3.0.0"
2587 | }
2588 | },
2589 | "spdx-exceptions": {
2590 | "version": "2.3.0",
2591 | "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz",
2592 | "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==",
2593 | "dev": true
2594 | },
2595 | "spdx-expression-parse": {
2596 | "version": "3.0.1",
2597 | "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz",
2598 | "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==",
2599 | "dev": true,
2600 | "requires": {
2601 | "spdx-exceptions": "^2.1.0",
2602 | "spdx-license-ids": "^3.0.0"
2603 | }
2604 | },
2605 | "spdx-license-ids": {
2606 | "version": "3.0.10",
2607 | "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.10.tgz",
2608 | "integrity": "sha512-oie3/+gKf7QtpitB0LYLETe+k8SifzsX4KixvpOsbI6S0kRiRQ5MKOio8eMSAKQ17N06+wdEOXRiId+zOxo0hA==",
2609 | "dev": true
2610 | },
2611 | "sprintf-js": {
2612 | "version": "1.0.3",
2613 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
2614 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
2615 | "dev": true
2616 | },
2617 | "string-width": {
2618 | "version": "4.2.3",
2619 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
2620 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
2621 | "dev": true,
2622 | "requires": {
2623 | "emoji-regex": "^8.0.0",
2624 | "is-fullwidth-code-point": "^3.0.0",
2625 | "strip-ansi": "^6.0.1"
2626 | }
2627 | },
2628 | "strip-ansi": {
2629 | "version": "6.0.1",
2630 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
2631 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
2632 | "dev": true,
2633 | "requires": {
2634 | "ansi-regex": "^5.0.1"
2635 | }
2636 | },
2637 | "strip-json-comments": {
2638 | "version": "3.1.1",
2639 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
2640 | "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
2641 | "dev": true
2642 | },
2643 | "supports-color": {
2644 | "version": "7.2.0",
2645 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
2646 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
2647 | "dev": true,
2648 | "requires": {
2649 | "has-flag": "^4.0.0"
2650 | }
2651 | },
2652 | "table": {
2653 | "version": "6.7.1",
2654 | "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz",
2655 | "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==",
2656 | "dev": true,
2657 | "requires": {
2658 | "ajv": "^8.0.1",
2659 | "lodash.clonedeep": "^4.5.0",
2660 | "lodash.truncate": "^4.4.2",
2661 | "slice-ansi": "^4.0.0",
2662 | "string-width": "^4.2.0",
2663 | "strip-ansi": "^6.0.0"
2664 | },
2665 | "dependencies": {
2666 | "ajv": {
2667 | "version": "8.6.3",
2668 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.3.tgz",
2669 | "integrity": "sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==",
2670 | "dev": true,
2671 | "requires": {
2672 | "fast-deep-equal": "^3.1.1",
2673 | "json-schema-traverse": "^1.0.0",
2674 | "require-from-string": "^2.0.2",
2675 | "uri-js": "^4.2.2"
2676 | }
2677 | },
2678 | "json-schema-traverse": {
2679 | "version": "1.0.0",
2680 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
2681 | "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
2682 | "dev": true
2683 | }
2684 | }
2685 | },
2686 | "text-table": {
2687 | "version": "0.2.0",
2688 | "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
2689 | "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
2690 | "dev": true
2691 | },
2692 | "type-check": {
2693 | "version": "0.4.0",
2694 | "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
2695 | "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
2696 | "dev": true,
2697 | "requires": {
2698 | "prelude-ls": "^1.2.1"
2699 | }
2700 | },
2701 | "type-fest": {
2702 | "version": "0.20.2",
2703 | "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
2704 | "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
2705 | "dev": true
2706 | },
2707 | "typescript": {
2708 | "version": "4.4.3",
2709 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.3.tgz",
2710 | "integrity": "sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA==",
2711 | "dev": true
2712 | },
2713 | "uri-js": {
2714 | "version": "4.4.1",
2715 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
2716 | "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
2717 | "dev": true,
2718 | "requires": {
2719 | "punycode": "^2.1.0"
2720 | }
2721 | },
2722 | "v8-compile-cache": {
2723 | "version": "2.3.0",
2724 | "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz",
2725 | "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==",
2726 | "dev": true
2727 | },
2728 | "which": {
2729 | "version": "2.0.2",
2730 | "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
2731 | "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
2732 | "dev": true,
2733 | "requires": {
2734 | "isexe": "^2.0.0"
2735 | }
2736 | },
2737 | "word-wrap": {
2738 | "version": "1.2.3",
2739 | "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
2740 | "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
2741 | "dev": true
2742 | },
2743 | "wrappy": {
2744 | "version": "1.0.2",
2745 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
2746 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
2747 | "dev": true
2748 | },
2749 | "yallist": {
2750 | "version": "4.0.0",
2751 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
2752 | "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
2753 | "dev": true
2754 | }
2755 | }
2756 | }
2757 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mailhog",
3 | "version": "4.16.0",
4 | "title": "MailHog NodeJS library",
5 | "description": "A NodeJS library to interact with the MailHog API",
6 | "keywords": [
7 | "mailhog",
8 | "nodejs",
9 | "library",
10 | "api"
11 | ],
12 | "homepage": "https://github.com/blueimp/mailhog-node",
13 | "author": {
14 | "name": "Sebastian Tschan",
15 | "url": "https://blueimp.net"
16 | },
17 | "repository": {
18 | "type": "git",
19 | "url": "git://github.com/blueimp/mailhog-node.git"
20 | },
21 | "license": "MIT",
22 | "engines": {
23 | "node": ">=10.0.0"
24 | },
25 | "optionalDependencies": {
26 | "iconv-lite": "^0.6"
27 | },
28 | "devDependencies": {
29 | "@types/mocha": "9",
30 | "@types/node": "16",
31 | "eslint": "7",
32 | "eslint-config-blueimp": "2",
33 | "eslint-config-prettier": "8",
34 | "eslint-plugin-jsdoc": "36",
35 | "eslint-plugin-node": "11",
36 | "eslint-plugin-prettier": "4",
37 | "prettier": "2",
38 | "typescript": "4"
39 | },
40 | "eslintConfig": {
41 | "extends": [
42 | "blueimp",
43 | "plugin:jsdoc/recommended",
44 | "plugin:node/recommended",
45 | "plugin:prettier/recommended"
46 | ]
47 | },
48 | "prettier": {
49 | "arrowParens": "avoid",
50 | "proseWrap": "always",
51 | "semi": false,
52 | "singleQuote": true,
53 | "trailingComma": "none"
54 | },
55 | "scripts": {
56 | "pretest": "eslint . && tsc",
57 | "test": "docker-compose run --rm test",
58 | "posttest": "docker-compose down",
59 | "build": "rm -f libqp/index.d.ts index.d.ts && tsc -p tsconfig.d.json",
60 | "preversion": "npm test",
61 | "version": "npm run build && git add -A libqp/index.d.ts index.d.ts",
62 | "postversion": "git push --tags origin HEAD && npm publish"
63 | },
64 | "files": [
65 | "libqp/index.d.ts",
66 | "libqp/index.js",
67 | "index.d.ts",
68 | "index.js"
69 | ],
70 | "main": "index.js"
71 | }
72 |
--------------------------------------------------------------------------------
/sendmail.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | set -e
4 |
5 | cd "$(dirname "$0")"
6 |
7 | for MAIL in mail/*.eml; do
8 | sendmail "$@" < "$MAIL"
9 | done
10 |
--------------------------------------------------------------------------------
/tsconfig.d.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig",
3 | "compilerOptions": {
4 | "noEmit": false,
5 | "declaration": true,
6 | "emitDeclarationOnly": true
7 | },
8 | "include": ["libqp/index.js", "index.js"]
9 | }
10 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowJs": true,
4 | "checkJs": true,
5 | "noEmit": true
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/wait-for-hosts.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # Waits for the given host(s) to be available before executing a given command.
5 | # Tests for availability by using netcat to connect to the hosts via TCP.
6 | #
7 | # Usage:
8 | # ./wait-for-hosts.sh [-q] [-t seconds] [host:port] [...] [-- command args...]
9 | #
10 | # The script accepts multiple `host:port` combinations as arguments or defined
11 | # as WAIT_FOR_HOSTS environment variable, separating the `host:port`
12 | # combinations via spaces.
13 | #
14 | # The status output can be made quiet by adding the `-q` argument or by setting
15 | # the environment variable WAIT_FOR_HOSTS_QUIET to `1`.
16 | #
17 | # The default timeout of 10 seconds can be changed via `-t seconds` argument or
18 | # by setting the WAIT_FOR_HOSTS_TIMEOUT environment variable to the desired
19 | # number of seconds.
20 | #
21 | # The command defined after the `--` argument separator will be executed if all
22 | # the given hosts are reachable.
23 | #
24 | # Copyright 2016, Sebastian Tschan
25 | # https://blueimp.net
26 | #
27 | # Licensed under the MIT license:
28 | # https://opensource.org/licenses/MIT
29 | #
30 |
31 | set -e
32 |
33 | is_integer() {
34 | test "$1" -eq "$1" 2> /dev/null
35 | }
36 |
37 | set_timeout() {
38 | if ! is_integer "$1"; then
39 | printf 'Error: "%s" is not a valid timeout value.\n' "$1" >&2
40 | return 1
41 | fi
42 | TIMEOUT="$1"
43 | }
44 |
45 | connect_to_service() {
46 | nc -w 1 -z "$1" "$2"
47 | }
48 |
49 | quiet_echo() {
50 | if [ "$QUIET" -ne 1 ]; then echo "$@" >&2; fi
51 | }
52 |
53 | wait_for_host() {
54 | HOST="${1%:*}"
55 | PORT="${1#*:}"
56 | if ! is_integer "$PORT"; then
57 | printf 'Error: "%s" is not a valid host:port combination.\n' "$1" >&2
58 | return 1
59 | fi
60 | if [ "$QUIET" -ne 1 ]; then
61 | printf "Waiting for host: %-${PADDING}s ... " "$1" >&2
62 | fi
63 | TIME_LIMIT=$(($(date +%s)+TIMEOUT))
64 | while ! OUTPUT="$(connect_to_service "$HOST" "$PORT" 2>&1)"; do
65 | if [ "$(date +%s)" -ge "$TIME_LIMIT" ]; then
66 | quiet_echo timeout
67 | if [ -n "$OUTPUT" ]; then
68 | quiet_echo "$OUTPUT"
69 | fi
70 | return 1
71 | fi
72 | sleep 1
73 | done
74 | quiet_echo ok
75 | }
76 |
77 | set_padding() {
78 | PADDING=0
79 | while [ $# != 0 ]; do
80 | case "$1" in
81 | -t) shift 2;;
82 | -q) break;;
83 | --) break;;
84 | *) test ${#1} -gt $PADDING && PADDING=${#1}; shift;;
85 | esac
86 | done
87 | }
88 |
89 | QUIET=${WAIT_FOR_HOSTS_QUIET:-0}
90 | set_timeout "${WAIT_FOR_HOSTS_TIMEOUT:-10}"
91 |
92 | if [ "$QUIET" -ne 1 ]; then
93 | # shellcheck disable=SC2086
94 | set_padding $WAIT_FOR_HOSTS "$@"
95 | fi
96 |
97 | while [ $# != 0 ]; do
98 | case "$1" in
99 | -t) set_timeout "$2"; shift 2;;
100 | -q) QUIET=1; shift;;
101 | --) shift; break;;
102 | *) wait_for_host "$1"; shift;;
103 | esac
104 | done
105 |
106 | for HOST in $WAIT_FOR_HOSTS; do
107 | wait_for_host "$HOST"
108 | done
109 |
110 | exec "$@"
111 |
--------------------------------------------------------------------------------