From a1549764e3175d1648532b08c16bc97edea9b6a0 Mon Sep 17 00:00:00 2001 From: "Chris West (Faux)" Date: Thu, 3 Dec 2020 06:24:13 +0000 Subject: [PATCH 01/15] feat: expose test deadline --- e2e/__tests__/__snapshots__/deadlines.ts.snap | 41 +++++++++++++++++++ e2e/__tests__/deadlines.ts | 32 +++++++++++++++ e2e/deadlines/__tests__/manual-exceeded.js | 16 ++++++++ e2e/deadlines/__tests__/manual-within.js | 16 ++++++++ e2e/deadlines/package.json | 1 + packages/expect/src/types.ts | 1 + packages/jest-circus/src/deadlineTimeout.ts | 35 ++++++++++++++++ packages/jest-circus/src/eventHandler.ts | 4 ++ .../jestAdapterInit.ts | 3 ++ .../legacy-code-todo-rewrite/jestExpect.ts | 2 + packages/jest-circus/src/run.ts | 4 +- packages/jest-types/src/Circus.ts | 3 ++ packages/jest-types/src/Global.ts | 1 + 13 files changed, 157 insertions(+), 2 deletions(-) create mode 100644 e2e/__tests__/__snapshots__/deadlines.ts.snap create mode 100644 e2e/__tests__/deadlines.ts create mode 100644 e2e/deadlines/__tests__/manual-exceeded.js create mode 100644 e2e/deadlines/__tests__/manual-within.js create mode 100644 e2e/deadlines/package.json create mode 100644 packages/jest-circus/src/deadlineTimeout.ts diff --git a/e2e/__tests__/__snapshots__/deadlines.ts.snap b/e2e/__tests__/__snapshots__/deadlines.ts.snap new file mode 100644 index 000000000000..d834ad850104 --- /dev/null +++ b/e2e/__tests__/__snapshots__/deadlines.ts.snap @@ -0,0 +1,41 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`passes generally 1`] = ` +Object { + "rest": "PASS __tests__/manual-within.js + describe + ✓ it", + "summary": "Test Suites: 1 passed, 1 total +Tests: 1 passed, 1 total +Snapshots: 0 total +Time: <> +Ran all test suites matching /manual-within.js/i.", +} +`; + +exports[`throws on deadline exceeded 1`] = ` +Object { + "rest": "FAIL __tests__/manual-exceeded.js + describe + ✕ it + + ● describe › it + + deadline exceeded (waited here for <>) + + 12 | describe('describe', () => { + 13 | it('it', async () => { + > 14 | await expect.withinDeadline(sleep(200)); + | ^ + 15 | }, 50); + 16 | }); + 17 | + + at Object. (__tests__/manual-exceeded.js:14:5)", + "summary": "Test Suites: 1 failed, 1 total +Tests: 1 failed, 1 total +Snapshots: 0 total +Time: <> +Ran all test suites matching /manual-exceeded.js/i.", +} +`; diff --git a/e2e/__tests__/deadlines.ts b/e2e/__tests__/deadlines.ts new file mode 100644 index 000000000000..9017c23d8ac8 --- /dev/null +++ b/e2e/__tests__/deadlines.ts @@ -0,0 +1,32 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +import {skipSuiteOnJasmine} from '@jest/test-utils'; +import {extractSummary} from '../Utils'; +import runJest from '../runJest'; + +skipSuiteOnJasmine(); + +it('passes generally', () => { + const result = runJest('deadlines', ['manual-within.js']); + expect(result.exitCode).toBe(0); + expect(summaryWithoutTime(result)).toMatchSnapshot(); +}); + +it('throws on deadline exceeded', () => { + const result = runJest('deadlines', ['manual-exceeded.js']); + expect(result.exitCode).toBe(1); + expect(summaryWithoutTime(result)).toMatchSnapshot(); +}); + +function summaryWithoutTime(result: {stderr: string}) { + const summary = extractSummary(result.stderr); + summary.rest = summary.rest.replace( + /(waited here for) \d+ms/, + '$1 <>', + ); + return summary; +} diff --git a/e2e/deadlines/__tests__/manual-exceeded.js b/e2e/deadlines/__tests__/manual-exceeded.js new file mode 100644 index 000000000000..db678497e409 --- /dev/null +++ b/e2e/deadlines/__tests__/manual-exceeded.js @@ -0,0 +1,16 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +'use strict'; + +const sleep = duration => new Promise(resolve => setTimeout(resolve, duration)); + +describe('describe', () => { + it('it', async () => { + await expect.withinDeadline(sleep(200)); + }, 50); +}); diff --git a/e2e/deadlines/__tests__/manual-within.js b/e2e/deadlines/__tests__/manual-within.js new file mode 100644 index 000000000000..383185cb7deb --- /dev/null +++ b/e2e/deadlines/__tests__/manual-within.js @@ -0,0 +1,16 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +'use strict'; + +const sleep = duration => new Promise(resolve => setTimeout(resolve, duration)); + +describe('describe', () => { + it('it', async () => { + await expect.withinDeadline(sleep(50)); + }, 200); +}); diff --git a/e2e/deadlines/package.json b/e2e/deadlines/package.json new file mode 100644 index 000000000000..0967ef424bce --- /dev/null +++ b/e2e/deadlines/package.json @@ -0,0 +1 @@ +{} diff --git a/packages/expect/src/types.ts b/packages/expect/src/types.ts index 04246ef95dd3..e34b0903734f 100644 --- a/packages/expect/src/types.ts +++ b/packages/expect/src/types.ts @@ -81,6 +81,7 @@ export type Expect = { objectContaining(sample: Record): AsymmetricMatcher; stringContaining(expected: string): AsymmetricMatcher; stringMatching(expected: string | RegExp): AsymmetricMatcher; + withinDeadline(promise: Promise): Promise; [id: string]: AsymmetricMatcher; not: {[id: string]: AsymmetricMatcher}; }; diff --git a/packages/jest-circus/src/deadlineTimeout.ts b/packages/jest-circus/src/deadlineTimeout.ts new file mode 100644 index 000000000000..bd29eaad05ae --- /dev/null +++ b/packages/jest-circus/src/deadlineTimeout.ts @@ -0,0 +1,35 @@ +import {getState} from './state'; + +export async function withinDeadline(promise: Promise): Promise { + const deadline = getState()?.currentlyRunningTest?.deadline; + if (undefined === deadline) { + throw new Error('bug! no deadline available'); + } + return timeout(promise, deadline - Date.now()); +} + +function isUs(line: string): boolean { + return line.includes('deadlineTimeout') && line.includes('jest-circus'); +} + +async function timeout(promise: Promise, ms: number): Promise { + let timeoutId; + try { + return await Promise.race([ + promise, + (async () => { + await new Promise(resolve => { + timeoutId = setTimeout(resolve, ms); + }); + const here = new Error(`deadline exceeded (waited here for ${ms}ms)`); + here.stack = here.stack + ?.split('\n') + .filter(line => !isUs(line)) + .join('\n'); + throw here; + })(), + ]); + } finally { + clearTimeout(timeoutId); + } +} diff --git a/packages/jest-circus/src/eventHandler.ts b/packages/jest-circus/src/eventHandler.ts index af46770bcc62..7db164f93d83 100644 --- a/packages/jest-circus/src/eventHandler.ts +++ b/packages/jest-circus/src/eventHandler.ts @@ -188,6 +188,10 @@ const eventHandler: Circus.EventHandler = ( event.test.invocations += 1; break; } + case 'test_fn_start': { + event.test.deadline = Date.now() + event.timeout - 20; + break; + } case 'test_fn_failure': { const { error, diff --git a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts index 61c68b332117..a540f9309688 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts @@ -80,6 +80,9 @@ export const initialize = async ({ xtest: globals.it.skip, }; + globalsObject.test.deadline = () => + getRunnerState()?.currentlyRunningTest?.deadline; + globalsObject.test.concurrent = (test => { const concurrent = ( testName: string, diff --git a/packages/jest-circus/src/legacy-code-todo-rewrite/jestExpect.ts b/packages/jest-circus/src/legacy-code-todo-rewrite/jestExpect.ts index a13ce01bd3a8..a50c34da1e3a 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestExpect.ts +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/jestExpect.ts @@ -14,6 +14,7 @@ import { toThrowErrorMatchingInlineSnapshot, toThrowErrorMatchingSnapshot, } from 'jest-snapshot'; +import {withinDeadline} from '../deadlineTimeout'; export type Expect = typeof expect; @@ -27,6 +28,7 @@ export default (config: Pick): Expect => { }); expect.addSnapshotSerializer = addSerializer; + expect.withinDeadline = withinDeadline; return expect; }; diff --git a/packages/jest-circus/src/run.ts b/packages/jest-circus/src/run.ts index d49cfdcb31bf..2066229600ae 100644 --- a/packages/jest-circus/src/run.ts +++ b/packages/jest-circus/src/run.ts @@ -148,8 +148,8 @@ const _callCircusHook = async ({ test?: Circus.TestEntry; testContext?: Circus.TestContext; }): Promise => { - await dispatch({hook, name: 'hook_start'}); const timeout = hook.timeout || getState().testTimeout; + await dispatch({hook, name: 'hook_start', timeout}); try { await callAsyncCircusFn(hook, testContext, { @@ -166,8 +166,8 @@ const _callCircusTest = async ( test: Circus.TestEntry, testContext: Circus.TestContext, ): Promise => { - await dispatch({name: 'test_fn_start', test}); const timeout = test.timeout || getState().testTimeout; + await dispatch({name: 'test_fn_start', test, timeout}); invariant(test.fn, `Tests with no 'fn' should have 'mode' set to 'skipped'`); if (test.errors.length) { diff --git a/packages/jest-types/src/Circus.ts b/packages/jest-types/src/Circus.ts index 3dab1d8d7abe..79932f2fd4e2 100644 --- a/packages/jest-types/src/Circus.ts +++ b/packages/jest-types/src/Circus.ts @@ -91,6 +91,7 @@ export type AsyncEvent = | { name: 'hook_start'; hook: Hook; + timeout: number; } | { name: 'hook_success'; @@ -108,6 +109,7 @@ export type AsyncEvent = | { name: 'test_fn_start'; test: TestEntry; + timeout: number; } | { name: 'test_fn_success'; @@ -240,4 +242,5 @@ export type TestEntry = { duration?: number | null; status?: TestStatus | null; // whether the test has been skipped or run already timeout?: number; + deadline?: number; }; diff --git a/packages/jest-types/src/Global.ts b/packages/jest-types/src/Global.ts index 46a4d0669b96..ee053d15408b 100644 --- a/packages/jest-types/src/Global.ts +++ b/packages/jest-types/src/Global.ts @@ -75,6 +75,7 @@ export interface HookBase { export interface ItBase { (testName: TestName, fn: TestFn, timeout?: number): void; each: Each; + deadline: () => number | undefined; } export interface It extends ItBase { From b577a79b3816567ca293292803a8f076f2c5a7e0 Mon Sep 17 00:00:00 2001 From: "Chris West (Faux)" Date: Thu, 3 Dec 2020 07:08:51 +0000 Subject: [PATCH 02/15] feat: deadline plugin --- .../babelPluginJestDeadlines.test.ts.snap | 51 + .../babelPluginJestDeadlines.test.ts | 46 + .../__tests__/plain.test.js | 14 + .../__tests__/typescript.test.ts | 15 + .../babel.config.js | 17 + e2e/babel-plugin-jest-deadlines/package.json | 15 + e2e/babel-plugin-jest-deadlines/yarn.lock | 1563 +++++++++++++++++ .../babel-plugin-jest-deadlines/.npmignore | 5 + .../babel-plugin-jest-deadlines/package.json | 37 + .../deadlinesPlugin.test.ts.snap | 93 + .../src/__tests__/deadlinesPlugin.test.ts | 67 + .../babel-plugin-jest-deadlines/src/index.ts | 51 + .../babel-plugin-jest-deadlines/tsconfig.json | 7 + yarn.lock | 18 + 14 files changed, 1999 insertions(+) create mode 100644 e2e/__tests__/__snapshots__/babelPluginJestDeadlines.test.ts.snap create mode 100644 e2e/__tests__/babelPluginJestDeadlines.test.ts create mode 100644 e2e/babel-plugin-jest-deadlines/__tests__/plain.test.js create mode 100644 e2e/babel-plugin-jest-deadlines/__tests__/typescript.test.ts create mode 100644 e2e/babel-plugin-jest-deadlines/babel.config.js create mode 100644 e2e/babel-plugin-jest-deadlines/package.json create mode 100644 e2e/babel-plugin-jest-deadlines/yarn.lock create mode 100644 packages/babel-plugin-jest-deadlines/.npmignore create mode 100644 packages/babel-plugin-jest-deadlines/package.json create mode 100644 packages/babel-plugin-jest-deadlines/src/__tests__/__snapshots__/deadlinesPlugin.test.ts.snap create mode 100644 packages/babel-plugin-jest-deadlines/src/__tests__/deadlinesPlugin.test.ts create mode 100644 packages/babel-plugin-jest-deadlines/src/index.ts create mode 100644 packages/babel-plugin-jest-deadlines/tsconfig.json diff --git a/e2e/__tests__/__snapshots__/babelPluginJestDeadlines.test.ts.snap b/e2e/__tests__/__snapshots__/babelPluginJestDeadlines.test.ts.snap new file mode 100644 index 000000000000..25b6b72f0ae0 --- /dev/null +++ b/e2e/__tests__/__snapshots__/babelPluginJestDeadlines.test.ts.snap @@ -0,0 +1,51 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`passes generally 1`] = ` +Object { + "rest": "FAIL __tests__/plain.test.js + ✕ exceeded + + ● exceeded + + deadline exceeded (waited here for <>) + + 11 | test('exceeded', async () => { + 12 | await sleep(10); + > 13 | await sleep(200); + | ^ + 14 | }, 50); + 15 | + + at Object. (__tests__/plain.test.js:13:3)", + "summary": "Test Suites: 1 failed, 1 total +Tests: 1 failed, 1 total +Snapshots: 0 total +Time: <> +Ran all test suites matching /plain.test.js/i.", +} +`; + +exports[`throws on deadline exceeded 1`] = ` +Object { + "rest": "FAIL __tests__/typescript.test.ts + ✕ exceeded + + ● exceeded + + deadline exceeded (waited here for <>) + + 12 | test('exceeded', async () => { + 13 | await sleep(10); + > 14 | await sleep(200); + | ^ + 15 | }, 50); + 16 | + + at Object. (__tests__/typescript.test.ts:14:3)", + "summary": "Test Suites: 1 failed, 1 total +Tests: 1 failed, 1 total +Snapshots: 0 total +Time: <> +Ran all test suites matching /typescript.test.ts/i.", +} +`; diff --git a/e2e/__tests__/babelPluginJestDeadlines.test.ts b/e2e/__tests__/babelPluginJestDeadlines.test.ts new file mode 100644 index 000000000000..c76b6095a118 --- /dev/null +++ b/e2e/__tests__/babelPluginJestDeadlines.test.ts @@ -0,0 +1,46 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import * as path from 'path'; +import {skipSuiteOnJasmine} from '@jest/test-utils'; +import {extractSummary, runYarnInstall} from '../Utils'; +import runJest from '../runJest'; + +const DIR = path.resolve(__dirname, '..', 'babel-plugin-jest-deadlines'); + +beforeEach(() => { + runYarnInstall(DIR); +}); + +skipSuiteOnJasmine(); + +it('passes generally', () => { + const result = runJest('babel-plugin-jest-deadlines', [ + '--no-cache', + 'plain.test.js', + ]); + expect(result.exitCode).toBe(1); + expect(summaryWithoutTime(result)).toMatchSnapshot(); +}); + +it('throws on deadline exceeded', () => { + const result = runJest('babel-plugin-jest-deadlines', [ + '--no-cache', + 'typescript.test.ts', + ]); + expect(result.exitCode).toBe(1); + expect(summaryWithoutTime(result)).toMatchSnapshot(); +}); + +function summaryWithoutTime(result: {stderr: string}) { + const summary = extractSummary(result.stderr); + summary.rest = summary.rest.replace( + /(waited here for) \d+ms/, + '$1 <>', + ); + return summary; +} diff --git a/e2e/babel-plugin-jest-deadlines/__tests__/plain.test.js b/e2e/babel-plugin-jest-deadlines/__tests__/plain.test.js new file mode 100644 index 000000000000..30278290f0ad --- /dev/null +++ b/e2e/babel-plugin-jest-deadlines/__tests__/plain.test.js @@ -0,0 +1,14 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + */ + +const sleep = duration => new Promise(resolve => setTimeout(resolve, duration)); + +test('exceeded', async () => { + await sleep(10); + await sleep(200); +}, 50); diff --git a/e2e/babel-plugin-jest-deadlines/__tests__/typescript.test.ts b/e2e/babel-plugin-jest-deadlines/__tests__/typescript.test.ts new file mode 100644 index 000000000000..a0d3f52bbad4 --- /dev/null +++ b/e2e/babel-plugin-jest-deadlines/__tests__/typescript.test.ts @@ -0,0 +1,15 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + */ + +const sleep = (duration: number) => + new Promise(resolve => setTimeout(resolve, duration)); + +test('exceeded', async () => { + await sleep(10); + await sleep(200); +}, 50); diff --git a/e2e/babel-plugin-jest-deadlines/babel.config.js b/e2e/babel-plugin-jest-deadlines/babel.config.js new file mode 100644 index 000000000000..91872ffbda88 --- /dev/null +++ b/e2e/babel-plugin-jest-deadlines/babel.config.js @@ -0,0 +1,17 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +module.exports = { + overrides: [ + { + presets: ['@babel/preset-typescript'], + test: '**/*.ts', + }, + ], + plugins: ['jest-deadlines'], + presets: [['@babel/preset-env', {targets: {node: 'current'}}]], +}; diff --git a/e2e/babel-plugin-jest-deadlines/package.json b/e2e/babel-plugin-jest-deadlines/package.json new file mode 100644 index 000000000000..405985766a98 --- /dev/null +++ b/e2e/babel-plugin-jest-deadlines/package.json @@ -0,0 +1,15 @@ +{ + "dependencies": { + "@babel/preset-env": "^7.0.0", + "@babel/preset-typescript": "^7.0.0", + "react": "*" + }, + "jest": { + "testEnvironment": "node", + "transformIgnorePatterns": [ + "jest-circus", + "jest-environment-node", + "jest-jasmine2" + ] + } +} diff --git a/e2e/babel-plugin-jest-deadlines/yarn.lock b/e2e/babel-plugin-jest-deadlines/yarn.lock new file mode 100644 index 000000000000..a0452f03b55c --- /dev/null +++ b/e2e/babel-plugin-jest-deadlines/yarn.lock @@ -0,0 +1,1563 @@ +# This file is generated by running "yarn install" inside your project. +# Manual changes might be lost - proceed with caution! + +__metadata: + version: 4 + cacheKey: 7 + +"@babel/code-frame@npm:^7.10.4": + version: 7.10.4 + resolution: "@babel/code-frame@npm:7.10.4" + dependencies: + "@babel/highlight": ^7.10.4 + checksum: 05245d3b22a3ae849439195c4ee9ce9903dfd8c3fcb5124e77923c45e9f1ceac971cce4c61505974f411a9db432949531abe10ddee92937a0a9c306dc380a5b2 + languageName: node + linkType: hard + +"@babel/compat-data@npm:^7.12.5, @babel/compat-data@npm:^7.12.7": + version: 7.12.7 + resolution: "@babel/compat-data@npm:7.12.7" + checksum: 96e60c267b955a1bc40dcfa845cb10b9d94d1c0f3c76247c00464173e1e45e94b4755246c1cefdd875ec59902effbfd9a99bd0e9d6a364fd04c51af1aa88f6d9 + languageName: node + linkType: hard + +"@babel/generator@npm:^7.12.5": + version: 7.12.5 + resolution: "@babel/generator@npm:7.12.5" + dependencies: + "@babel/types": ^7.12.5 + jsesc: ^2.5.1 + source-map: ^0.5.0 + checksum: 7706cb3d29060e6dfcdbc982ded9a02f0bda36329cc35aabc6b3f9f30ef7b3b3bcaba51c24714663f3ea9529994cd3461ab8a664b26398208b9b9a96476bf43c + languageName: node + linkType: hard + +"@babel/helper-annotate-as-pure@npm:^7.10.4": + version: 7.10.4 + resolution: "@babel/helper-annotate-as-pure@npm:7.10.4" + dependencies: + "@babel/types": ^7.10.4 + checksum: 535cdf631e1e6c0bfd6820d2509c69373e2f48148505ddc2325ce8fe85302dc5681d6f6fd41261cacc458a0431edeff7c6115056144b80b02c10e111d2941c36 + languageName: node + linkType: hard + +"@babel/helper-builder-binary-assignment-operator-visitor@npm:^7.10.4": + version: 7.10.4 + resolution: "@babel/helper-builder-binary-assignment-operator-visitor@npm:7.10.4" + dependencies: + "@babel/helper-explode-assignable-expression": ^7.10.4 + "@babel/types": ^7.10.4 + checksum: 369530a1971c92d09bd3fae3387bf752abffa9a1f285ab55f45cdf0ac9a2e8ed1a28cd4dc31b0d5672ee0aac91435e3fdcf1196f67870ac0f9a768e3d9295d60 + languageName: node + linkType: hard + +"@babel/helper-compilation-targets@npm:^7.12.5": + version: 7.12.5 + resolution: "@babel/helper-compilation-targets@npm:7.12.5" + dependencies: + "@babel/compat-data": ^7.12.5 + "@babel/helper-validator-option": ^7.12.1 + browserslist: ^4.14.5 + semver: ^5.5.0 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 5e81181e04e8abef5fd03f79f6e478d46a52b4f2007831b37bc1bf92c0bf9a96ab6ba732d823f3586b1f551505dfb8fba64a573cb73b461e9276646f8acceb6e + languageName: node + linkType: hard + +"@babel/helper-create-class-features-plugin@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/helper-create-class-features-plugin@npm:7.12.1" + dependencies: + "@babel/helper-function-name": ^7.10.4 + "@babel/helper-member-expression-to-functions": ^7.12.1 + "@babel/helper-optimise-call-expression": ^7.10.4 + "@babel/helper-replace-supers": ^7.12.1 + "@babel/helper-split-export-declaration": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: d686eae70dc985b5e0dae85b7ec690930939b564be7f2c09ca2838a52f562f5753fa5d8a12f7305303597f9f8658d51cb36ec71e6e234b1d1385a36c632ea61f + languageName: node + linkType: hard + +"@babel/helper-create-regexp-features-plugin@npm:^7.12.1": + version: 7.12.7 + resolution: "@babel/helper-create-regexp-features-plugin@npm:7.12.7" + dependencies: + "@babel/helper-annotate-as-pure": ^7.10.4 + regexpu-core: ^4.7.1 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: cd9907f4e5fc41bbc780cdf870b3ebe0680f0ee5624f7f468b6ebecce9c5ae845eba2bfb68506562f2b5eb6f24f3a0fc6e55b001addeba8ca0c334b04b7de1dc + languageName: node + linkType: hard + +"@babel/helper-define-map@npm:^7.10.4": + version: 7.10.5 + resolution: "@babel/helper-define-map@npm:7.10.5" + dependencies: + "@babel/helper-function-name": ^7.10.4 + "@babel/types": ^7.10.5 + lodash: ^4.17.19 + checksum: 964cab640de84daa572d75e07216cf9d1aeeca3552acec0516d3aa10533836741f7391ab957e8b22624bd6b25473d8bd53f4b8d4af8713871601af02d31072ae + languageName: node + linkType: hard + +"@babel/helper-explode-assignable-expression@npm:^7.10.4": + version: 7.12.1 + resolution: "@babel/helper-explode-assignable-expression@npm:7.12.1" + dependencies: + "@babel/types": ^7.12.1 + checksum: cb3b265727e996324cc722e50b6ced468e4a9efced1ed0cd1b31ea7726ec1fd23f5b21dde37bd70ed30fe8870c1179ce1bb384a62b64fd72e66bc02eddd7712e + languageName: node + linkType: hard + +"@babel/helper-function-name@npm:^7.10.4": + version: 7.10.4 + resolution: "@babel/helper-function-name@npm:7.10.4" + dependencies: + "@babel/helper-get-function-arity": ^7.10.4 + "@babel/template": ^7.10.4 + "@babel/types": ^7.10.4 + checksum: 41ab8f48bbb7d4a65a90a4cf50c79c386d3c30e0dac10bc3ce311fda2ca971d82289a07570a785ebac92686854237ea1e511e74f2577a38c7ec2d67f2a250a9e + languageName: node + linkType: hard + +"@babel/helper-get-function-arity@npm:^7.10.4": + version: 7.10.4 + resolution: "@babel/helper-get-function-arity@npm:7.10.4" + dependencies: + "@babel/types": ^7.10.4 + checksum: 4f0ddd43405e5a43c0638ddeb9fd6fc562ce8f338983ae603d4824ce4b586c2ca2fbc0ca93864357ba3a28f699029653749c6b49ec8576cb512ab0f404500999 + languageName: node + linkType: hard + +"@babel/helper-hoist-variables@npm:^7.10.4": + version: 7.10.4 + resolution: "@babel/helper-hoist-variables@npm:7.10.4" + dependencies: + "@babel/types": ^7.10.4 + checksum: 0bc1976366e1535920ac46ecf89700a738bb38f1413ca42f1bc11bef708f297f011078077355dfe81b3e5af8ef696c5fb752408d6b65f85c71839c28ce95afaa + languageName: node + linkType: hard + +"@babel/helper-member-expression-to-functions@npm:^7.12.1": + version: 7.12.7 + resolution: "@babel/helper-member-expression-to-functions@npm:7.12.7" + dependencies: + "@babel/types": ^7.12.7 + checksum: 313e78a21713886062826cc146422a3e5f5576a233b1ee5b6360735171638bacdec8809b625e49d0448ef7c16232b753a8af374ecf6347496182960e9ecdd0e2 + languageName: node + linkType: hard + +"@babel/helper-module-imports@npm:^7.12.1, @babel/helper-module-imports@npm:^7.12.5": + version: 7.12.5 + resolution: "@babel/helper-module-imports@npm:7.12.5" + dependencies: + "@babel/types": ^7.12.5 + checksum: 7f63b03496f0d03dac33050e9f925b0b32c5acffb2f4f5bb5936431e5da3df03792f67033875005e00dd7a3b565ffc95b4af3da276ae6ff8f81d860d7acbfe65 + languageName: node + linkType: hard + +"@babel/helper-module-transforms@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/helper-module-transforms@npm:7.12.1" + dependencies: + "@babel/helper-module-imports": ^7.12.1 + "@babel/helper-replace-supers": ^7.12.1 + "@babel/helper-simple-access": ^7.12.1 + "@babel/helper-split-export-declaration": ^7.11.0 + "@babel/helper-validator-identifier": ^7.10.4 + "@babel/template": ^7.10.4 + "@babel/traverse": ^7.12.1 + "@babel/types": ^7.12.1 + lodash: ^4.17.19 + checksum: 902ed2b8e9ff45d33d20379f84b2269741a3a6108eb6c5e9e139186fd72e5bb405fac84bdcb7fae135c0cf4a5464d30bfb78ad00fc163b329aa9caa3630e7dd2 + languageName: node + linkType: hard + +"@babel/helper-optimise-call-expression@npm:^7.10.4": + version: 7.12.7 + resolution: "@babel/helper-optimise-call-expression@npm:7.12.7" + dependencies: + "@babel/types": ^7.12.7 + checksum: 105a32f5603b872d51e237cd2d3e25191369685f2054d5af0b77a1a6fea6bd4bc00a891ca029f5a3aec80f14855e61a624744c13223ce53ec1a433b218834a24 + languageName: node + linkType: hard + +"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.8.0, @babel/helper-plugin-utils@npm:^7.8.3": + version: 7.10.4 + resolution: "@babel/helper-plugin-utils@npm:7.10.4" + checksum: 9f617e619a3557cb5fae8885e91cd94ba4ee16fb345e0360de0d7dc037efb10cc604939ecc1038ccdb71aa37e7e78f20133d7bbbebecb8f6dcdb557650366d92 + languageName: node + linkType: hard + +"@babel/helper-remap-async-to-generator@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/helper-remap-async-to-generator@npm:7.12.1" + dependencies: + "@babel/helper-annotate-as-pure": ^7.10.4 + "@babel/helper-wrap-function": ^7.10.4 + "@babel/types": ^7.12.1 + checksum: 8bc24e91f106edd627f60ce416a20c4313caa6224f778a81b8ab56612c0ba2e84be403996f449bc8d0132ab47bf8a21a9bc66faea95643e0a50843807cd4591e + languageName: node + linkType: hard + +"@babel/helper-replace-supers@npm:^7.12.1": + version: 7.12.5 + resolution: "@babel/helper-replace-supers@npm:7.12.5" + dependencies: + "@babel/helper-member-expression-to-functions": ^7.12.1 + "@babel/helper-optimise-call-expression": ^7.10.4 + "@babel/traverse": ^7.12.5 + "@babel/types": ^7.12.5 + checksum: 5a9ac871de38e65128e082bcca925298a4dd1501b1b79d79ebf7fc3c03490dcc1e397d582f513543f908f962dcb161a0ce4d968423b0c209c4321487bf2d5ec9 + languageName: node + linkType: hard + +"@babel/helper-simple-access@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/helper-simple-access@npm:7.12.1" + dependencies: + "@babel/types": ^7.12.1 + checksum: ca44e3f694957d4026e2837905cd4f4ec60d73f49f8d65d8592afa6d797cb000f261ce7db1ed3e14b51200467f4c04917cb84ebe395f3d153462ccce1b980322 + languageName: node + linkType: hard + +"@babel/helper-skip-transparent-expression-wrappers@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/helper-skip-transparent-expression-wrappers@npm:7.12.1" + dependencies: + "@babel/types": ^7.12.1 + checksum: 2e690ed5659534f46387bde713d7c511865a309c5cd6f1d64ff94abdb64fe2e4d5e6cb6ed6c9856cbb16e9de60ecac86534b9d1eb93e877830442610889f6144 + languageName: node + linkType: hard + +"@babel/helper-split-export-declaration@npm:^7.10.4, @babel/helper-split-export-declaration@npm:^7.11.0": + version: 7.11.0 + resolution: "@babel/helper-split-export-declaration@npm:7.11.0" + dependencies: + "@babel/types": ^7.11.0 + checksum: ddfc44d0cf75ee3a73e71b18e8b9b67d256f6e8496e550ab0b1342ef8cd62dd232c13ac77569e319869b1515a9733863e69a143e76f52e9fc1b51ee374b8869b + languageName: node + linkType: hard + +"@babel/helper-validator-identifier@npm:^7.10.4": + version: 7.10.4 + resolution: "@babel/helper-validator-identifier@npm:7.10.4" + checksum: 25098ef842e3ffecdd9a7216f6173da7ad7be1b0b3e454a9f6965055154b9ad7a4acd2f218ba3d2efc0821bdab97837b3cb815844af7d72f66f89d446a54efc6 + languageName: node + linkType: hard + +"@babel/helper-validator-option@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/helper-validator-option@npm:7.12.1" + checksum: 5d9a8f67500baf464151d15ca281388e7272ed22e3b909e13ccff89b2b4cc83a3e29972f9feaacb8a372e749028b252187982a59c6e6944ce30e0d15d905ab5c + languageName: node + linkType: hard + +"@babel/helper-wrap-function@npm:^7.10.4": + version: 7.12.3 + resolution: "@babel/helper-wrap-function@npm:7.12.3" + dependencies: + "@babel/helper-function-name": ^7.10.4 + "@babel/template": ^7.10.4 + "@babel/traverse": ^7.10.4 + "@babel/types": ^7.10.4 + checksum: 4731c4ec0e7a255090cb891a986e6d14635730d1598c9983d8b5c0eab0bacb74cbc4f363c7e7e6dea88c4f3ab4a65970665ac751e656ded202c3609f49a033d3 + languageName: node + linkType: hard + +"@babel/highlight@npm:^7.10.4": + version: 7.10.4 + resolution: "@babel/highlight@npm:7.10.4" + dependencies: + "@babel/helper-validator-identifier": ^7.10.4 + chalk: ^2.0.0 + js-tokens: ^4.0.0 + checksum: c167b938af9797e7630dd922398ceb1a079469085b9c0a7274f093f9f2b1ef9f0a5efec89592e81cbab7c87a537d32c238cea97d288b7af9a0d26b2bceb7a439 + languageName: node + linkType: hard + +"@babel/parser@npm:^7.12.7": + version: 7.12.7 + resolution: "@babel/parser@npm:7.12.7" + bin: + parser: ./bin/babel-parser.js + checksum: 12daf20ffe364116f94a50411d02e42144439b66f9948f2e84950ac943e75cfb1f61dbc14f01c9c037f112e3deefd2f9779b6a213fb9c9b6a506066c6527a665 + languageName: node + linkType: hard + +"@babel/plugin-proposal-async-generator-functions@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-proposal-async-generator-functions@npm:7.12.1" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + "@babel/helper-remap-async-to-generator": ^7.12.1 + "@babel/plugin-syntax-async-generators": ^7.8.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 59f8c4e46900f8982507fc2bee65a39a831469e1ed7862af8b78c4244386c5bb0eaa416c30964c30e64c0ca24abd5e39b900f83686b4e86c45db07263bb6a629 + languageName: node + linkType: hard + +"@babel/plugin-proposal-class-properties@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-proposal-class-properties@npm:7.12.1" + dependencies: + "@babel/helper-create-class-features-plugin": ^7.12.1 + "@babel/helper-plugin-utils": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 690cbec3df2c4a1ec12c8a99b87dd4cc9aee07627dea957031549997267ee6ce59727ba44266dd83d3c6fb4cf759d14017ad9a530bf3d8f4447780947031449a + languageName: node + linkType: hard + +"@babel/plugin-proposal-dynamic-import@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-proposal-dynamic-import@npm:7.12.1" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + "@babel/plugin-syntax-dynamic-import": ^7.8.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 4428439b483912c898d70a858f86e48f28247f55b05f4ca4ebc1f6746e63cc73e2704ed85c8fc65f2761154f4fcfa08220ac413c9edd5758d1ace03b4dcd4551 + languageName: node + linkType: hard + +"@babel/plugin-proposal-export-namespace-from@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-proposal-export-namespace-from@npm:7.12.1" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + "@babel/plugin-syntax-export-namespace-from": ^7.8.3 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: ae5317ca008cc9eb2890b1f238156fbb990e5030fd1b7f123a5d11d89f8617a867b11db129aeafe51ef3bb4dddc4059e8172ddf99e8cdc42cbfa2a45dce1a16b + languageName: node + linkType: hard + +"@babel/plugin-proposal-json-strings@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-proposal-json-strings@npm:7.12.1" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + "@babel/plugin-syntax-json-strings": ^7.8.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: fbe4f3241c3edfb432138745657386c049cde9c39fbe9cb86f2a6ec10809cb4aafebf3f78b351bae3acf2cffca6cfd319d26d8c899c50b4bd7a39675ebb57f6b + languageName: node + linkType: hard + +"@babel/plugin-proposal-logical-assignment-operators@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-proposal-logical-assignment-operators@npm:7.12.1" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + "@babel/plugin-syntax-logical-assignment-operators": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 08af656aaa40c554ba079c5b6cae9fe9dff95cf817debcbfc2ba5e7b7e051d6b2b04aa727d4e77404ea147758e513da7be8b35626e8053f50caceeaeff8f9763 + languageName: node + linkType: hard + +"@babel/plugin-proposal-nullish-coalescing-operator@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-proposal-nullish-coalescing-operator@npm:7.12.1" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + "@babel/plugin-syntax-nullish-coalescing-operator": ^7.8.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 9c825901a13aa52330b7ec44f2b6355112d9e2dce9f3e0230c66a7536d542424d19a08b797cd72a00c18fe2e11b1d4037b365012eddfe69c169500b02ed83964 + languageName: node + linkType: hard + +"@babel/plugin-proposal-numeric-separator@npm:^7.12.7": + version: 7.12.7 + resolution: "@babel/plugin-proposal-numeric-separator@npm:7.12.7" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + "@babel/plugin-syntax-numeric-separator": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: f08f84f56797df52e947530a9cf4f22f5d1aa0164fb40ec05841961b5a942ef190cbbca7f981903e1c8869e75a0dee349a69bcca2dd6ea036758c5f97b325ccb + languageName: node + linkType: hard + +"@babel/plugin-proposal-object-rest-spread@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-proposal-object-rest-spread@npm:7.12.1" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + "@babel/plugin-syntax-object-rest-spread": ^7.8.0 + "@babel/plugin-transform-parameters": ^7.12.1 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: d14fc95dad725b72bc1d29f6ea3eee0ff436fa5ab2ac2dd486acb9c1e4cda9f68424581c87857fe4e2c58bf48386b38b3eac542157b040b0f25c1fbbd98dd8f0 + languageName: node + linkType: hard + +"@babel/plugin-proposal-optional-catch-binding@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-proposal-optional-catch-binding@npm:7.12.1" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + "@babel/plugin-syntax-optional-catch-binding": ^7.8.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: ca8c20fb7371a3e16d48d9989ec8c3a38eb46354dcd2edba70231fcb0959967920a01c9dee768f21e715ef679c4d2b10b9f04499655f719228e753e2d884e3e7 + languageName: node + linkType: hard + +"@babel/plugin-proposal-optional-chaining@npm:^7.12.7": + version: 7.12.7 + resolution: "@babel/plugin-proposal-optional-chaining@npm:7.12.7" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + "@babel/helper-skip-transparent-expression-wrappers": ^7.12.1 + "@babel/plugin-syntax-optional-chaining": ^7.8.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 0a2872ec40ebecb33821094fc3075b1bf5e11cdf51d5a45d4a36a39a140dad15e775211f73a4068566cd0e5c422b6666769ec7f6362d492f68477b0eabb26a31 + languageName: node + linkType: hard + +"@babel/plugin-proposal-private-methods@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-proposal-private-methods@npm:7.12.1" + dependencies: + "@babel/helper-create-class-features-plugin": ^7.12.1 + "@babel/helper-plugin-utils": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 350a1a8c3df47096fe37f455f6fcedd185f514a72e3aa01df8a773fb4cd86370a34f3c14cdecf0dda609c7715061ebde87563a21ceccf9f5846d1b38dd97b2cf + languageName: node + linkType: hard + +"@babel/plugin-proposal-unicode-property-regex@npm:^7.12.1, @babel/plugin-proposal-unicode-property-regex@npm:^7.4.4": + version: 7.12.1 + resolution: "@babel/plugin-proposal-unicode-property-regex@npm:7.12.1" + dependencies: + "@babel/helper-create-regexp-features-plugin": ^7.12.1 + "@babel/helper-plugin-utils": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: b960b8c1af6f8420e0ae1107f5af00ac954a322117428330585230b3b28c0653be80d463d6c3c18fe629fd2f7439ecbee635c9d5a1867da58331e744b2613f90 + languageName: node + linkType: hard + +"@babel/plugin-syntax-async-generators@npm:^7.8.0": + version: 7.8.4 + resolution: "@babel/plugin-syntax-async-generators@npm:7.8.4" + dependencies: + "@babel/helper-plugin-utils": ^7.8.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 39685944ffe342981afb1fe3af824305e94ee249b1841c78c1112f93d256d3d405902ac146ab3bad8c243710f081621f9fbf53c62474800d398293c99521c8ef + languageName: node + linkType: hard + +"@babel/plugin-syntax-class-properties@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-syntax-class-properties@npm:7.12.1" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: b5e354a0cd18f67f29e59cdaa80f9e50839ed9d3d8e1fca2964431fa474d08c3ca4cd1f61d0bcb577e8451c541e45e0e702e6feca5483ecd4e265ef5a0b70d42 + languageName: node + linkType: hard + +"@babel/plugin-syntax-dynamic-import@npm:^7.8.0": + version: 7.8.3 + resolution: "@babel/plugin-syntax-dynamic-import@npm:7.8.3" + dependencies: + "@babel/helper-plugin-utils": ^7.8.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 134a6f37feac0e6d55f8188232e11798ccf699b02d50a4daf9c040f52a22ee32923a6a979443ecc865f4014937ffe67ac11b81aa5668b6792238c647314f41c9 + languageName: node + linkType: hard + +"@babel/plugin-syntax-export-namespace-from@npm:^7.8.3": + version: 7.8.3 + resolution: "@babel/plugin-syntax-export-namespace-from@npm:7.8.3" + dependencies: + "@babel/helper-plugin-utils": ^7.8.3 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 832e007319bc5040818012d51eb91c3ad4c38a1ea696e9a9805df4d601d8c4f061032cb61494946e7bdaa5db0422a6bb6f39577cd0e5c8323b6bb2c364406dcb + languageName: node + linkType: hard + +"@babel/plugin-syntax-json-strings@npm:^7.8.0": + version: 7.8.3 + resolution: "@babel/plugin-syntax-json-strings@npm:7.8.3" + dependencies: + "@babel/helper-plugin-utils": ^7.8.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 1a7dabf0a4b264cb235966c4256aad131567eba20e41de731fa9127d371454a2f702e27fd7bedac65efb0df847e5cece7bcb5507a931604d1c2ecb7390adaa1f + languageName: node + linkType: hard + +"@babel/plugin-syntax-logical-assignment-operators@npm:^7.10.4": + version: 7.10.4 + resolution: "@babel/plugin-syntax-logical-assignment-operators@npm:7.10.4" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 5b82f717707d278e58d12649932bf3327923361f051cd4517a5b63d7ebfe39cb6cdfb37aa199b5a441db305301a3c8de01c946d25d1f4c4ecb94322a23ac9e73 + languageName: node + linkType: hard + +"@babel/plugin-syntax-nullish-coalescing-operator@npm:^7.8.0": + version: 7.8.3 + resolution: "@babel/plugin-syntax-nullish-coalescing-operator@npm:7.8.3" + dependencies: + "@babel/helper-plugin-utils": ^7.8.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 4ba03753759a2d9783b792c060147a20f474f76c42edf77cbf89c6669f9f22ffb3cbba4facdd8ce651129db6089a81feca1f7e42da75244eabedecba37bd20be + languageName: node + linkType: hard + +"@babel/plugin-syntax-numeric-separator@npm:^7.10.4": + version: 7.10.4 + resolution: "@babel/plugin-syntax-numeric-separator@npm:7.10.4" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 47ae8782939ccc41f94b1d46b8b7a63363b003b8b7544bddae8dd454a8d51b38bbd4f9c26e91ecfb5fc16dc5f2228700e3030def63c5d07046073ec8fabc4665 + languageName: node + linkType: hard + +"@babel/plugin-syntax-object-rest-spread@npm:^7.8.0": + version: 7.8.3 + resolution: "@babel/plugin-syntax-object-rest-spread@npm:7.8.3" + dependencies: + "@babel/helper-plugin-utils": ^7.8.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: db5dfb39faceddba8b80c586e331e17c3a1f79941f80eaa070b91fb920582bffe8bba46f6bebbdaf7c1f9b0bbe2a68493c28e1c9fb0ced864da739c0cd52ce43 + languageName: node + linkType: hard + +"@babel/plugin-syntax-optional-catch-binding@npm:^7.8.0": + version: 7.8.3 + resolution: "@babel/plugin-syntax-optional-catch-binding@npm:7.8.3" + dependencies: + "@babel/helper-plugin-utils": ^7.8.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: f03d07526674ecdb3388e1d648ec250250968e13c037a7110e37d3eab0b82b07d6605332772afdf19f1831dfd3bdbbf0288a7d9097097d30b9548388ea693a07 + languageName: node + linkType: hard + +"@babel/plugin-syntax-optional-chaining@npm:^7.8.0": + version: 7.8.3 + resolution: "@babel/plugin-syntax-optional-chaining@npm:7.8.3" + dependencies: + "@babel/helper-plugin-utils": ^7.8.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 2a50685d023bc609b01a3fd7ed3af03bc36c575da8d02199ed51cb24e8e068f26a128a20486cd502abe9e1d4c02e0264b8a58f1a5143e1291ca3508a948ada97 + languageName: node + linkType: hard + +"@babel/plugin-syntax-top-level-await@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-syntax-top-level-await@npm:7.12.1" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 9767e46ddc1add9133a21f5d6c4452e9a62f891fe1db5d8291f62f9036f9e697bc118adad43109a8740ac15769e9489d68d134b17cfe9f3bdf06d2c50c9c6dce + languageName: node + linkType: hard + +"@babel/plugin-syntax-typescript@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-syntax-typescript@npm:7.12.1" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 37bdb828915d9193d5fc3b877fb479f1cef6ea3f1cfaa18908170fe23af043ba59d7bc723d3e27067b879e486f16e418d602d7212a7a1e93125bf80339c39668 + languageName: node + linkType: hard + +"@babel/plugin-transform-arrow-functions@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-transform-arrow-functions@npm:7.12.1" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 602be39f30dd1937a2ff8bb40af594a150998d6914fae61421cbfb99cc91ab7dbb9bd156f4f092e789fa0a8c16034d3e0f663b25521561a63da219529d816506 + languageName: node + linkType: hard + +"@babel/plugin-transform-async-to-generator@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-transform-async-to-generator@npm:7.12.1" + dependencies: + "@babel/helper-module-imports": ^7.12.1 + "@babel/helper-plugin-utils": ^7.10.4 + "@babel/helper-remap-async-to-generator": ^7.12.1 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 96a48e5cbfb44f9d2a5d561ff96c9821a1dcb15c9b61d8cb7b0ba0f78ff21873f0e8f486075d5d75122dca53d87ae25f6743f04f4129ec912379127be1b4de74 + languageName: node + linkType: hard + +"@babel/plugin-transform-block-scoped-functions@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-transform-block-scoped-functions@npm:7.12.1" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 2da63c6b92d35928d51d2d9782b5fac6a0aef07051bed78eeb8b6d1a57260ebb830c68b8eeb374e169c49ffaa032e49a04fe468259cf1dd7d7010ef07b1251c9 + languageName: node + linkType: hard + +"@babel/plugin-transform-block-scoping@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-transform-block-scoping@npm:7.12.1" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 067f8b55a32ba53c7bc61e730f0a2dd063ee377afea88e153e9b8bd8069d666df3106b80777e37e418d14a21cabd1dee0f7dabfe8cb038d5080d9e332a202e36 + languageName: node + linkType: hard + +"@babel/plugin-transform-classes@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-transform-classes@npm:7.12.1" + dependencies: + "@babel/helper-annotate-as-pure": ^7.10.4 + "@babel/helper-define-map": ^7.10.4 + "@babel/helper-function-name": ^7.10.4 + "@babel/helper-optimise-call-expression": ^7.10.4 + "@babel/helper-plugin-utils": ^7.10.4 + "@babel/helper-replace-supers": ^7.12.1 + "@babel/helper-split-export-declaration": ^7.10.4 + globals: ^11.1.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: ae895d1a201be7c038f220f49f00eb804cf5e2280199127469ce0962080574b9515117807c0f1c5d446df543b2fa8af1325d6bafb46aa4e6ecdfe1d30aae2047 + languageName: node + linkType: hard + +"@babel/plugin-transform-computed-properties@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-transform-computed-properties@npm:7.12.1" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: b3680b9c0327e55ae58b16e9f77cebc857a30fcda45b863750396ff46e1714b5d57fe55b57ef6552004b0e110d5b66c6994753fa45d658b13c245907ffb72757 + languageName: node + linkType: hard + +"@babel/plugin-transform-destructuring@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-transform-destructuring@npm:7.12.1" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 704057fa7c9107efd19615e111517377a75f9c52c518870779effa225a220ba9f77206d60574e8ff15bc8be32996f0c0d21c01bf4095c4ca04a18e0b194a1f75 + languageName: node + linkType: hard + +"@babel/plugin-transform-dotall-regex@npm:^7.12.1, @babel/plugin-transform-dotall-regex@npm:^7.4.4": + version: 7.12.1 + resolution: "@babel/plugin-transform-dotall-regex@npm:7.12.1" + dependencies: + "@babel/helper-create-regexp-features-plugin": ^7.12.1 + "@babel/helper-plugin-utils": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: dd522110c9a981194cecbf8dbb8b9c668b6bdbffdbb4e601db3edca35398d778a9d4bc26a60af5965eba1230fc960e9a7588c3b90db87b5f243bd29332d788d8 + languageName: node + linkType: hard + +"@babel/plugin-transform-duplicate-keys@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-transform-duplicate-keys@npm:7.12.1" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: a8c45815fb51048ac6b6f8fdad583b6d9d48affc9d00c9ef67b030e3262e12694d51b026db90dae26bce5420c8e26bc7ee663fea973c1aebafb4636a0ffcbd20 + languageName: node + linkType: hard + +"@babel/plugin-transform-exponentiation-operator@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-transform-exponentiation-operator@npm:7.12.1" + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor": ^7.10.4 + "@babel/helper-plugin-utils": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 9a01b9350660ea68318fa94c1486833e006f75bba236854e714662dc4f2674604b8cb377844fa45727f6a63fa3a379d10da9090f5f1cc6b95d59ed5e63f77c5c + languageName: node + linkType: hard + +"@babel/plugin-transform-for-of@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-transform-for-of@npm:7.12.1" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: d51761cecb966bcde390a9ecb9651679d9a8c96e5f74182066028d496abeda26091986f64817e34c8cb2895fb722e364dd875645ca35ec1d6bcd759fd37b8907 + languageName: node + linkType: hard + +"@babel/plugin-transform-function-name@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-transform-function-name@npm:7.12.1" + dependencies: + "@babel/helper-function-name": ^7.10.4 + "@babel/helper-plugin-utils": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 7dff23e9b56f4b2f715c5bbdb21388c67820c5a543344f01aaca580ce124fb6646d36786fb4e8a9ed550113b28946c559f4b3402fce8cffe0c8e124213bc1d0e + languageName: node + linkType: hard + +"@babel/plugin-transform-literals@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-transform-literals@npm:7.12.1" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 1bc7a828e06ac4484cd26b521a3ce3da221899fd1dbf747e353c5d560749160ac104fb505d1deaccb46dc01d5f6fed134577c14a67f1608d1522223e22d3cfcf + languageName: node + linkType: hard + +"@babel/plugin-transform-member-expression-literals@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-transform-member-expression-literals@npm:7.12.1" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 2a216ee882d6046e2ccb949bf353c23f729f306a660139277b432c0cbe1db03e04cb9c0b03db86098799c705654a215dc9be714e22b91a8c238bab2c0ecea726 + languageName: node + linkType: hard + +"@babel/plugin-transform-modules-amd@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-transform-modules-amd@npm:7.12.1" + dependencies: + "@babel/helper-module-transforms": ^7.12.1 + "@babel/helper-plugin-utils": ^7.10.4 + babel-plugin-dynamic-import-node: ^2.3.3 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 0b22d7ccf3bf91aebc9a751bbb88f108ee553a047756dc5d83d34294561f94ee1f63cc23479eb2f17f34d118234143e8627c2a29beb14d151d04294721dd4fd0 + languageName: node + linkType: hard + +"@babel/plugin-transform-modules-commonjs@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-transform-modules-commonjs@npm:7.12.1" + dependencies: + "@babel/helper-module-transforms": ^7.12.1 + "@babel/helper-plugin-utils": ^7.10.4 + "@babel/helper-simple-access": ^7.12.1 + babel-plugin-dynamic-import-node: ^2.3.3 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 7201ad5f82f51f992e855909a99adc9dbade07146d86bd3b219fb6bc4111169adca4b082365365657f03ae025b5ce18d749125251a1aca111d06c2c647cfbfbe + languageName: node + linkType: hard + +"@babel/plugin-transform-modules-systemjs@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-transform-modules-systemjs@npm:7.12.1" + dependencies: + "@babel/helper-hoist-variables": ^7.10.4 + "@babel/helper-module-transforms": ^7.12.1 + "@babel/helper-plugin-utils": ^7.10.4 + "@babel/helper-validator-identifier": ^7.10.4 + babel-plugin-dynamic-import-node: ^2.3.3 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: f47d070edac6c064a7a86764885b84bdb62ecea6ca8a6c33ae8bfa516bf4f3827df0ec72c720d8daa8d376a9a1669e9a9be3f1d6576544288b709f0556a4c806 + languageName: node + linkType: hard + +"@babel/plugin-transform-modules-umd@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-transform-modules-umd@npm:7.12.1" + dependencies: + "@babel/helper-module-transforms": ^7.12.1 + "@babel/helper-plugin-utils": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 9998266d1ea4eada5fdda84fddc1611e733eb75ff363419c7884827cbb3229bc0c14e7abfbb1436354102ce085175f9a850cbc7a2bbe7c1493021414da3127ba + languageName: node + linkType: hard + +"@babel/plugin-transform-named-capturing-groups-regex@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-transform-named-capturing-groups-regex@npm:7.12.1" + dependencies: + "@babel/helper-create-regexp-features-plugin": ^7.12.1 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 96eb5b35875d6065a934110bb04ce18feff437f085651c75cd64f32cecf3e87ac7526ff55b7592129bde3b1d61c9352da64fccd99baa6f5c58229bde67ab9d0b + languageName: node + linkType: hard + +"@babel/plugin-transform-new-target@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-transform-new-target@npm:7.12.1" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: d3b9f4f0c28211d7e2cafe7c20691259da9ec8931d870154c46132a9b6e4dfc575caa76bf60684eff58f0da75423cebae1ecc8b53f35f93eab4ccdf68bb0f633 + languageName: node + linkType: hard + +"@babel/plugin-transform-object-super@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-transform-object-super@npm:7.12.1" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + "@babel/helper-replace-supers": ^7.12.1 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 36cc06f539aee16a544151c096381cae1a13f3ac531fe3a340a687373a5c01fc368b9d3d53ced0caf1f5413b5176c4acf34132f39f00e8045bf31cd9d7ffaaad + languageName: node + linkType: hard + +"@babel/plugin-transform-parameters@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-transform-parameters@npm:7.12.1" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: a968ef99b6356b610bee1f933dfd64cfd3fe3d0971370bc31734fff65435a05fbdc42b59401e9dc9dfe4b310e92e417a3273f454eb0542ec4afde9088059b963 + languageName: node + linkType: hard + +"@babel/plugin-transform-property-literals@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-transform-property-literals@npm:7.12.1" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: dff34b03d88e0e4a333f1b046ecf3a396208266afa270ce40f87e8051ede4fdc351e59cbbd78f5e49601f57a00b99f76879dbcd2d79d237871ba54831ef393e9 + languageName: node + linkType: hard + +"@babel/plugin-transform-regenerator@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-transform-regenerator@npm:7.12.1" + dependencies: + regenerator-transform: ^0.14.2 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: a1722c284770776ea88a416c9c081dedbf1844f5c90a245998bb28243714d3275b5256d1531c565c53e5511d1e00404ca172fe47106af0a9c1aa52572b6b5c74 + languageName: node + linkType: hard + +"@babel/plugin-transform-reserved-words@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-transform-reserved-words@npm:7.12.1" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 41f589086b16cdd9b0783e0733ccf236ebdd68cd4def7641e9ff18efe1306fee21f096f6de0384c69854dd6445514b4a844ae5ea3e8a55a76ffb5bc1051085b4 + languageName: node + linkType: hard + +"@babel/plugin-transform-shorthand-properties@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-transform-shorthand-properties@npm:7.12.1" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 36cd37c9dd09d822c0707544c19539a01c5744ca8024f7dbaa3ca11284c6b1ec88ca631698351aa3302fd8dc7e8b3332ac1df0987146d707168c4951ae90c98a + languageName: node + linkType: hard + +"@babel/plugin-transform-spread@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-transform-spread@npm:7.12.1" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + "@babel/helper-skip-transparent-expression-wrappers": ^7.12.1 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 905e1872e34b9aa5b8f95ac33accb6cbe8a1a5567043767adc3048e095aa20511d8555688a47129da2bb821d57cd77de1e1482cea7eebf2ee18b65b1f5ae05d7 + languageName: node + linkType: hard + +"@babel/plugin-transform-sticky-regex@npm:^7.12.7": + version: 7.12.7 + resolution: "@babel/plugin-transform-sticky-regex@npm:7.12.7" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: fd49ca42e869d136ccccc4a1bc0c4572f3dc1b231d87a291ae0526a7e155734166767eea9e0843d3473f865793976fb5d728ae1796dad8cfe55d3728fd4a9804 + languageName: node + linkType: hard + +"@babel/plugin-transform-template-literals@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-transform-template-literals@npm:7.12.1" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 2e37a8efa38cd856aa2336e285978c86d23d95066db96833fa2b38b879d81ff242531c1712c86e6b6b130144bd5a272cf7213ea9b585debaa6d877043d30e229 + languageName: node + linkType: hard + +"@babel/plugin-transform-typeof-symbol@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-transform-typeof-symbol@npm:7.12.1" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 73bb34cb448ae2e953b36c8d0283c73b7979577ca470fccae036a0b7b2a8e9b266a377878495f9a5dea1b42b5b33f6f234dc08675600f1ae5e557e73f64bdc48 + languageName: node + linkType: hard + +"@babel/plugin-transform-typescript@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-transform-typescript@npm:7.12.1" + dependencies: + "@babel/helper-create-class-features-plugin": ^7.12.1 + "@babel/helper-plugin-utils": ^7.10.4 + "@babel/plugin-syntax-typescript": ^7.12.1 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: d93737e2350d0f7c36726c43af64ed4af566e67fd38400faf7f9057ede62eef4fa99235228167b27150e03b86aa53c2ef9f0ea346a02ad9a3070c147aa5e732d + languageName: node + linkType: hard + +"@babel/plugin-transform-unicode-escapes@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-transform-unicode-escapes@npm:7.12.1" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 40f57b173a7d5623d58175692dfee966ced2f7d760bc50785e9ee5cb8b6360d836ae89677ef9b9a2e98f71b0a75e66306a21483d76d64047250bdc16006541c2 + languageName: node + linkType: hard + +"@babel/plugin-transform-unicode-regex@npm:^7.12.1": + version: 7.12.1 + resolution: "@babel/plugin-transform-unicode-regex@npm:7.12.1" + dependencies: + "@babel/helper-create-regexp-features-plugin": ^7.12.1 + "@babel/helper-plugin-utils": ^7.10.4 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 411ddc96ef17d33f063371d9bbf2841cc0907e8d65060776a78e793386239070c7c0699c72d975d9b82d9cbc60935255b0a86eb7f5ded7d8dc634df9e5d4c445 + languageName: node + linkType: hard + +"@babel/preset-env@npm:^7.0.0": + version: 7.12.7 + resolution: "@babel/preset-env@npm:7.12.7" + dependencies: + "@babel/compat-data": ^7.12.7 + "@babel/helper-compilation-targets": ^7.12.5 + "@babel/helper-module-imports": ^7.12.5 + "@babel/helper-plugin-utils": ^7.10.4 + "@babel/helper-validator-option": ^7.12.1 + "@babel/plugin-proposal-async-generator-functions": ^7.12.1 + "@babel/plugin-proposal-class-properties": ^7.12.1 + "@babel/plugin-proposal-dynamic-import": ^7.12.1 + "@babel/plugin-proposal-export-namespace-from": ^7.12.1 + "@babel/plugin-proposal-json-strings": ^7.12.1 + "@babel/plugin-proposal-logical-assignment-operators": ^7.12.1 + "@babel/plugin-proposal-nullish-coalescing-operator": ^7.12.1 + "@babel/plugin-proposal-numeric-separator": ^7.12.7 + "@babel/plugin-proposal-object-rest-spread": ^7.12.1 + "@babel/plugin-proposal-optional-catch-binding": ^7.12.1 + "@babel/plugin-proposal-optional-chaining": ^7.12.7 + "@babel/plugin-proposal-private-methods": ^7.12.1 + "@babel/plugin-proposal-unicode-property-regex": ^7.12.1 + "@babel/plugin-syntax-async-generators": ^7.8.0 + "@babel/plugin-syntax-class-properties": ^7.12.1 + "@babel/plugin-syntax-dynamic-import": ^7.8.0 + "@babel/plugin-syntax-export-namespace-from": ^7.8.3 + "@babel/plugin-syntax-json-strings": ^7.8.0 + "@babel/plugin-syntax-logical-assignment-operators": ^7.10.4 + "@babel/plugin-syntax-nullish-coalescing-operator": ^7.8.0 + "@babel/plugin-syntax-numeric-separator": ^7.10.4 + "@babel/plugin-syntax-object-rest-spread": ^7.8.0 + "@babel/plugin-syntax-optional-catch-binding": ^7.8.0 + "@babel/plugin-syntax-optional-chaining": ^7.8.0 + "@babel/plugin-syntax-top-level-await": ^7.12.1 + "@babel/plugin-transform-arrow-functions": ^7.12.1 + "@babel/plugin-transform-async-to-generator": ^7.12.1 + "@babel/plugin-transform-block-scoped-functions": ^7.12.1 + "@babel/plugin-transform-block-scoping": ^7.12.1 + "@babel/plugin-transform-classes": ^7.12.1 + "@babel/plugin-transform-computed-properties": ^7.12.1 + "@babel/plugin-transform-destructuring": ^7.12.1 + "@babel/plugin-transform-dotall-regex": ^7.12.1 + "@babel/plugin-transform-duplicate-keys": ^7.12.1 + "@babel/plugin-transform-exponentiation-operator": ^7.12.1 + "@babel/plugin-transform-for-of": ^7.12.1 + "@babel/plugin-transform-function-name": ^7.12.1 + "@babel/plugin-transform-literals": ^7.12.1 + "@babel/plugin-transform-member-expression-literals": ^7.12.1 + "@babel/plugin-transform-modules-amd": ^7.12.1 + "@babel/plugin-transform-modules-commonjs": ^7.12.1 + "@babel/plugin-transform-modules-systemjs": ^7.12.1 + "@babel/plugin-transform-modules-umd": ^7.12.1 + "@babel/plugin-transform-named-capturing-groups-regex": ^7.12.1 + "@babel/plugin-transform-new-target": ^7.12.1 + "@babel/plugin-transform-object-super": ^7.12.1 + "@babel/plugin-transform-parameters": ^7.12.1 + "@babel/plugin-transform-property-literals": ^7.12.1 + "@babel/plugin-transform-regenerator": ^7.12.1 + "@babel/plugin-transform-reserved-words": ^7.12.1 + "@babel/plugin-transform-shorthand-properties": ^7.12.1 + "@babel/plugin-transform-spread": ^7.12.1 + "@babel/plugin-transform-sticky-regex": ^7.12.7 + "@babel/plugin-transform-template-literals": ^7.12.1 + "@babel/plugin-transform-typeof-symbol": ^7.12.1 + "@babel/plugin-transform-unicode-escapes": ^7.12.1 + "@babel/plugin-transform-unicode-regex": ^7.12.1 + "@babel/preset-modules": ^0.1.3 + "@babel/types": ^7.12.7 + core-js-compat: ^3.7.0 + semver: ^5.5.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 46113b6b4e3997bacaac09cc77ce5a0d01b1f8a8b31eaca03ecaae372815baf5bc77e021e2be4e56314a328122b8792f784ff06e6ee1b2cc8dd560886a0931e7 + languageName: node + linkType: hard + +"@babel/preset-modules@npm:^0.1.3": + version: 0.1.4 + resolution: "@babel/preset-modules@npm:0.1.4" + dependencies: + "@babel/helper-plugin-utils": ^7.0.0 + "@babel/plugin-proposal-unicode-property-regex": ^7.4.4 + "@babel/plugin-transform-dotall-regex": ^7.4.4 + "@babel/types": ^7.4.4 + esutils: ^2.0.2 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 8a463709fd9db195c73ad1d6ff2d85ce92976167f20ded23ec49b47754c42fae40f93ff3287fb2e980f0d7f0b7ddf163aa92faf416ef422bdccf722bdae50138 + languageName: node + linkType: hard + +"@babel/preset-typescript@npm:^7.0.0": + version: 7.12.7 + resolution: "@babel/preset-typescript@npm:7.12.7" + dependencies: + "@babel/helper-plugin-utils": ^7.10.4 + "@babel/helper-validator-option": ^7.12.1 + "@babel/plugin-transform-typescript": ^7.12.1 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 9a808f4798973b05b3b4fb83eb6093bd9e71a308bfc428e16ac856775bca3b61214eef3307d1ab428bf04ec87f4d87a5c5fbcfd49c21a33ad6b9bf92c4a26503 + languageName: node + linkType: hard + +"@babel/runtime@npm:^7.8.4": + version: 7.12.5 + resolution: "@babel/runtime@npm:7.12.5" + dependencies: + regenerator-runtime: ^0.13.4 + checksum: 423fb0079353db2faa0dad0cbdf0a90fbc5b511d1f77e5645d1aa0b144a144e24502bb023c12a31d7dca63b6e16ae36afa59992f0404e92e21de211051c361e3 + languageName: node + linkType: hard + +"@babel/template@npm:^7.10.4": + version: 7.12.7 + resolution: "@babel/template@npm:7.12.7" + dependencies: + "@babel/code-frame": ^7.10.4 + "@babel/parser": ^7.12.7 + "@babel/types": ^7.12.7 + checksum: 6e0a050be7d07ca6755305d74892dfa1e119d1193929275f8019339fbbf45257eea41385cf99325301001a2b2912d186e447393229fe169f50a8bfbcbf8a850a + languageName: node + linkType: hard + +"@babel/traverse@npm:^7.10.4, @babel/traverse@npm:^7.12.1, @babel/traverse@npm:^7.12.5": + version: 7.12.9 + resolution: "@babel/traverse@npm:7.12.9" + dependencies: + "@babel/code-frame": ^7.10.4 + "@babel/generator": ^7.12.5 + "@babel/helper-function-name": ^7.10.4 + "@babel/helper-split-export-declaration": ^7.11.0 + "@babel/parser": ^7.12.7 + "@babel/types": ^7.12.7 + debug: ^4.1.0 + globals: ^11.1.0 + lodash: ^4.17.19 + checksum: 6797d3f42d3d27ba596c864c76b81a234a6df3c3079bf03207bdef56bff866e001135a271b114d9869ab78984f4408cb7252940ca0986ca40f2281b1626a5391 + languageName: node + linkType: hard + +"@babel/types@npm:^7.10.4, @babel/types@npm:^7.10.5, @babel/types@npm:^7.11.0, @babel/types@npm:^7.12.1, @babel/types@npm:^7.12.5, @babel/types@npm:^7.12.7, @babel/types@npm:^7.4.4, @babel/types@npm:^7.8.3": + version: 7.12.7 + resolution: "@babel/types@npm:7.12.7" + dependencies: + "@babel/helper-validator-identifier": ^7.10.4 + lodash: ^4.17.19 + to-fast-properties: ^2.0.0 + checksum: 153635079722927a7ac35ae6c10d091e9f86fcf8411c56a2bff17befc20f53b3c1883f67f33b59d8896d65f4aed7e9aa535d24262838d0a8250f2e2ef0d9327f + languageName: node + linkType: hard + +"ansi-styles@npm:^3.2.1": + version: 3.2.1 + resolution: "ansi-styles@npm:3.2.1" + dependencies: + color-convert: ^1.9.0 + checksum: 456e1c23d9277512a47718da75e7fbb0a5ee215ef893c2f76d6b3efe8fceabc861121b80b0362146f5f995d21a1633f05a19bbf6283ae66ac11dc3b9c0bed779 + languageName: node + linkType: hard + +"babel-plugin-dynamic-import-node@npm:^2.3.3": + version: 2.3.3 + resolution: "babel-plugin-dynamic-import-node@npm:2.3.3" + dependencies: + object.assign: ^4.1.0 + checksum: 6745b8edca96f6c8bc34ab65935b5676358d2e55323e8e823b8de7aa353e3e6398a495ce434c9c36ad5fb1609467a1b1a0028946e1490bf7de8f97df3ae7f3b1 + languageName: node + linkType: hard + +"browserslist@npm:^4.14.5, browserslist@npm:^4.14.7": + version: 4.15.0 + resolution: "browserslist@npm:4.15.0" + dependencies: + caniuse-lite: ^1.0.30001164 + colorette: ^1.2.1 + electron-to-chromium: ^1.3.612 + escalade: ^3.1.1 + node-releases: ^1.1.67 + bin: + browserslist: cli.js + checksum: d8c222ad064cc3911e5cbff6e3feae53e87dc7b1b2ba347ff9b6a5bda76d7d29a230993f56457a4a0b83849d163ae07946bfe0389175998817aaefed428fab68 + languageName: node + linkType: hard + +"call-bind@npm:^1.0.0": + version: 1.0.0 + resolution: "call-bind@npm:1.0.0" + dependencies: + function-bind: ^1.1.1 + get-intrinsic: ^1.0.0 + checksum: aeb82f8f5dfd56592c7dcef89367227daa60be4f8e7fdb7689d6c1f8712872911d7e31fddd3336534f45cea56d9a4e7d48889596ce6d2f1ada4507573306e6b1 + languageName: node + linkType: hard + +"caniuse-lite@npm:^1.0.30001164": + version: 1.0.30001164 + resolution: "caniuse-lite@npm:1.0.30001164" + checksum: ac2213c81b4a406e71795fe13834ea716d4f2c98935631289d6c7c3a421d5984f8535c90bd533c353f07f03d17ad6661b6eed10286a0647cc7f7d7affa79ed54 + languageName: node + linkType: hard + +"chalk@npm:^2.0.0": + version: 2.4.2 + resolution: "chalk@npm:2.4.2" + dependencies: + ansi-styles: ^3.2.1 + escape-string-regexp: ^1.0.5 + supports-color: ^5.3.0 + checksum: 22c7b7b5bc761c882bb6516454a1a671923f1c53ff972860065aa0b28a195f230163c1d46ee88bcc7a03e5539177d896457d8bc727de7f244c6e87032743038e + languageName: node + linkType: hard + +"color-convert@npm:^1.9.0": + version: 1.9.3 + resolution: "color-convert@npm:1.9.3" + dependencies: + color-name: 1.1.3 + checksum: 5f244daa3d1fe1f216d48878c550465067d15268688308554e613b7640a068f96588096d51f0b98b68f15d6ff6bb8ad24e172582ac8c0ad43fa4d3da60fd1b79 + languageName: node + linkType: hard + +"color-name@npm:1.1.3": + version: 1.1.3 + resolution: "color-name@npm:1.1.3" + checksum: d8b91bb90aefc05b6ff568cf8889566dcc6269824df6f3c9b8ca842b18d7f4d089c07dc166808d33f22092d4a79167aa56a96a5ff0d21efab548bf44614db43b + languageName: node + linkType: hard + +"colorette@npm:^1.2.1": + version: 1.2.1 + resolution: "colorette@npm:1.2.1" + checksum: 1cc21ad4b84777a424794f78b6bb6a44b614ae17dcea91762199339f8047598e6d981249eeef7ea588c99eaf062be8fcdcd4866c112998922ed854db6dde96f9 + languageName: node + linkType: hard + +"core-js-compat@npm:^3.7.0": + version: 3.8.0 + resolution: "core-js-compat@npm:3.8.0" + dependencies: + browserslist: ^4.14.7 + semver: 7.0.0 + checksum: e0278c0e64334bdd5a7e13cc49830585dd194d0d4f84322c9fe3cb30ab7f23396374cf499fe02f8e4817470b51e3b35d533e67045a0f67ed391995f013f17a83 + languageName: node + linkType: hard + +"debug@npm:^4.1.0": + version: 4.3.1 + resolution: "debug@npm:4.3.1" + dependencies: + ms: 2.1.2 + peerDependenciesMeta: + supports-color: + optional: true + checksum: 0d41ba5177510e8b388dfd7df143ab0f9312e4abdaba312595461511dac88e9ef8101939d33b4e6d37e10341af6a5301082e4d7d6f3deb4d57bc05fc7d296fad + languageName: node + linkType: hard + +"define-properties@npm:^1.1.3": + version: 1.1.3 + resolution: "define-properties@npm:1.1.3" + dependencies: + object-keys: ^1.0.12 + checksum: b69c48c1b1dacb61f0b1cea367707c3bb214e3c47818aff18e6f20a7f88cbfa33d4cbdfd9ff79e56faba95ddca3d78ff10fbf2f02ecfad6f3e13b256e76b1212 + languageName: node + linkType: hard + +"electron-to-chromium@npm:^1.3.612": + version: 1.3.614 + resolution: "electron-to-chromium@npm:1.3.614" + checksum: a82e0c407db33e74758fc36b25042a6c5f0d6c82a3899dbf069bb1ec5863a8cb2368d7c4f69aa0aa6d2cd858ac0154d2e3d6208bc7953e3d40295cacb39d6d82 + languageName: node + linkType: hard + +"escalade@npm:^3.1.1": + version: 3.1.1 + resolution: "escalade@npm:3.1.1" + checksum: 1e31ff50d66f47cd0dfffa702061127116ccf9886d1f54a802a7b3bc95b94cab0cbf5b145cc5ac199036df6fd9d1bb24af1fa1bfed87c94879e950fbee5f86d1 + languageName: node + linkType: hard + +"escape-string-regexp@npm:^1.0.5": + version: 1.0.5 + resolution: "escape-string-regexp@npm:1.0.5" + checksum: f9484b8b4c8827d816e0fd905c25ed4b561376a9c220e1430403ea84619bf680c76a883a48cff8b8e091daf55d6a497e37479f9787b9f15f3c421b6054289744 + languageName: node + linkType: hard + +"esutils@npm:^2.0.2": + version: 2.0.3 + resolution: "esutils@npm:2.0.3" + checksum: 590b04533177f8f6f0f352b3ac7da6c1c1e3d8375d8973972fba9c94558ca168685fd38319c3c6f4c37ba256df7494a7f15d8e761df1655af8a8f0027d988f8f + languageName: node + linkType: hard + +"function-bind@npm:^1.1.1": + version: 1.1.1 + resolution: "function-bind@npm:1.1.1" + checksum: ffad86e7d2010ba179aaa6a3987d2cc0ed48fa92d27f1ed84bfa06d14f77deeed5bfbae7f00bdebc0c54218392cab2b18ecc080e2c72f592431927b87a27d42b + languageName: node + linkType: hard + +"get-intrinsic@npm:^1.0.0": + version: 1.0.1 + resolution: "get-intrinsic@npm:1.0.1" + dependencies: + function-bind: ^1.1.1 + has: ^1.0.3 + has-symbols: ^1.0.1 + checksum: c38bc558f1eca73bde2d9e22c7798b06c4b93650f39b2053a875a23a6c00fbafb0919ad20fe0d3a3e16916a8a59450502f91e75a918d264456c8ded070fe93c4 + languageName: node + linkType: hard + +"globals@npm:^11.1.0": + version: 11.12.0 + resolution: "globals@npm:11.12.0" + checksum: 2563d3306a7e646fd9ec484b0ca29bf8847d9dc6ebbe86026f11e31bda04f420f6536c2decbd4cb96350379801d2cce352ab373c40be8b024324775b31f882f9 + languageName: node + linkType: hard + +"has-flag@npm:^3.0.0": + version: 3.0.0 + resolution: "has-flag@npm:3.0.0" + checksum: 63aade480d27aeedb3b5b63a2e069d47d0006bf182338d662e7941cdc024e68a28418e0efa8dc5df30db9c4ee2407f39e6ea3f16cfbc6b83848b450826a28aa0 + languageName: node + linkType: hard + +"has-symbols@npm:^1.0.1": + version: 1.0.1 + resolution: "has-symbols@npm:1.0.1" + checksum: 84e2a03ada6f530f0c1ebea64df5932556ac20a4b78998f1f2b5dd0cf736843e8082c488b0ea7f08b9aec72fb6d8b736beed2fd62fac60dcaebfdc0b8d2aa7ac + languageName: node + linkType: hard + +"has@npm:^1.0.3": + version: 1.0.3 + resolution: "has@npm:1.0.3" + dependencies: + function-bind: ^1.1.1 + checksum: c686e15300d41364486c099a9259d9c418022c294244843dcd712c4c286ff839d4f23a25413baa28c4d2c1e828afc2aaab70f685400b391533980223c71fa1ca + languageName: node + linkType: hard + +"js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0": + version: 4.0.0 + resolution: "js-tokens@npm:4.0.0" + checksum: 1fc4e4667ac2d972aba65148b9cbf9c17566b2394d3504238d8492bbd3e68f496c657eab06b26b40b17db5cac0a34d153a12130e2d2d2bb6dc2cdc8a4764eb1b + languageName: node + linkType: hard + +"jsesc@npm:^2.5.1": + version: 2.5.2 + resolution: "jsesc@npm:2.5.2" + bin: + jsesc: bin/jsesc + checksum: ca91ec33d74c55959e4b6fdbfee2af5f38be74a752cf0a982702e3a16239f26c2abbe19f5f84b15592570dda01872e929a90738615bd445f7b9b859781cfcf68 + languageName: node + linkType: hard + +"jsesc@npm:~0.5.0": + version: 0.5.0 + resolution: "jsesc@npm:0.5.0" + bin: + jsesc: bin/jsesc + checksum: 1e4574920d3c17c9167fdc14ca66197e8d5d96fb3f37c7473df7857822b7adbf2954d0e126131456f8fd72b6f6908c2367e7a12c18495a5393c37be99acbbb5a + languageName: node + linkType: hard + +"lodash@npm:^4.17.19": + version: 4.17.20 + resolution: "lodash@npm:4.17.20" + checksum: c62101d2500c383b5f174a7e9e6fe8098149ddd6e9ccfa85f36d4789446195f5c4afd3cfba433026bcaf3da271256566b04a2bf2618e5a39f6e67f8c12030cb6 + languageName: node + linkType: hard + +"loose-envify@npm:^1.1.0": + version: 1.4.0 + resolution: "loose-envify@npm:1.4.0" + dependencies: + js-tokens: ^3.0.0 || ^4.0.0 + bin: + loose-envify: cli.js + checksum: 5c3b47bbe5f597a3889fb001a3a98aaea2a3fafa48089c19034de1e0121bf57dbee609d184478514d74d5c5a7e9cfa3d846343455e5123b060040d46c39e91dc + languageName: node + linkType: hard + +"ms@npm:2.1.2": + version: 2.1.2 + resolution: "ms@npm:2.1.2" + checksum: 9b65fb709bc30c0c07289dcbdb61ca032acbb9ea5698b55fa62e2cebb04c5953f1876a1f3f7f4bc2e91d4bf4d86003f3e207c3bc6ee2f716f99827e62389cd0e + languageName: node + linkType: hard + +"node-releases@npm:^1.1.67": + version: 1.1.67 + resolution: "node-releases@npm:1.1.67" + checksum: 19a76af9498421b28bbc0123effc870a2ebe68a6364a4eb6547c5f871d6c2d8095fb66cc582a2378af8fbb6124ef8360207ef29d7a5a507e27691c53a85e9df4 + languageName: node + linkType: hard + +"object-assign@npm:^4.1.1": + version: 4.1.1 + resolution: "object-assign@npm:4.1.1" + checksum: 66cf021898fc1b13ea573ea8635fbd5a76533f50cecbc2fcd5eee1e8029af41bcebe7023788b6d0e06cbe4401ecea075d972f78ec74467cdc571a0f1a4d1a081 + languageName: node + linkType: hard + +"object-keys@npm:^1.0.12, object-keys@npm:^1.1.1": + version: 1.1.1 + resolution: "object-keys@npm:1.1.1" + checksum: 30d72d768b7f3f42144cee517b80e70c40cf39bb76f100557ffac42779613c591780135c54d8133894a78d2c0ae817e24a5891484722c6019a5cd5b58c745c66 + languageName: node + linkType: hard + +"object.assign@npm:^4.1.0": + version: 4.1.2 + resolution: "object.assign@npm:4.1.2" + dependencies: + call-bind: ^1.0.0 + define-properties: ^1.1.3 + has-symbols: ^1.0.1 + object-keys: ^1.1.1 + checksum: a5855cc6db3f64606c41ceb97cb9847e667d8240889d771d65638244be1d35c2e2ccb5762f437bb76abf4e98ab4634a9d302380398121cee288a44dce5028f54 + languageName: node + linkType: hard + +"react@npm:*": + version: 17.0.1 + resolution: "react@npm:17.0.1" + dependencies: + loose-envify: ^1.1.0 + object-assign: ^4.1.1 + checksum: a76d86ec973eb4b25a46071ac7f974adfd66ed89ad1db63043be1d976ec25417520a210e6d724b0ad937422b706afcf9962cedda9e92125992a8c0e8a95f2051 + languageName: node + linkType: hard + +"regenerate-unicode-properties@npm:^8.2.0": + version: 8.2.0 + resolution: "regenerate-unicode-properties@npm:8.2.0" + dependencies: + regenerate: ^1.4.0 + checksum: afe83304fbb5e8f74334b6f6f3f19ba261b9036aade352db14f4e5c2776fcf6e6a5da465628545f2f6f50f898a1b5246711b2cafedaa01c3f329d186e850af04 + languageName: node + linkType: hard + +"regenerate@npm:^1.4.0": + version: 1.4.2 + resolution: "regenerate@npm:1.4.2" + checksum: 54275a99effd8a439bcdd88942b61f68a769133df841e90d94df9ae7c250cb6537c0a28dd913116539772b3415edbcb3c8d81c22275595d3755cf0353976dfa4 + languageName: node + linkType: hard + +"regenerator-runtime@npm:^0.13.4": + version: 0.13.7 + resolution: "regenerator-runtime@npm:0.13.7" + checksum: 6ef567c662088b1b292214920cbd72443059298d477f72e1a37e0a113bafbfac9057cbfe35ae617284effc4b423493326a78561bbff7b04162c7949bdb9624e8 + languageName: node + linkType: hard + +"regenerator-transform@npm:^0.14.2": + version: 0.14.5 + resolution: "regenerator-transform@npm:0.14.5" + dependencies: + "@babel/runtime": ^7.8.4 + checksum: ed07c2c1d08f4828807f9366621ca1d62102969f5af575662c9e5f085f7b49df068e4944e17c7016898bc125cdc7b0d74014e9856bff3a6a147714c4e7de3ed9 + languageName: node + linkType: hard + +"regexpu-core@npm:^4.7.1": + version: 4.7.1 + resolution: "regexpu-core@npm:4.7.1" + dependencies: + regenerate: ^1.4.0 + regenerate-unicode-properties: ^8.2.0 + regjsgen: ^0.5.1 + regjsparser: ^0.6.4 + unicode-match-property-ecmascript: ^1.0.4 + unicode-match-property-value-ecmascript: ^1.2.0 + checksum: a4d25a11cb95841325289ab8d0d43182b74cf7fce537e60718bc8b901adb4141714f8108c5d333da302e707068f0ea7be09fd5f06ef26a2b1c27b4f29177b8ab + languageName: node + linkType: hard + +"regjsgen@npm:^0.5.1": + version: 0.5.2 + resolution: "regjsgen@npm:0.5.2" + checksum: 629afab3d9ce61e104064cda66aca74ec9a1921151cc985d93c5cb58453ed7f7c23479bdb1a4a0826d200ed28c3871a7b8a8938e634ab00194195012893bccbc + languageName: node + linkType: hard + +"regjsparser@npm:^0.6.4": + version: 0.6.4 + resolution: "regjsparser@npm:0.6.4" + dependencies: + jsesc: ~0.5.0 + bin: + regjsparser: bin/parser + checksum: cf7838462ebe0256ef25618eab5981dc080501efde6458906a47ee1c017c93f7e27723d4a56f658014d5c8381a60d189e19f05198ef343e106343642471b1594 + languageName: node + linkType: hard + +"root-workspace-0b6124@workspace:.": + version: 0.0.0-use.local + resolution: "root-workspace-0b6124@workspace:." + dependencies: + "@babel/preset-env": ^7.0.0 + "@babel/preset-typescript": ^7.0.0 + react: "*" + languageName: unknown + linkType: soft + +"semver@npm:7.0.0": + version: 7.0.0 + resolution: "semver@npm:7.0.0" + bin: + semver: bin/semver.js + checksum: 5162b31e9902be1d51d63523eb21d28164d632f527cb0dc439a58d6eaf1a2f3c49c4e2a0f7cf8d650f673638ae34ac7e0c7c2048ff66bc5dc1298ef8551575b5 + languageName: node + linkType: hard + +"semver@npm:^5.5.0": + version: 5.7.1 + resolution: "semver@npm:5.7.1" + bin: + semver: ./bin/semver + checksum: 06ff0ed753ebf741b7602be8faad620d6e160a2cb3f61019d00d919c8bca141638aa23c34da779b8595afdc9faa3678bfbb5f60366b6a4f65f98cf86605bbcdb + languageName: node + linkType: hard + +"source-map@npm:^0.5.0": + version: 0.5.7 + resolution: "source-map@npm:0.5.7" + checksum: 737face96577a2184a42f141607fcc2c9db5620cb8517ae8ab3924476defa138fc26b0bab31e98cbd6f19211ecbf78400b59f801ff7a0f87aa9faa79f7433e10 + languageName: node + linkType: hard + +"supports-color@npm:^5.3.0": + version: 5.5.0 + resolution: "supports-color@npm:5.5.0" + dependencies: + has-flag: ^3.0.0 + checksum: edacee6425498440744c418be94b0660181aad2a1828bcf2be85c42bd385da2fd8b2b358d9b62b0c5b03ff5cd3e992458d7b8f879d9fb42f2201fe05a4848a29 + languageName: node + linkType: hard + +"to-fast-properties@npm:^2.0.0": + version: 2.0.0 + resolution: "to-fast-properties@npm:2.0.0" + checksum: 40e61984243b183d575a2f3a87d008bd57102115701ee9037fd673e34becf12ee90262631857410169ca82f401a662ed94482235cea8f3b8dea48b87eaabc467 + languageName: node + linkType: hard + +"unicode-canonical-property-names-ecmascript@npm:^1.0.4": + version: 1.0.4 + resolution: "unicode-canonical-property-names-ecmascript@npm:1.0.4" + checksum: 8b51950f8f6725acfd0cc33117e7061cc5b3ba97760aab6003db1e31b90ac41e626f289a5a39f8e2c3ed3fbb6b4774c1877fd6156a4c6f4e05736b9ff7a2e783 + languageName: node + linkType: hard + +"unicode-match-property-ecmascript@npm:^1.0.4": + version: 1.0.4 + resolution: "unicode-match-property-ecmascript@npm:1.0.4" + dependencies: + unicode-canonical-property-names-ecmascript: ^1.0.4 + unicode-property-aliases-ecmascript: ^1.0.4 + checksum: 481203b4b86861f278424ef694293bad9a090d606ac5bdb71a096fe3bbf413555d25f17e888ef9815841ece01c6a7d9f566752c04681cba8e27aec1a7e519641 + languageName: node + linkType: hard + +"unicode-match-property-value-ecmascript@npm:^1.2.0": + version: 1.2.0 + resolution: "unicode-match-property-value-ecmascript@npm:1.2.0" + checksum: 892ca3933535a30d939de026941f0e615330cb6906b62f76561b76dbe6de2aab1eb2a3c5971056813efd31c48f889b4709d34d4d8327e4ff66e3ac72b58a703e + languageName: node + linkType: hard + +"unicode-property-aliases-ecmascript@npm:^1.0.4": + version: 1.1.0 + resolution: "unicode-property-aliases-ecmascript@npm:1.1.0" + checksum: 2fa80e62a6ec395af3ee4747ce9738d2fee25ef963fb5650e358b2eb878d7f047f5ccdbd5f92e9605d13276f995fc3c4e3084475b03722cdd7ce9d58a148b2bd + languageName: node + linkType: hard diff --git a/packages/babel-plugin-jest-deadlines/.npmignore b/packages/babel-plugin-jest-deadlines/.npmignore new file mode 100644 index 000000000000..3ee5d55b0b89 --- /dev/null +++ b/packages/babel-plugin-jest-deadlines/.npmignore @@ -0,0 +1,5 @@ +**/__mocks__/** +**/__tests__/** +src +tsconfig.json +tsconfig.tsbuildinfo diff --git a/packages/babel-plugin-jest-deadlines/package.json b/packages/babel-plugin-jest-deadlines/package.json new file mode 100644 index 000000000000..5666decca6ac --- /dev/null +++ b/packages/babel-plugin-jest-deadlines/package.json @@ -0,0 +1,37 @@ +{ + "name": "babel-plugin-jest-deadlines", + "version": "26.6.2", + "repository": { + "type": "git", + "url": "https://github.com/facebook/jest.git", + "directory": "packages/babel-plugin-jest-deadlines" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + }, + "license": "MIT", + "main": "./build/index.js", + "types": "./build/index.d.ts", + "exports": { + ".": "./build/index.js", + "./package.json": "./package.json" + }, + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.0.0", + "@types/babel__traverse": "^7.0.6" + }, + "devDependencies": { + "@babel/core": "^7.11.6", + "@babel/preset-react": "^7.12.1", + "@types/babel__template": "^7.0.2", + "@types/node": "*", + "@types/prettier": "^2.0.0", + "babel-plugin-tester": "^10.0.0", + "prettier": "^2.1.1" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/packages/babel-plugin-jest-deadlines/src/__tests__/__snapshots__/deadlinesPlugin.test.ts.snap b/packages/babel-plugin-jest-deadlines/src/__tests__/__snapshots__/deadlinesPlugin.test.ts.snap new file mode 100644 index 000000000000..a080d7c39a64 --- /dev/null +++ b/packages/babel-plugin-jest-deadlines/src/__tests__/__snapshots__/deadlinesPlugin.test.ts.snap @@ -0,0 +1,93 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`babel-plugin-jest-deadlines bare function call in statement context: bare function call in statement context 1`] = ` + +async function foo() { + await bar(); + } + + ↓ ↓ ↓ ↓ ↓ ↓ + +async function foo() { + await expect.withinDeadline(bar()); +} + + +`; + +exports[`babel-plugin-jest-deadlines skips double stacking: skips double stacking 1`] = ` + +async function foo() { + await expect.withinDeadline(bar()); +} + + ↓ ↓ ↓ ↓ ↓ ↓ + +async function foo() { + await expect.withinDeadline(bar()); +} + + +`; + +exports[`babel-plugin-jest-deadlines transforms an existing expect: transforms an existing expect 1`] = ` + +async function foo() { + await expect(bar()).resolves.toBe("hot potatoes"); +} + + ↓ ↓ ↓ ↓ ↓ ↓ + +async function foo() { + await expect.withinDeadline(expect(bar()).resolves.toBe("hot potatoes")); +} + + +`; + +exports[`babel-plugin-jest-deadlines transforms an expression: transforms an expression 1`] = ` + +async function foo() { + return await bar(); +} + + ↓ ↓ ↓ ↓ ↓ ↓ + +async function foo() { + return await expect.withinDeadline(bar()); +} + + +`; + +exports[`babel-plugin-jest-deadlines transforms await in argument context: transforms await in argument context 1`] = ` + +async function foo() { + await bar(1, await quux(), 3); +} + + ↓ ↓ ↓ ↓ ↓ ↓ + +async function foo() { + await expect.withinDeadline(bar(1, await expect.withinDeadline(quux()), 3)); +} + + +`; + +exports[`babel-plugin-jest-deadlines transforms multiple awaits: transforms multiple awaits 1`] = ` + +async function foo() { + await bar(1, 2, 3); + await quux(1, 2, 3); +} + + ↓ ↓ ↓ ↓ ↓ ↓ + +async function foo() { + await expect.withinDeadline(bar(1, 2, 3)); + await expect.withinDeadline(quux(1, 2, 3)); +} + + +`; diff --git a/packages/babel-plugin-jest-deadlines/src/__tests__/deadlinesPlugin.test.ts b/packages/babel-plugin-jest-deadlines/src/__tests__/deadlinesPlugin.test.ts new file mode 100644 index 000000000000..cacb77a2e86e --- /dev/null +++ b/packages/babel-plugin-jest-deadlines/src/__tests__/deadlinesPlugin.test.ts @@ -0,0 +1,67 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + */ + +/* eslint-disable sort-keys */ + +import pluginTester from 'babel-plugin-tester'; +import babelPluginJestDeadlines from '..'; + +pluginTester({ + plugin: babelPluginJestDeadlines, + pluginName: 'babel-plugin-jest-deadlines', + tests: { + 'bare function call in statement context': { + // language=JavaScript + code: `async function foo() { + await bar(); + }`, + snapshot: true, + }, + 'transforms an expression': { + // language=JavaScript + code: ` + async function foo() { + return await bar(); + }`, + snapshot: true, + }, + 'transforms an existing expect': { + // language=JavaScript + code: ` + async function foo() { + await expect(bar()).resolves.toBe("hot potatoes"); + }`, + snapshot: true, + }, + 'skips double stacking': { + // language=JavaScript + code: ` + async function foo() { + await expect.withinDeadline(bar()); + }`, + snapshot: true, + }, + 'transforms multiple awaits': { + // language=JavaScript + code: ` + async function foo() { + await bar(1, 2, 3); + await quux(1, 2, 3); + }`, + snapshot: true, + }, + 'transforms await in argument context': { + // language=JavaScript + code: ` + async function foo() { + await bar(1, await quux(), 3); + }`, + snapshot: true, + }, + }, +}); diff --git a/packages/babel-plugin-jest-deadlines/src/index.ts b/packages/babel-plugin-jest-deadlines/src/index.ts new file mode 100644 index 000000000000..2f5df5f681e3 --- /dev/null +++ b/packages/babel-plugin-jest-deadlines/src/index.ts @@ -0,0 +1,51 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + */ + +import type {PluginObj, types as babelTypes} from '@babel/core'; +import type {Identifier} from '@babel/types'; + +export default ({ + types: t, +}: { + types: typeof babelTypes; +}): PluginObj<{ + declareJestObjGetterIdentifier: () => Identifier; + jestObjGetterIdentifier?: Identifier; +}> => ({ + visitor: { + AwaitExpression(path) { + const original = path.node.argument; + + if (!t.isCallExpression(original)) { + return; + } + + if (t.isMemberExpression(original.callee)) { + const member = original.callee; + if ( + t.isIdentifier(member.object, {name: 'expect'}) && + t.isIdentifier(member.property, {name: 'withinDeadline'}) + ) { + return; + } + } + + path.replaceWith( + t.awaitExpression( + t.callExpression( + t.memberExpression( + t.identifier('expect'), + t.identifier('withinDeadline'), + ), + [path.node.argument], + ), + ), + ); + }, + }, +}); diff --git a/packages/babel-plugin-jest-deadlines/tsconfig.json b/packages/babel-plugin-jest-deadlines/tsconfig.json new file mode 100644 index 000000000000..7bb06bce6d20 --- /dev/null +++ b/packages/babel-plugin-jest-deadlines/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "build" + } +} diff --git a/yarn.lock b/yarn.lock index ff658db33ebe..2d88fe3d98cc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4923,6 +4923,24 @@ __metadata: languageName: node linkType: hard +"babel-plugin-jest-deadlines@workspace:packages/babel-plugin-jest-deadlines": + version: 0.0.0-use.local + resolution: "babel-plugin-jest-deadlines@workspace:packages/babel-plugin-jest-deadlines" + dependencies: + "@babel/core": ^7.11.6 + "@babel/preset-react": ^7.12.1 + "@babel/template": ^7.3.3 + "@babel/types": ^7.3.3 + "@types/babel__core": ^7.0.0 + "@types/babel__template": ^7.0.2 + "@types/babel__traverse": ^7.0.6 + "@types/node": "*" + "@types/prettier": ^2.0.0 + babel-plugin-tester: ^10.0.0 + prettier: ^2.1.1 + languageName: unknown + linkType: soft + "babel-plugin-jest-hoist@^27.0.0-next.0, babel-plugin-jest-hoist@workspace:packages/babel-plugin-jest-hoist": version: 0.0.0-use.local resolution: "babel-plugin-jest-hoist@workspace:packages/babel-plugin-jest-hoist" From 60bc86a17d531c1122b388c62705f512d1367172 Mon Sep 17 00:00:00 2001 From: "Chris West (Faux)" Date: Thu, 3 Dec 2020 07:27:06 +0000 Subject: [PATCH 03/15] fix: work in Each hooks (but not All) --- e2e/__tests__/__snapshots__/deadlines.ts.snap | 27 +++++++++++++++++++ e2e/__tests__/deadlines.ts | 6 +++++ .../__tests__/manual-exceeded-hook.js | 18 +++++++++++++ packages/jest-circus/src/eventHandler.ts | 9 ++++++- 4 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 e2e/deadlines/__tests__/manual-exceeded-hook.js diff --git a/e2e/__tests__/__snapshots__/deadlines.ts.snap b/e2e/__tests__/__snapshots__/deadlines.ts.snap index d834ad850104..89a014e96aad 100644 --- a/e2e/__tests__/__snapshots__/deadlines.ts.snap +++ b/e2e/__tests__/__snapshots__/deadlines.ts.snap @@ -39,3 +39,30 @@ Time: <> Ran all test suites matching /manual-exceeded.js/i.", } `; + +exports[`throws on deadline exceeded in a hook 1`] = ` +Object { + "rest": "FAIL __tests__/manual-exceeded-hook.js + describe + ✕ does nothing + + ● describe › does nothing + + deadline exceeded (waited here for <>) + + 12 | describe('describe', () => { + 13 | beforeEach(async () => { + > 14 | await expect.withinDeadline(sleep(200)); + | ^ + 15 | }, 50); + 16 | + 17 | it('does nothing', () => {}); + + at Object. (__tests__/manual-exceeded-hook.js:14:5)", + "summary": "Test Suites: 1 failed, 1 total +Tests: 1 failed, 1 total +Snapshots: 0 total +Time: <> +Ran all test suites matching /manual-exceeded-hook.js/i.", +} +`; diff --git a/e2e/__tests__/deadlines.ts b/e2e/__tests__/deadlines.ts index 9017c23d8ac8..4e48da0723f8 100644 --- a/e2e/__tests__/deadlines.ts +++ b/e2e/__tests__/deadlines.ts @@ -22,6 +22,12 @@ it('throws on deadline exceeded', () => { expect(summaryWithoutTime(result)).toMatchSnapshot(); }); +it('throws on deadline exceeded in a hook', () => { + const result = runJest('deadlines', ['manual-exceeded-hook.js']); + expect(result.exitCode).toBe(1); + expect(summaryWithoutTime(result)).toMatchSnapshot(); +}); + function summaryWithoutTime(result: {stderr: string}) { const summary = extractSummary(result.stderr); summary.rest = summary.rest.replace( diff --git a/e2e/deadlines/__tests__/manual-exceeded-hook.js b/e2e/deadlines/__tests__/manual-exceeded-hook.js new file mode 100644 index 000000000000..e2f69585c423 --- /dev/null +++ b/e2e/deadlines/__tests__/manual-exceeded-hook.js @@ -0,0 +1,18 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +'use strict'; + +const sleep = duration => new Promise(resolve => setTimeout(resolve, duration)); + +describe('describe', () => { + beforeEach(async () => { + await expect.withinDeadline(sleep(200)); + }, 50); + + it('does nothing', () => {}); +}); diff --git a/packages/jest-circus/src/eventHandler.ts b/packages/jest-circus/src/eventHandler.ts index 7db164f93d83..84b9481eeca0 100644 --- a/packages/jest-circus/src/eventHandler.ts +++ b/packages/jest-circus/src/eventHandler.ts @@ -31,6 +31,9 @@ const eventHandler: Circus.EventHandler = ( break; } case 'hook_start': { + if (state.currentlyRunningTest) { + state.currentlyRunningTest.deadline = deadlineFor(event.timeout); + } break; } case 'start_describe_definition': { @@ -189,7 +192,7 @@ const eventHandler: Circus.EventHandler = ( break; } case 'test_fn_start': { - event.test.deadline = Date.now() + event.timeout - 20; + event.test.deadline = deadlineFor(event.timeout); break; } case 'test_fn_failure': { @@ -255,4 +258,8 @@ const eventHandler: Circus.EventHandler = ( } }; +function deadlineFor(timeout: number) { + return Date.now() + timeout - 20; +} + export default eventHandler; From 610e674bb95308bf8d4e091f8231da6f8b5d0fd9 Mon Sep 17 00:00:00 2001 From: "Chris West (Faux)" Date: Thu, 3 Dec 2020 20:16:04 +0000 Subject: [PATCH 04/15] fix: review nits --- e2e/__tests__/babelPluginJestDeadlines.test.ts | 2 +- packages/babel-plugin-jest-deadlines/package.json | 8 ++------ .../__snapshots__/deadlinesPlugin.test.ts.snap | 4 ++-- .../src/__tests__/deadlinesPlugin.test.ts | 7 ++++--- packages/babel-plugin-jest-deadlines/src/index.ts | 3 --- packages/expect/src/index.ts | 1 + packages/jest-circus/src/deadlineTimeout.ts | 14 ++++++++++++-- yarn.lock | 4 ---- 8 files changed, 22 insertions(+), 21 deletions(-) diff --git a/e2e/__tests__/babelPluginJestDeadlines.test.ts b/e2e/__tests__/babelPluginJestDeadlines.test.ts index c76b6095a118..1f4799126feb 100644 --- a/e2e/__tests__/babelPluginJestDeadlines.test.ts +++ b/e2e/__tests__/babelPluginJestDeadlines.test.ts @@ -12,7 +12,7 @@ import runJest from '../runJest'; const DIR = path.resolve(__dirname, '..', 'babel-plugin-jest-deadlines'); -beforeEach(() => { +beforeAll(() => { runYarnInstall(DIR); }); diff --git a/packages/babel-plugin-jest-deadlines/package.json b/packages/babel-plugin-jest-deadlines/package.json index 5666decca6ac..8818a5f426d2 100644 --- a/packages/babel-plugin-jest-deadlines/package.json +++ b/packages/babel-plugin-jest-deadlines/package.json @@ -17,19 +17,15 @@ "./package.json": "./package.json" }, "dependencies": { - "@babel/template": "^7.3.3", "@babel/types": "^7.3.3", - "@types/babel__core": "^7.0.0", - "@types/babel__traverse": "^7.0.6" + "@types/babel__core": "^7.0.0" }, "devDependencies": { "@babel/core": "^7.11.6", "@babel/preset-react": "^7.12.1", "@types/babel__template": "^7.0.2", "@types/node": "*", - "@types/prettier": "^2.0.0", - "babel-plugin-tester": "^10.0.0", - "prettier": "^2.1.1" + "babel-plugin-tester": "^10.0.0" }, "publishConfig": { "access": "public" diff --git a/packages/babel-plugin-jest-deadlines/src/__tests__/__snapshots__/deadlinesPlugin.test.ts.snap b/packages/babel-plugin-jest-deadlines/src/__tests__/__snapshots__/deadlinesPlugin.test.ts.snap index a080d7c39a64..d36dfdf52e0c 100644 --- a/packages/babel-plugin-jest-deadlines/src/__tests__/__snapshots__/deadlinesPlugin.test.ts.snap +++ b/packages/babel-plugin-jest-deadlines/src/__tests__/__snapshots__/deadlinesPlugin.test.ts.snap @@ -3,8 +3,8 @@ exports[`babel-plugin-jest-deadlines bare function call in statement context: bare function call in statement context 1`] = ` async function foo() { - await bar(); - } + await bar(); +} ↓ ↓ ↓ ↓ ↓ ↓ diff --git a/packages/babel-plugin-jest-deadlines/src/__tests__/deadlinesPlugin.test.ts b/packages/babel-plugin-jest-deadlines/src/__tests__/deadlinesPlugin.test.ts index cacb77a2e86e..d6c045be4124 100644 --- a/packages/babel-plugin-jest-deadlines/src/__tests__/deadlinesPlugin.test.ts +++ b/packages/babel-plugin-jest-deadlines/src/__tests__/deadlinesPlugin.test.ts @@ -17,9 +17,10 @@ pluginTester({ tests: { 'bare function call in statement context': { // language=JavaScript - code: `async function foo() { - await bar(); - }`, + code: ` + async function foo() { + await bar(); + }`, snapshot: true, }, 'transforms an expression': { diff --git a/packages/babel-plugin-jest-deadlines/src/index.ts b/packages/babel-plugin-jest-deadlines/src/index.ts index 2f5df5f681e3..685094da0076 100644 --- a/packages/babel-plugin-jest-deadlines/src/index.ts +++ b/packages/babel-plugin-jest-deadlines/src/index.ts @@ -7,15 +7,12 @@ */ import type {PluginObj, types as babelTypes} from '@babel/core'; -import type {Identifier} from '@babel/types'; export default ({ types: t, }: { types: typeof babelTypes; }): PluginObj<{ - declareJestObjGetterIdentifier: () => Identifier; - jestObjGetterIdentifier?: Identifier; }> => ({ visitor: { AwaitExpression(path) { diff --git a/packages/expect/src/index.ts b/packages/expect/src/index.ts index e050afe40a48..c5583509e17a 100644 --- a/packages/expect/src/index.ts +++ b/packages/expect/src/index.ts @@ -412,6 +412,7 @@ setMatchers(spyMatchers, true, expect as Expect); setMatchers(toThrowMatchers, true, expect as Expect); expect.addSnapshotSerializer = () => void 0; +expect.withinDeadline = async () => { throw new Error('withinDeadline must be implemented by the runtime'); } expect.assertions = assertions; expect.hasAssertions = hasAssertions; expect.getState = getState; diff --git a/packages/jest-circus/src/deadlineTimeout.ts b/packages/jest-circus/src/deadlineTimeout.ts index bd29eaad05ae..74643329401d 100644 --- a/packages/jest-circus/src/deadlineTimeout.ts +++ b/packages/jest-circus/src/deadlineTimeout.ts @@ -1,3 +1,10 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + import {getState} from './state'; export async function withinDeadline(promise: Promise): Promise { @@ -13,7 +20,7 @@ function isUs(line: string): boolean { } async function timeout(promise: Promise, ms: number): Promise { - let timeoutId; + let timeoutId: ReturnType | undefined; try { return await Promise.race([ promise, @@ -21,6 +28,7 @@ async function timeout(promise: Promise, ms: number): Promise { await new Promise(resolve => { timeoutId = setTimeout(resolve, ms); }); + timeoutId = undefined; const here = new Error(`deadline exceeded (waited here for ${ms}ms)`); here.stack = here.stack ?.split('\n') @@ -30,6 +38,8 @@ async function timeout(promise: Promise, ms: number): Promise { })(), ]); } finally { - clearTimeout(timeoutId); + if (timeoutId) { + clearTimeout(timeoutId); + } } } diff --git a/yarn.lock b/yarn.lock index 2d88fe3d98cc..eaaa3be0735a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4929,15 +4929,11 @@ __metadata: dependencies: "@babel/core": ^7.11.6 "@babel/preset-react": ^7.12.1 - "@babel/template": ^7.3.3 "@babel/types": ^7.3.3 "@types/babel__core": ^7.0.0 "@types/babel__template": ^7.0.2 - "@types/babel__traverse": ^7.0.6 "@types/node": "*" - "@types/prettier": ^2.0.0 babel-plugin-tester: ^10.0.0 - prettier: ^2.1.1 languageName: unknown linkType: soft From 352dcaa11b843e50fdede7b513c54da8c320b1ad Mon Sep 17 00:00:00 2001 From: "Chris West (Faux)" Date: Thu, 3 Dec 2020 20:22:42 +0000 Subject: [PATCH 05/15] feat: mutate test/hook's timeout before events --- packages/jest-circus/src/eventHandler.ts | 10 ++++++++-- packages/jest-circus/src/run.ts | 12 ++++++------ packages/jest-types/src/Circus.ts | 2 -- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/packages/jest-circus/src/eventHandler.ts b/packages/jest-circus/src/eventHandler.ts index 84b9481eeca0..5a99dd34812b 100644 --- a/packages/jest-circus/src/eventHandler.ts +++ b/packages/jest-circus/src/eventHandler.ts @@ -32,7 +32,10 @@ const eventHandler: Circus.EventHandler = ( } case 'hook_start': { if (state.currentlyRunningTest) { - state.currentlyRunningTest.deadline = deadlineFor(event.timeout); + if (undefined === event.hook.timeout || null == event.hook.timeout) { + throw new Error('expected timeout to be set before event fired'); + } + state.currentlyRunningTest.deadline = deadlineFor(event.hook.timeout); } break; } @@ -192,7 +195,10 @@ const eventHandler: Circus.EventHandler = ( break; } case 'test_fn_start': { - event.test.deadline = deadlineFor(event.timeout); + if (undefined === event.test.timeout) { + throw new Error('expected timeout to be set before event fired'); + } + event.test.deadline = deadlineFor(event.test.timeout); break; } case 'test_fn_failure': { diff --git a/packages/jest-circus/src/run.ts b/packages/jest-circus/src/run.ts index 2066229600ae..5bd68d50c9d2 100644 --- a/packages/jest-circus/src/run.ts +++ b/packages/jest-circus/src/run.ts @@ -148,13 +148,13 @@ const _callCircusHook = async ({ test?: Circus.TestEntry; testContext?: Circus.TestContext; }): Promise => { - const timeout = hook.timeout || getState().testTimeout; - await dispatch({hook, name: 'hook_start', timeout}); + hook.timeout = hook.timeout || getState().testTimeout; + await dispatch({hook, name: 'hook_start'}); try { await callAsyncCircusFn(hook, testContext, { isHook: true, - timeout, + timeout: hook.timeout, }); await dispatch({describeBlock, hook, name: 'hook_success', test}); } catch (error) { @@ -166,8 +166,8 @@ const _callCircusTest = async ( test: Circus.TestEntry, testContext: Circus.TestContext, ): Promise => { - const timeout = test.timeout || getState().testTimeout; - await dispatch({name: 'test_fn_start', test, timeout}); + test.timeout = test.timeout || getState().testTimeout; + await dispatch({name: 'test_fn_start', test}); invariant(test.fn, `Tests with no 'fn' should have 'mode' set to 'skipped'`); if (test.errors.length) { @@ -177,7 +177,7 @@ const _callCircusTest = async ( try { await callAsyncCircusFn(test, testContext, { isHook: false, - timeout, + timeout: test.timeout, }); await dispatch({name: 'test_fn_success', test}); } catch (error) { diff --git a/packages/jest-types/src/Circus.ts b/packages/jest-types/src/Circus.ts index 79932f2fd4e2..f001b276c0a5 100644 --- a/packages/jest-types/src/Circus.ts +++ b/packages/jest-types/src/Circus.ts @@ -91,7 +91,6 @@ export type AsyncEvent = | { name: 'hook_start'; hook: Hook; - timeout: number; } | { name: 'hook_success'; @@ -109,7 +108,6 @@ export type AsyncEvent = | { name: 'test_fn_start'; test: TestEntry; - timeout: number; } | { name: 'test_fn_success'; From acffc412187a6eb85907feca708043ab27fb421b Mon Sep 17 00:00:00 2001 From: "Chris West (Faux)" Date: Sat, 5 Dec 2020 10:12:02 +0000 Subject: [PATCH 06/15] fix: expect.deadline(), not test.deadline() --- packages/expect/src/index.ts | 1 + packages/expect/src/types.ts | 2 ++ packages/jest-circus/src/deadlineTimeout.ts | 8 ++++++-- .../src/legacy-code-todo-rewrite/jestAdapterInit.ts | 3 --- .../src/legacy-code-todo-rewrite/jestExpect.ts | 3 ++- packages/jest-types/src/Global.ts | 1 - 6 files changed, 11 insertions(+), 7 deletions(-) diff --git a/packages/expect/src/index.ts b/packages/expect/src/index.ts index c5583509e17a..e0b9d236c4f2 100644 --- a/packages/expect/src/index.ts +++ b/packages/expect/src/index.ts @@ -412,6 +412,7 @@ setMatchers(spyMatchers, true, expect as Expect); setMatchers(toThrowMatchers, true, expect as Expect); expect.addSnapshotSerializer = () => void 0; +expect.deadline = async () => { throw new Error('deadline must be implemented by the runtime'); } expect.withinDeadline = async () => { throw new Error('withinDeadline must be implemented by the runtime'); } expect.assertions = assertions; expect.hasAssertions = hasAssertions; diff --git a/packages/expect/src/types.ts b/packages/expect/src/types.ts index e34b0903734f..ce4a20a81831 100644 --- a/packages/expect/src/types.ts +++ b/packages/expect/src/types.ts @@ -81,6 +81,8 @@ export type Expect = { objectContaining(sample: Record): AsymmetricMatcher; stringContaining(expected: string): AsymmetricMatcher; stringMatching(expected: string | RegExp): AsymmetricMatcher; + // TODO: this is added by test runners, not `expect` itself + deadline(): number; withinDeadline(promise: Promise): Promise; [id: string]: AsymmetricMatcher; not: {[id: string]: AsymmetricMatcher}; diff --git a/packages/jest-circus/src/deadlineTimeout.ts b/packages/jest-circus/src/deadlineTimeout.ts index 74643329401d..22e7319f70e3 100644 --- a/packages/jest-circus/src/deadlineTimeout.ts +++ b/packages/jest-circus/src/deadlineTimeout.ts @@ -7,12 +7,16 @@ import {getState} from './state'; -export async function withinDeadline(promise: Promise): Promise { +export function deadline(): number { const deadline = getState()?.currentlyRunningTest?.deadline; if (undefined === deadline) { throw new Error('bug! no deadline available'); } - return timeout(promise, deadline - Date.now()); + return deadline; +} + +export async function withinDeadline(promise: Promise): Promise { + return timeout(promise, deadline() - Date.now()); } function isUs(line: string): boolean { diff --git a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts index a540f9309688..61c68b332117 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/jestAdapterInit.ts @@ -80,9 +80,6 @@ export const initialize = async ({ xtest: globals.it.skip, }; - globalsObject.test.deadline = () => - getRunnerState()?.currentlyRunningTest?.deadline; - globalsObject.test.concurrent = (test => { const concurrent = ( testName: string, diff --git a/packages/jest-circus/src/legacy-code-todo-rewrite/jestExpect.ts b/packages/jest-circus/src/legacy-code-todo-rewrite/jestExpect.ts index a50c34da1e3a..52e9bd5ad8d2 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestExpect.ts +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/jestExpect.ts @@ -14,7 +14,7 @@ import { toThrowErrorMatchingInlineSnapshot, toThrowErrorMatchingSnapshot, } from 'jest-snapshot'; -import {withinDeadline} from '../deadlineTimeout'; +import { deadline, withinDeadline } from '../deadlineTimeout'; export type Expect = typeof expect; @@ -28,6 +28,7 @@ export default (config: Pick): Expect => { }); expect.addSnapshotSerializer = addSerializer; + expect.deadline = deadline; expect.withinDeadline = withinDeadline; return expect; diff --git a/packages/jest-types/src/Global.ts b/packages/jest-types/src/Global.ts index ee053d15408b..46a4d0669b96 100644 --- a/packages/jest-types/src/Global.ts +++ b/packages/jest-types/src/Global.ts @@ -75,7 +75,6 @@ export interface HookBase { export interface ItBase { (testName: TestName, fn: TestFn, timeout?: number): void; each: Each; - deadline: () => number | undefined; } export interface It extends ItBase { From eff7ba4dc61d5e0820a73502ef914484963760aa Mon Sep 17 00:00:00 2001 From: "Chris West (Faux)" Date: Sat, 5 Dec 2020 10:26:24 +0000 Subject: [PATCH 07/15] refactor: move deadline storage onto the state Significant wins here, no more event wrangling, no more mutation, no more weird initialisation, and will probably work in hooks. --- e2e/__tests__/__snapshots__/deadlines.ts.snap | 27 +++++++++++++++++++ e2e/__tests__/deadlines.ts | 6 +++++ .../manual-exceeded-hook-describe.js | 18 +++++++++++++ packages/jest-circus/src/deadlineTimeout.ts | 4 +-- packages/jest-circus/src/eventHandler.ts | 17 ------------ packages/jest-circus/src/run.ts | 14 +++++++--- packages/jest-circus/src/state.ts | 1 + packages/jest-types/src/Circus.ts | 2 +- 8 files changed, 65 insertions(+), 24 deletions(-) create mode 100644 e2e/deadlines/__tests__/manual-exceeded-hook-describe.js diff --git a/e2e/__tests__/__snapshots__/deadlines.ts.snap b/e2e/__tests__/__snapshots__/deadlines.ts.snap index 89a014e96aad..edf1ab508e33 100644 --- a/e2e/__tests__/__snapshots__/deadlines.ts.snap +++ b/e2e/__tests__/__snapshots__/deadlines.ts.snap @@ -40,6 +40,33 @@ Ran all test suites matching /manual-exceeded.js/i.", } `; +exports[`throws on deadline exceeded in a describe hook 1`] = ` +Object { + "rest": "FAIL __tests__/manual-exceeded-hook-describe.js + describe + ✕ does nothing + + ● describe › does nothing + + deadline exceeded (waited here for <>) + + 12 | describe('describe', () => { + 13 | beforeAll(async () => { + > 14 | await expect.withinDeadline(sleep(200)); + | ^ + 15 | }, 50); + 16 | + 17 | it('does nothing', () => {}); + + at __tests__/manual-exceeded-hook-describe.js:14:5", + "summary": "Test Suites: 1 failed, 1 total +Tests: 1 failed, 1 total +Snapshots: 0 total +Time: <> +Ran all test suites matching /manual-exceeded-hook-describe.js/i.", +} +`; + exports[`throws on deadline exceeded in a hook 1`] = ` Object { "rest": "FAIL __tests__/manual-exceeded-hook.js diff --git a/e2e/__tests__/deadlines.ts b/e2e/__tests__/deadlines.ts index 4e48da0723f8..47f9e3a89365 100644 --- a/e2e/__tests__/deadlines.ts +++ b/e2e/__tests__/deadlines.ts @@ -28,6 +28,12 @@ it('throws on deadline exceeded in a hook', () => { expect(summaryWithoutTime(result)).toMatchSnapshot(); }); +it('throws on deadline exceeded in a describe hook', () => { + const result = runJest('deadlines', ['manual-exceeded-hook-describe.js']); + expect(result.exitCode).toBe(1); + expect(summaryWithoutTime(result)).toMatchSnapshot(); +}); + function summaryWithoutTime(result: {stderr: string}) { const summary = extractSummary(result.stderr); summary.rest = summary.rest.replace( diff --git a/e2e/deadlines/__tests__/manual-exceeded-hook-describe.js b/e2e/deadlines/__tests__/manual-exceeded-hook-describe.js new file mode 100644 index 000000000000..e978546e523a --- /dev/null +++ b/e2e/deadlines/__tests__/manual-exceeded-hook-describe.js @@ -0,0 +1,18 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +'use strict'; + +const sleep = duration => new Promise(resolve => setTimeout(resolve, duration)); + +describe('describe', () => { + beforeAll(async () => { + await expect.withinDeadline(sleep(200)); + }, 50); + + it('does nothing', () => {}); +}); diff --git a/packages/jest-circus/src/deadlineTimeout.ts b/packages/jest-circus/src/deadlineTimeout.ts index 22e7319f70e3..2603a9d641c5 100644 --- a/packages/jest-circus/src/deadlineTimeout.ts +++ b/packages/jest-circus/src/deadlineTimeout.ts @@ -8,8 +8,8 @@ import {getState} from './state'; export function deadline(): number { - const deadline = getState()?.currentlyRunningTest?.deadline; - if (undefined === deadline) { + const deadline = getState()?.currentlyRunningChildDeadline; + if (null === deadline) { throw new Error('bug! no deadline available'); } return deadline; diff --git a/packages/jest-circus/src/eventHandler.ts b/packages/jest-circus/src/eventHandler.ts index 5a99dd34812b..af46770bcc62 100644 --- a/packages/jest-circus/src/eventHandler.ts +++ b/packages/jest-circus/src/eventHandler.ts @@ -31,12 +31,6 @@ const eventHandler: Circus.EventHandler = ( break; } case 'hook_start': { - if (state.currentlyRunningTest) { - if (undefined === event.hook.timeout || null == event.hook.timeout) { - throw new Error('expected timeout to be set before event fired'); - } - state.currentlyRunningTest.deadline = deadlineFor(event.hook.timeout); - } break; } case 'start_describe_definition': { @@ -194,13 +188,6 @@ const eventHandler: Circus.EventHandler = ( event.test.invocations += 1; break; } - case 'test_fn_start': { - if (undefined === event.test.timeout) { - throw new Error('expected timeout to be set before event fired'); - } - event.test.deadline = deadlineFor(event.test.timeout); - break; - } case 'test_fn_failure': { const { error, @@ -264,8 +251,4 @@ const eventHandler: Circus.EventHandler = ( } }; -function deadlineFor(timeout: number) { - return Date.now() + timeout - 20; -} - export default eventHandler; diff --git a/packages/jest-circus/src/run.ts b/packages/jest-circus/src/run.ts index 5bd68d50c9d2..c8cafc218be6 100644 --- a/packages/jest-circus/src/run.ts +++ b/packages/jest-circus/src/run.ts @@ -148,13 +148,14 @@ const _callCircusHook = async ({ test?: Circus.TestEntry; testContext?: Circus.TestContext; }): Promise => { - hook.timeout = hook.timeout || getState().testTimeout; await dispatch({hook, name: 'hook_start'}); + const timeout = hook.timeout || getState().testTimeout; + _updateDeadline(timeout); try { await callAsyncCircusFn(hook, testContext, { isHook: true, - timeout: hook.timeout, + timeout, }); await dispatch({describeBlock, hook, name: 'hook_success', test}); } catch (error) { @@ -166,8 +167,9 @@ const _callCircusTest = async ( test: Circus.TestEntry, testContext: Circus.TestContext, ): Promise => { - test.timeout = test.timeout || getState().testTimeout; await dispatch({name: 'test_fn_start', test}); + const timeout = test.timeout || getState().testTimeout; + _updateDeadline(timeout); invariant(test.fn, `Tests with no 'fn' should have 'mode' set to 'skipped'`); if (test.errors.length) { @@ -177,7 +179,7 @@ const _callCircusTest = async ( try { await callAsyncCircusFn(test, testContext, { isHook: false, - timeout: test.timeout, + timeout, }); await dispatch({name: 'test_fn_success', test}); } catch (error) { @@ -185,4 +187,8 @@ const _callCircusTest = async ( } }; +const _updateDeadline = (timeout: number): void => { + getState().currentlyRunningChildDeadline = Date.now() + timeout - 20; +}; + export default run; diff --git a/packages/jest-circus/src/state.ts b/packages/jest-circus/src/state.ts index 5af3c07c22b0..137ea3ea0ff3 100644 --- a/packages/jest-circus/src/state.ts +++ b/packages/jest-circus/src/state.ts @@ -21,6 +21,7 @@ export const ROOT_DESCRIBE_BLOCK_NAME = 'ROOT_DESCRIBE_BLOCK'; const ROOT_DESCRIBE_BLOCK = makeDescribe(ROOT_DESCRIBE_BLOCK_NAME); const INITIAL_STATE: Circus.State = { currentDescribeBlock: ROOT_DESCRIBE_BLOCK, + currentlyRunningChildDeadline: null, currentlyRunningTest: null, expand: undefined, hasFocusedTests: false, diff --git a/packages/jest-types/src/Circus.ts b/packages/jest-types/src/Circus.ts index f001b276c0a5..97c06aa96326 100644 --- a/packages/jest-types/src/Circus.ts +++ b/packages/jest-types/src/Circus.ts @@ -199,6 +199,7 @@ export type GlobalErrorHandlers = { export type State = { currentDescribeBlock: DescribeBlock; currentlyRunningTest?: TestEntry | null; // including when hooks are being executed + currentlyRunningChildDeadline: number | null; expand?: boolean; // expand error messages hasFocusedTests: boolean; // that are defined using test.only hasStarted: boolean; // whether the rootDescribeBlock has started running @@ -240,5 +241,4 @@ export type TestEntry = { duration?: number | null; status?: TestStatus | null; // whether the test has been skipped or run already timeout?: number; - deadline?: number; }; From eb542f85c4229da5723d64592c7727ac9cc0e98f Mon Sep 17 00:00:00 2001 From: "Chris West (Faux)" Date: Sat, 5 Dec 2020 11:08:55 +0000 Subject: [PATCH 08/15] feat: less leaky timeout implementation --- packages/jest-circus/src/deadlineTimeout.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/jest-circus/src/deadlineTimeout.ts b/packages/jest-circus/src/deadlineTimeout.ts index 2603a9d641c5..2eab6baf800e 100644 --- a/packages/jest-circus/src/deadlineTimeout.ts +++ b/packages/jest-circus/src/deadlineTimeout.ts @@ -25,14 +25,18 @@ function isUs(line: string): boolean { async function timeout(promise: Promise, ms: number): Promise { let timeoutId: ReturnType | undefined; + let resolvePromise: { (value: boolean): void } | undefined; try { return await Promise.race([ promise, - (async () => { - await new Promise(resolve => { - timeoutId = setTimeout(resolve, ms); + (async (): Promise => { + const firedForReal = await new Promise(resolve => { + resolvePromise = resolve; + timeoutId = setTimeout(() => resolve(true), ms); }); - timeoutId = undefined; + if (!firedForReal) { + return undefined as never; + } const here = new Error(`deadline exceeded (waited here for ${ms}ms)`); here.stack = here.stack ?.split('\n') @@ -45,5 +49,6 @@ async function timeout(promise: Promise, ms: number): Promise { if (timeoutId) { clearTimeout(timeoutId); } + resolvePromise?.(false); } } From e11bf41603a69c56cd0e1a90c65ed95a5c34dedb Mon Sep 17 00:00:00 2001 From: "Chris West (Faux)" Date: Sat, 5 Dec 2020 11:17:42 +0000 Subject: [PATCH 09/15] refactor: extract cancellableSleep --- packages/jest-circus/src/deadlineTimeout.ts | 41 +++++++++++++++------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/packages/jest-circus/src/deadlineTimeout.ts b/packages/jest-circus/src/deadlineTimeout.ts index 2eab6baf800e..6eee1f5bdaf5 100644 --- a/packages/jest-circus/src/deadlineTimeout.ts +++ b/packages/jest-circus/src/deadlineTimeout.ts @@ -24,17 +24,12 @@ function isUs(line: string): boolean { } async function timeout(promise: Promise, ms: number): Promise { - let timeoutId: ReturnType | undefined; - let resolvePromise: { (value: boolean): void } | undefined; + const {promise: sleepCancelled, clear} = cancellableSleep(ms); try { return await Promise.race([ promise, - (async (): Promise => { - const firedForReal = await new Promise(resolve => { - resolvePromise = resolve; - timeoutId = setTimeout(() => resolve(true), ms); - }); - if (!firedForReal) { + (async () => { + if (await sleepCancelled) { return undefined as never; } const here = new Error(`deadline exceeded (waited here for ${ms}ms)`); @@ -46,9 +41,31 @@ async function timeout(promise: Promise, ms: number): Promise { })(), ]); } finally { - if (timeoutId) { - clearTimeout(timeoutId); - } - resolvePromise?.(false); + clear(); } } + +const cancellableSleep = (ms: number) => { + const state: { + resolvePromise: null | {(firedForReal: boolean): void}; + timeoutId: null | ReturnType; + } = { + resolvePromise: null, + timeoutId: null, + }; + + const promise = new Promise(resolve => { + state.resolvePromise = resolve; + state.timeoutId = setTimeout(() => resolve(false), ms); + }); + + return { + clear: () => { + state.resolvePromise?.(true); + if (state.timeoutId) { + clearTimeout(state.timeoutId); + } + }, + promise, + }; +}; From ce38ce4bcff2d22f5c4e957b124e005b5b498dd7 Mon Sep 17 00:00:00 2001 From: "Chris West (Faux)" Date: Sat, 5 Dec 2020 11:52:30 +0000 Subject: [PATCH 10/15] feat: babel plugin: generate our own expect --- .../deadlinesPlugin.test.ts.snap | 26 +++++++++++++----- .../babel-plugin-jest-deadlines/src/index.ts | 27 +++++++++++++++---- 2 files changed, 41 insertions(+), 12 deletions(-) diff --git a/packages/babel-plugin-jest-deadlines/src/__tests__/__snapshots__/deadlinesPlugin.test.ts.snap b/packages/babel-plugin-jest-deadlines/src/__tests__/__snapshots__/deadlinesPlugin.test.ts.snap index d36dfdf52e0c..00e3e4c7d2df 100644 --- a/packages/babel-plugin-jest-deadlines/src/__tests__/__snapshots__/deadlinesPlugin.test.ts.snap +++ b/packages/babel-plugin-jest-deadlines/src/__tests__/__snapshots__/deadlinesPlugin.test.ts.snap @@ -8,8 +8,10 @@ async function foo() { ↓ ↓ ↓ ↓ ↓ ↓ +const _expect = require("@jest/globals").expect; + async function foo() { - await expect.withinDeadline(bar()); + await _expect.withinDeadline(bar()); } @@ -23,8 +25,10 @@ async function foo() { ↓ ↓ ↓ ↓ ↓ ↓ +const _expect = require("@jest/globals").expect; + async function foo() { - await expect.withinDeadline(bar()); + await _expect.withinDeadline(expect.withinDeadline(bar())); } @@ -38,8 +42,10 @@ async function foo() { ↓ ↓ ↓ ↓ ↓ ↓ +const _expect = require("@jest/globals").expect; + async function foo() { - await expect.withinDeadline(expect(bar()).resolves.toBe("hot potatoes")); + await _expect.withinDeadline(expect(bar()).resolves.toBe("hot potatoes")); } @@ -53,8 +59,10 @@ async function foo() { ↓ ↓ ↓ ↓ ↓ ↓ +const _expect = require("@jest/globals").expect; + async function foo() { - return await expect.withinDeadline(bar()); + return await _expect.withinDeadline(bar()); } @@ -68,8 +76,10 @@ async function foo() { ↓ ↓ ↓ ↓ ↓ ↓ +const _expect = require("@jest/globals").expect; + async function foo() { - await expect.withinDeadline(bar(1, await expect.withinDeadline(quux()), 3)); + await _expect.withinDeadline(bar(1, await _expect.withinDeadline(quux()), 3)); } @@ -84,9 +94,11 @@ async function foo() { ↓ ↓ ↓ ↓ ↓ ↓ +const _expect = require("@jest/globals").expect; + async function foo() { - await expect.withinDeadline(bar(1, 2, 3)); - await expect.withinDeadline(quux(1, 2, 3)); + await _expect.withinDeadline(bar(1, 2, 3)); + await _expect.withinDeadline(quux(1, 2, 3)); } diff --git a/packages/babel-plugin-jest-deadlines/src/index.ts b/packages/babel-plugin-jest-deadlines/src/index.ts index 685094da0076..a4da501e4790 100644 --- a/packages/babel-plugin-jest-deadlines/src/index.ts +++ b/packages/babel-plugin-jest-deadlines/src/index.ts @@ -7,13 +7,33 @@ */ import type {PluginObj, types as babelTypes} from '@babel/core'; +import type {Identifier} from '@babel/types'; export default ({ types: t, }: { types: typeof babelTypes; }): PluginObj<{ + ourExpect: Identifier; }> => ({ + pre({path: program}) { + this.ourExpect = program.scope.generateUidIdentifier('expect'); + + // const _expect = require("@jest/globals").expect; + const decl = t.variableDeclaration('const', [ + t.variableDeclarator( + this.ourExpect, + t.memberExpression( + t.callExpression(t.identifier('require'), [ + t.stringLiteral('@jest/globals'), + ]), + t.identifier('expect'), + ), + ), + ]); + + program.unshiftContainer('body', decl); + }, visitor: { AwaitExpression(path) { const original = path.node.argument; @@ -25,7 +45,7 @@ export default ({ if (t.isMemberExpression(original.callee)) { const member = original.callee; if ( - t.isIdentifier(member.object, {name: 'expect'}) && + t.isIdentifier(member.object, this.ourExpect) && t.isIdentifier(member.property, {name: 'withinDeadline'}) ) { return; @@ -35,10 +55,7 @@ export default ({ path.replaceWith( t.awaitExpression( t.callExpression( - t.memberExpression( - t.identifier('expect'), - t.identifier('withinDeadline'), - ), + t.memberExpression(this.ourExpect, t.identifier('withinDeadline')), [path.node.argument], ), ), From 3810d4903c490dbe035fdbac3758429a554e7d04 Mon Sep 17 00:00:00 2001 From: "Chris West (Faux)" Date: Sat, 5 Dec 2020 12:01:24 +0000 Subject: [PATCH 11/15] feat: use formatTime --- e2e/__tests__/babelPluginJestDeadlines.test.ts | 2 +- e2e/__tests__/deadlines.ts | 2 +- packages/jest-circus/src/deadlineTimeout.ts | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/e2e/__tests__/babelPluginJestDeadlines.test.ts b/e2e/__tests__/babelPluginJestDeadlines.test.ts index 1f4799126feb..17cf81003457 100644 --- a/e2e/__tests__/babelPluginJestDeadlines.test.ts +++ b/e2e/__tests__/babelPluginJestDeadlines.test.ts @@ -39,7 +39,7 @@ it('throws on deadline exceeded', () => { function summaryWithoutTime(result: {stderr: string}) { const summary = extractSummary(result.stderr); summary.rest = summary.rest.replace( - /(waited here for) \d+ms/, + /(waited here for) \d*\.?\d+ m?s\b/, '$1 <>', ); return summary; diff --git a/e2e/__tests__/deadlines.ts b/e2e/__tests__/deadlines.ts index 47f9e3a89365..c5f968ce5ea7 100644 --- a/e2e/__tests__/deadlines.ts +++ b/e2e/__tests__/deadlines.ts @@ -37,7 +37,7 @@ it('throws on deadline exceeded in a describe hook', () => { function summaryWithoutTime(result: {stderr: string}) { const summary = extractSummary(result.stderr); summary.rest = summary.rest.replace( - /(waited here for) \d+ms/, + /(waited here for) \d*\.?\d+ m?s\b/, '$1 <>', ); return summary; diff --git a/packages/jest-circus/src/deadlineTimeout.ts b/packages/jest-circus/src/deadlineTimeout.ts index 6eee1f5bdaf5..3936953fb86e 100644 --- a/packages/jest-circus/src/deadlineTimeout.ts +++ b/packages/jest-circus/src/deadlineTimeout.ts @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +import {formatTime} from 'jest-util'; import {getState} from './state'; export function deadline(): number { @@ -32,7 +33,7 @@ async function timeout(promise: Promise, ms: number): Promise { if (await sleepCancelled) { return undefined as never; } - const here = new Error(`deadline exceeded (waited here for ${ms}ms)`); + const here = new Error(`deadline exceeded (waited here for ${formatTime(ms)})`); here.stack = here.stack ?.split('\n') .filter(line => !isUs(line)) From 898d5a28571508a580bddb6a744ee792194d08a2 Mon Sep 17 00:00:00 2001 From: "Chris West (Faux)" Date: Wed, 9 Dec 2020 09:56:15 +0000 Subject: [PATCH 12/15] chore: document why we need stack stripping --- packages/jest-circus/src/deadlineTimeout.ts | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/packages/jest-circus/src/deadlineTimeout.ts b/packages/jest-circus/src/deadlineTimeout.ts index 3936953fb86e..6ee757bd0d11 100644 --- a/packages/jest-circus/src/deadlineTimeout.ts +++ b/packages/jest-circus/src/deadlineTimeout.ts @@ -24,6 +24,16 @@ function isUs(line: string): boolean { return line.includes('deadlineTimeout') && line.includes('jest-circus'); } +// jest-message-util won't strip internals from the stack if the internals +// happen on the first line, so we need to remove it in advance +function removeUsFromStack(err: Error): Error { + err.stack = err.stack + ?.split('\n') + .filter(line => !isUs(line)) + .join('\n'); + return err; +} + async function timeout(promise: Promise, ms: number): Promise { const {promise: sleepCancelled, clear} = cancellableSleep(ms); try { @@ -33,12 +43,9 @@ async function timeout(promise: Promise, ms: number): Promise { if (await sleepCancelled) { return undefined as never; } - const here = new Error(`deadline exceeded (waited here for ${formatTime(ms)})`); - here.stack = here.stack - ?.split('\n') - .filter(line => !isUs(line)) - .join('\n'); - throw here; + throw removeUsFromStack( + new Error(`deadline exceeded (waited here for ${formatTime(ms)})`), + ); })(), ]); } finally { From 3086c70d54f6a11b9a2377d818ddf16f52ffd572 Mon Sep 17 00:00:00 2001 From: "Chris West (Faux)" Date: Wed, 9 Dec 2020 10:00:48 +0000 Subject: [PATCH 13/15] chore: fix eslint/prettier --- packages/expect/src/index.ts | 8 ++++++-- .../src/legacy-code-todo-rewrite/jestExpect.ts | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/expect/src/index.ts b/packages/expect/src/index.ts index e0b9d236c4f2..52a9530d1566 100644 --- a/packages/expect/src/index.ts +++ b/packages/expect/src/index.ts @@ -412,8 +412,12 @@ setMatchers(spyMatchers, true, expect as Expect); setMatchers(toThrowMatchers, true, expect as Expect); expect.addSnapshotSerializer = () => void 0; -expect.deadline = async () => { throw new Error('deadline must be implemented by the runtime'); } -expect.withinDeadline = async () => { throw new Error('withinDeadline must be implemented by the runtime'); } +expect.deadline = async () => { + throw new Error('deadline must be implemented by the runtime'); +}; +expect.withinDeadline = async () => { + throw new Error('withinDeadline must be implemented by the runtime'); +}; expect.assertions = assertions; expect.hasAssertions = hasAssertions; expect.getState = getState; diff --git a/packages/jest-circus/src/legacy-code-todo-rewrite/jestExpect.ts b/packages/jest-circus/src/legacy-code-todo-rewrite/jestExpect.ts index 52e9bd5ad8d2..d3c7a8b3410e 100644 --- a/packages/jest-circus/src/legacy-code-todo-rewrite/jestExpect.ts +++ b/packages/jest-circus/src/legacy-code-todo-rewrite/jestExpect.ts @@ -14,7 +14,7 @@ import { toThrowErrorMatchingInlineSnapshot, toThrowErrorMatchingSnapshot, } from 'jest-snapshot'; -import { deadline, withinDeadline } from '../deadlineTimeout'; +import {deadline, withinDeadline} from '../deadlineTimeout'; export type Expect = typeof expect; From 347f59888134ac37a5676a08248e2541499b77e4 Mon Sep 17 00:00:00 2001 From: "Chris West (Faux)" Date: Wed, 9 Dec 2020 10:07:30 +0000 Subject: [PATCH 14/15] feat: different message for negative times This shouldn't really ever be hit; at least, for healthy tests? It will probably never be seen by users, as it should be masked by the rest of the timeout mechanism. --- packages/jest-circus/src/deadlineTimeout.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/jest-circus/src/deadlineTimeout.ts b/packages/jest-circus/src/deadlineTimeout.ts index 6ee757bd0d11..357224b2b562 100644 --- a/packages/jest-circus/src/deadlineTimeout.ts +++ b/packages/jest-circus/src/deadlineTimeout.ts @@ -17,7 +17,11 @@ export function deadline(): number { } export async function withinDeadline(promise: Promise): Promise { - return timeout(promise, deadline() - Date.now()); + const ms = deadline() - Date.now(); + if (ms <= 0) { + throw removeUsFromStack(new Error('deadline already exceeded')); + } + return timeout(promise, ms); } function isUs(line: string): boolean { From 42cabaaa4f3d707b36c7cf34a78201fe6c69e7e5 Mon Sep 17 00:00:00 2001 From: "Chris West (Faux)" Date: Wed, 16 Dec 2020 06:33:33 +0000 Subject: [PATCH 15/15] chore: abuse inline snapshots for version switching --- .../babelPluginJestDeadlines.test.ts.snap | 36 ++-- e2e/__tests__/__snapshots__/deadlines.ts.snap | 81 --------- e2e/__tests__/deadlines.ts | 154 +++++++++++++++++- 3 files changed, 160 insertions(+), 111 deletions(-) diff --git a/e2e/__tests__/__snapshots__/babelPluginJestDeadlines.test.ts.snap b/e2e/__tests__/__snapshots__/babelPluginJestDeadlines.test.ts.snap index 25b6b72f0ae0..4bed4366c88e 100644 --- a/e2e/__tests__/__snapshots__/babelPluginJestDeadlines.test.ts.snap +++ b/e2e/__tests__/__snapshots__/babelPluginJestDeadlines.test.ts.snap @@ -3,22 +3,14 @@ exports[`passes generally 1`] = ` Object { "rest": "FAIL __tests__/plain.test.js - ✕ exceeded + ● Test suite failed to run - ● exceeded + Cannot find module 'babel-plugin-jest-deadlines' from '/home/faux/clone/jest/e2e/babel-plugin-jest-deadlines' - deadline exceeded (waited here for <>) - - 11 | test('exceeded', async () => { - 12 | await sleep(10); - > 13 | await sleep(200); - | ^ - 14 | }, 50); - 15 | - - at Object. (__tests__/plain.test.js:13:3)", + at Function.resolveSync [as sync] (../../node_modules/resolve/lib/sync.js:90:15) + at Array.map ()", "summary": "Test Suites: 1 failed, 1 total -Tests: 1 failed, 1 total +Tests: 0 total Snapshots: 0 total Time: <> Ran all test suites matching /plain.test.js/i.", @@ -28,22 +20,14 @@ Ran all test suites matching /plain.test.js/i.", exports[`throws on deadline exceeded 1`] = ` Object { "rest": "FAIL __tests__/typescript.test.ts - ✕ exceeded - - ● exceeded - - deadline exceeded (waited here for <>) + ● Test suite failed to run - 12 | test('exceeded', async () => { - 13 | await sleep(10); - > 14 | await sleep(200); - | ^ - 15 | }, 50); - 16 | + Cannot find module 'babel-plugin-jest-deadlines' from '/home/faux/clone/jest/e2e/babel-plugin-jest-deadlines' - at Object. (__tests__/typescript.test.ts:14:3)", + at Function.resolveSync [as sync] (../../node_modules/resolve/lib/sync.js:90:15) + at Array.map ()", "summary": "Test Suites: 1 failed, 1 total -Tests: 1 failed, 1 total +Tests: 0 total Snapshots: 0 total Time: <> Ran all test suites matching /typescript.test.ts/i.", diff --git a/e2e/__tests__/__snapshots__/deadlines.ts.snap b/e2e/__tests__/__snapshots__/deadlines.ts.snap index edf1ab508e33..984f5701ac7c 100644 --- a/e2e/__tests__/__snapshots__/deadlines.ts.snap +++ b/e2e/__tests__/__snapshots__/deadlines.ts.snap @@ -12,84 +12,3 @@ Time: <> Ran all test suites matching /manual-within.js/i.", } `; - -exports[`throws on deadline exceeded 1`] = ` -Object { - "rest": "FAIL __tests__/manual-exceeded.js - describe - ✕ it - - ● describe › it - - deadline exceeded (waited here for <>) - - 12 | describe('describe', () => { - 13 | it('it', async () => { - > 14 | await expect.withinDeadline(sleep(200)); - | ^ - 15 | }, 50); - 16 | }); - 17 | - - at Object. (__tests__/manual-exceeded.js:14:5)", - "summary": "Test Suites: 1 failed, 1 total -Tests: 1 failed, 1 total -Snapshots: 0 total -Time: <> -Ran all test suites matching /manual-exceeded.js/i.", -} -`; - -exports[`throws on deadline exceeded in a describe hook 1`] = ` -Object { - "rest": "FAIL __tests__/manual-exceeded-hook-describe.js - describe - ✕ does nothing - - ● describe › does nothing - - deadline exceeded (waited here for <>) - - 12 | describe('describe', () => { - 13 | beforeAll(async () => { - > 14 | await expect.withinDeadline(sleep(200)); - | ^ - 15 | }, 50); - 16 | - 17 | it('does nothing', () => {}); - - at __tests__/manual-exceeded-hook-describe.js:14:5", - "summary": "Test Suites: 1 failed, 1 total -Tests: 1 failed, 1 total -Snapshots: 0 total -Time: <> -Ran all test suites matching /manual-exceeded-hook-describe.js/i.", -} -`; - -exports[`throws on deadline exceeded in a hook 1`] = ` -Object { - "rest": "FAIL __tests__/manual-exceeded-hook.js - describe - ✕ does nothing - - ● describe › does nothing - - deadline exceeded (waited here for <>) - - 12 | describe('describe', () => { - 13 | beforeEach(async () => { - > 14 | await expect.withinDeadline(sleep(200)); - | ^ - 15 | }, 50); - 16 | - 17 | it('does nothing', () => {}); - - at Object. (__tests__/manual-exceeded-hook.js:14:5)", - "summary": "Test Suites: 1 failed, 1 total -Tests: 1 failed, 1 total -Snapshots: 0 total -Time: <> -Ran all test suites matching /manual-exceeded-hook.js/i.", -} -`; diff --git a/e2e/__tests__/deadlines.ts b/e2e/__tests__/deadlines.ts index c5f968ce5ea7..de2d6c1e97cf 100644 --- a/e2e/__tests__/deadlines.ts +++ b/e2e/__tests__/deadlines.ts @@ -4,34 +4,180 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ +import semver = require('semver'); import {skipSuiteOnJasmine} from '@jest/test-utils'; import {extractSummary} from '../Utils'; import runJest from '../runJest'; skipSuiteOnJasmine(); +function givenNode(versionRange: string, func: () => void): void { + if (semver.satisfies(process.versions.node, versionRange)) { + func(); + } +} + it('passes generally', () => { const result = runJest('deadlines', ['manual-within.js']); expect(result.exitCode).toBe(0); - expect(summaryWithoutTime(result)).toMatchSnapshot(); + const summary = summaryWithoutTime(result); + expect(summary).toMatchSnapshot(); }); it('throws on deadline exceeded', () => { const result = runJest('deadlines', ['manual-exceeded.js']); expect(result.exitCode).toBe(1); - expect(summaryWithoutTime(result)).toMatchSnapshot(); + const summary = summaryWithoutTime(result); + givenNode('>=12', () => + expect(summary).toMatchInlineSnapshot(` +Object { + "rest": "FAIL __tests__/manual-exceeded.js + describe + ✕ it + + ● describe › it + + deadline exceeded (waited here for <>) + + 12 | describe('describe', () => { + 13 | it('it', async () => { + > 14 | await expect.withinDeadline(sleep(200)); + | ^ + 15 | }, 50); + 16 | }); + 17 | + + at Object. (__tests__/manual-exceeded.js:14:5)", + "summary": "Test Suites: 1 failed, 1 total +Tests: 1 failed, 1 total +Snapshots: 0 total +Time: <> +Ran all test suites matching /manual-exceeded.js/i.", +} +`), + ); + givenNode('<12', () => + expect(summary).toMatchInlineSnapshot(` + Object { + "rest": "FAIL __tests__/manual-exceeded.js + describe + ✕ it + + ● describe › it + + deadline exceeded (waited here for <>)", + "summary": "Test Suites: 1 failed, 1 total + Tests: 1 failed, 1 total + Snapshots: 0 total + Time: <> + Ran all test suites matching /manual-exceeded.js/i.", + } + `), + ); }); it('throws on deadline exceeded in a hook', () => { const result = runJest('deadlines', ['manual-exceeded-hook.js']); expect(result.exitCode).toBe(1); - expect(summaryWithoutTime(result)).toMatchSnapshot(); + const summary = summaryWithoutTime(result); + givenNode('>=12', () => + expect(summary).toMatchInlineSnapshot(` +Object { + "rest": "FAIL __tests__/manual-exceeded-hook.js + describe + ✕ does nothing + + ● describe › does nothing + + deadline exceeded (waited here for <>) + + 12 | describe('describe', () => { + 13 | beforeEach(async () => { + > 14 | await expect.withinDeadline(sleep(200)); + | ^ + 15 | }, 50); + 16 | + 17 | it('does nothing', () => {}); + + at Object. (__tests__/manual-exceeded-hook.js:14:5)", + "summary": "Test Suites: 1 failed, 1 total +Tests: 1 failed, 1 total +Snapshots: 0 total +Time: <> +Ran all test suites matching /manual-exceeded-hook.js/i.", +} +`), + ); + givenNode('<12', () => + expect(summary).toMatchInlineSnapshot(` + Object { + "rest": "FAIL __tests__/manual-exceeded-hook.js + describe + ✕ does nothing + + ● describe › does nothing + + deadline exceeded (waited here for <>)", + "summary": "Test Suites: 1 failed, 1 total + Tests: 1 failed, 1 total + Snapshots: 0 total + Time: <> + Ran all test suites matching /manual-exceeded-hook.js/i.", + } + `), + ); }); it('throws on deadline exceeded in a describe hook', () => { const result = runJest('deadlines', ['manual-exceeded-hook-describe.js']); expect(result.exitCode).toBe(1); - expect(summaryWithoutTime(result)).toMatchSnapshot(); + const summary = summaryWithoutTime(result); + givenNode('>=12', () => + expect(summary).toMatchInlineSnapshot(` +Object { + "rest": "FAIL __tests__/manual-exceeded-hook-describe.js + describe + ✕ does nothing + + ● describe › does nothing + + deadline exceeded (waited here for <>) + + 12 | describe('describe', () => { + 13 | beforeAll(async () => { + > 14 | await expect.withinDeadline(sleep(200)); + | ^ + 15 | }, 50); + 16 | + 17 | it('does nothing', () => {}); + + at __tests__/manual-exceeded-hook-describe.js:14:5", + "summary": "Test Suites: 1 failed, 1 total +Tests: 1 failed, 1 total +Snapshots: 0 total +Time: <> +Ran all test suites matching /manual-exceeded-hook-describe.js/i.", +} +`), + ); + givenNode('<12', () => + expect(summary).toMatchInlineSnapshot(` + Object { + "rest": "FAIL __tests__/manual-exceeded-hook-describe.js + describe + ✕ does nothing + + ● describe › does nothing + + deadline exceeded (waited here for <>)", + "summary": "Test Suites: 1 failed, 1 total + Tests: 1 failed, 1 total + Snapshots: 0 total + Time: <> + Ran all test suites matching /manual-exceeded-hook-describe.js/i.", + } + `), + ); }); function summaryWithoutTime(result: {stderr: string}) {