diff --git a/.mocharc.json b/.mocharc.json index afc58dc..691cfa2 100644 --- a/.mocharc.json +++ b/.mocharc.json @@ -1,6 +1,3 @@ { - "require": [ - "textlint-scripts/register" - ], - "timeout": "20000" + "timeout": 20000 } diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index 6d058ca..0000000 --- a/.prettierrc +++ /dev/null @@ -1,5 +0,0 @@ -{ - "singleQuote": true, - "trailingComma": "all", - "arrowParens": "always" -} diff --git a/package.json b/package.json index 915102e..ce78cf8 100644 --- a/package.json +++ b/package.json @@ -13,24 +13,32 @@ "repository": "textlint-rule/textlint-rule-no-dead-link", "license": "MIT", "author": "nodaguti", + "main": "lib/no-dead-link.js", + "types": "lib/no-dead-link.d.ts", "files": [ "lib", "src" ], - "main": "lib/no-dead-link.js", "scripts": { "build": "textlint-scripts build", - "prepublish": "yarn run --if-present build", - "test": "textlint-scripts test", - "watch": "textlint-scripts build --watch", "format": "prettier --write \"**/*.{js,jsx,ts,tsx,css}\"", - "prepare": "git config --local core.hooksPath .githooks" + "prepare": "git config --local core.hooksPath .githooks", + "prepublish": "yarn run --if-present build", + "test": "npm run type-check && textlint-scripts test", + "type-check": "tsc --noEmit", + "watch": "textlint-scripts build --watch" }, "lint-staged": { "*.{js,jsx,ts,tsx,css}": [ "prettier --write" ] }, + "prettier": { + "printWidth": 120, + "singleQuote": false, + "tabWidth": 4, + "trailingComma": "none" + }, "dependencies": { "fs-extra": "^8.1.0", "get-url-origin": "^1.0.1", @@ -41,20 +49,25 @@ "textlint-rule-helper": "^2.2.2" }, "devDependencies": { + "@textlint/ast-node-types": "^12.2.2", + "@textlint/types": "^12.2.2", + "@types/minimatch": "^5.1.2", + "@types/mocha": "^10.0.0", + "@types/node": "^18.11.7", + "@types/node-fetch": "^2.6.2", + "cross-env": "^7.0.3", "lint-staged": "^13.0.3", + "mocha": "^10.1.0", "prettier": "^2.7.1", "textlint": "^12.2.2", "textlint-scripts": "^12.2.2", - "textlint-tester": "^12.2.2" + "textlint-tester": "^12.2.2", + "ts-node": "^10.9.1", + "ts-node-test-register": "^10.0.0", + "typescript": "^4.8.4" }, + "packageManager": "yarn@1.22.15", "engines": { "node": ">=4" - }, - "packageManager": "yarn@1.22.15", - "prettier": { - "singleQuote": false, - "printWidth": 120, - "tabWidth": 4, - "trailingComma": "none" } } diff --git a/src/no-dead-link.js b/src/no-dead-link.ts similarity index 74% rename from src/no-dead-link.js rename to src/no-dead-link.ts index 2f5c09a..e58e048 100644 --- a/src/no-dead-link.js +++ b/src/no-dead-link.ts @@ -1,7 +1,7 @@ import { RuleHelper } from "textlint-rule-helper"; -import fetch from "node-fetch"; +import fetch, { RequestInit } from "node-fetch"; import URL from "url"; -import fs from "fs-extra"; +import fs from "fs/promises"; import minimatch from "minimatch"; import { isAbsolute } from "path"; import { getURLOrigin } from "get-url-origin"; @@ -9,11 +9,28 @@ import pMemoize from "p-memoize"; import PQueue from "p-queue"; import * as http from "http"; import * as https from "https"; - -const DEFAULT_OPTIONS = { +import { TextlintRuleReporter } from "@textlint/types"; +import { TxtNode } from "@textlint/ast-node-types"; + +export type Options = { + checkRelative: boolean; // {boolean} `false` disables the checks for relative URIs. + baseURI: null | string; // {String|null} a base URI to resolve relative URIs. + ignore: string[]; // {Array} URIs to be skipped from availability checks. + ignoreRedirects: boolean; // {boolean} `false` ignores redirect status codes. + preferGET: string[]; // {Array} origins to prefer GET over HEAD. + retry: number; // {number} Max retry count + concurrency: number; // {number} Concurrency count of linting link [Experimental] + interval: number; // The length of time in milliseconds before the interval count resets. Must be finite. [Experimental] + intervalCap: number; // The max number of runs in the given interval of time. [Experimental] + keepAlive: boolean; // {boolean} if it is true, use keepAlive for checking request [Experimental] + userAgent: string; // {String} a UserAgent, + maxRetryTime: number; // (number) The max of waiting seconds for retry, if response returns `After-Retry` header. +}; +const DEFAULT_OPTIONS: Options = { checkRelative: true, // {boolean} `false` disables the checks for relative URIs. baseURI: null, // {String|null} a base URI to resolve relative URIs. ignore: [], // {Array} URIs to be skipped from availability checks. + ignoreRedirects: false, // {boolean} `false` ignores redirect status codes. preferGET: [], // {Array} origins to prefer GET over HEAD. retry: 3, // {number} Max retry count concurrency: 8, // {number} Concurrency count of linting link [Experimental] @@ -33,7 +50,7 @@ const URI_REGEXP = * @param {string} uri * @return {boolean} */ -function isHttp(uri) { +function isHttp(uri: string) { const { protocol } = URL.parse(uri); return protocol === "http:" || protocol === "https:"; } @@ -44,7 +61,7 @@ function isHttp(uri) { * @return {boolean} * @see https://github.com/panosoft/is-local-path */ -function isRelative(uri) { +function isRelative(uri: string) { const { host } = URL.parse(uri); return host === null || host === ""; } @@ -55,7 +72,7 @@ function isRelative(uri) { * @return {boolean} * @see https://nodejs.org/api/path.html#path_path_isabsolute_path */ -function isLocal(uri) { +function isLocal(uri: string) { if (isAbsolute(uri)) { return true; } @@ -68,11 +85,11 @@ function isLocal(uri) { * @param {number} code * @returns {boolean} */ -function isRedirect(code) { +function isRedirect(code: number) { return code === 301 || code === 302 || code === 303 || code === 307 || code === 308; } -function isIgnored(uri, ignore = []) { +function isIgnored(uri: string, ignore: string[] = []) { return ignore.some((pattern) => minimatch(uri, pattern)); } @@ -81,7 +98,7 @@ function isIgnored(uri, ignore = []) { * @param ms * @returns {Promise} */ -function waitTimeMs(ms) { +function waitTimeMs(ms: number) { return new Promise((resolve) => { setTimeout(resolve, ms); }); @@ -92,16 +109,16 @@ const keepAliveAgents = { https: new https.Agent({ keepAlive: true }) }; -const createFetchWithRuleDefaults = (ruleOptions) => { +const createFetchWithRuleDefaults = (ruleOptions: Options) => { /** * Use library agent, avoid to use global.http(s)Agent * Want to avoid Socket hang up * @param parsedURL * @returns {module:http.Agent|null|module:https.Agent} */ - const getAgent = (parsedURL) => { + const getAgent = (parsedURL: URL) => { if (!ruleOptions.keepAlive) { - return null; + return; } if (parsedURL.protocol === "http:") { return keepAliveAgents.http; @@ -109,7 +126,7 @@ const createFetchWithRuleDefaults = (ruleOptions) => { return keepAliveAgents.https; }; - return (uri, fetchOptions) => { + return (uri: string, fetchOptions: RequestInit) => { const { host } = URL.parse(uri); return fetch(uri, { ...fetchOptions, @@ -123,21 +140,34 @@ const createFetchWithRuleDefaults = (ruleOptions) => { headers: { "User-Agent": ruleOptions.userAgent, Accept: "*/*", - // Same host for target url - // https://github.com/textlint-rule/textlint-rule-no-dead-link/issues/111 - Host: host + // avoid assign null to Host + ...(host + ? { + // Same host for target url + // https://github.com/textlint-rule/textlint-rule-no-dead-link/issues/111 + Host: host + } + : {}) }, // custom http(s).agent agent: getAgent }); }; }; + +type AliveFunctionReturn = { + ok: boolean; + message: string; + redirected?: boolean; + redirectTo?: string | null; +}; + /** * Create isAliveURI function with ruleOptions * @param {object} ruleOptions * @returns {isAliveURI} */ -const createCheckAliveURL = (ruleOptions) => { +const createCheckAliveURL = (ruleOptions: Options) => { // Create fetch function for this rule const fetchWithDefaults = createFetchWithRuleDefaults(ruleOptions); /** @@ -155,8 +185,13 @@ const createCheckAliveURL = (ruleOptions) => { * @param {number} currentRetryCount * @return {{ ok: boolean, redirect?: string, message: string }} */ - return async function isAliveURI(uri, method = "HEAD", maxRetryCount = 3, currentRetryCount = 0) { - const opts = { + return async function isAliveURI( + uri: string, + method: string = "HEAD", + maxRetryCount: number = 3, + currentRetryCount: number = 0 + ): Promise { + const opts: RequestInit = { method, // Use `manual` redirect behaviour to get HTTP redirect status code // and see what kind of redirect is occurring @@ -167,6 +202,15 @@ const createCheckAliveURL = (ruleOptions) => { // redirected if (isRedirect(res.status)) { const redirectedUrl = res.headers.get("Location"); + // Status code is 301 or 302, but Location header is not set + if (redirectedUrl === null) { + return { + ok: false, + redirected: true, + redirectTo: null, + message: `${res.status} ${res.statusText}` + }; + } const finalRes = await fetchWithDefaults(redirectedUrl, { ...opts, redirect: "follow" }); const { hash } = URL.parse(uri); return { @@ -186,7 +230,8 @@ const createCheckAliveURL = (ruleOptions) => { const retrySeconds = res.headers.get("Retry-After"); // If the response has `Retry-After` header, prefer it // else exponential retry: 0ms -> 100ms -> 200ms -> 400ms -> 800ms ... - const retryWaitTimeMs = retrySeconds !== null ? retrySeconds * 1000 : currentRetryCount ** 2 * 100; + const retryWaitTimeMs = + retrySeconds !== null ? Number(retrySeconds) * 1000 : currentRetryCount ** 2 * 100; const maxRetryTimeMs = ruleOptions.maxRetryTime * 1000; if (retryWaitTimeMs <= maxRetryTimeMs) { await waitTimeMs(retryWaitTimeMs); @@ -198,7 +243,7 @@ const createCheckAliveURL = (ruleOptions) => { ok: res.ok, message: `${res.status} ${res.statusText}` }; - } catch (ex) { + } catch (ex: any) { // Retry with `GET` method if the request failed // as some servers don't accept `HEAD` requests but are OK with `GET` requests. // https://github.com/textlint-rule/textlint-rule-no-dead-link/pull/86 @@ -217,14 +262,14 @@ const createCheckAliveURL = (ruleOptions) => { /** * Check if a given file exists */ -async function isAliveLocalFile(filePath) { +async function isAliveLocalFile(filePath: string): Promise { try { await fs.access(filePath.replace(/[?#].*?$/, "")); - return { - ok: true + ok: true, + message: "OK" }; - } catch (ex) { + } catch (ex: any) { return { ok: false, message: ex.message @@ -232,7 +277,7 @@ async function isAliveLocalFile(filePath) { } } -function reporter(context, options = {}) { +const reporter: TextlintRuleReporter = (context, options) => { const { Syntax, getSource, report, RuleError, fixer, getFilePath } = context; const helper = new RuleHelper(context); const ruleOptions = { ...DEFAULT_OPTIONS, ...options }; @@ -248,7 +293,7 @@ function reporter(context, options = {}) { * @param {number} index column number the URI is located at. * @param {number} maxRetryCount retry count of linting */ - const lint = async ({ node, uri, index }, maxRetryCount) => { + const lint = async ({ node, uri, index }: { node: TxtNode; uri: string; index: number }, maxRetryCount: number) => { if (isIgnored(uri, ruleOptions.ignore)) { return; } @@ -296,16 +341,15 @@ function reporter(context, options = {}) { report(node, new RuleError(lintMessage, { index })); } else if (redirected) { const lintMessage = `${uri} is redirected to ${redirectTo}. (${message})`; - const fix = fixer.replaceTextRange([index, index + uri.length], redirectTo); + const fix = redirectTo ? fixer.replaceTextRange([index, index + uri.length], redirectTo) : undefined; report(node, new RuleError(lintMessage, { fix, index })); } }; /** * URIs to be checked. - * @type {Array<{ node: TextLintNode, uri: string, index: number }>} */ - const URIs = []; + const URIs: { node: TxtNode; uri: string; index: number }[] = []; return { [Syntax.Str](node) { @@ -322,8 +366,12 @@ function reporter(context, options = {}) { // Use `String#replace` instead of `RegExp#exec` to allow us // perform RegExp matches in an iterate and immutable manner - text.replace(URI_REGEXP, (uri, index) => { - URIs.push({ node, uri, index }); + const matches = text.matchAll(URI_REGEXP); + Array.from(matches).forEach((match) => { + const url = match[0]; + if (url && match.input !== undefined && match.index !== undefined) { + URIs.push({ node, uri: url, index: match.index }); + } }); }, @@ -378,8 +426,7 @@ function reporter(context, options = {}) { return queue.addAll(linkTasks); } }; -} - +}; export default { linter: reporter, fixer: reporter diff --git a/test/no-dead-link.js b/test/no-dead-link.ts similarity index 99% rename from test/no-dead-link.js rename to test/no-dead-link.ts index 26a606f..419a736 100644 --- a/test/no-dead-link.js +++ b/test/no-dead-link.ts @@ -1,4 +1,3 @@ -/* eslint-disable max-len */ import TextlintTester from "textlint-tester"; import fs from "fs"; import path from "path"; @@ -6,6 +5,7 @@ import rule from "../src/no-dead-link"; const tester = new TextlintTester(); +// @ts-expect-error tester.run("no-dead-link", rule, { valid: [ "should ignore non-http url [email address](mailto:mail.example.com) by default", diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..575b166 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,36 @@ +{ + "compilerOptions": { + /* Basic Options */ + "module": "commonjs", + "moduleResolution": "node", + "esModuleInterop": true, + "newLine": "LF", + "noEmit": true, + "target": "ES2018", + "sourceMap": true, + "declaration": true, + "jsx": "preserve", + "lib": [ + "esnext", + "dom" + ], + /* Strict Type-Checking Options */ + "strict": true, + /* Additional Checks */ + /* Report errors on unused locals. */ + "noUnusedLocals": true, + /* Report errors on unused parameters. */ + "noUnusedParameters": true, + /* Report error when not all code paths in function return a value. */ + "noImplicitReturns": true, + /* Report errors for fallthrough cases in switch statement. */ + "noFallthroughCasesInSwitch": true + }, + "include": [ + "**/*" + ], + "exclude": [ + ".git", + "node_modules" + ] +} diff --git a/yarn.lock b/yarn.lock index 7f25448..f84b331 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1055,6 +1055,13 @@ "@babel/helper-validator-identifier" "^7.19.1" to-fast-properties "^2.0.0" +"@cspotcode/source-map-support@^0.8.0": + version "0.8.1" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" + integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== + dependencies: + "@jridgewell/trace-mapping" "0.3.9" + "@jridgewell/gen-mapping@^0.1.0": version "0.1.1" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz#e5d2e450306a9491e3bd77e323e38d7aff315996" @@ -1072,7 +1079,7 @@ "@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/trace-mapping" "^0.3.9" -"@jridgewell/resolve-uri@3.1.0": +"@jridgewell/resolve-uri@3.1.0", "@jridgewell/resolve-uri@^3.0.3": version "3.1.0" resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== @@ -1087,6 +1094,14 @@ resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== +"@jridgewell/trace-mapping@0.3.9": + version "0.3.9" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" + integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping@^0.3.8", "@jridgewell/trace-mapping@^0.3.9": version "0.3.16" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.16.tgz#a7982f16c18cae02be36274365433e5b49d7b23f" @@ -1240,6 +1255,26 @@ resolved "https://registry.yarnpkg.com/@textlint/utils/-/utils-12.2.2.tgz#48ba9dace5b25d2945a0d8cfbd19571324ea84e9" integrity sha512-74p3VWj5KlmXs+gFRJALEuUsyt/Sz4t91KQ//LAX1zNTY/aK0nk8LxipUcDZeBHArn3Gh5nf3SwlTgUZ7jvNrQ== +"@tsconfig/node10@^1.0.7": + version "1.0.9" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2" + integrity sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA== + +"@tsconfig/node12@^1.0.7": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" + integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== + +"@tsconfig/node14@^1.0.0": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" + integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== + +"@tsconfig/node16@^1.0.2": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.3.tgz#472eaab5f15c1ffdd7f8628bd4c4f753995ec79e" + integrity sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ== + "@types/color-name@^1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" @@ -1252,11 +1287,34 @@ dependencies: "@types/unist" "*" +"@types/minimatch@^5.1.2": + version "5.1.2" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-5.1.2.tgz#07508b45797cb81ec3f273011b054cd0755eddca" + integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA== + "@types/minimist@^1.2.0": version "1.2.2" resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.2.tgz#ee771e2ba4b3dc5b372935d549fd9617bf345b8c" integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ== +"@types/mocha@^10.0.0": + version "10.0.0" + resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-10.0.0.tgz#3d9018c575f0e3f7386c1de80ee66cc21fbb7a52" + integrity sha512-rADY+HtTOA52l9VZWtgQfn4p+UDVM2eDVkMZT1I6syp0YKxW2F9v+0pbRZLsvskhQv/vMb6ZfCay81GHbz5SHg== + +"@types/node-fetch@^2.6.2": + version "2.6.2" + resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.2.tgz#d1a9c5fd049d9415dce61571557104dec3ec81da" + integrity sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A== + dependencies: + "@types/node" "*" + form-data "^3.0.0" + +"@types/node@*", "@types/node@^18.11.7": + version "18.11.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.7.tgz#8ccef136f240770c1379d50100796a6952f01f94" + integrity sha512-LhFTglglr63mNXUSRYD8A+ZAIu5sFqNJ4Y2fPuY7UlrySJH87rRRlhtVmMHplmfk5WkoJGmDjE9oiTfyX94CpQ== + "@types/normalize-package-data@^2.4.0": version "2.4.0" resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e" @@ -1272,6 +1330,16 @@ resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q== +acorn-walk@^8.1.1: + version "8.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" + integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== + +acorn@^8.4.1: + version "8.8.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.1.tgz#0a3f9cbecc4ec3bea6f0a80b66ae8dd2da250b73" + integrity sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA== + aggregate-error@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.0.1.tgz#db2fe7246e536f40d9b5442a39e117d7dd6a24e0" @@ -1352,6 +1420,11 @@ anymatch@~3.1.2: normalize-path "^3.0.0" picomatch "^2.0.4" +arg@^4.1.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== + argparse@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" @@ -1379,6 +1452,11 @@ async@^3.2.3: resolved "https://registry.yarnpkg.com/async/-/async-3.2.4.tgz#2d22e00f8cddeb5fde5dd33522b56d1cf569a81c" integrity sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ== +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + babel-plugin-dynamic-import-node@^2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" @@ -1646,6 +1724,13 @@ colorette@^2.0.16, colorette@^2.0.17: resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.19.tgz#cdf044f47ad41a0f4b56b3a0d5b4e6e1a2d5a798" integrity sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ== +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + commander@^4.0.1: version "4.1.1" resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" @@ -1685,7 +1770,19 @@ core-js-compat@^3.25.1: dependencies: browserslist "^4.21.4" -cross-spawn@^7.0.3: +create-require@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" + integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== + +cross-env@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf" + integrity sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw== + dependencies: + cross-spawn "^7.0.1" + +cross-spawn@^7.0.1, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -1706,7 +1803,7 @@ debug@4.3.3: dependencies: ms "2.1.2" -debug@^4.0.0, debug@^4.3.4: +debug@4.3.4, debug@^4.0.0, debug@^4.3.4: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -1762,12 +1859,17 @@ define-properties@^1.1.2, define-properties@^1.1.3: dependencies: object-keys "^1.0.12" +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + diff@5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== -diff@^4.0.2: +diff@^4.0.1, diff@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== @@ -1983,6 +2085,15 @@ flatted@^2.0.0: resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== +form-data@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" + integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + format@^0.2.0: version "0.2.2" resolved "https://registry.yarnpkg.com/format/-/format-0.2.2.tgz#d6170107e9efdc4ed30c9dc39016df942b5cb58b" @@ -2566,6 +2677,11 @@ make-dir@^2.0.0, make-dir@^2.1.0: pify "^4.0.1" semver "^5.6.0" +make-error@^1.1.1: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + map-age-cleaner@^0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a" @@ -2799,6 +2915,18 @@ micromatch@^4.0.5: braces "^3.0.2" picomatch "^2.3.1" +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + mimic-fn@^2.0.0, mimic-fn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" @@ -2821,6 +2949,13 @@ minimatch@4.2.1: dependencies: brace-expansion "^1.1.7" +minimatch@5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.0.1.tgz#fb9022f7528125187c92bd9e9b6366be1cf3415b" + integrity sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g== + dependencies: + brace-expansion "^2.0.1" + minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" @@ -2875,6 +3010,33 @@ mkdirp@^0.5.6: dependencies: minimist "^1.2.6" +mocha@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.1.0.tgz#dbf1114b7c3f9d0ca5de3133906aea3dfc89ef7a" + integrity sha512-vUF7IYxEoN7XhQpFLxQAEMtE4W91acW4B6En9l97MwE9stL1A9gusXfoHZCLVHDUJ/7V5+lbCM6yMqzo5vNymg== + dependencies: + ansi-colors "4.1.1" + browser-stdout "1.3.1" + chokidar "3.5.3" + debug "4.3.4" + diff "5.0.0" + escape-string-regexp "4.0.0" + find-up "5.0.0" + glob "7.2.0" + he "1.2.0" + js-yaml "4.1.0" + log-symbols "4.1.0" + minimatch "5.0.1" + ms "2.1.3" + nanoid "3.3.3" + serialize-javascript "6.0.0" + strip-json-comments "3.1.1" + supports-color "8.1.1" + workerpool "6.2.1" + yargs "16.2.0" + yargs-parser "20.2.4" + yargs-unparser "2.0.0" + mocha@^9.2.2: version "9.2.2" resolved "https://registry.yarnpkg.com/mocha/-/mocha-9.2.2.tgz#d70db46bdb93ca57402c809333e5a84977a88fb9" @@ -2925,6 +3087,11 @@ nanoid@3.3.1: resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.1.tgz#6347a18cac88af88f58af0b3594b723d5e99bb35" integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw== +nanoid@3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.3.tgz#fd8e8b7aa761fe807dba2d1b98fb7241bb724a25" + integrity sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w== + node-fetch@^2.6.0: version "2.6.0" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd" @@ -3976,6 +4143,32 @@ try-resolve@^1.0.1: resolved "https://registry.yarnpkg.com/try-resolve/-/try-resolve-1.0.1.tgz#cfde6fabd72d63e5797cfaab873abbe8e700e912" integrity sha1-z95vq9ctY+V5fPqrhzq76OcA6RI= +ts-node-test-register@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/ts-node-test-register/-/ts-node-test-register-10.0.0.tgz#eb8cbe40954331f2f70c8e5fb83c677965ac14f9" + integrity sha512-W8yzvufsG7/ulT65G1D218HMPf6uduojDXuSrGAaakkZlUtuLC+3pxphDktBe/N9w5Gi7teAxKCaTpBH5p6fkQ== + dependencies: + read-pkg "^5.2.0" + +ts-node@^10.9.1: + version "10.9.1" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.1.tgz#e73de9102958af9e1f0b168a6ff320e25adcff4b" + integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw== + dependencies: + "@cspotcode/source-map-support" "^0.8.0" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" + arg "^4.1.0" + create-require "^1.1.0" + diff "^4.0.1" + make-error "^1.1.1" + v8-compile-cache-lib "^3.0.1" + yn "3.1.1" + tslib@^2.1.0: version "2.4.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" @@ -4008,6 +4201,11 @@ type-fest@^0.8.1: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== +typescript@^4.8.4: + version "4.8.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.4.tgz#c464abca159669597be5f96b8943500b238e60e6" + integrity sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ== + unicode-canonical-property-names-ecmascript@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818" @@ -4120,6 +4318,11 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" +v8-compile-cache-lib@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" + integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== + validate-npm-package-license@^3.0.1: version "3.0.4" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" @@ -4163,6 +4366,11 @@ workerpool@6.2.0: resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.0.tgz#827d93c9ba23ee2019c3ffaff5c27fccea289e8b" integrity sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A== +workerpool@6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.1.tgz#46fc150c17d826b86a008e5a4508656777e9c343" + integrity sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw== + wrap-ansi@^6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" @@ -4246,6 +4454,11 @@ yargs@16.2.0: y18n "^5.0.5" yargs-parser "^20.2.2" +yn@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== + yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"