diff --git a/.coveralls.yml b/.coveralls.yml deleted file mode 100644 index e69de29..0000000 diff --git a/.github/workflows/nodejs-ci.yml b/.github/workflows/nodejs-ci.yml index 05a9a9c..f7f9c03 100644 --- a/.github/workflows/nodejs-ci.yml +++ b/.github/workflows/nodejs-ci.yml @@ -20,11 +20,18 @@ jobs: # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ steps: - - uses: actions/checkout@v2 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node-version }} - - run: npm ci - - run: npm run build --if-present - - run: npm test + - uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - run: npm ci + - run: npm run build --if-present + - run: npm test + + - name: Coveralls GitHub Action + uses: coverallsapp/github-action@v1.1.2 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + + diff --git a/.gitignore b/.gitignore index ee1cd6c..eaf8538 100644 --- a/.gitignore +++ b/.gitignore @@ -40,4 +40,5 @@ lib es .vscode -yarn.lock \ No newline at end of file +yarn.lock +.DS_Store \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index fa717a7..d907436 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1265,6 +1265,83 @@ } } }, + "@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "dependencies": { + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + } + } + }, + "@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true + }, "@nicolo-ribaudo/chokidar-2": { "version": "2.1.8-no-fsevents", "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.tgz", @@ -1704,6 +1781,15 @@ "buffer-equal": "^1.0.0" } }, + "append-transform": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", + "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", + "dev": true, + "requires": { + "default-require-extensions": "^3.0.0" + } + }, "aproba": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", @@ -2354,6 +2440,35 @@ "unset-value": "^1.0.0" } }, + "caching-transform": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz", + "integrity": "sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==", + "dev": true, + "requires": { + "hasha": "^5.0.0", + "make-dir": "^3.0.0", + "package-hash": "^4.0.0", + "write-file-atomic": "^3.0.0" + }, + "dependencies": { + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, "call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", @@ -3285,23 +3400,148 @@ "dev": true }, "coveralls": { - "version": "2.13.3", - "resolved": "https://registry.npmjs.org/coveralls/-/coveralls-2.13.3.tgz", - "integrity": "sha512-iiAmn+l1XqRwNLXhW8Rs5qHZRFMYp9ZIPjEOVRpC/c4so6Y/f4/lFi0FfR5B9cCqgyhkJ5cZmbvcVRfP8MHchw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/coveralls/-/coveralls-3.1.0.tgz", + "integrity": "sha512-sHxOu2ELzW8/NC1UP5XVLbZDzO4S3VxfFye3XYCznopHy02YjNkHcj5bKaVw2O7hVaBdBjEdQGpie4II1mWhuQ==", "dev": true, "requires": { - "js-yaml": "3.6.1", - "lcov-parse": "0.0.10", - "log-driver": "1.2.5", - "minimist": "1.2.0", - "request": "2.79.0" + "js-yaml": "^3.13.1", + "lcov-parse": "^1.0.0", + "log-driver": "^1.2.7", + "minimist": "^1.2.5", + "request": "^2.88.2" }, "dependencies": { - "minimist": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "dev": true, + "requires": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + } + }, + "http-signature": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", "dev": true + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true + }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + } + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } } } }, @@ -3467,6 +3707,23 @@ } } }, + "default-require-extensions": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.0.tgz", + "integrity": "sha512-ek6DpXq/SCpvjhpFsLFRVtIxJCRw6fUR42lYMVZuUMK7n8eMz4Uh5clckdBjEpLhn/gEBZo7hDJnJcwdKLKQjg==", + "dev": true, + "requires": { + "strip-bom": "^4.0.0" + }, + "dependencies": { + "strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true + } + } + }, "default-resolution": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/default-resolution/-/default-resolution-2.0.0.tgz", @@ -3782,6 +4039,12 @@ "next-tick": "~1.0.0" } }, + "es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true + }, "es6-iterator": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", @@ -4700,6 +4963,16 @@ "for-in": "^1.0.1" } }, + "foreground-child": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", + "integrity": "sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0", + "signal-exit": "^3.0.2" + } + }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -4726,6 +4999,12 @@ "map-cache": "^0.2.2" } }, + "fromentries": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fromentries/-/fromentries-1.3.2.tgz", + "integrity": "sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==", + "dev": true + }, "fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", @@ -4878,6 +5157,12 @@ "has-symbols": "^1.0.1" } }, + "get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true + }, "get-pkg-repo": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/get-pkg-repo/-/get-pkg-repo-1.4.0.tgz", @@ -5626,6 +5911,12 @@ } } }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, "har-validator": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", @@ -5752,6 +6043,16 @@ } } }, + "hasha": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", + "integrity": "sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==", + "dev": true, + "requires": { + "is-stream": "^2.0.0", + "type-fest": "^0.8.0" + } + }, "hawk": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", @@ -5791,6 +6092,12 @@ "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", "dev": true }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, "http-signature": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", @@ -6251,6 +6558,12 @@ "is-unc-path": "^1.0.0" } }, + "is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "dev": true + }, "is-string": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", @@ -6399,6 +6712,178 @@ } } }, + "istanbul-lib-coverage": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", + "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", + "dev": true + }, + "istanbul-lib-hook": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-hook/-/istanbul-lib-hook-3.0.0.tgz", + "integrity": "sha512-Pt/uge1Q9s+5VAZ+pCo16TYMWPBIl+oaNIjgLQxcX0itS6ueeaA+pEfThZpH8WxhFgCiEb8sAJY6MdUKgiIWaQ==", + "dev": true, + "requires": { + "append-transform": "^2.0.0" + } + }, + "istanbul-lib-instrument": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", + "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "dev": true, + "requires": { + "@babel/core": "^7.7.5", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "istanbul-lib-processinfo": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.2.tgz", + "integrity": "sha512-kOwpa7z9hme+IBPZMzQ5vdQj8srYgAtaRqeI48NGmAQ+/5yKiHLV0QbYqQpxsdEF0+w14SoB8YbnHKcXE2KnYw==", + "dev": true, + "requires": { + "archy": "^1.0.0", + "cross-spawn": "^7.0.0", + "istanbul-lib-coverage": "^3.0.0-alpha.1", + "make-dir": "^3.0.0", + "p-map": "^3.0.0", + "rimraf": "^3.0.0", + "uuid": "^3.3.3" + }, + "dependencies": { + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", + "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "dependencies": { + "debug": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", + "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "istanbul-reports": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz", + "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", + "dev": true, + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -6560,9 +7045,9 @@ } }, "lcov-parse": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-0.0.10.tgz", - "integrity": "sha1-GwuP+ayceIklBYK3C3ExXZ2m2aM=", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-1.0.0.tgz", + "integrity": "sha1-6w1GtUER68VhrLTECO+TY73I9+A=", "dev": true }, "lead": { @@ -6648,6 +7133,12 @@ "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", "dev": true }, + "lodash.flattendeep": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz", + "integrity": "sha1-+wMJF/hqMTTlvJvsDWngAT3f7bI=", + "dev": true + }, "lodash.ismatch": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz", @@ -6655,9 +7146,9 @@ "dev": true }, "log-driver": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.5.tgz", - "integrity": "sha1-euTsJXMC/XkNVXyxDJcQDYV7AFY=", + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz", + "integrity": "sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==", "dev": true }, "log-symbols": { @@ -7456,6 +7947,15 @@ "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", "dev": true }, + "node-preload": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", + "integrity": "sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==", + "dev": true, + "requires": { + "process-on-spawn": "^1.0.0" + } + }, "node-releases": { "version": "1.1.71", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.71.tgz", @@ -7549,6 +8049,136 @@ "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", "dev": true }, + "nyc": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", + "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==", + "dev": true, + "requires": { + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "caching-transform": "^4.0.0", + "convert-source-map": "^1.7.0", + "decamelize": "^1.2.0", + "find-cache-dir": "^3.2.0", + "find-up": "^4.1.0", + "foreground-child": "^2.0.0", + "get-package-type": "^0.1.0", + "glob": "^7.1.6", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-hook": "^3.0.0", + "istanbul-lib-instrument": "^4.0.0", + "istanbul-lib-processinfo": "^2.0.2", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.2", + "make-dir": "^3.0.0", + "node-preload": "^0.2.1", + "p-map": "^3.0.0", + "process-on-spawn": "^1.0.0", + "resolve-from": "^5.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "spawn-wrap": "^2.0.0", + "test-exclude": "^6.0.0", + "yargs": "^15.0.2" + }, + "dependencies": { + "find-cache-dir": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz", + "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-map": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz", + "integrity": "sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, "oauth-sign": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", @@ -7780,6 +8410,18 @@ "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, + "package-hash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/package-hash/-/package-hash-4.0.0.tgz", + "integrity": "sha512-whdkPIooSu/bASggZ96BWVvZTRMOFxnyUG5PnTSGKoJE2gd5mbVNmR2Nj20QFzxYYgAXpoqC+AiXzl+UMRh7zQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.15", + "hasha": "^5.0.0", + "lodash.flattendeep": "^4.4.0", + "release-zalgo": "^1.0.0" + } + }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -7901,6 +8543,12 @@ } } }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, "picomatch": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", @@ -8008,12 +8656,27 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, + "process-on-spawn": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", + "integrity": "sha512-1WsPDsUSMmZH5LeMLegqkPDrsGgsWwk1Exipy2hvB0o/F0ASzbpIctSCcZIK1ykJvtTJULEH+20WOFjMvGnCTg==", + "dev": true, + "requires": { + "fromentries": "^1.2.0" + } + }, "progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, + "psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==", + "dev": true + }, "pumpify": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", @@ -8270,6 +8933,15 @@ } } }, + "release-zalgo": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", + "integrity": "sha1-CXALflB0Mpc5Mw5TXFqQ+2eFFzA=", + "dev": true, + "requires": { + "es6-error": "^4.0.1" + } + }, "remove-bom-buffer": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz", @@ -8771,6 +9443,46 @@ "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==", "dev": true }, + "spawn-wrap": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz", + "integrity": "sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==", + "dev": true, + "requires": { + "foreground-child": "^2.0.0", + "is-windows": "^1.0.2", + "make-dir": "^3.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "which": "^2.0.1" + }, + "dependencies": { + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, "spdx-correct": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", @@ -9132,6 +9844,17 @@ "uuid": "^3.3.2" } }, + "test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "requires": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + } + }, "text-extensions": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz", @@ -9423,6 +10146,15 @@ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", "dev": true }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "requires": { + "is-typedarray": "^1.0.0" + } + }, "typescript": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.2.tgz", @@ -9864,6 +10596,18 @@ "mkdirp": "^0.5.1" } }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", diff --git a/package.json b/package.json index c9a78ff..b98286c 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "prepublishOnly": "npm run test && npm run build", "tdd": "mocha --watch", "test": "npm run lint && npm run test:once && npm run test:types", - "test:once": "mocha", + "test:once": "nyc --reporter=lcovonly --reporter=html mocha", "test:types": "dtslint --expectOnly --localTs node_modules/typescript/lib types", "doctoc:": "doctoc README.md", "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s" @@ -60,7 +60,7 @@ "babel-eslint": "^9.0.0", "chai": "^3.5.0", "conventional-changelog-cli": "^2.1.1", - "coveralls": "^2.13.1", + "coveralls": "^3.1.0", "cross-env": "^6.0.3", "del": "^6.0.0", "dtslint": "^4.0.7", @@ -73,6 +73,7 @@ "gulp-babel": "^8.0.0", "istanbul": "^0.4.5", "mocha": "^8.3.0", + "nyc": "^15.1.0", "object-flaser": "^0.1.1", "prettier": "^2.2.1", "ts-node": "^9.1.1", diff --git a/src/ArrayType.ts b/src/ArrayType.ts index b44ab6f..737402b 100644 --- a/src/ArrayType.ts +++ b/src/ArrayType.ts @@ -1,69 +1,94 @@ import { MixedType } from './MixedType'; -import { CheckType, PlainObject, CheckResult } from './types'; +import { CheckType, PlainObject, CheckResult, ErrorMessageType } from './types'; +import { ArrayTypeLocale } from './locales'; -export class ArrayType extends MixedType< +export class ArrayType extends MixedType< any[], DataType, - ErrorMsgType + E, + ArrayTypeLocale > { - constructor(errorMessage?: ErrorMsgType) { + constructor(errorMessage?: E | string) { super('array'); - super.pushRule(v => Array.isArray(v), errorMessage || 'Please enter a valid array'); + super.pushRule({ + onValid: v => Array.isArray(v), + errorMessage: errorMessage || this.locale.type + }); } - rangeLength(minLength: number, maxLength: number, errorMessage?: ErrorMsgType) { - super.pushRule( - (value: string[]) => value.length >= minLength && value.length <= maxLength, - errorMessage - ); + rangeLength( + minLength: number, + maxLength: number, + errorMessage: E | string = this.locale.rangeLength + ) { + super.pushRule({ + onValid: (value: string[]) => value.length >= minLength && value.length <= maxLength, + errorMessage, + params: { minLength, maxLength } + }); return this; } - minLength(minLength: number, errorMessage?: ErrorMsgType) { - super.pushRule(value => value.length >= minLength, errorMessage); + minLength(minLength: number, errorMessage: E | string = this.locale.minLength) { + super.pushRule({ + onValid: value => value.length >= minLength, + errorMessage, + params: { minLength } + }); + return this; } - maxLength(maxLength: number, errorMessage?: ErrorMsgType) { - super.pushRule(value => value.length <= maxLength, errorMessage); + maxLength(maxLength: number, errorMessage: E | string = this.locale.minLength) { + super.pushRule({ + onValid: value => value.length <= maxLength, + errorMessage, + params: { maxLength } + }); return this; } - unrepeatable(errorMessage?: ErrorMsgType) { - super.pushRule(items => { - const hash: PlainObject = {}; - for (const i in items) { - if (hash[items[i]]) { - return false; + unrepeatable(errorMessage: E | string = this.locale.unrepeatable) { + super.pushRule({ + onValid: items => { + const hash: PlainObject = {}; + for (const i in items) { + if (hash[items[i]]) { + return false; + } + hash[items[i]] = true; } - hash[items[i]] = true; - } - return true; - }, errorMessage); + return true; + }, + errorMessage + }); + return this; } - /** - * @example - * ArrayType().of(StringType().isOneOf(['数码','体育','游戏','旅途','其他'],'Can only be the value of a predefined option') - */ - of(type: CheckType, errorMessage?: ErrorMsgType) { - super.pushRule(items => { - const checkResults = items.map(value => type.check(value)); - const hasError = !!checkResults.find(item => item?.hasError); + of(type: CheckType) { + super.pushRule({ + onValid: (items, data, filedName) => { + const checkResults = items.map((value, index) => { + const name = Array.isArray(filedName) + ? [...filedName, `[${index}]`] + : [filedName, `[${index}]`]; + + return type.check(value, data, name as string[]); + }); + const hasError = !!checkResults.find(item => item?.hasError); - return { - hasError, - array: checkResults - } as CheckResult; - }, errorMessage); + return { + hasError, + array: checkResults + } as CheckResult; + } + }); return this; } } -export default function getArrayType( - errorMessage?: ErrorMsgType -) { - return new ArrayType(errorMessage); +export default function getArrayType(errorMessage?: E) { + return new ArrayType(errorMessage); } diff --git a/src/BooleanType.ts b/src/BooleanType.ts index 1d8991e..ba8cfd5 100644 --- a/src/BooleanType.ts +++ b/src/BooleanType.ts @@ -1,18 +1,22 @@ import { MixedType } from './MixedType'; +import { ErrorMessageType } from './types'; +import { BooleanTypeLocale } from './locales'; -export class BooleanType extends MixedType< +export class BooleanType extends MixedType< boolean, DataType, - ErrorMsgType + E, + BooleanTypeLocale > { - constructor(errorMessage?: ErrorMsgType) { + constructor(errorMessage?: E | string) { super('boolean'); - super.pushRule(v => typeof v === 'boolean', errorMessage || 'Please enter a valid `boolean`'); + super.pushRule({ + onValid: v => typeof v === 'boolean', + errorMessage: errorMessage || this.locale.type + }); } } -export default function getBooleanType( - errorMessage?: ErrorMsgType -) { - return new BooleanType(errorMessage); +export default function getBooleanType(errorMessage?: E) { + return new BooleanType(errorMessage); } diff --git a/src/DateType.ts b/src/DateType.ts index 0c6082f..78a1eb4 100644 --- a/src/DateType.ts +++ b/src/DateType.ts @@ -1,39 +1,46 @@ import { MixedType } from './MixedType'; +import { ErrorMessageType } from './types'; +import { DateTypeLocale } from './locales'; -export class DateType extends MixedType< +export class DateType extends MixedType< string | Date, DataType, - ErrorMsgType + E, + DateTypeLocale > { - constructor(errorMessage?: ErrorMsgType) { + constructor(errorMessage?: E | string) { super('date'); - super.pushRule( - value => !/Invalid|NaN/.test(new Date(value).toString()), - errorMessage || 'Please enter a valid date' - ); + super.pushRule({ + onValid: value => !/Invalid|NaN/.test(new Date(value).toString()), + errorMessage: errorMessage || this.locale.type + }); } - range(min: string | Date, max: string | Date, errorMessage?: ErrorMsgType) { - super.pushRule( - value => new Date(value) >= new Date(min) && new Date(value) <= new Date(max), + range(min: string | Date, max: string | Date, errorMessage: E | string = this.locale.range) { + super.pushRule({ + onValid: value => new Date(value) >= new Date(min) && new Date(value) <= new Date(max), errorMessage - ); + }); return this; } - min(min: string | Date, errorMessage?: ErrorMsgType) { - super.pushRule(value => new Date(value) >= new Date(min), errorMessage); + min(min: string | Date, errorMessage: E | string = this.locale.min) { + super.pushRule({ + onValid: value => new Date(value) >= new Date(min), + errorMessage + }); return this; } - max(max: string | Date, errorMessage?: ErrorMsgType) { - super.pushRule(value => new Date(value) <= new Date(max), errorMessage); + max(max: string | Date, errorMessage: E | string = this.locale.max) { + super.pushRule({ + onValid: value => new Date(value) <= new Date(max), + errorMessage + }); return this; } } -export default function getDateType( - errorMessage?: ErrorMsgType -) { - return new DateType(errorMessage); +export default function getDateType(errorMessage?: E) { + return new DateType(errorMessage); } diff --git a/src/MixedType.ts b/src/MixedType.ts index 908e8a8..240ce0b 100644 --- a/src/MixedType.ts +++ b/src/MixedType.ts @@ -1,35 +1,54 @@ -import { SchemaDeclaration, CheckResult, ValidCallbackType, RuleType } from './types'; -import { checkRequired, createValidator, createValidatorAsync, isEmpty } from './utils'; - -export class MixedType { - readonly name?: string; +import { + SchemaDeclaration, + CheckResult, + ValidCallbackType, + RuleType, + ErrorMessageType, + TypeName +} from './types'; +import { + checkRequired, + createValidator, + createValidatorAsync, + isEmpty, + formatErrorMessage +} from './utils'; +import locales, { MixedTypeLocale } from './locales'; + +export class MixedType { + readonly typeName?: string; protected required = false; - protected requiredMessage: ErrorMsgType | string = ''; + protected requiredMessage: E | string = ''; protected trim = false; protected emptyAllowed = false; - protected rules: RuleType[] = []; - protected priorityRules: RuleType[] = []; + protected rules: RuleType[] = []; + protected priorityRules: RuleType[] = []; - schemaSpec: SchemaDeclaration; + schemaSpec: SchemaDeclaration; value: any; + locale: L & MixedTypeLocale; - constructor(name?: string) { - this.name = name; + constructor(name?: TypeName) { + this.typeName = name; + this.locale = Object.assign(name ? locales[name] : {}, locales.mixed) as L & MixedTypeLocale; } - setSchemaOptions(schemaSpec: SchemaDeclaration, value: any) { + setSchemaOptions(schemaSpec: SchemaDeclaration, value: any) { this.schemaSpec = schemaSpec; this.value = value; } - check(value: ValueType = this.value, data?: DataType) { + check(value: ValueType = this.value, data?: DataType, fieldName?: string | string[]) { if (this.required && !checkRequired(value, this.trim, this.emptyAllowed)) { - return { hasError: true, errorMessage: this.requiredMessage }; + return { + hasError: true, + errorMessage: formatErrorMessage(this.requiredMessage, { name: fieldName }) + }; } - const validator = createValidator(data); + const validator = createValidator(data, fieldName); - let checkStatus = validator(value, this.priorityRules); + const checkStatus = validator(value, this.priorityRules); if (checkStatus) { return checkStatus; @@ -44,17 +63,21 @@ export class MixedType { checkAsync( value: ValueType = this.value, - data?: DataType - ): Promise> { + data?: DataType, + fieldName?: string | string[] + ): Promise> { if (this.required && !checkRequired(value, this.trim, this.emptyAllowed)) { - return Promise.resolve({ hasError: true, errorMessage: this.requiredMessage }); + return Promise.resolve({ + hasError: true, + errorMessage: formatErrorMessage(this.requiredMessage, { name: fieldName }) + }); } - const validator = createValidatorAsync(data); + const validator = createValidatorAsync(data, fieldName); return new Promise(resolve => validator(value, this.priorityRules) - .then((checkStatus: CheckResult | void | null) => { + .then((checkStatus: CheckResult | void | null) => { if (checkStatus) { resolve(checkStatus); } @@ -65,7 +88,7 @@ export class MixedType { } }) .then(() => validator(value, this.rules)) - .then((checkStatus: CheckResult | void | null) => { + .then((checkStatus: CheckResult | void | null) => { if (checkStatus) { resolve(checkStatus); } @@ -73,35 +96,36 @@ export class MixedType { }) ); } - protected pushRule( - onValid: ValidCallbackType, - errorMessage?: ErrorMsgType | string, - priority?: boolean - ) { - errorMessage = errorMessage || this.rules?.[0]?.errorMessage; + protected pushRule(rule: RuleType) { + const { onValid, errorMessage, priority, params } = rule; + const nextRule = { + onValid, + params, + errorMessage: errorMessage || this.rules?.[0]?.errorMessage + }; if (priority) { - this.priorityRules.push({ onValid, errorMessage }); + this.priorityRules.push(nextRule); } else { - this.rules.push({ onValid, errorMessage }); + this.rules.push(nextRule); } } addRule( - onValid: ValidCallbackType, - errorMessage?: ErrorMsgType | string, + onValid: ValidCallbackType, + errorMessage?: E | string, priority?: boolean ) { - this.pushRule(onValid, errorMessage, priority); + this.pushRule({ onValid, errorMessage, priority }); return this; } - isRequired(errorMessage: ErrorMsgType | string, trim = true) { + isRequired(errorMessage: E | string = this.locale.isRequired, trim = true) { this.required = true; this.trim = trim; this.requiredMessage = errorMessage; return this; } - isRequiredOrEmpty(errorMessage: ErrorMsgType | string, trim = true) { + isRequiredOrEmpty(errorMessage: E | string = this.locale.isRequiredOrEmpty, trim = true) { this.required = true; this.trim = trim; this.emptyAllowed = true; @@ -117,18 +141,18 @@ export class MixedType { * return schema.filed1.check() ? NumberType().min(5) : NumberType().min(0); * }); */ - when(condition: (schemaSpec: SchemaDeclaration) => MixedType) { + when(condition: (schemaSpec: SchemaDeclaration) => MixedType) { this.addRule( - (value, data) => { - return condition(this.schemaSpec).check(value, data); + (value, data, filedName) => { + return condition(this.schemaSpec).check(value, data, filedName); }, - 'error', + undefined, true ); return this; } } -export default function getMixedType() { - return new MixedType(); +export default function getMixedType() { + return new MixedType(); } diff --git a/src/NumberType.ts b/src/NumberType.ts index 0e73f87..0e2ce06 100644 --- a/src/NumberType.ts +++ b/src/NumberType.ts @@ -1,55 +1,80 @@ import { MixedType } from './MixedType'; +import { ErrorMessageType } from './types'; +import { NumberTypeLocale } from './locales'; -function FN(value: string | number) { +function toNumber(value: string | number) { return +value; } -export class NumberType extends MixedType< +export class NumberType extends MixedType< number | string, DataType, - ErrorMsgType + E, + NumberTypeLocale > { - constructor(errorMessage?: ErrorMsgType) { + constructor(errorMessage?: E | string) { super('number'); - super.pushRule( - value => /^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d+)?$/.test(value + ''), - errorMessage || 'Please enter a valid number' - ); + super.pushRule({ + onValid: value => /^-?(?:\d+|\d{1,3}(?:,\d{3})+)(?:\.\d+)?$/.test(value + ''), + errorMessage: errorMessage || this.locale.type + }); } - isInteger(errorMessage?: ErrorMsgType) { - super.pushRule(value => /^-?\d+$/.test(value + ''), errorMessage); + isInteger(errorMessage: E | string = this.locale.isInteger) { + super.pushRule({ + onValid: value => /^-?\d+$/.test(value + ''), + errorMessage + }); + return this; } - pattern(regexp: RegExp, errorMessage?: ErrorMsgType) { - super.pushRule(value => regexp.test(value + ''), errorMessage); + pattern(regexp: RegExp, errorMessage: E | string = this.locale.pattern) { + super.pushRule({ + onValid: value => regexp.test(value + ''), + errorMessage, + params: { regexp } + }); return this; } - isOneOf(numLst: number[], errorMessage?: ErrorMsgType) { - super.pushRule(value => numLst.includes(FN(value)), errorMessage); + isOneOf(values: number[], errorMessage: E | string = this.locale.isOneOf) { + super.pushRule({ + onValid: value => values.includes(toNumber(value)), + errorMessage, + params: { values } + }); return this; } - range(min: number, max: number, errorMessage?: ErrorMsgType) { - super.pushRule(value => FN(value) >= min && FN(value) <= max, errorMessage); + range(min: number, max: number, errorMessage: E | string = this.locale.range) { + super.pushRule({ + onValid: value => toNumber(value) >= min && toNumber(value) <= max, + errorMessage, + params: { min, max } + }); return this; } - min(min: number, errorMessage?: ErrorMsgType) { - super.pushRule(value => FN(value) >= min, errorMessage); + min(min: number, errorMessage: E | string = this.locale.min) { + super.pushRule({ + onValid: value => toNumber(value) >= min, + errorMessage, + params: { min } + }); return this; } - max(max: number, errorMessage?: ErrorMsgType) { - super.pushRule(value => FN(value) <= max, errorMessage); + max(max: number, errorMessage: E | string = this.locale.max) { + super.pushRule({ + onValid: value => toNumber(value) <= max, + errorMessage, + params: { max } + }); return this; } } -export default function getNumberType( - errorMessage?: ErrorMsgType -) { - return new NumberType(errorMessage); +export default function getNumberType(errorMessage?: E) { + return new NumberType(errorMessage); } diff --git a/src/ObjectType.ts b/src/ObjectType.ts index 5172ff8..f119c88 100644 --- a/src/ObjectType.ts +++ b/src/ObjectType.ts @@ -1,20 +1,24 @@ import { MixedType } from './MixedType'; import { createValidator, createValidatorAsync, checkRequired, isEmpty } from './utils'; -import { PlainObject, SchemaDeclaration, CheckResult } from './types'; +import { PlainObject, SchemaDeclaration, CheckResult, ErrorMessageType } from './types'; +import { ObjectTypeLocale } from './locales'; -export class ObjectType extends MixedType< +export class ObjectType extends MixedType< PlainObject, DataType, - ErrorMsgType + E, + ObjectTypeLocale > { - objectTypeSchemaSpec: SchemaDeclaration; - - constructor(errorMessage?: ErrorMsgType) { + objectTypeSchemaSpec: SchemaDeclaration; + constructor(errorMessage?: E | string) { super('object'); - super.pushRule(v => typeof v === 'object', errorMessage || 'Please enter a valid `object`'); + super.pushRule({ + onValid: v => typeof v === 'object', + errorMessage: errorMessage || this.locale.type + }); } - check(value: PlainObject = this.value, data?: DataType) { + check(value: PlainObject = this.value, data?: DataType, fieldName?: string | string[]) { const check = (value: any, data: any, type: any) => { if (type.required && !checkRequired(value, type.trim, type.emptyAllowed)) { return { hasError: true, errorMessage: type.requiredMessage }; @@ -34,8 +38,7 @@ export class ObjectType extends MixedType return { hasError, object: checkResultObject }; } - const validator = createValidator(data); - + const validator = createValidator(data, fieldName); const checkStatus = validator(value, type.priorityRules); if (checkStatus) { @@ -49,16 +52,16 @@ export class ObjectType extends MixedType return validator(value, type.rules) || { hasError: false }; }; - return check(value, data, this) as CheckResult; + return check(value, data, this) as CheckResult; } - checkAsync(value: PlainObject = this.value, data?: DataType) { + checkAsync(value: PlainObject = this.value, data?: DataType, fieldName?: string | string[]) { const check = (value: any, data: any, type: any) => { if (type.required && !checkRequired(value, type.trim, type.emptyAllowed)) { return Promise.resolve({ hasError: true, errorMessage: this.requiredMessage }); } - const validator = createValidatorAsync(data); + const validator = createValidatorAsync(data, fieldName); return new Promise(resolve => { if (type.objectTypeSchemaSpec && typeof value === 'object') { @@ -80,7 +83,7 @@ export class ObjectType extends MixedType } return validator(value, type.priorityRules) - .then((checkStatus: CheckResult | void | null) => { + .then((checkStatus: CheckResult | void | null) => { if (checkStatus) { resolve(checkStatus); } @@ -91,7 +94,7 @@ export class ObjectType extends MixedType } }) .then(() => validator(value, type.rules)) - .then((checkStatus: CheckResult | void | null) => { + .then((checkStatus: CheckResult | void | null) => { if (checkStatus) { resolve(checkStatus); } @@ -100,7 +103,7 @@ export class ObjectType extends MixedType }); }; - return check(value, data, this) as Promise>; + return check(value, data, this) as Promise>; } /** @@ -110,14 +113,12 @@ export class ObjectType extends MixedType * age: NumberType() * }) */ - shape(fields: SchemaDeclaration) { + shape(fields: SchemaDeclaration) { this.objectTypeSchemaSpec = fields; return this; } } -export default function getObjectType( - errorMessage?: ErrorMsgType -) { - return new ObjectType(errorMessage); +export default function getObjectType(errorMessage?: E) { + return new ObjectType(errorMessage); } diff --git a/src/Schema.ts b/src/Schema.ts index 084a108..597792c 100644 --- a/src/Schema.ts +++ b/src/Schema.ts @@ -38,7 +38,7 @@ export class Schema { return { hasError: false }; } - return fieldChecker.check((data[fieldName] as unknown) as never, data); + return fieldChecker.check((data[fieldName] as unknown) as never, data, fieldName as string); } checkForFieldAsync( @@ -52,7 +52,11 @@ export class Schema { // fieldValue can be anything if no schema defined return Promise.resolve({ hasError: false }); } - return fieldChecker.checkAsync((data[fieldName] as unknown) as never, data); + return fieldChecker.checkAsync( + (data[fieldName] as unknown) as never, + data, + fieldName as string + ); } check(data: DataType) { diff --git a/src/StringType.ts b/src/StringType.ts index 5e5669e..7476b31 100644 --- a/src/StringType.ts +++ b/src/StringType.ts @@ -1,88 +1,140 @@ import { MixedType } from './MixedType'; +import { ErrorMessageType } from './types'; +import { StringTypeLocale } from './locales'; -export class StringType extends MixedType< +export class StringType extends MixedType< string, DataType, - ErrorMsgType + E, + StringTypeLocale > { - constructor(errorMessage?: ErrorMsgType) { + constructor(errorMessage?: E | string) { super('string'); - super.pushRule(v => typeof v === 'string', errorMessage || 'Please enter a valid string'); + super.pushRule({ + onValid: v => typeof v === 'string', + errorMessage: errorMessage || this.locale.type + }); } - containsLetter(errorMessage?: ErrorMsgType) { - super.pushRule(v => /[a-zA-Z]/.test(v), errorMessage); + containsLetter(errorMessage: E | string = this.locale.containsLetter) { + super.pushRule({ + onValid: v => /[a-zA-Z]/.test(v), + errorMessage + }); return this; } - containsUppercaseLetter(errorMessage?: ErrorMsgType) { - super.pushRule(v => /[A-Z]/.test(v), errorMessage); + containsUppercaseLetter(errorMessage: E | string = this.locale.containsUppercaseLetter) { + super.pushRule({ + onValid: v => /[A-Z]/.test(v), + errorMessage + }); return this; } - containsLowercaseLetter(errorMessage?: ErrorMsgType) { - super.pushRule(v => /[a-z]/.test(v), errorMessage); + containsLowercaseLetter(errorMessage: E | string = this.locale.containsLowercaseLetter) { + super.pushRule({ + onValid: v => /[a-z]/.test(v), + errorMessage + }); return this; } - containsLetterOnly(errorMessage?: ErrorMsgType) { - super.pushRule(v => /^[a-zA-Z]+$/.test(v), errorMessage); + containsLetterOnly(errorMessage: E | string = this.locale.containsLetterOnly) { + super.pushRule({ + onValid: v => /^[a-zA-Z]+$/.test(v), + errorMessage + }); return this; } - containsNumber(errorMessage?: ErrorMsgType) { - super.pushRule(v => /[0-9]/.test(v), errorMessage); + containsNumber(errorMessage: E | string = this.locale.containsNumber) { + super.pushRule({ + onValid: v => /[0-9]/.test(v), + errorMessage + }); return this; } - isOneOf(strArr: string[], errorMessage?: ErrorMsgType) { - super.pushRule(v => !!~strArr.indexOf(v), errorMessage); + isOneOf(values: string[], errorMessage: E | string = this.locale.isOneOf) { + super.pushRule({ + onValid: v => !!~values.indexOf(v), + errorMessage, + params: { values } + }); return this; } - isEmail(errorMessage?: ErrorMsgType) { - //http://emailregex.com/ + isEmail(errorMessage: E | string = this.locale.isEmail) { + // http://emailregex.com/ const regexp = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; - super.pushRule(v => regexp.test(v), errorMessage); + super.pushRule({ + onValid: v => regexp.test(v), + errorMessage + }); return this; } - isURL(errorMessage?: ErrorMsgType) { + isURL(errorMessage: E | string = this.locale.isURL) { const regexp = new RegExp( '^(?!mailto:)(?:(?:http|https|ftp)://|//)(?:\\S+(?::\\S*)?@)?(?:(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[0-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-z\\u00a1-\\uffff]{2,})))|localhost)(?::\\d{2,5})?(?:(/|\\?|#)[^\\s]*)?$', 'i' ); - super.pushRule(v => regexp.test(v), errorMessage); + super.pushRule({ + onValid: v => regexp.test(v), + errorMessage + }); return this; } - isHex(errorMessage?: ErrorMsgType) { + isHex(errorMessage: E | string = this.locale.isHex) { const regexp = /^#?([a-f0-9]{6}|[a-f0-9]{3})$/i; - super.pushRule(v => regexp.test(v), errorMessage); + super.pushRule({ + onValid: v => regexp.test(v), + errorMessage + }); return this; } - pattern(regexp: RegExp, errorMessage?: ErrorMsgType) { - super.pushRule(value => regexp.test(value), errorMessage); + pattern(regexp: RegExp, errorMessage: E | string = this.locale.pattern) { + super.pushRule({ + onValid: v => regexp.test(v), + errorMessage, + params: { regexp } + }); return this; } - rangeLength(minLength: number, maxLength: number, errorMessage?: ErrorMsgType) { - super.pushRule(value => value.length >= minLength && value.length <= maxLength, errorMessage); + rangeLength( + minLength: number, + maxLength: number, + errorMessage: E | string = this.locale.rangeLength + ) { + super.pushRule({ + onValid: value => value.length >= minLength && value.length <= maxLength, + errorMessage, + params: { minLength, maxLength } + }); return this; } - minLength(minLength: number, errorMessage?: ErrorMsgType) { - super.pushRule(value => Array.from(value).length >= minLength, errorMessage); + minLength(minLength: number, errorMessage: E | string = this.locale.minLength) { + super.pushRule({ + onValid: value => Array.from(value).length >= minLength, + errorMessage, + params: { minLength } + }); return this; } - maxLength(maxLength: number, errorMessage?: ErrorMsgType) { - super.pushRule(value => Array.from(value).length <= maxLength, errorMessage); + maxLength(maxLength: number, errorMessage: E | string = this.locale.maxLength) { + super.pushRule({ + onValid: value => Array.from(value).length <= maxLength, + errorMessage, + params: { maxLength } + }); return this; } } -export default function getStringType( - errorMessage?: ErrorMsgType -) { - return new StringType(errorMessage); +export default function getStringType(errorMessage?: E) { + return new StringType(errorMessage); } diff --git a/src/locales/default.ts b/src/locales/default.ts new file mode 100644 index 0000000..b88e84b --- /dev/null +++ b/src/locales/default.ts @@ -0,0 +1,50 @@ +export default { + mixed: { + isRequired: '${name} is a required field', + isRequiredOrEmpty: '${name} is a required field' + }, + array: { + type: '${name} must be an array', + rangeLength: '${name} must contain ${minLength} to ${maxLength} items', + minLength: '${name} field must have at least ${minLength} items', + maxLength: '${name} field must have less than or equal to ${maxLength} items', + unrepeatable: '${name} must have non-repeatable items' + }, + boolean: { + type: '${name} must be a boolean' + }, + date: { + type: '${name} must be a date', + min: '${name} field must be later than ${min}', + max: '${name} field must be at earlier than ${max}', + range: '${name} field must be between ${min} and ${max}' + }, + number: { + type: '${name} must be a number', + isInteger: '${name} must be an integer', + pattern: '${name} is invalid', + isOneOf: '${name} must be one of the following values: ${values}', + range: '${name} field must be between ${min} and ${max}', + min: '${name} must be greater than or equal to ${min}', + max: '${name} must be less than or equal to ${max}' + }, + string: { + type: '${name} must be a string', + containsLetter: '${name} field must contain letters', + containsUppercaseLetter: '${name} must be a upper case string', + containsLowercaseLetter: '${name} must be a lowercase string', + containsLetterOnly: '${name} must all be letters', + containsNumber: '${name} field must contain numbers', + isOneOf: '${name} must be one of the following values: ${values}', + isEmail: '${name} must be a valid email', + isURL: '${name} must be a valid URL', + isHex: '${name} must be a valid hexadecimal', + pattern: '${name} is invalid', + rangeLength: '${name} must contain ${minLength} to ${maxLength} characters', + minLength: '${name} must be at least ${minLength} characters', + maxLength: '${name} must be at most ${maxLength} characters' + }, + object: { + type: '${name} must be an object' + } +}; diff --git a/src/locales/index.ts b/src/locales/index.ts new file mode 100644 index 0000000..0a37e48 --- /dev/null +++ b/src/locales/index.ts @@ -0,0 +1,16 @@ +import defaultLocale from './default'; + +export type PickKeys = { + [keys in keyof T]: T[keys]; +}; + +export type Locale = PickKeys; +export type MixedTypeLocale = PickKeys; +export type ArrayTypeLocale = PickKeys & MixedTypeLocale; +export type ObjectTypeLocale = PickKeys & MixedTypeLocale; +export type BooleanTypeLocale = PickKeys & MixedTypeLocale; +export type StringTypeLocale = PickKeys & MixedTypeLocale; +export type NumberTypeLocale = PickKeys & MixedTypeLocale; +export type DateTypeLocale = PickKeys & MixedTypeLocale; + +export default defaultLocale; diff --git a/src/types.ts b/src/types.ts index d3e1dc4..ab3f8a4 100644 --- a/src/types.ts +++ b/src/types.ts @@ -5,48 +5,55 @@ import { NumberType } from './NumberType'; import { StringType } from './StringType'; import { ObjectType } from './ObjectType'; +export type TypeName = 'array' | 'string' | 'boolean' | 'number' | 'object' | 'date'; + export interface CheckResult { hasError?: boolean; errorMessage?: E | string; object?: CheckResult; array?: CheckResult[]; } - -export type ValidCallbackType = (value: V, data?: D) => CheckResult | boolean; - +export type ErrorMessageType = string; +export type ValidCallbackType = ( + value: V, + data?: D, + filedName?: string | string[] +) => CheckResult | boolean; export type PlainObject = any> = { [P in keyof T]: T; }; export interface RuleType { onValid: ValidCallbackType; - errorMessage: E; + errorMessage?: E; + priority?: boolean; + params?: any; } -export type CheckType = X extends string - ? StringType | DateType | NumberType +export type CheckType = X extends string + ? StringType | DateType | NumberType : X extends number - ? NumberType + ? NumberType : X extends boolean - ? BooleanType + ? BooleanType : X extends Date - ? DateType + ? DateType : X extends Array - ? ArrayType + ? ArrayType : X extends Record - ? ObjectType + ? ObjectType : - | StringType - | NumberType - | BooleanType - | ArrayType - | DateType - | ObjectType; + | StringType + | NumberType + | BooleanType + | ArrayType + | DateType + | ObjectType; -export type SchemaDeclaration = { - [P in keyof T]: CheckType; +export type SchemaDeclaration = { + [P in keyof T]: CheckType; }; -export type SchemaCheckResult = { - [P in keyof T]: CheckResult; +export type SchemaCheckResult = { + [P in keyof T]: CheckResult; }; diff --git a/src/utils/createValidator.ts b/src/utils/createValidator.ts index dcfdcc3..c6fe036 100644 --- a/src/utils/createValidator.ts +++ b/src/utils/createValidator.ts @@ -1,17 +1,24 @@ import { CheckResult, RuleType } from '../types'; +import formatErrorMessage from './formatErrorMessage'; /** * Create a data validator * @param data */ -export function createValidator(data?: D) { +export function createValidator(data?: D, name?: string | string[]) { return (value: V, rules: RuleType[]): CheckResult | null => { for (let i = 0; i < rules.length; i += 1) { - const { onValid, errorMessage } = rules[i]; - const checkResult = onValid(value, data); + const { onValid, errorMessage, params } = rules[i]; + const checkResult = onValid(value, data, name); if (checkResult === false) { - return { hasError: true, errorMessage }; + return { + hasError: true, + errorMessage: formatErrorMessage(errorMessage, { + ...params, + name: Array.isArray(name) ? name.join('.') : name + }) + }; } else if (typeof checkResult === 'object' && (checkResult.hasError || checkResult.array)) { return checkResult; } diff --git a/src/utils/createValidatorAsync.ts b/src/utils/createValidatorAsync.ts index 30239f5..4b38059 100644 --- a/src/utils/createValidatorAsync.ts +++ b/src/utils/createValidatorAsync.ts @@ -1,11 +1,12 @@ import { CheckResult, RuleType } from '../types'; +import formatErrorMessage from './formatErrorMessage'; /** * Create a data asynchronous validator * @param data */ -export function createValidatorAsync(data?: D) { - function check(errorMessage?: E) { +export function createValidatorAsync(data?: D, name?: string | string[]) { + function check(errorMessage?: E | string) { return (checkResult: CheckResult | boolean): CheckResult | null => { if (checkResult === false) { return { hasError: true, errorMessage }; @@ -18,8 +19,15 @@ export function createValidatorAsync(data?: D) { return (value: V, rules: RuleType[]) => { const promises = rules.map(rule => { - const { onValid, errorMessage } = rule; - return Promise.resolve(onValid(value, data)).then(check(errorMessage)); + const { onValid, errorMessage, params } = rule; + return Promise.resolve(onValid(value, data, name)).then( + check( + formatErrorMessage(errorMessage, { + ...params, + name: Array.isArray(name) ? name.join('.') : name + }) + ) + ); }); return Promise.all(promises).then(results => diff --git a/src/utils/formatErrorMessage.ts b/src/utils/formatErrorMessage.ts new file mode 100644 index 0000000..e5285fb --- /dev/null +++ b/src/utils/formatErrorMessage.ts @@ -0,0 +1,13 @@ +/** + * formatErrorMessage('${name} is a required field', {name: 'email'}); + * output: 'email is a required field' + */ +export default function formatErrorMessage(errorMessage?: string | E, params?: any) { + if (typeof errorMessage === 'string') { + return errorMessage.replace(/\$\{\s*(\w+)\s*\}/g, (_, key) => { + return params?.[key] || `[${key}]`; + }); + } + + return errorMessage; +} diff --git a/src/utils/index.ts b/src/utils/index.ts index 4a16d55..c9393e6 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -3,3 +3,4 @@ export { default as checkRequired } from './checkRequired'; export { default as createValidator } from './createValidator'; export { default as createValidatorAsync } from './createValidatorAsync'; export { default as isEmpty } from './isEmpty'; +export { default as formatErrorMessage } from './formatErrorMessage'; diff --git a/test/ArrayTypeSpec.js b/test/ArrayTypeSpec.js index 1a15643..5e6b909 100644 --- a/test/ArrayTypeSpec.js +++ b/test/ArrayTypeSpec.js @@ -1,12 +1,17 @@ -const should = require('chai').should(); +/* eslint-disable @typescript-eslint/no-var-requires */ + +require('chai').should(); + const schema = require('../src'); const { ArrayType, StringType, NumberType, ObjectType, Schema } = schema; describe('#ArrayType', () => { it('Should be a valid array', () => { const schemaData = { - data: ArrayType().minLength(2, 'abc').of(StringType().isEmail('应该是一个 email'), '格式错误') + data: ArrayType().minLength(2, 'error1').of(StringType().isEmail('error2')), + data2: ArrayType().minLength(2).of(StringType().isEmail()) }; + const schema = new Schema(schemaData); const check1 = schema.checkForField('data', { @@ -24,26 +29,44 @@ describe('#ArrayType', () => { check2.data.hasError.should.equal(true); check2.data.array[1].hasError.should.equal(true); - check2.data.array[1].errorMessage.should.equal('应该是一个 email'); + check2.data.array[1].errorMessage.should.equal('error2'); + + const check3 = schema.check({ + data2: [] + }); + + check3.data2.errorMessage.should.equal('data2 field must have at least 2 items'); + + const check4 = schema.check({ + data2: ['simon.guo@hypers.com', 'error_email', 'ddd@bbb.com'] + }); + + check4.data2.array[1].errorMessage.should.equal('data2.[1] must be a valid email'); }); it('Should output default error message ', () => { - const schemaData = { data: ArrayType().of(StringType().isEmail(), '格式错误') }; + const schemaData = { data: ArrayType().of(StringType().isEmail()) }; const schema = new Schema(schemaData); const checkStatus = schema.checkForField('data', { data: ['simon.guo@hypers.com', 'error_email', 'ddd@bbb.com'] }); checkStatus.array[1].hasError.should.equal(true); - checkStatus.array[1].errorMessage.should.equal('Please enter a valid string'); + checkStatus.array[1].errorMessage.should.equal('data.[1] must be a valid email'); }); it('Should support array nested objects', () => { const schemaData = { users: ArrayType().of( - ObjectType('应该是一个对象').shape({ - email: StringType().isEmail('应该是一个 email'), - age: NumberType().min(18, '年龄应该大于18岁') + ObjectType('error1').shape({ + email: StringType().isEmail('error2'), + age: NumberType().min(18, 'error3') + }) + ), + users2: ArrayType().of( + ObjectType().shape({ + email: StringType().isEmail(), + age: NumberType().min(18) }) ) }; @@ -58,33 +81,60 @@ describe('#ArrayType', () => { checkStatus.users.hasError.should.equal(true); checkStatus.users.array[0].hasError.should.equal(true); - checkStatus.users.array[0].errorMessage.should.equal('应该是一个对象'); + checkStatus.users.array[0].errorMessage.should.equal('error1'); checkStatus.users.array[1].object.email.hasError.should.equal(true); - checkStatus.users.array[1].object.email.errorMessage.should.equal('应该是一个 email'); + checkStatus.users.array[1].object.email.errorMessage.should.equal('error2'); checkStatus.users.array[1].object.age.hasError.should.equal(false); checkStatus.users.array[2].object.email.hasError.should.equal(true); - checkStatus.users.array[2].object.email.errorMessage.should.equal('应该是一个 email'); + checkStatus.users.array[2].object.email.errorMessage.should.equal('error2'); checkStatus.users.array[2].object.age.hasError.should.equal(true); - checkStatus.users.array[2].object.age.errorMessage.should.equal('年龄应该大于18岁'); + checkStatus.users.array[2].object.age.errorMessage.should.equal('error3'); + + const schema2 = new Schema(schemaData); + const checkStatus2 = schema2.check({ + users2: [ + 'simon.guo@hypers.com', + { email: 'error_email', age: 19 }, + { email: 'error_email', age: 17 } + ] + }); + + checkStatus2.users2.array[0].errorMessage.should.equal('users2.[0] must be an object'); + checkStatus2.users2.array[1].object.email.errorMessage.should.equal( + 'users2.[1] must be a valid email' + ); + checkStatus2.users2.array[2].object.age.errorMessage.should.equal( + 'users2.[2] must be greater than or equal to 18' + ); }); it('Should be unrepeatable ', () => { - const schemaData = { data: ArrayType().unrepeatable('不能有个重复数据') }; + const schemaData = { data: ArrayType().unrepeatable('error1') }; const schema = new Schema(schemaData); const checkStatus = schema.checkForField('data', { data: ['abc', '123', 'abc'] }); checkStatus.hasError.should.equal(true); - checkStatus.errorMessage.should.equal('不能有个重复数据'); + checkStatus.errorMessage.should.equal('error1'); + + const schemaData2 = { data: ArrayType().unrepeatable() }; + const schema2 = new Schema(schemaData2); + const checkStatus2 = schema2.checkForField('data', { data: ['abc', '123', 'abc'] }); + checkStatus2.errorMessage.should.equal('data must have non-repeatable items'); }); it('Should be required ', () => { - const schemaData = { data: ArrayType().isRequired('不能为空') }; + const schemaData = { + data: ArrayType().isRequired('error1'), + data2: ArrayType().isRequired() + }; const schema = new Schema(schemaData); const checkStatus = schema.checkForField('data', { data: null }); + const checkStatus2 = schema.checkForField('data2', { data2: null }); checkStatus.hasError.should.equal(true); - checkStatus.errorMessage.should.equal('不能为空'); + checkStatus.errorMessage.should.equal('error1'); + checkStatus2.errorMessage.should.equal('data2 is a required field'); schema.checkForField('data', { data: [] }).hasError.should.equal(true); schema.checkForField('data', { data: undefined }).hasError.should.equal(true); diff --git a/test/MixedTypeSpec.js b/test/MixedTypeSpec.js index a39f790..9d29b9e 100644 --- a/test/MixedTypeSpec.js +++ b/test/MixedTypeSpec.js @@ -1,6 +1,8 @@ -const should = require('chai').should(); +/* eslint-disable @typescript-eslint/no-var-requires */ +require('chai').should(); + const schema = require('../src'); -const { StringType, SchemaModel, NumberType, ObjectType, ArrayType, MixedType } = schema; +const { StringType, SchemaModel, NumberType, ArrayType, MixedType } = schema; describe('#MixedType', () => { it('Should be the same password twice', () => { diff --git a/test/NumberTypeSpec.js b/test/NumberTypeSpec.js index 68bf4d2..7acb482 100644 --- a/test/NumberTypeSpec.js +++ b/test/NumberTypeSpec.js @@ -1,6 +1,7 @@ -const should = require('chai').should(); +/* eslint-disable @typescript-eslint/no-var-requires */ +require('chai').should(); const schema = require('../src'); -const { StringType, NumberType, Schema } = schema; +const { NumberType, Schema } = schema; describe('#NumberType', () => { let schemaData = { data: NumberType() }; @@ -24,6 +25,7 @@ describe('#NumberType', () => { schema.checkForField('data', { data: '1abc' }).hasError.should.equal(true); schema.checkForField('data', { data: {} }).hasError.should.equal(true); schema.checkForField('data', { data: [] }).hasError.should.equal(true); + schema.checkForField('data', { data: [] }).errorMessage.should.equal('data must be a number'); }); it('True should be a invalid number', () => { diff --git a/test/ObjectTypeSpec.js b/test/ObjectTypeSpec.js index 2c716dc..ca35d12 100644 --- a/test/ObjectTypeSpec.js +++ b/test/ObjectTypeSpec.js @@ -1,6 +1,8 @@ import { flaser } from 'object-flaser'; -const should = require('chai').should(); +/* eslint-disable @typescript-eslint/no-var-requires */ +require('chai').should(); + const schema = require('../src'); const { ObjectType, StringType, NumberType, Schema } = schema; @@ -89,8 +91,8 @@ describe('#ObjectType', () => { it('Should be a valid object by flaser', () => { const schemaData = { - 'data.email': StringType().isEmail('应该是一个 email'), - 'data.age': NumberType().min(18, '年龄应该大于18岁') + 'data.email': StringType().isEmail('error1'), + 'data.age': NumberType().min(18, 'error1') }; const data = { @@ -106,7 +108,7 @@ describe('#ObjectType', () => { it('Should call async check', done => { const schema = new Schema({ - url: StringType().isURL('应该是一个 url'), + url: StringType().isURL('error1'), user: ObjectType().shape({ email: StringType().addRule((value, data) => { return new Promise(resolve => { diff --git a/test/SchemaSpec.js b/test/SchemaSpec.js index 5643491..6000413 100644 --- a/test/SchemaSpec.js +++ b/test/SchemaSpec.js @@ -1,4 +1,5 @@ -const should = require('chai').should(); +/* eslint-disable @typescript-eslint/no-var-requires */ +require('chai').should(); const schema = require('../src'); const { StringType, NumberType, Schema, SchemaModel } = schema; diff --git a/test/StringTypeSpec.js b/test/StringTypeSpec.js index 7eb8023..13b8400 100644 --- a/test/StringTypeSpec.js +++ b/test/StringTypeSpec.js @@ -1,11 +1,12 @@ -const should = require('chai').should(); +/* eslint-disable @typescript-eslint/no-var-requires */ +require('chai').should(); const schema = require('../src'); const { StringType, SchemaModel } = schema; describe('#StringType', () => { it('Should check min string length', () => { const schema = SchemaModel({ - str: StringType().minLength(5, ''), + str: StringType().minLength(5), cjkStr: StringType().minLength(5, ''), emojiStr: StringType().minLength(5, '') }); @@ -18,11 +19,15 @@ describe('#StringType', () => { schema.checkForField('emojiStr', { emojiStr: '👌👍🐱🐶🐸' }).hasError.should.equal(false); schema.checkForField('emojiStr', { emojiStr: '👌👍🐱🐶' }).hasError.should.equal(true); + + schema + .checkForField('str', { str: 'a' }) + .errorMessage.should.equal('str must be at least 5 characters'); }); it('Should check max string length', () => { const schema = SchemaModel({ - str: StringType().maxLength(4, ''), + str: StringType().maxLength(4), cjkStr: StringType().maxLength(4, ''), emojiStr: StringType().maxLength(4, '') }); @@ -33,11 +38,16 @@ describe('#StringType', () => { schema.checkForField('cjkStr', { cjkStr: '岁寒三友' }).hasError.should.equal(false); schema.checkForField('emojiStr', { emojiStr: '👌👍🐱🐶🐸' }).hasError.should.equal(true); schema.checkForField('emojiStr', { emojiStr: '👌👍🐱🐶' }).hasError.should.equal(false); + + schema + .checkForField('str', { str: 'abcde' }) + .errorMessage.should.equal('str must be at most 4 characters'); }); it('Should be required', () => { const schema = SchemaModel({ str: StringType().isRequired('isrequired'), + str1: StringType().isRequired(), str2: StringType().isRequired('isrequired', false) }); @@ -45,6 +55,10 @@ describe('#StringType', () => { schema.checkForField('str', { str: ' abcde ' }).hasError.should.equal(false); schema.checkForField('str', { str: ' ' }).hasError.should.equal(true); + schema + .checkForField('str1', { str1: '' }) + .errorMessage.should.equal('str1 is a required field'); + schema.checkForField('str2', { str2: '' }).hasError.should.equal(true); schema.checkForField('str2', { str2: ' abcde ' }).hasError.should.equal(false); schema.checkForField('str2', { str2: ' ' }).hasError.should.equal(false); @@ -67,10 +81,14 @@ describe('#StringType', () => { it('Should be one of value in array', () => { const schema = SchemaModel({ - str: StringType().isOneOf(['A', 'B', 'C'], 'error') + str: StringType().isOneOf(['A', 'B', 'C'], 'error'), + str1: StringType().isOneOf(['A', 'B', 'C']) }); schema.checkForField('str', { str: 'A' }).hasError.should.equal(false); schema.checkForField('str', { str: 'D' }).hasError.should.equal(true); schema.checkForField('str', { str: 'D' }).errorMessage.should.equal('error'); + schema + .checkForField('str1', { str1: 'D' }) + .errorMessage.should.equal('str1 must be one of the following values: A,B,C'); }); }); diff --git a/test/utilsSpec.js b/test/utilsSpec.js new file mode 100644 index 0000000..446d8b6 --- /dev/null +++ b/test/utilsSpec.js @@ -0,0 +1,59 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ +require('chai').should(); +const { formatErrorMessage, checkRequired } = require('../src/utils'); + +describe('#utils', () => { + describe('## formatErrorMessage', () => { + it('Should output the parameter `email`', () => { + const str = formatErrorMessage('${name} is a required field', { name: 'email' }); + const str2 = formatErrorMessage('${name} is a required field', { name1: 'email' }); + str.should.equal('email is a required field'); + str2.should.equal('[name] is a required field'); + }); + + it('Should output multiple parameters', () => { + const str = formatErrorMessage('${name} must contain ${minLength} to ${maxLength} items', { + name: 'tag', + minLength: 3, + maxLength: 10 + }); + + const str2 = formatErrorMessage('${name} must contain ${minLength} to ${maxLength} items', { + name: 'tag', + minLength1: 3, + maxLength: 10 + }); + str.should.equal('tag must contain 3 to 10 items'); + str2.should.equal('tag must contain [minLength] to 10 items'); + }); + + it('Should not replace parameters', () => { + const str = formatErrorMessage('name is a required field'); + str.should.equal('name is a required field'); + }); + }); + + describe('## checkRequired', () => { + it('Should check string, null and undefined', () => { + checkRequired('1').should.equal(true); + checkRequired(0).should.equal(true); + checkRequired(' ').should.equal(true); + checkRequired(' ', true).should.equal(false); + + checkRequired('').should.equal(false); + checkRequired().should.equal(false); + checkRequired(null).should.equal(false); + + checkRequired('', false, true).should.equal(true); + checkRequired(undefined, false, true).should.equal(false); + checkRequired(null, false, true).should.equal(false); + }); + + it('Should check array', () => { + checkRequired([]).should.equal(false); + checkRequired([1]).should.equal(true); + checkRequired([undefined]).should.equal(true); + checkRequired(['']).should.equal(true); + }); + }); +});