mirror of
https://github.com/idanoo/GoScrobble
synced 2025-07-01 05:32:18 +00:00
0.2.0 - Mid migration
This commit is contained in:
parent
139e6a915e
commit
7e38fdbd7d
42393 changed files with 5358157 additions and 62 deletions
17
web/node_modules/@hapi/address/.travis.yml
generated
vendored
Normal file
17
web/node_modules/@hapi/address/.travis.yml
generated
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
language: node_js
|
||||
|
||||
node_js:
|
||||
- "8"
|
||||
- "10"
|
||||
- "12"
|
||||
- "node"
|
||||
|
||||
sudo: false
|
||||
|
||||
install:
|
||||
- "npm install"
|
||||
|
||||
os:
|
||||
- "linux"
|
||||
- "osx"
|
||||
- "windows"
|
49
web/node_modules/@hapi/address/API.md
generated
vendored
Executable file
49
web/node_modules/@hapi/address/API.md
generated
vendored
Executable file
|
@ -0,0 +1,49 @@
|
|||
## Methods
|
||||
|
||||
### `domain.analyze(domain, [options])`
|
||||
|
||||
Analyzes a string to verify it is a valid domain name where:
|
||||
- `domain` - the domain name string being verified.
|
||||
- `options` - optional settings:
|
||||
- `allowUnicode` - if `false`, Unicode characters are not allowd in domain names. Defaults to `true`.
|
||||
- `minDomainSegments` - the minimum number of domain segments (e.g. `x.y.z` has 3 segments) required. Defaults to `2`.
|
||||
- `tlds` - options to validate the top-level-domain segment (e.g. `com` in `example.com`). Can be set to one of:
|
||||
- `false` - disable TLD validation.
|
||||
- `true` - validate the TLD using the official list of [registered names](http://data.iana.org/TLD/tlds-alpha-by-domain.txt). This is the default setting.
|
||||
- an object with one (and only one) of:
|
||||
- `deny` - a `Set` with strings matching forbidden TLD values (all non-matching values are allowed).
|
||||
- `allow` - a `Set` with strings matching the only allowed TLD values. Can also be set to `true` which defaults to the official list of [registered names](http://data.iana.org/TLD/tlds-alpha-by-domain.txt).
|
||||
|
||||
If the `domain` is valid, no return value. If the `domain` is invalid, an object is returned with:
|
||||
- `error` - a string containing the reason the domain is invalid.
|
||||
|
||||
### `domain.isValid(domain, [options])`
|
||||
|
||||
Validates a string to verify it is a valid domain name where:
|
||||
- `domain` - the domain name string being verified.
|
||||
- `options` - same options as [`domain.analyze()`](#domainanalyzedomain-options).
|
||||
|
||||
### `email.analyze(email, [options])`
|
||||
|
||||
Analyzes a string to verify it is a valid email address where:
|
||||
- `email` - the email address string being verified.
|
||||
- `options` - optional settings:
|
||||
- `allowUnicode` - if `false`, Unicode characters are not allowd in the email address local and domain parts. Defaults to `true`.
|
||||
- `ignoreLength` - if `true`, the standards email maximum length limit is ignored. Defaults to `true`.
|
||||
- `minDomainSegments` - the minimum number of domain segments (e.g. `x.y.z` has 3 segments) required in the domain part. Defaults to `2`.
|
||||
- `tlds` - options to validate the top-level-domain segment (e.g. `com` in `example.com`) of the domain part. Can be set to one of:
|
||||
- `false` - disable TLD validation.
|
||||
- `true` - validate the TLD using the official list of [registered names](http://data.iana.org/TLD/tlds-alpha-by-domain.txt). This is the default setting.
|
||||
- an object with one (and only one) of:
|
||||
- `deny` - a `Set` with strings matching forbidden TLD values (all non-matching values are allowed).
|
||||
- `allow` - a `Set` with strings matching the only allowed TLD values. Can also be set to `true` which defaults to the official list of [registered names](http://data.iana.org/TLD/tlds-alpha-by-domain.txt).
|
||||
|
||||
If the `email` is valid, no return value. If the `email` is invalid, an object is returned with:
|
||||
- `error` - a string containing the reason the email is invalid.
|
||||
|
||||
|
||||
### `email.isValid(email, [options])`
|
||||
|
||||
Validates a string to verify it is a valid email address where:
|
||||
- `email` - the email address string being verified.
|
||||
- `options` - same options as [`email.analyze()`](#emailanalyzeemail-options).
|
3
web/node_modules/@hapi/address/CHANGELOG.md
generated
vendored
Normal file
3
web/node_modules/@hapi/address/CHANGELOG.md
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
Breaking changes are documented using GitHub issues, see [issues labeled "release notes"](https://github.com/hapijs/address/issues?q=is%3Aissue+label%3A%22release+notes%22).
|
||||
|
||||
If you want changes of a specific minor or patch release, you can browse the [GitHub milestones](https://github.com/hapijs/address/milestones?state=closed&direction=asc&sort=due_date).
|
9
web/node_modules/@hapi/address/LICENSE.md
generated
vendored
Normal file
9
web/node_modules/@hapi/address/LICENSE.md
generated
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
Copyright (c) 2019, Project contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* The names of any contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
16
web/node_modules/@hapi/address/README.md
generated
vendored
Executable file
16
web/node_modules/@hapi/address/README.md
generated
vendored
Executable file
|
@ -0,0 +1,16 @@
|
|||
<a href="https://hapi.dev"><img src="https://raw.githubusercontent.com/hapijs/assets/master/images/family.png" width="180px" align="right" /></a>
|
||||
|
||||
# @hapi/address
|
||||
|
||||
#### Validate email address and domain.
|
||||
|
||||
**address** is part of the **hapi** ecosystem and was designed to work seamlessly with the [hapi web framework](https://hapi.dev) and its other components (but works great on its own or with other frameworks). If you are using a different web framework and find this module useful, check out [hapi](https://hapi.dev) – they work even better together.
|
||||
|
||||
### Visit the [hapi.dev](https://hapi.dev) Developer Portal for tutorials, documentation, and support
|
||||
|
||||
## Useful resources
|
||||
|
||||
- [Documentation and API](https://hapi.dev/family/address/)
|
||||
- [Versions status](https://hapi.dev/resources/status/#address)
|
||||
- [Project policies](https://hapi.dev/policies/)
|
||||
- [Free and commercial support options](https://hapi.dev/support/)
|
238
web/node_modules/@hapi/address/bench/test.js
generated
vendored
Executable file
238
web/node_modules/@hapi/address/bench/test.js
generated
vendored
Executable file
|
@ -0,0 +1,238 @@
|
|||
'use strict';
|
||||
|
||||
const Bench = require('bench');
|
||||
const Address = require('../');
|
||||
const Isemail = require('isemail');
|
||||
|
||||
|
||||
const tests = [
|
||||
['', false],
|
||||
['\r', false],
|
||||
['test', false],
|
||||
['@', false],
|
||||
['test@', false],
|
||||
['test@io', false],
|
||||
['test@io', true, { minDomainSegments: 1 }],
|
||||
['@io', false],
|
||||
['@iana.org', false],
|
||||
['test@iana.org', true],
|
||||
['test@nominet.org.uk', true],
|
||||
['test@about.museum', true],
|
||||
['a@iana.org', true],
|
||||
['êjness@iana.org', true],
|
||||
['ñoñó1234@iana.org', true],
|
||||
['ñoñó1234@something.com', true],
|
||||
['伊昭傑@郵件.商務', true],
|
||||
['\ud801\udc37\ud852\udf62@iana.org', true],
|
||||
['test.test@iana.org', true],
|
||||
['.test@iana.org', false],
|
||||
['test.@iana.org', false],
|
||||
['test..iana.org', false],
|
||||
['test_exa-mple.com', false],
|
||||
['!#$%&`*+/=?^`{|}~@iana.org', true],
|
||||
['test\\@test@iana.org', false],
|
||||
['123@iana.org', true],
|
||||
['test@123.com', true],
|
||||
['test@iana.123', false],
|
||||
['test@255.255.255.255', false],
|
||||
['abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghiklm@iana.org', true],
|
||||
['abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghiklmn@iana.org', false],
|
||||
['\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06@iana.org', false],
|
||||
['test@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghiklm', false],
|
||||
['test@\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06.org', true],
|
||||
['test@abcdefghijklmnopqrstuvwxyzabcdefghijklmno\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06.org', false],
|
||||
['test@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghiklm.com', false],
|
||||
['test@mason-dixon.com', true],
|
||||
['test@-iana.org', false],
|
||||
['test@iana-.com', false],
|
||||
['test@.iana.org', false],
|
||||
['test@iana.org.', false],
|
||||
['test@iana..com', false],
|
||||
['abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghiklm@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijklmno', false],
|
||||
['abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghiklm@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06', false],
|
||||
['abcdef@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdef.hijklmnopqrstuv', false],
|
||||
['abcdef@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghi.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd\ud83d\ude06', false],
|
||||
['abcdef@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghi.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\ud83d\ude06', false],
|
||||
['a@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijkl.hijk', false],
|
||||
['a@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijkl.\ud83d\ude06', false],
|
||||
['\"\r', false],
|
||||
['\"test\"@iana.org', false],
|
||||
['\"\"@iana.org', false],
|
||||
['\"\"\"@iana.org', false],
|
||||
['\"\\a\"@iana.org', false],
|
||||
['\"\\\"\"@iana.org', false],
|
||||
['\"\\\"@iana.org', false],
|
||||
['\"\\\\\"@iana.org', false],
|
||||
['test\"@iana.org', false],
|
||||
['\"test@iana.org', false],
|
||||
['\"test\"test@iana.org', false],
|
||||
['test\"text\"@iana.org', false],
|
||||
['\"test\"\"test\"@iana.org', false],
|
||||
['\"test\".\"test\"@iana.org', false],
|
||||
['\"test\\ test\"@iana.org', false],
|
||||
['\"test\".test@iana.org', false],
|
||||
['\"test\u0000\"@iana.org', false],
|
||||
['\"test\\\u0000\"@iana.org', false],
|
||||
['\"test\r\n test\"@iana.org', false],
|
||||
['\"abcdefghijklmnopqrstuvwxyz abcdefghijklmnopqrstuvwxyz abcdefghj\"@iana.org', false],
|
||||
['\"abcdefghijklmnopqrstuvwxyz abcdefghijklmnopqrstuvwxyz abcdefg\\h\"@iana.org', false],
|
||||
['test@[255.255.255.255]', false],
|
||||
['test@a[255.255.255.255]', false],
|
||||
['test@[255.255.255]', false],
|
||||
['test@[255.255.255.255.255]', false],
|
||||
['test@[255.255.255.256]', false],
|
||||
['test@[1111:2222:3333:4444:5555:6666:7777:8888]', false],
|
||||
['test@[IPv6:1111:2222:3333:4444:5555:6666:7777]', false],
|
||||
['test@[IPv6:1111:2222:3333:4444:5555:6666:7777:8888]', false],
|
||||
['test@[IPv6:1111:2222:3333:4444:5555:6666:7777:8888:9999]', false],
|
||||
['test@[IPv6:1111:2222:3333:4444:5555:6666:7777:888G]', false],
|
||||
['test@[IPv6:1111:2222:3333:4444:5555:6666::8888]', false],
|
||||
['test@[IPv6:1111:2222:3333:4444:5555::8888]', false],
|
||||
['test@[IPv6:1111:2222:3333:4444:5555:6666::7777:8888]', false],
|
||||
['test@[IPv6::3333:4444:5555:6666:7777:8888]', false],
|
||||
['test@[IPv6:::3333:4444:5555:6666:7777:8888]', false],
|
||||
['test@[IPv6:1111::4444:5555::8888]', false],
|
||||
['test@[IPv6:::]', false],
|
||||
['test@[IPv6:1111:2222:3333:4444:5555:255.255.255.255]', false],
|
||||
['test@[IPv6:1111:2222:3333:4444:5555:6666:255.255.255.255]', false],
|
||||
['test@[IPv6:1111:2222:3333:4444:5555:6666:7777:255.255.255.255]', false],
|
||||
['test@[IPv6:1111:2222:3333:4444::255.255.255.255]', false],
|
||||
['test@[IPv6:1111:2222:3333:4444:5555:6666::255.255.255.255]', false],
|
||||
['test@[IPv6:1111:2222:3333:4444:::255.255.255.255]', false],
|
||||
['test@[IPv6::255.255.255.255]', false],
|
||||
['test@[255.255.255.255].local', false],
|
||||
['test@local.[255.255.255.255]', false],
|
||||
['test@local.[255.255.255.255].local', false],
|
||||
['test@local.(comment)[255.255.255.255].local', false],
|
||||
['test@local. [255.255.255.255].local', false],
|
||||
['test@local.[255.255.255.255](comment).local', false],
|
||||
['test@local.[255.255.255.255] .local', false],
|
||||
[' test @iana.org', false],
|
||||
['test@ iana .com', false],
|
||||
['test . test@iana.org', false],
|
||||
['\r\n test@iana.org', false],
|
||||
['\r\n \r\n test@iana.org', false],
|
||||
['(\r', false],
|
||||
['(comment)test@iana.org', false],
|
||||
['((comment)test@iana.org', false],
|
||||
['(comment(comment))test@iana.org', false],
|
||||
['test@(comment)iana.org', false],
|
||||
['test(comment)@iana.org', false],
|
||||
['test(comment)test@iana.org', false],
|
||||
['test@(comment)[255.255.255.255]', false],
|
||||
['(comment)abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghiklm@iana.org', false],
|
||||
['test@(comment)abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.com', false],
|
||||
['(comment)test@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijklmnopqrstuvwxyzabcdefghijk.abcdefghijklmnopqrst', false],
|
||||
['test@iana.org\n', false],
|
||||
['xn--test@iana.org', true],
|
||||
['test@iana.org-', false],
|
||||
['\"test@iana.org', false],
|
||||
['(test@iana.org', false],
|
||||
['test@(iana.org', false],
|
||||
['test@[1.2.3.4', false],
|
||||
['\"test\\\"@iana.org', false],
|
||||
['(comment\\)test@iana.org', false],
|
||||
['test@iana.org(comment\\)', false],
|
||||
['test@iana.org(comment\\', false],
|
||||
['test@[RFC-5322-domain-literal]', false],
|
||||
['test@[RFC-5322-郵件ñó-domain-literal]', false],
|
||||
['test@[RFC-5322]-domain-literal]', false],
|
||||
['test@[RFC-5322].domain-literal]', false],
|
||||
['test@[RFC-5322-[domain-literal]', false],
|
||||
['test@[', false],
|
||||
['test@[\u0007]', false],
|
||||
['test@[RFC-5322-\\\u0007-domain-literal]', false],
|
||||
['test@[RFC-5322-\\\t-domain-literal]', false],
|
||||
['test@[RFC-5322-\\]-domain-literal]', false],
|
||||
['test@[RFC-5322-\\郵-no-domain-literal]', false],
|
||||
['test@[RFC-5322--domain-literal]', false],
|
||||
['test@[RFC-5322-domain-literal\\]', false],
|
||||
['test@[RFC-5322-domain-literal\\', false],
|
||||
['test@[RFC 5322 domain literal]', false],
|
||||
['test@[RFC-5322-domain-literal] (comment)', false],
|
||||
['@iana.org', false],
|
||||
['test@.org', false],
|
||||
['\"\"@iana.org', false],
|
||||
['\"\"@iana.org', false],
|
||||
['\"\\\"@iana.org', false],
|
||||
['()test@iana.org', false],
|
||||
['()test@iana.org', false],
|
||||
['test@iana.org\r', false],
|
||||
['\rtest@iana.org', false],
|
||||
['\"\rtest\"@iana.org', false],
|
||||
['(\r)test@iana.org', false],
|
||||
['test@iana.org(\r)', false],
|
||||
['test@<iana>.org', false],
|
||||
['\ntest@iana.org', false],
|
||||
['\"\n\"@iana.org', false],
|
||||
['\"\\\n\"@iana.org', false],
|
||||
['(\n)test@iana.org', false],
|
||||
['\u0007@iana.org', false],
|
||||
['test@\u0007.org', false],
|
||||
['\"\u0007\"@iana.org', false],
|
||||
['\"\\\u0007\"@iana.org', false],
|
||||
['(\u0007)test@iana.org', false],
|
||||
['\r\ntest@iana.org', false],
|
||||
['\r\n \r\ntest@iana.org', false],
|
||||
[' \r\ntest@iana.org', false],
|
||||
[' \r\n test@iana.org', false],
|
||||
[' \r\n \r\ntest@iana.org', false],
|
||||
[' \r\n\r\ntest@iana.org', false],
|
||||
[' \r\n\r\n test@iana.org', false],
|
||||
['test@iana.org\r\n ', false],
|
||||
['test@iana.org\r\n \r\n ', false],
|
||||
['test@iana.org\r\n', false],
|
||||
['test@iana.org \r', false],
|
||||
['test@iana.org\r\n \r\n', false],
|
||||
['test@iana.org \r\n', false],
|
||||
['test@iana.org \r\n ', false],
|
||||
['test@iana.org \r\n \r\n', false],
|
||||
['test@iana.org \r\n\r\n', false],
|
||||
['test@iana.org \r\n\r\n ', false],
|
||||
['test@iana. org', false],
|
||||
['test@[\r', false],
|
||||
['test@[\r\n', false],
|
||||
[' test@iana.org', false],
|
||||
['test@iana.org ', false],
|
||||
['test@[IPv6:1::2:]', false],
|
||||
['\"test\\\u0094\"@iana.org', false],
|
||||
['test@iana/icann.org', false],
|
||||
['test@iana!icann.org', false],
|
||||
['test@iana?icann.org', false],
|
||||
['test@iana^icann.org', false],
|
||||
['test@iana{icann}.org', false],
|
||||
['test.(comment)test@iana.org', false],
|
||||
['test@iana.(comment)org', false],
|
||||
['test@iana(comment)iana.org', false],
|
||||
['(comment\r\n comment)test@iana.org', false],
|
||||
['test@org', true, { minDomainSegments: 1 }],
|
||||
['test\ud800@invalid', false],
|
||||
['\"\ud800\"@invalid', false],
|
||||
['\"\\\ud800\"@invalid', false],
|
||||
['(\ud800)thing@invalid', false],
|
||||
['\"\\\ud800\"@invalid', false],
|
||||
['test@\ud800\udfffñoñó郵件ñoñó郵件.郵件ñoñó郵件ñoñó郵件.ñoñó郵件ñoñó郵件.ñoñó郵件ñoñó郵件.ñoñó郵件ñoñó郵件.ñoñó郵件ñoñó郵件.ñoñó郵件ñoñó郵件.noñó郵件.商務', true],
|
||||
['test@\ud800\udfffñoñó郵件ñoñó郵件.郵件ñoñó郵件ñoñó郵件.ñoñó郵件ñoñó郵件.ñoñó郵件ñoñó郵件.ñoñó郵件ñoñó郵件.ñoñó郵件ñoñó郵件.ñoñó郵件ñoñó郵件.noñó郵件ñoñó郵.商務', false],
|
||||
['test@\ud800\udfffñoñó郵件ñoñó郵件.郵件ñoñó郵件ñoñó郵件.ñoñó郵件ñoñó郵件ñoñó郵件.ñoñó郵件ñoñó郵件.ñoñó郵件ñoñó郵件.ñoñó郵件ñoñó郵件.ñoñó郵件ñoñó郵件.ñoñó郵件ñoñó郵件.oñó郵件ñoñó郵件ñoñó郵件.商務', false],
|
||||
['test@ñoñoñó郵件\ud83d\ude06ñoñ.oñó郵件\uc138ñoñ.oñó郵件\u0644\u4eec\u010dñoñoñó郵件\u05dcño.ñoñó郵件\u092f\u672cñoñoñó郵件\uc138añoñ.oñó郵件\ud83d\ude06bc\uc138郵\ud83d\ude06ño.ñoñó郵件ñoñoñó郵件\ud83d\ude06ñoñoñó郵件\uc138ñoñ.oñó郵件\u0644\u4eecñoñoñó.郵件\ud83d\ude06ñoñoñó郵件郵\uc138ñoñoñó郵件\u0644\u4eecñoñoñó郵件.\ud83d\ude06ñoñoñó郵件郵\uc138\u0644\u4eec.郵件\ud83d\ude06ñoñoñó郵.件郵\uc138\u4eec\ud83d\ude06ñoñoñó件郵\uc138ñoñoñó郵件', false],
|
||||
['test@ñoñó郵件ñoñó郵件ñoñó郵件ñoñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件.商務', false],
|
||||
['\ud83d\ude06ñoñó郵件ñoñó郵件ñoñó\ud83d\ude06郵件ñoñoñó郵@\ud83d\ude06郵件ñoñó郵件ñoñó.\ud83d\ude06郵件ñoñó郵件ñoñó.\ud83d\ude06郵件ñoñó郵件ñoñó.郵件ñoñó郵件ñoñó\ud83d\ude06.郵件ñoñó郵件ñoñó.郵件ñoñó郵件.ñoñó郵件ñoñó.郵件ñoñó郵件.\ud83d\ude06郵件ñoñó郵件ñoñó.\ud83d\ude06郵件ñoñó郵件ñoñó.\ud83d\ude06商務.郵件ñoñó郵件ñoñó郵件.\ud83d\ude06商務.\ud83d\ude06商務.\ud83d\ude06商務', false]
|
||||
];
|
||||
|
||||
exports.compare = {
|
||||
address: function () {
|
||||
|
||||
for (const test of tests) {
|
||||
Address.email.isValid(test[0]);
|
||||
}
|
||||
},
|
||||
isemail: function () {
|
||||
|
||||
for (const test of tests) {
|
||||
Isemail.validate(test[0]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Bench.runMain();
|
103
web/node_modules/@hapi/address/lib/domain.js
generated
vendored
Executable file
103
web/node_modules/@hapi/address/lib/domain.js
generated
vendored
Executable file
|
@ -0,0 +1,103 @@
|
|||
'use strict';
|
||||
|
||||
const Url = require('url');
|
||||
|
||||
|
||||
const internals = {
|
||||
minDomainSegments: 2,
|
||||
nonAsciiRx: /[^\x00-\x7f]/,
|
||||
domainControlRx: /[\x00-\x20@\:\/]/, // Control + space + separators
|
||||
tldSegmentRx: /^[a-zA-Z](?:[a-zA-Z0-9\-]*[a-zA-Z0-9])?$/,
|
||||
domainSegmentRx: /^[a-zA-Z0-9](?:[a-zA-Z0-9\-]*[a-zA-Z0-9])?$/,
|
||||
URL: Url.URL || URL // $lab:coverage:ignore$
|
||||
};
|
||||
|
||||
|
||||
exports.analyze = function (domain, options = {}) {
|
||||
|
||||
if (typeof domain !== 'string') {
|
||||
throw new Error('Invalid input: domain must be a string');
|
||||
}
|
||||
|
||||
if (!domain) {
|
||||
return { error: 'Domain must be a non-empty string' };
|
||||
}
|
||||
|
||||
if (domain.length > 256) {
|
||||
return { error: 'Domain too long' };
|
||||
}
|
||||
|
||||
const ascii = !internals.nonAsciiRx.test(domain);
|
||||
if (!ascii) {
|
||||
if (options.allowUnicode === false) { // Defaults to true
|
||||
return { error: 'Domain contains forbidden Unicode characters' };
|
||||
}
|
||||
|
||||
domain = domain.normalize('NFC');
|
||||
}
|
||||
|
||||
if (internals.domainControlRx.test(domain)) {
|
||||
return { error: 'Domain contains invalid character' };
|
||||
}
|
||||
|
||||
domain = internals.punycode(domain);
|
||||
|
||||
// https://tools.ietf.org/html/rfc1035 section 2.3.1
|
||||
|
||||
const minDomainSegments = options.minDomainSegments || internals.minDomainSegments;
|
||||
|
||||
const segments = domain.split('.');
|
||||
if (segments.length < minDomainSegments) {
|
||||
return { error: 'Domain lacks the minimum required number of segments' };
|
||||
}
|
||||
|
||||
const tlds = options.tlds;
|
||||
if (tlds) {
|
||||
const tld = segments[segments.length - 1].toLowerCase();
|
||||
if (tlds.deny && tlds.deny.has(tld) ||
|
||||
tlds.allow && !tlds.allow.has(tld)) {
|
||||
|
||||
return { error: 'Domain uses forbidden TLD' };
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < segments.length; ++i) {
|
||||
const segment = segments[i];
|
||||
|
||||
if (!segment.length) {
|
||||
return { error: 'Domain contains empty dot-separated segment' };
|
||||
}
|
||||
|
||||
if (segment.length > 63) {
|
||||
return { error: 'Domain contains dot-separated segment that is too long' };
|
||||
}
|
||||
|
||||
if (i < segments.length - 1) {
|
||||
if (!internals.domainSegmentRx.test(segment)) {
|
||||
return { error: 'Domain contains invalid character' };
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!internals.tldSegmentRx.test(segment)) {
|
||||
return { error: 'Domain contains invalid tld character' };
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
exports.isValid = function (domain, options) {
|
||||
|
||||
return !exports.analyze(domain, options);
|
||||
};
|
||||
|
||||
|
||||
internals.punycode = function (domain) {
|
||||
|
||||
try {
|
||||
return new internals.URL(`http://${domain}`).host;
|
||||
}
|
||||
catch (err) {
|
||||
return domain;
|
||||
}
|
||||
};
|
169
web/node_modules/@hapi/address/lib/email.js
generated
vendored
Executable file
169
web/node_modules/@hapi/address/lib/email.js
generated
vendored
Executable file
|
@ -0,0 +1,169 @@
|
|||
'use strict';
|
||||
|
||||
const Util = require('util');
|
||||
|
||||
const Domain = require('./domain');
|
||||
|
||||
|
||||
const internals = {
|
||||
nonAsciiRx: /[^\x00-\x7f]/,
|
||||
encoder: new (Util.TextEncoder || TextEncoder)() // $lab:coverage:ignore$
|
||||
};
|
||||
|
||||
|
||||
exports.analyze = function (email, options) {
|
||||
|
||||
return internals.email(email, options);
|
||||
};
|
||||
|
||||
|
||||
exports.isValid = function (email, options) {
|
||||
|
||||
return !internals.email(email, options);
|
||||
};
|
||||
|
||||
|
||||
internals.email = function (email, options = {}) {
|
||||
|
||||
if (typeof email !== 'string') {
|
||||
throw new Error('Invalid input: email must be a string');
|
||||
}
|
||||
|
||||
if (!email) {
|
||||
return { error: 'Address must be a non-empty string' };
|
||||
}
|
||||
|
||||
// Unicode
|
||||
|
||||
const ascii = !internals.nonAsciiRx.test(email);
|
||||
if (!ascii) {
|
||||
if (options.allowUnicode === false) { // Defaults to true
|
||||
return { error: 'Address contains forbidden Unicode characters' };
|
||||
}
|
||||
|
||||
email = email.normalize('NFC');
|
||||
}
|
||||
|
||||
// Basic structure
|
||||
|
||||
const parts = email.split('@');
|
||||
if (parts.length !== 2) {
|
||||
return { error: parts.length > 2 ? 'Address cannot contain more than one @ character' : 'Address must contain one @ character' };
|
||||
}
|
||||
|
||||
const [local, domain] = parts;
|
||||
|
||||
if (!local) {
|
||||
return { error: 'Address local part cannot be empty' };
|
||||
}
|
||||
|
||||
if (!options.ignoreLength) {
|
||||
if (email.length > 254) { // http://tools.ietf.org/html/rfc5321#section-4.5.3.1.3
|
||||
return { error: 'Address too long' };
|
||||
}
|
||||
|
||||
if (internals.encoder.encode(local).length > 64) { // http://tools.ietf.org/html/rfc5321#section-4.5.3.1.1
|
||||
return { error: 'Address local part too long' };
|
||||
}
|
||||
}
|
||||
|
||||
// Validate parts
|
||||
|
||||
return internals.local(local, ascii) || Domain.analyze(domain, options);
|
||||
};
|
||||
|
||||
|
||||
internals.local = function (local, ascii) {
|
||||
|
||||
const segments = local.split('.');
|
||||
for (const segment of segments) {
|
||||
if (!segment.length) {
|
||||
return { error: 'Address local part contains empty dot-separated segment' };
|
||||
}
|
||||
|
||||
if (ascii) {
|
||||
if (!internals.atextRx.test(segment)) {
|
||||
return { error: 'Address local part contains invalid character' };
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const char of segment) {
|
||||
if (internals.atextRx.test(char)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const binary = internals.binary(char);
|
||||
if (!internals.atomRx.test(binary)) {
|
||||
return { error: 'Address local part contains invalid character' };
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
internals.binary = function (char) {
|
||||
|
||||
return Array.from(internals.encoder.encode(char)).map((v) => String.fromCharCode(v)).join('');
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
From RFC 5321:
|
||||
|
||||
Mailbox = Local-part "@" ( Domain / address-literal )
|
||||
|
||||
Local-part = Dot-string / Quoted-string
|
||||
Dot-string = Atom *("." Atom)
|
||||
Atom = 1*atext
|
||||
atext = ALPHA / DIGIT / "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "/" / "=" / "?" / "^" / "_" / "`" / "{" / "|" / "}" / "~"
|
||||
|
||||
Domain = sub-domain *("." sub-domain)
|
||||
sub-domain = Let-dig [Ldh-str]
|
||||
Let-dig = ALPHA / DIGIT
|
||||
Ldh-str = *( ALPHA / DIGIT / "-" ) Let-dig
|
||||
|
||||
ALPHA = %x41-5A / %x61-7A ; a-z, A-Z
|
||||
DIGIT = %x30-39 ; 0-9
|
||||
|
||||
From RFC 6531:
|
||||
|
||||
sub-domain =/ U-label
|
||||
atext =/ UTF8-non-ascii
|
||||
|
||||
UTF8-non-ascii = UTF8-2 / UTF8-3 / UTF8-4
|
||||
|
||||
UTF8-2 = %xC2-DF UTF8-tail
|
||||
UTF8-3 = %xE0 %xA0-BF UTF8-tail /
|
||||
%xE1-EC 2( UTF8-tail ) /
|
||||
%xED %x80-9F UTF8-tail /
|
||||
%xEE-EF 2( UTF8-tail )
|
||||
UTF8-4 = %xF0 %x90-BF 2( UTF8-tail ) /
|
||||
%xF1-F3 3( UTF8-tail ) /
|
||||
%xF4 %x80-8F 2( UTF8-tail )
|
||||
|
||||
UTF8-tail = %x80-BF
|
||||
|
||||
Note: The following are not supported:
|
||||
|
||||
RFC 5321: address-literal, Quoted-string
|
||||
RFC 5322: obs-*, CFWS
|
||||
*/
|
||||
|
||||
|
||||
internals.atextRx = /^[\w!#\$%&'\*\+\-/=\?\^`\{\|\}~]+$/; // _ included in \w
|
||||
|
||||
|
||||
internals.atomRx = new RegExp([
|
||||
|
||||
// %xC2-DF UTF8-tail
|
||||
'(?:[\\xc2-\\xdf][\\x80-\\xbf])',
|
||||
|
||||
// %xE0 %xA0-BF UTF8-tail %xE1-EC 2( UTF8-tail ) %xED %x80-9F UTF8-tail %xEE-EF 2( UTF8-tail )
|
||||
'(?:\\xe0[\\xa0-\\xbf][\\x80-\\xbf])|(?:[\\xe1-\\xec][\\x80-\\xbf]{2})|(?:\\xed[\\x80-\\x9f][\\x80-\\xbf])|(?:[\\xee-\\xef][\\x80-\\xbf]{2})',
|
||||
|
||||
// %xF0 %x90-BF 2( UTF8-tail ) %xF1-F3 3( UTF8-tail ) %xF4 %x80-8F 2( UTF8-tail )
|
||||
'(?:\\xf0[\\x90-\\xbf][\\x80-\\xbf]{2})|(?:[\\xf1-\\xf3][\\x80-\\xbf]{3})|(?:\\xf4[\\x80-\\x8f][\\x80-\\xbf]{2})'
|
||||
|
||||
].join('|'));
|
84
web/node_modules/@hapi/address/lib/index.js
generated
vendored
Executable file
84
web/node_modules/@hapi/address/lib/index.js
generated
vendored
Executable file
|
@ -0,0 +1,84 @@
|
|||
'use strict';
|
||||
|
||||
const Domain = require('./domain');
|
||||
const Email = require('./email');
|
||||
const Tlds = require('./tlds');
|
||||
|
||||
|
||||
const internals = {
|
||||
defaultTlds: { allow: Tlds, deny: null }
|
||||
};
|
||||
|
||||
|
||||
module.exports = {
|
||||
domain: {
|
||||
analyze(domain, options) {
|
||||
|
||||
options = internals.options(options);
|
||||
return Domain.analyze(domain, options);
|
||||
},
|
||||
|
||||
isValid(domain, options) {
|
||||
|
||||
options = internals.options(options);
|
||||
return Domain.isValid(domain, options);
|
||||
}
|
||||
},
|
||||
email: {
|
||||
analyze(email, options) {
|
||||
|
||||
options = internals.options(options);
|
||||
return Email.analyze(email, options);
|
||||
},
|
||||
|
||||
isValid(email, options) {
|
||||
|
||||
options = internals.options(options);
|
||||
return Email.isValid(email, options);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
internals.options = function (options) {
|
||||
|
||||
if (!options) {
|
||||
return { tlds: internals.defaultTlds };
|
||||
}
|
||||
|
||||
if (options.tlds === false) { // Defaults to true
|
||||
return options;
|
||||
}
|
||||
|
||||
if (!options.tlds ||
|
||||
options.tlds === true) {
|
||||
|
||||
return Object.assign({}, options, { tlds: internals.defaultTlds });
|
||||
}
|
||||
|
||||
if (typeof options.tlds !== 'object') {
|
||||
throw new Error('Invalid options: tlds must be a boolean or an object');
|
||||
}
|
||||
|
||||
if (options.tlds.deny) {
|
||||
if (options.tlds.deny instanceof Set === false) {
|
||||
throw new Error('Invalid options: tlds.deny must be a Set object');
|
||||
}
|
||||
|
||||
if (options.tlds.allow) {
|
||||
throw new Error('Invalid options: cannot specify both tlds.allow and tlds.deny lists');
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
if (options.tlds.allow === true) {
|
||||
return Object.assign({}, options, { tlds: internals.defaultTlds });
|
||||
}
|
||||
|
||||
if (options.tlds.allow instanceof Set === false) {
|
||||
throw new Error('Invalid options: tlds.allow must be a Set object or true');
|
||||
}
|
||||
|
||||
return options;
|
||||
};
|
1542
web/node_modules/@hapi/address/lib/tlds.js
generated
vendored
Executable file
1542
web/node_modules/@hapi/address/lib/tlds.js
generated
vendored
Executable file
File diff suppressed because it is too large
Load diff
23
web/node_modules/@hapi/address/package.json
generated
vendored
Normal file
23
web/node_modules/@hapi/address/package.json
generated
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"name": "@hapi/address",
|
||||
"description": "Email address and domain validation",
|
||||
"version": "2.1.4",
|
||||
"repository": "git://github.com/hapijs/address",
|
||||
"main": "lib/index.js",
|
||||
"keywords": [
|
||||
"email",
|
||||
"domain",
|
||||
"address",
|
||||
"validation"
|
||||
],
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"@hapi/code": "6.x.x",
|
||||
"@hapi/lab": "20.x.x"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "lab -a @hapi/code -t 100 -L",
|
||||
"test-cov-html": "lab -a @hapi/code -t 100 -L -r html -o coverage.html"
|
||||
},
|
||||
"license": "BSD-3-Clause"
|
||||
}
|
451
web/node_modules/@hapi/address/test/index.js
generated
vendored
Executable file
451
web/node_modules/@hapi/address/test/index.js
generated
vendored
Executable file
|
@ -0,0 +1,451 @@
|
|||
'use strict';
|
||||
|
||||
const Punycode = require('punycode');
|
||||
|
||||
const Code = require('@hapi/code');
|
||||
const Address = require('..');
|
||||
const Lab = require('@hapi/lab');
|
||||
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
const { describe, it } = exports.lab = Lab.script();
|
||||
const expect = Code.expect;
|
||||
|
||||
|
||||
describe('email', () => {
|
||||
|
||||
it('available as direct require', () => {
|
||||
|
||||
expect(require('../lib/email').isValid('test@example.com')).to.be.true();
|
||||
});
|
||||
|
||||
describe('analyze()', () => {
|
||||
|
||||
it('identifies error', () => {
|
||||
|
||||
const tests = [
|
||||
['', 'Address must be a non-empty string'],
|
||||
['êjness@iana.org', 'Address contains forbidden Unicode characters', { allowUnicode: false }],
|
||||
['test@test@test', 'Address cannot contain more than one @ character'],
|
||||
['test', 'Address must contain one @ character'],
|
||||
['@example.com', 'Address local part cannot be empty'],
|
||||
['test@', 'Domain must be a non-empty string'],
|
||||
['1234567890@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz.com', 'Address too long'],
|
||||
['1234567890123456789012345678901234567890123456789012345678901234567890@example.com', 'Address local part too long'],
|
||||
['x..y@example.com', 'Address local part contains empty dot-separated segment'],
|
||||
['x:y@example.com', 'Address local part contains invalid character'],
|
||||
['ê:y@example.com', 'Address local part contains invalid character'],
|
||||
['test@com', 'Domain lacks the minimum required number of segments'],
|
||||
['test@x.no-such-tld', 'Domain uses forbidden TLD'],
|
||||
['test@example..com', 'Domain contains empty dot-separated segment'],
|
||||
['test@1234567890123456789012345678901234567890123456789012345678901234567890.com', 'Domain contains dot-separated segment that is too long'],
|
||||
['test@example+.com', 'Domain contains invalid character', { tlds: false }],
|
||||
['test@example.com_', 'Domain contains invalid tld character', { tlds: false }]
|
||||
];
|
||||
|
||||
for (let i = 0; i < tests.length; ++i) {
|
||||
const email = tests[i];
|
||||
const output = Address.email.analyze(email[0], email[2]);
|
||||
const result = email[1];
|
||||
|
||||
if (!output ||
|
||||
output.error !== result) {
|
||||
|
||||
console.log(i, email[0]);
|
||||
}
|
||||
|
||||
expect(output.error).to.equal(result);
|
||||
}
|
||||
});
|
||||
|
||||
it('validates options', () => {
|
||||
|
||||
const tests = [
|
||||
['test@example.com', 'Invalid options: tlds must be a boolean or an object', { tlds: 1 }],
|
||||
['test@example.com', 'Invalid options: tlds.allow must be a Set object or true', { tlds: { allow: ['test'] } }],
|
||||
['test@example.com', 'Invalid options: tlds.deny must be a Set object', { tlds: { deny: ['test'] } }],
|
||||
['test@example.com', 'Invalid options: cannot specify both tlds.allow and tlds.deny lists', { tlds: { allow: new Set(), deny: new Set() } }],
|
||||
[1, 'Invalid input: email must be a string']
|
||||
];
|
||||
|
||||
for (let i = 0; i < tests.length; ++i) {
|
||||
const email = tests[i];
|
||||
expect(() => Address.email.analyze(email[0], email[2])).to.throw(email[1]);
|
||||
}
|
||||
});
|
||||
|
||||
describe('validated TLD', () => {
|
||||
|
||||
it('applies built-in list', () => {
|
||||
|
||||
expect(Address.email.analyze('test@example.com')).to.not.exist();
|
||||
expect(Address.email.analyze('test@example.com', { tlds: true })).to.not.exist();
|
||||
expect(Address.email.analyze('test@example.com', { tlds: { allow: true } })).to.not.exist();
|
||||
});
|
||||
|
||||
it('ignores built-in list', () => {
|
||||
|
||||
expect(Address.email.analyze('test@example.invalid-top', { tlds: false })).to.not.exist();
|
||||
});
|
||||
|
||||
it('denies listed tls', () => {
|
||||
|
||||
expect(Address.email.analyze('test@example.com', { tlds: { deny: new Set(['test']) } })).to.not.exist();
|
||||
expect(Address.email.analyze('test@example.com', { tlds: { deny: new Set(['com']) } })).to.equal({ error: 'Domain uses forbidden TLD' });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('isValid()', () => {
|
||||
|
||||
it('validates email', () => {
|
||||
|
||||
// Tests adapted from https://github.com/skeggse/isemail
|
||||
// Copyright (c) 2008-2019, Eli Skeggs, Dominic Sayers, GlobeSherpa
|
||||
|
||||
const tests = [
|
||||
['\r', false],
|
||||
['test', false],
|
||||
['@', false],
|
||||
['test@', false],
|
||||
['test@io', false],
|
||||
['test@io', true, { minDomainSegments: 1 }],
|
||||
['@io', false],
|
||||
['@iana.org', false],
|
||||
['test@iana.org', true],
|
||||
['test@nominet.org.uk', true],
|
||||
['test@about.museum', true],
|
||||
['a@iana.org', true],
|
||||
['êjness@iana.org', true],
|
||||
['ñoñó1234@iana.org', true],
|
||||
['ñoñó1234@something.com', true],
|
||||
['伊昭傑@郵件.商務', true, { tlds: { allow: new Set([Punycode.toASCII('商務')]) } }],
|
||||
['\ud801\udc37\ud852\udf62@iana.org', true],
|
||||
['test.test@iana.org', true],
|
||||
['.test@iana.org', false],
|
||||
['test.@iana.org', false],
|
||||
['test..iana.org', false],
|
||||
['test_exa-mple.com', false],
|
||||
['!#$%&`*+/=?^`{|}~@iana.org', true],
|
||||
['test\\@test@iana.org', false],
|
||||
['123@iana.org', true],
|
||||
['test@123.com', true],
|
||||
['test@iana.123', false],
|
||||
['test@255.255.255.255', false],
|
||||
['abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghiklm@iana.org', true],
|
||||
['abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghiklmn@iana.org', false],
|
||||
['\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06@iana.org', false],
|
||||
['test@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghiklm', false],
|
||||
['test@\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06.org', true],
|
||||
['test@abcdefghijklmnopqrstuvwxyzabcdefghijklmno\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06.org', false],
|
||||
['test@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghiklm.com', false],
|
||||
['test@mason-dixon.com', true],
|
||||
['test@-iana.org', false],
|
||||
['test@iana-.com', false],
|
||||
['test@.iana.org', false],
|
||||
['test@iana.org.', false],
|
||||
['test@iana..com', false],
|
||||
['abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghiklm@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijklmno', false],
|
||||
['abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghiklm@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.\ud83d\ude06\ud83d\ude06\ud83d\ude06\ud83d\ude06', false],
|
||||
['abcdef@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdef.hijklmnopqrstuv', false],
|
||||
['abcdef@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghi.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcd\ud83d\ude06', false],
|
||||
['abcdef@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghi.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz\ud83d\ude06', false],
|
||||
['a@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijkl.hijk', false],
|
||||
['a@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijkl.\ud83d\ude06', false],
|
||||
['\"\r', false],
|
||||
['\"test\"@iana.org', false],
|
||||
['\"\"@iana.org', false],
|
||||
['\"\"\"@iana.org', false],
|
||||
['\"\\a\"@iana.org', false],
|
||||
['\"\\\"\"@iana.org', false],
|
||||
['\"\\\"@iana.org', false],
|
||||
['\"\\\\\"@iana.org', false],
|
||||
['test\"@iana.org', false],
|
||||
['\"test@iana.org', false],
|
||||
['\"test\"test@iana.org', false],
|
||||
['test\"text\"@iana.org', false],
|
||||
['\"test\"\"test\"@iana.org', false],
|
||||
['\"test\".\"test\"@iana.org', false],
|
||||
['\"test\\ test\"@iana.org', false],
|
||||
['\"test\".test@iana.org', false],
|
||||
['\"test\u0000\"@iana.org', false],
|
||||
['\"test\\\u0000\"@iana.org', false],
|
||||
['\"test\r\n test\"@iana.org', false],
|
||||
['\"abcdefghijklmnopqrstuvwxyz abcdefghijklmnopqrstuvwxyz abcdefghj\"@iana.org', false],
|
||||
['\"abcdefghijklmnopqrstuvwxyz abcdefghijklmnopqrstuvwxyz abcdefg\\h\"@iana.org', false],
|
||||
['test@[255.255.255.255]', false],
|
||||
['test@a[255.255.255.255]', false],
|
||||
['test@[255.255.255]', false],
|
||||
['test@[255.255.255.255.255]', false],
|
||||
['test@[255.255.255.256]', false],
|
||||
['test@[1111:2222:3333:4444:5555:6666:7777:8888]', false],
|
||||
['test@[IPv6:1111:2222:3333:4444:5555:6666:7777]', false],
|
||||
['test@[IPv6:1111:2222:3333:4444:5555:6666:7777:8888]', false],
|
||||
['test@[IPv6:1111:2222:3333:4444:5555:6666:7777:8888:9999]', false],
|
||||
['test@[IPv6:1111:2222:3333:4444:5555:6666:7777:888G]', false],
|
||||
['test@[IPv6:1111:2222:3333:4444:5555:6666::8888]', false],
|
||||
['test@[IPv6:1111:2222:3333:4444:5555::8888]', false],
|
||||
['test@[IPv6:1111:2222:3333:4444:5555:6666::7777:8888]', false],
|
||||
['test@[IPv6::3333:4444:5555:6666:7777:8888]', false],
|
||||
['test@[IPv6:::3333:4444:5555:6666:7777:8888]', false],
|
||||
['test@[IPv6:1111::4444:5555::8888]', false],
|
||||
['test@[IPv6:::]', false],
|
||||
['test@[IPv6:1111:2222:3333:4444:5555:255.255.255.255]', false],
|
||||
['test@[IPv6:1111:2222:3333:4444:5555:6666:255.255.255.255]', false],
|
||||
['test@[IPv6:1111:2222:3333:4444:5555:6666:7777:255.255.255.255]', false],
|
||||
['test@[IPv6:1111:2222:3333:4444::255.255.255.255]', false],
|
||||
['test@[IPv6:1111:2222:3333:4444:5555:6666::255.255.255.255]', false],
|
||||
['test@[IPv6:1111:2222:3333:4444:::255.255.255.255]', false],
|
||||
['test@[IPv6::255.255.255.255]', false],
|
||||
['test@[255.255.255.255].local', false],
|
||||
['test@local.[255.255.255.255]', false],
|
||||
['test@local.[255.255.255.255].local', false],
|
||||
['test@local.(comment)[255.255.255.255].local', false],
|
||||
['test@local. [255.255.255.255].local', false],
|
||||
['test@local.[255.255.255.255](comment).local', false],
|
||||
['test@local.[255.255.255.255] .local', false],
|
||||
[' test @iana.org', false],
|
||||
['test@ iana .com', false],
|
||||
['test . test@iana.org', false],
|
||||
['\r\n test@iana.org', false],
|
||||
['\r\n \r\n test@iana.org', false],
|
||||
['(\r', false],
|
||||
['(comment)test@iana.org', false],
|
||||
['((comment)test@iana.org', false],
|
||||
['(comment(comment))test@iana.org', false],
|
||||
['test@(comment)iana.org', false],
|
||||
['test(comment)@iana.org', false],
|
||||
['test(comment)test@iana.org', false],
|
||||
['test@(comment)[255.255.255.255]', false],
|
||||
['(comment)abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghiklm@iana.org', false],
|
||||
['test@(comment)abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.com', false],
|
||||
['(comment)test@abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefg.abcdefghijklmnopqrstuvwxyzabcdefghijk.abcdefghijklmnopqrst', false],
|
||||
['test@iana.org\n', false],
|
||||
['xn--test@iana.org', true],
|
||||
['test@iana.org-', false],
|
||||
['\"test@iana.org', false],
|
||||
['(test@iana.org', false],
|
||||
['test@(iana.org', false],
|
||||
['test@[1.2.3.4', false],
|
||||
['\"test\\\"@iana.org', false],
|
||||
['(comment\\)test@iana.org', false],
|
||||
['test@iana.org(comment\\)', false],
|
||||
['test@iana.org(comment\\', false],
|
||||
['test@[RFC-5322-domain-literal]', false],
|
||||
['test@[RFC-5322-郵件ñó-domain-literal]', false],
|
||||
['test@[RFC-5322]-domain-literal]', false],
|
||||
['test@[RFC-5322].domain-literal]', false],
|
||||
['test@[RFC-5322-[domain-literal]', false],
|
||||
['test@[', false],
|
||||
['test@[\u0007]', false],
|
||||
['test@[RFC-5322-\\\u0007-domain-literal]', false],
|
||||
['test@[RFC-5322-\\\t-domain-literal]', false],
|
||||
['test@[RFC-5322-\\]-domain-literal]', false],
|
||||
['test@[RFC-5322-\\郵-no-domain-literal]', false],
|
||||
['test@[RFC-5322--domain-literal]', false],
|
||||
['test@[RFC-5322-domain-literal\\]', false],
|
||||
['test@[RFC-5322-domain-literal\\', false],
|
||||
['test@[RFC 5322 domain literal]', false],
|
||||
['test@[RFC-5322-domain-literal] (comment)', false],
|
||||
['@iana.org', false],
|
||||
['test@.org', false],
|
||||
['\"\"@iana.org', false],
|
||||
['\"\"@iana.org', false],
|
||||
['\"\\\"@iana.org', false],
|
||||
['()test@iana.org', false],
|
||||
['()test@iana.org', false],
|
||||
['test@iana.org\r', false],
|
||||
['\rtest@iana.org', false],
|
||||
['\"\rtest\"@iana.org', false],
|
||||
['(\r)test@iana.org', false],
|
||||
['test@iana.org(\r)', false],
|
||||
['test@<iana>.org', false],
|
||||
['\ntest@iana.org', false],
|
||||
['\"\n\"@iana.org', false],
|
||||
['\"\\\n\"@iana.org', false],
|
||||
['(\n)test@iana.org', false],
|
||||
['\u0007@iana.org', false],
|
||||
['test@\u0007.org', false],
|
||||
['\"\u0007\"@iana.org', false],
|
||||
['\"\\\u0007\"@iana.org', false],
|
||||
['(\u0007)test@iana.org', false],
|
||||
['\r\ntest@iana.org', false],
|
||||
['\r\n \r\ntest@iana.org', false],
|
||||
[' \r\ntest@iana.org', false],
|
||||
[' \r\n test@iana.org', false],
|
||||
[' \r\n \r\ntest@iana.org', false],
|
||||
[' \r\n\r\ntest@iana.org', false],
|
||||
[' \r\n\r\n test@iana.org', false],
|
||||
['test@iana.org\r\n ', false],
|
||||
['test@iana.org\r\n \r\n ', false],
|
||||
['test@iana.org\r\n', false],
|
||||
['test@iana.org \r', false],
|
||||
['test@iana.org\r\n \r\n', false],
|
||||
['test@iana.org \r\n', false],
|
||||
['test@iana.org \r\n ', false],
|
||||
['test@iana.org \r\n \r\n', false],
|
||||
['test@iana.org \r\n\r\n', false],
|
||||
['test@iana.org \r\n\r\n ', false],
|
||||
['test@iana. org', false],
|
||||
['test@[\r', false],
|
||||
['test@[\r\n', false],
|
||||
[' test@iana.org', false],
|
||||
['test@iana.org ', false],
|
||||
['test@[IPv6:1::2:]', false],
|
||||
['\"test\\\u0094\"@iana.org', false],
|
||||
['test@iana/icann.org', false],
|
||||
['test@iana!icann.org', false],
|
||||
['test@iana?icann.org', false],
|
||||
['test@iana^icann.org', false],
|
||||
['test@iana{icann}.org', false],
|
||||
['test.(comment)test@iana.org', false],
|
||||
['test@iana.(comment)org', false],
|
||||
['test@iana(comment)iana.org', false],
|
||||
['(comment\r\n comment)test@iana.org', false],
|
||||
['test@org', true, { minDomainSegments: 1 }],
|
||||
['test\ud800@invalid', false],
|
||||
['\"\ud800\"@invalid', false],
|
||||
['\"\\\ud800\"@invalid', false],
|
||||
['(\ud800)thing@invalid', false],
|
||||
['\"\\\ud800\"@invalid', false],
|
||||
['test@\ud800\udfffñoñó郵件ñoñó郵件.郵件ñoñó郵件ñoñó郵件.ñoñó郵件ñoñó郵件.ñoñó郵件ñoñó郵件.ñoñó郵件ñoñó郵件.ñoñó郵件ñoñó郵件.ñoñó郵件ñoñó郵件.noñó郵件ñoñó郵.商務', false, { tlds: { allow: new Set([Punycode.toASCII('商務')]) } }],
|
||||
['test@\ud800\udfffñoñó郵件ñoñó郵件.郵件ñoñó郵件ñoñó郵件.ñoñó郵件ñoñó郵件ñoñó郵件.ñoñó郵件ñoñó郵件.ñoñó郵件ñoñó郵件.ñoñó郵件ñoñó郵件.ñoñó郵件ñoñó郵件.ñoñó郵件ñoñó郵件.oñó郵件ñoñó郵件ñoñó郵件.商務', false, { tlds: { allow: new Set([Punycode.toASCII('商務')]) } }],
|
||||
['test@ñoñoñó郵件\ud83d\ude06ñoñ.oñó郵件\uc138ñoñ.oñó郵件\u0644\u4eec\u010dñoñoñó郵件\u05dcño.ñoñó郵件\u092f\u672cñoñoñó郵件\uc138añoñ.oñó郵件\ud83d\ude06bc\uc138郵\ud83d\ude06ño.ñoñó郵件ñoñoñó郵件\ud83d\ude06ñoñoñó郵件\uc138ñoñ.oñó郵件\u0644\u4eecñoñoñó.郵件\ud83d\ude06ñoñoñó郵件郵\uc138ñoñoñó郵件\u0644\u4eecñoñoñó郵件.\ud83d\ude06ñoñoñó郵件郵\uc138\u0644\u4eec.郵件\ud83d\ude06ñoñoñó郵.件郵\uc138\u4eec\ud83d\ude06ñoñoñó件郵\uc138ñoñoñó郵件', false, { tlds: { allow: new Set([Punycode.toASCII('商務')]) } }],
|
||||
['test@ñoñó郵件ñoñó郵件ñoñó郵件ñoñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件ñoñó郵件.商務', false, { tlds: { allow: new Set([Punycode.toASCII('商務')]) } }],
|
||||
['\ud83d\ude06ñoñó郵件ñoñó郵件ñoñó\ud83d\ude06郵件ñoñoñó郵@\ud83d\ude06郵件ñoñó郵件ñoñó.\ud83d\ude06郵件ñoñó郵件ñoñó.\ud83d\ude06郵件ñoñó郵件ñoñó.郵件ñoñó郵件ñoñó\ud83d\ude06.郵件ñoñó郵件ñoñó.郵件ñoñó郵件.ñoñó郵件ñoñó.郵件ñoñó郵件.\ud83d\ude06郵件ñoñó郵件ñoñó.\ud83d\ude06郵件ñoñó郵件ñoñó.\ud83d\ude06商務.郵件ñoñó郵件ñoñó郵件.\ud83d\ude06商務.\ud83d\ude06商務.\ud83d\ude06商務', false, { tlds: { allow: new Set([Punycode.toASCII('商務')]) } }],
|
||||
['test@[\0', false],
|
||||
['(\0)test@example.com', false],
|
||||
['shouldbe@invalid', false],
|
||||
['shouldbe@INVALID', false],
|
||||
['shouldbe@example.com', true],
|
||||
['shouldbe@example.COM', true],
|
||||
['apple-touch-icon-60x60@2x.png', false],
|
||||
['shouldbe@XN--UNUP4Y', true, { minDomainSegments: 1 }],
|
||||
['shouldbe@xn--unup4y', true, { minDomainSegments: 1 }],
|
||||
['shouldbe@\u6e38\u620f', true, { minDomainSegments: 1 }],
|
||||
['æøå', false],
|
||||
['1234567890abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvw@xyz.com', true, { ignoreLength: true }],
|
||||
['test@example.com@example.com', false],
|
||||
['test@example.com/path', false],
|
||||
['test@example.com:123', false]
|
||||
];
|
||||
|
||||
for (let i = 0; i < tests.length; ++i) {
|
||||
const email = tests[i];
|
||||
const valid = Address.email.isValid(email[0], email[2]);
|
||||
const result = email[1];
|
||||
|
||||
if (valid !== result) {
|
||||
const outcome = Address.email.analyze(email[0], email[2]);
|
||||
if (outcome) {
|
||||
console.log(i, email[0], outcome.error);
|
||||
}
|
||||
else {
|
||||
console.log(i, email[0]);
|
||||
}
|
||||
}
|
||||
|
||||
expect(valid).to.equal(result);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('domain', () => {
|
||||
|
||||
it('available as direct require', () => {
|
||||
|
||||
expect(require('../lib/domain').isValid('example.com')).to.be.true();
|
||||
});
|
||||
|
||||
describe('analyze()', () => {
|
||||
|
||||
it('identifies error', () => {
|
||||
|
||||
const tests = [
|
||||
['', 'Domain must be a non-empty string'],
|
||||
['êiana.org', 'Domain contains forbidden Unicode characters', { allowUnicode: false }],
|
||||
['abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz.com', 'Domain too long'],
|
||||
['com', 'Domain lacks the minimum required number of segments'],
|
||||
['x.no-such-tld', 'Domain uses forbidden TLD'],
|
||||
['example..com', 'Domain contains empty dot-separated segment'],
|
||||
['1234567890123456789012345678901234567890123456789012345678901234567890.com', 'Domain contains dot-separated segment that is too long'],
|
||||
['example+.com', 'Domain contains invalid character', { tlds: false }],
|
||||
['example.com_', 'Domain contains invalid tld character', { tlds: false }]
|
||||
];
|
||||
|
||||
for (let i = 0; i < tests.length; ++i) {
|
||||
const domain = tests[i];
|
||||
const output = Address.domain.analyze(domain[0], domain[2]);
|
||||
const result = domain[1];
|
||||
|
||||
if (!output ||
|
||||
output.error !== result) {
|
||||
|
||||
console.log(i, domain[0]);
|
||||
}
|
||||
|
||||
expect(output.error).to.equal(result);
|
||||
}
|
||||
});
|
||||
|
||||
it('validates options', () => {
|
||||
|
||||
const tests = [
|
||||
['example.com', 'Invalid options: tlds must be a boolean or an object', { tlds: 1 }],
|
||||
['example.com', 'Invalid options: tlds.allow must be a Set object or true', { tlds: { allow: ['test'] } }],
|
||||
['example.com', 'Invalid options: tlds.deny must be a Set object', { tlds: { deny: ['test'] } }],
|
||||
['example.com', 'Invalid options: cannot specify both tlds.allow and tlds.deny lists', { tlds: { allow: new Set(), deny: new Set() } }],
|
||||
[1, 'Invalid input: domain must be a string']
|
||||
];
|
||||
|
||||
for (let i = 0; i < tests.length; ++i) {
|
||||
const domain = tests[i];
|
||||
expect(() => Address.domain.analyze(domain[0], domain[2])).to.throw(domain[1]);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('isValid()', () => {
|
||||
|
||||
it('validates domain', () => {
|
||||
|
||||
const tests = [
|
||||
['\r', false],
|
||||
['test', false],
|
||||
['@', false],
|
||||
['iana.org', true],
|
||||
['nominet.org.uk', true],
|
||||
['about.museum', true],
|
||||
['x.商務', true, { tlds: { allow: new Set([Punycode.toASCII('商務')]) } }],
|
||||
['iana.123', false],
|
||||
['255.255.255.255', false],
|
||||
['XN--UNUP4Y', true, { minDomainSegments: 1 }],
|
||||
['test@example.com', false],
|
||||
['test:example.com', false],
|
||||
['example.com:123', false],
|
||||
['example.com/path', false]
|
||||
];
|
||||
|
||||
for (let i = 0; i < tests.length; ++i) {
|
||||
const domain = tests[i];
|
||||
const valid = Address.domain.isValid(domain[0], domain[2]);
|
||||
const result = domain[1];
|
||||
|
||||
if (valid !== result) {
|
||||
const outcome = Address.domain.analyze(domain[0], domain[2]);
|
||||
if (outcome) {
|
||||
console.log(i, domain[0], outcome.error);
|
||||
}
|
||||
else {
|
||||
console.log(i, domain[0]);
|
||||
}
|
||||
}
|
||||
|
||||
expect(valid).to.equal(result);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
3
web/node_modules/@hapi/bourne/.npmignore
generated
vendored
Normal file
3
web/node_modules/@hapi/bourne/.npmignore
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
*
|
||||
!lib/**
|
||||
!.npmignore
|
9
web/node_modules/@hapi/bourne/LICENSE.md
generated
vendored
Executable file
9
web/node_modules/@hapi/bourne/LICENSE.md
generated
vendored
Executable file
|
@ -0,0 +1,9 @@
|
|||
Copyright (c) 2019, Sideway Inc, and project contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* The names of any contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS OFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
54
web/node_modules/@hapi/bourne/README.md
generated
vendored
Executable file
54
web/node_modules/@hapi/bourne/README.md
generated
vendored
Executable file
|
@ -0,0 +1,54 @@
|
|||
<a href="http://hapijs.com"><img src="https://raw.githubusercontent.com/hapijs/assets/master/images/family.png" width="180px" align="right" /></a>
|
||||
|
||||
# Bourne. JSON Bourne.
|
||||
|
||||
`JSON.parse()` drop-in replacement with prototype poisoning protection
|
||||
|
||||
[](https://travis-ci.org/hapijs/bourne)
|
||||
|
||||
## Introduction
|
||||
|
||||
Consider this:
|
||||
|
||||
```
|
||||
> const a = '{"__proto__":{ "b":5}}';
|
||||
'{"__proto__":{ "b":5}}'
|
||||
|
||||
> const b = JSON.parse(a);
|
||||
{ __proto__: { b: 5 } }
|
||||
|
||||
> b.b;
|
||||
undefined
|
||||
|
||||
> const c = Object.assign({}, b);
|
||||
{}
|
||||
|
||||
> c.b
|
||||
5
|
||||
```
|
||||
|
||||
The problem is that `JSON.parse()` retains the `__proto__` property as a plain object key. By
|
||||
itself, this is not a security issue. However, as soon as that object is assigned to another or
|
||||
iterated on and values copied, the `__proto__` property leaks and becomes the object's prototype.
|
||||
|
||||
## API
|
||||
|
||||
### `Bourne.parse(text, [reviver], [options])`
|
||||
|
||||
Parses a given JSON-formatted text into an object where:
|
||||
- `text` - the JSON text string.
|
||||
- `reviver` - the `JSON.parse()` optional `reviver` argument.
|
||||
- `options` - optional configuration object where:
|
||||
- `protoAction` - optional string with one of:
|
||||
- `'error'` - throw a `SyntaxError` when a `__proto__` key is found. This is the default value.
|
||||
- `'remove'` - deletes any `__proto__` keys from the result object.
|
||||
- `'ignore'` - skips all validation (same as calling `JSON.parse()` directly).
|
||||
|
||||
### `Bourne.scan(obj, [options])`
|
||||
|
||||
Scans a given object for prototype properties where:
|
||||
- `obj` - the object being scanned.
|
||||
- `options` - optional configuration object where:
|
||||
- `protoAction` - optional string with one of:
|
||||
- `'error'` - throw a `SyntaxError` when a `__proto__` key is found. This is the default value.
|
||||
- `'remove'` - deletes any `__proto__` keys from the input `obj`.
|
97
web/node_modules/@hapi/bourne/lib/index.js
generated
vendored
Executable file
97
web/node_modules/@hapi/bourne/lib/index.js
generated
vendored
Executable file
|
@ -0,0 +1,97 @@
|
|||
'use strict';
|
||||
|
||||
|
||||
const internals = {
|
||||
suspectRx: /"(?:_|\\u005[Ff])(?:_|\\u005[Ff])(?:p|\\u0070)(?:r|\\u0072)(?:o|\\u006[Ff])(?:t|\\u0074)(?:o|\\u006[Ff])(?:_|\\u005[Ff])(?:_|\\u005[Ff])"\s*\:/
|
||||
};
|
||||
|
||||
|
||||
exports.parse = function (text, reviver, options) {
|
||||
|
||||
// Normalize arguments
|
||||
|
||||
if (!options) {
|
||||
if (reviver &&
|
||||
typeof reviver === 'object') {
|
||||
|
||||
options = reviver;
|
||||
reviver = undefined;
|
||||
}
|
||||
else {
|
||||
options = {};
|
||||
}
|
||||
}
|
||||
|
||||
// Parse normally, allowing exceptions
|
||||
|
||||
const obj = JSON.parse(text, reviver);
|
||||
|
||||
// options.protoAction: 'error' (default) / 'remove' / 'ignore'
|
||||
|
||||
if (options.protoAction === 'ignore') {
|
||||
return obj;
|
||||
}
|
||||
|
||||
// Ignore null and non-objects
|
||||
|
||||
if (!obj ||
|
||||
typeof obj !== 'object') {
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
// Check original string for potential exploit
|
||||
|
||||
if (!text.match(internals.suspectRx)) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
// Scan result for proto keys
|
||||
|
||||
exports.scan(obj, options);
|
||||
|
||||
return obj;
|
||||
};
|
||||
|
||||
|
||||
exports.scan = function (obj, options) {
|
||||
|
||||
options = options || {};
|
||||
|
||||
let next = [obj];
|
||||
|
||||
while (next.length) {
|
||||
const nodes = next;
|
||||
next = [];
|
||||
|
||||
for (const node of nodes) {
|
||||
if (Object.prototype.hasOwnProperty.call(node, '__proto__')) { // Avoid calling node.hasOwnProperty directly
|
||||
if (options.protoAction !== 'remove') {
|
||||
throw new SyntaxError('Object contains forbidden prototype property');
|
||||
}
|
||||
|
||||
delete node.__proto__;
|
||||
}
|
||||
|
||||
for (const key in node) {
|
||||
const value = node[key];
|
||||
if (value &&
|
||||
typeof value === 'object') {
|
||||
|
||||
next.push(node[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
exports.safeParse = function (text, reviver) {
|
||||
|
||||
try {
|
||||
return exports.parse(text, reviver);
|
||||
}
|
||||
catch (ignoreError) {
|
||||
return null;
|
||||
}
|
||||
};
|
24
web/node_modules/@hapi/bourne/package.json
generated
vendored
Normal file
24
web/node_modules/@hapi/bourne/package.json
generated
vendored
Normal file
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"name": "@hapi/bourne",
|
||||
"description": "JSON parse with prototype poisoning protection",
|
||||
"version": "1.3.2",
|
||||
"repository": "git://github.com/hapijs/bourne",
|
||||
"main": "lib/index.js",
|
||||
"keywords": [
|
||||
"JSON",
|
||||
"parse",
|
||||
"safe",
|
||||
"prototype"
|
||||
],
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"@hapi/code": "5.x.x",
|
||||
"@hapi/lab": "18.x.x",
|
||||
"benchmark": "^2.1.4"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "lab -a @hapi/code -t 100 -L",
|
||||
"test-cov-html": "lab -a @hapi/code -r html -o coverage.html"
|
||||
},
|
||||
"license": "BSD-3-Clause"
|
||||
}
|
3
web/node_modules/@hapi/hoek/CHANGELOG.md
generated
vendored
Normal file
3
web/node_modules/@hapi/hoek/CHANGELOG.md
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
Breaking changes are documented using GitHub issues, see [issues labeled "release notes"](https://github.com/hapijs/hoek/issues?q=is%3Aissue+label%3A%22release+notes%22).
|
||||
|
||||
If you want changes of a specific minor or patch release, you can browse the [GitHub milestones](https://github.com/hapijs/hoek/milestones?state=closed&direction=asc&sort=due_date).
|
12
web/node_modules/@hapi/hoek/LICENSE.md
generated
vendored
Executable file
12
web/node_modules/@hapi/hoek/LICENSE.md
generated
vendored
Executable file
|
@ -0,0 +1,12 @@
|
|||
Copyright (c) 2011-2019, Sideway Inc, and project contributors
|
||||
Copyright (c) 2011-2014, Walmart
|
||||
Copyright (c) 2011, Yahoo Inc.
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* The names of any contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS OFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
18
web/node_modules/@hapi/hoek/README.md
generated
vendored
Executable file
18
web/node_modules/@hapi/hoek/README.md
generated
vendored
Executable file
|
@ -0,0 +1,18 @@
|
|||
<a href="https://hapi.dev"><img src="https://raw.githubusercontent.com/hapijs/assets/master/images/family.png" width="180px" align="right" /></a>
|
||||
|
||||
# @hapi/hoek
|
||||
|
||||
#### Utility methods for the hapi ecosystem.
|
||||
|
||||
**hoek** is part of the **hapi** ecosystem and was designed to work seamlessly with the [hapi web framework](https://hapi.dev) and its other components (but works great on its own or with other frameworks). If you are using a different web framework and find this module useful, check out [hapi](https://hapi.dev) – they work even better together.
|
||||
|
||||
This module is not intended to solve every problem for everyone, but rather as a central place to store hapi-specific methods. If you're looking for a general purpose utility module, check out [lodash](https://github.com/lodash/lodash).
|
||||
|
||||
### Visit the [hapi.dev](https://hapi.dev) Developer Portal for tutorials, documentation, and support
|
||||
|
||||
## Useful resources
|
||||
|
||||
- [Documentation and API](https://hapi.dev/family/hoek/)
|
||||
- [Version status](https://hapi.dev/resources/status/#hoek) (builds, dependencies, node versions, licenses, eol)
|
||||
- [Project policies](https://hapi.dev/policies/)
|
||||
- [Free and commercial support options](https://hapi.dev/support/)
|
55
web/node_modules/@hapi/hoek/lib/applyToDefaults.js
generated
vendored
Executable file
55
web/node_modules/@hapi/hoek/lib/applyToDefaults.js
generated
vendored
Executable file
|
@ -0,0 +1,55 @@
|
|||
'use strict';
|
||||
|
||||
const Assert = require('./assert');
|
||||
const Clone = require('./clone');
|
||||
const Merge = require('./merge');
|
||||
const Utils = require('./utils');
|
||||
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
module.exports = function (defaults, source, options = {}) {
|
||||
|
||||
Assert(defaults && typeof defaults === 'object', 'Invalid defaults value: must be an object');
|
||||
Assert(!source || source === true || typeof source === 'object', 'Invalid source value: must be true, falsy or an object');
|
||||
Assert(typeof options === 'object', 'Invalid options: must be an object');
|
||||
|
||||
if (!source) { // If no source, return null
|
||||
return null;
|
||||
}
|
||||
|
||||
if (options.shallow) {
|
||||
return internals.applyToDefaultsWithShallow(defaults, source, options);
|
||||
}
|
||||
|
||||
const copy = Clone(defaults);
|
||||
|
||||
if (source === true) { // If source is set to true, use defaults
|
||||
return copy;
|
||||
}
|
||||
|
||||
const nullOverride = options.nullOverride !== undefined ? options.nullOverride : false;
|
||||
return Merge(copy, source, { nullOverride, mergeArrays: false });
|
||||
};
|
||||
|
||||
|
||||
internals.applyToDefaultsWithShallow = function (defaults, source, options) {
|
||||
|
||||
const keys = options.shallow;
|
||||
Assert(Array.isArray(keys), 'Invalid keys');
|
||||
|
||||
options = Object.assign({}, options);
|
||||
options.shallow = false;
|
||||
|
||||
const copy = Clone(defaults, { shallow: keys });
|
||||
|
||||
if (source === true) { // If source is set to true, use defaults
|
||||
return copy;
|
||||
}
|
||||
|
||||
const storage = Utils.store(source, keys); // Move shallow copy items to storage
|
||||
Merge(copy, source, { mergeArrays: false, nullOverride: false }); // Deep copy the rest
|
||||
Utils.restore(copy, source, storage); // Shallow copy the stored items and restore
|
||||
return copy;
|
||||
};
|
21
web/node_modules/@hapi/hoek/lib/assert.js
generated
vendored
Executable file
21
web/node_modules/@hapi/hoek/lib/assert.js
generated
vendored
Executable file
|
@ -0,0 +1,21 @@
|
|||
'use strict';
|
||||
|
||||
const AssertError = require('./error');
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
module.exports = function (condition, ...args) {
|
||||
|
||||
if (condition) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.length === 1 &&
|
||||
args[0] instanceof Error) {
|
||||
|
||||
throw args[0];
|
||||
}
|
||||
|
||||
throw new AssertError(args);
|
||||
};
|
29
web/node_modules/@hapi/hoek/lib/bench.js
generated
vendored
Executable file
29
web/node_modules/@hapi/hoek/lib/bench.js
generated
vendored
Executable file
|
@ -0,0 +1,29 @@
|
|||
'use strict';
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
module.exports = internals.Bench = class {
|
||||
|
||||
constructor() {
|
||||
|
||||
this.ts = 0;
|
||||
this.reset();
|
||||
}
|
||||
|
||||
reset() {
|
||||
|
||||
this.ts = internals.Bench.now();
|
||||
}
|
||||
|
||||
elapsed() {
|
||||
|
||||
return internals.Bench.now() - this.ts;
|
||||
}
|
||||
|
||||
static now() {
|
||||
|
||||
const ts = process.hrtime();
|
||||
return (ts[0] * 1e3) + (ts[1] / 1e6);
|
||||
}
|
||||
};
|
12
web/node_modules/@hapi/hoek/lib/block.js
generated
vendored
Executable file
12
web/node_modules/@hapi/hoek/lib/block.js
generated
vendored
Executable file
|
@ -0,0 +1,12 @@
|
|||
'use strict';
|
||||
|
||||
const Ignore = require('./ignore');
|
||||
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
module.exports = function () {
|
||||
|
||||
return new Promise(Ignore); // $lab:coverage:ignore$
|
||||
};
|
161
web/node_modules/@hapi/hoek/lib/clone.js
generated
vendored
Executable file
161
web/node_modules/@hapi/hoek/lib/clone.js
generated
vendored
Executable file
|
@ -0,0 +1,161 @@
|
|||
'use strict';
|
||||
|
||||
const Types = require('./types');
|
||||
const Utils = require('./utils');
|
||||
|
||||
|
||||
const internals = {
|
||||
needsProtoHack: new Set([Types.set, Types.map, Types.weakSet, Types.weakMap])
|
||||
};
|
||||
|
||||
|
||||
module.exports = internals.clone = function (obj, options = {}, _seen = null) {
|
||||
|
||||
if (typeof obj !== 'object' ||
|
||||
obj === null) {
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
let clone = internals.clone;
|
||||
let seen = _seen;
|
||||
|
||||
if (options.shallow) {
|
||||
if (options.shallow !== true) {
|
||||
return internals.cloneWithShallow(obj, options);
|
||||
}
|
||||
|
||||
clone = (value) => value;
|
||||
}
|
||||
else {
|
||||
seen = seen || new Map();
|
||||
|
||||
const lookup = seen.get(obj);
|
||||
if (lookup) {
|
||||
return lookup;
|
||||
}
|
||||
}
|
||||
|
||||
// Built-in object types
|
||||
|
||||
const baseProto = Types.getInternalProto(obj);
|
||||
if (baseProto === Types.buffer) {
|
||||
return Buffer && Buffer.from(obj); // $lab:coverage:ignore$
|
||||
}
|
||||
|
||||
if (baseProto === Types.date) {
|
||||
return new Date(obj.getTime());
|
||||
}
|
||||
|
||||
if (baseProto === Types.regex) {
|
||||
return new RegExp(obj);
|
||||
}
|
||||
|
||||
// Generic objects
|
||||
|
||||
const newObj = internals.base(obj, baseProto, options);
|
||||
if (newObj === obj) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
if (seen) {
|
||||
seen.set(obj, newObj); // Set seen, since obj could recurse
|
||||
}
|
||||
|
||||
if (baseProto === Types.set) {
|
||||
for (const value of obj) {
|
||||
newObj.add(clone(value, options, seen));
|
||||
}
|
||||
}
|
||||
else if (baseProto === Types.map) {
|
||||
for (const [key, value] of obj) {
|
||||
newObj.set(key, clone(value, options, seen));
|
||||
}
|
||||
}
|
||||
|
||||
const keys = Utils.keys(obj, options);
|
||||
for (const key of keys) {
|
||||
if (key === '__proto__') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (baseProto === Types.array &&
|
||||
key === 'length') {
|
||||
|
||||
newObj.length = obj.length;
|
||||
continue;
|
||||
}
|
||||
|
||||
const descriptor = Object.getOwnPropertyDescriptor(obj, key);
|
||||
if (descriptor) {
|
||||
if (descriptor.get ||
|
||||
descriptor.set) {
|
||||
|
||||
Object.defineProperty(newObj, key, descriptor);
|
||||
}
|
||||
else if (descriptor.enumerable) {
|
||||
newObj[key] = clone(obj[key], options, seen);
|
||||
}
|
||||
else {
|
||||
Object.defineProperty(newObj, key, { enumerable: false, writable: true, configurable: true, value: clone(obj[key], options, seen) });
|
||||
}
|
||||
}
|
||||
else {
|
||||
Object.defineProperty(newObj, key, {
|
||||
enumerable: true,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
value: clone(obj[key], options, seen)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return newObj;
|
||||
};
|
||||
|
||||
|
||||
internals.cloneWithShallow = function (source, options) {
|
||||
|
||||
const keys = options.shallow;
|
||||
options = Object.assign({}, options);
|
||||
options.shallow = false;
|
||||
|
||||
const storage = Utils.store(source, keys); // Move shallow copy items to storage
|
||||
const copy = internals.clone(source, options); // Deep copy the rest
|
||||
Utils.restore(copy, source, storage); // Shallow copy the stored items and restore
|
||||
return copy;
|
||||
};
|
||||
|
||||
|
||||
internals.base = function (obj, baseProto, options) {
|
||||
|
||||
if (baseProto === Types.array) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (options.prototype === false) { // Defaults to true
|
||||
if (internals.needsProtoHack.has(baseProto)) {
|
||||
return new baseProto.constructor();
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
const proto = Object.getPrototypeOf(obj);
|
||||
if (proto &&
|
||||
proto.isImmutable) {
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
if (internals.needsProtoHack.has(baseProto)) {
|
||||
const newObj = new proto.constructor();
|
||||
if (proto !== baseProto) {
|
||||
Object.setPrototypeOf(newObj, proto);
|
||||
}
|
||||
|
||||
return newObj;
|
||||
}
|
||||
|
||||
return Object.create(proto);
|
||||
};
|
305
web/node_modules/@hapi/hoek/lib/contain.js
generated
vendored
Executable file
305
web/node_modules/@hapi/hoek/lib/contain.js
generated
vendored
Executable file
|
@ -0,0 +1,305 @@
|
|||
'use strict';
|
||||
|
||||
const Assert = require('./assert');
|
||||
const DeepEqual = require('./deepEqual');
|
||||
const EscapeRegex = require('./escapeRegex');
|
||||
const Utils = require('./utils');
|
||||
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
module.exports = function (ref, values, options = {}) { // options: { deep, once, only, part, symbols }
|
||||
|
||||
/*
|
||||
string -> string(s)
|
||||
array -> item(s)
|
||||
object -> key(s)
|
||||
object -> object (key:value)
|
||||
*/
|
||||
|
||||
if (typeof values !== 'object') {
|
||||
values = [values];
|
||||
}
|
||||
|
||||
Assert(!Array.isArray(values) || values.length, 'Values array cannot be empty');
|
||||
|
||||
// String
|
||||
|
||||
if (typeof ref === 'string') {
|
||||
return internals.string(ref, values, options);
|
||||
}
|
||||
|
||||
// Array
|
||||
|
||||
if (Array.isArray(ref)) {
|
||||
return internals.array(ref, values, options);
|
||||
}
|
||||
|
||||
// Object
|
||||
|
||||
Assert(typeof ref === 'object', 'Reference must be string or an object');
|
||||
return internals.object(ref, values, options);
|
||||
};
|
||||
|
||||
|
||||
internals.array = function (ref, values, options) {
|
||||
|
||||
if (!Array.isArray(values)) {
|
||||
values = [values];
|
||||
}
|
||||
|
||||
if (!ref.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (options.only &&
|
||||
options.once &&
|
||||
ref.length !== values.length) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
let compare;
|
||||
|
||||
// Map values
|
||||
|
||||
const map = new Map();
|
||||
for (const value of values) {
|
||||
if (!options.deep ||
|
||||
!value ||
|
||||
typeof value !== 'object') {
|
||||
|
||||
const existing = map.get(value);
|
||||
if (existing) {
|
||||
++existing.allowed;
|
||||
}
|
||||
else {
|
||||
map.set(value, { allowed: 1, hits: 0 });
|
||||
}
|
||||
}
|
||||
else {
|
||||
compare = compare || internals.compare(options);
|
||||
|
||||
let found = false;
|
||||
for (const [key, existing] of map.entries()) {
|
||||
if (compare(key, value)) {
|
||||
++existing.allowed;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
map.set(value, { allowed: 1, hits: 0 });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Lookup values
|
||||
|
||||
let hits = 0;
|
||||
for (const item of ref) {
|
||||
let match;
|
||||
if (!options.deep ||
|
||||
!item ||
|
||||
typeof item !== 'object') {
|
||||
|
||||
match = map.get(item);
|
||||
}
|
||||
else {
|
||||
for (const [key, existing] of map.entries()) {
|
||||
if (compare(key, item)) {
|
||||
match = existing;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (match) {
|
||||
++match.hits;
|
||||
++hits;
|
||||
|
||||
if (options.once &&
|
||||
match.hits > match.allowed) {
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Validate results
|
||||
|
||||
if (options.only &&
|
||||
hits !== ref.length) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const match of map.values()) {
|
||||
if (match.hits === match.allowed) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (match.hits < match.allowed &&
|
||||
!options.part) {
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return !!hits;
|
||||
};
|
||||
|
||||
|
||||
internals.object = function (ref, values, options) {
|
||||
|
||||
Assert(options.once === undefined, 'Cannot use option once with object');
|
||||
|
||||
const keys = Utils.keys(ref, options);
|
||||
if (!keys.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Keys list
|
||||
|
||||
if (Array.isArray(values)) {
|
||||
return internals.array(keys, values, options);
|
||||
}
|
||||
|
||||
// Key value pairs
|
||||
|
||||
const symbols = Object.getOwnPropertySymbols(values).filter((sym) => values.propertyIsEnumerable(sym));
|
||||
const targets = [...Object.keys(values), ...symbols];
|
||||
|
||||
const compare = internals.compare(options);
|
||||
const set = new Set(targets);
|
||||
|
||||
for (const key of keys) {
|
||||
if (!set.has(key)) {
|
||||
if (options.only) {
|
||||
return false;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!compare(values[key], ref[key])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
set.delete(key);
|
||||
}
|
||||
|
||||
if (set.size) {
|
||||
return options.part ? set.size < targets.length : false;
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
internals.string = function (ref, values, options) {
|
||||
|
||||
// Empty string
|
||||
|
||||
if (ref === '') {
|
||||
return values.length === 1 && values[0] === '' || // '' contains ''
|
||||
!options.once && !values.some((v) => v !== ''); // '' contains multiple '' if !once
|
||||
}
|
||||
|
||||
// Map values
|
||||
|
||||
const map = new Map();
|
||||
const patterns = [];
|
||||
|
||||
for (const value of values) {
|
||||
Assert(typeof value === 'string', 'Cannot compare string reference to non-string value');
|
||||
|
||||
if (value) {
|
||||
const existing = map.get(value);
|
||||
if (existing) {
|
||||
++existing.allowed;
|
||||
}
|
||||
else {
|
||||
map.set(value, { allowed: 1, hits: 0 });
|
||||
patterns.push(EscapeRegex(value));
|
||||
}
|
||||
}
|
||||
else if (options.once ||
|
||||
options.only) {
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!patterns.length) { // Non-empty string contains unlimited empty string
|
||||
return true;
|
||||
}
|
||||
|
||||
// Match patterns
|
||||
|
||||
const regex = new RegExp(`(${patterns.join('|')})`, 'g');
|
||||
const leftovers = ref.replace(regex, ($0, $1) => {
|
||||
|
||||
++map.get($1).hits;
|
||||
return ''; // Remove from string
|
||||
});
|
||||
|
||||
// Validate results
|
||||
|
||||
if (options.only &&
|
||||
leftovers) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
let any = false;
|
||||
for (const match of map.values()) {
|
||||
if (match.hits) {
|
||||
any = true;
|
||||
}
|
||||
|
||||
if (match.hits === match.allowed) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (match.hits < match.allowed &&
|
||||
!options.part) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// match.hits > match.allowed
|
||||
|
||||
if (options.once) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return !!any;
|
||||
};
|
||||
|
||||
|
||||
internals.compare = function (options) {
|
||||
|
||||
if (!options.deep) {
|
||||
return internals.shallow;
|
||||
}
|
||||
|
||||
const hasOnly = options.only !== undefined;
|
||||
const hasPart = options.part !== undefined;
|
||||
|
||||
const flags = {
|
||||
prototype: hasOnly ? options.only : hasPart ? !options.part : false,
|
||||
part: hasOnly ? !options.only : hasPart ? options.part : false
|
||||
};
|
||||
|
||||
return (a, b) => DeepEqual(a, b, flags);
|
||||
};
|
||||
|
||||
|
||||
internals.shallow = function (a, b) {
|
||||
|
||||
return a === b;
|
||||
};
|
317
web/node_modules/@hapi/hoek/lib/deepEqual.js
generated
vendored
Executable file
317
web/node_modules/@hapi/hoek/lib/deepEqual.js
generated
vendored
Executable file
|
@ -0,0 +1,317 @@
|
|||
'use strict';
|
||||
|
||||
const Types = require('./types');
|
||||
|
||||
|
||||
const internals = {
|
||||
mismatched: null
|
||||
};
|
||||
|
||||
|
||||
module.exports = function (obj, ref, options) {
|
||||
|
||||
options = Object.assign({ prototype: true }, options);
|
||||
|
||||
return !!internals.isDeepEqual(obj, ref, options, []);
|
||||
};
|
||||
|
||||
|
||||
internals.isDeepEqual = function (obj, ref, options, seen) {
|
||||
|
||||
if (obj === ref) { // Copied from Deep-eql, copyright(c) 2013 Jake Luer, jake@alogicalparadox.com, MIT Licensed, https://github.com/chaijs/deep-eql
|
||||
return obj !== 0 || 1 / obj === 1 / ref;
|
||||
}
|
||||
|
||||
const type = typeof obj;
|
||||
|
||||
if (type !== typeof ref) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (obj === null ||
|
||||
ref === null) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (type === 'function') {
|
||||
if (!options.deepFunction ||
|
||||
obj.toString() !== ref.toString()) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Continue as object
|
||||
}
|
||||
else if (type !== 'object') {
|
||||
return obj !== obj && ref !== ref; // NaN
|
||||
}
|
||||
|
||||
const instanceType = internals.getSharedType(obj, ref, !!options.prototype);
|
||||
switch (instanceType) {
|
||||
case Types.buffer:
|
||||
return Buffer && Buffer.prototype.equals.call(obj, ref); // $lab:coverage:ignore$
|
||||
case Types.promise:
|
||||
return obj === ref;
|
||||
case Types.regex:
|
||||
return obj.toString() === ref.toString();
|
||||
case internals.mismatched:
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let i = seen.length - 1; i >= 0; --i) {
|
||||
if (seen[i].isSame(obj, ref)) {
|
||||
return true; // If previous comparison failed, it would have stopped execution
|
||||
}
|
||||
}
|
||||
|
||||
seen.push(new internals.SeenEntry(obj, ref));
|
||||
|
||||
try {
|
||||
return !!internals.isDeepEqualObj(instanceType, obj, ref, options, seen);
|
||||
}
|
||||
finally {
|
||||
seen.pop();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
internals.getSharedType = function (obj, ref, checkPrototype) {
|
||||
|
||||
if (checkPrototype) {
|
||||
if (Object.getPrototypeOf(obj) !== Object.getPrototypeOf(ref)) {
|
||||
return internals.mismatched;
|
||||
}
|
||||
|
||||
return Types.getInternalProto(obj);
|
||||
}
|
||||
|
||||
const type = Types.getInternalProto(obj);
|
||||
if (type !== Types.getInternalProto(ref)) {
|
||||
return internals.mismatched;
|
||||
}
|
||||
|
||||
return type;
|
||||
};
|
||||
|
||||
|
||||
internals.valueOf = function (obj) {
|
||||
|
||||
const objValueOf = obj.valueOf;
|
||||
if (objValueOf === undefined) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
try {
|
||||
return objValueOf.call(obj);
|
||||
}
|
||||
catch (err) {
|
||||
return err;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
internals.hasOwnEnumerableProperty = function (obj, key) {
|
||||
|
||||
return Object.prototype.propertyIsEnumerable.call(obj, key);
|
||||
};
|
||||
|
||||
|
||||
internals.isSetSimpleEqual = function (obj, ref) {
|
||||
|
||||
for (const entry of obj) {
|
||||
if (!ref.has(entry)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
internals.isDeepEqualObj = function (instanceType, obj, ref, options, seen) {
|
||||
|
||||
const { isDeepEqual, valueOf, hasOwnEnumerableProperty } = internals;
|
||||
const { keys, getOwnPropertySymbols } = Object;
|
||||
|
||||
if (instanceType === Types.array) {
|
||||
if (options.part) {
|
||||
|
||||
// Check if any index match any other index
|
||||
|
||||
for (const objValue of obj) {
|
||||
for (const refValue of ref) {
|
||||
if (isDeepEqual(objValue, refValue, options, seen)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (obj.length !== ref.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let i = 0; i < obj.length; ++i) {
|
||||
if (!isDeepEqual(obj[i], ref[i], options, seen)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (instanceType === Types.set) {
|
||||
if (obj.size !== ref.size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!internals.isSetSimpleEqual(obj, ref)) {
|
||||
|
||||
// Check for deep equality
|
||||
|
||||
const ref2 = new Set(ref);
|
||||
for (const objEntry of obj) {
|
||||
if (ref2.delete(objEntry)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let found = false;
|
||||
for (const refEntry of ref2) {
|
||||
if (isDeepEqual(objEntry, refEntry, options, seen)) {
|
||||
ref2.delete(refEntry);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (instanceType === Types.map) {
|
||||
if (obj.size !== ref.size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const [key, value] of obj) {
|
||||
if (value === undefined && !ref.has(key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isDeepEqual(value, ref.get(key), options, seen)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (instanceType === Types.error) {
|
||||
|
||||
// Always check name and message
|
||||
|
||||
if (obj.name !== ref.name ||
|
||||
obj.message !== ref.message) {
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check .valueOf()
|
||||
|
||||
const valueOfObj = valueOf(obj);
|
||||
const valueOfRef = valueOf(ref);
|
||||
if ((obj !== valueOfObj || ref !== valueOfRef) &&
|
||||
!isDeepEqual(valueOfObj, valueOfRef, options, seen)) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check properties
|
||||
|
||||
const objKeys = keys(obj);
|
||||
if (!options.part &&
|
||||
objKeys.length !== keys(ref).length &&
|
||||
!options.skip) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
let skipped = 0;
|
||||
for (const key of objKeys) {
|
||||
if (options.skip &&
|
||||
options.skip.includes(key)) {
|
||||
|
||||
if (ref[key] === undefined) {
|
||||
++skipped;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!hasOwnEnumerableProperty(ref, key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isDeepEqual(obj[key], ref[key], options, seen)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!options.part &&
|
||||
objKeys.length - skipped !== keys(ref).length) {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check symbols
|
||||
|
||||
if (options.symbols !== false) { // Defaults to true
|
||||
const objSymbols = getOwnPropertySymbols(obj);
|
||||
const refSymbols = new Set(getOwnPropertySymbols(ref));
|
||||
|
||||
for (const key of objSymbols) {
|
||||
if (!options.skip ||
|
||||
!options.skip.includes(key)) {
|
||||
|
||||
if (hasOwnEnumerableProperty(obj, key)) {
|
||||
if (!hasOwnEnumerableProperty(ref, key)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!isDeepEqual(obj[key], ref[key], options, seen)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (hasOwnEnumerableProperty(ref, key)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
refSymbols.delete(key);
|
||||
}
|
||||
|
||||
for (const key of refSymbols) {
|
||||
if (hasOwnEnumerableProperty(ref, key)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
internals.SeenEntry = class {
|
||||
|
||||
constructor(obj, ref) {
|
||||
|
||||
this.obj = obj;
|
||||
this.ref = ref;
|
||||
}
|
||||
|
||||
isSame(obj, ref) {
|
||||
|
||||
return this.obj === obj && this.ref === ref;
|
||||
}
|
||||
};
|
26
web/node_modules/@hapi/hoek/lib/error.js
generated
vendored
Executable file
26
web/node_modules/@hapi/hoek/lib/error.js
generated
vendored
Executable file
|
@ -0,0 +1,26 @@
|
|||
'use strict';
|
||||
|
||||
const Stringify = require('./stringify');
|
||||
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
module.exports = class extends Error {
|
||||
|
||||
constructor(args) {
|
||||
|
||||
const msgs = args
|
||||
.filter((arg) => arg !== '')
|
||||
.map((arg) => {
|
||||
|
||||
return typeof arg === 'string' ? arg : arg instanceof Error ? arg.message : Stringify(arg);
|
||||
});
|
||||
|
||||
super(msgs.join(' ') || 'Unknown error');
|
||||
|
||||
if (typeof Error.captureStackTrace === 'function') { // $lab:coverage:ignore$
|
||||
Error.captureStackTrace(this, exports.assert);
|
||||
}
|
||||
}
|
||||
};
|
16
web/node_modules/@hapi/hoek/lib/escapeHeaderAttribute.js
generated
vendored
Executable file
16
web/node_modules/@hapi/hoek/lib/escapeHeaderAttribute.js
generated
vendored
Executable file
|
@ -0,0 +1,16 @@
|
|||
'use strict';
|
||||
|
||||
const Assert = require('./assert');
|
||||
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
module.exports = function (attribute) {
|
||||
|
||||
// Allowed value characters: !#$%&'()*+,-./:;<=>?@[]^_`{|}~ and space, a-z, A-Z, 0-9, \, "
|
||||
|
||||
Assert(/^[ \w\!#\$%&'\(\)\*\+,\-\.\/\:;<\=>\?@\[\]\^`\{\|\}~\"\\]*$/.test(attribute), 'Bad attribute value (' + attribute + ')');
|
||||
|
||||
return attribute.replace(/\\/g, '\\\\').replace(/\"/g, '\\"'); // Escape quotes and slash
|
||||
};
|
87
web/node_modules/@hapi/hoek/lib/escapeHtml.js
generated
vendored
Executable file
87
web/node_modules/@hapi/hoek/lib/escapeHtml.js
generated
vendored
Executable file
|
@ -0,0 +1,87 @@
|
|||
'use strict';
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
module.exports = function (input) {
|
||||
|
||||
if (!input) {
|
||||
return '';
|
||||
}
|
||||
|
||||
let escaped = '';
|
||||
|
||||
for (let i = 0; i < input.length; ++i) {
|
||||
|
||||
const charCode = input.charCodeAt(i);
|
||||
|
||||
if (internals.isSafe(charCode)) {
|
||||
escaped += input[i];
|
||||
}
|
||||
else {
|
||||
escaped += internals.escapeHtmlChar(charCode);
|
||||
}
|
||||
}
|
||||
|
||||
return escaped;
|
||||
};
|
||||
|
||||
|
||||
internals.escapeHtmlChar = function (charCode) {
|
||||
|
||||
const namedEscape = internals.namedHtml[charCode];
|
||||
if (typeof namedEscape !== 'undefined') {
|
||||
return namedEscape;
|
||||
}
|
||||
|
||||
if (charCode >= 256) {
|
||||
return '&#' + charCode + ';';
|
||||
}
|
||||
|
||||
const hexValue = charCode.toString(16).padStart(2, '0');
|
||||
return `&#x${hexValue};`;
|
||||
};
|
||||
|
||||
|
||||
internals.isSafe = function (charCode) {
|
||||
|
||||
return (typeof internals.safeCharCodes[charCode] !== 'undefined');
|
||||
};
|
||||
|
||||
|
||||
internals.namedHtml = {
|
||||
'38': '&',
|
||||
'60': '<',
|
||||
'62': '>',
|
||||
'34': '"',
|
||||
'160': ' ',
|
||||
'162': '¢',
|
||||
'163': '£',
|
||||
'164': '¤',
|
||||
'169': '©',
|
||||
'174': '®'
|
||||
};
|
||||
|
||||
|
||||
internals.safeCharCodes = (function () {
|
||||
|
||||
const safe = {};
|
||||
|
||||
for (let i = 32; i < 123; ++i) {
|
||||
|
||||
if ((i >= 97) || // a-z
|
||||
(i >= 65 && i <= 90) || // A-Z
|
||||
(i >= 48 && i <= 57) || // 0-9
|
||||
i === 32 || // space
|
||||
i === 46 || // .
|
||||
i === 44 || // ,
|
||||
i === 45 || // -
|
||||
i === 58 || // :
|
||||
i === 95) { // _
|
||||
|
||||
safe[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
return safe;
|
||||
}());
|
41
web/node_modules/@hapi/hoek/lib/escapeJson.js
generated
vendored
Executable file
41
web/node_modules/@hapi/hoek/lib/escapeJson.js
generated
vendored
Executable file
|
@ -0,0 +1,41 @@
|
|||
'use strict';
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
module.exports = function (input) {
|
||||
|
||||
if (!input) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const lessThan = 0x3C;
|
||||
const greaterThan = 0x3E;
|
||||
const andSymbol = 0x26;
|
||||
const lineSeperator = 0x2028;
|
||||
|
||||
// replace method
|
||||
let charCode;
|
||||
return input.replace(/[<>&\u2028\u2029]/g, (match) => {
|
||||
|
||||
charCode = match.charCodeAt(0);
|
||||
|
||||
if (charCode === lessThan) {
|
||||
return '\\u003c';
|
||||
}
|
||||
|
||||
if (charCode === greaterThan) {
|
||||
return '\\u003e';
|
||||
}
|
||||
|
||||
if (charCode === andSymbol) {
|
||||
return '\\u0026';
|
||||
}
|
||||
|
||||
if (charCode === lineSeperator) {
|
||||
return '\\u2028';
|
||||
}
|
||||
|
||||
return '\\u2029';
|
||||
});
|
||||
};
|
11
web/node_modules/@hapi/hoek/lib/escapeRegex.js
generated
vendored
Executable file
11
web/node_modules/@hapi/hoek/lib/escapeRegex.js
generated
vendored
Executable file
|
@ -0,0 +1,11 @@
|
|||
'use strict';
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
module.exports = function (string) {
|
||||
|
||||
// Escape ^$.*+-?=!:|\/()[]{},
|
||||
|
||||
return string.replace(/[\^\$\.\*\+\-\?\=\!\:\|\\\/\(\)\[\]\{\}\,]/g, '\\$&');
|
||||
};
|
20
web/node_modules/@hapi/hoek/lib/flatten.js
generated
vendored
Executable file
20
web/node_modules/@hapi/hoek/lib/flatten.js
generated
vendored
Executable file
|
@ -0,0 +1,20 @@
|
|||
'use strict';
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
module.exports = internals.flatten = function (array, target) {
|
||||
|
||||
const result = target || [];
|
||||
|
||||
for (let i = 0; i < array.length; ++i) {
|
||||
if (Array.isArray(array[i])) {
|
||||
internals.flatten(array[i], result);
|
||||
}
|
||||
else {
|
||||
result.push(array[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
6
web/node_modules/@hapi/hoek/lib/ignore.js
generated
vendored
Executable file
6
web/node_modules/@hapi/hoek/lib/ignore.js
generated
vendored
Executable file
|
@ -0,0 +1,6 @@
|
|||
'use strict';
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
module.exports = function () { };
|
470
web/node_modules/@hapi/hoek/lib/index.d.ts
generated
vendored
Executable file
470
web/node_modules/@hapi/hoek/lib/index.d.ts
generated
vendored
Executable file
|
@ -0,0 +1,470 @@
|
|||
/// <reference types="node" />
|
||||
|
||||
|
||||
/**
|
||||
* Performs a deep comparison of the two values including support for circular dependencies, prototype, and enumerable properties.
|
||||
*
|
||||
* @param obj - The value being compared.
|
||||
* @param ref - The reference value used for comparison.
|
||||
*
|
||||
* @return true when the two values are equal, otherwise false.
|
||||
*/
|
||||
export function deepEqual(obj: any, ref: any, options?: deepEqual.Options): boolean;
|
||||
|
||||
export namespace deepEqual {
|
||||
|
||||
interface Options {
|
||||
|
||||
/**
|
||||
* Compare functions with difference references by comparing their internal code and properties.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
readonly deepFunction?: boolean;
|
||||
|
||||
/**
|
||||
* Allow partial match.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
readonly part?: boolean;
|
||||
|
||||
/**
|
||||
* Compare the objects' prototypes.
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
readonly prototype?: boolean;
|
||||
|
||||
/**
|
||||
* List of object keys to ignore different values of.
|
||||
*
|
||||
* @default null
|
||||
*/
|
||||
readonly skip?: (string | symbol)[];
|
||||
|
||||
/**
|
||||
* Compare symbol properties.
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
readonly symbols?: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Clone any value, object, or array.
|
||||
*
|
||||
* @param obj - The value being cloned.
|
||||
* @param options - Optional settings.
|
||||
*
|
||||
* @returns A deep clone of `obj`.
|
||||
*/
|
||||
export function clone<T>(obj: T, options?: clone.Options): T;
|
||||
|
||||
export namespace clone {
|
||||
|
||||
interface Options {
|
||||
|
||||
/**
|
||||
* Clone the object's prototype.
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
readonly prototype?: boolean;
|
||||
|
||||
/**
|
||||
* Include symbol properties.
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
readonly symbols?: boolean;
|
||||
|
||||
/**
|
||||
* Shallow clone the specified keys.
|
||||
*
|
||||
* @default undefined
|
||||
*/
|
||||
readonly shallow?: string[] | string[][] | boolean;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Merge all the properties of source into target.
|
||||
*
|
||||
* @param target - The object being modified.
|
||||
* @param source - The object used to copy properties from.
|
||||
* @param options - Optional settings.
|
||||
*
|
||||
* @returns The `target` object.
|
||||
*/
|
||||
export function merge<T1 extends object, T2 extends object>(target: T1, source: T2, options?: merge.Options): T1 & T2;
|
||||
|
||||
export namespace merge {
|
||||
|
||||
interface Options {
|
||||
|
||||
/**
|
||||
* When true, null value from `source` overrides existing value in `target`.
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
readonly nullOverride?: boolean;
|
||||
|
||||
/**
|
||||
* When true, array value from `source` is merged with the existing value in `target`.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
readonly mergeArrays?: boolean;
|
||||
|
||||
/**
|
||||
* Compare symbol properties.
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
readonly symbols?: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Apply source to a copy of the defaults.
|
||||
*
|
||||
* @param defaults - An object with the default values to use of `options` does not contain the same keys.
|
||||
* @param source - The source used to override the `defaults`.
|
||||
* @param options - Optional settings.
|
||||
*
|
||||
* @returns A copy of `defaults` with `source` keys overriding any conflicts.
|
||||
*/
|
||||
export function applyToDefaults<T extends object>(defaults: Partial<T>, source: Partial<T> | boolean | null, options?: applyToDefaults.Options): Partial<T>;
|
||||
|
||||
export namespace applyToDefaults {
|
||||
|
||||
interface Options {
|
||||
|
||||
/**
|
||||
* When true, null value from `source` overrides existing value in `target`.
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
readonly nullOverride?: boolean;
|
||||
|
||||
/**
|
||||
* Shallow clone the specified keys.
|
||||
*
|
||||
* @default undefined
|
||||
*/
|
||||
readonly shallow?: string[] | string[][];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find the common unique items in two arrays.
|
||||
*
|
||||
* @param array1 - The first array to compare.
|
||||
* @param array2 - The second array to compare.
|
||||
* @param options - Optional settings.
|
||||
*
|
||||
* @return - An array of the common items. If `justFirst` is true, returns the first common item.
|
||||
*/
|
||||
export function intersect<T1, T2>(array1: intersect.Array<T1>, array2: intersect.Array<T2>, options?: intersect.Options): Array<T1 | T2>;
|
||||
export function intersect<T1, T2>(array1: intersect.Array<T1>, array2: intersect.Array<T2>, options?: intersect.Options): T1 | T2;
|
||||
|
||||
export namespace intersect {
|
||||
|
||||
type Array<T> = ArrayLike<T> | Set<T> | null;
|
||||
|
||||
interface Options {
|
||||
|
||||
/**
|
||||
* When true, return the first overlapping value.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
readonly first?: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks if the reference value contains the provided values.
|
||||
*
|
||||
* @param ref - The reference string, array, or object.
|
||||
* @param values - A single or array of values to find within `ref`. If `ref` is an object, `values` can be a key name, an array of key names, or an object with key-value pairs to compare.
|
||||
*
|
||||
* @return true if the value contains the provided values, otherwise false.
|
||||
*/
|
||||
export function contain(ref: string, values: string | string[], options?: contain.Options): boolean;
|
||||
export function contain(ref: any[], values: any, options?: contain.Options): boolean;
|
||||
export function contain(ref: object, values: string | string[] | object, options?: Omit<contain.Options, 'once'>): boolean;
|
||||
|
||||
export namespace contain {
|
||||
|
||||
interface Options {
|
||||
|
||||
/**
|
||||
* Perform a deep comparison.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
readonly deep?: boolean;
|
||||
|
||||
/**
|
||||
* Allow only one occurrence of each value.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
readonly once?: boolean;
|
||||
|
||||
/**
|
||||
* Allow only values explicitly listed.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
readonly only?: boolean;
|
||||
|
||||
/**
|
||||
* Allow partial match.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
readonly part?: boolean;
|
||||
|
||||
/**
|
||||
* Include symbol properties.
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
readonly symbols?: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Flatten an array with sub arrays
|
||||
*
|
||||
* @param array - an array of items or other arrays to flatten.
|
||||
* @param target - if provided, an array to shallow copy the flattened `array` items to
|
||||
*
|
||||
* @return a flat array of the provided values (appended to `target` is provided).
|
||||
*/
|
||||
export function flatten<T>(array: ArrayLike<T | ReadonlyArray<T>>, target?: ArrayLike<T | ReadonlyArray<T>>): T[];
|
||||
|
||||
|
||||
/**
|
||||
* Convert an object key chain string to reference.
|
||||
*
|
||||
* @param obj - the object from which to look up the value.
|
||||
* @param chain - the string path of the requested value. The chain string is split into key names using `options.separator`, or an array containing each individual key name. A chain including negative numbers will work like a negative index on an array.
|
||||
*
|
||||
* @return The value referenced by the chain if found, otherwise undefined. If chain is null, undefined, or false, the object itself will be returned.
|
||||
*/
|
||||
export function reach(obj: object | null, chain: string | (string | number)[] | false | null | undefined, options?: reach.Options): any;
|
||||
|
||||
export namespace reach {
|
||||
|
||||
interface Options {
|
||||
|
||||
/**
|
||||
* String to split chain path on. Defaults to '.'.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
readonly separator?: string;
|
||||
|
||||
/**
|
||||
* Value to return if the path or value is not present. No default value.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
readonly default?: any;
|
||||
|
||||
/**
|
||||
* If true, will throw an error on missing member in the chain. Default to false.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
readonly strict?: boolean;
|
||||
|
||||
/**
|
||||
* If true, allows traversing functions for properties. false will throw an error if a function is part of the chain.
|
||||
*
|
||||
* @default true
|
||||
*/
|
||||
readonly functions?: boolean;
|
||||
|
||||
/**
|
||||
* If true, allows traversing Set and Map objects for properties. false will return undefined regardless of the Set or Map passed.
|
||||
*
|
||||
* @default false
|
||||
*/
|
||||
readonly iterables?: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Replace string parameters (using format "{path.to.key}") with their corresponding object key values using `Hoek.reach()`.
|
||||
*
|
||||
* @param obj - the object from which to look up the value.
|
||||
* @param template - the string containing {} enclosed key paths to be replaced.
|
||||
*
|
||||
* @return The template string with the {} enclosed keys replaced with looked-up values.
|
||||
*/
|
||||
export function reachTemplate(obj: object | null, template: string, options?: reach.Options): string;
|
||||
|
||||
|
||||
/**
|
||||
* Throw an error if condition is falsy.
|
||||
*
|
||||
* @param condition - If `condition` is not truthy, an exception is thrown.
|
||||
* @param error - The error thrown if the condition fails.
|
||||
*
|
||||
* @return Does not return a value but throws if the `condition` is falsy.
|
||||
*/
|
||||
export function assert(condition: any, error: Error): void;
|
||||
|
||||
|
||||
/**
|
||||
* Throw an error if condition is falsy.
|
||||
*
|
||||
* @param condition - If `condition` is not truthy, an exception is thrown.
|
||||
* @param args - Any number of values, concatenated together (space separated) to create the error message.
|
||||
*
|
||||
* @return Does not return a value but throws if the `condition` is falsy.
|
||||
*/
|
||||
export function assert(condition: any, ...args: any): void;
|
||||
|
||||
|
||||
/**
|
||||
* A benchmarking timer, using the internal node clock for maximum accuracy.
|
||||
*/
|
||||
export class Bench {
|
||||
|
||||
constructor();
|
||||
|
||||
/** The starting timestamp expressed in the number of milliseconds since the epoch. */
|
||||
ts: number;
|
||||
|
||||
/** The time in milliseconds since the object was created. */
|
||||
elapsed(): number;
|
||||
|
||||
/** Reset the `ts` value to now. */
|
||||
reset(): void;
|
||||
|
||||
/** The current time in milliseconds since the epoch. */
|
||||
static now(): number;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Escape string for Regex construction by prefixing all reserved characters with a backslash.
|
||||
*
|
||||
* @param string - The string to be escaped.
|
||||
*
|
||||
* @return The escaped string.
|
||||
*/
|
||||
export function escapeRegex(string: string): string;
|
||||
|
||||
|
||||
/**
|
||||
* Escape string for usage as an attribute value in HTTP headers.
|
||||
*
|
||||
* @param attribute - The string to be escaped.
|
||||
*
|
||||
* @return The escaped string. Will throw on invalid characters that are not supported to be escaped.
|
||||
*/
|
||||
export function escapeHeaderAttribute(attribute: string): string;
|
||||
|
||||
|
||||
/**
|
||||
* Escape string for usage in HTML.
|
||||
*
|
||||
* @param string - The string to be escaped.
|
||||
*
|
||||
* @return The escaped string.
|
||||
*/
|
||||
export function escapeHtml(string: string): string;
|
||||
|
||||
|
||||
/**
|
||||
* Escape string for usage in JSON.
|
||||
*
|
||||
* @param string - The string to be escaped.
|
||||
*
|
||||
* @return The escaped string.
|
||||
*/
|
||||
export function escapeJson(string: string): string;
|
||||
|
||||
|
||||
/**
|
||||
* Wraps a function to ensure it can only execute once.
|
||||
*
|
||||
* @param method - The function to be wrapped.
|
||||
*
|
||||
* @return The wrapped function.
|
||||
*/
|
||||
export function once<T extends Function>(method: T): T;
|
||||
|
||||
|
||||
/**
|
||||
* A reusable no-op function.
|
||||
*/
|
||||
export function ignore(...ignore: any): void;
|
||||
|
||||
|
||||
/**
|
||||
* Converts a JavaScript value to a JavaScript Object Notation (JSON) string with protection against thrown errors.
|
||||
*
|
||||
* @param value A JavaScript value, usually an object or array, to be converted.
|
||||
* @param replacer The JSON.stringify() `replacer` argument.
|
||||
* @param space Adds indentation, white space, and line break characters to the return-value JSON text to make it easier to read.
|
||||
*
|
||||
* @return The JSON string. If the operation fails, an error string value is returned (no exception thrown).
|
||||
*/
|
||||
export function stringify(value: any, replacer?: any, space?: string | number): string;
|
||||
|
||||
|
||||
/**
|
||||
* Returns a Promise that resolves after the requested timeout.
|
||||
*
|
||||
* @param timeout - The number of milliseconds to wait before resolving the Promise.
|
||||
*
|
||||
* @return A Promise.
|
||||
*/
|
||||
export function wait(timeout?: number): Promise<void>;
|
||||
|
||||
|
||||
/**
|
||||
* Returns a Promise that never resolves.
|
||||
*/
|
||||
export function block(): Promise<void>;
|
||||
|
||||
|
||||
/**
|
||||
* Determines if an object is a promise.
|
||||
*
|
||||
* @param promise - the object tested.
|
||||
*
|
||||
* @returns true if the object is a promise, otherwise false.
|
||||
*/
|
||||
export function isPromise(promise: any): boolean;
|
||||
|
||||
|
||||
export namespace ts {
|
||||
|
||||
/**
|
||||
* Defines a type that can must be one of T or U but not both.
|
||||
*/
|
||||
type XOR<T, U> = (T | U) extends object ? (internals.Without<T, U> & U) | (internals.Without<U, T> & T) : T | U;
|
||||
}
|
||||
|
||||
|
||||
declare namespace internals {
|
||||
|
||||
type Without<T, U> = { [P in Exclude<keyof T, keyof U>]?: never };
|
||||
}
|
29
web/node_modules/@hapi/hoek/lib/index.js
generated
vendored
Executable file
29
web/node_modules/@hapi/hoek/lib/index.js
generated
vendored
Executable file
|
@ -0,0 +1,29 @@
|
|||
'use strict';
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
module.exports = {
|
||||
applyToDefaults: require('./applyToDefaults'),
|
||||
assert: require('./assert'),
|
||||
Bench: require('./bench'),
|
||||
block: require('./block'),
|
||||
clone: require('./clone'),
|
||||
contain: require('./contain'),
|
||||
deepEqual: require('./deepEqual'),
|
||||
Error: require('./error'),
|
||||
escapeHeaderAttribute: require('./escapeHeaderAttribute'),
|
||||
escapeHtml: require('./escapeHtml'),
|
||||
escapeJson: require('./escapeJson'),
|
||||
escapeRegex: require('./escapeRegex'),
|
||||
flatten: require('./flatten'),
|
||||
ignore: require('./ignore'),
|
||||
intersect: require('./intersect'),
|
||||
isPromise: require('./isPromise'),
|
||||
merge: require('./merge'),
|
||||
once: require('./once'),
|
||||
reach: require('./reach'),
|
||||
reachTemplate: require('./reachTemplate'),
|
||||
stringify: require('./stringify'),
|
||||
wait: require('./wait')
|
||||
};
|
41
web/node_modules/@hapi/hoek/lib/intersect.js
generated
vendored
Executable file
41
web/node_modules/@hapi/hoek/lib/intersect.js
generated
vendored
Executable file
|
@ -0,0 +1,41 @@
|
|||
'use strict';
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
module.exports = function (array1, array2, options = {}) {
|
||||
|
||||
if (!array1 ||
|
||||
!array2) {
|
||||
|
||||
return (options.first ? null : []);
|
||||
}
|
||||
|
||||
const common = [];
|
||||
const hash = (Array.isArray(array1) ? new Set(array1) : array1);
|
||||
const found = new Set();
|
||||
for (const value of array2) {
|
||||
if (internals.has(hash, value) &&
|
||||
!found.has(value)) {
|
||||
|
||||
if (options.first) {
|
||||
return value;
|
||||
}
|
||||
|
||||
common.push(value);
|
||||
found.add(value);
|
||||
}
|
||||
}
|
||||
|
||||
return (options.first ? null : common);
|
||||
};
|
||||
|
||||
|
||||
internals.has = function (ref, key) {
|
||||
|
||||
if (typeof ref.has === 'function') {
|
||||
return ref.has(key);
|
||||
}
|
||||
|
||||
return ref[key] !== undefined;
|
||||
};
|
9
web/node_modules/@hapi/hoek/lib/isPromise.js
generated
vendored
Executable file
9
web/node_modules/@hapi/hoek/lib/isPromise.js
generated
vendored
Executable file
|
@ -0,0 +1,9 @@
|
|||
'use strict';
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
module.exports = function (promise) {
|
||||
|
||||
return !!promise && typeof promise.then === 'function';
|
||||
};
|
74
web/node_modules/@hapi/hoek/lib/merge.js
generated
vendored
Executable file
74
web/node_modules/@hapi/hoek/lib/merge.js
generated
vendored
Executable file
|
@ -0,0 +1,74 @@
|
|||
'use strict';
|
||||
|
||||
const Assert = require('./assert');
|
||||
const Clone = require('./clone');
|
||||
const Utils = require('./utils');
|
||||
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
module.exports = internals.merge = function (target, source, options) {
|
||||
|
||||
Assert(target && typeof target === 'object', 'Invalid target value: must be an object');
|
||||
Assert(source === null || source === undefined || typeof source === 'object', 'Invalid source value: must be null, undefined, or an object');
|
||||
|
||||
if (!source) {
|
||||
return target;
|
||||
}
|
||||
|
||||
options = Object.assign({ nullOverride: true, mergeArrays: true }, options);
|
||||
|
||||
if (Array.isArray(source)) {
|
||||
Assert(Array.isArray(target), 'Cannot merge array onto an object');
|
||||
if (!options.mergeArrays) {
|
||||
target.length = 0; // Must not change target assignment
|
||||
}
|
||||
|
||||
for (let i = 0; i < source.length; ++i) {
|
||||
target.push(Clone(source[i], { symbols: options.symbols }));
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
const keys = Utils.keys(source, options);
|
||||
for (let i = 0; i < keys.length; ++i) {
|
||||
const key = keys[i];
|
||||
if (key === '__proto__' ||
|
||||
!Object.prototype.propertyIsEnumerable.call(source, key)) {
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
const value = source[key];
|
||||
if (value &&
|
||||
typeof value === 'object') {
|
||||
|
||||
if (!target[key] ||
|
||||
typeof target[key] !== 'object' ||
|
||||
(Array.isArray(target[key]) !== Array.isArray(value)) ||
|
||||
value instanceof Date ||
|
||||
(Buffer && Buffer.isBuffer(value)) || // $lab:coverage:ignore$
|
||||
value instanceof RegExp) {
|
||||
|
||||
target[key] = Clone(value, { symbols: options.symbols });
|
||||
}
|
||||
else {
|
||||
internals.merge(target[key], value, options);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (value !== null &&
|
||||
value !== undefined) { // Explicit to preserve empty strings
|
||||
|
||||
target[key] = value;
|
||||
}
|
||||
else if (options.nullOverride) {
|
||||
target[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return target;
|
||||
};
|
23
web/node_modules/@hapi/hoek/lib/once.js
generated
vendored
Executable file
23
web/node_modules/@hapi/hoek/lib/once.js
generated
vendored
Executable file
|
@ -0,0 +1,23 @@
|
|||
'use strict';
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
module.exports = function (method) {
|
||||
|
||||
if (method._hoekOnce) {
|
||||
return method;
|
||||
}
|
||||
|
||||
let once = false;
|
||||
const wrapped = function (...args) {
|
||||
|
||||
if (!once) {
|
||||
once = true;
|
||||
method(...args);
|
||||
}
|
||||
};
|
||||
|
||||
wrapped._hoekOnce = true;
|
||||
return wrapped;
|
||||
};
|
76
web/node_modules/@hapi/hoek/lib/reach.js
generated
vendored
Executable file
76
web/node_modules/@hapi/hoek/lib/reach.js
generated
vendored
Executable file
|
@ -0,0 +1,76 @@
|
|||
'use strict';
|
||||
|
||||
const Assert = require('./assert');
|
||||
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
module.exports = function (obj, chain, options) {
|
||||
|
||||
if (chain === false ||
|
||||
chain === null ||
|
||||
chain === undefined) {
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
options = options || {};
|
||||
if (typeof options === 'string') {
|
||||
options = { separator: options };
|
||||
}
|
||||
|
||||
const isChainArray = Array.isArray(chain);
|
||||
|
||||
Assert(!isChainArray || !options.separator, 'Separator option no valid for array-based chain');
|
||||
|
||||
const path = isChainArray ? chain : chain.split(options.separator || '.');
|
||||
let ref = obj;
|
||||
for (let i = 0; i < path.length; ++i) {
|
||||
let key = path[i];
|
||||
const type = options.iterables && internals.iterables(ref);
|
||||
|
||||
if (Array.isArray(ref) ||
|
||||
type === 'set') {
|
||||
|
||||
const number = Number(key);
|
||||
if (Number.isInteger(number)) {
|
||||
key = number < 0 ? ref.length + number : number;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ref ||
|
||||
typeof ref === 'function' && options.functions === false || // Defaults to true
|
||||
!type && ref[key] === undefined) {
|
||||
|
||||
Assert(!options.strict || i + 1 === path.length, 'Missing segment', key, 'in reach path ', chain);
|
||||
Assert(typeof ref === 'object' || options.functions === true || typeof ref !== 'function', 'Invalid segment', key, 'in reach path ', chain);
|
||||
ref = options.default;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!type) {
|
||||
ref = ref[key];
|
||||
}
|
||||
else if (type === 'set') {
|
||||
ref = [...ref][key];
|
||||
}
|
||||
else { // type === 'map'
|
||||
ref = ref.get(key);
|
||||
}
|
||||
}
|
||||
|
||||
return ref;
|
||||
};
|
||||
|
||||
|
||||
internals.iterables = function (ref) {
|
||||
|
||||
if (ref instanceof Set) {
|
||||
return 'set';
|
||||
}
|
||||
|
||||
if (ref instanceof Map) {
|
||||
return 'map';
|
||||
}
|
||||
};
|
16
web/node_modules/@hapi/hoek/lib/reachTemplate.js
generated
vendored
Executable file
16
web/node_modules/@hapi/hoek/lib/reachTemplate.js
generated
vendored
Executable file
|
@ -0,0 +1,16 @@
|
|||
'use strict';
|
||||
|
||||
const Reach = require('./reach');
|
||||
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
module.exports = function (obj, template, options) {
|
||||
|
||||
return template.replace(/{([^}]+)}/g, ($0, chain) => {
|
||||
|
||||
const value = Reach(obj, chain, options);
|
||||
return (value === undefined || value === null ? '' : value);
|
||||
});
|
||||
};
|
14
web/node_modules/@hapi/hoek/lib/stringify.js
generated
vendored
Executable file
14
web/node_modules/@hapi/hoek/lib/stringify.js
generated
vendored
Executable file
|
@ -0,0 +1,14 @@
|
|||
'use strict';
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
module.exports = function (...args) {
|
||||
|
||||
try {
|
||||
return JSON.stringify.apply(null, args);
|
||||
}
|
||||
catch (err) {
|
||||
return '[Cannot display object: ' + err.message + ']';
|
||||
}
|
||||
};
|
55
web/node_modules/@hapi/hoek/lib/types.js
generated
vendored
Executable file
55
web/node_modules/@hapi/hoek/lib/types.js
generated
vendored
Executable file
|
@ -0,0 +1,55 @@
|
|||
'use strict';
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
exports = module.exports = {
|
||||
array: Array.prototype,
|
||||
buffer: Buffer && Buffer.prototype, // $lab:coverage:ignore$
|
||||
date: Date.prototype,
|
||||
error: Error.prototype,
|
||||
generic: Object.prototype,
|
||||
map: Map.prototype,
|
||||
promise: Promise.prototype,
|
||||
regex: RegExp.prototype,
|
||||
set: Set.prototype,
|
||||
weakMap: WeakMap.prototype,
|
||||
weakSet: WeakSet.prototype
|
||||
};
|
||||
|
||||
|
||||
internals.typeMap = new Map([
|
||||
['[object Error]', exports.error],
|
||||
['[object Map]', exports.map],
|
||||
['[object Promise]', exports.promise],
|
||||
['[object Set]', exports.set],
|
||||
['[object WeakMap]', exports.weakMap],
|
||||
['[object WeakSet]', exports.weakSet]
|
||||
]);
|
||||
|
||||
|
||||
exports.getInternalProto = function (obj) {
|
||||
|
||||
if (Array.isArray(obj)) {
|
||||
return exports.array;
|
||||
}
|
||||
|
||||
if (Buffer && obj instanceof Buffer) { // $lab:coverage:ignore$
|
||||
return exports.buffer;
|
||||
}
|
||||
|
||||
if (obj instanceof Date) {
|
||||
return exports.date;
|
||||
}
|
||||
|
||||
if (obj instanceof RegExp) {
|
||||
return exports.regex;
|
||||
}
|
||||
|
||||
if (obj instanceof Error) {
|
||||
return exports.error;
|
||||
}
|
||||
|
||||
const objName = Object.prototype.toString.call(obj);
|
||||
return internals.typeMap.get(objName) || exports.generic;
|
||||
};
|
54
web/node_modules/@hapi/hoek/lib/utils.js
generated
vendored
Executable file
54
web/node_modules/@hapi/hoek/lib/utils.js
generated
vendored
Executable file
|
@ -0,0 +1,54 @@
|
|||
'use strict';
|
||||
|
||||
const Reach = require('./reach');
|
||||
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
exports.keys = function (obj, options = {}) {
|
||||
|
||||
return options.symbols !== false ? Reflect.ownKeys(obj) : Object.getOwnPropertyNames(obj); // Defaults to true
|
||||
};
|
||||
|
||||
|
||||
exports.store = function (source, keys) {
|
||||
|
||||
const storage = new Map();
|
||||
for (let i = 0; i < keys.length; ++i) {
|
||||
const key = keys[i];
|
||||
const value = Reach(source, key);
|
||||
if (typeof value === 'object' ||
|
||||
typeof value === 'function') {
|
||||
|
||||
storage.set(key, value);
|
||||
internals.reachSet(source, key, undefined);
|
||||
}
|
||||
}
|
||||
|
||||
return storage;
|
||||
};
|
||||
|
||||
|
||||
exports.restore = function (copy, source, storage) {
|
||||
|
||||
for (const [key, value] of storage) {
|
||||
internals.reachSet(copy, key, value);
|
||||
internals.reachSet(source, key, value);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
internals.reachSet = function (obj, key, value) {
|
||||
|
||||
const path = Array.isArray(key) ? key : key.split('.');
|
||||
let ref = obj;
|
||||
for (let i = 0; i < path.length; ++i) {
|
||||
const segment = path[i];
|
||||
if (i + 1 === path.length) {
|
||||
ref[segment] = value;
|
||||
}
|
||||
|
||||
ref = ref[segment];
|
||||
}
|
||||
};
|
9
web/node_modules/@hapi/hoek/lib/wait.js
generated
vendored
Executable file
9
web/node_modules/@hapi/hoek/lib/wait.js
generated
vendored
Executable file
|
@ -0,0 +1,9 @@
|
|||
'use strict';
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
module.exports = function (timeout) {
|
||||
|
||||
return new Promise((resolve) => setTimeout(resolve, timeout));
|
||||
};
|
24
web/node_modules/@hapi/hoek/package.json
generated
vendored
Executable file
24
web/node_modules/@hapi/hoek/package.json
generated
vendored
Executable file
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"name": "@hapi/hoek",
|
||||
"description": "General purpose node utilities",
|
||||
"version": "8.5.1",
|
||||
"repository": "git://github.com/hapijs/hoek",
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
"keywords": [
|
||||
"utilities"
|
||||
],
|
||||
"files": [
|
||||
"lib"
|
||||
],
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"@hapi/code": "6.x.x",
|
||||
"@hapi/lab": "20.x.x"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "lab -a @hapi/code -t 100 -L -Y",
|
||||
"test-cov-html": "lab -a @hapi/code -t 100 -L -r html -o coverage.html"
|
||||
},
|
||||
"license": "BSD-3-Clause"
|
||||
}
|
3
web/node_modules/@hapi/joi/CHANGELOG.md
generated
vendored
Normal file
3
web/node_modules/@hapi/joi/CHANGELOG.md
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
Breaking changes are documented using GitHub issues, see [issues labeled "release notes"](https://github.com/hapijs/joi/issues?q=is%3Aissue+label%3A%22release+notes%22).
|
||||
|
||||
If you want changes of a specific minor or patch release, you can browse the [GitHub milestones](https://github.com/hapijs/joi/milestones?state=closed&direction=asc&sort=due_date).
|
10
web/node_modules/@hapi/joi/LICENSE.md
generated
vendored
Executable file
10
web/node_modules/@hapi/joi/LICENSE.md
generated
vendored
Executable file
|
@ -0,0 +1,10 @@
|
|||
Copyright (c) 2012-2019, Sideway Inc, and project contributors
|
||||
Copyright (c) 2012-2014, Walmart.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* The names of any contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS OFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
125
web/node_modules/@hapi/joi/README.md
generated
vendored
Normal file
125
web/node_modules/@hapi/joi/README.md
generated
vendored
Normal file
|
@ -0,0 +1,125 @@
|
|||
<a href="http://hapijs.com"><img src="https://raw.githubusercontent.com/hapijs/assets/master/images/family.png" width="180px" align="right" /></a>
|
||||
|
||||
# joi
|
||||
|
||||
Object schema description language and validator for JavaScript objects.
|
||||
|
||||
[](https://travis-ci.org/hapijs/joi)
|
||||
|
||||
## Introduction
|
||||
|
||||
Imagine you run facebook and you want visitors to sign up on the website with real names and not something like `l337_p@nda` in the first name field. How would you define the limitations of what can be inputted and validate it against the set rules?
|
||||
|
||||
This is joi, joi allows you to create *blueprints* or *schemas* for JavaScript objects (an object that stores information) to ensure *validation* of key information.
|
||||
|
||||
# Installation
|
||||
|
||||
```cli
|
||||
npm install --save @hapi/joi
|
||||
```
|
||||
|
||||
## API
|
||||
See the detailed [API Reference](https://github.com/hapijs/joi/blob/v15.1.0/API.md).
|
||||
|
||||
## Example
|
||||
|
||||
```javascript
|
||||
const Joi = require('@hapi/joi');
|
||||
|
||||
const schema = Joi.object().keys({
|
||||
username: Joi.string().alphanum().min(3).max(30).required(),
|
||||
password: Joi.string().regex(/^[a-zA-Z0-9]{3,30}$/),
|
||||
access_token: [Joi.string(), Joi.number()],
|
||||
birthyear: Joi.number().integer().min(1900).max(2013),
|
||||
email: Joi.string().email({ minDomainSegments: 2 })
|
||||
}).with('username', 'birthyear').without('password', 'access_token');
|
||||
|
||||
// Return result.
|
||||
const result = Joi.validate({ username: 'abc', birthyear: 1994 }, schema);
|
||||
// result.error === null -> valid
|
||||
|
||||
// You can also pass a callback which will be called synchronously with the validation result.
|
||||
Joi.validate({ username: 'abc', birthyear: 1994 }, schema, function (err, value) { }); // err === null -> valid
|
||||
|
||||
```
|
||||
|
||||
The above schema defines the following constraints:
|
||||
* `username`
|
||||
* a required string
|
||||
* must contain only alphanumeric characters
|
||||
* at least 3 characters long but no more than 30
|
||||
* must be accompanied by `birthyear`
|
||||
* `password`
|
||||
* an optional string
|
||||
* must satisfy the custom regex
|
||||
* cannot appear together with `access_token`
|
||||
* `access_token`
|
||||
* an optional, unconstrained string or number
|
||||
* `birthyear`
|
||||
* an integer between 1900 and 2013
|
||||
* `email`
|
||||
* a valid email address string
|
||||
* must have two domain parts e.g. `example.com`
|
||||
|
||||
## Usage
|
||||
|
||||
Usage is a two steps process. First, a schema is constructed using the provided types and constraints:
|
||||
|
||||
```javascript
|
||||
const schema = {
|
||||
a: Joi.string()
|
||||
};
|
||||
```
|
||||
|
||||
Note that **joi** schema objects are immutable which means every additional rule added (e.g. `.min(5)`) will return a
|
||||
new schema object.
|
||||
|
||||
Second, the value is validated against the defined schema:
|
||||
|
||||
```javascript
|
||||
const {error, value} = Joi.validate({ a: 'a string' }, schema);
|
||||
|
||||
// or
|
||||
|
||||
Joi.validate({ a: 'a string' }, schema, function (error, value) { });
|
||||
```
|
||||
|
||||
If the input is valid, then the `error` will be `null`, otherwise it will be an `Error` object providing more information.
|
||||
|
||||
The schema can be a plain JavaScript object where every key is assigned a **joi** type, or it can be a **joi** type directly:
|
||||
|
||||
```javascript
|
||||
const schema = Joi.string().min(10);
|
||||
```
|
||||
|
||||
If the schema is a **joi** type, the `schema.validate(value, callback)` can be called directly on the type. When passing a non-type schema object,
|
||||
the module converts it internally to an object() type equivalent to:
|
||||
|
||||
```javascript
|
||||
const schema = Joi.object().keys({
|
||||
a: Joi.string()
|
||||
});
|
||||
```
|
||||
|
||||
When validating a schema:
|
||||
|
||||
* Values (or keys in case of objects) are optional by default.
|
||||
|
||||
```javascript
|
||||
Joi.validate(undefined, Joi.string()); // validates fine
|
||||
```
|
||||
|
||||
To disallow this behavior, you can either set the schema as `required()`, or set `presence` to `"required"` when passing `options`:
|
||||
|
||||
```javascript
|
||||
Joi.validate(undefined, Joi.string().required());
|
||||
// or
|
||||
Joi.validate(undefined, Joi.string(), /* options */ { presence: "required" });
|
||||
```
|
||||
|
||||
* Strings are utf-8 encoded by default.
|
||||
* Rules are defined in an additive fashion and evaluated in order, first the inclusive rules, then the exclusive rules.
|
||||
|
||||
## Browsers
|
||||
|
||||
Joi doesn't directly support browsers, but you could use [joi-browser](https://github.com/jeffbski/joi-browser) for an ES5 build of Joi that works in browsers, or as a source of inspiration for your own builds.
|
59
web/node_modules/@hapi/joi/lib/cast.js
generated
vendored
Executable file
59
web/node_modules/@hapi/joi/lib/cast.js
generated
vendored
Executable file
|
@ -0,0 +1,59 @@
|
|||
'use strict';
|
||||
|
||||
const Hoek = require('@hapi/hoek');
|
||||
|
||||
const Ref = require('./ref');
|
||||
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
exports.schema = function (Joi, config) {
|
||||
|
||||
if (config !== undefined && config !== null && typeof config === 'object') {
|
||||
|
||||
if (config.isJoi) {
|
||||
return config;
|
||||
}
|
||||
|
||||
if (Array.isArray(config)) {
|
||||
return Joi.alternatives().try(config);
|
||||
}
|
||||
|
||||
if (config instanceof RegExp) {
|
||||
return Joi.string().regex(config);
|
||||
}
|
||||
|
||||
if (config instanceof Date) {
|
||||
return Joi.date().valid(config);
|
||||
}
|
||||
|
||||
return Joi.object().keys(config);
|
||||
}
|
||||
|
||||
if (typeof config === 'string') {
|
||||
return Joi.string().valid(config);
|
||||
}
|
||||
|
||||
if (typeof config === 'number') {
|
||||
return Joi.number().valid(config);
|
||||
}
|
||||
|
||||
if (typeof config === 'boolean') {
|
||||
return Joi.boolean().valid(config);
|
||||
}
|
||||
|
||||
if (Ref.isRef(config)) {
|
||||
return Joi.valid(config);
|
||||
}
|
||||
|
||||
Hoek.assert(config === null, 'Invalid schema content:', config);
|
||||
|
||||
return Joi.valid(null);
|
||||
};
|
||||
|
||||
|
||||
exports.ref = function (id) {
|
||||
|
||||
return Ref.isRef(id) ? id : Ref.create(id);
|
||||
};
|
372
web/node_modules/@hapi/joi/lib/errors.js
generated
vendored
Executable file
372
web/node_modules/@hapi/joi/lib/errors.js
generated
vendored
Executable file
|
@ -0,0 +1,372 @@
|
|||
'use strict';
|
||||
|
||||
const Hoek = require('@hapi/hoek');
|
||||
|
||||
const Language = require('./language');
|
||||
|
||||
|
||||
const internals = {
|
||||
annotations: Symbol('joi-annotations')
|
||||
};
|
||||
|
||||
|
||||
internals.stringify = function (value, wrapArrays) {
|
||||
|
||||
const type = typeof value;
|
||||
|
||||
if (value === null) {
|
||||
return 'null';
|
||||
}
|
||||
|
||||
if (type === 'string') {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (value instanceof exports.Err || type === 'function' || type === 'symbol') {
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
if (type === 'object') {
|
||||
if (Array.isArray(value)) {
|
||||
let partial = '';
|
||||
|
||||
for (let i = 0; i < value.length; ++i) {
|
||||
partial = partial + (partial.length ? ', ' : '') + internals.stringify(value[i], wrapArrays);
|
||||
}
|
||||
|
||||
return wrapArrays ? '[' + partial + ']' : partial;
|
||||
}
|
||||
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
return JSON.stringify(value);
|
||||
};
|
||||
|
||||
|
||||
exports.Err = class {
|
||||
|
||||
constructor(type, context, state, options, flags, message, template) {
|
||||
|
||||
this.isJoi = true;
|
||||
this.type = type;
|
||||
this.context = context || {};
|
||||
this.context.key = state.path[state.path.length - 1];
|
||||
this.context.label = state.key;
|
||||
this.path = state.path;
|
||||
this.options = options;
|
||||
this.flags = flags;
|
||||
this.message = message;
|
||||
this.template = template;
|
||||
|
||||
const localized = this.options.language;
|
||||
|
||||
if (this.flags.label) {
|
||||
this.context.label = this.flags.label;
|
||||
}
|
||||
else if (localized && // language can be null for arrays exclusion check
|
||||
(this.context.label === '' ||
|
||||
this.context.label === null)) {
|
||||
this.context.label = localized.root || Language.errors.root;
|
||||
}
|
||||
}
|
||||
|
||||
toString() {
|
||||
|
||||
if (this.message) {
|
||||
return this.message;
|
||||
}
|
||||
|
||||
let format;
|
||||
|
||||
if (this.template) {
|
||||
format = this.template;
|
||||
}
|
||||
|
||||
const localized = this.options.language;
|
||||
|
||||
format = format || Hoek.reach(localized, this.type) || Hoek.reach(Language.errors, this.type);
|
||||
|
||||
if (format === undefined) {
|
||||
return `Error code "${this.type}" is not defined, your custom type is missing the correct language definition`;
|
||||
}
|
||||
|
||||
let wrapArrays = Hoek.reach(localized, 'messages.wrapArrays');
|
||||
if (typeof wrapArrays !== 'boolean') {
|
||||
wrapArrays = Language.errors.messages.wrapArrays;
|
||||
}
|
||||
|
||||
if (format === null) {
|
||||
const childrenString = internals.stringify(this.context.reason, wrapArrays);
|
||||
if (wrapArrays) {
|
||||
return childrenString.slice(1, -1);
|
||||
}
|
||||
|
||||
return childrenString;
|
||||
}
|
||||
|
||||
const hasKey = /{{!?label}}/.test(format);
|
||||
const skipKey = format.length > 2 && format[0] === '!' && format[1] === '!';
|
||||
|
||||
if (skipKey) {
|
||||
format = format.slice(2);
|
||||
}
|
||||
|
||||
if (!hasKey && !skipKey) {
|
||||
const localizedKey = Hoek.reach(localized, 'key');
|
||||
if (typeof localizedKey === 'string') {
|
||||
format = localizedKey + format;
|
||||
}
|
||||
else {
|
||||
format = Hoek.reach(Language.errors, 'key') + format;
|
||||
}
|
||||
}
|
||||
|
||||
const message = format.replace(/{{(!?)([^}]+)}}/g, ($0, isSecure, name) => {
|
||||
|
||||
const value = Hoek.reach(this.context, name);
|
||||
const normalized = internals.stringify(value, wrapArrays);
|
||||
return (isSecure && this.options.escapeHtml ? Hoek.escapeHtml(normalized) : normalized);
|
||||
});
|
||||
|
||||
this.toString = () => message; // Persist result of last toString call, it won't change
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
exports.create = function (type, context, state, options, flags, message, template) {
|
||||
|
||||
return new exports.Err(type, context, state, options, flags, message, template);
|
||||
};
|
||||
|
||||
|
||||
exports.process = function (errors, object) {
|
||||
|
||||
if (!errors) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Construct error
|
||||
|
||||
let message = '';
|
||||
const details = [];
|
||||
|
||||
const processErrors = function (localErrors, parent, overrideMessage) {
|
||||
|
||||
for (let i = 0; i < localErrors.length; ++i) {
|
||||
const item = localErrors[i];
|
||||
|
||||
if (item instanceof Error) {
|
||||
return item;
|
||||
}
|
||||
|
||||
if (item.flags.error && typeof item.flags.error !== 'function') {
|
||||
if (!item.flags.selfError || !item.context.reason) {
|
||||
return item.flags.error;
|
||||
}
|
||||
}
|
||||
|
||||
let itemMessage;
|
||||
if (parent === undefined) {
|
||||
itemMessage = item.toString();
|
||||
message = message + (message ? '. ' : '') + itemMessage;
|
||||
}
|
||||
|
||||
// Do not push intermediate errors, we're only interested in leafs
|
||||
|
||||
if (item.context.reason) {
|
||||
const override = processErrors(item.context.reason, item.path, item.type === 'override' ? item.message : null);
|
||||
if (override) {
|
||||
return override;
|
||||
}
|
||||
}
|
||||
else {
|
||||
details.push({
|
||||
message: overrideMessage || itemMessage || item.toString(),
|
||||
path: item.path,
|
||||
type: item.type,
|
||||
context: item.context
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const override = processErrors(errors);
|
||||
if (override) {
|
||||
return override;
|
||||
}
|
||||
|
||||
const error = new Error(message);
|
||||
error.isJoi = true;
|
||||
error.name = 'ValidationError';
|
||||
error.details = details;
|
||||
error._object = object;
|
||||
error.annotate = internals.annotate;
|
||||
return error;
|
||||
};
|
||||
|
||||
|
||||
// Inspired by json-stringify-safe
|
||||
|
||||
internals.safeStringify = function (obj, spaces) {
|
||||
|
||||
return JSON.stringify(obj, internals.serializer(), spaces);
|
||||
};
|
||||
|
||||
|
||||
internals.serializer = function () {
|
||||
|
||||
const keys = [];
|
||||
const stack = [];
|
||||
|
||||
const cycleReplacer = (key, value) => {
|
||||
|
||||
if (stack[0] === value) {
|
||||
return '[Circular ~]';
|
||||
}
|
||||
|
||||
return '[Circular ~.' + keys.slice(0, stack.indexOf(value)).join('.') + ']';
|
||||
};
|
||||
|
||||
return function (key, value) {
|
||||
|
||||
if (stack.length > 0) {
|
||||
const thisPos = stack.indexOf(this);
|
||||
if (~thisPos) {
|
||||
stack.length = thisPos + 1;
|
||||
keys.length = thisPos + 1;
|
||||
keys[thisPos] = key;
|
||||
}
|
||||
else {
|
||||
stack.push(this);
|
||||
keys.push(key);
|
||||
}
|
||||
|
||||
if (~stack.indexOf(value)) {
|
||||
value = cycleReplacer.call(this, key, value);
|
||||
}
|
||||
}
|
||||
else {
|
||||
stack.push(value);
|
||||
}
|
||||
|
||||
if (value) {
|
||||
const annotations = value[internals.annotations];
|
||||
if (annotations) {
|
||||
if (Array.isArray(value)) {
|
||||
const annotated = [];
|
||||
|
||||
for (let i = 0; i < value.length; ++i) {
|
||||
if (annotations.errors[i]) {
|
||||
annotated.push(`_$idx$_${annotations.errors[i].sort().join(', ')}_$end$_`);
|
||||
}
|
||||
|
||||
annotated.push(value[i]);
|
||||
}
|
||||
|
||||
value = annotated;
|
||||
}
|
||||
else {
|
||||
const errorKeys = Object.keys(annotations.errors);
|
||||
for (let i = 0; i < errorKeys.length; ++i) {
|
||||
const errorKey = errorKeys[i];
|
||||
value[`${errorKey}_$key$_${annotations.errors[errorKey].sort().join(', ')}_$end$_`] = value[errorKey];
|
||||
value[errorKey] = undefined;
|
||||
}
|
||||
|
||||
const missingKeys = Object.keys(annotations.missing);
|
||||
for (let i = 0; i < missingKeys.length; ++i) {
|
||||
const missingKey = missingKeys[i];
|
||||
value[`_$miss$_${missingKey}|${annotations.missing[missingKey]}_$end$_`] = '__missing__';
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
if (value === Infinity || value === -Infinity || Number.isNaN(value) ||
|
||||
typeof value === 'function' || typeof value === 'symbol') {
|
||||
return '[' + value.toString() + ']';
|
||||
}
|
||||
|
||||
return value;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
internals.annotate = function (stripColorCodes) {
|
||||
|
||||
const redFgEscape = stripColorCodes ? '' : '\u001b[31m';
|
||||
const redBgEscape = stripColorCodes ? '' : '\u001b[41m';
|
||||
const endColor = stripColorCodes ? '' : '\u001b[0m';
|
||||
|
||||
if (typeof this._object !== 'object') {
|
||||
return this.details[0].message;
|
||||
}
|
||||
|
||||
const obj = Hoek.clone(this._object || {});
|
||||
|
||||
for (let i = this.details.length - 1; i >= 0; --i) { // Reverse order to process deepest child first
|
||||
const pos = i + 1;
|
||||
const error = this.details[i];
|
||||
const path = error.path;
|
||||
let ref = obj;
|
||||
for (let j = 0; ; ++j) {
|
||||
const seg = path[j];
|
||||
|
||||
if (ref.isImmutable) {
|
||||
ref = ref.clone(); // joi schemas are not cloned by hoek, we have to take this extra step
|
||||
}
|
||||
|
||||
if (j + 1 < path.length &&
|
||||
ref[seg] &&
|
||||
typeof ref[seg] !== 'string') {
|
||||
|
||||
ref = ref[seg];
|
||||
}
|
||||
else {
|
||||
const refAnnotations = ref[internals.annotations] = ref[internals.annotations] || { errors: {}, missing: {} };
|
||||
const value = ref[seg];
|
||||
const cacheKey = seg || error.context.label;
|
||||
|
||||
if (value !== undefined) {
|
||||
refAnnotations.errors[cacheKey] = refAnnotations.errors[cacheKey] || [];
|
||||
refAnnotations.errors[cacheKey].push(pos);
|
||||
}
|
||||
else {
|
||||
refAnnotations.missing[cacheKey] = pos;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const replacers = {
|
||||
key: /_\$key\$_([, \d]+)_\$end\$_"/g,
|
||||
missing: /"_\$miss\$_([^|]+)\|(\d+)_\$end\$_": "__missing__"/g,
|
||||
arrayIndex: /\s*"_\$idx\$_([, \d]+)_\$end\$_",?\n(.*)/g,
|
||||
specials: /"\[(NaN|Symbol.*|-?Infinity|function.*|\(.*)]"/g
|
||||
};
|
||||
|
||||
let message = internals.safeStringify(obj, 2)
|
||||
.replace(replacers.key, ($0, $1) => `" ${redFgEscape}[${$1}]${endColor}`)
|
||||
.replace(replacers.missing, ($0, $1, $2) => `${redBgEscape}"${$1}"${endColor}${redFgEscape} [${$2}]: -- missing --${endColor}`)
|
||||
.replace(replacers.arrayIndex, ($0, $1, $2) => `\n${$2} ${redFgEscape}[${$1}]${endColor}`)
|
||||
.replace(replacers.specials, ($0, $1) => $1);
|
||||
|
||||
message = `${message}\n${redFgEscape}`;
|
||||
|
||||
for (let i = 0; i < this.details.length; ++i) {
|
||||
const pos = i + 1;
|
||||
message = `${message}\n[${pos}] ${this.details[i].message}`;
|
||||
}
|
||||
|
||||
message = message + endColor;
|
||||
|
||||
return message;
|
||||
};
|
478
web/node_modules/@hapi/joi/lib/index.js
generated
vendored
Executable file
478
web/node_modules/@hapi/joi/lib/index.js
generated
vendored
Executable file
|
@ -0,0 +1,478 @@
|
|||
'use strict';
|
||||
|
||||
const Hoek = require('@hapi/hoek');
|
||||
|
||||
const Any = require('./types/any');
|
||||
const Cast = require('./cast');
|
||||
const Errors = require('./errors');
|
||||
const Lazy = require('./types/lazy');
|
||||
const Ref = require('./ref');
|
||||
|
||||
|
||||
const internals = {
|
||||
alternatives: require('./types/alternatives'),
|
||||
array: require('./types/array'),
|
||||
boolean: require('./types/boolean'),
|
||||
binary: require('./types/binary'),
|
||||
date: require('./types/date'),
|
||||
func: require('./types/func'),
|
||||
number: require('./types/number'),
|
||||
object: require('./types/object'),
|
||||
string: require('./types/string'),
|
||||
symbol: require('./types/symbol')
|
||||
};
|
||||
|
||||
|
||||
internals.callWithDefaults = function (schema, args) {
|
||||
|
||||
Hoek.assert(this, 'Must be invoked on a Joi instance.');
|
||||
|
||||
if (this._defaults) {
|
||||
schema = this._defaults(schema);
|
||||
}
|
||||
|
||||
schema._currentJoi = this;
|
||||
|
||||
return schema._init(...args);
|
||||
};
|
||||
|
||||
|
||||
internals.root = function () {
|
||||
|
||||
const any = new Any();
|
||||
|
||||
const root = any.clone();
|
||||
Any.prototype._currentJoi = root;
|
||||
root._currentJoi = root;
|
||||
root._binds = new Set(['any', 'alternatives', 'alt', 'array', 'bool', 'boolean', 'binary', 'date', 'func', 'number', 'object', 'string', 'symbol', 'validate', 'describe', 'compile', 'assert', 'attempt', 'lazy', 'defaults', 'extend', 'allow', 'valid', 'only', 'equal', 'invalid', 'disallow', 'not', 'required', 'exist', 'optional', 'forbidden', 'strip', 'when', 'empty', 'default']);
|
||||
|
||||
root.any = function (...args) {
|
||||
|
||||
Hoek.assert(args.length === 0, 'Joi.any() does not allow arguments.');
|
||||
|
||||
return internals.callWithDefaults.call(this, any, args);
|
||||
};
|
||||
|
||||
root.alternatives = root.alt = function (...args) {
|
||||
|
||||
return internals.callWithDefaults.call(this, internals.alternatives, args);
|
||||
};
|
||||
|
||||
root.array = function (...args) {
|
||||
|
||||
Hoek.assert(args.length === 0, 'Joi.array() does not allow arguments.');
|
||||
|
||||
return internals.callWithDefaults.call(this, internals.array, args);
|
||||
};
|
||||
|
||||
root.boolean = root.bool = function (...args) {
|
||||
|
||||
Hoek.assert(args.length === 0, 'Joi.boolean() does not allow arguments.');
|
||||
|
||||
return internals.callWithDefaults.call(this, internals.boolean, args);
|
||||
};
|
||||
|
||||
root.binary = function (...args) {
|
||||
|
||||
Hoek.assert(args.length === 0, 'Joi.binary() does not allow arguments.');
|
||||
|
||||
return internals.callWithDefaults.call(this, internals.binary, args);
|
||||
};
|
||||
|
||||
root.date = function (...args) {
|
||||
|
||||
Hoek.assert(args.length === 0, 'Joi.date() does not allow arguments.');
|
||||
|
||||
return internals.callWithDefaults.call(this, internals.date, args);
|
||||
};
|
||||
|
||||
root.func = function (...args) {
|
||||
|
||||
Hoek.assert(args.length === 0, 'Joi.func() does not allow arguments.');
|
||||
|
||||
return internals.callWithDefaults.call(this, internals.func, args);
|
||||
};
|
||||
|
||||
root.number = function (...args) {
|
||||
|
||||
Hoek.assert(args.length === 0, 'Joi.number() does not allow arguments.');
|
||||
|
||||
return internals.callWithDefaults.call(this, internals.number, args);
|
||||
};
|
||||
|
||||
root.object = function (...args) {
|
||||
|
||||
return internals.callWithDefaults.call(this, internals.object, args);
|
||||
};
|
||||
|
||||
root.string = function (...args) {
|
||||
|
||||
Hoek.assert(args.length === 0, 'Joi.string() does not allow arguments.');
|
||||
|
||||
return internals.callWithDefaults.call(this, internals.string, args);
|
||||
};
|
||||
|
||||
root.symbol = function (...args) {
|
||||
|
||||
Hoek.assert(args.length === 0, 'Joi.symbol() does not allow arguments.');
|
||||
|
||||
return internals.callWithDefaults.call(this, internals.symbol, args);
|
||||
};
|
||||
|
||||
root.ref = function (...args) {
|
||||
|
||||
return Ref.create(...args);
|
||||
};
|
||||
|
||||
root.isRef = function (ref) {
|
||||
|
||||
return Ref.isRef(ref);
|
||||
};
|
||||
|
||||
root.validate = function (value, ...args /*, [schema], [options], callback */) {
|
||||
|
||||
const last = args[args.length - 1];
|
||||
const callback = typeof last === 'function' ? last : null;
|
||||
|
||||
const count = args.length - (callback ? 1 : 0);
|
||||
if (count === 0) {
|
||||
return any.validate(value, callback);
|
||||
}
|
||||
|
||||
const options = count === 2 ? args[1] : undefined;
|
||||
const schema = this.compile(args[0]);
|
||||
|
||||
return schema._validateWithOptions(value, options, callback);
|
||||
};
|
||||
|
||||
root.describe = function (...args) {
|
||||
|
||||
const schema = args.length ? this.compile(args[0]) : any;
|
||||
return schema.describe();
|
||||
};
|
||||
|
||||
root.compile = function (schema) {
|
||||
|
||||
try {
|
||||
return Cast.schema(this, schema);
|
||||
}
|
||||
catch (err) {
|
||||
if (err.hasOwnProperty('path')) {
|
||||
err.message = err.message + '(' + err.path + ')';
|
||||
}
|
||||
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
root.assert = function (value, schema, message) {
|
||||
|
||||
this.attempt(value, schema, message);
|
||||
};
|
||||
|
||||
root.attempt = function (value, schema, message) {
|
||||
|
||||
const result = this.validate(value, schema);
|
||||
const error = result.error;
|
||||
if (error) {
|
||||
if (!message) {
|
||||
if (typeof error.annotate === 'function') {
|
||||
error.message = error.annotate();
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
|
||||
if (!(message instanceof Error)) {
|
||||
if (typeof error.annotate === 'function') {
|
||||
error.message = `${message} ${error.annotate()}`;
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
|
||||
throw message;
|
||||
}
|
||||
|
||||
return result.value;
|
||||
};
|
||||
|
||||
root.reach = function (schema, path) {
|
||||
|
||||
Hoek.assert(schema && schema instanceof Any, 'you must provide a joi schema');
|
||||
Hoek.assert(Array.isArray(path) || typeof path === 'string', 'path must be a string or an array of strings');
|
||||
|
||||
const reach = (sourceSchema, schemaPath) => {
|
||||
|
||||
if (!schemaPath.length) {
|
||||
return sourceSchema;
|
||||
}
|
||||
|
||||
const children = sourceSchema._inner.children;
|
||||
if (!children) {
|
||||
return;
|
||||
}
|
||||
|
||||
const key = schemaPath.shift();
|
||||
for (let i = 0; i < children.length; ++i) {
|
||||
const child = children[i];
|
||||
if (child.key === key) {
|
||||
return reach(child.schema, schemaPath);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const schemaPath = typeof path === 'string' ? (path ? path.split('.') : []) : path.slice();
|
||||
|
||||
return reach(schema, schemaPath);
|
||||
};
|
||||
|
||||
root.lazy = function (...args) {
|
||||
|
||||
return internals.callWithDefaults.call(this, Lazy, args);
|
||||
};
|
||||
|
||||
root.defaults = function (fn) {
|
||||
|
||||
Hoek.assert(typeof fn === 'function', 'Defaults must be a function');
|
||||
|
||||
let joi = Object.create(this.any());
|
||||
joi = fn(joi);
|
||||
|
||||
Hoek.assert(joi && joi instanceof this.constructor, 'defaults() must return a schema');
|
||||
|
||||
Object.assign(joi, this, joi.clone()); // Re-add the types from `this` but also keep the settings from joi's potential new defaults
|
||||
|
||||
joi._defaults = (schema) => {
|
||||
|
||||
if (this._defaults) {
|
||||
schema = this._defaults(schema);
|
||||
Hoek.assert(schema instanceof this.constructor, 'defaults() must return a schema');
|
||||
}
|
||||
|
||||
schema = fn(schema);
|
||||
Hoek.assert(schema instanceof this.constructor, 'defaults() must return a schema');
|
||||
return schema;
|
||||
};
|
||||
|
||||
return joi;
|
||||
};
|
||||
|
||||
root.bind = function () {
|
||||
|
||||
const joi = Object.create(this);
|
||||
|
||||
joi._binds.forEach((bind) => {
|
||||
|
||||
joi[bind] = joi[bind].bind(joi);
|
||||
});
|
||||
|
||||
return joi;
|
||||
};
|
||||
|
||||
root.extend = function (...args) {
|
||||
|
||||
const extensions = Hoek.flatten(args);
|
||||
Hoek.assert(extensions.length > 0, 'You need to provide at least one extension');
|
||||
|
||||
this.assert(extensions, root.extensionsSchema);
|
||||
|
||||
const joi = Object.create(this.any());
|
||||
Object.assign(joi, this);
|
||||
joi._currentJoi = joi;
|
||||
joi._binds = new Set(joi._binds);
|
||||
|
||||
for (let i = 0; i < extensions.length; ++i) {
|
||||
let extension = extensions[i];
|
||||
|
||||
if (typeof extension === 'function') {
|
||||
extension = extension(joi);
|
||||
}
|
||||
|
||||
this.assert(extension, root.extensionSchema);
|
||||
|
||||
const base = (extension.base || this.any()).clone(); // Cloning because we're going to override language afterwards
|
||||
const ctor = base.constructor;
|
||||
const type = class extends ctor { // eslint-disable-line no-loop-func
|
||||
|
||||
constructor() {
|
||||
|
||||
super();
|
||||
if (extension.base) {
|
||||
Object.assign(this, base);
|
||||
}
|
||||
|
||||
this._type = extension.name;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
if (extension.language) {
|
||||
const lang = {
|
||||
[extension.name]: extension.language
|
||||
};
|
||||
type.prototype._language = Hoek.applyToDefaults(type.prototype._language || (base._settings && base._settings.language) || {}, lang);
|
||||
}
|
||||
|
||||
|
||||
if (extension.coerce) {
|
||||
type.prototype._coerce = function (value, state, options) {
|
||||
|
||||
if (ctor.prototype._coerce) {
|
||||
const baseRet = ctor.prototype._coerce.call(this, value, state, options);
|
||||
|
||||
if (baseRet.errors) {
|
||||
return baseRet;
|
||||
}
|
||||
|
||||
value = baseRet.value;
|
||||
}
|
||||
|
||||
const ret = extension.coerce.call(this, value, state, options);
|
||||
if (ret instanceof Errors.Err) {
|
||||
return { value, errors: ret };
|
||||
}
|
||||
|
||||
return { value: ret };
|
||||
};
|
||||
}
|
||||
|
||||
if (extension.pre) {
|
||||
type.prototype._base = function (value, state, options) {
|
||||
|
||||
if (ctor.prototype._base) {
|
||||
const baseRet = ctor.prototype._base.call(this, value, state, options);
|
||||
|
||||
if (baseRet.errors) {
|
||||
return baseRet;
|
||||
}
|
||||
|
||||
value = baseRet.value;
|
||||
}
|
||||
|
||||
const ret = extension.pre.call(this, value, state, options);
|
||||
if (ret instanceof Errors.Err) {
|
||||
return { value, errors: ret };
|
||||
}
|
||||
|
||||
return { value: ret };
|
||||
};
|
||||
}
|
||||
|
||||
if (extension.rules) {
|
||||
for (let j = 0; j < extension.rules.length; ++j) {
|
||||
const rule = extension.rules[j];
|
||||
const ruleArgs = rule.params ?
|
||||
(rule.params instanceof Any ? rule.params._inner.children.map((k) => k.key) : Object.keys(rule.params)) :
|
||||
[];
|
||||
const validateArgs = rule.params ? Cast.schema(this, rule.params) : null;
|
||||
|
||||
type.prototype[rule.name] = function (...rArgs) { // eslint-disable-line no-loop-func
|
||||
|
||||
if (rArgs.length > ruleArgs.length) {
|
||||
throw new Error('Unexpected number of arguments');
|
||||
}
|
||||
|
||||
let hasRef = false;
|
||||
let arg = {};
|
||||
|
||||
for (let k = 0; k < ruleArgs.length; ++k) {
|
||||
arg[ruleArgs[k]] = rArgs[k];
|
||||
if (!hasRef && Ref.isRef(rArgs[k])) {
|
||||
hasRef = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (validateArgs) {
|
||||
arg = joi.attempt(arg, validateArgs);
|
||||
}
|
||||
|
||||
let schema;
|
||||
if (rule.validate && !rule.setup) {
|
||||
const validate = function (value, state, options) {
|
||||
|
||||
return rule.validate.call(this, arg, value, state, options);
|
||||
};
|
||||
|
||||
schema = this._test(rule.name, arg, validate, {
|
||||
description: rule.description,
|
||||
hasRef
|
||||
});
|
||||
}
|
||||
else {
|
||||
schema = this.clone();
|
||||
}
|
||||
|
||||
if (rule.setup) {
|
||||
const newSchema = rule.setup.call(schema, arg);
|
||||
if (newSchema !== undefined) {
|
||||
Hoek.assert(newSchema instanceof Any, `Setup of extension Joi.${this._type}().${rule.name}() must return undefined or a Joi object`);
|
||||
schema = newSchema;
|
||||
}
|
||||
|
||||
if (rule.validate) {
|
||||
const validate = function (value, state, options) {
|
||||
|
||||
return rule.validate.call(this, arg, value, state, options);
|
||||
};
|
||||
|
||||
schema = schema._test(rule.name, arg, validate, {
|
||||
description: rule.description,
|
||||
hasRef
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return schema;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (extension.describe) {
|
||||
type.prototype.describe = function () {
|
||||
|
||||
const description = ctor.prototype.describe.call(this);
|
||||
return extension.describe.call(this, description);
|
||||
};
|
||||
}
|
||||
|
||||
const instance = new type();
|
||||
joi[extension.name] = function (...extArgs) {
|
||||
|
||||
return internals.callWithDefaults.call(this, instance, extArgs);
|
||||
};
|
||||
|
||||
joi._binds.add(extension.name);
|
||||
}
|
||||
|
||||
return joi;
|
||||
};
|
||||
|
||||
root.extensionSchema = internals.object.keys({
|
||||
base: internals.object.type(Any, 'Joi object'),
|
||||
name: internals.string.required(),
|
||||
coerce: internals.func.arity(3),
|
||||
pre: internals.func.arity(3),
|
||||
language: internals.object,
|
||||
describe: internals.func.arity(1),
|
||||
rules: internals.array.items(internals.object.keys({
|
||||
name: internals.string.required(),
|
||||
setup: internals.func.arity(1),
|
||||
validate: internals.func.arity(4),
|
||||
params: [
|
||||
internals.object.pattern(/.*/, internals.object.type(Any, 'Joi object')),
|
||||
internals.object.type(internals.object.constructor, 'Joi object')
|
||||
],
|
||||
description: [internals.string, internals.func.arity(1)]
|
||||
}).or('setup', 'validate'))
|
||||
}).strict();
|
||||
|
||||
root.extensionsSchema = internals.array.items([internals.object, internals.func.arity(1)]).strict();
|
||||
|
||||
root.version = require('../package.json').version;
|
||||
|
||||
return root;
|
||||
};
|
||||
|
||||
|
||||
module.exports = internals.root();
|
161
web/node_modules/@hapi/joi/lib/language.js
generated
vendored
Executable file
161
web/node_modules/@hapi/joi/lib/language.js
generated
vendored
Executable file
|
@ -0,0 +1,161 @@
|
|||
'use strict';
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
exports.errors = {
|
||||
root: 'value',
|
||||
key: '"{{!label}}" ',
|
||||
messages: {
|
||||
wrapArrays: true
|
||||
},
|
||||
any: {
|
||||
unknown: 'is not allowed',
|
||||
invalid: 'contains an invalid value',
|
||||
empty: 'is not allowed to be empty',
|
||||
required: 'is required',
|
||||
allowOnly: 'must be one of {{valids}}',
|
||||
default: 'threw an error when running default method'
|
||||
},
|
||||
alternatives: {
|
||||
base: 'not matching any of the allowed alternatives',
|
||||
child: null
|
||||
},
|
||||
array: {
|
||||
base: 'must be an array',
|
||||
includes: 'at position {{pos}} does not match any of the allowed types',
|
||||
includesSingle: 'single value of "{{!label}}" does not match any of the allowed types',
|
||||
includesOne: 'at position {{pos}} fails because {{reason}}',
|
||||
includesOneSingle: 'single value of "{{!label}}" fails because {{reason}}',
|
||||
includesRequiredUnknowns: 'does not contain {{unknownMisses}} required value(s)',
|
||||
includesRequiredKnowns: 'does not contain {{knownMisses}}',
|
||||
includesRequiredBoth: 'does not contain {{knownMisses}} and {{unknownMisses}} other required value(s)',
|
||||
excludes: 'at position {{pos}} contains an excluded value',
|
||||
excludesSingle: 'single value of "{{!label}}" contains an excluded value',
|
||||
hasKnown: 'does not contain at least one required match for type "{{!patternLabel}}"',
|
||||
hasUnknown: 'does not contain at least one required match',
|
||||
min: 'must contain at least {{limit}} items',
|
||||
max: 'must contain less than or equal to {{limit}} items',
|
||||
length: 'must contain {{limit}} items',
|
||||
ordered: 'at position {{pos}} fails because {{reason}}',
|
||||
orderedLength: 'at position {{pos}} fails because array must contain at most {{limit}} items',
|
||||
ref: 'references "{{ref}}" which is not a positive integer',
|
||||
sparse: 'must not be a sparse array',
|
||||
unique: 'position {{pos}} contains a duplicate value'
|
||||
},
|
||||
boolean: {
|
||||
base: 'must be a boolean'
|
||||
},
|
||||
binary: {
|
||||
base: 'must be a buffer or a string',
|
||||
min: 'must be at least {{limit}} bytes',
|
||||
max: 'must be less than or equal to {{limit}} bytes',
|
||||
length: 'must be {{limit}} bytes'
|
||||
},
|
||||
date: {
|
||||
base: 'must be a number of milliseconds or valid date string',
|
||||
strict: 'must be a valid date',
|
||||
min: 'must be larger than or equal to "{{limit}}"',
|
||||
max: 'must be less than or equal to "{{limit}}"',
|
||||
less: 'must be less than "{{limit}}"',
|
||||
greater: 'must be greater than "{{limit}}"',
|
||||
isoDate: 'must be a valid ISO 8601 date',
|
||||
timestamp: {
|
||||
javascript: 'must be a valid timestamp or number of milliseconds',
|
||||
unix: 'must be a valid timestamp or number of seconds'
|
||||
},
|
||||
ref: 'references "{{ref}}" which is not a date'
|
||||
},
|
||||
function: {
|
||||
base: 'must be a Function',
|
||||
arity: 'must have an arity of {{n}}',
|
||||
minArity: 'must have an arity greater or equal to {{n}}',
|
||||
maxArity: 'must have an arity lesser or equal to {{n}}',
|
||||
ref: 'must be a Joi reference',
|
||||
class: 'must be a class'
|
||||
},
|
||||
lazy: {
|
||||
base: '!!schema error: lazy schema must be set',
|
||||
schema: '!!schema error: lazy schema function must return a schema'
|
||||
},
|
||||
object: {
|
||||
base: 'must be an object',
|
||||
child: '!!child "{{!child}}" fails because {{reason}}',
|
||||
min: 'must have at least {{limit}} children',
|
||||
max: 'must have less than or equal to {{limit}} children',
|
||||
length: 'must have {{limit}} children',
|
||||
allowUnknown: '!!"{{!child}}" is not allowed',
|
||||
with: '!!"{{mainWithLabel}}" missing required peer "{{peerWithLabel}}"',
|
||||
without: '!!"{{mainWithLabel}}" conflict with forbidden peer "{{peerWithLabel}}"',
|
||||
missing: 'must contain at least one of {{peersWithLabels}}',
|
||||
xor: 'contains a conflict between exclusive peers {{peersWithLabels}}',
|
||||
oxor: 'contains a conflict between optional exclusive peers {{peersWithLabels}}',
|
||||
and: 'contains {{presentWithLabels}} without its required peers {{missingWithLabels}}',
|
||||
nand: '!!"{{mainWithLabel}}" must not exist simultaneously with {{peersWithLabels}}',
|
||||
assert: '!!"{{ref}}" validation failed because "{{ref}}" failed to {{message}}',
|
||||
rename: {
|
||||
multiple: 'cannot rename child "{{from}}" because multiple renames are disabled and another key was already renamed to "{{to}}"',
|
||||
override: 'cannot rename child "{{from}}" because override is disabled and target "{{to}}" exists',
|
||||
regex: {
|
||||
multiple: 'cannot rename children {{from}} because multiple renames are disabled and another key was already renamed to "{{to}}"',
|
||||
override: 'cannot rename children {{from}} because override is disabled and target "{{to}}" exists'
|
||||
}
|
||||
},
|
||||
type: 'must be an instance of "{{type}}"',
|
||||
schema: 'must be a Joi instance'
|
||||
},
|
||||
number: {
|
||||
base: 'must be a number',
|
||||
unsafe: 'must be a safe number',
|
||||
min: 'must be larger than or equal to {{limit}}',
|
||||
max: 'must be less than or equal to {{limit}}',
|
||||
less: 'must be less than {{limit}}',
|
||||
greater: 'must be greater than {{limit}}',
|
||||
integer: 'must be an integer',
|
||||
negative: 'must be a negative number',
|
||||
positive: 'must be a positive number',
|
||||
precision: 'must have no more than {{limit}} decimal places',
|
||||
ref: 'references "{{ref}}" which is not a number',
|
||||
multiple: 'must be a multiple of {{multiple}}',
|
||||
port: 'must be a valid port'
|
||||
},
|
||||
string: {
|
||||
base: 'must be a string',
|
||||
min: 'length must be at least {{limit}} characters long',
|
||||
max: 'length must be less than or equal to {{limit}} characters long',
|
||||
length: 'length must be {{limit}} characters long',
|
||||
alphanum: 'must only contain alpha-numeric characters',
|
||||
token: 'must only contain alpha-numeric and underscore characters',
|
||||
regex: {
|
||||
base: 'with value "{{!value}}" fails to match the required pattern: {{pattern}}',
|
||||
name: 'with value "{{!value}}" fails to match the {{name}} pattern',
|
||||
invert: {
|
||||
base: 'with value "{{!value}}" matches the inverted pattern: {{pattern}}',
|
||||
name: 'with value "{{!value}}" matches the inverted {{name}} pattern'
|
||||
}
|
||||
},
|
||||
email: 'must be a valid email',
|
||||
uri: 'must be a valid uri',
|
||||
uriRelativeOnly: 'must be a valid relative uri',
|
||||
uriCustomScheme: 'must be a valid uri with a scheme matching the {{scheme}} pattern',
|
||||
isoDate: 'must be a valid ISO 8601 date',
|
||||
guid: 'must be a valid GUID',
|
||||
hex: 'must only contain hexadecimal characters',
|
||||
hexAlign: 'hex decoded representation must be byte aligned',
|
||||
base64: 'must be a valid base64 string',
|
||||
dataUri: 'must be a valid dataUri string',
|
||||
hostname: 'must be a valid hostname',
|
||||
normalize: 'must be unicode normalized in the {{form}} form',
|
||||
lowercase: 'must only contain lowercase characters',
|
||||
uppercase: 'must only contain uppercase characters',
|
||||
trim: 'must not have leading or trailing whitespace',
|
||||
creditCard: 'must be a credit card',
|
||||
ref: 'references "{{ref}}" which is not a number',
|
||||
ip: 'must be a valid ip address with a {{cidr}} CIDR',
|
||||
ipVersion: 'must be a valid ip address of one of the following versions {{version}} with a {{cidr}} CIDR'
|
||||
},
|
||||
symbol: {
|
||||
base: 'must be a symbol',
|
||||
map: 'must be one of {{map}}'
|
||||
}
|
||||
};
|
49
web/node_modules/@hapi/joi/lib/ref.js
generated
vendored
Executable file
49
web/node_modules/@hapi/joi/lib/ref.js
generated
vendored
Executable file
|
@ -0,0 +1,49 @@
|
|||
'use strict';
|
||||
|
||||
const Hoek = require('@hapi/hoek');
|
||||
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
exports.create = function (key, options) {
|
||||
|
||||
Hoek.assert(typeof key === 'string', 'Invalid reference key:', key);
|
||||
|
||||
const settings = Hoek.clone(options); // options can be reused and modified
|
||||
|
||||
const ref = function (value, validationOptions) {
|
||||
|
||||
return Hoek.reach(ref.isContext ? validationOptions.context : value, ref.key, settings);
|
||||
};
|
||||
|
||||
ref.isContext = (key[0] === ((settings && settings.contextPrefix) || '$'));
|
||||
ref.key = (ref.isContext ? key.slice(1) : key);
|
||||
ref.path = ref.key.split((settings && settings.separator) || '.');
|
||||
ref.depth = ref.path.length;
|
||||
ref.root = ref.path[0];
|
||||
ref.isJoi = true;
|
||||
|
||||
ref.toString = function () {
|
||||
|
||||
return (ref.isContext ? 'context:' : 'ref:') + ref.key;
|
||||
};
|
||||
|
||||
return ref;
|
||||
};
|
||||
|
||||
|
||||
exports.isRef = function (ref) {
|
||||
|
||||
return typeof ref === 'function' && ref.isJoi;
|
||||
};
|
||||
|
||||
|
||||
exports.push = function (array, ref) {
|
||||
|
||||
if (exports.isRef(ref) &&
|
||||
!ref.isContext) {
|
||||
|
||||
array.push(ref.root);
|
||||
}
|
||||
};
|
20
web/node_modules/@hapi/joi/lib/schemas.js
generated
vendored
Executable file
20
web/node_modules/@hapi/joi/lib/schemas.js
generated
vendored
Executable file
|
@ -0,0 +1,20 @@
|
|||
'use strict';
|
||||
|
||||
const Joi = require('./index');
|
||||
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
exports.options = Joi.object({
|
||||
abortEarly: Joi.boolean(),
|
||||
convert: Joi.boolean(),
|
||||
allowUnknown: Joi.boolean(),
|
||||
skipFunctions: Joi.boolean(),
|
||||
stripUnknown: [Joi.boolean(), Joi.object({ arrays: Joi.boolean(), objects: Joi.boolean() }).or('arrays', 'objects')],
|
||||
language: Joi.object(),
|
||||
presence: Joi.string().only('required', 'optional', 'forbidden', 'ignore'),
|
||||
context: Joi.object(),
|
||||
noDefaults: Joi.boolean(),
|
||||
escapeHtml: Joi.boolean()
|
||||
}).strict();
|
191
web/node_modules/@hapi/joi/lib/set.js
generated
vendored
Normal file
191
web/node_modules/@hapi/joi/lib/set.js
generated
vendored
Normal file
|
@ -0,0 +1,191 @@
|
|||
'use strict';
|
||||
|
||||
const Ref = require('./ref');
|
||||
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
internals.extendedCheckForValue = function (value, insensitive) {
|
||||
|
||||
const valueType = typeof value;
|
||||
|
||||
if (valueType === 'object') {
|
||||
if (value instanceof Date) {
|
||||
return (item) => {
|
||||
|
||||
return item instanceof Date && value.getTime() === item.getTime();
|
||||
};
|
||||
}
|
||||
|
||||
if (Buffer.isBuffer(value)) {
|
||||
return (item) => {
|
||||
|
||||
return Buffer.isBuffer(item) && value.length === item.length && value.toString('binary') === item.toString('binary');
|
||||
};
|
||||
}
|
||||
}
|
||||
else if (insensitive && valueType === 'string') {
|
||||
const lowercaseValue = value.toLowerCase();
|
||||
return (item) => {
|
||||
|
||||
return typeof item === 'string' && lowercaseValue === item.toLowerCase();
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
|
||||
module.exports = class InternalSet {
|
||||
|
||||
constructor(from) {
|
||||
|
||||
this._set = new Set(from);
|
||||
this._hasRef = false;
|
||||
}
|
||||
|
||||
add(value, refs) {
|
||||
|
||||
const isRef = Ref.isRef(value);
|
||||
if (!isRef && this.has(value, null, null, false)) {
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
if (refs !== undefined) { // If it's a merge, we don't have any refs
|
||||
Ref.push(refs, value);
|
||||
}
|
||||
|
||||
this._set.add(value);
|
||||
|
||||
this._hasRef |= isRef;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
merge(add, remove) {
|
||||
|
||||
for (const item of add._set) {
|
||||
this.add(item);
|
||||
}
|
||||
|
||||
for (const item of remove._set) {
|
||||
this.remove(item);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
remove(value) {
|
||||
|
||||
this._set.delete(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
has(value, state, options, insensitive) {
|
||||
|
||||
return !!this.get(value, state, options, insensitive);
|
||||
}
|
||||
|
||||
get(value, state, options, insensitive) {
|
||||
|
||||
if (!this._set.size) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const hasValue = this._set.has(value);
|
||||
if (hasValue) {
|
||||
return { value };
|
||||
}
|
||||
|
||||
const extendedCheck = internals.extendedCheckForValue(value, insensitive);
|
||||
if (!extendedCheck) {
|
||||
if (state && this._hasRef) {
|
||||
for (let item of this._set) {
|
||||
if (Ref.isRef(item)) {
|
||||
item = [].concat(item(state.reference || state.parent, options));
|
||||
const found = item.indexOf(value);
|
||||
if (found >= 0) {
|
||||
return { value: item[found] };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return this._has(value, state, options, extendedCheck);
|
||||
}
|
||||
|
||||
_has(value, state, options, check) {
|
||||
|
||||
const checkRef = !!(state && this._hasRef);
|
||||
|
||||
const isReallyEqual = function (item) {
|
||||
|
||||
if (value === item) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return check(item);
|
||||
};
|
||||
|
||||
for (let item of this._set) {
|
||||
if (checkRef && Ref.isRef(item)) { // Only resolve references if there is a state, otherwise it's a merge
|
||||
item = item(state.reference || state.parent, options);
|
||||
|
||||
if (Array.isArray(item)) {
|
||||
const found = item.findIndex(isReallyEqual);
|
||||
if (found >= 0) {
|
||||
return {
|
||||
value: item[found]
|
||||
};
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (isReallyEqual(item)) {
|
||||
return {
|
||||
value: item
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
values(options) {
|
||||
|
||||
if (options && options.stripUndefined) {
|
||||
const values = [];
|
||||
|
||||
for (const item of this._set) {
|
||||
if (item !== undefined) {
|
||||
values.push(item);
|
||||
}
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
return Array.from(this._set);
|
||||
}
|
||||
|
||||
slice() {
|
||||
|
||||
const set = new InternalSet(this._set);
|
||||
set._hasRef = this._hasRef;
|
||||
return set;
|
||||
}
|
||||
|
||||
concat(source) {
|
||||
|
||||
const set = new InternalSet([...this._set, ...source._set]);
|
||||
set._hasRef = !!(this._hasRef | source._hasRef);
|
||||
return set;
|
||||
}
|
||||
};
|
215
web/node_modules/@hapi/joi/lib/types/alternatives/index.js
generated
vendored
Executable file
215
web/node_modules/@hapi/joi/lib/types/alternatives/index.js
generated
vendored
Executable file
|
@ -0,0 +1,215 @@
|
|||
'use strict';
|
||||
|
||||
const Hoek = require('@hapi/hoek');
|
||||
|
||||
const Any = require('../any');
|
||||
const Cast = require('../../cast');
|
||||
const Ref = require('../../ref');
|
||||
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
internals.Alternatives = class extends Any {
|
||||
|
||||
constructor() {
|
||||
|
||||
super();
|
||||
this._type = 'alternatives';
|
||||
this._invalids.remove(null);
|
||||
this._inner.matches = [];
|
||||
}
|
||||
|
||||
_init(...args) {
|
||||
|
||||
return args.length ? this.try(...args) : this;
|
||||
}
|
||||
|
||||
_base(value, state, options) {
|
||||
|
||||
const errors = [];
|
||||
const il = this._inner.matches.length;
|
||||
const baseType = this._baseType;
|
||||
|
||||
for (let i = 0; i < il; ++i) {
|
||||
const item = this._inner.matches[i];
|
||||
if (!item.schema) {
|
||||
const schema = item.peek || item.is;
|
||||
const input = item.is ? item.ref(state.reference || state.parent, options) : value;
|
||||
const failed = schema._validate(input, null, options, state.parent).errors;
|
||||
|
||||
if (failed) {
|
||||
if (item.otherwise) {
|
||||
return item.otherwise._validate(value, state, options);
|
||||
}
|
||||
}
|
||||
else if (item.then) {
|
||||
return item.then._validate(value, state, options);
|
||||
}
|
||||
|
||||
if (i === (il - 1) && baseType) {
|
||||
return baseType._validate(value, state, options);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
const result = item.schema._validate(value, state, options);
|
||||
if (!result.errors) { // Found a valid match
|
||||
return result;
|
||||
}
|
||||
|
||||
errors.push(...result.errors);
|
||||
}
|
||||
|
||||
if (errors.length) {
|
||||
return { errors: this.createError('alternatives.child', { reason: errors }, state, options) };
|
||||
}
|
||||
|
||||
return { errors: this.createError('alternatives.base', null, state, options) };
|
||||
}
|
||||
|
||||
try(...schemas) {
|
||||
|
||||
schemas = Hoek.flatten(schemas);
|
||||
Hoek.assert(schemas.length, 'Cannot add other alternatives without at least one schema');
|
||||
|
||||
const obj = this.clone();
|
||||
|
||||
for (let i = 0; i < schemas.length; ++i) {
|
||||
const cast = Cast.schema(this._currentJoi, schemas[i]);
|
||||
if (cast._refs.length) {
|
||||
obj._refs.push(...cast._refs);
|
||||
}
|
||||
|
||||
obj._inner.matches.push({ schema: cast });
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
when(condition, options) {
|
||||
|
||||
let schemaCondition = false;
|
||||
Hoek.assert(Ref.isRef(condition) || typeof condition === 'string' || (schemaCondition = condition instanceof Any), 'Invalid condition:', condition);
|
||||
Hoek.assert(options, 'Missing options');
|
||||
Hoek.assert(typeof options === 'object', 'Invalid options');
|
||||
if (schemaCondition) {
|
||||
Hoek.assert(!options.hasOwnProperty('is'), '"is" can not be used with a schema condition');
|
||||
}
|
||||
else {
|
||||
Hoek.assert(options.hasOwnProperty('is'), 'Missing "is" directive');
|
||||
}
|
||||
|
||||
Hoek.assert(options.then !== undefined || options.otherwise !== undefined, 'options must have at least one of "then" or "otherwise"');
|
||||
|
||||
const obj = this.clone();
|
||||
let is;
|
||||
if (!schemaCondition) {
|
||||
is = Cast.schema(this._currentJoi, options.is);
|
||||
|
||||
if (options.is === null || !(Ref.isRef(options.is) || options.is instanceof Any)) {
|
||||
|
||||
// Only apply required if this wasn't already a schema or a ref, we'll suppose people know what they're doing
|
||||
is = is.required();
|
||||
}
|
||||
}
|
||||
|
||||
const item = {
|
||||
ref: schemaCondition ? null : Cast.ref(condition),
|
||||
peek: schemaCondition ? condition : null,
|
||||
is,
|
||||
then: options.then !== undefined ? Cast.schema(this._currentJoi, options.then) : undefined,
|
||||
otherwise: options.otherwise !== undefined ? Cast.schema(this._currentJoi, options.otherwise) : undefined
|
||||
};
|
||||
|
||||
if (obj._baseType) {
|
||||
|
||||
item.then = item.then && obj._baseType.concat(item.then);
|
||||
item.otherwise = item.otherwise && obj._baseType.concat(item.otherwise);
|
||||
}
|
||||
|
||||
if (!schemaCondition) {
|
||||
Ref.push(obj._refs, item.ref);
|
||||
obj._refs.push(...item.is._refs);
|
||||
}
|
||||
|
||||
if (item.then && item.then._refs.length) {
|
||||
obj._refs.push(...item.then._refs);
|
||||
}
|
||||
|
||||
if (item.otherwise && item.otherwise._refs.length) {
|
||||
obj._refs.push(...item.otherwise._refs);
|
||||
}
|
||||
|
||||
obj._inner.matches.push(item);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
label(name) {
|
||||
|
||||
const obj = super.label(name);
|
||||
obj._inner.matches = obj._inner.matches.map((match) => {
|
||||
|
||||
if (match.schema) {
|
||||
return { schema: match.schema.label(name) };
|
||||
}
|
||||
|
||||
match = Object.assign({}, match);
|
||||
if (match.then) {
|
||||
match.then = match.then.label(name);
|
||||
}
|
||||
|
||||
if (match.otherwise) {
|
||||
match.otherwise = match.otherwise.label(name);
|
||||
}
|
||||
|
||||
return match;
|
||||
});
|
||||
return obj;
|
||||
}
|
||||
|
||||
describe() {
|
||||
|
||||
const description = super.describe();
|
||||
const alternatives = [];
|
||||
for (let i = 0; i < this._inner.matches.length; ++i) {
|
||||
const item = this._inner.matches[i];
|
||||
if (item.schema) {
|
||||
|
||||
// try()
|
||||
|
||||
alternatives.push(item.schema.describe());
|
||||
}
|
||||
else {
|
||||
|
||||
// when()
|
||||
|
||||
const when = item.is ? {
|
||||
ref: item.ref.toString(),
|
||||
is: item.is.describe()
|
||||
} : {
|
||||
peek: item.peek.describe()
|
||||
};
|
||||
|
||||
if (item.then) {
|
||||
when.then = item.then.describe();
|
||||
}
|
||||
|
||||
if (item.otherwise) {
|
||||
when.otherwise = item.otherwise.describe();
|
||||
}
|
||||
|
||||
alternatives.push(when);
|
||||
}
|
||||
}
|
||||
|
||||
description.alternatives = alternatives;
|
||||
return description;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
module.exports = new internals.Alternatives();
|
984
web/node_modules/@hapi/joi/lib/types/any/index.js
generated
vendored
Executable file
984
web/node_modules/@hapi/joi/lib/types/any/index.js
generated
vendored
Executable file
|
@ -0,0 +1,984 @@
|
|||
'use strict';
|
||||
|
||||
const Hoek = require('@hapi/hoek');
|
||||
|
||||
const Cast = require('../../cast');
|
||||
const Settings = require('./settings');
|
||||
const Ref = require('../../ref');
|
||||
const Errors = require('../../errors');
|
||||
const State = require('../state');
|
||||
const Symbols = require('../symbols');
|
||||
|
||||
const Pkg = require('../../../package.json');
|
||||
|
||||
let Alternatives = null; // Delay-loaded to prevent circular dependencies
|
||||
let Schemas = null;
|
||||
|
||||
|
||||
const internals = {
|
||||
Set: require('../../set'),
|
||||
symbol: Symbol.for('@hapi/joi/schema')
|
||||
};
|
||||
|
||||
|
||||
internals.defaults = {
|
||||
abortEarly: true,
|
||||
convert: true,
|
||||
allowUnknown: false,
|
||||
skipFunctions: false,
|
||||
stripUnknown: false,
|
||||
language: {},
|
||||
presence: 'optional',
|
||||
noDefaults: false,
|
||||
escapeHtml: false
|
||||
|
||||
// context: null
|
||||
};
|
||||
|
||||
|
||||
module.exports = internals.Any = class {
|
||||
|
||||
constructor() {
|
||||
|
||||
this.isJoi = true;
|
||||
this._type = 'any';
|
||||
this._settings = null;
|
||||
this._valids = new internals.Set();
|
||||
this._invalids = new internals.Set();
|
||||
this._tests = [];
|
||||
this._refs = [];
|
||||
this._flags = {
|
||||
/*
|
||||
presence: 'optional', // optional, required, forbidden, ignore
|
||||
allowOnly: false,
|
||||
allowUnknown: undefined,
|
||||
default: undefined,
|
||||
forbidden: false,
|
||||
encoding: undefined,
|
||||
insensitive: false,
|
||||
trim: false,
|
||||
normalize: undefined, // NFC, NFD, NFKC, NFKD
|
||||
case: undefined, // upper, lower
|
||||
empty: undefined,
|
||||
func: false,
|
||||
raw: false
|
||||
*/
|
||||
};
|
||||
|
||||
this._description = null;
|
||||
this._unit = null;
|
||||
this._notes = [];
|
||||
this._tags = [];
|
||||
this._examples = [];
|
||||
this._meta = [];
|
||||
|
||||
this._inner = {}; // Hash of arrays of immutable objects
|
||||
}
|
||||
|
||||
_init() {
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
get schemaType() {
|
||||
|
||||
return this._type;
|
||||
}
|
||||
|
||||
createError(type, context, state, options, flags = this._flags) {
|
||||
|
||||
return Errors.create(type, context, state, options, flags);
|
||||
}
|
||||
|
||||
createOverrideError(type, context, state, options, message, template) {
|
||||
|
||||
return Errors.create(type, context, state, options, this._flags, message, template);
|
||||
}
|
||||
|
||||
checkOptions(options) {
|
||||
|
||||
Schemas = Schemas || require('../../schemas');
|
||||
|
||||
const result = Schemas.options.validate(options);
|
||||
|
||||
if (result.error) {
|
||||
throw new Error(result.error.details[0].message);
|
||||
}
|
||||
}
|
||||
|
||||
clone() {
|
||||
|
||||
const obj = Object.create(Object.getPrototypeOf(this));
|
||||
|
||||
obj.isJoi = true;
|
||||
obj._currentJoi = this._currentJoi;
|
||||
obj._type = this._type;
|
||||
obj._settings = this._settings;
|
||||
obj._baseType = this._baseType;
|
||||
obj._valids = this._valids.slice();
|
||||
obj._invalids = this._invalids.slice();
|
||||
obj._tests = this._tests.slice();
|
||||
obj._refs = this._refs.slice();
|
||||
obj._flags = Hoek.clone(this._flags);
|
||||
|
||||
obj._description = this._description;
|
||||
obj._unit = this._unit;
|
||||
obj._notes = this._notes.slice();
|
||||
obj._tags = this._tags.slice();
|
||||
obj._examples = this._examples.slice();
|
||||
obj._meta = this._meta.slice();
|
||||
|
||||
obj._inner = {};
|
||||
const inners = Object.keys(this._inner);
|
||||
for (let i = 0; i < inners.length; ++i) {
|
||||
const key = inners[i];
|
||||
obj._inner[key] = this._inner[key] ? this._inner[key].slice() : null;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
concat(schema) {
|
||||
|
||||
Hoek.assert(schema instanceof internals.Any, 'Invalid schema object');
|
||||
Hoek.assert(this._type === 'any' || schema._type === 'any' || schema._type === this._type, 'Cannot merge type', this._type, 'with another type:', schema._type);
|
||||
|
||||
let obj = this.clone();
|
||||
|
||||
if (this._type === 'any' && schema._type !== 'any') {
|
||||
|
||||
// Reset values as if we were "this"
|
||||
const tmpObj = schema.clone();
|
||||
const keysToRestore = ['_settings', '_valids', '_invalids', '_tests', '_refs', '_flags', '_description', '_unit',
|
||||
'_notes', '_tags', '_examples', '_meta', '_inner'];
|
||||
|
||||
for (let i = 0; i < keysToRestore.length; ++i) {
|
||||
tmpObj[keysToRestore[i]] = obj[keysToRestore[i]];
|
||||
}
|
||||
|
||||
obj = tmpObj;
|
||||
}
|
||||
|
||||
obj._settings = obj._settings ? Settings.concat(obj._settings, schema._settings) : schema._settings;
|
||||
obj._valids.merge(schema._valids, schema._invalids);
|
||||
obj._invalids.merge(schema._invalids, schema._valids);
|
||||
obj._tests.push(...schema._tests);
|
||||
obj._refs.push(...schema._refs);
|
||||
if (obj._flags.empty && schema._flags.empty) {
|
||||
obj._flags.empty = obj._flags.empty.concat(schema._flags.empty);
|
||||
const flags = Object.assign({}, schema._flags);
|
||||
delete flags.empty;
|
||||
Hoek.merge(obj._flags, flags);
|
||||
}
|
||||
else if (schema._flags.empty) {
|
||||
obj._flags.empty = schema._flags.empty;
|
||||
const flags = Object.assign({}, schema._flags);
|
||||
delete flags.empty;
|
||||
Hoek.merge(obj._flags, flags);
|
||||
}
|
||||
else {
|
||||
Hoek.merge(obj._flags, schema._flags);
|
||||
}
|
||||
|
||||
obj._description = schema._description || obj._description;
|
||||
obj._unit = schema._unit || obj._unit;
|
||||
obj._notes.push(...schema._notes);
|
||||
obj._tags.push(...schema._tags);
|
||||
obj._examples.push(...schema._examples);
|
||||
obj._meta.push(...schema._meta);
|
||||
|
||||
const inners = Object.keys(schema._inner);
|
||||
const isObject = obj._type === 'object';
|
||||
for (let i = 0; i < inners.length; ++i) {
|
||||
const key = inners[i];
|
||||
const source = schema._inner[key];
|
||||
if (source) {
|
||||
const target = obj._inner[key];
|
||||
if (target) {
|
||||
if (isObject && key === 'children') {
|
||||
const keys = {};
|
||||
|
||||
for (let j = 0; j < target.length; ++j) {
|
||||
keys[target[j].key] = j;
|
||||
}
|
||||
|
||||
for (let j = 0; j < source.length; ++j) {
|
||||
const sourceKey = source[j].key;
|
||||
if (keys[sourceKey] >= 0) {
|
||||
target[keys[sourceKey]] = {
|
||||
key: sourceKey,
|
||||
schema: target[keys[sourceKey]].schema.concat(source[j].schema)
|
||||
};
|
||||
}
|
||||
else {
|
||||
target.push(source[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
obj._inner[key] = obj._inner[key].concat(source);
|
||||
}
|
||||
}
|
||||
else {
|
||||
obj._inner[key] = source.slice();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
_test(name, arg, func, options) {
|
||||
|
||||
const obj = this.clone();
|
||||
obj._tests.push({ func, name, arg, options });
|
||||
return obj;
|
||||
}
|
||||
|
||||
_testUnique(name, arg, func, options) {
|
||||
|
||||
const obj = this.clone();
|
||||
obj._tests = obj._tests.filter((test) => test.name !== name);
|
||||
obj._tests.push({ func, name, arg, options });
|
||||
return obj;
|
||||
}
|
||||
|
||||
options(options) {
|
||||
|
||||
Hoek.assert(!options.context, 'Cannot override context');
|
||||
this.checkOptions(options);
|
||||
|
||||
const obj = this.clone();
|
||||
obj._settings = Settings.concat(obj._settings, options);
|
||||
return obj;
|
||||
}
|
||||
|
||||
strict(isStrict) {
|
||||
|
||||
const obj = this.clone();
|
||||
|
||||
const convert = isStrict === undefined ? false : !isStrict;
|
||||
obj._settings = Settings.concat(obj._settings, { convert });
|
||||
return obj;
|
||||
}
|
||||
|
||||
raw(isRaw) {
|
||||
|
||||
const value = isRaw === undefined ? true : isRaw;
|
||||
|
||||
if (this._flags.raw === value) {
|
||||
return this;
|
||||
}
|
||||
|
||||
const obj = this.clone();
|
||||
obj._flags.raw = value;
|
||||
return obj;
|
||||
}
|
||||
|
||||
error(err, options = { self: false }) {
|
||||
|
||||
Hoek.assert(err && (err instanceof Error || typeof err === 'function'), 'Must provide a valid Error object or a function');
|
||||
|
||||
const unknownKeys = Object.keys(options).filter((k) => !['self'].includes(k));
|
||||
Hoek.assert(unknownKeys.length === 0, `Options ${unknownKeys} are unknown`);
|
||||
|
||||
const obj = this.clone();
|
||||
obj._flags.error = err;
|
||||
|
||||
if (options.self) {
|
||||
obj._flags.selfError = true;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
allow(...values) {
|
||||
|
||||
const obj = this.clone();
|
||||
values = Hoek.flatten(values);
|
||||
for (let i = 0; i < values.length; ++i) {
|
||||
const value = values[i];
|
||||
|
||||
Hoek.assert(value !== undefined, 'Cannot call allow/valid/invalid with undefined');
|
||||
obj._invalids.remove(value);
|
||||
obj._valids.add(value, obj._refs);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
valid(...values) {
|
||||
|
||||
const obj = this.allow(...values);
|
||||
obj._flags.allowOnly = true;
|
||||
return obj;
|
||||
}
|
||||
|
||||
invalid(...values) {
|
||||
|
||||
const obj = this.clone();
|
||||
values = Hoek.flatten(values);
|
||||
for (let i = 0; i < values.length; ++i) {
|
||||
const value = values[i];
|
||||
|
||||
Hoek.assert(value !== undefined, 'Cannot call allow/valid/invalid with undefined');
|
||||
obj._valids.remove(value);
|
||||
obj._invalids.add(value, obj._refs);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
required() {
|
||||
|
||||
if (this._flags.presence === 'required') {
|
||||
return this;
|
||||
}
|
||||
|
||||
const obj = this.clone();
|
||||
obj._flags.presence = 'required';
|
||||
return obj;
|
||||
}
|
||||
|
||||
optional() {
|
||||
|
||||
if (this._flags.presence === 'optional') {
|
||||
return this;
|
||||
}
|
||||
|
||||
const obj = this.clone();
|
||||
obj._flags.presence = 'optional';
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
forbidden() {
|
||||
|
||||
if (this._flags.presence === 'forbidden') {
|
||||
return this;
|
||||
}
|
||||
|
||||
const obj = this.clone();
|
||||
obj._flags.presence = 'forbidden';
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
strip() {
|
||||
|
||||
if (this._flags.strip) {
|
||||
return this;
|
||||
}
|
||||
|
||||
const obj = this.clone();
|
||||
obj._flags.strip = true;
|
||||
return obj;
|
||||
}
|
||||
|
||||
applyFunctionToChildren(children, fn, args = [], root) {
|
||||
|
||||
children = [].concat(children);
|
||||
|
||||
if (children.length !== 1 || children[0] !== '') {
|
||||
root = root ? (root + '.') : '';
|
||||
|
||||
const extraChildren = (children[0] === '' ? children.slice(1) : children).map((child) => {
|
||||
|
||||
return root + child;
|
||||
});
|
||||
|
||||
throw new Error('unknown key(s) ' + extraChildren.join(', '));
|
||||
}
|
||||
|
||||
return this[fn](...args);
|
||||
}
|
||||
|
||||
default(value, description) {
|
||||
|
||||
if (typeof value === 'function' &&
|
||||
!Ref.isRef(value)) {
|
||||
|
||||
if (!value.description &&
|
||||
description) {
|
||||
|
||||
value.description = description;
|
||||
}
|
||||
|
||||
if (!this._flags.func) {
|
||||
Hoek.assert(typeof value.description === 'string' && value.description.length > 0, 'description must be provided when default value is a function');
|
||||
}
|
||||
}
|
||||
|
||||
const obj = this.clone();
|
||||
obj._flags.default = value;
|
||||
Ref.push(obj._refs, value);
|
||||
return obj;
|
||||
}
|
||||
|
||||
empty(schema) {
|
||||
|
||||
const obj = this.clone();
|
||||
if (schema === undefined) {
|
||||
delete obj._flags.empty;
|
||||
}
|
||||
else {
|
||||
obj._flags.empty = Cast.schema(this._currentJoi, schema);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
when(condition, options) {
|
||||
|
||||
Hoek.assert(options && typeof options === 'object', 'Invalid options');
|
||||
Hoek.assert(options.then !== undefined || options.otherwise !== undefined, 'options must have at least one of "then" or "otherwise"');
|
||||
|
||||
const then = options.hasOwnProperty('then') ? this.concat(Cast.schema(this._currentJoi, options.then)) : undefined;
|
||||
const otherwise = options.hasOwnProperty('otherwise') ? this.concat(Cast.schema(this._currentJoi, options.otherwise)) : undefined;
|
||||
|
||||
Alternatives = Alternatives || require('../alternatives');
|
||||
|
||||
const alternativeOptions = { then, otherwise };
|
||||
if (Object.prototype.hasOwnProperty.call(options, 'is')) {
|
||||
alternativeOptions.is = options.is;
|
||||
}
|
||||
|
||||
const obj = Alternatives.when(condition, alternativeOptions);
|
||||
obj._flags.presence = 'ignore';
|
||||
obj._baseType = this;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
description(desc) {
|
||||
|
||||
Hoek.assert(desc && typeof desc === 'string', 'Description must be a non-empty string');
|
||||
|
||||
const obj = this.clone();
|
||||
obj._description = desc;
|
||||
return obj;
|
||||
}
|
||||
|
||||
notes(notes) {
|
||||
|
||||
Hoek.assert(notes && (typeof notes === 'string' || Array.isArray(notes)), 'Notes must be a non-empty string or array');
|
||||
|
||||
const obj = this.clone();
|
||||
obj._notes = obj._notes.concat(notes);
|
||||
return obj;
|
||||
}
|
||||
|
||||
tags(tags) {
|
||||
|
||||
Hoek.assert(tags && (typeof tags === 'string' || Array.isArray(tags)), 'Tags must be a non-empty string or array');
|
||||
|
||||
const obj = this.clone();
|
||||
obj._tags = obj._tags.concat(tags);
|
||||
return obj;
|
||||
}
|
||||
|
||||
meta(meta) {
|
||||
|
||||
Hoek.assert(meta !== undefined, 'Meta cannot be undefined');
|
||||
|
||||
const obj = this.clone();
|
||||
obj._meta = obj._meta.concat(meta);
|
||||
return obj;
|
||||
}
|
||||
|
||||
example(...examples) {
|
||||
|
||||
Hoek.assert(examples.length > 0, 'Missing examples');
|
||||
|
||||
const processed = [];
|
||||
for (let i = 0; i < examples.length; ++i) {
|
||||
const example = [].concat(examples[i]);
|
||||
Hoek.assert(example.length <= 2, `Bad example format at index ${i}`);
|
||||
|
||||
const value = example[0];
|
||||
let options = example[1];
|
||||
if (options !== undefined) {
|
||||
Hoek.assert(options && typeof options === 'object', `Options for example at index ${i} must be an object`);
|
||||
const unknownOptions = Object.keys(options).filter((option) => !['parent', 'context'].includes(option));
|
||||
Hoek.assert(unknownOptions.length === 0, `Unknown example options ${unknownOptions} at index ${i}`);
|
||||
}
|
||||
else {
|
||||
options = {};
|
||||
}
|
||||
|
||||
const localState = new State('', [], options.parent || null);
|
||||
const result = this._validate(value, localState, Settings.concat(internals.defaults, options.context ? { context: options.context } : null));
|
||||
Hoek.assert(!result.errors, `Bad example at index ${i}:`, result.errors && Errors.process(result.errors, value));
|
||||
|
||||
const ex = { value };
|
||||
if (Object.keys(options).length) {
|
||||
ex.options = options;
|
||||
}
|
||||
|
||||
processed.push(ex);
|
||||
}
|
||||
|
||||
const obj = this.clone();
|
||||
obj._examples = processed;
|
||||
return obj;
|
||||
}
|
||||
|
||||
unit(name) {
|
||||
|
||||
Hoek.assert(name && typeof name === 'string', 'Unit name must be a non-empty string');
|
||||
|
||||
const obj = this.clone();
|
||||
obj._unit = name;
|
||||
return obj;
|
||||
}
|
||||
|
||||
_prepareEmptyValue(value) {
|
||||
|
||||
if (typeof value === 'string' && this._flags.trim) {
|
||||
return value.trim();
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
_validate(value, state, options, reference) {
|
||||
|
||||
const originalValue = value;
|
||||
|
||||
// Setup state and settings
|
||||
|
||||
state = state || new State('', [], null, reference);
|
||||
|
||||
if (this._settings) {
|
||||
const isDefaultOptions = options === internals.defaults;
|
||||
if (isDefaultOptions && this._settings[Symbols.settingsCache]) {
|
||||
options = this._settings[Symbols.settingsCache];
|
||||
}
|
||||
else {
|
||||
options = Settings.concat(this._language ? Settings.concat({ language: this._language }, options) : options, this._settings);
|
||||
if (isDefaultOptions) {
|
||||
this._settings[Symbols.settingsCache] = options;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (this._language) {
|
||||
options = Settings.concat({ language: this._language }, options);
|
||||
}
|
||||
|
||||
let errors = [];
|
||||
|
||||
if (this._coerce) {
|
||||
const coerced = this._coerce(value, state, options);
|
||||
if (coerced.errors) {
|
||||
value = coerced.value;
|
||||
errors = errors.concat(coerced.errors);
|
||||
return this._finalizeValue(value, originalValue, errors, state, options); // Coerced error always aborts early
|
||||
}
|
||||
|
||||
value = coerced.value;
|
||||
}
|
||||
|
||||
if (this._flags.empty && !this._flags.empty._validate(this._prepareEmptyValue(value), null, internals.defaults).errors) {
|
||||
value = undefined;
|
||||
}
|
||||
|
||||
// Check presence requirements
|
||||
|
||||
const presence = this._flags.presence || options.presence;
|
||||
if (presence === 'optional') {
|
||||
if (value === undefined) {
|
||||
const isDeepDefault = this._flags.hasOwnProperty('default') && this._flags.default === undefined;
|
||||
if (isDeepDefault && this._type === 'object') {
|
||||
value = {};
|
||||
}
|
||||
else {
|
||||
return this._finalizeValue(value, originalValue, errors, state, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (presence === 'required' &&
|
||||
value === undefined) {
|
||||
|
||||
errors.push(this.createError('any.required', null, state, options));
|
||||
return this._finalizeValue(value, originalValue, errors, state, options);
|
||||
}
|
||||
else if (presence === 'forbidden') {
|
||||
if (value === undefined) {
|
||||
return this._finalizeValue(value, originalValue, errors, state, options);
|
||||
}
|
||||
|
||||
errors.push(this.createError('any.unknown', null, state, options));
|
||||
return this._finalizeValue(value, originalValue, errors, state, options);
|
||||
}
|
||||
|
||||
// Check allowed and denied values using the original value
|
||||
|
||||
let match = this._valids.get(value, state, options, this._flags.insensitive);
|
||||
if (match) {
|
||||
if (options.convert) {
|
||||
value = match.value;
|
||||
}
|
||||
|
||||
return this._finalizeValue(value, originalValue, errors, state, options);
|
||||
}
|
||||
|
||||
if (this._invalids.has(value, state, options, this._flags.insensitive)) {
|
||||
errors.push(this.createError(value === '' ? 'any.empty' : 'any.invalid', { value, invalids: this._invalids.values({ stripUndefined: true }) }, state, options));
|
||||
if (options.abortEarly) {
|
||||
|
||||
return this._finalizeValue(value, originalValue, errors, state, options);
|
||||
}
|
||||
}
|
||||
|
||||
// Convert value and validate type
|
||||
|
||||
if (this._base) {
|
||||
const base = this._base(value, state, options);
|
||||
if (base.errors) {
|
||||
value = base.value;
|
||||
errors = errors.concat(base.errors);
|
||||
return this._finalizeValue(value, originalValue, errors, state, options); // Base error always aborts early
|
||||
}
|
||||
|
||||
if (base.value !== value) {
|
||||
value = base.value;
|
||||
|
||||
// Check allowed and denied values using the converted value
|
||||
|
||||
match = this._valids.get(value, state, options, this._flags.insensitive);
|
||||
if (match) {
|
||||
value = match.value;
|
||||
return this._finalizeValue(value, originalValue, errors, state, options);
|
||||
}
|
||||
|
||||
if (this._invalids.has(value, state, options, this._flags.insensitive)) {
|
||||
errors.push(this.createError(value === '' ? 'any.empty' : 'any.invalid', { value, invalids: this._invalids.values({ stripUndefined: true }) }, state, options));
|
||||
if (options.abortEarly) {
|
||||
return this._finalizeValue(value, originalValue, errors, state, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Required values did not match
|
||||
|
||||
if (this._flags.allowOnly) {
|
||||
errors.push(this.createError('any.allowOnly', { value, valids: this._valids.values({ stripUndefined: true }) }, state, options));
|
||||
if (options.abortEarly) {
|
||||
return this._finalizeValue(value, originalValue, errors, state, options);
|
||||
}
|
||||
}
|
||||
|
||||
// Validate tests
|
||||
|
||||
for (let i = 0; i < this._tests.length; ++i) {
|
||||
const test = this._tests[i];
|
||||
const ret = test.func.call(this, value, state, options);
|
||||
if (ret instanceof Errors.Err) {
|
||||
errors.push(ret);
|
||||
if (options.abortEarly) {
|
||||
return this._finalizeValue(value, originalValue, errors, state, options);
|
||||
}
|
||||
}
|
||||
else {
|
||||
value = ret;
|
||||
}
|
||||
}
|
||||
|
||||
return this._finalizeValue(value, originalValue, errors, state, options);
|
||||
}
|
||||
|
||||
_finalizeValue(value, originalValue, errors, state, options) {
|
||||
|
||||
let finalValue;
|
||||
|
||||
if (value !== undefined) {
|
||||
finalValue = this._flags.raw ? originalValue : value;
|
||||
}
|
||||
else if (options.noDefaults) {
|
||||
finalValue = value;
|
||||
}
|
||||
else if (Ref.isRef(this._flags.default)) {
|
||||
finalValue = this._flags.default(state.parent, options);
|
||||
}
|
||||
else if (typeof this._flags.default === 'function' &&
|
||||
!(this._flags.func && !this._flags.default.description)) {
|
||||
|
||||
let args;
|
||||
|
||||
if (state.parent !== null &&
|
||||
this._flags.default.length > 0) {
|
||||
|
||||
args = [Hoek.clone(state.parent), options];
|
||||
}
|
||||
|
||||
const defaultValue = internals._try(this._flags.default, args);
|
||||
finalValue = defaultValue.value;
|
||||
if (defaultValue.error) {
|
||||
errors.push(this.createError('any.default', { error: defaultValue.error }, state, options));
|
||||
}
|
||||
}
|
||||
else {
|
||||
finalValue = Hoek.clone(this._flags.default);
|
||||
}
|
||||
|
||||
if (errors.length &&
|
||||
typeof this._flags.error === 'function' &&
|
||||
(
|
||||
!this._flags.selfError ||
|
||||
errors.some((e) => state.path.length === e.path.length)
|
||||
)
|
||||
) {
|
||||
const change = this._flags.error.call(this, errors);
|
||||
|
||||
if (typeof change === 'string') {
|
||||
errors = [this.createOverrideError('override', { reason: errors }, state, options, change)];
|
||||
}
|
||||
else {
|
||||
errors = [].concat(change)
|
||||
.map((err) => {
|
||||
|
||||
return err instanceof Error ?
|
||||
err :
|
||||
this.createOverrideError(err.type || 'override', err.context, state, options, err.message, err.template);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
value: this._flags.strip ? undefined : finalValue,
|
||||
finalValue,
|
||||
errors: errors.length ? errors : null
|
||||
};
|
||||
}
|
||||
|
||||
_validateWithOptions(value, options, callback) {
|
||||
|
||||
if (options) {
|
||||
this.checkOptions(options);
|
||||
}
|
||||
|
||||
const settings = Settings.concat(internals.defaults, options);
|
||||
const result = this._validate(value, null, settings);
|
||||
const errors = Errors.process(result.errors, value);
|
||||
|
||||
if (callback) {
|
||||
return callback(errors, result.value);
|
||||
}
|
||||
|
||||
return {
|
||||
error: errors,
|
||||
value: result.value,
|
||||
then(resolve, reject) {
|
||||
|
||||
if (errors) {
|
||||
return Promise.reject(errors).catch(reject);
|
||||
}
|
||||
|
||||
return Promise.resolve(result.value).then(resolve);
|
||||
},
|
||||
catch(reject) {
|
||||
|
||||
if (errors) {
|
||||
return Promise.reject(errors).catch(reject);
|
||||
}
|
||||
|
||||
return Promise.resolve(result.value);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
validate(value, options, callback) {
|
||||
|
||||
if (typeof options === 'function') {
|
||||
return this._validateWithOptions(value, null, options);
|
||||
}
|
||||
|
||||
return this._validateWithOptions(value, options, callback);
|
||||
}
|
||||
|
||||
describe() {
|
||||
|
||||
const description = {
|
||||
type: this._type
|
||||
};
|
||||
|
||||
const flags = Object.keys(this._flags);
|
||||
if (flags.length) {
|
||||
if (['empty', 'default', 'lazy', 'label'].some((flag) => this._flags.hasOwnProperty(flag))) {
|
||||
description.flags = {};
|
||||
for (let i = 0; i < flags.length; ++i) {
|
||||
const flag = flags[i];
|
||||
if (flag === 'empty') {
|
||||
description.flags[flag] = this._flags[flag].describe();
|
||||
}
|
||||
else if (flag === 'default') {
|
||||
if (Ref.isRef(this._flags[flag])) {
|
||||
description.flags[flag] = this._flags[flag].toString();
|
||||
}
|
||||
else if (typeof this._flags[flag] === 'function') {
|
||||
description.flags[flag] = {
|
||||
description: this._flags[flag].description,
|
||||
function : this._flags[flag]
|
||||
};
|
||||
}
|
||||
else {
|
||||
description.flags[flag] = this._flags[flag];
|
||||
}
|
||||
}
|
||||
else if (flag === 'lazy' || flag === 'label') {
|
||||
// We don't want it in the description
|
||||
}
|
||||
else {
|
||||
description.flags[flag] = this._flags[flag];
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
description.flags = this._flags;
|
||||
}
|
||||
}
|
||||
|
||||
if (this._settings) {
|
||||
description.options = Hoek.clone(this._settings);
|
||||
}
|
||||
|
||||
if (this._baseType) {
|
||||
description.base = this._baseType.describe();
|
||||
}
|
||||
|
||||
if (this._description) {
|
||||
description.description = this._description;
|
||||
}
|
||||
|
||||
if (this._notes.length) {
|
||||
description.notes = this._notes;
|
||||
}
|
||||
|
||||
if (this._tags.length) {
|
||||
description.tags = this._tags;
|
||||
}
|
||||
|
||||
if (this._meta.length) {
|
||||
description.meta = this._meta;
|
||||
}
|
||||
|
||||
if (this._examples.length) {
|
||||
description.examples = this._examples;
|
||||
}
|
||||
|
||||
if (this._unit) {
|
||||
description.unit = this._unit;
|
||||
}
|
||||
|
||||
const valids = this._valids.values();
|
||||
if (valids.length) {
|
||||
description.valids = valids.map((v) => {
|
||||
|
||||
return Ref.isRef(v) ? v.toString() : v;
|
||||
});
|
||||
}
|
||||
|
||||
const invalids = this._invalids.values();
|
||||
if (invalids.length) {
|
||||
description.invalids = invalids.map((v) => {
|
||||
|
||||
return Ref.isRef(v) ? v.toString() : v;
|
||||
});
|
||||
}
|
||||
|
||||
description.rules = [];
|
||||
|
||||
for (let i = 0; i < this._tests.length; ++i) {
|
||||
const validator = this._tests[i];
|
||||
const item = { name: validator.name };
|
||||
|
||||
if (validator.arg !== void 0) {
|
||||
item.arg = Ref.isRef(validator.arg) ? validator.arg.toString() : validator.arg;
|
||||
}
|
||||
|
||||
const options = validator.options;
|
||||
if (options) {
|
||||
if (options.hasRef) {
|
||||
item.arg = {};
|
||||
const keys = Object.keys(validator.arg);
|
||||
for (let j = 0; j < keys.length; ++j) {
|
||||
const key = keys[j];
|
||||
const value = validator.arg[key];
|
||||
item.arg[key] = Ref.isRef(value) ? value.toString() : value;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof options.description === 'string') {
|
||||
item.description = options.description;
|
||||
}
|
||||
else if (typeof options.description === 'function') {
|
||||
item.description = options.description(item.arg);
|
||||
}
|
||||
}
|
||||
|
||||
description.rules.push(item);
|
||||
}
|
||||
|
||||
if (!description.rules.length) {
|
||||
delete description.rules;
|
||||
}
|
||||
|
||||
const label = this._getLabel();
|
||||
if (label) {
|
||||
description.label = label;
|
||||
}
|
||||
|
||||
return description;
|
||||
}
|
||||
|
||||
label(name) {
|
||||
|
||||
Hoek.assert(name && typeof name === 'string', 'Label name must be a non-empty string');
|
||||
|
||||
const obj = this.clone();
|
||||
obj._flags.label = name;
|
||||
return obj;
|
||||
}
|
||||
|
||||
_getLabel(def) {
|
||||
|
||||
return this._flags.label || def;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
internals.Any.prototype.isImmutable = true; // Prevents Hoek from deep cloning schema objects
|
||||
|
||||
// Aliases
|
||||
|
||||
internals.Any.prototype.only = internals.Any.prototype.equal = internals.Any.prototype.valid;
|
||||
internals.Any.prototype.disallow = internals.Any.prototype.not = internals.Any.prototype.invalid;
|
||||
internals.Any.prototype.exist = internals.Any.prototype.required;
|
||||
|
||||
|
||||
internals.Any.prototype[internals.symbol] = {
|
||||
version: Pkg.version,
|
||||
compile: Cast.schema,
|
||||
root: '_currentJoi'
|
||||
};
|
||||
|
||||
|
||||
internals._try = function (fn, args = []) {
|
||||
|
||||
let err;
|
||||
let result;
|
||||
|
||||
try {
|
||||
result = fn(...args);
|
||||
}
|
||||
catch (e) {
|
||||
err = e;
|
||||
}
|
||||
|
||||
return {
|
||||
value: result,
|
||||
error: err
|
||||
};
|
||||
};
|
32
web/node_modules/@hapi/joi/lib/types/any/settings.js
generated
vendored
Executable file
32
web/node_modules/@hapi/joi/lib/types/any/settings.js
generated
vendored
Executable file
|
@ -0,0 +1,32 @@
|
|||
'use strict';
|
||||
|
||||
const Hoek = require('@hapi/hoek');
|
||||
|
||||
const Symbols = require('../symbols');
|
||||
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
exports.concat = function (target, source) {
|
||||
|
||||
if (!source) {
|
||||
return target;
|
||||
}
|
||||
|
||||
const obj = Object.assign({}, target);
|
||||
|
||||
const language = source.language;
|
||||
|
||||
Object.assign(obj, source);
|
||||
|
||||
if (language && target && target.language) {
|
||||
obj.language = Hoek.applyToDefaults(target.language, language);
|
||||
}
|
||||
|
||||
if (obj[Symbols.settingsCache]) {
|
||||
delete obj[Symbols.settingsCache];
|
||||
}
|
||||
|
||||
return obj;
|
||||
};
|
699
web/node_modules/@hapi/joi/lib/types/array/index.js
generated
vendored
Executable file
699
web/node_modules/@hapi/joi/lib/types/array/index.js
generated
vendored
Executable file
|
@ -0,0 +1,699 @@
|
|||
'use strict';
|
||||
|
||||
const Bourne = require('@hapi/bourne');
|
||||
const Hoek = require('@hapi/hoek');
|
||||
|
||||
const Any = require('../any');
|
||||
const Cast = require('../../cast');
|
||||
const Ref = require('../../ref');
|
||||
const State = require('../state');
|
||||
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
internals.fastSplice = function (arr, i) {
|
||||
|
||||
let pos = i;
|
||||
while (pos < arr.length) {
|
||||
arr[pos++] = arr[pos];
|
||||
}
|
||||
|
||||
--arr.length;
|
||||
};
|
||||
|
||||
|
||||
internals.Array = class extends Any {
|
||||
|
||||
constructor() {
|
||||
|
||||
super();
|
||||
this._type = 'array';
|
||||
this._inner.items = [];
|
||||
this._inner.ordereds = [];
|
||||
this._inner.inclusions = [];
|
||||
this._inner.exclusions = [];
|
||||
this._inner.requireds = [];
|
||||
this._flags.sparse = false;
|
||||
}
|
||||
|
||||
_base(value, state, options) {
|
||||
|
||||
const result = {
|
||||
value
|
||||
};
|
||||
|
||||
if (typeof value === 'string' &&
|
||||
options.convert) {
|
||||
|
||||
if (value.length > 1 &&
|
||||
(value[0] === '[' || /^\s*\[/.test(value))) {
|
||||
|
||||
try {
|
||||
result.value = Bourne.parse(value);
|
||||
}
|
||||
catch (e) { }
|
||||
}
|
||||
}
|
||||
|
||||
let isArray = Array.isArray(result.value);
|
||||
const wasArray = isArray;
|
||||
if (options.convert && this._flags.single && !isArray) {
|
||||
result.value = [result.value];
|
||||
isArray = true;
|
||||
}
|
||||
|
||||
if (!isArray) {
|
||||
result.errors = this.createError('array.base', null, state, options);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (this._inner.inclusions.length ||
|
||||
this._inner.exclusions.length ||
|
||||
this._inner.requireds.length ||
|
||||
this._inner.ordereds.length ||
|
||||
!this._flags.sparse) {
|
||||
|
||||
// Clone the array so that we don't modify the original
|
||||
if (wasArray) {
|
||||
result.value = result.value.slice(0);
|
||||
}
|
||||
|
||||
result.errors = this._checkItems(result.value, wasArray, state, options);
|
||||
|
||||
if (result.errors && wasArray && options.convert && this._flags.single) {
|
||||
|
||||
// Attempt a 2nd pass by putting the array inside one.
|
||||
const previousErrors = result.errors;
|
||||
|
||||
result.value = [result.value];
|
||||
result.errors = this._checkItems(result.value, wasArray, state, options);
|
||||
|
||||
if (result.errors) {
|
||||
|
||||
// Restore previous errors and value since this didn't validate either.
|
||||
result.errors = previousErrors;
|
||||
result.value = result.value[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
_checkItems(items, wasArray, state, options) {
|
||||
|
||||
const errors = [];
|
||||
let errored;
|
||||
|
||||
const requireds = this._inner.requireds.slice();
|
||||
const ordereds = this._inner.ordereds.slice();
|
||||
const inclusions = [...this._inner.inclusions, ...requireds];
|
||||
|
||||
let il = items.length;
|
||||
for (let i = 0; i < il; ++i) {
|
||||
errored = false;
|
||||
const item = items[i];
|
||||
let isValid = false;
|
||||
const key = wasArray ? i : state.key;
|
||||
const path = wasArray ? [...state.path, i] : state.path;
|
||||
const localState = new State(key, path, state.parent, state.reference);
|
||||
let res;
|
||||
|
||||
// Sparse
|
||||
|
||||
if (!this._flags.sparse && item === undefined) {
|
||||
errors.push(this.createError('array.sparse', null, { key: state.key, path: localState.path, pos: i }, options));
|
||||
|
||||
if (options.abortEarly) {
|
||||
return errors;
|
||||
}
|
||||
|
||||
ordereds.shift();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Exclusions
|
||||
|
||||
for (let j = 0; j < this._inner.exclusions.length; ++j) {
|
||||
res = this._inner.exclusions[j]._validate(item, localState, {}); // Not passing options to use defaults
|
||||
|
||||
if (!res.errors) {
|
||||
errors.push(this.createError(wasArray ? 'array.excludes' : 'array.excludesSingle', { pos: i, value: item }, { key: state.key, path: localState.path }, options));
|
||||
errored = true;
|
||||
|
||||
if (options.abortEarly) {
|
||||
return errors;
|
||||
}
|
||||
|
||||
ordereds.shift();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (errored) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Ordered
|
||||
if (this._inner.ordereds.length) {
|
||||
if (ordereds.length > 0) {
|
||||
const ordered = ordereds.shift();
|
||||
res = ordered._validate(item, localState, options);
|
||||
if (!res.errors) {
|
||||
if (ordered._flags.strip) {
|
||||
internals.fastSplice(items, i);
|
||||
--i;
|
||||
--il;
|
||||
}
|
||||
else if (!this._flags.sparse && res.value === undefined) {
|
||||
errors.push(this.createError('array.sparse', null, { key: state.key, path: localState.path, pos: i }, options));
|
||||
|
||||
if (options.abortEarly) {
|
||||
return errors;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
items[i] = res.value;
|
||||
}
|
||||
}
|
||||
else {
|
||||
errors.push(this.createError('array.ordered', { pos: i, reason: res.errors, value: item }, { key: state.key, path: localState.path }, options));
|
||||
if (options.abortEarly) {
|
||||
return errors;
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
else if (!this._inner.items.length) {
|
||||
errors.push(this.createError('array.orderedLength', { pos: i, limit: this._inner.ordereds.length }, { key: state.key, path: localState.path }, options));
|
||||
if (options.abortEarly) {
|
||||
return errors;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Requireds
|
||||
|
||||
const requiredChecks = [];
|
||||
let jl = requireds.length;
|
||||
for (let j = 0; j < jl; ++j) {
|
||||
res = requiredChecks[j] = requireds[j]._validate(item, localState, options);
|
||||
if (!res.errors) {
|
||||
items[i] = res.value;
|
||||
isValid = true;
|
||||
internals.fastSplice(requireds, j);
|
||||
--j;
|
||||
--jl;
|
||||
|
||||
if (!this._flags.sparse && res.value === undefined) {
|
||||
errors.push(this.createError('array.sparse', null, { key: state.key, path: localState.path, pos: i }, options));
|
||||
|
||||
if (options.abortEarly) {
|
||||
return errors;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isValid) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Inclusions
|
||||
|
||||
const stripUnknown = options.stripUnknown && !!options.stripUnknown.arrays || false;
|
||||
|
||||
jl = inclusions.length;
|
||||
for (let j = 0; j < jl; ++j) {
|
||||
const inclusion = inclusions[j];
|
||||
|
||||
// Avoid re-running requireds that already didn't match in the previous loop
|
||||
const previousCheck = requireds.indexOf(inclusion);
|
||||
if (previousCheck !== -1) {
|
||||
res = requiredChecks[previousCheck];
|
||||
}
|
||||
else {
|
||||
res = inclusion._validate(item, localState, options);
|
||||
|
||||
if (!res.errors) {
|
||||
if (inclusion._flags.strip) {
|
||||
internals.fastSplice(items, i);
|
||||
--i;
|
||||
--il;
|
||||
}
|
||||
else if (!this._flags.sparse && res.value === undefined) {
|
||||
errors.push(this.createError('array.sparse', null, { key: state.key, path: localState.path, pos: i }, options));
|
||||
errored = true;
|
||||
}
|
||||
else {
|
||||
items[i] = res.value;
|
||||
}
|
||||
|
||||
isValid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the actual error if only one inclusion defined
|
||||
if (jl === 1) {
|
||||
if (stripUnknown) {
|
||||
internals.fastSplice(items, i);
|
||||
--i;
|
||||
--il;
|
||||
isValid = true;
|
||||
break;
|
||||
}
|
||||
|
||||
errors.push(this.createError(wasArray ? 'array.includesOne' : 'array.includesOneSingle', { pos: i, reason: res.errors, value: item }, { key: state.key, path: localState.path }, options));
|
||||
errored = true;
|
||||
|
||||
if (options.abortEarly) {
|
||||
return errors;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (errored) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (this._inner.inclusions.length && !isValid) {
|
||||
if (stripUnknown) {
|
||||
internals.fastSplice(items, i);
|
||||
--i;
|
||||
--il;
|
||||
continue;
|
||||
}
|
||||
|
||||
errors.push(this.createError(wasArray ? 'array.includes' : 'array.includesSingle', { pos: i, value: item }, { key: state.key, path: localState.path }, options));
|
||||
|
||||
if (options.abortEarly) {
|
||||
return errors;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (requireds.length) {
|
||||
this._fillMissedErrors(errors, requireds, state, options);
|
||||
}
|
||||
|
||||
if (ordereds.length) {
|
||||
this._fillOrderedErrors(errors, ordereds, state, options);
|
||||
}
|
||||
|
||||
return errors.length ? errors : null;
|
||||
}
|
||||
|
||||
describe() {
|
||||
|
||||
const description = super.describe();
|
||||
|
||||
if (this._inner.ordereds.length) {
|
||||
description.orderedItems = [];
|
||||
|
||||
for (let i = 0; i < this._inner.ordereds.length; ++i) {
|
||||
description.orderedItems.push(this._inner.ordereds[i].describe());
|
||||
}
|
||||
}
|
||||
|
||||
if (this._inner.items.length) {
|
||||
description.items = [];
|
||||
|
||||
for (let i = 0; i < this._inner.items.length; ++i) {
|
||||
description.items.push(this._inner.items[i].describe());
|
||||
}
|
||||
}
|
||||
|
||||
if (description.rules) {
|
||||
for (let i = 0; i < description.rules.length; ++i) {
|
||||
const rule = description.rules[i];
|
||||
if (rule.name === 'has') {
|
||||
rule.arg = rule.arg.describe();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return description;
|
||||
}
|
||||
|
||||
items(...schemas) {
|
||||
|
||||
const obj = this.clone();
|
||||
|
||||
Hoek.flatten(schemas).forEach((type, index) => {
|
||||
|
||||
try {
|
||||
type = Cast.schema(this._currentJoi, type);
|
||||
}
|
||||
catch (castErr) {
|
||||
if (castErr.hasOwnProperty('path')) {
|
||||
castErr.path = index + '.' + castErr.path;
|
||||
}
|
||||
else {
|
||||
castErr.path = index;
|
||||
}
|
||||
|
||||
castErr.message = `${castErr.message}(${castErr.path})`;
|
||||
throw castErr;
|
||||
}
|
||||
|
||||
obj._inner.items.push(type);
|
||||
|
||||
if (type._flags.presence === 'required') {
|
||||
obj._inner.requireds.push(type);
|
||||
}
|
||||
else if (type._flags.presence === 'forbidden') {
|
||||
obj._inner.exclusions.push(type.optional());
|
||||
}
|
||||
else {
|
||||
obj._inner.inclusions.push(type);
|
||||
}
|
||||
});
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
ordered(...schemas) {
|
||||
|
||||
const obj = this.clone();
|
||||
|
||||
Hoek.flatten(schemas).forEach((type, index) => {
|
||||
|
||||
try {
|
||||
type = Cast.schema(this._currentJoi, type);
|
||||
}
|
||||
catch (castErr) {
|
||||
if (castErr.hasOwnProperty('path')) {
|
||||
castErr.path = index + '.' + castErr.path;
|
||||
}
|
||||
else {
|
||||
castErr.path = index;
|
||||
}
|
||||
|
||||
castErr.message = `${castErr.message}(${castErr.path})`;
|
||||
throw castErr;
|
||||
}
|
||||
|
||||
obj._inner.ordereds.push(type);
|
||||
});
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
min(limit) {
|
||||
|
||||
const isRef = Ref.isRef(limit);
|
||||
|
||||
Hoek.assert((Number.isSafeInteger(limit) && limit >= 0) || isRef, 'limit must be a positive integer or reference');
|
||||
|
||||
return this._testUnique('min', limit, function (value, state, options) {
|
||||
|
||||
let compareTo;
|
||||
if (isRef) {
|
||||
compareTo = limit(state.reference || state.parent, options);
|
||||
|
||||
if (!(Number.isSafeInteger(compareTo) && compareTo >= 0)) {
|
||||
return this.createError('array.ref', { ref: limit, value: compareTo }, state, options);
|
||||
}
|
||||
}
|
||||
else {
|
||||
compareTo = limit;
|
||||
}
|
||||
|
||||
if (value.length >= compareTo) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return this.createError('array.min', { limit, value }, state, options);
|
||||
});
|
||||
}
|
||||
|
||||
max(limit) {
|
||||
|
||||
const isRef = Ref.isRef(limit);
|
||||
|
||||
Hoek.assert((Number.isSafeInteger(limit) && limit >= 0) || isRef, 'limit must be a positive integer or reference');
|
||||
|
||||
return this._testUnique('max', limit, function (value, state, options) {
|
||||
|
||||
let compareTo;
|
||||
if (isRef) {
|
||||
compareTo = limit(state.reference || state.parent, options);
|
||||
|
||||
if (!(Number.isSafeInteger(compareTo) && compareTo >= 0)) {
|
||||
return this.createError('array.ref', { ref: limit.key }, state, options);
|
||||
}
|
||||
}
|
||||
else {
|
||||
compareTo = limit;
|
||||
}
|
||||
|
||||
if (value.length <= compareTo) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return this.createError('array.max', { limit, value }, state, options);
|
||||
});
|
||||
}
|
||||
|
||||
length(limit) {
|
||||
|
||||
const isRef = Ref.isRef(limit);
|
||||
|
||||
Hoek.assert((Number.isSafeInteger(limit) && limit >= 0) || isRef, 'limit must be a positive integer or reference');
|
||||
|
||||
return this._testUnique('length', limit, function (value, state, options) {
|
||||
|
||||
let compareTo;
|
||||
if (isRef) {
|
||||
compareTo = limit(state.reference || state.parent, options);
|
||||
|
||||
if (!(Number.isSafeInteger(compareTo) && compareTo >= 0)) {
|
||||
return this.createError('array.ref', { ref: limit.key }, state, options);
|
||||
}
|
||||
}
|
||||
else {
|
||||
compareTo = limit;
|
||||
}
|
||||
|
||||
if (value.length === compareTo) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return this.createError('array.length', { limit, value }, state, options);
|
||||
});
|
||||
}
|
||||
|
||||
has(schema) {
|
||||
|
||||
try {
|
||||
schema = Cast.schema(this._currentJoi, schema);
|
||||
}
|
||||
catch (castErr) {
|
||||
if (castErr.hasOwnProperty('path')) {
|
||||
castErr.message = `${castErr.message}(${castErr.path})`;
|
||||
}
|
||||
|
||||
throw castErr;
|
||||
}
|
||||
|
||||
return this._test('has', schema, function (value, state, options) {
|
||||
|
||||
const isValid = value.some((item, idx) => {
|
||||
|
||||
const localState = new State(idx, [...state.path, idx], state.key, state.reference);
|
||||
return !schema._validate(item, localState, options).errors;
|
||||
});
|
||||
|
||||
if (isValid) {
|
||||
return value;
|
||||
}
|
||||
|
||||
const patternLabel = schema._getLabel();
|
||||
if (patternLabel) {
|
||||
return this.createError('array.hasKnown', { patternLabel }, state, options);
|
||||
}
|
||||
|
||||
return this.createError('array.hasUnknown', null, state, options);
|
||||
});
|
||||
}
|
||||
|
||||
unique(comparator, configs) {
|
||||
|
||||
Hoek.assert(comparator === undefined ||
|
||||
typeof comparator === 'function' ||
|
||||
typeof comparator === 'string', 'comparator must be a function or a string');
|
||||
|
||||
Hoek.assert(configs === undefined ||
|
||||
typeof configs === 'object', 'configs must be an object');
|
||||
|
||||
const settings = {
|
||||
ignoreUndefined: (configs && configs.ignoreUndefined) || false
|
||||
};
|
||||
|
||||
|
||||
if (typeof comparator === 'string') {
|
||||
settings.path = comparator;
|
||||
}
|
||||
else if (typeof comparator === 'function') {
|
||||
settings.comparator = comparator;
|
||||
}
|
||||
|
||||
return this._test('unique', settings, function (value, state, options) {
|
||||
|
||||
const found = {
|
||||
string: Object.create(null),
|
||||
number: Object.create(null),
|
||||
undefined: Object.create(null),
|
||||
boolean: Object.create(null),
|
||||
object: new Map(),
|
||||
function: new Map(),
|
||||
custom: new Map()
|
||||
};
|
||||
|
||||
const compare = settings.comparator || Hoek.deepEqual;
|
||||
const ignoreUndefined = settings.ignoreUndefined;
|
||||
|
||||
for (let i = 0; i < value.length; ++i) {
|
||||
const item = settings.path ? Hoek.reach(value[i], settings.path) : value[i];
|
||||
const records = settings.comparator ? found.custom : found[typeof item];
|
||||
|
||||
// All available types are supported, so it's not possible to reach 100% coverage without ignoring this line.
|
||||
// I still want to keep the test for future js versions with new types (eg. Symbol).
|
||||
if (/* $lab:coverage:off$ */ records /* $lab:coverage:on$ */) {
|
||||
if (records instanceof Map) {
|
||||
const entries = records.entries();
|
||||
let current;
|
||||
while (!(current = entries.next()).done) {
|
||||
if (compare(current.value[0], item)) {
|
||||
const localState = new State(state.key, [...state.path, i], state.parent, state.reference);
|
||||
const context = {
|
||||
pos: i,
|
||||
value: value[i],
|
||||
dupePos: current.value[1],
|
||||
dupeValue: value[current.value[1]]
|
||||
};
|
||||
|
||||
if (settings.path) {
|
||||
context.path = settings.path;
|
||||
}
|
||||
|
||||
return this.createError('array.unique', context, localState, options);
|
||||
}
|
||||
}
|
||||
|
||||
records.set(item, i);
|
||||
}
|
||||
else {
|
||||
if ((!ignoreUndefined || item !== undefined) && records[item] !== undefined) {
|
||||
const localState = new State(state.key, [...state.path, i], state.parent, state.reference);
|
||||
|
||||
const context = {
|
||||
pos: i,
|
||||
value: value[i],
|
||||
dupePos: records[item],
|
||||
dupeValue: value[records[item]]
|
||||
};
|
||||
|
||||
if (settings.path) {
|
||||
context.path = settings.path;
|
||||
}
|
||||
|
||||
return this.createError('array.unique', context, localState, options);
|
||||
}
|
||||
|
||||
records[item] = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
});
|
||||
}
|
||||
|
||||
sparse(enabled) {
|
||||
|
||||
const value = enabled === undefined ? true : !!enabled;
|
||||
|
||||
if (this._flags.sparse === value) {
|
||||
return this;
|
||||
}
|
||||
|
||||
const obj = this.clone();
|
||||
obj._flags.sparse = value;
|
||||
return obj;
|
||||
}
|
||||
|
||||
single(enabled) {
|
||||
|
||||
const value = enabled === undefined ? true : !!enabled;
|
||||
|
||||
if (this._flags.single === value) {
|
||||
return this;
|
||||
}
|
||||
|
||||
const obj = this.clone();
|
||||
obj._flags.single = value;
|
||||
return obj;
|
||||
}
|
||||
|
||||
_fillMissedErrors(errors, requireds, state, options) {
|
||||
|
||||
const knownMisses = [];
|
||||
let unknownMisses = 0;
|
||||
for (let i = 0; i < requireds.length; ++i) {
|
||||
const label = requireds[i]._getLabel();
|
||||
if (label) {
|
||||
knownMisses.push(label);
|
||||
}
|
||||
else {
|
||||
++unknownMisses;
|
||||
}
|
||||
}
|
||||
|
||||
if (knownMisses.length) {
|
||||
if (unknownMisses) {
|
||||
errors.push(this.createError('array.includesRequiredBoth', { knownMisses, unknownMisses }, { key: state.key, path: state.path }, options));
|
||||
}
|
||||
else {
|
||||
errors.push(this.createError('array.includesRequiredKnowns', { knownMisses }, { key: state.key, path: state.path }, options));
|
||||
}
|
||||
}
|
||||
else {
|
||||
errors.push(this.createError('array.includesRequiredUnknowns', { unknownMisses }, { key: state.key, path: state.path }, options));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_fillOrderedErrors(errors, ordereds, state, options) {
|
||||
|
||||
const requiredOrdereds = [];
|
||||
|
||||
for (let i = 0; i < ordereds.length; ++i) {
|
||||
const presence = Hoek.reach(ordereds[i], '_flags.presence');
|
||||
if (presence === 'required') {
|
||||
requiredOrdereds.push(ordereds[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (requiredOrdereds.length) {
|
||||
this._fillMissedErrors(errors, requiredOrdereds, state, options);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
module.exports = new internals.Array();
|
96
web/node_modules/@hapi/joi/lib/types/binary/index.js
generated
vendored
Executable file
96
web/node_modules/@hapi/joi/lib/types/binary/index.js
generated
vendored
Executable file
|
@ -0,0 +1,96 @@
|
|||
'use strict';
|
||||
|
||||
const Hoek = require('@hapi/hoek');
|
||||
|
||||
const Any = require('../any');
|
||||
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
internals.Binary = class extends Any {
|
||||
|
||||
constructor() {
|
||||
|
||||
super();
|
||||
this._type = 'binary';
|
||||
}
|
||||
|
||||
_base(value, state, options) {
|
||||
|
||||
const result = {
|
||||
value
|
||||
};
|
||||
|
||||
if (typeof value === 'string' &&
|
||||
options.convert) {
|
||||
|
||||
try {
|
||||
result.value = Buffer.from(value, this._flags.encoding);
|
||||
}
|
||||
catch (e) { }
|
||||
}
|
||||
|
||||
result.errors = Buffer.isBuffer(result.value) ? null : this.createError('binary.base', null, state, options);
|
||||
return result;
|
||||
}
|
||||
|
||||
encoding(encoding) {
|
||||
|
||||
Hoek.assert(Buffer.isEncoding(encoding), 'Invalid encoding:', encoding);
|
||||
|
||||
if (this._flags.encoding === encoding) {
|
||||
return this;
|
||||
}
|
||||
|
||||
const obj = this.clone();
|
||||
obj._flags.encoding = encoding;
|
||||
return obj;
|
||||
}
|
||||
|
||||
min(limit) {
|
||||
|
||||
Hoek.assert(Number.isSafeInteger(limit) && limit >= 0, 'limit must be a positive integer');
|
||||
|
||||
return this._test('min', limit, function (value, state, options) {
|
||||
|
||||
if (value.length >= limit) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return this.createError('binary.min', { limit, value }, state, options);
|
||||
});
|
||||
}
|
||||
|
||||
max(limit) {
|
||||
|
||||
Hoek.assert(Number.isSafeInteger(limit) && limit >= 0, 'limit must be a positive integer');
|
||||
|
||||
return this._test('max', limit, function (value, state, options) {
|
||||
|
||||
if (value.length <= limit) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return this.createError('binary.max', { limit, value }, state, options);
|
||||
});
|
||||
}
|
||||
|
||||
length(limit) {
|
||||
|
||||
Hoek.assert(Number.isSafeInteger(limit) && limit >= 0, 'limit must be a positive integer');
|
||||
|
||||
return this._test('length', limit, function (value, state, options) {
|
||||
|
||||
if (value.length === limit) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return this.createError('binary.length', { limit, value }, state, options);
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
module.exports = new internals.Binary();
|
97
web/node_modules/@hapi/joi/lib/types/boolean/index.js
generated
vendored
Executable file
97
web/node_modules/@hapi/joi/lib/types/boolean/index.js
generated
vendored
Executable file
|
@ -0,0 +1,97 @@
|
|||
'use strict';
|
||||
|
||||
const Hoek = require('@hapi/hoek');
|
||||
|
||||
const Any = require('../any');
|
||||
|
||||
|
||||
const internals = {
|
||||
Set: require('../../set')
|
||||
};
|
||||
|
||||
|
||||
internals.Boolean = class extends Any {
|
||||
constructor() {
|
||||
|
||||
super();
|
||||
this._type = 'boolean';
|
||||
this._flags.insensitive = true;
|
||||
this._inner.truthySet = new internals.Set();
|
||||
this._inner.falsySet = new internals.Set();
|
||||
}
|
||||
|
||||
_base(value, state, options) {
|
||||
|
||||
const result = {
|
||||
value
|
||||
};
|
||||
|
||||
if (typeof value === 'string' &&
|
||||
options.convert) {
|
||||
|
||||
const normalized = this._flags.insensitive ? value.toLowerCase() : value;
|
||||
result.value = (normalized === 'true' ? true
|
||||
: (normalized === 'false' ? false : value));
|
||||
}
|
||||
|
||||
if (typeof result.value !== 'boolean') {
|
||||
result.value = (this._inner.truthySet.has(value, null, null, this._flags.insensitive) ? true
|
||||
: (this._inner.falsySet.has(value, null, null, this._flags.insensitive) ? false : value));
|
||||
}
|
||||
|
||||
result.errors = (typeof result.value === 'boolean') ? null : this.createError('boolean.base', { value }, state, options);
|
||||
return result;
|
||||
}
|
||||
|
||||
truthy(...values) {
|
||||
|
||||
const obj = this.clone();
|
||||
values = Hoek.flatten(values);
|
||||
for (let i = 0; i < values.length; ++i) {
|
||||
const value = values[i];
|
||||
|
||||
Hoek.assert(value !== undefined, 'Cannot call truthy with undefined');
|
||||
obj._inner.truthySet.add(value);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
falsy(...values) {
|
||||
|
||||
const obj = this.clone();
|
||||
values = Hoek.flatten(values);
|
||||
for (let i = 0; i < values.length; ++i) {
|
||||
const value = values[i];
|
||||
|
||||
Hoek.assert(value !== undefined, 'Cannot call falsy with undefined');
|
||||
obj._inner.falsySet.add(value);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
insensitive(enabled) {
|
||||
|
||||
const insensitive = enabled === undefined ? true : !!enabled;
|
||||
|
||||
if (this._flags.insensitive === insensitive) {
|
||||
return this;
|
||||
}
|
||||
|
||||
const obj = this.clone();
|
||||
obj._flags.insensitive = insensitive;
|
||||
return obj;
|
||||
}
|
||||
|
||||
describe() {
|
||||
|
||||
const description = super.describe();
|
||||
description.truthy = [true, ...this._inner.truthySet.values()];
|
||||
description.falsy = [false, ...this._inner.falsySet.values()];
|
||||
return description;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
module.exports = new internals.Boolean();
|
179
web/node_modules/@hapi/joi/lib/types/date/index.js
generated
vendored
Executable file
179
web/node_modules/@hapi/joi/lib/types/date/index.js
generated
vendored
Executable file
|
@ -0,0 +1,179 @@
|
|||
'use strict';
|
||||
|
||||
const Hoek = require('@hapi/hoek');
|
||||
|
||||
const Any = require('../any');
|
||||
const Ref = require('../../ref');
|
||||
|
||||
|
||||
const internals = {};
|
||||
|
||||
internals.isoDate = /^(?:[-+]\d{2})?(?:\d{4}(?!\d{2}\b))(?:(-?)(?:(?:0[1-9]|1[0-2])(?:\1(?:[12]\d|0[1-9]|3[01]))?|W(?:[0-4]\d|5[0-2])(?:-?[1-7])?|(?:00[1-9]|0[1-9]\d|[12]\d{2}|3(?:[0-5]\d|6[1-6])))(?![T]$|[T][\d]+Z$)(?:[T\s](?:(?:(?:[01]\d|2[0-3])(?:(:?)[0-5]\d)?|24\:?00)(?:[.,]\d+(?!:))?)(?:\2[0-5]\d(?:[.,]\d+)?)?(?:[Z]|(?:[+-])(?:[01]\d|2[0-3])(?::?[0-5]\d)?)?)?)?$/;
|
||||
internals.invalidDate = new Date('');
|
||||
internals.isIsoDate = (() => {
|
||||
|
||||
const isoString = internals.isoDate.toString();
|
||||
|
||||
return (date) => {
|
||||
|
||||
return date && (date.toString() === isoString);
|
||||
};
|
||||
})();
|
||||
|
||||
internals.Date = class extends Any {
|
||||
|
||||
constructor() {
|
||||
|
||||
super();
|
||||
this._type = 'date';
|
||||
}
|
||||
|
||||
_base(value, state, options) {
|
||||
|
||||
const result = {
|
||||
value: (options.convert && internals.Date.toDate(value, this._flags.format, this._flags.timestamp, this._flags.multiplier)) || value
|
||||
};
|
||||
|
||||
if (result.value instanceof Date && !isNaN(result.value.getTime())) {
|
||||
result.errors = null;
|
||||
}
|
||||
else if (!options.convert) {
|
||||
result.errors = this.createError('date.strict', { value }, state, options);
|
||||
}
|
||||
else {
|
||||
let type;
|
||||
if (internals.isIsoDate(this._flags.format)) {
|
||||
type = 'isoDate';
|
||||
}
|
||||
else if (this._flags.timestamp) {
|
||||
type = `timestamp.${this._flags.timestamp}`;
|
||||
}
|
||||
else {
|
||||
type = 'base';
|
||||
}
|
||||
|
||||
result.errors = this.createError(`date.${type}`, { value }, state, options);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static toDate(value, format, timestamp, multiplier) {
|
||||
|
||||
if (value instanceof Date) {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (typeof value === 'string' ||
|
||||
(typeof value === 'number' && !isNaN(value) && isFinite(value))) {
|
||||
|
||||
const isIsoDate = format && internals.isIsoDate(format);
|
||||
if (!isIsoDate &&
|
||||
typeof value === 'string' &&
|
||||
/^[+-]?\d+(\.\d+)?$/.test(value)) {
|
||||
|
||||
value = parseFloat(value);
|
||||
}
|
||||
|
||||
let date;
|
||||
if (isIsoDate) {
|
||||
date = format.test(value) ? new Date(value.toString()) : internals.invalidDate;
|
||||
}
|
||||
else if (timestamp) {
|
||||
date = /^\s*$/.test(value) ? internals.invalidDate : new Date(value * multiplier);
|
||||
}
|
||||
else {
|
||||
date = new Date(value);
|
||||
}
|
||||
|
||||
if (!isNaN(date.getTime())) {
|
||||
return date;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
iso() {
|
||||
|
||||
if (this._flags.format === internals.isoDate) {
|
||||
return this;
|
||||
}
|
||||
|
||||
const obj = this.clone();
|
||||
obj._flags.format = internals.isoDate;
|
||||
return obj;
|
||||
}
|
||||
|
||||
timestamp(type = 'javascript') {
|
||||
|
||||
const allowed = ['javascript', 'unix'];
|
||||
Hoek.assert(allowed.includes(type), '"type" must be one of "' + allowed.join('", "') + '"');
|
||||
|
||||
if (this._flags.timestamp === type) {
|
||||
return this;
|
||||
}
|
||||
|
||||
const obj = this.clone();
|
||||
obj._flags.timestamp = type;
|
||||
obj._flags.multiplier = type === 'unix' ? 1000 : 1;
|
||||
return obj;
|
||||
}
|
||||
|
||||
_isIsoDate(value) {
|
||||
|
||||
return internals.isoDate.test(value);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
internals.compare = function (type, compare) {
|
||||
|
||||
return function (date) {
|
||||
|
||||
const isNow = date === 'now';
|
||||
const isRef = Ref.isRef(date);
|
||||
|
||||
if (!isNow && !isRef) {
|
||||
date = internals.Date.toDate(date);
|
||||
}
|
||||
|
||||
Hoek.assert(date, 'Invalid date format');
|
||||
|
||||
return this._test(type, date, function (value, state, options) {
|
||||
|
||||
let compareTo;
|
||||
if (isNow) {
|
||||
compareTo = Date.now();
|
||||
}
|
||||
else if (isRef) {
|
||||
const refValue = date(state.reference || state.parent, options);
|
||||
compareTo = internals.Date.toDate(refValue);
|
||||
|
||||
if (!compareTo) {
|
||||
return this.createError('date.ref', { ref: date, value: refValue }, state, options);
|
||||
}
|
||||
|
||||
compareTo = compareTo.getTime();
|
||||
}
|
||||
else {
|
||||
compareTo = date.getTime();
|
||||
}
|
||||
|
||||
if (compare(value.getTime(), compareTo)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return this.createError('date.' + type, { limit: new Date(compareTo), value }, state, options);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
internals.Date.prototype.min = internals.compare('min', (value, date) => value >= date);
|
||||
internals.Date.prototype.max = internals.compare('max', (value, date) => value <= date);
|
||||
internals.Date.prototype.greater = internals.compare('greater', (value, date) => value > date);
|
||||
internals.Date.prototype.less = internals.compare('less', (value, date) => value < date);
|
||||
|
||||
|
||||
module.exports = new internals.Date();
|
87
web/node_modules/@hapi/joi/lib/types/func/index.js
generated
vendored
Executable file
87
web/node_modules/@hapi/joi/lib/types/func/index.js
generated
vendored
Executable file
|
@ -0,0 +1,87 @@
|
|||
'use strict';
|
||||
|
||||
const Hoek = require('@hapi/hoek');
|
||||
|
||||
const ObjectType = require('../object');
|
||||
const Ref = require('../../ref');
|
||||
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
internals.Func = class extends ObjectType.constructor {
|
||||
|
||||
constructor() {
|
||||
|
||||
super();
|
||||
this._flags.func = true;
|
||||
}
|
||||
|
||||
arity(n) {
|
||||
|
||||
Hoek.assert(Number.isSafeInteger(n) && n >= 0, 'n must be a positive integer');
|
||||
|
||||
return this._test('arity', n, function (value, state, options) {
|
||||
|
||||
if (value.length === n) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return this.createError('function.arity', { n }, state, options);
|
||||
});
|
||||
}
|
||||
|
||||
minArity(n) {
|
||||
|
||||
Hoek.assert(Number.isSafeInteger(n) && n > 0, 'n must be a strict positive integer');
|
||||
|
||||
return this._test('minArity', n, function (value, state, options) {
|
||||
|
||||
if (value.length >= n) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return this.createError('function.minArity', { n }, state, options);
|
||||
});
|
||||
}
|
||||
|
||||
maxArity(n) {
|
||||
|
||||
Hoek.assert(Number.isSafeInteger(n) && n >= 0, 'n must be a positive integer');
|
||||
|
||||
return this._test('maxArity', n, function (value, state, options) {
|
||||
|
||||
if (value.length <= n) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return this.createError('function.maxArity', { n }, state, options);
|
||||
});
|
||||
}
|
||||
|
||||
ref() {
|
||||
|
||||
return this._test('ref', null, function (value, state, options) {
|
||||
|
||||
if (Ref.isRef(value)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return this.createError('function.ref', { value }, state, options);
|
||||
});
|
||||
}
|
||||
|
||||
class() {
|
||||
|
||||
return this._test('class', null, function (value, state, options) {
|
||||
|
||||
if ((/^\s*class\s/).test(value.toString())) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return this.createError('function.class', { value }, state, options);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = new internals.Func();
|
79
web/node_modules/@hapi/joi/lib/types/lazy/index.js
generated
vendored
Executable file
79
web/node_modules/@hapi/joi/lib/types/lazy/index.js
generated
vendored
Executable file
|
@ -0,0 +1,79 @@
|
|||
'use strict';
|
||||
|
||||
const Hoek = require('@hapi/hoek');
|
||||
|
||||
const Any = require('../any');
|
||||
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
internals.Lazy = class extends Any {
|
||||
|
||||
constructor() {
|
||||
|
||||
super();
|
||||
this._type = 'lazy';
|
||||
this._flags.once = true;
|
||||
this._cache = null;
|
||||
}
|
||||
|
||||
_init(fn, options) {
|
||||
|
||||
return this.set(fn, options);
|
||||
}
|
||||
|
||||
_base(value, state, options) {
|
||||
|
||||
let schema;
|
||||
if (this._cache) {
|
||||
schema = this._cache;
|
||||
}
|
||||
else {
|
||||
const result = { value };
|
||||
const lazy = this._flags.lazy;
|
||||
|
||||
if (!lazy) {
|
||||
result.errors = this.createError('lazy.base', null, state, options);
|
||||
return result;
|
||||
}
|
||||
|
||||
schema = lazy();
|
||||
|
||||
if (!(schema instanceof Any)) {
|
||||
result.errors = this.createError('lazy.schema', { schema }, state, options);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (this._flags.once) {
|
||||
this._cache = schema;
|
||||
}
|
||||
}
|
||||
|
||||
return schema._validate(value, state, options);
|
||||
}
|
||||
|
||||
set(fn, options) {
|
||||
|
||||
Hoek.assert(typeof fn === 'function', 'You must provide a function as first argument');
|
||||
Hoek.assert(options === undefined || (options && typeof options === 'object' && !Array.isArray(options)), `Options must be an object`);
|
||||
|
||||
if (options) {
|
||||
const unknownOptions = Object.keys(options).filter((key) => !['once'].includes(key));
|
||||
Hoek.assert(unknownOptions.length === 0, `Options contain unknown keys: ${unknownOptions}`);
|
||||
Hoek.assert(options.once === undefined || typeof options.once === 'boolean', 'Option "once" must be a boolean');
|
||||
}
|
||||
|
||||
const obj = this.clone();
|
||||
obj._flags.lazy = fn;
|
||||
|
||||
if (options && options.once !== obj._flags.once) {
|
||||
obj._flags.once = options.once;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
module.exports = new internals.Lazy();
|
245
web/node_modules/@hapi/joi/lib/types/number/index.js
generated
vendored
Executable file
245
web/node_modules/@hapi/joi/lib/types/number/index.js
generated
vendored
Executable file
|
@ -0,0 +1,245 @@
|
|||
'use strict';
|
||||
|
||||
const Hoek = require('@hapi/hoek');
|
||||
|
||||
const Any = require('../any');
|
||||
const Ref = require('../../ref');
|
||||
|
||||
|
||||
const internals = {
|
||||
precisionRx: /(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/,
|
||||
normalizeExponent(str) {
|
||||
|
||||
return str
|
||||
.replace(/\.?0+e/, 'e')
|
||||
.replace(/e\+/, 'e')
|
||||
.replace(/^\+/, '')
|
||||
.replace(/^(-?)0+([1-9])/, '$1$2');
|
||||
},
|
||||
normalizeDecimal(str) {
|
||||
|
||||
str = str
|
||||
.replace(/^\+/, '')
|
||||
.replace(/\.0+$/, '')
|
||||
.replace(/^(-?)0+([1-9])/, '$1$2');
|
||||
|
||||
if (str.includes('.') && str.endsWith('0')) {
|
||||
str = str.replace(/0+$/, '');
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
internals.Number = class extends Any {
|
||||
|
||||
constructor() {
|
||||
|
||||
super();
|
||||
this._type = 'number';
|
||||
this._flags.unsafe = false;
|
||||
this._invalids.add(Infinity);
|
||||
this._invalids.add(-Infinity);
|
||||
}
|
||||
|
||||
_base(value, state, options) {
|
||||
|
||||
const result = {
|
||||
errors: null,
|
||||
value
|
||||
};
|
||||
|
||||
if (typeof value === 'string' &&
|
||||
options.convert) {
|
||||
|
||||
const matches = value.match(/^\s*[+-]?\d+(?:\.\d+)?(?:e([+-]?\d+))?\s*$/i);
|
||||
if (matches) {
|
||||
|
||||
value = value.trim();
|
||||
result.value = parseFloat(value);
|
||||
|
||||
if (!this._flags.unsafe) {
|
||||
if (value.includes('e')) {
|
||||
if (internals.normalizeExponent(`${result.value / Math.pow(10, matches[1])}e${matches[1]}`) !== internals.normalizeExponent(value)) {
|
||||
result.errors = this.createError('number.unsafe', { value }, state, options);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (result.value.toString() !== internals.normalizeDecimal(value)) {
|
||||
result.errors = this.createError('number.unsafe', { value }, state, options);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const isNumber = typeof result.value === 'number' && !isNaN(result.value);
|
||||
|
||||
if (options.convert && 'precision' in this._flags && isNumber) {
|
||||
|
||||
// This is conceptually equivalent to using toFixed but it should be much faster
|
||||
const precision = Math.pow(10, this._flags.precision);
|
||||
result.value = Math.round(result.value * precision) / precision;
|
||||
}
|
||||
|
||||
if (isNumber) {
|
||||
if (!this._flags.unsafe &&
|
||||
(value > Number.MAX_SAFE_INTEGER || value < Number.MIN_SAFE_INTEGER)) {
|
||||
result.errors = this.createError('number.unsafe', { value }, state, options);
|
||||
}
|
||||
}
|
||||
else {
|
||||
result.errors = this.createError('number.base', { value }, state, options);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
multiple(base) {
|
||||
|
||||
const isRef = Ref.isRef(base);
|
||||
|
||||
if (!isRef) {
|
||||
Hoek.assert(typeof base === 'number' && isFinite(base), 'multiple must be a number');
|
||||
Hoek.assert(base > 0, 'multiple must be greater than 0');
|
||||
}
|
||||
|
||||
return this._test('multiple', base, function (value, state, options) {
|
||||
|
||||
const divisor = isRef ? base(state.reference || state.parent, options) : base;
|
||||
|
||||
if (isRef && (typeof divisor !== 'number' || !isFinite(divisor))) {
|
||||
return this.createError('number.ref', { ref: base.key }, state, options);
|
||||
}
|
||||
|
||||
if (value % divisor === 0) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return this.createError('number.multiple', { multiple: base, value }, state, options);
|
||||
});
|
||||
}
|
||||
|
||||
integer() {
|
||||
|
||||
return this._test('integer', undefined, function (value, state, options) {
|
||||
|
||||
return Math.trunc(value) - value === 0 ? value : this.createError('number.integer', { value }, state, options);
|
||||
});
|
||||
}
|
||||
|
||||
unsafe(enabled = true) {
|
||||
|
||||
Hoek.assert(typeof enabled === 'boolean', 'enabled must be a boolean');
|
||||
|
||||
if (this._flags.unsafe === enabled) {
|
||||
return this;
|
||||
}
|
||||
|
||||
const obj = this.clone();
|
||||
obj._flags.unsafe = enabled;
|
||||
return obj;
|
||||
}
|
||||
|
||||
negative() {
|
||||
|
||||
return this._test('negative', undefined, function (value, state, options) {
|
||||
|
||||
if (value < 0) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return this.createError('number.negative', { value }, state, options);
|
||||
});
|
||||
}
|
||||
|
||||
positive() {
|
||||
|
||||
return this._test('positive', undefined, function (value, state, options) {
|
||||
|
||||
if (value > 0) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return this.createError('number.positive', { value }, state, options);
|
||||
});
|
||||
}
|
||||
|
||||
precision(limit) {
|
||||
|
||||
Hoek.assert(Number.isSafeInteger(limit), 'limit must be an integer');
|
||||
Hoek.assert(!('precision' in this._flags), 'precision already set');
|
||||
|
||||
const obj = this._test('precision', limit, function (value, state, options) {
|
||||
|
||||
const places = value.toString().match(internals.precisionRx);
|
||||
const decimals = Math.max((places[1] ? places[1].length : 0) - (places[2] ? parseInt(places[2], 10) : 0), 0);
|
||||
if (decimals <= limit) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return this.createError('number.precision', { limit, value }, state, options);
|
||||
});
|
||||
|
||||
obj._flags.precision = limit;
|
||||
return obj;
|
||||
}
|
||||
|
||||
port() {
|
||||
|
||||
return this._test('port', undefined, function (value, state, options) {
|
||||
|
||||
if (!Number.isSafeInteger(value) || value < 0 || value > 65535) {
|
||||
return this.createError('number.port', { value }, state, options);
|
||||
}
|
||||
|
||||
return value;
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
internals.compare = function (type, compare) {
|
||||
|
||||
return function (limit) {
|
||||
|
||||
const isRef = Ref.isRef(limit);
|
||||
const isNumber = typeof limit === 'number' && !isNaN(limit);
|
||||
|
||||
Hoek.assert(isNumber || isRef, 'limit must be a number or reference');
|
||||
|
||||
return this._test(type, limit, function (value, state, options) {
|
||||
|
||||
let compareTo;
|
||||
if (isRef) {
|
||||
compareTo = limit(state.reference || state.parent, options);
|
||||
|
||||
if (!(typeof compareTo === 'number' && !isNaN(compareTo))) {
|
||||
return this.createError('number.ref', { ref: limit.key }, state, options);
|
||||
}
|
||||
}
|
||||
else {
|
||||
compareTo = limit;
|
||||
}
|
||||
|
||||
if (compare(value, compareTo)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return this.createError('number.' + type, { limit: compareTo, value }, state, options);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
internals.Number.prototype.min = internals.compare('min', (value, limit) => value >= limit);
|
||||
internals.Number.prototype.max = internals.compare('max', (value, limit) => value <= limit);
|
||||
internals.Number.prototype.greater = internals.compare('greater', (value, limit) => value > limit);
|
||||
internals.Number.prototype.less = internals.compare('less', (value, limit) => value < limit);
|
||||
|
||||
|
||||
module.exports = new internals.Number();
|
952
web/node_modules/@hapi/joi/lib/types/object/index.js
generated
vendored
Executable file
952
web/node_modules/@hapi/joi/lib/types/object/index.js
generated
vendored
Executable file
|
@ -0,0 +1,952 @@
|
|||
'use strict';
|
||||
|
||||
const Bourne = require('@hapi/bourne');
|
||||
const Hoek = require('@hapi/hoek');
|
||||
const Topo = require('@hapi/topo');
|
||||
|
||||
const Any = require('../any');
|
||||
const Errors = require('../../errors');
|
||||
const Cast = require('../../cast');
|
||||
const State = require('../state');
|
||||
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
internals.Object = class extends Any {
|
||||
|
||||
constructor() {
|
||||
|
||||
super();
|
||||
this._type = 'object';
|
||||
this._inner.children = null;
|
||||
this._inner.renames = [];
|
||||
this._inner.dependencies = [];
|
||||
this._inner.patterns = [];
|
||||
}
|
||||
|
||||
_init(...args) {
|
||||
|
||||
return args.length ? this.keys(...args) : this;
|
||||
}
|
||||
|
||||
_base(value, state, options) {
|
||||
|
||||
let target = value;
|
||||
const errors = [];
|
||||
const finish = () => {
|
||||
|
||||
return {
|
||||
value: target,
|
||||
errors: errors.length ? errors : null
|
||||
};
|
||||
};
|
||||
|
||||
if (typeof value === 'string' &&
|
||||
options.convert) {
|
||||
|
||||
if (value.length > 1 &&
|
||||
(value[0] === '{' || /^\s*\{/.test(value))) {
|
||||
|
||||
try {
|
||||
value = Bourne.parse(value);
|
||||
}
|
||||
catch (e) { }
|
||||
}
|
||||
}
|
||||
|
||||
const type = this._flags.func ? 'function' : 'object';
|
||||
if (!value ||
|
||||
typeof value !== type ||
|
||||
Array.isArray(value)) {
|
||||
|
||||
errors.push(this.createError(type + '.base', { value }, state, options));
|
||||
return finish();
|
||||
}
|
||||
|
||||
// Skip if there are no other rules to test
|
||||
|
||||
if (!this._inner.renames.length &&
|
||||
!this._inner.dependencies.length &&
|
||||
!this._inner.children && // null allows any keys
|
||||
!this._inner.patterns.length) {
|
||||
|
||||
target = value;
|
||||
return finish();
|
||||
}
|
||||
|
||||
// Ensure target is a local copy (parsed) or shallow copy
|
||||
|
||||
if (target === value) {
|
||||
if (type === 'object') {
|
||||
target = Object.create(Object.getPrototypeOf(value));
|
||||
}
|
||||
else {
|
||||
target = function (...args) {
|
||||
|
||||
return value.apply(this, args);
|
||||
};
|
||||
|
||||
target.prototype = Hoek.clone(value.prototype);
|
||||
}
|
||||
|
||||
const valueKeys = Object.keys(value);
|
||||
for (let i = 0; i < valueKeys.length; ++i) {
|
||||
target[valueKeys[i]] = value[valueKeys[i]];
|
||||
}
|
||||
}
|
||||
else {
|
||||
target = value;
|
||||
}
|
||||
|
||||
// Rename keys
|
||||
|
||||
const renamed = {};
|
||||
for (let i = 0; i < this._inner.renames.length; ++i) {
|
||||
const rename = this._inner.renames[i];
|
||||
|
||||
if (rename.isRegExp) {
|
||||
const targetKeys = Object.keys(target);
|
||||
const matchedTargetKeys = [];
|
||||
|
||||
for (let j = 0; j < targetKeys.length; ++j) {
|
||||
if (rename.from.test(targetKeys[j])) {
|
||||
matchedTargetKeys.push(targetKeys[j]);
|
||||
}
|
||||
}
|
||||
|
||||
const allUndefined = matchedTargetKeys.every((key) => target[key] === undefined);
|
||||
if (rename.options.ignoreUndefined && allUndefined) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!rename.options.multiple &&
|
||||
renamed[rename.to]) {
|
||||
|
||||
errors.push(this.createError('object.rename.regex.multiple', { from: matchedTargetKeys, to: rename.to }, state, options));
|
||||
if (options.abortEarly) {
|
||||
return finish();
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(target, rename.to) &&
|
||||
!rename.options.override &&
|
||||
!renamed[rename.to]) {
|
||||
|
||||
errors.push(this.createError('object.rename.regex.override', { from: matchedTargetKeys, to: rename.to }, state, options));
|
||||
if (options.abortEarly) {
|
||||
return finish();
|
||||
}
|
||||
}
|
||||
|
||||
if (allUndefined) {
|
||||
delete target[rename.to];
|
||||
}
|
||||
else {
|
||||
target[rename.to] = target[matchedTargetKeys[matchedTargetKeys.length - 1]];
|
||||
}
|
||||
|
||||
renamed[rename.to] = true;
|
||||
|
||||
if (!rename.options.alias) {
|
||||
for (let j = 0; j < matchedTargetKeys.length; ++j) {
|
||||
delete target[matchedTargetKeys[j]];
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (rename.options.ignoreUndefined && target[rename.from] === undefined) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!rename.options.multiple &&
|
||||
renamed[rename.to]) {
|
||||
|
||||
errors.push(this.createError('object.rename.multiple', { from: rename.from, to: rename.to }, state, options));
|
||||
if (options.abortEarly) {
|
||||
return finish();
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(target, rename.to) &&
|
||||
!rename.options.override &&
|
||||
!renamed[rename.to]) {
|
||||
|
||||
errors.push(this.createError('object.rename.override', { from: rename.from, to: rename.to }, state, options));
|
||||
if (options.abortEarly) {
|
||||
return finish();
|
||||
}
|
||||
}
|
||||
|
||||
if (target[rename.from] === undefined) {
|
||||
delete target[rename.to];
|
||||
}
|
||||
else {
|
||||
target[rename.to] = target[rename.from];
|
||||
}
|
||||
|
||||
renamed[rename.to] = true;
|
||||
|
||||
if (!rename.options.alias) {
|
||||
delete target[rename.from];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Validate schema
|
||||
|
||||
if (!this._inner.children && // null allows any keys
|
||||
!this._inner.patterns.length &&
|
||||
!this._inner.dependencies.length) {
|
||||
|
||||
return finish();
|
||||
}
|
||||
|
||||
const unprocessed = new Set(Object.keys(target));
|
||||
|
||||
if (this._inner.children) {
|
||||
const stripProps = [];
|
||||
|
||||
for (let i = 0; i < this._inner.children.length; ++i) {
|
||||
const child = this._inner.children[i];
|
||||
const key = child.key;
|
||||
const item = target[key];
|
||||
|
||||
unprocessed.delete(key);
|
||||
|
||||
const localState = new State(key, [...state.path, key], target, state.reference);
|
||||
const result = child.schema._validate(item, localState, options);
|
||||
if (result.errors) {
|
||||
errors.push(this.createError('object.child', { key, child: child.schema._getLabel(key), reason: result.errors }, localState, options));
|
||||
|
||||
if (options.abortEarly) {
|
||||
return finish();
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (child.schema._flags.strip || (result.value === undefined && result.value !== item)) {
|
||||
stripProps.push(key);
|
||||
target[key] = result.finalValue;
|
||||
}
|
||||
else if (result.value !== undefined) {
|
||||
target[key] = result.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < stripProps.length; ++i) {
|
||||
delete target[stripProps[i]];
|
||||
}
|
||||
}
|
||||
|
||||
// Unknown keys
|
||||
|
||||
if (unprocessed.size && this._inner.patterns.length) {
|
||||
|
||||
for (const key of unprocessed) {
|
||||
const localState = new State(key, [...state.path, key], target, state.reference);
|
||||
const item = target[key];
|
||||
|
||||
for (let i = 0; i < this._inner.patterns.length; ++i) {
|
||||
const pattern = this._inner.patterns[i];
|
||||
|
||||
if (pattern.regex ?
|
||||
pattern.regex.test(key) :
|
||||
!pattern.schema._validate(key, state, { ...options, abortEarly:true }).errors) {
|
||||
|
||||
unprocessed.delete(key);
|
||||
|
||||
const result = pattern.rule._validate(item, localState, options);
|
||||
if (result.errors) {
|
||||
errors.push(this.createError('object.child', {
|
||||
key,
|
||||
child: pattern.rule._getLabel(key),
|
||||
reason: result.errors
|
||||
}, localState, options));
|
||||
|
||||
if (options.abortEarly) {
|
||||
return finish();
|
||||
}
|
||||
}
|
||||
|
||||
target[key] = result.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (unprocessed.size && (this._inner.children || this._inner.patterns.length)) {
|
||||
if ((options.stripUnknown && this._flags.allowUnknown !== true) ||
|
||||
options.skipFunctions) {
|
||||
|
||||
const stripUnknown = options.stripUnknown
|
||||
? (options.stripUnknown === true ? true : !!options.stripUnknown.objects)
|
||||
: false;
|
||||
|
||||
|
||||
for (const key of unprocessed) {
|
||||
if (stripUnknown) {
|
||||
delete target[key];
|
||||
unprocessed.delete(key);
|
||||
}
|
||||
else if (typeof target[key] === 'function') {
|
||||
unprocessed.delete(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((this._flags.allowUnknown !== undefined ? !this._flags.allowUnknown : !options.allowUnknown)) {
|
||||
|
||||
for (const unprocessedKey of unprocessed) {
|
||||
errors.push(this.createError('object.allowUnknown', { child: unprocessedKey, value: target[unprocessedKey] }, {
|
||||
key: unprocessedKey,
|
||||
path: [...state.path, unprocessedKey]
|
||||
}, options, {}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Validate dependencies
|
||||
|
||||
for (let i = 0; i < this._inner.dependencies.length; ++i) {
|
||||
const dep = this._inner.dependencies[i];
|
||||
const hasKey = dep.key !== null;
|
||||
const splitKey = hasKey && dep.key.split('.');
|
||||
const localState = hasKey ? new State(splitKey[splitKey.length - 1], [...state.path, ...splitKey]) : new State(null, state.path);
|
||||
const err = internals[dep.type].call(this, dep.key, hasKey && Hoek.reach(target, dep.key, { functions: true }), dep.peers, target, localState, options);
|
||||
if (err instanceof Errors.Err) {
|
||||
errors.push(err);
|
||||
if (options.abortEarly) {
|
||||
return finish();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return finish();
|
||||
}
|
||||
|
||||
keys(schema) {
|
||||
|
||||
Hoek.assert(schema === null || schema === undefined || typeof schema === 'object', 'Object schema must be a valid object');
|
||||
Hoek.assert(!schema || !(schema instanceof Any), 'Object schema cannot be a joi schema');
|
||||
|
||||
const obj = this.clone();
|
||||
|
||||
if (!schema) {
|
||||
obj._inner.children = null;
|
||||
return obj;
|
||||
}
|
||||
|
||||
const children = Object.keys(schema);
|
||||
|
||||
if (!children.length) {
|
||||
obj._inner.children = [];
|
||||
return obj;
|
||||
}
|
||||
|
||||
const topo = new Topo();
|
||||
if (obj._inner.children) {
|
||||
for (let i = 0; i < obj._inner.children.length; ++i) {
|
||||
const child = obj._inner.children[i];
|
||||
|
||||
// Only add the key if we are not going to replace it later
|
||||
if (!children.includes(child.key)) {
|
||||
topo.add(child, { after: child._refs, group: child.key });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < children.length; ++i) {
|
||||
const key = children[i];
|
||||
const child = schema[key];
|
||||
try {
|
||||
const cast = Cast.schema(this._currentJoi, child);
|
||||
topo.add({ key, schema: cast }, { after: cast._refs, group: key });
|
||||
}
|
||||
catch (castErr) {
|
||||
if (castErr.hasOwnProperty('path')) {
|
||||
castErr.path = key + '.' + castErr.path;
|
||||
}
|
||||
else {
|
||||
castErr.path = key;
|
||||
}
|
||||
|
||||
throw castErr;
|
||||
}
|
||||
}
|
||||
|
||||
obj._inner.children = topo.nodes;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
append(schema) {
|
||||
// Skip any changes
|
||||
if (schema === null || schema === undefined || Object.keys(schema).length === 0) {
|
||||
return this;
|
||||
}
|
||||
|
||||
return this.keys(schema);
|
||||
}
|
||||
|
||||
unknown(allow) {
|
||||
|
||||
const value = allow !== false;
|
||||
|
||||
if (this._flags.allowUnknown === value) {
|
||||
return this;
|
||||
}
|
||||
|
||||
const obj = this.clone();
|
||||
obj._flags.allowUnknown = value;
|
||||
return obj;
|
||||
}
|
||||
|
||||
length(limit) {
|
||||
|
||||
Hoek.assert(Number.isSafeInteger(limit) && limit >= 0, 'limit must be a positive integer');
|
||||
|
||||
return this._test('length', limit, function (value, state, options) {
|
||||
|
||||
if (Object.keys(value).length === limit) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return this.createError('object.length', { limit, value }, state, options);
|
||||
});
|
||||
}
|
||||
|
||||
min(limit) {
|
||||
|
||||
Hoek.assert(Number.isSafeInteger(limit) && limit >= 0, 'limit must be a positive integer');
|
||||
|
||||
return this._test('min', limit, function (value, state, options) {
|
||||
|
||||
if (Object.keys(value).length >= limit) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return this.createError('object.min', { limit, value }, state, options);
|
||||
});
|
||||
}
|
||||
|
||||
max(limit) {
|
||||
|
||||
Hoek.assert(Number.isSafeInteger(limit) && limit >= 0, 'limit must be a positive integer');
|
||||
|
||||
return this._test('max', limit, function (value, state, options) {
|
||||
|
||||
if (Object.keys(value).length <= limit) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return this.createError('object.max', { limit, value }, state, options);
|
||||
});
|
||||
}
|
||||
|
||||
pattern(pattern, schema) {
|
||||
|
||||
const isRegExp = pattern instanceof RegExp;
|
||||
Hoek.assert(isRegExp || pattern instanceof Any, 'pattern must be a regex or schema');
|
||||
Hoek.assert(schema !== undefined, 'Invalid rule');
|
||||
|
||||
if (isRegExp) {
|
||||
Hoek.assert(!pattern.flags.includes('g') && !pattern.flags.includes('y'), 'pattern should not use global or sticky mode');
|
||||
}
|
||||
|
||||
try {
|
||||
schema = Cast.schema(this._currentJoi, schema);
|
||||
}
|
||||
catch (castErr) {
|
||||
if (castErr.hasOwnProperty('path')) {
|
||||
castErr.message = `${castErr.message}(${castErr.path})`;
|
||||
}
|
||||
|
||||
throw castErr;
|
||||
}
|
||||
|
||||
const obj = this.clone();
|
||||
if (isRegExp) {
|
||||
obj._inner.patterns.push({ regex: pattern, rule: schema });
|
||||
}
|
||||
else {
|
||||
obj._inner.patterns.push({ schema: pattern, rule: schema });
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
schema() {
|
||||
|
||||
return this._test('schema', null, function (value, state, options) {
|
||||
|
||||
if (value instanceof Any) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return this.createError('object.schema', null, state, options);
|
||||
});
|
||||
}
|
||||
|
||||
with(key, peers) {
|
||||
|
||||
Hoek.assert(arguments.length === 2, 'Invalid number of arguments, expected 2.');
|
||||
|
||||
return this._dependency('with', key, peers);
|
||||
}
|
||||
|
||||
without(key, peers) {
|
||||
|
||||
Hoek.assert(arguments.length === 2, 'Invalid number of arguments, expected 2.');
|
||||
|
||||
return this._dependency('without', key, peers);
|
||||
}
|
||||
|
||||
xor(...peers) {
|
||||
|
||||
peers = Hoek.flatten(peers);
|
||||
return this._dependency('xor', null, peers);
|
||||
}
|
||||
|
||||
oxor(...peers) {
|
||||
|
||||
return this._dependency('oxor', null, peers);
|
||||
}
|
||||
|
||||
or(...peers) {
|
||||
|
||||
peers = Hoek.flatten(peers);
|
||||
return this._dependency('or', null, peers);
|
||||
}
|
||||
|
||||
and(...peers) {
|
||||
|
||||
peers = Hoek.flatten(peers);
|
||||
return this._dependency('and', null, peers);
|
||||
}
|
||||
|
||||
nand(...peers) {
|
||||
|
||||
peers = Hoek.flatten(peers);
|
||||
return this._dependency('nand', null, peers);
|
||||
}
|
||||
|
||||
requiredKeys(...children) {
|
||||
|
||||
children = Hoek.flatten(children);
|
||||
return this.applyFunctionToChildren(children, 'required');
|
||||
}
|
||||
|
||||
optionalKeys(...children) {
|
||||
|
||||
children = Hoek.flatten(children);
|
||||
return this.applyFunctionToChildren(children, 'optional');
|
||||
}
|
||||
|
||||
forbiddenKeys(...children) {
|
||||
|
||||
children = Hoek.flatten(children);
|
||||
return this.applyFunctionToChildren(children, 'forbidden');
|
||||
}
|
||||
|
||||
rename(from, to, options) {
|
||||
|
||||
Hoek.assert(typeof from === 'string' || from instanceof RegExp, 'Rename missing the from argument');
|
||||
Hoek.assert(typeof to === 'string', 'Rename missing the to argument');
|
||||
Hoek.assert(to !== from, 'Cannot rename key to same name:', from);
|
||||
|
||||
for (let i = 0; i < this._inner.renames.length; ++i) {
|
||||
Hoek.assert(this._inner.renames[i].from !== from, 'Cannot rename the same key multiple times');
|
||||
}
|
||||
|
||||
const obj = this.clone();
|
||||
|
||||
obj._inner.renames.push({
|
||||
from,
|
||||
to,
|
||||
options: Hoek.applyToDefaults(internals.renameDefaults, options || {}),
|
||||
isRegExp: from instanceof RegExp
|
||||
});
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
applyFunctionToChildren(children, fn, args = [], root) {
|
||||
|
||||
children = [].concat(children);
|
||||
Hoek.assert(children.length > 0, 'expected at least one children');
|
||||
|
||||
const groupedChildren = internals.groupChildren(children);
|
||||
let obj;
|
||||
|
||||
if ('' in groupedChildren) {
|
||||
obj = this[fn](...args);
|
||||
delete groupedChildren[''];
|
||||
}
|
||||
else {
|
||||
obj = this.clone();
|
||||
}
|
||||
|
||||
if (obj._inner.children) {
|
||||
root = root ? (root + '.') : '';
|
||||
|
||||
for (let i = 0; i < obj._inner.children.length; ++i) {
|
||||
const child = obj._inner.children[i];
|
||||
const group = groupedChildren[child.key];
|
||||
|
||||
if (group) {
|
||||
obj._inner.children[i] = {
|
||||
key: child.key,
|
||||
_refs: child._refs,
|
||||
schema: child.schema.applyFunctionToChildren(group, fn, args, root + child.key)
|
||||
};
|
||||
|
||||
delete groupedChildren[child.key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const remaining = Object.keys(groupedChildren);
|
||||
Hoek.assert(remaining.length === 0, 'unknown key(s)', remaining.join(', '));
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
_dependency(type, key, peers) {
|
||||
|
||||
peers = [].concat(peers);
|
||||
for (let i = 0; i < peers.length; ++i) {
|
||||
Hoek.assert(typeof peers[i] === 'string', type, 'peers must be a string or array of strings');
|
||||
}
|
||||
|
||||
const obj = this.clone();
|
||||
obj._inner.dependencies.push({ type, key, peers });
|
||||
return obj;
|
||||
}
|
||||
|
||||
describe(shallow) {
|
||||
|
||||
const description = super.describe();
|
||||
|
||||
if (description.rules) {
|
||||
for (let i = 0; i < description.rules.length; ++i) {
|
||||
const rule = description.rules[i];
|
||||
// Coverage off for future-proof descriptions, only object().assert() is use right now
|
||||
if (/* $lab:coverage:off$ */rule.arg &&
|
||||
typeof rule.arg === 'object' &&
|
||||
rule.arg.schema &&
|
||||
rule.arg.ref /* $lab:coverage:on$ */) {
|
||||
rule.arg = {
|
||||
schema: rule.arg.schema.describe(),
|
||||
ref: rule.arg.ref.toString()
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this._inner.children &&
|
||||
!shallow) {
|
||||
|
||||
description.children = {};
|
||||
for (let i = 0; i < this._inner.children.length; ++i) {
|
||||
const child = this._inner.children[i];
|
||||
description.children[child.key] = child.schema.describe();
|
||||
}
|
||||
}
|
||||
|
||||
if (this._inner.dependencies.length) {
|
||||
description.dependencies = Hoek.clone(this._inner.dependencies);
|
||||
}
|
||||
|
||||
if (this._inner.patterns.length) {
|
||||
description.patterns = [];
|
||||
|
||||
for (let i = 0; i < this._inner.patterns.length; ++i) {
|
||||
const pattern = this._inner.patterns[i];
|
||||
if (pattern.regex) {
|
||||
description.patterns.push({ regex: pattern.regex.toString(), rule: pattern.rule.describe() });
|
||||
}
|
||||
else {
|
||||
description.patterns.push({ schema: pattern.schema.describe(), rule: pattern.rule.describe() });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this._inner.renames.length > 0) {
|
||||
description.renames = Hoek.clone(this._inner.renames);
|
||||
}
|
||||
|
||||
return description;
|
||||
}
|
||||
|
||||
assert(ref, schema, message) {
|
||||
|
||||
ref = Cast.ref(ref);
|
||||
Hoek.assert(ref.isContext || ref.depth > 1, 'Cannot use assertions for root level references - use direct key rules instead');
|
||||
message = message || 'pass the assertion test';
|
||||
Hoek.assert(typeof message === 'string', 'Message must be a string');
|
||||
|
||||
try {
|
||||
schema = Cast.schema(this._currentJoi, schema);
|
||||
}
|
||||
catch (castErr) {
|
||||
if (castErr.hasOwnProperty('path')) {
|
||||
castErr.message = `${castErr.message}(${castErr.path})`;
|
||||
}
|
||||
|
||||
throw castErr;
|
||||
}
|
||||
|
||||
const key = ref.path[ref.path.length - 1];
|
||||
const path = ref.path.join('.');
|
||||
|
||||
return this._test('assert', { schema, ref }, function (value, state, options) {
|
||||
|
||||
const result = schema._validate(ref(value), null, options, value);
|
||||
if (!result.errors) {
|
||||
return value;
|
||||
}
|
||||
|
||||
const localState = new State(key, ref.path, state.parent, state.reference);
|
||||
return this.createError('object.assert', { ref: path, message }, localState, options);
|
||||
});
|
||||
}
|
||||
|
||||
type(constructor, name = constructor.name) {
|
||||
|
||||
Hoek.assert(typeof constructor === 'function', 'type must be a constructor function');
|
||||
const typeData = {
|
||||
name,
|
||||
ctor: constructor
|
||||
};
|
||||
|
||||
return this._test('type', typeData, function (value, state, options) {
|
||||
|
||||
if (value instanceof constructor) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return this.createError('object.type', { type: typeData.name, value }, state, options);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
internals.renameDefaults = {
|
||||
alias: false, // Keep old value in place
|
||||
multiple: false, // Allow renaming multiple keys into the same target
|
||||
override: false // Overrides an existing key
|
||||
};
|
||||
|
||||
|
||||
internals.groupChildren = function (children) {
|
||||
|
||||
children.sort();
|
||||
|
||||
const grouped = {};
|
||||
|
||||
for (let i = 0; i < children.length; ++i) {
|
||||
const child = children[i];
|
||||
Hoek.assert(typeof child === 'string', 'children must be strings');
|
||||
const group = child.split('.')[0];
|
||||
const childGroup = grouped[group] = (grouped[group] || []);
|
||||
childGroup.push(child.substring(group.length + 1));
|
||||
}
|
||||
|
||||
return grouped;
|
||||
};
|
||||
|
||||
|
||||
internals.keysToLabels = function (schema, keys) {
|
||||
|
||||
const children = schema._inner.children;
|
||||
|
||||
if (!children) {
|
||||
return keys;
|
||||
}
|
||||
|
||||
const findLabel = function (key) {
|
||||
|
||||
const matchingChild = schema._currentJoi.reach(schema, key);
|
||||
return matchingChild ? matchingChild._getLabel(key) : key;
|
||||
};
|
||||
|
||||
if (Array.isArray(keys)) {
|
||||
return keys.map(findLabel);
|
||||
}
|
||||
|
||||
return findLabel(keys);
|
||||
};
|
||||
|
||||
|
||||
internals.with = function (key, value, peers, parent, state, options) {
|
||||
|
||||
if (value === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i = 0; i < peers.length; ++i) {
|
||||
|
||||
const peer = peers[i];
|
||||
const keysExist = Hoek.reach(parent, peer, { functions: true });
|
||||
if (keysExist === undefined) {
|
||||
|
||||
return this.createError('object.with', {
|
||||
main: key,
|
||||
mainWithLabel: internals.keysToLabels(this, key),
|
||||
peer,
|
||||
peerWithLabel: internals.keysToLabels(this, peer)
|
||||
}, state, options);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
internals.without = function (key, value, peers, parent, state, options) {
|
||||
|
||||
if (value === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i = 0; i < peers.length; ++i) {
|
||||
const peer = peers[i];
|
||||
const keysExist = Hoek.reach(parent, peer, { functions: true });
|
||||
if (keysExist !== undefined) {
|
||||
|
||||
return this.createError('object.without', {
|
||||
main: key,
|
||||
mainWithLabel: internals.keysToLabels(this, key),
|
||||
peer,
|
||||
peerWithLabel: internals.keysToLabels(this, peer)
|
||||
}, state, options);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
internals.xor = function (key, value, peers, parent, state, options) {
|
||||
|
||||
const present = [];
|
||||
for (let i = 0; i < peers.length; ++i) {
|
||||
const peer = peers[i];
|
||||
const keysExist = Hoek.reach(parent, peer, { functions: true });
|
||||
if (keysExist !== undefined) {
|
||||
present.push(peer);
|
||||
}
|
||||
}
|
||||
|
||||
if (present.length === 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
const context = { peers, peersWithLabels: internals.keysToLabels(this, peers) };
|
||||
|
||||
if (present.length === 0) {
|
||||
return this.createError('object.missing', context, state, options);
|
||||
}
|
||||
|
||||
context.present = present;
|
||||
context.presentWithLabels = internals.keysToLabels(this, present);
|
||||
|
||||
return this.createError('object.xor', context, state, options);
|
||||
};
|
||||
|
||||
|
||||
internals.oxor = function (key, value, peers, parent, state, options) {
|
||||
|
||||
const present = [];
|
||||
for (let i = 0; i < peers.length; ++i) {
|
||||
const peer = peers[i];
|
||||
const keysExist = Hoek.reach(parent, peer, { functions: true });
|
||||
if (keysExist !== undefined) {
|
||||
present.push(peer);
|
||||
}
|
||||
}
|
||||
|
||||
if (!present.length ||
|
||||
present.length === 1) {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const context = { peers, peersWithLabels: internals.keysToLabels(this, peers) };
|
||||
context.present = present;
|
||||
context.presentWithLabels = internals.keysToLabels(this, present);
|
||||
|
||||
return this.createError('object.oxor', context, state, options);
|
||||
};
|
||||
|
||||
|
||||
internals.or = function (key, value, peers, parent, state, options) {
|
||||
|
||||
for (let i = 0; i < peers.length; ++i) {
|
||||
const peer = peers[i];
|
||||
const keysExist = Hoek.reach(parent, peer, { functions: true });
|
||||
if (keysExist !== undefined) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return this.createError('object.missing', {
|
||||
peers,
|
||||
peersWithLabels: internals.keysToLabels(this, peers)
|
||||
}, state, options);
|
||||
};
|
||||
|
||||
|
||||
internals.and = function (key, value, peers, parent, state, options) {
|
||||
|
||||
const missing = [];
|
||||
const present = [];
|
||||
const count = peers.length;
|
||||
for (let i = 0; i < count; ++i) {
|
||||
const peer = peers[i];
|
||||
const keysExist = Hoek.reach(parent, peer, { functions: true });
|
||||
if (keysExist === undefined) {
|
||||
|
||||
missing.push(peer);
|
||||
}
|
||||
else {
|
||||
present.push(peer);
|
||||
}
|
||||
}
|
||||
|
||||
const aon = (missing.length === count || present.length === count);
|
||||
|
||||
if (!aon) {
|
||||
|
||||
return this.createError('object.and', {
|
||||
present,
|
||||
presentWithLabels: internals.keysToLabels(this, present),
|
||||
missing,
|
||||
missingWithLabels: internals.keysToLabels(this, missing)
|
||||
}, state, options);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
internals.nand = function (key, value, peers, parent, state, options) {
|
||||
|
||||
const present = [];
|
||||
for (let i = 0; i < peers.length; ++i) {
|
||||
const peer = peers[i];
|
||||
const keysExist = Hoek.reach(parent, peer, { functions: true });
|
||||
if (keysExist !== undefined) {
|
||||
|
||||
present.push(peer);
|
||||
}
|
||||
}
|
||||
|
||||
const main = peers[0];
|
||||
const values = peers.slice(1);
|
||||
const allPresent = (present.length === peers.length);
|
||||
return allPresent ? this.createError('object.nand', {
|
||||
main,
|
||||
mainWithLabel: internals.keysToLabels(this, main),
|
||||
peers: values,
|
||||
peersWithLabels: internals.keysToLabels(this, values)
|
||||
}, state, options) : null;
|
||||
};
|
||||
|
||||
|
||||
module.exports = new internals.Object();
|
14
web/node_modules/@hapi/joi/lib/types/state.js
generated
vendored
Executable file
14
web/node_modules/@hapi/joi/lib/types/state.js
generated
vendored
Executable file
|
@ -0,0 +1,14 @@
|
|||
'use strict';
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
module.exports = class {
|
||||
constructor(key, path, parent, reference) {
|
||||
|
||||
this.key = key;
|
||||
this.path = path;
|
||||
this.parent = parent;
|
||||
this.reference = reference;
|
||||
}
|
||||
};
|
724
web/node_modules/@hapi/joi/lib/types/string/index.js
generated
vendored
Executable file
724
web/node_modules/@hapi/joi/lib/types/string/index.js
generated
vendored
Executable file
|
@ -0,0 +1,724 @@
|
|||
'use strict';
|
||||
|
||||
const Net = require('net');
|
||||
|
||||
const Address = require('@hapi/address');
|
||||
const Hoek = require('@hapi/hoek');
|
||||
|
||||
const Any = require('../any');
|
||||
const Ref = require('../../ref');
|
||||
const JoiDate = require('../date');
|
||||
|
||||
const Uri = require('./uri');
|
||||
const Ip = require('./ip');
|
||||
|
||||
|
||||
const internals = {
|
||||
uriRegex: Uri.createUriRegex(),
|
||||
ipRegex: Ip.createIpRegex(['ipv4', 'ipv6', 'ipvfuture'], 'optional'),
|
||||
guidBrackets: {
|
||||
'{': '}', '[': ']', '(': ')', '': ''
|
||||
},
|
||||
guidVersions: {
|
||||
uuidv1: '1',
|
||||
uuidv2: '2',
|
||||
uuidv3: '3',
|
||||
uuidv4: '4',
|
||||
uuidv5: '5'
|
||||
},
|
||||
cidrPresences: ['required', 'optional', 'forbidden'],
|
||||
normalizationForms: ['NFC', 'NFD', 'NFKC', 'NFKD']
|
||||
};
|
||||
|
||||
|
||||
internals.String = class extends Any {
|
||||
|
||||
constructor() {
|
||||
|
||||
super();
|
||||
this._type = 'string';
|
||||
this._invalids.add('');
|
||||
}
|
||||
|
||||
_base(value, state, options) {
|
||||
|
||||
if (typeof value === 'string' &&
|
||||
options.convert) {
|
||||
|
||||
if (this._flags.normalize) {
|
||||
value = value.normalize(this._flags.normalize);
|
||||
}
|
||||
|
||||
if (this._flags.case) {
|
||||
value = (this._flags.case === 'upper' ? value.toLocaleUpperCase() : value.toLocaleLowerCase());
|
||||
}
|
||||
|
||||
if (this._flags.trim) {
|
||||
value = value.trim();
|
||||
}
|
||||
|
||||
if (this._inner.replacements) {
|
||||
|
||||
for (let i = 0; i < this._inner.replacements.length; ++i) {
|
||||
const replacement = this._inner.replacements[i];
|
||||
value = value.replace(replacement.pattern, replacement.replacement);
|
||||
}
|
||||
}
|
||||
|
||||
if (this._flags.truncate) {
|
||||
for (let i = 0; i < this._tests.length; ++i) {
|
||||
const test = this._tests[i];
|
||||
if (test.name === 'max') {
|
||||
value = value.slice(0, test.arg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this._flags.byteAligned && value.length % 2 !== 0) {
|
||||
value = `0${value}`;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
value,
|
||||
errors: (typeof value === 'string') ? null : this.createError('string.base', { value }, state, options)
|
||||
};
|
||||
}
|
||||
|
||||
insensitive() {
|
||||
|
||||
if (this._flags.insensitive) {
|
||||
return this;
|
||||
}
|
||||
|
||||
const obj = this.clone();
|
||||
obj._flags.insensitive = true;
|
||||
return obj;
|
||||
}
|
||||
|
||||
creditCard() {
|
||||
|
||||
return this._test('creditCard', undefined, function (value, state, options) {
|
||||
|
||||
let i = value.length;
|
||||
let sum = 0;
|
||||
let mul = 1;
|
||||
|
||||
while (i--) {
|
||||
const char = value.charAt(i) * mul;
|
||||
sum = sum + (char - (char > 9) * 9);
|
||||
mul = mul ^ 3;
|
||||
}
|
||||
|
||||
const check = (sum % 10 === 0) && (sum > 0);
|
||||
return check ? value : this.createError('string.creditCard', { value }, state, options);
|
||||
});
|
||||
}
|
||||
|
||||
regex(pattern, patternOptions) {
|
||||
|
||||
Hoek.assert(pattern instanceof RegExp, 'pattern must be a RegExp');
|
||||
Hoek.assert(!pattern.flags.includes('g') && !pattern.flags.includes('y'), 'pattern should not use global or sticky mode');
|
||||
|
||||
const patternObject = { pattern };
|
||||
|
||||
if (typeof patternOptions === 'string') {
|
||||
patternObject.name = patternOptions;
|
||||
}
|
||||
else if (typeof patternOptions === 'object') {
|
||||
patternObject.invert = !!patternOptions.invert;
|
||||
|
||||
if (patternOptions.name) {
|
||||
patternObject.name = patternOptions.name;
|
||||
}
|
||||
}
|
||||
|
||||
const errorCode = ['string.regex', patternObject.invert ? '.invert' : '', patternObject.name ? '.name' : '.base'].join('');
|
||||
|
||||
return this._test('regex', patternObject, function (value, state, options) {
|
||||
|
||||
const patternMatch = patternObject.pattern.test(value);
|
||||
|
||||
if (patternMatch ^ patternObject.invert) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return this.createError(errorCode, { name: patternObject.name, pattern: patternObject.pattern, value }, state, options);
|
||||
});
|
||||
}
|
||||
|
||||
alphanum() {
|
||||
|
||||
return this._test('alphanum', undefined, function (value, state, options) {
|
||||
|
||||
if (/^[a-zA-Z0-9]+$/.test(value)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return this.createError('string.alphanum', { value }, state, options);
|
||||
});
|
||||
}
|
||||
|
||||
token() {
|
||||
|
||||
return this._test('token', undefined, function (value, state, options) {
|
||||
|
||||
if (/^\w+$/.test(value)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return this.createError('string.token', { value }, state, options);
|
||||
});
|
||||
}
|
||||
|
||||
email(validationOptions) {
|
||||
|
||||
if (validationOptions) {
|
||||
Hoek.assert(typeof validationOptions === 'object', 'email options must be an object');
|
||||
|
||||
// Migration validation for unsupported options
|
||||
|
||||
Hoek.assert(validationOptions.checkDNS === undefined, 'checkDNS option is not supported');
|
||||
Hoek.assert(validationOptions.errorLevel === undefined, 'errorLevel option is not supported');
|
||||
Hoek.assert(validationOptions.minDomainAtoms === undefined, 'minDomainAtoms option is not supported, use minDomainSegments instead');
|
||||
Hoek.assert(validationOptions.tldBlacklist === undefined, 'tldBlacklist option is not supported, use tlds.deny instead');
|
||||
Hoek.assert(validationOptions.tldWhitelist === undefined, 'tldWhitelist option is not supported, use tlds.allow instead');
|
||||
|
||||
// Validate options
|
||||
|
||||
if (validationOptions.tlds &&
|
||||
typeof validationOptions.tlds === 'object') {
|
||||
|
||||
Hoek.assert(validationOptions.tlds.allow === undefined ||
|
||||
validationOptions.tlds.allow === false ||
|
||||
validationOptions.tlds.allow === true ||
|
||||
Array.isArray(validationOptions.tlds.allow) ||
|
||||
validationOptions.tlds.allow instanceof Set, 'tlds.allow must be an array, Set, or boolean');
|
||||
|
||||
Hoek.assert(validationOptions.tlds.deny === undefined ||
|
||||
Array.isArray(validationOptions.tlds.deny) ||
|
||||
validationOptions.tlds.deny instanceof Set, 'tlds.deny must be an array or Set');
|
||||
|
||||
const normalizeTable = (table) => {
|
||||
|
||||
if (table === undefined ||
|
||||
typeof table === 'boolean' ||
|
||||
table instanceof Set) {
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
return new Set(table);
|
||||
};
|
||||
|
||||
validationOptions = Object.assign({}, validationOptions); // Shallow cloned
|
||||
validationOptions.tlds = {
|
||||
allow: normalizeTable(validationOptions.tlds.allow),
|
||||
deny: normalizeTable(validationOptions.tlds.deny)
|
||||
};
|
||||
}
|
||||
|
||||
Hoek.assert(validationOptions.minDomainSegments === undefined ||
|
||||
Number.isSafeInteger(validationOptions.minDomainSegments) && validationOptions.minDomainSegments > 0, 'minDomainSegments must be a positive integer');
|
||||
}
|
||||
|
||||
return this._test('email', validationOptions, function (value, state, options) {
|
||||
|
||||
if (Address.email.isValid(value, validationOptions)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return this.createError('string.email', { value }, state, options);
|
||||
});
|
||||
}
|
||||
|
||||
ip(ipOptions = {}) {
|
||||
|
||||
let regex = internals.ipRegex;
|
||||
Hoek.assert(typeof ipOptions === 'object', 'options must be an object');
|
||||
|
||||
if (ipOptions.cidr) {
|
||||
Hoek.assert(typeof ipOptions.cidr === 'string', 'cidr must be a string');
|
||||
ipOptions.cidr = ipOptions.cidr.toLowerCase();
|
||||
|
||||
Hoek.assert(Hoek.contain(internals.cidrPresences, ipOptions.cidr), 'cidr must be one of ' + internals.cidrPresences.join(', '));
|
||||
|
||||
// If we only received a `cidr` setting, create a regex for it. But we don't need to create one if `cidr` is "optional" since that is the default
|
||||
if (!ipOptions.version && ipOptions.cidr !== 'optional') {
|
||||
regex = Ip.createIpRegex(['ipv4', 'ipv6', 'ipvfuture'], ipOptions.cidr);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
// Set our default cidr strategy
|
||||
ipOptions.cidr = 'optional';
|
||||
}
|
||||
|
||||
let versions;
|
||||
if (ipOptions.version) {
|
||||
if (!Array.isArray(ipOptions.version)) {
|
||||
ipOptions.version = [ipOptions.version];
|
||||
}
|
||||
|
||||
Hoek.assert(ipOptions.version.length >= 1, 'version must have at least 1 version specified');
|
||||
|
||||
versions = [];
|
||||
for (let i = 0; i < ipOptions.version.length; ++i) {
|
||||
let version = ipOptions.version[i];
|
||||
Hoek.assert(typeof version === 'string', 'version at position ' + i + ' must be a string');
|
||||
version = version.toLowerCase();
|
||||
Hoek.assert(Ip.versions[version], 'version at position ' + i + ' must be one of ' + Object.keys(Ip.versions).join(', '));
|
||||
versions.push(version);
|
||||
}
|
||||
|
||||
// Make sure we have a set of versions
|
||||
versions = Array.from(new Set(versions));
|
||||
|
||||
regex = Ip.createIpRegex(versions, ipOptions.cidr);
|
||||
}
|
||||
|
||||
return this._test('ip', ipOptions, function (value, state, options) {
|
||||
|
||||
if (regex.test(value)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (versions) {
|
||||
return this.createError('string.ipVersion', { value, cidr: ipOptions.cidr, version: versions }, state, options);
|
||||
}
|
||||
|
||||
return this.createError('string.ip', { value, cidr: ipOptions.cidr }, state, options);
|
||||
});
|
||||
}
|
||||
|
||||
uri(uriOptions) {
|
||||
|
||||
let customScheme = '';
|
||||
let allowRelative = false;
|
||||
let relativeOnly = false;
|
||||
let allowQuerySquareBrackets = false;
|
||||
let regex = internals.uriRegex;
|
||||
|
||||
if (uriOptions) {
|
||||
Hoek.assert(typeof uriOptions === 'object', 'options must be an object');
|
||||
|
||||
const unknownOptions = Object.keys(uriOptions).filter((key) => !['scheme', 'allowRelative', 'relativeOnly', 'allowQuerySquareBrackets'].includes(key));
|
||||
Hoek.assert(unknownOptions.length === 0, `options contain unknown keys: ${unknownOptions}`);
|
||||
|
||||
if (uriOptions.scheme) {
|
||||
Hoek.assert(uriOptions.scheme instanceof RegExp || typeof uriOptions.scheme === 'string' || Array.isArray(uriOptions.scheme), 'scheme must be a RegExp, String, or Array');
|
||||
|
||||
if (!Array.isArray(uriOptions.scheme)) {
|
||||
uriOptions.scheme = [uriOptions.scheme];
|
||||
}
|
||||
|
||||
Hoek.assert(uriOptions.scheme.length >= 1, 'scheme must have at least 1 scheme specified');
|
||||
|
||||
// Flatten the array into a string to be used to match the schemes.
|
||||
for (let i = 0; i < uriOptions.scheme.length; ++i) {
|
||||
const scheme = uriOptions.scheme[i];
|
||||
Hoek.assert(scheme instanceof RegExp || typeof scheme === 'string', 'scheme at position ' + i + ' must be a RegExp or String');
|
||||
|
||||
// Add OR separators if a value already exists
|
||||
customScheme = customScheme + (customScheme ? '|' : '');
|
||||
|
||||
// If someone wants to match HTTP or HTTPS for example then we need to support both RegExp and String so we don't escape their pattern unknowingly.
|
||||
if (scheme instanceof RegExp) {
|
||||
customScheme = customScheme + scheme.source;
|
||||
}
|
||||
else {
|
||||
Hoek.assert(/[a-zA-Z][a-zA-Z0-9+-\.]*/.test(scheme), 'scheme at position ' + i + ' must be a valid scheme');
|
||||
customScheme = customScheme + Hoek.escapeRegex(scheme);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (uriOptions.allowRelative) {
|
||||
allowRelative = true;
|
||||
}
|
||||
|
||||
if (uriOptions.relativeOnly) {
|
||||
relativeOnly = true;
|
||||
}
|
||||
|
||||
if (uriOptions.allowQuerySquareBrackets) {
|
||||
allowQuerySquareBrackets = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (customScheme || allowRelative || relativeOnly || allowQuerySquareBrackets) {
|
||||
regex = Uri.createUriRegex(customScheme, allowRelative, relativeOnly, allowQuerySquareBrackets);
|
||||
}
|
||||
|
||||
return this._test('uri', uriOptions, function (value, state, options) {
|
||||
|
||||
if (regex.test(value)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (relativeOnly) {
|
||||
return this.createError('string.uriRelativeOnly', { value }, state, options);
|
||||
}
|
||||
|
||||
if (customScheme) {
|
||||
return this.createError('string.uriCustomScheme', { scheme: customScheme, value }, state, options);
|
||||
}
|
||||
|
||||
return this.createError('string.uri', { value }, state, options);
|
||||
});
|
||||
}
|
||||
|
||||
isoDate() {
|
||||
|
||||
return this._test('isoDate', undefined, function (value, state, options) {
|
||||
|
||||
if (JoiDate._isIsoDate(value)) {
|
||||
if (!options.convert) {
|
||||
return value;
|
||||
}
|
||||
|
||||
const d = new Date(value);
|
||||
if (!isNaN(d.getTime())) {
|
||||
return d.toISOString();
|
||||
}
|
||||
}
|
||||
|
||||
return this.createError('string.isoDate', { value }, state, options);
|
||||
});
|
||||
}
|
||||
|
||||
guid(guidOptions) {
|
||||
|
||||
let versionNumbers = '';
|
||||
|
||||
if (guidOptions && guidOptions.version) {
|
||||
if (!Array.isArray(guidOptions.version)) {
|
||||
guidOptions.version = [guidOptions.version];
|
||||
}
|
||||
|
||||
Hoek.assert(guidOptions.version.length >= 1, 'version must have at least 1 valid version specified');
|
||||
const versions = new Set();
|
||||
|
||||
for (let i = 0; i < guidOptions.version.length; ++i) {
|
||||
let version = guidOptions.version[i];
|
||||
Hoek.assert(typeof version === 'string', 'version at position ' + i + ' must be a string');
|
||||
version = version.toLowerCase();
|
||||
const versionNumber = internals.guidVersions[version];
|
||||
Hoek.assert(versionNumber, 'version at position ' + i + ' must be one of ' + Object.keys(internals.guidVersions).join(', '));
|
||||
Hoek.assert(!(versions.has(versionNumber)), 'version at position ' + i + ' must not be a duplicate.');
|
||||
|
||||
versionNumbers += versionNumber;
|
||||
versions.add(versionNumber);
|
||||
}
|
||||
}
|
||||
|
||||
const guidRegex = new RegExp(`^([\\[{\\(]?)[0-9A-F]{8}([:-]?)[0-9A-F]{4}\\2?[${versionNumbers || '0-9A-F'}][0-9A-F]{3}\\2?[${versionNumbers ? '89AB' : '0-9A-F'}][0-9A-F]{3}\\2?[0-9A-F]{12}([\\]}\\)]?)$`, 'i');
|
||||
|
||||
return this._test('guid', guidOptions, function (value, state, options) {
|
||||
|
||||
const results = guidRegex.exec(value);
|
||||
|
||||
if (!results) {
|
||||
return this.createError('string.guid', { value }, state, options);
|
||||
}
|
||||
|
||||
// Matching braces
|
||||
if (internals.guidBrackets[results[1]] !== results[results.length - 1]) {
|
||||
return this.createError('string.guid', { value }, state, options);
|
||||
}
|
||||
|
||||
return value;
|
||||
});
|
||||
}
|
||||
|
||||
hex(hexOptions = {}) {
|
||||
|
||||
Hoek.assert(typeof hexOptions === 'object', 'hex options must be an object');
|
||||
Hoek.assert(typeof hexOptions.byteAligned === 'undefined' || typeof hexOptions.byteAligned === 'boolean',
|
||||
'byteAligned must be boolean');
|
||||
|
||||
const byteAligned = hexOptions.byteAligned === true;
|
||||
const regex = /^[a-f0-9]+$/i;
|
||||
|
||||
const obj = this._test('hex', regex, function (value, state, options) {
|
||||
|
||||
if (regex.test(value)) {
|
||||
if (byteAligned && value.length % 2 !== 0) {
|
||||
return this.createError('string.hexAlign', { value }, state, options);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
return this.createError('string.hex', { value }, state, options);
|
||||
});
|
||||
|
||||
if (byteAligned) {
|
||||
obj._flags.byteAligned = true;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
base64(base64Options = {}) {
|
||||
|
||||
// Validation.
|
||||
Hoek.assert(typeof base64Options === 'object', 'base64 options must be an object');
|
||||
Hoek.assert(typeof base64Options.paddingRequired === 'undefined' || typeof base64Options.paddingRequired === 'boolean',
|
||||
'paddingRequired must be boolean');
|
||||
|
||||
// Determine if padding is required.
|
||||
const paddingRequired = base64Options.paddingRequired === false ?
|
||||
base64Options.paddingRequired
|
||||
: base64Options.paddingRequired || true;
|
||||
|
||||
// Set validation based on preference.
|
||||
const regex = paddingRequired ?
|
||||
// Padding is required.
|
||||
/^(?:[A-Za-z0-9+\/]{2}[A-Za-z0-9+\/]{2})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)?$/
|
||||
// Padding is optional.
|
||||
: /^(?:[A-Za-z0-9+\/]{2}[A-Za-z0-9+\/]{2})*(?:[A-Za-z0-9+\/]{2}(==)?|[A-Za-z0-9+\/]{3}=?)?$/;
|
||||
|
||||
return this._test('base64', regex, function (value, state, options) {
|
||||
|
||||
if (regex.test(value)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return this.createError('string.base64', { value }, state, options);
|
||||
});
|
||||
}
|
||||
|
||||
dataUri(dataUriOptions = {}) {
|
||||
|
||||
const regex = /^data:[\w+.-]+\/[\w+.-]+;((charset=[\w-]+|base64),)?(.*)$/;
|
||||
|
||||
// Determine if padding is required.
|
||||
const paddingRequired = dataUriOptions.paddingRequired === false ?
|
||||
dataUriOptions.paddingRequired
|
||||
: dataUriOptions.paddingRequired || true;
|
||||
|
||||
const base64regex = paddingRequired ?
|
||||
/^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=)?$/
|
||||
: /^(?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}(==)?|[A-Za-z0-9+\/]{3}=?)?$/;
|
||||
|
||||
return this._test('dataUri', regex, function (value, state, options) {
|
||||
|
||||
const matches = value.match(regex);
|
||||
|
||||
if (matches) {
|
||||
if (!matches[2]) {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (matches[2] !== 'base64') {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (base64regex.test(matches[3])) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
return this.createError('string.dataUri', { value }, state, options);
|
||||
});
|
||||
}
|
||||
|
||||
hostname() {
|
||||
|
||||
const regex = /^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$/;
|
||||
|
||||
return this._test('hostname', undefined, function (value, state, options) {
|
||||
|
||||
if ((value.length <= 255 && regex.test(value)) ||
|
||||
Net.isIPv6(value)) {
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
return this.createError('string.hostname', { value }, state, options);
|
||||
});
|
||||
}
|
||||
|
||||
normalize(form = 'NFC') {
|
||||
|
||||
Hoek.assert(Hoek.contain(internals.normalizationForms, form), 'normalization form must be one of ' + internals.normalizationForms.join(', '));
|
||||
|
||||
const obj = this._test('normalize', form, function (value, state, options) {
|
||||
|
||||
if (options.convert ||
|
||||
value === value.normalize(form)) {
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
return this.createError('string.normalize', { value, form }, state, options);
|
||||
});
|
||||
|
||||
obj._flags.normalize = form;
|
||||
return obj;
|
||||
}
|
||||
|
||||
lowercase() {
|
||||
|
||||
const obj = this._test('lowercase', undefined, function (value, state, options) {
|
||||
|
||||
if (options.convert ||
|
||||
value === value.toLocaleLowerCase()) {
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
return this.createError('string.lowercase', { value }, state, options);
|
||||
});
|
||||
|
||||
obj._flags.case = 'lower';
|
||||
return obj;
|
||||
}
|
||||
|
||||
uppercase() {
|
||||
|
||||
const obj = this._test('uppercase', undefined, function (value, state, options) {
|
||||
|
||||
if (options.convert ||
|
||||
value === value.toLocaleUpperCase()) {
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
return this.createError('string.uppercase', { value }, state, options);
|
||||
});
|
||||
|
||||
obj._flags.case = 'upper';
|
||||
return obj;
|
||||
}
|
||||
|
||||
trim(enabled = true) {
|
||||
|
||||
Hoek.assert(typeof enabled === 'boolean', 'option must be a boolean');
|
||||
|
||||
if ((this._flags.trim && enabled) || (!this._flags.trim && !enabled)) {
|
||||
return this;
|
||||
}
|
||||
|
||||
let obj;
|
||||
if (enabled) {
|
||||
obj = this._test('trim', undefined, function (value, state, options) {
|
||||
|
||||
if (options.convert ||
|
||||
value === value.trim()) {
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
return this.createError('string.trim', { value }, state, options);
|
||||
});
|
||||
}
|
||||
else {
|
||||
obj = this.clone();
|
||||
obj._tests = obj._tests.filter((test) => test.name !== 'trim');
|
||||
}
|
||||
|
||||
obj._flags.trim = enabled;
|
||||
return obj;
|
||||
}
|
||||
|
||||
replace(pattern, replacement) {
|
||||
|
||||
if (typeof pattern === 'string') {
|
||||
pattern = new RegExp(Hoek.escapeRegex(pattern), 'g');
|
||||
}
|
||||
|
||||
Hoek.assert(pattern instanceof RegExp, 'pattern must be a RegExp');
|
||||
Hoek.assert(typeof replacement === 'string', 'replacement must be a String');
|
||||
|
||||
// This can not be considere a test like trim, we can't "reject"
|
||||
// anything from this rule, so just clone the current object
|
||||
const obj = this.clone();
|
||||
|
||||
if (!obj._inner.replacements) {
|
||||
obj._inner.replacements = [];
|
||||
}
|
||||
|
||||
obj._inner.replacements.push({
|
||||
pattern,
|
||||
replacement
|
||||
});
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
truncate(enabled) {
|
||||
|
||||
const value = enabled === undefined ? true : !!enabled;
|
||||
|
||||
if (this._flags.truncate === value) {
|
||||
return this;
|
||||
}
|
||||
|
||||
const obj = this.clone();
|
||||
obj._flags.truncate = value;
|
||||
return obj;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
internals.compare = function (type, compare) {
|
||||
|
||||
return function (limit, encoding) {
|
||||
|
||||
const isRef = Ref.isRef(limit);
|
||||
|
||||
Hoek.assert((Number.isSafeInteger(limit) && limit >= 0) || isRef, 'limit must be a positive integer or reference');
|
||||
Hoek.assert(!encoding || Buffer.isEncoding(encoding), 'Invalid encoding:', encoding);
|
||||
|
||||
return this._test(type, limit, function (value, state, options) {
|
||||
|
||||
let compareTo;
|
||||
if (isRef) {
|
||||
compareTo = limit(state.reference || state.parent, options);
|
||||
|
||||
if (!Number.isSafeInteger(compareTo)) {
|
||||
return this.createError('string.ref', { ref: limit, value: compareTo }, state, options);
|
||||
}
|
||||
}
|
||||
else {
|
||||
compareTo = limit;
|
||||
}
|
||||
|
||||
if (compare(value, compareTo, encoding)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return this.createError('string.' + type, { limit: compareTo, value, encoding }, state, options);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
internals.String.prototype.min = internals.compare('min', (value, limit, encoding) => {
|
||||
|
||||
const length = encoding ? Buffer.byteLength(value, encoding) : value.length;
|
||||
return length >= limit;
|
||||
});
|
||||
|
||||
|
||||
internals.String.prototype.max = internals.compare('max', (value, limit, encoding) => {
|
||||
|
||||
const length = encoding ? Buffer.byteLength(value, encoding) : value.length;
|
||||
return length <= limit;
|
||||
});
|
||||
|
||||
|
||||
internals.String.prototype.length = internals.compare('length', (value, limit, encoding) => {
|
||||
|
||||
const length = encoding ? Buffer.byteLength(value, encoding) : value.length;
|
||||
return length === limit;
|
||||
});
|
||||
|
||||
// Aliases
|
||||
|
||||
internals.String.prototype.uuid = internals.String.prototype.guid;
|
||||
|
||||
module.exports = new internals.String();
|
50
web/node_modules/@hapi/joi/lib/types/string/ip.js
generated
vendored
Executable file
50
web/node_modules/@hapi/joi/lib/types/string/ip.js
generated
vendored
Executable file
|
@ -0,0 +1,50 @@
|
|||
'use strict';
|
||||
|
||||
const RFC3986 = require('./rfc3986');
|
||||
|
||||
|
||||
const internals = {
|
||||
Ip: {
|
||||
cidrs: {
|
||||
ipv4: {
|
||||
required: '\\/(?:' + RFC3986.ipv4Cidr + ')',
|
||||
optional: '(?:\\/(?:' + RFC3986.ipv4Cidr + '))?',
|
||||
forbidden: ''
|
||||
},
|
||||
ipv6: {
|
||||
required: '\\/' + RFC3986.ipv6Cidr,
|
||||
optional: '(?:\\/' + RFC3986.ipv6Cidr + ')?',
|
||||
forbidden: ''
|
||||
},
|
||||
ipvfuture: {
|
||||
required: '\\/' + RFC3986.ipv6Cidr,
|
||||
optional: '(?:\\/' + RFC3986.ipv6Cidr + ')?',
|
||||
forbidden: ''
|
||||
}
|
||||
},
|
||||
versions: {
|
||||
ipv4: RFC3986.IPv4address,
|
||||
ipv6: RFC3986.IPv6address,
|
||||
ipvfuture: RFC3986.IPvFuture
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
internals.Ip.createIpRegex = function (versions, cidr) {
|
||||
|
||||
let regex;
|
||||
for (let i = 0; i < versions.length; ++i) {
|
||||
const version = versions[i];
|
||||
if (!regex) {
|
||||
regex = '^(?:' + internals.Ip.versions[version] + internals.Ip.cidrs[version][cidr];
|
||||
}
|
||||
else {
|
||||
regex += '|' + internals.Ip.versions[version] + internals.Ip.cidrs[version][cidr];
|
||||
}
|
||||
}
|
||||
|
||||
return new RegExp(regex + ')$');
|
||||
};
|
||||
|
||||
module.exports = internals.Ip;
|
214
web/node_modules/@hapi/joi/lib/types/string/rfc3986.js
generated
vendored
Executable file
214
web/node_modules/@hapi/joi/lib/types/string/rfc3986.js
generated
vendored
Executable file
|
@ -0,0 +1,214 @@
|
|||
'use strict';
|
||||
|
||||
const internals = {
|
||||
rfc3986: {}
|
||||
};
|
||||
|
||||
|
||||
internals.generate = function () {
|
||||
|
||||
/**
|
||||
* elements separated by forward slash ("/") are alternatives.
|
||||
*/
|
||||
const or = '|';
|
||||
|
||||
/**
|
||||
* Rule to support zero-padded addresses.
|
||||
*/
|
||||
const zeroPad = '0?';
|
||||
|
||||
/**
|
||||
* DIGIT = %x30-39 ; 0-9
|
||||
*/
|
||||
const digit = '0-9';
|
||||
const digitOnly = '[' + digit + ']';
|
||||
|
||||
/**
|
||||
* ALPHA = %x41-5A / %x61-7A ; A-Z / a-z
|
||||
*/
|
||||
const alpha = 'a-zA-Z';
|
||||
const alphaOnly = '[' + alpha + ']';
|
||||
|
||||
/**
|
||||
* IPv4
|
||||
* cidr = DIGIT ; 0-9
|
||||
* / %x31-32 DIGIT ; 10-29
|
||||
* / "3" %x30-32 ; 30-32
|
||||
*/
|
||||
internals.rfc3986.ipv4Cidr = digitOnly + or + '[1-2]' + digitOnly + or + '3' + '[0-2]';
|
||||
|
||||
/**
|
||||
* IPv6
|
||||
* cidr = DIGIT ; 0-9
|
||||
* / %x31-39 DIGIT ; 10-99
|
||||
* / "1" %x0-1 DIGIT ; 100-119
|
||||
* / "12" %x0-8 ; 120-128
|
||||
*/
|
||||
internals.rfc3986.ipv6Cidr = '(?:' + zeroPad + zeroPad + digitOnly + or + zeroPad + '[1-9]' + digitOnly + or + '1' + '[01]' + digitOnly + or + '12[0-8])';
|
||||
|
||||
/**
|
||||
* HEXDIG = DIGIT / "A" / "B" / "C" / "D" / "E" / "F"
|
||||
*/
|
||||
const hexDigit = digit + 'A-Fa-f';
|
||||
const hexDigitOnly = '[' + hexDigit + ']';
|
||||
|
||||
/**
|
||||
* unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
|
||||
*/
|
||||
const unreserved = alpha + digit + '-\\._~';
|
||||
|
||||
/**
|
||||
* sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
|
||||
*/
|
||||
const subDelims = '!\\$&\'\\(\\)\\*\\+,;=';
|
||||
|
||||
/**
|
||||
* pct-encoded = "%" HEXDIG HEXDIG
|
||||
*/
|
||||
const pctEncoded = '%' + hexDigit;
|
||||
|
||||
/**
|
||||
* pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
|
||||
*/
|
||||
const pchar = unreserved + pctEncoded + subDelims + ':@';
|
||||
const pcharOnly = '[' + pchar + ']';
|
||||
|
||||
/**
|
||||
* squareBrackets example: []
|
||||
*/
|
||||
const squareBrackets = '\\[\\]';
|
||||
|
||||
/**
|
||||
* dec-octet = DIGIT ; 0-9
|
||||
* / %x31-39 DIGIT ; 10-99
|
||||
* / "1" 2DIGIT ; 100-199
|
||||
* / "2" %x30-34 DIGIT ; 200-249
|
||||
* / "25" %x30-35 ; 250-255
|
||||
*/
|
||||
const decOctect = '(?:' + zeroPad + zeroPad + digitOnly + or + zeroPad + '[1-9]' + digitOnly + or + '1' + digitOnly + digitOnly + or + '2' + '[0-4]' + digitOnly + or + '25' + '[0-5])';
|
||||
|
||||
/**
|
||||
* IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
|
||||
*/
|
||||
internals.rfc3986.IPv4address = '(?:' + decOctect + '\\.){3}' + decOctect;
|
||||
|
||||
/**
|
||||
* h16 = 1*4HEXDIG ; 16 bits of address represented in hexadecimal
|
||||
* ls32 = ( h16 ":" h16 ) / IPv4address ; least-significant 32 bits of address
|
||||
* IPv6address = 6( h16 ":" ) ls32
|
||||
* / "::" 5( h16 ":" ) ls32
|
||||
* / [ h16 ] "::" 4( h16 ":" ) ls32
|
||||
* / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
|
||||
* / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
|
||||
* / [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32
|
||||
* / [ *4( h16 ":" ) h16 ] "::" ls32
|
||||
* / [ *5( h16 ":" ) h16 ] "::" h16
|
||||
* / [ *6( h16 ":" ) h16 ] "::"
|
||||
*/
|
||||
const h16 = hexDigitOnly + '{1,4}';
|
||||
const ls32 = '(?:' + h16 + ':' + h16 + '|' + internals.rfc3986.IPv4address + ')';
|
||||
const IPv6SixHex = '(?:' + h16 + ':){6}' + ls32;
|
||||
const IPv6FiveHex = '::(?:' + h16 + ':){5}' + ls32;
|
||||
const IPv6FourHex = '(?:' + h16 + ')?::(?:' + h16 + ':){4}' + ls32;
|
||||
const IPv6ThreeHex = '(?:(?:' + h16 + ':){0,1}' + h16 + ')?::(?:' + h16 + ':){3}' + ls32;
|
||||
const IPv6TwoHex = '(?:(?:' + h16 + ':){0,2}' + h16 + ')?::(?:' + h16 + ':){2}' + ls32;
|
||||
const IPv6OneHex = '(?:(?:' + h16 + ':){0,3}' + h16 + ')?::' + h16 + ':' + ls32;
|
||||
const IPv6NoneHex = '(?:(?:' + h16 + ':){0,4}' + h16 + ')?::' + ls32;
|
||||
const IPv6NoneHex2 = '(?:(?:' + h16 + ':){0,5}' + h16 + ')?::' + h16;
|
||||
const IPv6NoneHex3 = '(?:(?:' + h16 + ':){0,6}' + h16 + ')?::';
|
||||
internals.rfc3986.IPv6address = '(?:' + IPv6SixHex + or + IPv6FiveHex + or + IPv6FourHex + or + IPv6ThreeHex + or + IPv6TwoHex + or + IPv6OneHex + or + IPv6NoneHex + or + IPv6NoneHex2 + or + IPv6NoneHex3 + ')';
|
||||
|
||||
/**
|
||||
* IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
|
||||
*/
|
||||
internals.rfc3986.IPvFuture = 'v' + hexDigitOnly + '+\\.[' + unreserved + subDelims + ':]+';
|
||||
|
||||
/**
|
||||
* scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
|
||||
*/
|
||||
internals.rfc3986.scheme = alphaOnly + '[' + alpha + digit + '+-\\.]*';
|
||||
|
||||
/**
|
||||
* userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
|
||||
*/
|
||||
const userinfo = '[' + unreserved + pctEncoded + subDelims + ':]*';
|
||||
|
||||
/**
|
||||
* IP-literal = "[" ( IPv6address / IPvFuture ) "]"
|
||||
*/
|
||||
const IPLiteral = '\\[(?:' + internals.rfc3986.IPv6address + or + internals.rfc3986.IPvFuture + ')\\]';
|
||||
|
||||
/**
|
||||
* reg-name = *( unreserved / pct-encoded / sub-delims )
|
||||
*/
|
||||
const regName = '[' + unreserved + pctEncoded + subDelims + ']{0,255}';
|
||||
|
||||
/**
|
||||
* host = IP-literal / IPv4address / reg-name
|
||||
*/
|
||||
const host = '(?:' + IPLiteral + or + internals.rfc3986.IPv4address + or + regName + ')';
|
||||
|
||||
/**
|
||||
* port = *DIGIT
|
||||
*/
|
||||
const port = digitOnly + '*';
|
||||
|
||||
/**
|
||||
* authority = [ userinfo "@" ] host [ ":" port ]
|
||||
*/
|
||||
const authority = '(?:' + userinfo + '@)?' + host + '(?::' + port + ')?';
|
||||
|
||||
/**
|
||||
* segment = *pchar
|
||||
* segment-nz = 1*pchar
|
||||
* path = path-abempty ; begins with "/" or is empty
|
||||
* / path-absolute ; begins with "/" but not "//"
|
||||
* / path-noscheme ; begins with a non-colon segment
|
||||
* / path-rootless ; begins with a segment
|
||||
* / path-empty ; zero characters
|
||||
* path-abempty = *( "/" segment )
|
||||
* path-absolute = "/" [ segment-nz *( "/" segment ) ]
|
||||
* path-rootless = segment-nz *( "/" segment )
|
||||
*/
|
||||
const segment = pcharOnly + '*';
|
||||
const segmentNz = pcharOnly + '+';
|
||||
const segmentNzNc = '[' + unreserved + pctEncoded + subDelims + '@' + ']+';
|
||||
const pathEmpty = '';
|
||||
const pathAbEmpty = '(?:\\/' + segment + ')*';
|
||||
const pathAbsolute = '\\/(?:' + segmentNz + pathAbEmpty + ')?';
|
||||
const pathRootless = segmentNz + pathAbEmpty;
|
||||
const pathNoScheme = segmentNzNc + pathAbEmpty;
|
||||
|
||||
/**
|
||||
* hier-part = "//" authority path
|
||||
*/
|
||||
internals.rfc3986.hierPart = '(?:' + '(?:\\/\\/' + authority + pathAbEmpty + ')' + or + pathAbsolute + or + pathRootless + ')';
|
||||
|
||||
/**
|
||||
* relative-part = "//" authority path-abempty
|
||||
* / path-absolute
|
||||
* / path-noscheme
|
||||
* / path-empty
|
||||
*/
|
||||
internals.rfc3986.relativeRef = '(?:' + '(?:\\/\\/' + authority + pathAbEmpty + ')' + or + pathAbsolute + or + pathNoScheme + or + pathEmpty + ')';
|
||||
|
||||
/**
|
||||
* query = *( pchar / "/" / "?" )
|
||||
*/
|
||||
internals.rfc3986.query = '[' + pchar + '\\/\\?]*(?=#|$)'; //Finish matching either at the fragment part or end of the line.
|
||||
|
||||
/**
|
||||
* query = *( pchar / "[" / "]" / "/" / "?" )
|
||||
*/
|
||||
internals.rfc3986.queryWithSquareBrackets = '[' + pchar + squareBrackets + '\\/\\?]*(?=#|$)'; //Finish matching either at the fragment part or end of the line.
|
||||
|
||||
/**
|
||||
* fragment = *( pchar / "/" / "?" )
|
||||
*/
|
||||
internals.rfc3986.fragment = '[' + pchar + '\\/\\?]*';
|
||||
};
|
||||
|
||||
|
||||
internals.generate();
|
||||
|
||||
module.exports = internals.rfc3986;
|
41
web/node_modules/@hapi/joi/lib/types/string/uri.js
generated
vendored
Executable file
41
web/node_modules/@hapi/joi/lib/types/string/uri.js
generated
vendored
Executable file
|
@ -0,0 +1,41 @@
|
|||
'use strict';
|
||||
|
||||
const RFC3986 = require('./rfc3986');
|
||||
|
||||
|
||||
const internals = {
|
||||
Uri: {
|
||||
createUriRegex: function (optionalScheme, allowRelative, relativeOnly, allowQuerySquareBrackets) {
|
||||
|
||||
let scheme = RFC3986.scheme;
|
||||
let prefix;
|
||||
|
||||
if (relativeOnly) {
|
||||
prefix = '(?:' + RFC3986.relativeRef + ')';
|
||||
}
|
||||
else {
|
||||
// If we were passed a scheme, use it instead of the generic one
|
||||
if (optionalScheme) {
|
||||
|
||||
// Have to put this in a non-capturing group to handle the OR statements
|
||||
scheme = '(?:' + optionalScheme + ')';
|
||||
}
|
||||
|
||||
const withScheme = '(?:' + scheme + ':' + RFC3986.hierPart + ')';
|
||||
|
||||
prefix = allowRelative ? '(?:' + withScheme + '|' + RFC3986.relativeRef + ')' : withScheme;
|
||||
}
|
||||
|
||||
/**
|
||||
* URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
|
||||
*
|
||||
* OR
|
||||
*
|
||||
* relative-ref = relative-part [ "?" query ] [ "#" fragment ]
|
||||
*/
|
||||
return new RegExp('^' + prefix + '(?:\\?' + (allowQuerySquareBrackets ? RFC3986.queryWithSquareBrackets : RFC3986.query) + ')?' + '(?:#' + RFC3986.fragment + ')?$');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = internals.Uri;
|
90
web/node_modules/@hapi/joi/lib/types/symbol/index.js
generated
vendored
Executable file
90
web/node_modules/@hapi/joi/lib/types/symbol/index.js
generated
vendored
Executable file
|
@ -0,0 +1,90 @@
|
|||
'use strict';
|
||||
|
||||
const Util = require('util');
|
||||
|
||||
const Hoek = require('@hapi/hoek');
|
||||
|
||||
const Any = require('../any');
|
||||
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
internals.Map = class extends Map {
|
||||
|
||||
slice() {
|
||||
|
||||
return new internals.Map(this);
|
||||
}
|
||||
|
||||
toString() {
|
||||
|
||||
return Util.inspect(this);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
internals.Symbol = class extends Any {
|
||||
|
||||
constructor() {
|
||||
|
||||
super();
|
||||
this._type = 'symbol';
|
||||
this._inner.map = new internals.Map();
|
||||
}
|
||||
|
||||
_base(value, state, options) {
|
||||
|
||||
if (options.convert) {
|
||||
const lookup = this._inner.map.get(value);
|
||||
if (lookup) {
|
||||
value = lookup;
|
||||
}
|
||||
|
||||
if (this._flags.allowOnly) {
|
||||
return {
|
||||
value,
|
||||
errors: (typeof value === 'symbol') ? null : this.createError('symbol.map', { value, map: this._inner.map }, state, options)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
value,
|
||||
errors: (typeof value === 'symbol') ? null : this.createError('symbol.base', { value }, state, options)
|
||||
};
|
||||
}
|
||||
|
||||
map(iterable) {
|
||||
|
||||
if (iterable && !iterable[Symbol.iterator] && typeof iterable === 'object') {
|
||||
iterable = Object.entries(iterable);
|
||||
}
|
||||
|
||||
Hoek.assert(iterable && iterable[Symbol.iterator], 'Iterable must be an iterable or object');
|
||||
const obj = this.clone();
|
||||
|
||||
const symbols = [];
|
||||
for (const entry of iterable) {
|
||||
Hoek.assert(entry && entry[Symbol.iterator], 'Entry must be an iterable');
|
||||
const [key, value] = entry;
|
||||
|
||||
Hoek.assert(typeof key !== 'object' && typeof key !== 'function' && typeof key !== 'symbol', 'Key must not be an object, function, or Symbol');
|
||||
Hoek.assert(typeof value === 'symbol', 'Value must be a Symbol');
|
||||
obj._inner.map.set(key, value);
|
||||
symbols.push(value);
|
||||
}
|
||||
|
||||
return obj.valid(...symbols);
|
||||
}
|
||||
|
||||
describe() {
|
||||
|
||||
const description = super.describe();
|
||||
description.map = new Map(this._inner.map);
|
||||
return description;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
module.exports = new internals.Symbol();
|
8
web/node_modules/@hapi/joi/lib/types/symbols.js
generated
vendored
Executable file
8
web/node_modules/@hapi/joi/lib/types/symbols.js
generated
vendored
Executable file
|
@ -0,0 +1,8 @@
|
|||
'use strict';
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
module.exports = {
|
||||
settingsCache: Symbol('settingsCache')
|
||||
};
|
27
web/node_modules/@hapi/joi/package.json
generated
vendored
Normal file
27
web/node_modules/@hapi/joi/package.json
generated
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"name": "@hapi/joi",
|
||||
"description": "Object schema validation",
|
||||
"version": "15.1.1",
|
||||
"homepage": "https://github.com/hapijs/joi",
|
||||
"repository": "git://github.com/hapijs/joi",
|
||||
"main": "lib/index.js",
|
||||
"keywords": [
|
||||
"schema",
|
||||
"validation"
|
||||
],
|
||||
"dependencies": {
|
||||
"@hapi/address": "2.x.x",
|
||||
"@hapi/bourne": "1.x.x",
|
||||
"@hapi/hoek": "8.x.x",
|
||||
"@hapi/topo": "3.x.x"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@hapi/code": "6.x.x",
|
||||
"@hapi/lab": "20.x.x"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "lab -t 100 -a @hapi/code -L",
|
||||
"test-cov-html": "lab -r html -o coverage.html -a @hapi/code"
|
||||
},
|
||||
"license": "BSD-3-Clause"
|
||||
}
|
3
web/node_modules/@hapi/topo/CHANGELOG.md
generated
vendored
Normal file
3
web/node_modules/@hapi/topo/CHANGELOG.md
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
Breaking changes are documented using GitHub issues, see [issues labeled "release notes"](https://github.com/hapijs/topo/issues?q=is%3Aissue+label%3A%22release+notes%22).
|
||||
|
||||
If you want changes of a specific minor or patch release, you can browse the [GitHub milestones](https://github.com/hapijs/topo/milestones?state=closed&direction=asc&sort=due_date).
|
10
web/node_modules/@hapi/topo/LICENSE.md
generated
vendored
Executable file
10
web/node_modules/@hapi/topo/LICENSE.md
generated
vendored
Executable file
|
@ -0,0 +1,10 @@
|
|||
Copyright (c) 2012-2019, Sideway Inc, and project contributors
|
||||
Copyright (c) 2012-2014, Walmart.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* The names of any contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS OFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
web/node_modules/@hapi/topo/README.md
generated
vendored
Executable file
29
web/node_modules/@hapi/topo/README.md
generated
vendored
Executable file
|
@ -0,0 +1,29 @@
|
|||
<a href="http://hapijs.com"><img src="https://raw.githubusercontent.com/hapijs/assets/master/images/family.png" width="180px" align="right" /></a>
|
||||
|
||||
# @hapi/topo
|
||||
|
||||
Topological sorting with grouping support.
|
||||
|
||||
[](http://travis-ci.org/hapijs/topo)
|
||||
|
||||
## Usage
|
||||
|
||||
See the [API Reference](API.md)
|
||||
|
||||
**Example**
|
||||
```js
|
||||
const Topo = require('topo');
|
||||
|
||||
const morning = new Topo();
|
||||
|
||||
morning.add('Nap', { after: ['breakfast', 'prep'] });
|
||||
|
||||
morning.add([
|
||||
'Make toast',
|
||||
'Pour juice'
|
||||
], { before: 'breakfast', group: 'prep' });
|
||||
|
||||
morning.add('Eat breakfast', { group: 'breakfast' });
|
||||
|
||||
morning.nodes; // ['Make toast', 'Pour juice', 'Eat breakfast', 'Nap']
|
||||
```
|
215
web/node_modules/@hapi/topo/lib/index.js
generated
vendored
Executable file
215
web/node_modules/@hapi/topo/lib/index.js
generated
vendored
Executable file
|
@ -0,0 +1,215 @@
|
|||
'use strict';
|
||||
|
||||
const Assert = require('@hapi/hoek/lib/assert');
|
||||
|
||||
|
||||
const internals = {};
|
||||
|
||||
|
||||
module.exports = class Topo {
|
||||
|
||||
constructor() {
|
||||
|
||||
this._items = [];
|
||||
this.nodes = [];
|
||||
}
|
||||
|
||||
add(nodes, options) {
|
||||
|
||||
options = options || {};
|
||||
|
||||
// Validate rules
|
||||
|
||||
const before = [].concat(options.before || []);
|
||||
const after = [].concat(options.after || []);
|
||||
const group = options.group || '?';
|
||||
const sort = options.sort || 0; // Used for merging only
|
||||
|
||||
Assert(!before.includes(group), `Item cannot come before itself: ${group}`);
|
||||
Assert(!before.includes('?'), 'Item cannot come before unassociated items');
|
||||
Assert(!after.includes(group), `Item cannot come after itself: ${group}`);
|
||||
Assert(!after.includes('?'), 'Item cannot come after unassociated items');
|
||||
|
||||
if (!Array.isArray(nodes)) {
|
||||
nodes = [nodes];
|
||||
}
|
||||
|
||||
for (const node of nodes) {
|
||||
const item = {
|
||||
seq: this._items.length,
|
||||
sort,
|
||||
before,
|
||||
after,
|
||||
group,
|
||||
node
|
||||
};
|
||||
|
||||
this._items.push(item);
|
||||
}
|
||||
|
||||
// Insert event
|
||||
|
||||
const valid = this._sort();
|
||||
Assert(valid, 'item', group !== '?' ? `added into group ${group}` : '', 'created a dependencies error');
|
||||
|
||||
return this.nodes;
|
||||
}
|
||||
|
||||
merge(others) {
|
||||
|
||||
if (!Array.isArray(others)) {
|
||||
others = [others];
|
||||
}
|
||||
|
||||
for (const other of others) {
|
||||
if (other) {
|
||||
for (const item of other._items) {
|
||||
this._items.push(Object.assign({}, item)); // Shallow cloned
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort items
|
||||
|
||||
this._items.sort(internals.mergeSort);
|
||||
for (let i = 0; i < this._items.length; ++i) {
|
||||
this._items[i].seq = i;
|
||||
}
|
||||
|
||||
const valid = this._sort();
|
||||
Assert(valid, 'merge created a dependencies error');
|
||||
|
||||
return this.nodes;
|
||||
}
|
||||
|
||||
_sort() {
|
||||
|
||||
// Construct graph
|
||||
|
||||
const graph = {};
|
||||
const graphAfters = Object.create(null); // A prototype can bungle lookups w/ false positives
|
||||
const groups = Object.create(null);
|
||||
|
||||
for (const item of this._items) {
|
||||
const seq = item.seq; // Unique across all items
|
||||
const group = item.group;
|
||||
|
||||
// Determine Groups
|
||||
|
||||
groups[group] = groups[group] || [];
|
||||
groups[group].push(seq);
|
||||
|
||||
// Build intermediary graph using 'before'
|
||||
|
||||
graph[seq] = item.before;
|
||||
|
||||
// Build second intermediary graph with 'after'
|
||||
|
||||
for (const after of item.after) {
|
||||
graphAfters[after] = graphAfters[after] || [];
|
||||
graphAfters[after].push(seq);
|
||||
}
|
||||
}
|
||||
|
||||
// Expand intermediary graph
|
||||
|
||||
for (const node in graph) {
|
||||
const expandedGroups = [];
|
||||
|
||||
for (const graphNodeItem in graph[node]) {
|
||||
const group = graph[node][graphNodeItem];
|
||||
groups[group] = groups[group] || [];
|
||||
expandedGroups.push(...groups[group]);
|
||||
}
|
||||
|
||||
graph[node] = expandedGroups;
|
||||
}
|
||||
|
||||
// Merge intermediary graph using graphAfters into final graph
|
||||
|
||||
for (const group in graphAfters) {
|
||||
if (groups[group]) {
|
||||
for (const node of groups[group]) {
|
||||
graph[node].push(...graphAfters[group]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Compile ancestors
|
||||
|
||||
const ancestors = {};
|
||||
for (const node in graph) {
|
||||
const children = graph[node];
|
||||
for (const child of children) {
|
||||
ancestors[child] = ancestors[child] || [];
|
||||
ancestors[child].push(node);
|
||||
}
|
||||
}
|
||||
|
||||
// Topo sort
|
||||
|
||||
const visited = {};
|
||||
const sorted = [];
|
||||
|
||||
for (let i = 0; i < this._items.length; ++i) { // Looping through item.seq values out of order
|
||||
let next = i;
|
||||
|
||||
if (ancestors[i]) {
|
||||
next = null;
|
||||
for (let j = 0; j < this._items.length; ++j) { // As above, these are item.seq values
|
||||
if (visited[j] === true) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ancestors[j]) {
|
||||
ancestors[j] = [];
|
||||
}
|
||||
|
||||
const shouldSeeCount = ancestors[j].length;
|
||||
let seenCount = 0;
|
||||
for (let k = 0; k < shouldSeeCount; ++k) {
|
||||
if (visited[ancestors[j][k]]) {
|
||||
++seenCount;
|
||||
}
|
||||
}
|
||||
|
||||
if (seenCount === shouldSeeCount) {
|
||||
next = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (next !== null) {
|
||||
visited[next] = true;
|
||||
sorted.push(next);
|
||||
}
|
||||
}
|
||||
|
||||
if (sorted.length !== this._items.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const seqIndex = {};
|
||||
for (const item of this._items) {
|
||||
seqIndex[item.seq] = item;
|
||||
}
|
||||
|
||||
this._items = [];
|
||||
this.nodes = [];
|
||||
|
||||
for (const value of sorted) {
|
||||
const sortedItem = seqIndex[value];
|
||||
this.nodes.push(sortedItem.node);
|
||||
this._items.push(sortedItem);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
internals.mergeSort = (a, b) => {
|
||||
|
||||
return a.sort === b.sort ? 0 : (a.sort < b.sort ? -1 : 1);
|
||||
};
|
28
web/node_modules/@hapi/topo/package.json
generated
vendored
Executable file
28
web/node_modules/@hapi/topo/package.json
generated
vendored
Executable file
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"name": "@hapi/topo",
|
||||
"description": "Topological sorting with grouping support",
|
||||
"version": "3.1.6",
|
||||
"repository": "git://github.com/hapijs/topo",
|
||||
"main": "lib/index.js",
|
||||
"keywords": [
|
||||
"topological",
|
||||
"sort",
|
||||
"toposort",
|
||||
"topsort"
|
||||
],
|
||||
"files": [
|
||||
"lib"
|
||||
],
|
||||
"dependencies": {
|
||||
"@hapi/hoek": "^8.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@hapi/code": "6.x.x",
|
||||
"@hapi/lab": "20.x.x"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "lab -a @hapi/code -t 100 -L",
|
||||
"test-cov-html": "lab -a @hapi/code -t 100 -L -r html -o coverage.html"
|
||||
},
|
||||
"license": "BSD-3-Clause"
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue