From 0c09a40d2b71ebfdde65c5bb6f7a8ab8f0301692 Mon Sep 17 00:00:00 2001 From: Vladimir Date: Thu, 27 Apr 2023 15:04:05 +0200 Subject: [PATCH] feat!: update mock implementation to support ESM runtime, introduce "vi.hoisted" (#3258) --- docs/api/expect.md | 14 +- docs/api/vi.md | 71 +- docs/config/index.md | 17 +- examples/mocks/test/hoisted.test.ts | 26 + examples/mocks/tsconfig.json | 3 + .../vue/test/__snapshots__/basic.test.ts.snap | 2 +- packages/browser/package.json | 6 +- packages/browser/src/client/index.html | 49 + packages/browser/src/client/main.ts | 6 +- packages/browser/src/client/mocker.ts | 25 + packages/browser/src/client/utils.ts | 3 +- packages/browser/src/node/esmInjector.ts | 276 ++++++ packages/browser/src/node/esmWalker.ts | 301 ++++++ packages/browser/src/node/index.ts | 16 +- packages/utils/src/descriptors.ts | 10 +- packages/vitest/package.json | 1 + .../vitest/src/integrations/browser/server.ts | 7 +- packages/vitest/src/integrations/vi.ts | 13 +- packages/vitest/src/node/config.ts | 1 + packages/vitest/src/node/core.ts | 6 +- packages/vitest/src/node/hoistMocks.ts | 184 ++++ packages/vitest/src/node/mock.ts | 235 ----- packages/vitest/src/node/plugins/index.ts | 2 + packages/vitest/src/node/plugins/mocks.ts | 12 + packages/vitest/src/node/plugins/workspace.ts | 2 + packages/vitest/src/node/pool.ts | 4 +- packages/vitest/src/node/server.ts | 20 - packages/vitest/src/node/workspace.ts | 8 +- packages/vitest/src/runtime/entry.ts | 2 - packages/vitest/src/types/browser.ts | 9 + packages/vitest/src/types/config.ts | 7 +- pnpm-lock.yaml | 754 +++++++------- test/browser/specs/runner.test.mjs | 2 +- test/browser/src/actions.ts | 3 + test/browser/src/calculator.ts | 8 + test/browser/test/mocked.test.ts | 30 + test/core/package.json | 1 + test/core/test/injector-esm.test.ts | 927 ++++++++++++++++++ test/core/test/injector-mock.test.ts | 60 ++ 39 files changed, 2430 insertions(+), 693 deletions(-) create mode 100644 examples/mocks/test/hoisted.test.ts create mode 100644 packages/browser/src/client/mocker.ts create mode 100644 packages/browser/src/node/esmInjector.ts create mode 100644 packages/browser/src/node/esmWalker.ts create mode 100644 packages/vitest/src/node/hoistMocks.ts delete mode 100644 packages/vitest/src/node/mock.ts create mode 100644 packages/vitest/src/node/plugins/mocks.ts delete mode 100644 packages/vitest/src/node/server.ts create mode 100644 test/browser/src/actions.ts create mode 100644 test/browser/src/calculator.ts create mode 100644 test/browser/test/mocked.test.ts create mode 100644 test/core/test/injector-esm.test.ts create mode 100644 test/core/test/injector-mock.test.ts diff --git a/docs/api/expect.md b/docs/api/expect.md index a5068955ac61..68527034bed0 100644 --- a/docs/api/expect.md +++ b/docs/api/expect.md @@ -138,7 +138,7 @@ type Awaitable = T | PromiseLike ```ts import { Stocks } from './stocks.js' - + const stocks = new Stocks() stocks.sync('Bill') if (stocks.getInfo('Bill')) @@ -150,7 +150,7 @@ type Awaitable = T | PromiseLike ```ts import { expect, test } from 'vitest' import { Stocks } from './stocks.js' - + const stocks = new Stocks() test('if we know Bill stock, sell apples to him', () => { @@ -171,7 +171,7 @@ type Awaitable = T | PromiseLike ```ts import { Stocks } from './stocks.js' - + const stocks = new Stocks() stocks.sync('Bill') if (!stocks.stockFailed('Bill')) @@ -183,7 +183,7 @@ type Awaitable = T | PromiseLike ```ts import { expect, test } from 'vitest' import { Stocks } from './stocks.js' - + const stocks = new Stocks() test('if Bill stock hasn\'t failed, sell apples to him', () => { @@ -242,7 +242,7 @@ type Awaitable = T | PromiseLike ```ts import { expect, test } from 'vitest' - + const actual = 'stock' test('stock is type of string', () => { @@ -259,7 +259,7 @@ type Awaitable = T | PromiseLike ```ts import { expect, test } from 'vitest' import { Stocks } from './stocks.js' - + const stocks = new Stocks() test('stocks are instance of Stocks', () => { @@ -695,7 +695,7 @@ If the value in the error message is too truncated, you can increase [chaiConfig ## toMatchFileSnapshot - **Type:** `(filepath: string, message?: string) => Promise` -- **Version:** Vitest 0.30.0 +- **Version:** Since Vitest 0.30.0 Compare or update the snapshot with the content of a file explicitly specified (instead of the `.snap` file). diff --git a/docs/api/vi.md b/docs/api/vi.md index afa7976291a2..29ba59e3f578 100644 --- a/docs/api/vi.md +++ b/docs/api/vi.md @@ -114,11 +114,55 @@ import { vi } from 'vitest' When using `vi.useFakeTimers`, `Date.now` calls are mocked. If you need to get real time in milliseconds, you can call this function. +## vi.hoisted + +- **Type**: `(factory: () => T) => T` +- **Version**: Since Vitest 0.31.0 + + All static `import` statements in ES modules are hoisted to top of the file, so any code that is define before the imports will actually be executed after imports are evaluated. + + Hovewer it can be useful to invoke some side effect like mocking dates before importing a module. + + To bypass this limitation, you can rewrite static imports into dynamic ones like this: + + ```diff + callFunctionWithSideEffect() + - import { value } from './some/module.ts' + + const { value } = await import('./some/module.ts') + ``` + + When running `vitest`, you can do this automatically by using `vi.hoisted` method. + + ```diff + - callFunctionWithSideEffect() + import { value } from './some/module.ts' + + vi.hoisted(() => callFunctionWithSideEffect()) + ``` + + This method returns the value that was returned from the factory. You can use that value in your `vi.mock` factories if you need an easy access to locally defined variables: + + ```ts + import { expect, vi } from 'vitest' + import { originalMethod } from './path/to/module.js' + + const { mockedMethod } = vi.hoisted(() => { + return { mockedMethod: vi.fn() } + }) + + vi.mocked('./path/to/module.js', () => { + return { originalMethod: mockedMethod } + }) + + mockedMethod.mockReturnValue(100) + expect(originalMethod()).toBe(100) + ``` + + ## vi.mock - **Type**: `(path: string, factory?: () => unknown) => void` - Substitutes all imported modules from provided `path` with another module. You can use configured Vite aliases inside a path. The call to `vi.mock` is hoisted, so it doesn't matter where you call it. It will always be executed before all imports. + Substitutes all imported modules from provided `path` with another module. You can use configured Vite aliases inside a path. The call to `vi.mock` is hoisted, so it doesn't matter where you call it. It will always be executed before all imports. If you need to reference some variables outside of its scope, you can defined them inside [`vi.hoisted`](/api/vi#vi-hoisted) and reference inside `vi.mock`. ::: warning `vi.mock` works only for modules that were imported with the `import` keyword. It doesn't work with `require`. @@ -151,6 +195,29 @@ import { vi } from 'vitest' This also means that you cannot use any variables inside the factory that are defined outside the factory. If you need to use variables inside the factory, try [`vi.doMock`](#vi-domock). It works the same way but isn't hoisted. Beware that it only mocks subsequent imports. + + You can also reference variables defined by `vi.hoisted` method if it was declared before `vi.mock`: + + ```ts + import { namedExport } from './path/to/module.js' + + const mocks = vi.hoisted(() => { + return { + namedExport: vi.fn(), + } + }) + + vi.mock('./path/to/module.js', () => { + return { + namedExport: mocks.namedExport, + } + }) + + vi.mocked(namedExport).mockReturnValue(100) + + expect(namedExport()).toBe(100) + expect(namedExport).toBe(mocks.namedExport) + ``` ::: ::: warning @@ -199,7 +266,7 @@ import { vi } from 'vitest' ``` ::: warning - Beware that if you don't call `vi.mock`, modules **are not** mocked automatically. + Beware that if you don't call `vi.mock`, modules **are not** mocked automatically. To replicate Jest's automocking behaviour, you can call `vi.mock` for each required module inside [`setupFiles`](/config/#setupfiles). ::: If there is no `__mocks__` folder or a factory provided, Vitest will import the original module and auto-mock all its exports. For the rules applied, see [algorithm](/guide/mocking#automocking-algorithm). diff --git a/docs/config/index.md b/docs/config/index.md index 566e8ed3b951..595dfb9210ee 100644 --- a/docs/config/index.md +++ b/docs/config/index.md @@ -963,7 +963,7 @@ Listen to port and serve API. When set to true, the default port is 51204 ### browser -- **Type:** `{ enabled?, name?, provider?, headless?, api? }` +- **Type:** `{ enabled?, name?, provider?, headless?, api?, slowHijackESM? }` - **Default:** `{ enabled: false, headless: process.env.CI, api: 63315 }` - **Version:** Since Vitest 0.29.4 - **CLI:** `--browser`, `--browser=`, `--browser.name=chrome --browser.headless` @@ -1035,6 +1035,19 @@ export interface BrowserProvider { This is an advanced API for library authors. If you just need to run tests in a browser, use the [browser](/config/#browser) option. ::: +#### browser.slowHijackESM + +- **Type:** `boolean` +- **Default:** `true` +- **Version:** Since Vitest 0.31.0 + +When running tests in Node.js Vitest can use its own module resolution to easily mock modules with `vi.mock` syntax. However it's not so easy to replicate ES module resolution in browser, so we need to transform your source files before browser can consume it. + +This option has no effect on tests running inside Node.js. + +This options is enabled by default when running in the browser. If you don't rely on spying on ES modules with `vi.spyOn` and don't use `vi.mock`, you can disable this to get a slight boost to performance. + + ### clearMocks - **Type:** `boolean` @@ -1358,7 +1371,7 @@ The number of milliseconds after which a test is considered slow and reported as - **Type:** `{ includeStack?, showDiff?, truncateThreshold? }` - **Default:** `{ includeStack: false, showDiff: true, truncateThreshold: 40 }` -- **Version:** Vitest 0.30.0 +- **Version:** Since Vitest 0.30.0 Equivalent to [Chai config](https://github.com/chaijs/chai/blob/4.x.x/lib/chai/config.js). diff --git a/examples/mocks/test/hoisted.test.ts b/examples/mocks/test/hoisted.test.ts new file mode 100644 index 000000000000..1866ea4a9c5e --- /dev/null +++ b/examples/mocks/test/hoisted.test.ts @@ -0,0 +1,26 @@ +import { expect, test, vi } from 'vitest' +import { asyncSquare as importedAsyncSquare, square as importedSquare } from '../src/example' + +const mocks = vi.hoisted(() => { + return { + square: vi.fn(), + } +}) + +const { asyncSquare } = await vi.hoisted(async () => { + return { + asyncSquare: vi.fn(), + } +}) + +vi.mock('../src/example.ts', () => { + return { + square: mocks.square, + asyncSquare, + } +}) + +test('hoisted works', () => { + expect(importedSquare).toBe(mocks.square) + expect(importedAsyncSquare).toBe(asyncSquare) +}) diff --git a/examples/mocks/tsconfig.json b/examples/mocks/tsconfig.json index aa0a8c03107c..784f2ef7fbfc 100644 --- a/examples/mocks/tsconfig.json +++ b/examples/mocks/tsconfig.json @@ -1,5 +1,8 @@ { "compilerOptions": { + "module": "esnext", + "target": "esnext", + "moduleResolution": "nodenext", "types": ["vitest/globals"] } } diff --git a/examples/vue/test/__snapshots__/basic.test.ts.snap b/examples/vue/test/__snapshots__/basic.test.ts.snap index 45642c5659b1..522e894f6726 100644 --- a/examples/vue/test/__snapshots__/basic.test.ts.snap +++ b/examples/vue/test/__snapshots__/basic.test.ts.snap @@ -1,4 +1,4 @@ -// Vitest Snapshot v1 +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`mount component 1`] = ` "
4 x 2 = 8
diff --git a/packages/browser/package.json b/packages/browser/package.json index 77b8fd38d8ae..7d97e046818f 100644 --- a/packages/browser/package.json +++ b/packages/browser/package.json @@ -39,17 +39,21 @@ "prepublishOnly": "pnpm build" }, "peerDependencies": { - "vitest": ">=0.29.4" + "vitest": ">=0.31.0" }, "dependencies": { "modern-node-polyfills": "^0.1.1", "sirv": "^2.0.2" }, "devDependencies": { + "@types/estree": "^1.0.1", "@types/ws": "^8.5.4", "@vitest/runner": "workspace:*", "@vitest/ui": "workspace:*", "@vitest/ws-client": "workspace:*", + "estree-walker": "^3.0.3", + "periscopic": "^3.1.0", + "rollup": "3.20.2", "vitest": "workspace:*" } } diff --git a/packages/browser/src/client/index.html b/packages/browser/src/client/index.html index 284367484299..8d319d9444e8 100644 --- a/packages/browser/src/client/index.html +++ b/packages/browser/src/client/index.html @@ -24,6 +24,55 @@ + diff --git a/packages/browser/src/client/main.ts b/packages/browser/src/client/main.ts index 8e6deddc9b7b..1a0f434ab187 100644 --- a/packages/browser/src/client/main.ts +++ b/packages/browser/src/client/main.ts @@ -8,6 +8,7 @@ import { setupConsoleLogSpy } from './logger' import { createSafeRpc, rpc, rpcDone } from './rpc' import { setupDialogsSpy } from './dialog' import { BrowserSnapshotEnvironment } from './snapshot' +import { VitestBrowserClientMocker } from './mocker' // @ts-expect-error mocking some node apis globalThis.process = { env: {}, argv: [], cwd: () => '/', stdout: { write: () => {} }, nextTick: cb => cb() } @@ -72,7 +73,8 @@ ws.addEventListener('open', async () => { globalThis.__vitest_worker__ = { config, browserHashMap, - moduleCache: new Map(), + // @ts-expect-error untyped global for internal use + moduleCache: globalThis.__vi_module_cache__, rpc: client.rpc, safeRpc, durations: { @@ -80,6 +82,8 @@ ws.addEventListener('open', async () => { prepare: 0, }, } + // @ts-expect-error mocking vitest apis + globalThis.__vitest_mocker__ = new VitestBrowserClientMocker() const paths = getQueryPaths() diff --git a/packages/browser/src/client/mocker.ts b/packages/browser/src/client/mocker.ts new file mode 100644 index 000000000000..f076413d52e9 --- /dev/null +++ b/packages/browser/src/client/mocker.ts @@ -0,0 +1,25 @@ +function throwNotImplemented(name: string) { + throw new Error(`[vitest] ${name} is not implemented in browser environment yet.`) +} + +export class VitestBrowserClientMocker { + public importActual() { + throwNotImplemented('importActual') + } + + public importMock() { + throwNotImplemented('importMock') + } + + public queueMock() { + throwNotImplemented('queueMock') + } + + public queueUnmock() { + throwNotImplemented('queueUnmock') + } + + public prepare() { + // TODO: prepare + } +} diff --git a/packages/browser/src/client/utils.ts b/packages/browser/src/client/utils.ts index 91dba6260a96..9c751c2be0ea 100644 --- a/packages/browser/src/client/utils.ts +++ b/packages/browser/src/client/utils.ts @@ -1,4 +1,5 @@ export function importId(id: string) { const name = `/@id/${id}` - return import(name) + // @ts-expect-error mocking vitest apis + return __vi_wrap_module__(import(name)) } diff --git a/packages/browser/src/node/esmInjector.ts b/packages/browser/src/node/esmInjector.ts new file mode 100644 index 000000000000..4aa977c089a7 --- /dev/null +++ b/packages/browser/src/node/esmInjector.ts @@ -0,0 +1,276 @@ +import MagicString from 'magic-string' +import { extract_names as extractNames } from 'periscopic' +import type { Expression, ImportDeclaration } from 'estree' +import type { AcornNode } from 'rollup' +import type { Node, Positioned } from './esmWalker' +import { esmWalker, isInDestructuringAssignment, isNodeInPattern, isStaticProperty } from './esmWalker' + +const viInjectedKey = '__vi_inject__' +// const viImportMetaKey = '__vi_import_meta__' // to allow overwrite +const viExportAllHelper = '__vi_export_all__' + +const skipHijack = [ + '/@vite/client', + '/@vite/env', + /vite\/dist\/client/, +] + +interface Options { + cacheDir: string +} + +// this is basically copypaste from Vite SSR +// this method transforms all import and export statements into `__vi_injected__` variable +// to allow spying on them. this can be disabled by setting `slowHijackESM` to `false` +export function injectVitestModule(code: string, id: string, parse: (code: string, options: any) => AcornNode, options: Options) { + if (skipHijack.some(skip => id.match(skip))) + return + + const s = new MagicString(code) + + let ast: any + try { + ast = parse(code, { + sourceType: 'module', + ecmaVersion: 'latest', + locations: true, + }) + } + catch (err) { + console.error(`Cannot parse ${id}:\n${(err as any).message}`) + return + } + + let uid = 0 + const idToImportMap = new Map() + const declaredConst = new Set() + + const hoistIndex = 0 + + let hasInjected = false + + // this will tranfrom import statements into dynamic ones, if there are imports + // it will keep the import as is, if we don't need to mock anything + // in browser environment it will wrap the module value with "vitest_wrap_module" function + // that returns a proxy to the module so that named exports can be mocked + const transformImportDeclaration = (node: ImportDeclaration) => { + const source = node.source.value as string + + if (skipHijack.some(skip => source.match(skip))) + return null + + const importId = `__vi_esm_${uid++}__` + const hasSpecifiers = node.specifiers.length > 0 + const code = hasSpecifiers + ? `import { ${viInjectedKey} as ${importId} } from '${source}'\n` + : `import '${source}'\n` + return { + code, + id: importId, + } + } + + function defineImport(node: ImportDeclaration) { + const declaration = transformImportDeclaration(node) + if (!declaration) + return null + s.appendLeft(hoistIndex, declaration.code) + return declaration.id + } + + function defineImportAll(source: string) { + const importId = `__vi_esm_${uid++}__` + s.appendLeft(hoistIndex, `const { ${viInjectedKey}: ${importId} } = await import(${JSON.stringify(source)});\n`) + return importId + } + + function defineExport(position: number, name: string, local = name) { + hasInjected = true + s.appendLeft( + position, + `\nObject.defineProperty(${viInjectedKey}, "${name}", ` + + `{ enumerable: true, configurable: true, get(){ return ${local} }});`, + ) + } + + // 1. check all import statements and record id -> importName map + for (const node of ast.body as Node[]) { + // import foo from 'foo' --> foo -> __import_foo__.default + // import { baz } from 'foo' --> baz -> __import_foo__.baz + // import * as ok from 'foo' --> ok -> __import_foo__ + if (node.type === 'ImportDeclaration') { + const importId = defineImport(node) + if (!importId) + continue + s.remove(node.start, node.end) + for (const spec of node.specifiers) { + if (spec.type === 'ImportSpecifier') { + idToImportMap.set( + spec.local.name, + `${importId}.${spec.imported.name}`, + ) + } + else if (spec.type === 'ImportDefaultSpecifier') { + idToImportMap.set(spec.local.name, `${importId}.default`) + } + else { + // namespace specifier + idToImportMap.set(spec.local.name, importId) + } + } + } + } + + // 2. check all export statements and define exports + for (const node of ast.body as Node[]) { + // named exports + if (node.type === 'ExportNamedDeclaration') { + if (node.declaration) { + if ( + node.declaration.type === 'FunctionDeclaration' + || node.declaration.type === 'ClassDeclaration' + ) { + // export function foo() {} + defineExport(node.end, node.declaration.id!.name) + } + else { + // export const foo = 1, bar = 2 + for (const declaration of node.declaration.declarations) { + const names = extractNames(declaration.id as any) + for (const name of names) + defineExport(node.end, name) + } + } + s.remove(node.start, (node.declaration as Node).start) + } + else { + s.remove(node.start, node.end) + if (node.source) { + // export { foo, bar } from './foo' + const importId = defineImportAll(node.source.value as string) + // hoist re-exports near the defined import so they are immediately exported + for (const spec of node.specifiers) { + defineExport( + hoistIndex, + spec.exported.name, + `${importId}.${spec.local.name}`, + ) + } + } + else { + // export { foo, bar } + for (const spec of node.specifiers) { + const local = spec.local.name + const binding = idToImportMap.get(local) + defineExport(node.end, spec.exported.name, binding || local) + } + } + } + } + + // default export + if (node.type === 'ExportDefaultDeclaration') { + const expressionTypes = ['FunctionExpression', 'ClassExpression'] + if ( + 'id' in node.declaration + && node.declaration.id + && !expressionTypes.includes(node.declaration.type) + ) { + // named hoistable/class exports + // export default function foo() {} + // export default class A {} + hasInjected = true + const { name } = node.declaration.id + s.remove(node.start, node.start + 15 /* 'export default '.length */) + s.append( + `\nObject.defineProperty(${viInjectedKey}, "default", ` + + `{ enumerable: true, configurable: true, value: ${name} });`, + ) + } + else { + // anonymous default exports + hasInjected = true + s.update( + node.start, + node.start + 14 /* 'export default'.length */, + `${viInjectedKey}.default =`, + ) + if (id.startsWith(options.cacheDir)) { + // keep export default for optimized dependencies + s.append(`\nexport default { ${viInjectedKey}: ${viInjectedKey}.default };\n`) + } + } + } + + // export * from './foo' + if (node.type === 'ExportAllDeclaration') { + s.remove(node.start, node.end) + const importId = defineImportAll(node.source.value as string) + // hoist re-exports near the defined import so they are immediately exported + if (node.exported) { + defineExport(hoistIndex, node.exported.name, `${importId}`) + } + else { + hasInjected = true + s.appendLeft(hoistIndex, `${viExportAllHelper}(${viInjectedKey}, ${importId});\n`) + } + } + } + + // 3. convert references to import bindings & import.meta references + esmWalker(ast, { + onIdentifier(id, parent, parentStack) { + const grandparent = parentStack[1] + const binding = idToImportMap.get(id.name) + if (!binding) + return + + if (isStaticProperty(parent) && parent.shorthand) { + // let binding used in a property shorthand + // { foo } -> { foo: __import_x__.foo } + // skip for destructuring patterns + if ( + !isNodeInPattern(parent) + || isInDestructuringAssignment(parent, parentStack) + ) + s.appendLeft(id.end, `: ${binding}`) + } + else if ( + (parent.type === 'PropertyDefinition' + && grandparent?.type === 'ClassBody') + || (parent.type === 'ClassDeclaration' && id === parent.superClass) + ) { + if (!declaredConst.has(id.name)) { + declaredConst.add(id.name) + // locate the top-most node containing the class declaration + const topNode = parentStack[parentStack.length - 2] + s.prependRight(topNode.start, `const ${id.name} = ${binding};\n`) + } + } + else { + s.update(id.start, id.end, binding) + } + }, + // TODO: make env updatable + onImportMeta() { + // s.update(node.start, node.end, viImportMetaKey) + }, + onDynamicImport(node) { + const replace = '__vi_wrap_module__(import(' + s.overwrite(node.start, (node.source as Positioned).start, replace) + s.overwrite(node.end - 1, node.end, '))') + }, + }) + + if (hasInjected) { + // make sure "__vi_injected__" is declared as soon as possible + s.prepend(`const ${viInjectedKey} = { [Symbol.toStringTag]: "Module" };\n`) + s.append(`\nexport { ${viInjectedKey} }`) + } + + return { + ast, + code: s.toString(), + map: s.generateMap({ hires: true, source: id }), + } +} diff --git a/packages/browser/src/node/esmWalker.ts b/packages/browser/src/node/esmWalker.ts new file mode 100644 index 000000000000..01e54ad1eea5 --- /dev/null +++ b/packages/browser/src/node/esmWalker.ts @@ -0,0 +1,301 @@ +import type { + Function as FunctionNode, + Identifier, + ImportExpression, + Pattern, + Property, + VariableDeclaration, + Node as _Node, +} from 'estree' +import { walk as eswalk } from 'estree-walker' + +export type Positioned = T & { + start: number + end: number +} + +export type Node = Positioned<_Node> + +interface Visitors { + onIdentifier: ( + node: Positioned, + parent: Node, + parentStack: Node[], + ) => void + onImportMeta: (node: Node) => void + onDynamicImport: (node: Positioned) => void +} + +const isNodeInPatternWeakSet = new WeakSet<_Node>() +export function setIsNodeInPattern(node: Property) { + return isNodeInPatternWeakSet.add(node) +} +export function isNodeInPattern(node: _Node): node is Property { + return isNodeInPatternWeakSet.has(node) +} + +/** + * Same logic from \@vue/compiler-core & \@vue/compiler-sfc + * Except this is using acorn AST + */ +export function esmWalker( + root: Node, + { onIdentifier, onImportMeta, onDynamicImport }: Visitors, +) { + const parentStack: Node[] = [] + const varKindStack: VariableDeclaration['kind'][] = [] + const scopeMap = new WeakMap<_Node, Set>() + const identifiers: [id: any, stack: Node[]][] = [] + + const setScope = (node: _Node, name: string) => { + let scopeIds = scopeMap.get(node) + if (scopeIds && scopeIds.has(name)) + return + + if (!scopeIds) { + scopeIds = new Set() + scopeMap.set(node, scopeIds) + } + scopeIds.add(name) + } + + function isInScope(name: string, parents: Node[]) { + return parents.some(node => node && scopeMap.get(node)?.has(name)) + } + function handlePattern(p: Pattern, parentScope: _Node) { + if (p.type === 'Identifier') { + setScope(parentScope, p.name) + } + else if (p.type === 'RestElement') { + handlePattern(p.argument, parentScope) + } + else if (p.type === 'ObjectPattern') { + p.properties.forEach((property) => { + if (property.type === 'RestElement') + setScope(parentScope, (property.argument as Identifier).name) + + else + handlePattern(property.value, parentScope) + }) + } + else if (p.type === 'ArrayPattern') { + p.elements.forEach((element) => { + if (element) + handlePattern(element, parentScope) + }) + } + else if (p.type === 'AssignmentPattern') { + handlePattern(p.left, parentScope) + } + else { + setScope(parentScope, (p as any).name) + } + } + + (eswalk as any)(root, { + enter(node: Node, parent: Node | null) { + if (node.type === 'ImportDeclaration') + return this.skip() + + // track parent stack, skip for "else-if"/"else" branches as acorn nests + // the ast within "if" nodes instead of flattening them + if ( + parent + && !(parent.type === 'IfStatement' && node === parent.alternate) + ) + parentStack.unshift(parent) + + // track variable declaration kind stack used by VariableDeclarator + if (node.type === 'VariableDeclaration') + varKindStack.unshift(node.kind) + + if (node.type === 'MetaProperty' && node.meta.name === 'import') + onImportMeta(node) + + else if (node.type === 'ImportExpression') + onDynamicImport(node) + + if (node.type === 'Identifier') { + if ( + !isInScope(node.name, parentStack) + && isRefIdentifier(node, parent!, parentStack) + ) { + // record the identifier, for DFS -> BFS + identifiers.push([node, parentStack.slice(0)]) + } + } + else if (isFunctionNode(node)) { + // If it is a function declaration, it could be shadowing an import + // Add its name to the scope so it won't get replaced + if (node.type === 'FunctionDeclaration') { + const parentScope = findParentScope(parentStack) + if (parentScope) + setScope(parentScope, node.id!.name) + } + // walk function expressions and add its arguments to known identifiers + // so that we don't prefix them + node.params.forEach((p) => { + if (p.type === 'ObjectPattern' || p.type === 'ArrayPattern') { + handlePattern(p, node) + return + } + (eswalk as any)(p.type === 'AssignmentPattern' ? p.left : p, { + enter(child: Node, parent: Node) { + // skip params default value of destructure + if ( + parent?.type === 'AssignmentPattern' + && parent?.right === child + ) + return this.skip() + + if (child.type !== 'Identifier') + return + // do not record as scope variable if is a destructuring keyword + if (isStaticPropertyKey(child, parent)) + return + // do not record if this is a default value + // assignment of a destructuring variable + if ( + (parent?.type === 'TemplateLiteral' + && parent?.expressions.includes(child)) + || (parent?.type === 'CallExpression' && parent?.callee === child) + ) + return + + setScope(node, child.name) + }, + }) + }) + } + else if (node.type === 'Property' && parent!.type === 'ObjectPattern') { + // mark property in destructuring pattern + setIsNodeInPattern(node) + } + else if (node.type === 'VariableDeclarator') { + const parentFunction = findParentScope( + parentStack, + varKindStack[0] === 'var', + ) + if (parentFunction) + handlePattern(node.id, parentFunction) + } + else if (node.type === 'CatchClause' && node.param) { + handlePattern(node.param, node) + } + }, + + leave(node: Node, parent: Node | null) { + // untrack parent stack from above + if ( + parent + && !(parent.type === 'IfStatement' && node === parent.alternate) + ) + parentStack.shift() + + if (node.type === 'VariableDeclaration') + varKindStack.shift() + }, + }) + + // emit the identifier events in BFS so the hoisted declarations + // can be captured correctly + identifiers.forEach(([node, stack]) => { + if (!isInScope(node.name, stack)) + onIdentifier(node, stack[0], stack) + }) +} + +function isRefIdentifier(id: Identifier, parent: _Node, parentStack: _Node[]) { + // declaration id + if ( + parent.type === 'CatchClause' + || ((parent.type === 'VariableDeclarator' + || parent.type === 'ClassDeclaration') + && parent.id === id) + ) + return false + + if (isFunctionNode(parent)) { + // function declaration/expression id + if ((parent as any).id === id) + return false + + // params list + if (parent.params.includes(id)) + return false + } + + // class method name + if (parent.type === 'MethodDefinition' && !parent.computed) + return false + + // property key + if (isStaticPropertyKey(id, parent)) + return false + + // object destructuring pattern + if (isNodeInPattern(parent) && parent.value === id) + return false + + // non-assignment array destructuring pattern + if ( + parent.type === 'ArrayPattern' + && !isInDestructuringAssignment(parent, parentStack) + ) + return false + + // member expression property + if ( + parent.type === 'MemberExpression' + && parent.property === id + && !parent.computed + ) + return false + + if (parent.type === 'ExportSpecifier') + return false + + // is a special keyword but parsed as identifier + if (id.name === 'arguments') + return false + + return true +} + +export function isStaticProperty(node: _Node): node is Property { + return node && node.type === 'Property' && !node.computed +} + +export function isStaticPropertyKey(node: _Node, parent: _Node) { + return isStaticProperty(parent) && parent.key === node +} + +const functionNodeTypeRE = /Function(?:Expression|Declaration)$|Method$/ +export function isFunctionNode(node: _Node): node is FunctionNode { + return functionNodeTypeRE.test(node.type) +} + +const blockNodeTypeRE = /^BlockStatement$|^For(?:In|Of)?Statement$/ +function isBlock(node: _Node) { + return blockNodeTypeRE.test(node.type) +} + +function findParentScope( + parentStack: _Node[], + isVar = false, +): _Node | undefined { + return parentStack.find(isVar ? isFunctionNode : isBlock) +} + +export function isInDestructuringAssignment( + parent: _Node, + parentStack: _Node[], +): boolean { + if ( + parent + && (parent.type === 'Property' || parent.type === 'ArrayPattern') + ) + return parentStack.some(i => i.type === 'AssignmentExpression') + + return false +} diff --git a/packages/browser/src/node/index.ts b/packages/browser/src/node/index.ts index d582f8908e0e..541b1758d67e 100644 --- a/packages/browser/src/node/index.ts +++ b/packages/browser/src/node/index.ts @@ -5,12 +5,14 @@ import { builtinModules } from 'node:module' import { polyfillPath } from 'modern-node-polyfills' import sirv from 'sirv' import type { Plugin } from 'vite' +import { injectVitestModule } from './esmInjector' const polyfills = [ 'util', ] -export default (base = '/'): Plugin[] => { +// don't expose type to not bundle it here +export default (project: any, base = '/'): Plugin[] => { const pkgRoot = resolve(fileURLToPath(import.meta.url), '../..') const distRoot = resolve(pkgRoot, 'dist') @@ -51,6 +53,18 @@ export default (base = '/'): Plugin[] => { return { id: await polyfillPath(id), moduleSideEffects: false } }, }, + { + name: 'vitest:browser:esm-injector', + enforce: 'post', + transform(source, id) { + const hijackESM = project.config.browser.slowHijackESM ?? false + if (!hijackESM) + return + return injectVitestModule(source, id, this.parse, { + cacheDir: project.server.config.cacheDir, + }) + }, + }, ] } diff --git a/packages/utils/src/descriptors.ts b/packages/utils/src/descriptors.ts index 2d961b60d07b..d20f5ea7093c 100644 --- a/packages/utils/src/descriptors.ts +++ b/packages/utils/src/descriptors.ts @@ -1,6 +1,10 @@ -import concordance from 'concordance' +import * as concordance from 'concordance' import { getColors } from './colors' +const concordanceModule = 'default' in concordance + ? concordance.default + : concordance as any + interface DisplayOptions { theme?: any maxDepth?: number @@ -89,6 +93,6 @@ export function getConcordanceTheme() { } } -export function diffDescriptors(actual: unknown, expected: unknown, options: DisplayOptions) { - return concordance.diff(expected, actual, options) +export function diffDescriptors(actual: unknown, expected: unknown, options: DisplayOptions): string { + return concordanceModule.diff(expected, actual, options) } diff --git a/packages/vitest/package.json b/packages/vitest/package.json index 8ebc85542dda..3ba792543692 100644 --- a/packages/vitest/package.json +++ b/packages/vitest/package.json @@ -167,6 +167,7 @@ "@jridgewell/trace-mapping": "^0.3.17", "@sinonjs/fake-timers": "^10.0.2", "@types/diff": "^5.0.3", + "@types/estree": "^1.0.1", "@types/istanbul-lib-coverage": "^2.0.4", "@types/istanbul-reports": "^3.0.1", "@types/jsdom": "^21.1.1", diff --git a/packages/vitest/src/integrations/browser/server.ts b/packages/vitest/src/integrations/browser/server.ts index ada77fb26364..7dd2ac36b431 100644 --- a/packages/vitest/src/integrations/browser/server.ts +++ b/packages/vitest/src/integrations/browser/server.ts @@ -7,6 +7,7 @@ import { ensurePackageInstalled } from '../../node/pkg' import { resolveApiServerConfig } from '../../node/config' import { CoverageTransform } from '../../node/plugins/coverageTransform' import type { WorkspaceProject } from '../../node/workspace' +import { MocksPlugin } from '../../node/plugins/mocks' export async function createBrowserServer(project: WorkspaceProject, options: UserConfig) { const root = project.config.root @@ -31,7 +32,7 @@ export async function createBrowserServer(project: WorkspaceProject, options: Us }, }, plugins: [ - (await import('@vitest/browser')).default('/'), + (await import('@vitest/browser')).default(project, '/'), CoverageTransform(project.ctx), { enforce: 'post', @@ -42,7 +43,8 @@ export async function createBrowserServer(project: WorkspaceProject, options: Us } config.server = server - config.server.fs = { strict: false } + config.server.fs ??= {} + config.server.fs.strict = false return { resolve: { @@ -51,6 +53,7 @@ export async function createBrowserServer(project: WorkspaceProject, options: Us } }, }, + MocksPlugin(), ], }) diff --git a/packages/vitest/src/integrations/vi.ts b/packages/vitest/src/integrations/vi.ts index bd4d9517cfc3..1fcc6f30d553 100644 --- a/packages/vitest/src/integrations/vi.ts +++ b/packages/vitest/src/integrations/vi.ts @@ -1,5 +1,5 @@ import type { FakeTimerInstallOpts } from '@sinonjs/fake-timers' -import { createSimpleStackTrace } from '@vitest/utils' +import { assertTypes, createSimpleStackTrace } from '@vitest/utils' import { parseSingleStack } from '../utils/source-map' import type { VitestMocker } from '../runtime/mocker' import type { ResolvedConfig, RuntimeConfig } from '../types' @@ -30,6 +30,12 @@ interface VitestUtils { spyOn: typeof spyOn fn: typeof fn + /** + * Run the factory before imports are evaluated. You can return a value from the factory + * to reuse it inside your `vi.mock` factory and tests. + */ + hoisted(factory: () => T): T + /** * Makes all `imports` to passed module to be mocked. * - If there is a factory, will return it's result. The call to `vi.mock` is hoisted to the top of the file, @@ -286,6 +292,11 @@ function createVitest(): VitestUtils { spyOn, fn, + hoisted(factory: () => T): T { + assertTypes(factory, '"vi.hoisted" factory', ['function']) + return factory() + }, + mock(path: string, factory?: MockFactoryWithHelper) { const importer = getImporter() _mocker.queueMock( diff --git a/packages/vitest/src/node/config.ts b/packages/vitest/src/node/config.ts index dedbf05be139..ae3cfe462329 100644 --- a/packages/vitest/src/node/config.ts +++ b/packages/vitest/src/node/config.ts @@ -272,6 +272,7 @@ export function resolveConfig( resolved.browser ??= {} as any resolved.browser.enabled ??= false resolved.browser.headless ??= isCI + resolved.browser.slowHijackESM ??= true resolved.browser.api = resolveApiServerConfig(resolved.browser) || { port: defaultBrowserPort, diff --git a/packages/vitest/src/node/core.ts b/packages/vitest/src/node/core.ts index 1b4b2a6e4120..0ec32306e3e4 100644 --- a/packages/vitest/src/node/core.ts +++ b/packages/vitest/src/node/core.ts @@ -9,6 +9,7 @@ import { normalizeRequestId } from 'vite-node/utils' import { ViteNodeRunner } from 'vite-node/client' import { SnapshotManager } from '@vitest/snapshot/manager' import type { CancelReason } from '@vitest/runner' +import { ViteNodeServer } from 'vite-node/server' import type { ArgumentsType, CoverageProvider, OnServerRestartHandler, Reporter, ResolvedConfig, UserConfig, UserWorkspaceConfig, VitestRunMode } from '../types' import { hasFailed, noop, slash, toArray } from '../utils' import { getCoverageProvider } from '../integrations/coverage' @@ -22,7 +23,6 @@ import { resolveConfig } from './config' import { Logger } from './logger' import { VitestCache } from './cache' import { WorkspaceProject, initializeProject } from './workspace' -import { VitestServer } from './server' const WATCHER_DEBOUNCE = 100 @@ -40,7 +40,7 @@ export class Vitest { logger: Logger pool: ProcessPool | undefined - vitenode: VitestServer = undefined! + vitenode: ViteNodeServer = undefined! invalidates: Set = new Set() changedTests: Set = new Set() @@ -89,7 +89,7 @@ export class Vitest { if (this.config.watch && this.mode !== 'typecheck') this.registerWatcher() - this.vitenode = new VitestServer(server, this.config) + this.vitenode = new ViteNodeServer(server, this.config) const node = this.vitenode this.runner = new ViteNodeRunner({ root: server.config.root, diff --git a/packages/vitest/src/node/hoistMocks.ts b/packages/vitest/src/node/hoistMocks.ts new file mode 100644 index 000000000000..a3d9a2aed391 --- /dev/null +++ b/packages/vitest/src/node/hoistMocks.ts @@ -0,0 +1,184 @@ +import MagicString from 'magic-string' +import type { CallExpression, Identifier, ImportDeclaration, VariableDeclaration, Node as _Node } from 'estree' +import { findNodeAround, simple as simpleWalk } from 'acorn-walk' +import type { AcornNode } from 'rollup' + +export type Positioned = T & { + start: number + end: number +} + +export type Node = Positioned<_Node> + +const API_NOT_FOUND_ERROR = `There are some problems in resolving the mocks API. +You may encounter this issue when importing the mocks API from another module other than 'vitest'. +To fix this issue you can either: +- import the mocks API directly from 'vitest' +- enable the 'globals' options` + +const API_NOT_FOUND_CHECK = '\nif (typeof globalThis.vi === "undefined" && typeof globalThis.vitest === "undefined") ' ++ `{ throw new Error(${JSON.stringify(API_NOT_FOUND_ERROR)}) }\n` + +function isIdentifier(node: any): node is Positioned { + return node.type === 'Identifier' +} + +function transformImportSpecifiers(node: ImportDeclaration) { + const specifiers = node.specifiers + + if (specifiers.length === 1 && specifiers[0].type === 'ImportNamespaceSpecifier') + return specifiers[0].local.name + + const dynamicImports = node.specifiers.map((specifier) => { + if (specifier.type === 'ImportDefaultSpecifier') + return `default: ${specifier.local.name}` + + if (specifier.type === 'ImportSpecifier') { + const local = specifier.local.name + const imported = specifier.imported.name + if (local === imported) + return local + return `${imported}: ${local}` + } + + return null + }).filter(Boolean).join(', ') + + if (!dynamicImports.length) + return '' + + return `{ ${dynamicImports} }` +} + +const regexpHoistable = /^[ \t]*\b(vi|vitest)\s*\.\s*(mock|unmock|hoisted)\(/m +const hashbangRE = /^#!.*\n/ + +export function hoistMocks(code: string, id: string, parse: (code: string, options: any) => AcornNode) { + const hasMocks = regexpHoistable.test(code) + + if (!hasMocks) + return + + const s = new MagicString(code) + + let ast: any + try { + ast = parse(code, { + sourceType: 'module', + ecmaVersion: 'latest', + locations: true, + }) + } + catch (err) { + console.error(`Cannot parse ${id}:\n${(err as any).message}`) + return + } + + const hoistIndex = code.match(hashbangRE)?.[0].length ?? 0 + + let hoistedCode = '' + let hoistedVitestImports = '' + + // this will tranfrom import statements into dynamic ones, if there are imports + // it will keep the import as is, if we don't need to mock anything + // in browser environment it will wrap the module value with "vitest_wrap_module" function + // that returns a proxy to the module so that named exports can be mocked + const transformImportDeclaration = (node: ImportDeclaration) => { + const source = node.source.value as string + + // if we don't hijack ESM and process this file, then we definetly have mocks, + // so we need to transform imports into dynamic ones, so "vi.mock" can be executed before + const specifiers = transformImportSpecifiers(node) + const code = specifiers + ? `const ${specifiers} = await import('${source}')\n` + : `await import('${source}')\n` + return code + } + + function hoistImport(node: Positioned) { + // always hoist vitest import to top of the file, so + // "vi" helpers can access it + s.remove(node.start, node.end) + + if (node.source.value === 'vitest') { + const code = `const ${transformImportSpecifiers(node)} = await import('vitest')\n` + hoistedVitestImports += code + return + } + const code = transformImportDeclaration(node) + s.appendLeft(hoistIndex, code) + } + + // 1. check all import statements and record id -> importName map + for (const node of ast.body as Node[]) { + // import foo from 'foo' --> foo -> __import_foo__.default + // import { baz } from 'foo' --> baz -> __import_foo__.baz + // import * as ok from 'foo' --> ok -> __import_foo__ + if (node.type === 'ImportDeclaration') + hoistImport(node) + } + + simpleWalk(ast, { + CallExpression(_node) { + const node = _node as any as Positioned + if ( + node.callee.type === 'MemberExpression' + && isIdentifier(node.callee.object) + && (node.callee.object.name === 'vi' || node.callee.object.name === 'vitest') + && isIdentifier(node.callee.property) + ) { + const methodName = node.callee.property.name + + if (methodName === 'mock' || methodName === 'unmock') { + hoistedCode += `${code.slice(node.start, node.end)}\n` + s.remove(node.start, node.end) + } + + if (methodName === 'hoisted') { + const declarationNode = findNodeAround(ast, node.start, 'VariableDeclaration')?.node as Positioned | undefined + const init = declarationNode?.declarations[0]?.init + const isViHoisted = (node: CallExpression) => { + return node.callee.type === 'MemberExpression' + && isIdentifier(node.callee.object) + && (node.callee.object.name === 'vi' || node.callee.object.name === 'vitest') + && isIdentifier(node.callee.property) + && node.callee.property.name === 'hoisted' + } + + const canMoveDeclaration = (init + && init.type === 'CallExpression' + && isViHoisted(init)) /* const v = vi.hoisted() */ + || (init + && init.type === 'AwaitExpression' + && init.argument.type === 'CallExpression' + && isViHoisted(init.argument)) /* const v = await vi.hoisted() */ + + if (canMoveDeclaration) { + // hoist "const variable = vi.hoisted(() => {})" + hoistedCode += `${code.slice(declarationNode.start, declarationNode.end)}\n` + s.remove(declarationNode.start, declarationNode.end) + } + else { + // hoist "vi.hoisted(() => {})" + hoistedCode += `${code.slice(node.start, node.end)}\n` + s.remove(node.start, node.end) + } + } + } + }, + }) + + if (hoistedCode || hoistedVitestImports) { + s.prepend( + hoistedVitestImports + + ((!hoistedVitestImports && hoistedCode) ? API_NOT_FOUND_CHECK : '') + + hoistedCode, + ) + } + + return { + ast, + code: s.toString(), + map: s.generateMap({ hires: true, source: id }), + } +} diff --git a/packages/vitest/src/node/mock.ts b/packages/vitest/src/node/mock.ts deleted file mode 100644 index 5de2338a28cd..000000000000 --- a/packages/vitest/src/node/mock.ts +++ /dev/null @@ -1,235 +0,0 @@ -import MagicString from 'magic-string' -import type { DecodedSourceMap, RawSourceMap } from '@ampproject/remapping' -import type { SourceMap } from 'rollup' -import type { TransformResult } from 'vite' -import remapping from '@ampproject/remapping' -import { getCallLastIndex } from '../utils' - -const hoistRegexp = /^[ \t]*\b(?:__vite_ssr_import_\d+__\.)?((?:vitest|vi)\s*.\s*(mock|unmock)\(["`'\s]+(.*[@\w_-]+)["`'\s]+)[),]{1};?/gm - -const API_NOT_FOUND_ERROR = `There are some problems in resolving the mocks API. -You may encounter this issue when importing the mocks API from another module other than 'vitest'. - -To fix this issue you can either: -- import the mocks API directly from 'vitest' -- enable the 'globals' options` - -export function hoistModuleMocks(mod: TransformResult, vitestPath: string): TransformResult { - if (!mod.code) - return mod - const m = hoistCodeMocks(mod.code) - - if (m) { - const vitestRegexp = new RegExp(`const __vite_ssr_import_\\d+__ = await __vite_ssr_import__\\("(?:\/@fs\/?)?(?:${vitestPath}|vitest)"\\);`, 'gm') - // hoist vitest imports in case it was used inside vi.mock factory #425 - const vitestImports = mod.code.matchAll(vitestRegexp) - let found = false - - for (const match of vitestImports) { - const indexStart = match.index! - const indexEnd = match[0].length + indexStart - m.remove(indexStart, indexEnd) - m.prepend(`${match[0]}\n`) - found = true - } - - // if no vitest import found, check if the mock API is reachable after the hoisting - if (!found) { - m.prepend('if (typeof globalThis.vi === "undefined" && typeof globalThis.vitest === "undefined") ' - + `{ throw new Error(${JSON.stringify(API_NOT_FOUND_ERROR)}) }\n`) - } - - return { - ...mod, - code: m.toString(), - map: mod.map - ? combineSourcemaps( - mod.map.file, - [ - { - ...m.generateMap({ hires: true }), - sourcesContent: mod.map.sourcesContent, - } as RawSourceMap, - mod.map as RawSourceMap, - ], - ) as SourceMap - : null, - } - } - - return mod -} - -function hoistCodeMocks(code: string) { - let m: MagicString | undefined - const mocks = code.matchAll(hoistRegexp) - - for (const mockResult of mocks) { - const lastIndex = getMockLastIndex(code.slice(mockResult.index!)) - - if (lastIndex === null) - continue - - const startIndex = mockResult.index! - - const { insideComment, insideString } = getIndexStatus(code, startIndex) - - if (insideComment || insideString) - continue - - const endIndex = startIndex + lastIndex - - m ??= new MagicString(code) - - m.prepend(`${m.slice(startIndex, endIndex)}\n`) - m.remove(startIndex, endIndex) - } - - return m -} - -function escapeToLinuxLikePath(path: string) { - if (/^[A-Z]:/.test(path)) - return path.replace(/^([A-Z]):\//, '/windows/$1/') - - if (/^\/[^/]/.test(path)) - return `/linux${path}` - - return path -} - -function unescapeToLinuxLikePath(path: string) { - if (path.startsWith('/linux/')) - return path.slice('/linux'.length) - - if (path.startsWith('/windows/')) - return path.replace(/^\/windows\/([A-Z])\//, '$1:/') - - return path -} - -// based on https://github.com/vitejs/vite/blob/6b40f03574cd71a17cbe564bc63adebb156ff06e/packages/vite/src/node/utils.ts#L727 -const nullSourceMap: RawSourceMap = { - names: [], - sources: [], - mappings: '', - version: 3, -} -export function combineSourcemaps( - filename: string, - sourcemapList: Array, - excludeContent = true, -): RawSourceMap { - if ( - sourcemapList.length === 0 - || sourcemapList.every(m => m.sources.length === 0) - ) - return { ...nullSourceMap } - - // hack for parse broken with normalized absolute paths on windows (C:/path/to/something). - // escape them to linux like paths - // also avoid mutation here to prevent breaking plugin's using cache to generate sourcemaps like vue (see #7442) - sourcemapList = sourcemapList.map((sourcemap) => { - const newSourcemaps = { ...sourcemap } - newSourcemaps.sources = sourcemap.sources.map(source => - source ? escapeToLinuxLikePath(source) : null, - ) - if (sourcemap.sourceRoot) - newSourcemaps.sourceRoot = escapeToLinuxLikePath(sourcemap.sourceRoot) - - return newSourcemaps - }) - const escapedFilename = escapeToLinuxLikePath(filename) - - // We don't declare type here so we can convert/fake/map as RawSourceMap - let map // : SourceMap - let mapIndex = 1 - const useArrayInterface - = sourcemapList.slice(0, -1).find(m => m.sources.length !== 1) === undefined - if (useArrayInterface) { - map = remapping(sourcemapList, () => null, excludeContent) - } - else { - map = remapping( - sourcemapList[0], - (sourcefile) => { - if (sourcefile === escapedFilename && sourcemapList[mapIndex]) - return sourcemapList[mapIndex++] - - else - return null - }, - excludeContent, - ) - } - if (!map.file) - delete map.file - - // unescape the previous hack - map.sources = map.sources.map(source => - source ? unescapeToLinuxLikePath(source) : source, - ) - map.file = filename - - return map as RawSourceMap -} - -function getMockLastIndex(code: string): number | null { - const index = getCallLastIndex(code) - if (index === null) - return null - return code[index + 1] === ';' ? index + 2 : index + 1 -} - -function getIndexStatus(code: string, from: number) { - let index = 0 - let commentStarted = false - let commentEnded = true - let multilineCommentStarted = false - let multilineCommentEnded = true - let inString: string | null = null - let beforeChar: string | null = null - - while (index <= from) { - const char = code[index] - const sub = code[index] + code[index + 1] - - if (!inString) { - if (sub === '/*') { - multilineCommentStarted = true - multilineCommentEnded = false - } - if (sub === '*/' && multilineCommentStarted) { - multilineCommentStarted = false - multilineCommentEnded = true - } - if (sub === '//') { - commentStarted = true - commentEnded = false - } - if ((char === '\n' || sub === '\r\n') && commentStarted) { - commentStarted = false - commentEnded = true - } - } - - if (!multilineCommentStarted && !commentStarted) { - const isCharString = char === '"' || char === '\'' || char === '`' - - if (isCharString && beforeChar !== '\\') { - if (inString === char) - inString = null - else if (!inString) - inString = char - } - } - - beforeChar = char - index++ - } - - return { - insideComment: !multilineCommentEnded || !commentEnded, - insideString: inString !== null, - } -} diff --git a/packages/vitest/src/node/plugins/index.ts b/packages/vitest/src/node/plugins/index.ts index 02655dc17a4c..effb776c795e 100644 --- a/packages/vitest/src/node/plugins/index.ts +++ b/packages/vitest/src/node/plugins/index.ts @@ -11,6 +11,7 @@ import { EnvReplacerPlugin } from './envReplacer' import { GlobalSetupPlugin } from './globalSetup' import { CSSEnablerPlugin } from './cssEnabler' import { CoverageTransform } from './coverageTransform' +import { MocksPlugin } from './mocks' export async function VitestPlugin(options: UserConfig = {}, ctx = new Vitest('test')): Promise { const userConfig = deepMerge({}, options) as UserConfig @@ -242,6 +243,7 @@ export async function VitestPlugin(options: UserConfig = {}, ctx = new Vitest('t options.ui ? await UIPlugin() : null, + MocksPlugin(), ] .filter(notNullish) } diff --git a/packages/vitest/src/node/plugins/mocks.ts b/packages/vitest/src/node/plugins/mocks.ts new file mode 100644 index 000000000000..9628fe908606 --- /dev/null +++ b/packages/vitest/src/node/plugins/mocks.ts @@ -0,0 +1,12 @@ +import type { Plugin } from 'vite' +import { hoistMocks } from '../hoistMocks' + +export function MocksPlugin(): Plugin { + return { + name: 'vite:mocks', + enforce: 'post', + transform(code, id) { + return hoistMocks(code, id, this.parse) + }, + } +} diff --git a/packages/vitest/src/node/plugins/workspace.ts b/packages/vitest/src/node/plugins/workspace.ts index 250d8040cc77..bef905d8a90c 100644 --- a/packages/vitest/src/node/plugins/workspace.ts +++ b/packages/vitest/src/node/plugins/workspace.ts @@ -9,6 +9,7 @@ import { CoverageTransform } from './coverageTransform' import { CSSEnablerPlugin } from './cssEnabler' import { EnvReplacerPlugin } from './envReplacer' import { GlobalSetupPlugin } from './globalSetup' +import { MocksPlugin } from './mocks' interface WorkspaceOptions extends UserWorkspaceConfig { root?: string @@ -138,5 +139,6 @@ export function WorkspaceVitestPlugin(project: WorkspaceProject, options: Worksp ...CSSEnablerPlugin(project), CoverageTransform(project.ctx), GlobalSetupPlugin(project, project.ctx.logger), + MocksPlugin(), ] } diff --git a/packages/vitest/src/node/pool.ts b/packages/vitest/src/node/pool.ts index 35854f4d9fe1..dcfa13a14bd6 100644 --- a/packages/vitest/src/node/pool.ts +++ b/packages/vitest/src/node/pool.ts @@ -42,8 +42,10 @@ export function createPool(ctx: Vitest): ProcessPool { function getPoolName([project, file]: WorkspaceSpec) { for (const [glob, pool] of project.config.poolMatchGlobs || []) { + if (pool === 'browser') + throw new Error('Since Vitest 0.31.0 "browser" pool is not supported in "poolMatchGlobs". You can create a workspace to run some of your tests in browser in parallel. Read more: https://vitest.dev/guide/workspace') if (mm.isMatch(file, glob, { cwd: project.config.root })) - return pool + return pool as VitestPool } return getDefaultPoolName(project) } diff --git a/packages/vitest/src/node/server.ts b/packages/vitest/src/node/server.ts deleted file mode 100644 index 6b8f0115546e..000000000000 --- a/packages/vitest/src/node/server.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { TransformResult } from 'vite' -import { ViteNodeServer } from 'vite-node/server' -import { hoistModuleMocks } from './mock' - -export class VitestServer extends ViteNodeServer { - private _vitestPath?: string - - private async getVitestPath() { - if (!this._vitestPath) { - const { id } = await this.resolveId('vitest') || { id: 'vitest' } - this._vitestPath = id - } - return this._vitestPath - } - - protected async processTransformResult(id: string, result: TransformResult): Promise { - const vitestId = await this.getVitestPath() - return super.processTransformResult(id, hoistModuleMocks(result, vitestId)) - } -} diff --git a/packages/vitest/src/node/workspace.ts b/packages/vitest/src/node/workspace.ts index c875fe298e59..f373f7c1c50b 100644 --- a/packages/vitest/src/node/workspace.ts +++ b/packages/vitest/src/node/workspace.ts @@ -5,6 +5,7 @@ import { dirname, relative, resolve, toNamespacedPath } from 'pathe' import { createServer } from 'vite' import type { ViteDevServer, InlineConfig as ViteInlineConfig } from 'vite' import { ViteNodeRunner } from 'vite-node/client' +import { ViteNodeServer } from 'vite-node/server' import { createBrowserServer } from '../integrations/browser/server' import type { ArgumentsType, Reporter, ResolvedConfig, UserConfig, UserWorkspaceConfig, Vitest } from '../types' import { deepMerge, hasFailed } from '../utils' @@ -13,10 +14,9 @@ import type { BrowserProvider } from '../types/browser' import { getBrowserProvider } from '../integrations/browser' import { isBrowserEnabled, resolveConfig } from './config' import { WorkspaceVitestPlugin } from './plugins/workspace' -import { VitestServer } from './server' interface InitializeServerOptions { - server?: VitestServer + server?: ViteNodeServer runner?: ViteNodeRunner } @@ -65,7 +65,7 @@ export class WorkspaceProject { config!: ResolvedConfig server!: ViteDevServer - vitenode!: VitestServer + vitenode!: ViteNodeServer runner!: ViteNodeRunner browser: ViteDevServer = undefined! typechecker?: Typechecker @@ -170,7 +170,7 @@ export class WorkspaceProject { this.config = resolveConfig(this.ctx.mode, options, server.config) this.server = server - this.vitenode = params.server ?? new VitestServer(server, this.config) + this.vitenode = params.server ?? new ViteNodeServer(server, this.config) const node = this.vitenode this.runner = params.runner ?? new ViteNodeRunner({ root: server.config.root, diff --git a/packages/vitest/src/runtime/entry.ts b/packages/vitest/src/runtime/entry.ts index 2c16e82e58b1..45586375c4b1 100644 --- a/packages/vitest/src/runtime/entry.ts +++ b/packages/vitest/src/runtime/entry.ts @@ -124,8 +124,6 @@ export async function run(files: string[], config: ResolvedConfig, environment: await startTests([file], runner) - workerState.filepath = undefined - // reset after tests, because user might call `vi.setConfig` in setupFile vi.resetConfig() // mocks should not affect different files diff --git a/packages/vitest/src/types/browser.ts b/packages/vitest/src/types/browser.ts index 2f1ede9b2ec2..9bfd32e464f6 100644 --- a/packages/vitest/src/types/browser.ts +++ b/packages/vitest/src/types/browser.ts @@ -51,6 +51,15 @@ export interface BrowserConfigOptions { * The default port is 63315. */ api?: ApiConfig | number + + /** + * Update ESM imports so they can be spied/stubbed with vi.spyOn. + * Enabled by default when running in browser. + * + * @default true + * @experimental + */ + slowHijackESM?: boolean } export interface ResolvedBrowserOptions extends BrowserConfigOptions { diff --git a/packages/vitest/src/types/config.ts b/packages/vitest/src/types/config.ts index 858303728c59..54ec5e84e20f 100644 --- a/packages/vitest/src/types/config.ts +++ b/packages/vitest/src/types/config.ts @@ -188,6 +188,7 @@ export interface InlineConfig { /** * Automatically assign environment based on globs. The first match will be used. + * This has effect only when running tests inside Node.js. * * Format: [glob, environment-name] * @@ -209,13 +210,13 @@ export interface InlineConfig { * * @default [] * @example [ - * // all tests in "browser" directory will run in an actual browser - * ['tests/browser/**', 'browser'], + * // all tests in "child_process" directory will run using "child_process" API + * ['tests/child_process/**', 'child_process'], * // all other tests will run based on "threads" option, if you didn't specify other globs * // ... * ] */ - poolMatchGlobs?: [string, VitestPool][] + poolMatchGlobs?: [string, Omit][] /** * Update snapshot diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 40228d85cbf0..b34742300b45 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -146,7 +146,7 @@ importers: version: 0.0.5(vite-plugin-pwa@0.14.7) '@vitejs/plugin-vue': specifier: latest - version: 4.1.0(vite@4.2.1)(vue@3.2.47) + version: 4.2.1(vite@4.2.1)(vue@3.2.47) esno: specifier: ^0.16.3 version: 0.16.3 @@ -318,10 +318,10 @@ importers: version: 13.3.0(react-dom@18.0.0)(react@18.0.0) '@types/node': specifier: latest - version: 18.16.0 + version: 18.16.1 '@types/react': specifier: latest - version: 18.0.38 + version: 18.2.0 '@vitejs/plugin-react': specifier: latest version: 4.0.0(vite@4.2.1) @@ -388,7 +388,7 @@ importers: version: link:../../packages/ui happy-dom: specifier: latest - version: 9.1.7 + version: 9.1.9 jsdom: specifier: latest version: 21.1.1 @@ -678,7 +678,7 @@ importers: devDependencies: '@vitejs/plugin-vue': specifier: latest - version: 4.1.0(vite@4.2.1)(vue@3.2.47) + version: 4.2.1(vite@4.2.1)(vue@3.2.47) '@vue/test-utils': specifier: latest version: 2.3.2(vue@3.2.47) @@ -755,7 +755,7 @@ importers: devDependencies: '@vitejs/plugin-vue': specifier: latest - version: 4.1.0(vite@4.2.1)(vue@3.2.47) + version: 4.2.1(vite@4.2.1)(vue@3.2.47) '@vue/test-utils': specifier: ^2.0.2 version: 2.0.2(vue@3.2.47) @@ -764,10 +764,10 @@ importers: version: 21.1.1 unplugin-auto-import: specifier: latest - version: 0.7.2(esbuild@0.17.15)(rollup@3.20.2)(vite@4.2.1) + version: 0.12.1(rollup@3.20.2) unplugin-vue-components: specifier: latest - version: 0.19.6(esbuild@0.17.15)(rollup@3.20.2)(vite@4.2.1)(vue@3.2.47) + version: 0.22.12(rollup@3.20.2)(vue@3.2.47) vite: specifier: ^4.2.1 version: 4.2.1(@types/node@18.15.11) @@ -783,7 +783,7 @@ importers: devDependencies: '@vitejs/plugin-vue': specifier: latest - version: 4.1.0(vite@4.2.1)(vue@3.2.47) + version: 4.2.1(vite@4.2.1)(vue@3.2.47) '@vue/test-utils': specifier: ^2.0.0 version: 2.0.0(vue@3.2.47) @@ -801,7 +801,7 @@ importers: devDependencies: '@vitejs/plugin-vue': specifier: latest - version: 4.1.0(vite@4.2.1)(vue@3.2.47) + version: 4.2.1(vite@4.2.1)(vue@3.2.47) '@vitejs/plugin-vue-jsx': specifier: latest version: 3.0.1(vite@4.2.1)(vue@3.2.47) @@ -855,6 +855,9 @@ importers: specifier: ^2.0.2 version: 2.0.2 devDependencies: + '@types/estree': + specifier: ^1.0.1 + version: 1.0.1 '@types/ws': specifier: ^8.5.4 version: 8.5.4 @@ -867,6 +870,15 @@ importers: '@vitest/ws-client': specifier: workspace:* version: link:../ws-client + estree-walker: + specifier: ^3.0.3 + version: 3.0.3 + periscopic: + specifier: ^3.1.0 + version: 3.1.0 + rollup: + specifier: 3.20.2 + version: 3.20.2 vitest: specifier: workspace:* version: link:../vitest @@ -1252,6 +1264,9 @@ importers: '@types/diff': specifier: ^5.0.3 version: 5.0.3 + '@types/estree': + specifier: ^1.0.1 + version: 1.0.1 '@types/istanbul-lib-coverage': specifier: ^2.0.4 version: 2.0.4 @@ -1397,7 +1412,7 @@ importers: version: link:../../packages/vitest webdriverio: specifier: latest - version: 8.7.0(typescript@5.0.3) + version: 8.8.0(typescript@5.0.3) test/base: devDependencies: @@ -1488,6 +1503,9 @@ importers: '@vitest/utils': specifier: workspace:* version: link:../../packages/utils + acorn: + specifier: ^8.8.2 + version: 8.8.2 tinyspy: specifier: ^1.0.2 version: 1.0.2 @@ -1505,7 +1523,7 @@ importers: version: 2.0.4 '@vitejs/plugin-vue': specifier: latest - version: 4.1.0(vite@4.2.1)(vue@3.2.47) + version: 4.2.1(vite@4.2.1)(vue@3.2.47) '@vitest/browser': specifier: workspace:* version: link:../../packages/browser @@ -1514,7 +1532,7 @@ importers: version: 2.3.2(vue@3.2.47) happy-dom: specifier: latest - version: 9.1.7 + version: 9.1.9 istanbul-lib-coverage: specifier: ^3.2.0 version: 3.2.0 @@ -1529,7 +1547,7 @@ importers: version: 3.2.47 webdriverio: specifier: latest - version: 8.7.0(typescript@5.0.3) + version: 8.8.0(typescript@5.0.3) test/css: devDependencies: @@ -1785,7 +1803,7 @@ importers: version: link:../../packages/vitest webdriverio: specifier: latest - version: 8.7.0(typescript@5.0.3) + version: 8.8.0(typescript@5.0.3) test/web-worker: devDependencies: @@ -2106,10 +2124,6 @@ packages: dependencies: '@babel/highlight': 7.18.6 - /@babel/compat-data@7.20.10: - resolution: {integrity: sha512-sEnuDPpOJR/fcafHMjpcpGN5M2jbUGUHwmuWKM/YdPzeEDJg8bgmbcWQFUfE32MQjti1koACvoPVsDe8Uq+idg==} - engines: {node: '>=6.9.0'} - /@babel/compat-data@7.21.4: resolution: {integrity: sha512-/DYyDpeCfaVinT40FPGdkkb+lYSKvsVuMjDAG7jPOWWiM1ibOaB9CXJAlc4d1QpP/U2q2P9jbrSlClKSErd55g==} engines: {node: '>=6.9.0'} @@ -2165,15 +2179,15 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@ampproject/remapping': 2.2.0 - '@babel/code-frame': 7.18.6 - '@babel/generator': 7.20.7 - '@babel/helper-compilation-targets': 7.20.7(@babel/core@7.20.5) - '@babel/helper-module-transforms': 7.20.11 - '@babel/helpers': 7.20.7 - '@babel/parser': 7.20.7 + '@babel/code-frame': 7.21.4 + '@babel/generator': 7.21.4 + '@babel/helper-compilation-targets': 7.21.4(@babel/core@7.20.5) + '@babel/helper-module-transforms': 7.21.2 + '@babel/helpers': 7.21.0 + '@babel/parser': 7.21.4 '@babel/template': 7.20.7 - '@babel/traverse': 7.20.12 - '@babel/types': 7.21.3 + '@babel/traverse': 7.21.4 + '@babel/types': 7.21.4 convert-source-map: 1.9.0 debug: 4.3.4(supports-color@8.1.1) gensync: 1.0.0-beta.2 @@ -2209,15 +2223,7 @@ packages: resolution: {integrity: sha512-CkPg8ySSPuHTYPJYo7IRALdqyjM9HCbt/3uOBEFbzyGVP6Mn8bwFPB0jX6982JVNBlYzM1nnPkfjuXSOPtQeEQ==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.21.3 - '@jridgewell/gen-mapping': 0.3.2 - jsesc: 2.5.2 - - /@babel/generator@7.20.7: - resolution: {integrity: sha512-7wqMOJq8doJMZmP4ApXTzLxSr7+oO2jroJURrVEp6XShrQUObV8Tq/D0NCcoYg2uHqUrjzO0zwBjoYzelxK+sw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.21.3 + '@babel/types': 7.21.4 '@jridgewell/gen-mapping': 0.3.2 jsesc: 2.5.2 @@ -2234,7 +2240,7 @@ packages: resolution: {integrity: sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.21.3 + '@babel/types': 7.21.4 dev: true /@babel/helper-builder-binary-assignment-operator-visitor@7.18.9: @@ -2242,7 +2248,7 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/helper-explode-assignable-expression': 7.18.6 - '@babel/types': 7.21.3 + '@babel/types': 7.21.4 dev: true /@babel/helper-compilation-targets@7.18.9(@babel/core@7.18.13): @@ -2251,49 +2257,35 @@ packages: peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/compat-data': 7.20.10 + '@babel/compat-data': 7.21.4 '@babel/core': 7.18.13 - '@babel/helper-validator-option': 7.18.6 + '@babel/helper-validator-option': 7.21.0 browserslist: 4.21.3 semver: 6.3.0 - /@babel/helper-compilation-targets@7.20.7(@babel/core@7.18.13): - resolution: {integrity: sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==} + /@babel/helper-compilation-targets@7.21.4(@babel/core@7.18.13): + resolution: {integrity: sha512-Fa0tTuOXZ1iL8IeDFUWCzjZcn+sJGd9RZdH9esYVjEejGmzf+FFYQpMi/kZUk2kPy/q1H3/GPw7np8qar/stfg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/compat-data': 7.20.10 + '@babel/compat-data': 7.21.4 '@babel/core': 7.18.13 - '@babel/helper-validator-option': 7.18.6 + '@babel/helper-validator-option': 7.21.0 browserslist: 4.21.3 lru-cache: 5.1.1 semver: 6.3.0 dev: true - /@babel/helper-compilation-targets@7.20.7(@babel/core@7.20.5): - resolution: {integrity: sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==} + /@babel/helper-compilation-targets@7.21.4(@babel/core@7.20.5): + resolution: {integrity: sha512-Fa0tTuOXZ1iL8IeDFUWCzjZcn+sJGd9RZdH9esYVjEejGmzf+FFYQpMi/kZUk2kPy/q1H3/GPw7np8qar/stfg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/compat-data': 7.20.10 + '@babel/compat-data': 7.21.4 '@babel/core': 7.20.5 - '@babel/helper-validator-option': 7.18.6 - browserslist: 4.21.3 - lru-cache: 5.1.1 - semver: 6.3.0 - dev: true - - /@babel/helper-compilation-targets@7.20.7(@babel/core@7.21.4): - resolution: {integrity: sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/compat-data': 7.20.10 - '@babel/core': 7.21.4 - '@babel/helper-validator-option': 7.18.6 + '@babel/helper-validator-option': 7.21.0 browserslist: 4.21.3 lru-cache: 5.1.1 semver: 6.3.0 @@ -2397,10 +2389,10 @@ packages: '@babel/core': ^7.4.0-0 dependencies: '@babel/core': 7.21.4 - '@babel/helper-compilation-targets': 7.20.7(@babel/core@7.21.4) + '@babel/helper-compilation-targets': 7.21.4(@babel/core@7.21.4) '@babel/helper-module-imports': 7.18.6 '@babel/helper-plugin-utils': 7.20.2 - '@babel/traverse': 7.20.12 + '@babel/traverse': 7.21.4 debug: 4.3.4(supports-color@8.1.1) lodash.debounce: 4.0.8 resolve: 1.22.1 @@ -2415,7 +2407,7 @@ packages: '@babel/core': ^7.4.0-0 dependencies: '@babel/core': 7.18.13 - '@babel/helper-compilation-targets': 7.20.7(@babel/core@7.18.13) + '@babel/helper-compilation-targets': 7.21.4(@babel/core@7.18.13) '@babel/helper-plugin-utils': 7.20.2 debug: 4.3.4(supports-color@8.1.1) lodash.debounce: 4.0.8 @@ -2431,7 +2423,7 @@ packages: '@babel/core': ^7.4.0-0 dependencies: '@babel/core': 7.21.4 - '@babel/helper-compilation-targets': 7.20.7(@babel/core@7.21.4) + '@babel/helper-compilation-targets': 7.21.4(@babel/core@7.21.4) '@babel/helper-plugin-utils': 7.20.2 debug: 4.3.4(supports-color@8.1.1) lodash.debounce: 4.0.8 @@ -2449,7 +2441,7 @@ packages: resolution: {integrity: sha512-eyAYAsQmB80jNfg4baAtLeWAQHfHFiR483rzFK+BhETlGZaQC9bsfrugfXDCbRHLQbIA7U5NxhhOxN7p/dWIcg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.21.3 + '@babel/types': 7.21.4 dev: true /@babel/helper-function-name@7.21.0: @@ -2457,33 +2449,33 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/template': 7.20.7 - '@babel/types': 7.21.3 + '@babel/types': 7.21.4 /@babel/helper-hoist-variables@7.18.6: resolution: {integrity: sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.21.3 + '@babel/types': 7.21.4 /@babel/helper-member-expression-to-functions@7.21.0: resolution: {integrity: sha512-Muu8cdZwNN6mRRNG6lAYErJ5X3bRevgYR2O8wN0yn7jJSnGDu6eG59RfT29JHxGUovyfrh6Pj0XzmR7drNVL3Q==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.21.3 + '@babel/types': 7.21.4 dev: true /@babel/helper-module-imports@7.16.0: resolution: {integrity: sha512-kkH7sWzKPq0xt3H1n+ghb4xEMP8k0U7XV3kkB+ZGy69kDk2ySFW1qPi06sjKzFY3t1j6XbJSqr4mF9L7CYVyhg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.21.3 + '@babel/types': 7.21.4 dev: true /@babel/helper-module-imports@7.18.6: resolution: {integrity: sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.21.3 + '@babel/types': 7.21.4 /@babel/helper-module-transforms@7.18.9: resolution: {integrity: sha512-KYNqY0ICwfv19b31XzvmI/mfcylOzbLtowkw+mfvGPAQ3kfCnMLYbED3YecL5tPd8nAYFQFAd6JHp2LxZk/J1g==} @@ -2495,26 +2487,10 @@ packages: '@babel/helper-split-export-declaration': 7.18.6 '@babel/helper-validator-identifier': 7.19.1 '@babel/template': 7.20.7 - '@babel/traverse': 7.20.12 - '@babel/types': 7.21.3 - transitivePeerDependencies: - - supports-color - - /@babel/helper-module-transforms@7.20.11: - resolution: {integrity: sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-environment-visitor': 7.18.9 - '@babel/helper-module-imports': 7.18.6 - '@babel/helper-simple-access': 7.20.2 - '@babel/helper-split-export-declaration': 7.18.6 - '@babel/helper-validator-identifier': 7.19.1 - '@babel/template': 7.20.7 - '@babel/traverse': 7.20.12 - '@babel/types': 7.21.3 + '@babel/traverse': 7.21.4 + '@babel/types': 7.21.4 transitivePeerDependencies: - supports-color - dev: true /@babel/helper-module-transforms@7.21.2: resolution: {integrity: sha512-79yj2AR4U/Oqq/WOV7Lx6hUjau1Zfo4cI+JLAVYeMV5XIlbOhmjEk5ulbTc9fMpmlojzZHkUUxAiK+UKn+hNQQ==} @@ -2535,7 +2511,7 @@ packages: resolution: {integrity: sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.21.3 + '@babel/types': 7.21.4 dev: true /@babel/helper-plugin-utils@7.10.4: @@ -2556,7 +2532,7 @@ packages: '@babel/helper-annotate-as-pure': 7.18.6 '@babel/helper-environment-visitor': 7.18.9 '@babel/helper-wrap-function': 7.18.11 - '@babel/types': 7.21.3 + '@babel/types': 7.21.4 transitivePeerDependencies: - supports-color dev: true @@ -2571,7 +2547,7 @@ packages: '@babel/helper-annotate-as-pure': 7.18.6 '@babel/helper-environment-visitor': 7.18.9 '@babel/helper-wrap-function': 7.18.11 - '@babel/types': 7.21.3 + '@babel/types': 7.21.4 transitivePeerDependencies: - supports-color dev: true @@ -2584,8 +2560,8 @@ packages: '@babel/helper-member-expression-to-functions': 7.21.0 '@babel/helper-optimise-call-expression': 7.18.6 '@babel/template': 7.20.7 - '@babel/traverse': 7.20.12 - '@babel/types': 7.21.3 + '@babel/traverse': 7.21.4 + '@babel/types': 7.21.4 transitivePeerDependencies: - supports-color dev: true @@ -2594,20 +2570,20 @@ packages: resolution: {integrity: sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.21.3 + '@babel/types': 7.21.4 /@babel/helper-skip-transparent-expression-wrappers@7.20.0: resolution: {integrity: sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.21.3 + '@babel/types': 7.21.4 dev: true /@babel/helper-split-export-declaration@7.18.6: resolution: {integrity: sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.21.3 + '@babel/types': 7.21.4 /@babel/helper-string-parser@7.19.4: resolution: {integrity: sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==} @@ -2617,10 +2593,6 @@ packages: resolution: {integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==} engines: {node: '>=6.9.0'} - /@babel/helper-validator-option@7.18.6: - resolution: {integrity: sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==} - engines: {node: '>=6.9.0'} - /@babel/helper-validator-option@7.21.0: resolution: {integrity: sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==} engines: {node: '>=6.9.0'} @@ -2631,8 +2603,8 @@ packages: dependencies: '@babel/helper-function-name': 7.21.0 '@babel/template': 7.20.7 - '@babel/traverse': 7.20.12 - '@babel/types': 7.21.3 + '@babel/traverse': 7.21.4 + '@babel/types': 7.21.4 transitivePeerDependencies: - supports-color dev: true @@ -2642,21 +2614,10 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/template': 7.20.7 - '@babel/traverse': 7.20.12 - '@babel/types': 7.21.3 - transitivePeerDependencies: - - supports-color - - /@babel/helpers@7.20.7: - resolution: {integrity: sha512-PBPjs5BppzsGaxHQCDKnZ6Gd9s6xl8bBCluz3vEInLGRJmnZan4F6BYCeqtyXqkk4W5IlPmjK4JlOuZkpJ3xZA==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/template': 7.20.7 - '@babel/traverse': 7.20.12 - '@babel/types': 7.21.3 + '@babel/traverse': 7.21.4 + '@babel/types': 7.21.4 transitivePeerDependencies: - supports-color - dev: true /@babel/helpers@7.21.0: resolution: {integrity: sha512-XXve0CBtOW0pd7MRzzmoyuSj0e3SEzj8pgyFxnTT1NJZL38BD1MK7yYrm8yefRPIDvNNe14xR4FdbHwpInD4rA==} @@ -2681,14 +2642,7 @@ packages: engines: {node: '>=6.0.0'} hasBin: true dependencies: - '@babel/types': 7.21.3 - - /@babel/parser@7.20.7: - resolution: {integrity: sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg==} - engines: {node: '>=6.0.0'} - hasBin: true - dependencies: - '@babel/types': 7.21.3 + '@babel/types': 7.21.4 /@babel/parser@7.21.4: resolution: {integrity: sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==} @@ -3001,9 +2955,9 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/compat-data': 7.20.10 + '@babel/compat-data': 7.21.4 '@babel/core': 7.18.13 - '@babel/helper-compilation-targets': 7.20.7(@babel/core@7.18.13) + '@babel/helper-compilation-targets': 7.21.4(@babel/core@7.18.13) '@babel/helper-plugin-utils': 7.20.2 '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.18.13) '@babel/plugin-transform-parameters': 7.18.8(@babel/core@7.18.13) @@ -3015,9 +2969,9 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/compat-data': 7.20.10 + '@babel/compat-data': 7.21.4 '@babel/core': 7.21.4 - '@babel/helper-compilation-targets': 7.20.7(@babel/core@7.21.4) + '@babel/helper-compilation-targets': 7.21.4(@babel/core@7.21.4) '@babel/helper-plugin-utils': 7.20.2 '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.21.4) '@babel/plugin-transform-parameters': 7.18.8(@babel/core@7.21.4) @@ -3808,7 +3762,7 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.18.13 - '@babel/helper-compilation-targets': 7.20.7(@babel/core@7.18.13) + '@babel/helper-compilation-targets': 7.21.4(@babel/core@7.18.13) '@babel/helper-function-name': 7.21.0 '@babel/helper-plugin-utils': 7.20.2 dev: true @@ -3820,7 +3774,7 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.21.4 - '@babel/helper-compilation-targets': 7.20.7(@babel/core@7.21.4) + '@babel/helper-compilation-targets': 7.21.4(@babel/core@7.21.4) '@babel/helper-function-name': 7.21.0 '@babel/helper-plugin-utils': 7.20.2 dev: true @@ -3872,7 +3826,7 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.18.13 - '@babel/helper-module-transforms': 7.20.11 + '@babel/helper-module-transforms': 7.21.2 '@babel/helper-plugin-utils': 7.20.2 babel-plugin-dynamic-import-node: 2.3.3 transitivePeerDependencies: @@ -3886,7 +3840,7 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.21.4 - '@babel/helper-module-transforms': 7.20.11 + '@babel/helper-module-transforms': 7.21.2 '@babel/helper-plugin-utils': 7.20.2 babel-plugin-dynamic-import-node: 2.3.3 transitivePeerDependencies: @@ -3900,7 +3854,7 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.18.13 - '@babel/helper-module-transforms': 7.20.11 + '@babel/helper-module-transforms': 7.21.2 '@babel/helper-plugin-utils': 7.20.2 '@babel/helper-simple-access': 7.20.2 babel-plugin-dynamic-import-node: 2.3.3 @@ -3915,7 +3869,7 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.21.4 - '@babel/helper-module-transforms': 7.20.11 + '@babel/helper-module-transforms': 7.21.2 '@babel/helper-plugin-utils': 7.20.2 '@babel/helper-simple-access': 7.20.2 babel-plugin-dynamic-import-node: 2.3.3 @@ -3931,7 +3885,7 @@ packages: dependencies: '@babel/core': 7.18.13 '@babel/helper-hoist-variables': 7.18.6 - '@babel/helper-module-transforms': 7.20.11 + '@babel/helper-module-transforms': 7.21.2 '@babel/helper-plugin-utils': 7.20.2 '@babel/helper-validator-identifier': 7.19.1 babel-plugin-dynamic-import-node: 2.3.3 @@ -3947,7 +3901,7 @@ packages: dependencies: '@babel/core': 7.21.4 '@babel/helper-hoist-variables': 7.18.6 - '@babel/helper-module-transforms': 7.20.11 + '@babel/helper-module-transforms': 7.21.2 '@babel/helper-plugin-utils': 7.20.2 '@babel/helper-validator-identifier': 7.19.1 babel-plugin-dynamic-import-node: 2.3.3 @@ -3962,7 +3916,7 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.18.13 - '@babel/helper-module-transforms': 7.20.11 + '@babel/helper-module-transforms': 7.21.2 '@babel/helper-plugin-utils': 7.20.2 transitivePeerDependencies: - supports-color @@ -3975,7 +3929,7 @@ packages: '@babel/core': ^7.0.0-0 dependencies: '@babel/core': 7.21.4 - '@babel/helper-module-transforms': 7.20.11 + '@babel/helper-module-transforms': 7.21.2 '@babel/helper-plugin-utils': 7.20.2 transitivePeerDependencies: - supports-color @@ -4190,7 +4144,7 @@ packages: '@babel/helper-module-imports': 7.18.6 '@babel/helper-plugin-utils': 7.20.2 '@babel/plugin-syntax-jsx': 7.18.6(@babel/core@7.18.13) - '@babel/types': 7.21.3 + '@babel/types': 7.21.4 dev: true /@babel/plugin-transform-react-jsx@7.19.0(@babel/core@7.18.13): @@ -4204,7 +4158,7 @@ packages: '@babel/helper-module-imports': 7.18.6 '@babel/helper-plugin-utils': 7.20.2 '@babel/plugin-syntax-jsx': 7.18.6(@babel/core@7.18.13) - '@babel/types': 7.21.3 + '@babel/types': 7.21.4 dev: true /@babel/plugin-transform-react-jsx@7.19.0(@babel/core@7.21.4): @@ -4218,7 +4172,7 @@ packages: '@babel/helper-module-imports': 7.18.6 '@babel/helper-plugin-utils': 7.20.2 '@babel/plugin-syntax-jsx': 7.18.6(@babel/core@7.21.4) - '@babel/types': 7.21.3 + '@babel/types': 7.21.4 dev: true /@babel/plugin-transform-react-pure-annotations@7.18.6(@babel/core@7.18.13): @@ -4465,11 +4419,11 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/compat-data': 7.20.10 + '@babel/compat-data': 7.21.4 '@babel/core': 7.18.13 - '@babel/helper-compilation-targets': 7.20.7(@babel/core@7.18.13) + '@babel/helper-compilation-targets': 7.21.4(@babel/core@7.18.13) '@babel/helper-plugin-utils': 7.20.2 - '@babel/helper-validator-option': 7.18.6 + '@babel/helper-validator-option': 7.21.0 '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.18.6(@babel/core@7.18.13) '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.18.9(@babel/core@7.18.13) '@babel/plugin-proposal-async-generator-functions': 7.18.10(@babel/core@7.18.13) @@ -4535,7 +4489,7 @@ packages: '@babel/plugin-transform-unicode-escapes': 7.18.10(@babel/core@7.18.13) '@babel/plugin-transform-unicode-regex': 7.18.6(@babel/core@7.18.13) '@babel/preset-modules': 0.1.5(@babel/core@7.18.13) - '@babel/types': 7.21.3 + '@babel/types': 7.21.4 babel-plugin-polyfill-corejs2: 0.3.2(@babel/core@7.18.13) babel-plugin-polyfill-corejs3: 0.5.3(@babel/core@7.18.13) babel-plugin-polyfill-regenerator: 0.4.0(@babel/core@7.18.13) @@ -4551,11 +4505,11 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/compat-data': 7.20.10 + '@babel/compat-data': 7.21.4 '@babel/core': 7.21.4 - '@babel/helper-compilation-targets': 7.20.7(@babel/core@7.21.4) + '@babel/helper-compilation-targets': 7.21.4(@babel/core@7.21.4) '@babel/helper-plugin-utils': 7.20.2 - '@babel/helper-validator-option': 7.18.6 + '@babel/helper-validator-option': 7.21.0 '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.18.6(@babel/core@7.21.4) '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.18.9(@babel/core@7.21.4) '@babel/plugin-proposal-async-generator-functions': 7.18.10(@babel/core@7.21.4) @@ -4621,7 +4575,7 @@ packages: '@babel/plugin-transform-unicode-escapes': 7.18.10(@babel/core@7.21.4) '@babel/plugin-transform-unicode-regex': 7.18.6(@babel/core@7.21.4) '@babel/preset-modules': 0.1.5(@babel/core@7.21.4) - '@babel/types': 7.21.3 + '@babel/types': 7.21.4 babel-plugin-polyfill-corejs2: 0.3.2(@babel/core@7.21.4) babel-plugin-polyfill-corejs3: 0.5.3(@babel/core@7.21.4) babel-plugin-polyfill-regenerator: 0.4.0(@babel/core@7.21.4) @@ -4639,7 +4593,7 @@ packages: dependencies: '@babel/core': 7.18.13 '@babel/helper-plugin-utils': 7.20.2 - '@babel/helper-validator-option': 7.18.6 + '@babel/helper-validator-option': 7.21.0 '@babel/plugin-transform-flow-strip-types': 7.18.9(@babel/core@7.18.13) dev: true @@ -4652,7 +4606,7 @@ packages: '@babel/helper-plugin-utils': 7.20.2 '@babel/plugin-proposal-unicode-property-regex': 7.18.6(@babel/core@7.18.13) '@babel/plugin-transform-dotall-regex': 7.18.6(@babel/core@7.18.13) - '@babel/types': 7.21.3 + '@babel/types': 7.21.4 esutils: 2.0.3 dev: true @@ -4665,7 +4619,7 @@ packages: '@babel/helper-plugin-utils': 7.20.2 '@babel/plugin-proposal-unicode-property-regex': 7.18.6(@babel/core@7.21.4) '@babel/plugin-transform-dotall-regex': 7.18.6(@babel/core@7.21.4) - '@babel/types': 7.21.3 + '@babel/types': 7.21.4 esutils: 2.0.3 dev: true @@ -4677,7 +4631,7 @@ packages: dependencies: '@babel/core': 7.18.13 '@babel/helper-plugin-utils': 7.20.2 - '@babel/helper-validator-option': 7.18.6 + '@babel/helper-validator-option': 7.21.0 '@babel/plugin-transform-react-display-name': 7.18.6(@babel/core@7.18.13) '@babel/plugin-transform-react-jsx': 7.19.0(@babel/core@7.18.13) '@babel/plugin-transform-react-jsx-development': 7.18.6(@babel/core@7.18.13) @@ -4692,7 +4646,7 @@ packages: dependencies: '@babel/core': 7.21.4 '@babel/helper-plugin-utils': 7.20.2 - '@babel/helper-validator-option': 7.18.6 + '@babel/helper-validator-option': 7.21.0 '@babel/plugin-transform-react-display-name': 7.18.6(@babel/core@7.21.4) '@babel/plugin-transform-react-jsx': 7.19.0(@babel/core@7.21.4) '@babel/plugin-transform-react-jsx-development': 7.18.6(@babel/core@7.21.4) @@ -4707,7 +4661,7 @@ packages: dependencies: '@babel/core': 7.20.5 '@babel/helper-plugin-utils': 7.20.2 - '@babel/helper-validator-option': 7.18.6 + '@babel/helper-validator-option': 7.21.0 '@babel/plugin-transform-typescript': 7.21.3(@babel/core@7.20.5) transitivePeerDependencies: - supports-color @@ -4721,7 +4675,7 @@ packages: dependencies: '@babel/core': 7.21.4 '@babel/helper-plugin-utils': 7.20.2 - '@babel/helper-validator-option': 7.18.6 + '@babel/helper-validator-option': 7.21.0 '@babel/plugin-transform-typescript': 7.21.3(@babel/core@7.21.4) transitivePeerDependencies: - supports-color @@ -4751,47 +4705,30 @@ packages: resolution: {integrity: sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/code-frame': 7.18.6 - '@babel/parser': 7.20.7 - '@babel/types': 7.21.3 + '@babel/code-frame': 7.21.4 + '@babel/parser': 7.21.4 + '@babel/types': 7.21.4 /@babel/template@7.20.7: resolution: {integrity: sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/code-frame': 7.18.6 - '@babel/parser': 7.20.7 - '@babel/types': 7.21.3 + '@babel/code-frame': 7.21.4 + '@babel/parser': 7.21.4 + '@babel/types': 7.21.4 /@babel/traverse@7.18.13: resolution: {integrity: sha512-N6kt9X1jRMLPxxxPYWi7tgvJRH/rtoU+dbKAPDM44RFHiMH8igdsaSBgFeskhSl/kLWLDUvIh1RXCrTmg0/zvA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/code-frame': 7.18.6 - '@babel/generator': 7.20.7 - '@babel/helper-environment-visitor': 7.18.9 - '@babel/helper-function-name': 7.21.0 - '@babel/helper-hoist-variables': 7.18.6 - '@babel/helper-split-export-declaration': 7.18.6 - '@babel/parser': 7.20.7 - '@babel/types': 7.21.3 - debug: 4.3.4(supports-color@8.1.1) - globals: 11.12.0 - transitivePeerDependencies: - - supports-color - - /@babel/traverse@7.20.12: - resolution: {integrity: sha512-MsIbFN0u+raeja38qboyF8TIT7K0BFzz/Yd/77ta4MsUsmP2RAnidIlwq7d5HFQrH/OZJecGV6B71C4zAgpoSQ==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/code-frame': 7.18.6 - '@babel/generator': 7.20.7 + '@babel/code-frame': 7.21.4 + '@babel/generator': 7.21.4 '@babel/helper-environment-visitor': 7.18.9 '@babel/helper-function-name': 7.21.0 '@babel/helper-hoist-variables': 7.18.6 '@babel/helper-split-export-declaration': 7.18.6 - '@babel/parser': 7.20.7 - '@babel/types': 7.21.3 + '@babel/parser': 7.21.4 + '@babel/types': 7.21.4 debug: 4.3.4(supports-color@8.1.1) globals: 11.12.0 transitivePeerDependencies: @@ -4822,14 +4759,6 @@ packages: '@babel/helper-validator-identifier': 7.19.1 to-fast-properties: 2.0.0 - /@babel/types@7.21.3: - resolution: {integrity: sha512-sBGdETxC+/M4o/zKC0sl6sjWv62WFR/uzxrJ6uYyMLZOUlPnwzw0tKgVHOXxaAd5l2g8pEDM5RZ495GPQI77kg==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-string-parser': 7.19.4 - '@babel/helper-validator-identifier': 7.19.1 - to-fast-properties: 2.0.0 - /@babel/types@7.21.4: resolution: {integrity: sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA==} engines: {node: '>=6.9.0'} @@ -5563,7 +5492,7 @@ packages: engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: '@jest/types': 27.5.1 - '@types/node': 18.16.0 + '@types/node': 18.16.1 chalk: 4.1.2 jest-message-util: 27.5.1 jest-util: 27.5.1 @@ -5584,7 +5513,7 @@ packages: '@jest/test-result': 27.5.1 '@jest/transform': 27.5.1 '@jest/types': 27.5.1 - '@types/node': 18.16.0 + '@types/node': 18.16.1 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.8.1 @@ -5621,7 +5550,7 @@ packages: dependencies: '@jest/fake-timers': 27.5.1 '@jest/types': 27.5.1 - '@types/node': 18.16.0 + '@types/node': 18.16.1 jest-mock: 27.5.1 dev: true @@ -5638,7 +5567,7 @@ packages: dependencies: '@jest/types': 27.5.1 '@sinonjs/fake-timers': 8.1.0 - '@types/node': 18.16.0 + '@types/node': 18.16.1 jest-message-util: 27.5.1 jest-mock: 27.5.1 jest-util: 27.5.1 @@ -5667,7 +5596,7 @@ packages: '@jest/test-result': 27.5.1 '@jest/transform': 27.5.1 '@jest/types': 27.5.1 - '@types/node': 18.16.0 + '@types/node': 18.16.1 chalk: 4.1.2 collect-v8-coverage: 1.0.1 exit: 0.1.2 @@ -5781,7 +5710,7 @@ packages: dependencies: '@types/istanbul-lib-coverage': 2.0.4 '@types/istanbul-reports': 3.0.1 - '@types/node': 18.16.0 + '@types/node': 18.16.1 '@types/yargs': 15.0.14 chalk: 4.1.2 dev: true @@ -5792,7 +5721,7 @@ packages: dependencies: '@types/istanbul-lib-coverage': 2.0.4 '@types/istanbul-reports': 3.0.1 - '@types/node': 18.16.0 + '@types/node': 18.16.1 '@types/yargs': 16.0.5 chalk: 4.1.2 dev: true @@ -5804,7 +5733,7 @@ packages: '@jest/schemas': 29.0.0 '@types/istanbul-lib-coverage': 2.0.4 '@types/istanbul-reports': 3.0.1 - '@types/node': 18.16.0 + '@types/node': 18.16.1 '@types/yargs': 17.0.12 chalk: 4.1.2 dev: true @@ -6317,7 +6246,7 @@ packages: engines: {node: '>=14'} hasBin: true dependencies: - '@types/node': 18.16.0 + '@types/node': 18.16.1 playwright-core: 1.28.0 dev: true @@ -6367,6 +6296,29 @@ packages: resolution: {integrity: sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==} dev: false + /@puppeteer/browsers@0.4.0(typescript@5.0.3): + resolution: {integrity: sha512-3iB5pWn9Sr55PKKwqFWSWjLsTKCOEhKNI+uV3BZesgXuA3IhsX8I3hW0HI+3ksMIPkh2mVYzKSpvgq3oicjG2Q==} + engines: {node: '>=14.1.0'} + hasBin: true + peerDependencies: + typescript: '>= 4.7.4' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + debug: 4.3.4(supports-color@8.1.1) + extract-zip: 2.0.1(supports-color@8.1.1) + https-proxy-agent: 5.0.1 + progress: 2.0.3 + proxy-from-env: 1.1.0 + tar-fs: 2.1.1 + typescript: 5.0.3 + unbzip2-stream: 1.4.3 + yargs: 17.7.1 + transitivePeerDependencies: + - supports-color + dev: true + /@rollup/plugin-alias@4.0.2(rollup@3.20.2): resolution: {integrity: sha512-1hv7dBOZZwo3SEupxn4UA2N0EDThqSSS+wI1St1TNTBtOZvUchyIClyHcnDcjjrReTPZ47Faedrhblv4n+T5UQ==} engines: {node: '>=14.0.0'} @@ -6525,7 +6477,7 @@ packages: rollup: optional: true dependencies: - '@types/estree': 1.0.0 + '@types/estree': 1.0.1 estree-walker: 2.0.2 picomatch: 2.3.1 rollup: 2.79.1 @@ -6540,7 +6492,7 @@ packages: rollup: optional: true dependencies: - '@types/estree': 1.0.0 + '@types/estree': 1.0.1 estree-walker: 2.0.2 picomatch: 2.3.1 rollup: 3.20.2 @@ -7567,10 +7519,10 @@ packages: /@storybook/mdx1-csf@0.0.1(@babel/core@7.18.13): resolution: {integrity: sha512-4biZIWWzoWlCarMZmTpqcJNgo/RBesYZwGFbQeXiGYsswuvfWARZnW9RE9aUEMZ4XPn7B1N3EKkWcdcWe/K2tg==} dependencies: - '@babel/generator': 7.20.7 - '@babel/parser': 7.20.7 + '@babel/generator': 7.21.4 + '@babel/parser': 7.21.4 '@babel/preset-env': 7.18.10(@babel/core@7.18.13) - '@babel/types': 7.21.3 + '@babel/types': 7.21.4 '@mdx-js/mdx': 1.6.22 '@types/lodash': 4.14.192 js-string-escape: 1.0.1 @@ -7586,10 +7538,10 @@ packages: /@storybook/mdx1-csf@0.0.1(@babel/core@7.21.4): resolution: {integrity: sha512-4biZIWWzoWlCarMZmTpqcJNgo/RBesYZwGFbQeXiGYsswuvfWARZnW9RE9aUEMZ4XPn7B1N3EKkWcdcWe/K2tg==} dependencies: - '@babel/generator': 7.20.7 - '@babel/parser': 7.20.7 + '@babel/generator': 7.21.4 + '@babel/parser': 7.21.4 '@babel/preset-env': 7.18.10(@babel/core@7.21.4) - '@babel/types': 7.21.3 + '@babel/types': 7.21.4 '@mdx-js/mdx': 1.6.22 '@types/lodash': 4.14.192 js-string-escape: 1.0.1 @@ -7605,10 +7557,10 @@ packages: /@storybook/mdx1-csf@0.0.4(@babel/core@7.18.13)(react@17.0.2): resolution: {integrity: sha512-xxUEMy0D+0G1aSYxbeVNbs+XBU5nCqW4I7awpBYSTywXDv/MJWeC6FDRpj5P1pgfq8j8jWDD5ZDvBQ7syFg0LQ==} dependencies: - '@babel/generator': 7.20.7 - '@babel/parser': 7.20.7 + '@babel/generator': 7.21.4 + '@babel/parser': 7.21.4 '@babel/preset-env': 7.18.10(@babel/core@7.18.13) - '@babel/types': 7.21.3 + '@babel/types': 7.21.4 '@mdx-js/mdx': 1.6.22 '@mdx-js/react': 1.6.22(react@17.0.2) '@types/lodash': 4.14.192 @@ -7989,7 +7941,7 @@ packages: resolution: {integrity: sha512-KnH2MnJUzmFNPW6RIKfd+zf2Wue8mEKX0M3cpX6aKl5ZXrJM1/c/Pc8c2xDNYQCnJO48Sm5ITbMXgqTr3h4jxQ==} engines: {node: '>=12'} dependencies: - '@babel/code-frame': 7.18.6 + '@babel/code-frame': 7.21.4 '@babel/runtime': 7.18.9 '@types/aria-query': 4.2.2 aria-query: 5.0.2 @@ -8003,7 +7955,7 @@ packages: resolution: {integrity: sha512-6YWYPPpxG3e/xOo6HIWwB/58HukkwIVTOaZ0VwdMVjhRUX/01E4FtQbck9GazOOj7MXHc5RBzMrU86iBJHbI+A==} engines: {node: '>=12'} dependencies: - '@babel/code-frame': 7.18.6 + '@babel/code-frame': 7.21.4 '@babel/runtime': 7.18.9 '@types/aria-query': 4.2.2 aria-query: 5.0.2 @@ -8203,7 +8155,7 @@ packages: /@types/cheerio@0.22.31: resolution: {integrity: sha512-Kt7Cdjjdi2XWSfrZ53v4Of0wG3ZcmaegFXjMmz9tfNrZSkzzo36G0AL1YqSdcIA78Etjt6E609pt5h1xnQkPUw==} dependencies: - '@types/node': 18.16.0 + '@types/node': 18.16.1 dev: true /@types/codemirror@5.60.7: @@ -8238,20 +8190,20 @@ packages: resolution: {integrity: sha512-xryQlOEIe1TduDWAOphR0ihfebKFSWOXpIsk+70JskCfRfW+xALdnJ0r1ZOTo85F9Qsjk6vtlU7edTYHbls9tA==} dependencies: '@types/cheerio': 0.22.31 - '@types/react': 18.0.38 + '@types/react': 18.2.0 dev: true /@types/eslint-scope@3.7.4: resolution: {integrity: sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA==} dependencies: '@types/eslint': 8.4.6 - '@types/estree': 1.0.0 + '@types/estree': 1.0.1 dev: true /@types/eslint@8.4.6: resolution: {integrity: sha512-/fqTbjxyFUaYNO7VcW5g+4npmqVACz1bB7RTHYuLj+PRjw9hrCwrUXVQFpChUS0JsyEFvMZ7U/PfmvWgxJhI9g==} dependencies: - '@types/estree': 1.0.0 + '@types/estree': 1.0.1 '@types/json-schema': 7.0.11 dev: true @@ -8263,41 +8215,41 @@ packages: resolution: {integrity: sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==} dev: true - /@types/estree@1.0.0: - resolution: {integrity: sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==} + /@types/estree@1.0.1: + resolution: {integrity: sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==} dev: true /@types/fs-extra@11.0.1: resolution: {integrity: sha512-MxObHvNl4A69ofaTRU8DFqvgzzv8s9yRtaPPm5gud9HDNvpB3GPQFvNuTWAI59B9huVGV5jXYJwbCsmBsOGYWA==} dependencies: '@types/jsonfile': 6.1.1 - '@types/node': 18.16.0 + '@types/node': 18.16.1 dev: true /@types/fs-extra@9.0.13: resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==} dependencies: - '@types/node': 18.16.0 + '@types/node': 18.16.1 dev: true /@types/glob@7.2.0: resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} dependencies: '@types/minimatch': 5.1.1 - '@types/node': 18.16.0 + '@types/node': 18.16.1 dev: true /@types/glob@8.0.0: resolution: {integrity: sha512-l6NQsDDyQUVeoTynNpC9uRvCUint/gSUXQA2euwmTuWGvPY5LSDUu6tkCtJB2SvGQlJQzLaKqcGZP4//7EDveA==} dependencies: '@types/minimatch': 5.1.1 - '@types/node': 18.16.0 + '@types/node': 18.16.1 dev: true /@types/graceful-fs@4.1.5: resolution: {integrity: sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==} dependencies: - '@types/node': 18.16.0 + '@types/node': 18.16.1 dev: true /@types/hast@2.3.4: @@ -8362,7 +8314,7 @@ packages: /@types/jsdom@21.1.1: resolution: {integrity: sha512-cZFuoVLtzKP3gmq9eNosUL1R50U+USkbLtUQ1bYVgl/lKp0FZM7Cq4aIHAL8oIvQ17uSHi7jXPtfDOdjPwBE7A==} dependencies: - '@types/node': 18.16.0 + '@types/node': 18.16.1 '@types/tough-cookie': 4.0.2 parse5: 7.1.2 dev: true @@ -8378,7 +8330,7 @@ packages: /@types/jsonfile@6.1.1: resolution: {integrity: sha512-GSgiRCVeapDN+3pqA35IkQwasaCh/0YFH5dEF6S88iDvEn901DjOeH3/QPY+XYP1DFzDZPvIvfeEgk+7br5png==} dependencies: - '@types/node': 18.16.0 + '@types/node': 18.16.1 dev: true /@types/lodash@4.14.192: @@ -8412,7 +8364,7 @@ packages: /@types/node-fetch@2.6.2: resolution: {integrity: sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==} dependencies: - '@types/node': 18.16.0 + '@types/node': 18.16.1 form-data: 3.0.1 dev: true @@ -8427,8 +8379,8 @@ packages: /@types/node@18.15.11: resolution: {integrity: sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==} - /@types/node@18.16.0: - resolution: {integrity: sha512-BsAaKhB+7X+H4GnSjGhJG9Qi8Tw+inU9nJDwmD5CgOmBLEI6ArdhikpLX7DjbjDRDTbqZzU2LSQNZg8WGPiSZQ==} + /@types/node@18.16.1: + resolution: {integrity: sha512-DZxSZWXxFfOlx7k7Rv4LAyiMroaxa3Ly/7OOzZO8cBNho0YzAi4qlbrx8W27JGqG57IgR/6J7r+nOJWw6kcvZA==} dev: true /@types/node@18.7.13: @@ -8461,7 +8413,7 @@ packages: /@types/prompts@2.4.4: resolution: {integrity: sha512-p5N9uoTH76lLvSAaYSZtBCdEXzpOOufsRjnhjVSrZGXikVGHX9+cc9ERtHRV4hvBKHyZb1bg4K+56Bd2TqUn4A==} dependencies: - '@types/node': 18.16.0 + '@types/node': 18.16.1 kleur: 3.0.3 dev: true @@ -8481,19 +8433,19 @@ packages: /@types/react-dom@18.0.6: resolution: {integrity: sha512-/5OFZgfIPSwy+YuIBP/FgJnQnsxhZhjjrnxudMddeblOouIodEQ75X14Rr4wGSG/bknL+Omy9iWlLo1u/9GzAA==} dependencies: - '@types/react': 18.0.38 + '@types/react': 18.2.0 dev: true /@types/react-dom@18.0.8: resolution: {integrity: sha512-C3GYO0HLaOkk9dDAz3Dl4sbe4AKUGTCfFIZsz3n/82dPNN8Du533HzKatDxeUYWu24wJgMP1xICqkWk1YOLOIw==} dependencies: - '@types/react': 18.0.38 + '@types/react': 18.2.0 dev: true /@types/react-is@17.0.3: resolution: {integrity: sha512-aBTIWg1emtu95bLTLx0cpkxwGW3ueZv71nE2YFBpL8k/z5czEW8yYpOo8Dp+UUAFAtKwNaOsh/ioSeQnWlZcfw==} dependencies: - '@types/react': 18.0.38 + '@types/react': 18.2.0 dev: false /@types/react-test-renderer@17.0.2: @@ -8505,7 +8457,7 @@ packages: /@types/react-transition-group@4.4.5: resolution: {integrity: sha512-juKD/eiSM3/xZYzjuzH6ZwpP+/lejltmiS3QEzV/vmb/Q8+HfDmxu+Baga8UEMGBqV88Nbg4l2hY/K2DkyaLLA==} dependencies: - '@types/react': 18.0.38 + '@types/react': 18.2.0 dev: false /@types/react@17.0.49: @@ -8524,8 +8476,8 @@ packages: csstype: 3.1.0 dev: true - /@types/react@18.0.38: - resolution: {integrity: sha512-ExsidLLSzYj4cvaQjGnQCk4HFfVT9+EZ9XZsQ8Hsrcn8QNgXtpZ3m9vSIC2MWtx7jHictK6wYhQgGh6ic58oOw==} + /@types/react@18.2.0: + resolution: {integrity: sha512-0FLj93y5USLHdnhIhABk83rm8XEGA7kH3cr+YUlvxoUGp1xNt/DINUMvqPxLyOQMzLmZe8i4RTHbvb8MC7NmrA==} dependencies: '@types/prop-types': 15.7.5 '@types/scheduler': 0.16.2 @@ -8534,7 +8486,7 @@ packages: /@types/resolve@1.17.1: resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==} dependencies: - '@types/node': 18.16.0 + '@types/node': 18.16.1 dev: true /@types/resolve@1.20.2: @@ -8551,7 +8503,7 @@ packages: /@types/set-cookie-parser@2.4.2: resolution: {integrity: sha512-fBZgytwhYAUkj/jC/FAV4RQ5EerRup1YQsXQCh8rZfiHkc4UahC192oH0smGwsXol3cL3A5oETuAHeQHmhXM4w==} dependencies: - '@types/node': 18.16.0 + '@types/node': 18.16.1 dev: true /@types/sinonjs__fake-timers@8.1.1: @@ -8581,7 +8533,7 @@ packages: /@types/tern@0.23.4: resolution: {integrity: sha512-JAUw1iXGO1qaWwEOzxTKJZ/5JxVeON9kvGZ/osgZaJImBnyjyn0cjovPsf6FNLmyGY8Vw9DoXZCMlfMkMwHRWg==} dependencies: - '@types/estree': 1.0.0 + '@types/estree': 1.0.1 dev: true /@types/testing-library__jest-dom@5.14.5: @@ -8625,7 +8577,7 @@ packages: /@types/webpack-sources@3.2.0: resolution: {integrity: sha512-Ft7YH3lEVRQ6ls8k4Ff1oB4jN6oy/XmU6tQISKdhfh+1mR+viZFphS6WL0IrtDOzvefmJg5a0s7ZQoRXwqTEFg==} dependencies: - '@types/node': 18.16.0 + '@types/node': 18.16.1 '@types/source-list-map': 0.1.2 source-map: 0.7.4 dev: true @@ -8633,7 +8585,7 @@ packages: /@types/webpack@4.41.32: resolution: {integrity: sha512-cb+0ioil/7oz5//7tZUSwbrSAN/NWHrQylz5cW8G0dWTcF/g+/dSdMlKVZspBYuMAN1+WnwHrkxiRrLcwd0Heg==} dependencies: - '@types/node': 18.16.0 + '@types/node': 18.16.1 '@types/tapable': 1.0.8 '@types/uglify-js': 3.17.0 '@types/webpack-sources': 3.2.0 @@ -8648,7 +8600,7 @@ packages: /@types/ws@8.5.4: resolution: {integrity: sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==} dependencies: - '@types/node': 18.16.0 + '@types/node': 18.16.1 dev: true /@types/yargs-parser@21.0.0: @@ -8677,7 +8629,7 @@ packages: resolution: {integrity: sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==} requiresBuild: true dependencies: - '@types/node': 18.16.0 + '@types/node': 18.16.1 dev: true optional: true @@ -9078,7 +9030,7 @@ packages: '@babel/plugin-transform-react-jsx-self': 7.21.0(@babel/core@7.21.4) '@babel/plugin-transform-react-jsx-source': 7.19.6(@babel/core@7.21.4) react-refresh: 0.14.0 - vite: 4.2.1(@types/node@18.16.0) + vite: 4.2.1(@types/node@18.16.1) transitivePeerDependencies: - supports-color dev: true @@ -9121,6 +9073,17 @@ packages: vue: 3.2.47 dev: true + /@vitejs/plugin-vue@4.2.1(vite@4.2.1)(vue@3.2.47): + resolution: {integrity: sha512-ZTZjzo7bmxTRTkb8GSTwkPOYDIP7pwuyV+RV53c9PYUouwcbkIZIvWvNWlX2b1dYZqtOv7D6iUAnJLVNGcLrSw==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + vite: ^4.0.0 + vue: ^3.2.25 + dependencies: + vite: 4.2.1(@types/node@18.15.11) + vue: 3.2.47 + dev: true + /@vitest/coverage-c8@0.24.5: resolution: {integrity: sha512-955yK/SdSBZPYrSXgXB0F+0JnOX5EY9kSL7ywJ4rNajmkFUhwLjuKm13Xb6YKSyIY/g5WvbBnyowqfNRxBJ3ww==} dependencies: @@ -9176,8 +9139,8 @@ packages: '@babel/helper-module-imports': 7.18.6 '@babel/plugin-syntax-jsx': 7.18.6(@babel/core@7.21.4) '@babel/template': 7.20.7 - '@babel/traverse': 7.20.12 - '@babel/types': 7.21.3 + '@babel/traverse': 7.21.4 + '@babel/types': 7.21.4 '@vue/babel-helper-vue-transform-on': 1.0.2 camelcase: 6.3.0 html-tags: 3.2.0 @@ -9218,14 +9181,14 @@ packages: /@vue/compiler-sfc@2.7.10: resolution: {integrity: sha512-55Shns6WPxlYsz4WX7q9ZJBL77sKE1ZAYNYStLs6GbhIOMrNtjMvzcob6gu3cGlfpCR4bT7NXgyJ3tly2+Hx8Q==} dependencies: - '@babel/parser': 7.20.7 - postcss: 8.4.19 + '@babel/parser': 7.21.4 + postcss: 8.4.21 source-map: 0.6.1 /@vue/compiler-sfc@3.2.39: resolution: {integrity: sha512-fqAQgFs1/BxTUZkd0Vakn3teKUt//J3c420BgnYgEOoVdTwYpBTSXCMJ88GOBCylmUBbtquGPli9tVs7LzsWIA==} dependencies: - '@babel/parser': 7.20.7 + '@babel/parser': 7.21.4 '@vue/compiler-core': 3.2.39 '@vue/compiler-dom': 3.2.39 '@vue/compiler-ssr': 3.2.39 @@ -9233,7 +9196,7 @@ packages: '@vue/shared': 3.2.39 estree-walker: 2.0.2 magic-string: 0.25.9 - postcss: 8.4.19 + postcss: 8.4.21 source-map: 0.6.1 /@vue/compiler-sfc@3.2.47: @@ -9516,13 +9479,13 @@ packages: read-pkg-up: 9.1.0 dev: true - /@wdio/config@8.7.0: - resolution: {integrity: sha512-zGUaM8PVbp0iDDlhUqWzFpwn2V3nko2k6/C80VggYAqNtmoE1R20DcYqknl8wZUZVlRNcpFVx98G3HqWf5kCQw==} + /@wdio/config@8.8.0: + resolution: {integrity: sha512-gm8gXqpiIR0EU9Blkqmxe+xsEoKS2EXpWrKlx2JXyx3Yf7By0UNsZVZHMSO8lLunzUjYIntpWYpmKmBmnlrnKQ==} engines: {node: ^16.13 || >=18} dependencies: '@wdio/logger': 8.6.6 - '@wdio/types': 8.7.0 - '@wdio/utils': 8.7.0 + '@wdio/types': 8.8.0 + '@wdio/utils': 8.8.0 decamelize: 6.0.0 deepmerge-ts: 5.0.0 glob: 9.3.0 @@ -9548,21 +9511,21 @@ packages: resolution: {integrity: sha512-vyJzqHJ5yOmfVyk5WWo6pRsJ2xhgWl3DVIBdDNR0wKrtFcm/g1jnB+pNf6Eb7NhCDh3oGul25bmhAwWDoxcFYA==} engines: {node: ^16.13 || >=18} dependencies: - '@types/node': 18.16.0 + '@types/node': 18.16.1 dev: true /@wdio/types@8.6.8: resolution: {integrity: sha512-hwlkQ6E8DNIFL/l8vHve3Zpl1t6Hqle7vtatEkAlrmbnExc7qI6Yw6SI5T/KiBSAi0ez1OypbGhdrbXFfywxng==} engines: {node: ^16.13 || >=18} dependencies: - '@types/node': 18.16.0 + '@types/node': 18.16.1 dev: true - /@wdio/types@8.7.0: - resolution: {integrity: sha512-baiWFVR28mOdI7gI9802cnicGmlbfSZvhLWjd0cD2ep8BhvdengEWyj4GG+qqjk9ZfraBgHunDT+cB6hdPIPow==} + /@wdio/types@8.8.0: + resolution: {integrity: sha512-Ai6yIlwWB32FUfvQKCqSa6nSyHIhSF5BOU9OfE7I2XYkLAJTxu8B6NORHQ+rgoppHSWc4D2V9r21y3etF8AGnQ==} engines: {node: ^16.13 || >=18} dependencies: - '@types/node': 18.16.0 + '@types/node': 18.16.1 dev: true /@wdio/utils@8.6.8: @@ -9575,12 +9538,12 @@ packages: p-iteration: 1.1.8 dev: true - /@wdio/utils@8.7.0: - resolution: {integrity: sha512-2g2CSNRp5yJEOww2S3cLtTmyJ0PEIEbhff0nL3R0d0bkDDxuO198iUr0Oszay3KmVqg+Jt0mZlhFlNIa593WnQ==} + /@wdio/utils@8.8.0: + resolution: {integrity: sha512-JUl1AwdtrJ3GzwtEmLyLohh29ycKkTKQ9S7K5Tc3p4kC3d9YmFKsifVj9riyJUFFrbICO0d35O63kNzsVMYj/w==} engines: {node: ^16.13 || >=18} dependencies: '@wdio/logger': 8.6.6 - '@wdio/types': 8.7.0 + '@wdio/types': 8.8.0 import-meta-resolve: 2.2.2 p-iteration: 1.1.8 dev: true @@ -9978,12 +9941,6 @@ packages: hasBin: true dev: true - /acorn@8.8.1: - resolution: {integrity: sha512-7zFpHzhnqYKrkYdUjF1HI1bzd0VygEGX8lFk4k5zVMqHEoES+P+7TKI+EvLO9WVMJ8eekdO0aDEK044xTXwPPA==} - engines: {node: '>=0.4.0'} - hasBin: true - dev: true - /acorn@8.8.2: resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==} engines: {node: '>=0.4.0'} @@ -10649,7 +10606,7 @@ packages: '@babel/core': 7.20.5 '@babel/helper-module-imports': 7.16.0 '@babel/plugin-syntax-jsx': 7.18.6(@babel/core@7.20.5) - '@babel/types': 7.21.3 + '@babel/types': 7.21.4 html-entities: 2.3.2 dev: true @@ -10666,7 +10623,7 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/compat-data': 7.20.10 + '@babel/compat-data': 7.21.4 '@babel/core': 7.18.13 '@babel/helper-define-polyfill-provider': 0.3.2(@babel/core@7.18.13) semver: 6.3.0 @@ -10679,7 +10636,7 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/compat-data': 7.20.10 + '@babel/compat-data': 7.21.4 '@babel/core': 7.21.4 '@babel/helper-define-polyfill-provider': 0.3.2(@babel/core@7.21.4) semver: 6.3.0 @@ -11537,7 +11494,7 @@ packages: engines: {node: '>=12.13.0'} hasBin: true dependencies: - '@types/node': 18.16.0 + '@types/node': 18.16.1 escape-string-regexp: 4.0.0 is-wsl: 2.2.0 lighthouse-logger: 1.3.0 @@ -11854,7 +11811,7 @@ packages: dev: true /concat-map@0.0.1: - resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=} + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} /concat-stream@1.6.2: resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==} @@ -12777,7 +12734,7 @@ packages: resolution: {integrity: sha512-Xv7NA5nUPU2ma/VMcAYRIMLX4+YrsEOXMG6ZGPVuU5tC9zylb5L7fkBCqjqYJ/kkVWibbIn3l63hMpnZ63AS5w==} engines: {node: ^16.13 || >=18} dependencies: - '@types/node': 18.16.0 + '@types/node': 18.16.1 '@wdio/config': 8.6.8 '@wdio/logger': 8.6.6 '@wdio/protocols': 8.6.6 @@ -12799,20 +12756,20 @@ packages: - utf-8-validate dev: true - /devtools@8.7.0(typescript@5.0.3): - resolution: {integrity: sha512-rl6yShHkh624wkCN9WWb7uUxGsgIfUAL2v6fcHQvPmI42BRRkbiXURq2oRds9fup3qyCv2UPeAlYtf4LQerkDQ==} + /devtools@8.8.0(typescript@5.0.3): + resolution: {integrity: sha512-FfvMEald7LtXIA12oo6wStlxSlAFy3NMAkVAHmu23g8jYhuhl2ASQQzVUFlBHKhVqLvbwSF0VuPZzaPRoz3uDQ==} engines: {node: ^16.13 || >=18} dependencies: - '@types/node': 18.16.0 - '@wdio/config': 8.7.0 + '@types/node': 18.16.1 + '@wdio/config': 8.8.0 '@wdio/logger': 8.6.6 '@wdio/protocols': 8.6.6 - '@wdio/types': 8.7.0 - '@wdio/utils': 8.7.0 + '@wdio/types': 8.8.0 + '@wdio/utils': 8.8.0 chrome-launcher: 0.15.1 edge-paths: 3.0.5 import-meta-resolve: 2.2.2 - puppeteer-core: 19.8.3(typescript@5.0.3) + puppeteer-core: 19.8.5(typescript@5.0.3) query-selector-shadow-dom: 1.0.1 ua-parser-js: 1.0.34 uuid: 9.0.0 @@ -14277,6 +14234,12 @@ packages: /estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + /estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + dependencies: + '@types/estree': 1.0.1 + dev: true + /esutils@2.0.3: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} @@ -15078,7 +15041,7 @@ packages: resolution: {integrity: sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==} engines: {node: '>= 4.0'} os: [darwin] - deprecated: fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2. + deprecated: The v1 package contains DANGEROUS / INSECURE binaries. Upgrade to safe fsevents v2 requiresBuild: true dependencies: bindings: 1.5.0 @@ -15485,8 +15448,8 @@ packages: - encoding dev: true - /happy-dom@9.1.7: - resolution: {integrity: sha512-tLkzW0w9EclIsV75hlCFStJa7CYSEUe+OVU8vK+3wzSvzFeXrGnCujuMcYQAPUXDl1CXoQ2ySaTZcqt3ZBJbSw==} + /happy-dom@9.1.9: + resolution: {integrity: sha512-OMbnoknA7iNNG/5fwt1JckCKc53QLLFo2ljzit1pCV9SC1TYwcQj0obq0QUTeqIf2p2skbFG69bo19YoSj/1DA==} dependencies: css.escape: 1.5.1 he: 1.2.0 @@ -16429,7 +16392,13 @@ packages: /is-reference@1.2.1: resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} dependencies: - '@types/estree': 1.0.0 + '@types/estree': 1.0.1 + dev: true + + /is-reference@3.0.1: + resolution: {integrity: sha512-baJJdQLiYaJdvFbJqXrcGv3WU3QCzBlUcI5QhbesIm6/xPsvmO+2CDoi/GMOFBQEQm+PXkwOPrp9KK5ozZsp2w==} + dependencies: + '@types/estree': 1.0.1 dev: true /is-regex@1.1.4: @@ -16689,7 +16658,7 @@ packages: '@jest/environment': 27.5.1 '@jest/test-result': 27.5.1 '@jest/types': 27.5.1 - '@types/node': 18.16.0 + '@types/node': 18.16.1 chalk: 4.1.2 co: 4.6.0 dedent: 0.7.0 @@ -16825,7 +16794,7 @@ packages: '@jest/environment': 27.5.1 '@jest/fake-timers': 27.5.1 '@jest/types': 27.5.1 - '@types/node': 18.16.0 + '@types/node': 18.16.1 jest-mock: 27.5.1 jest-util: 27.5.1 jsdom: 16.7.0 @@ -16843,7 +16812,7 @@ packages: '@jest/environment': 27.5.1 '@jest/fake-timers': 27.5.1 '@jest/types': 27.5.1 - '@types/node': 18.16.0 + '@types/node': 18.16.1 jest-mock: 27.5.1 jest-util: 27.5.1 dev: true @@ -16864,7 +16833,7 @@ packages: dependencies: '@jest/types': 26.6.2 '@types/graceful-fs': 4.1.5 - '@types/node': 18.16.0 + '@types/node': 18.16.1 anymatch: 3.1.2 fb-watchman: 2.0.1 graceful-fs: 4.2.10 @@ -16887,7 +16856,7 @@ packages: dependencies: '@jest/types': 27.5.1 '@types/graceful-fs': 4.1.5 - '@types/node': 18.16.0 + '@types/node': 18.16.1 anymatch: 3.1.2 fb-watchman: 2.0.1 graceful-fs: 4.2.10 @@ -16927,7 +16896,7 @@ packages: '@jest/source-map': 27.5.1 '@jest/test-result': 27.5.1 '@jest/types': 27.5.1 - '@types/node': 18.16.0 + '@types/node': 18.16.1 chalk: 4.1.2 co: 4.6.0 expect: 27.5.1 @@ -16991,7 +16960,7 @@ packages: resolution: {integrity: sha512-wRMAQt3HrLpxSubdnzOo68QoTfQ+NLXFzU0Heb18ZUzO2S9GgaXNEdQ4rpd0fI9dq2NXkpCk1IUWSqzYKji64A==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@babel/code-frame': 7.18.6 + '@babel/code-frame': 7.21.4 '@jest/types': 29.0.1 '@types/stack-utils': 2.0.1 chalk: 4.1.2 @@ -17007,7 +16976,7 @@ packages: engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: '@jest/types': 27.5.1 - '@types/node': 18.16.0 + '@types/node': 18.16.1 dev: true /jest-pnp-resolver@1.2.3(jest-resolve@27.5.1): @@ -17068,7 +17037,7 @@ packages: '@jest/test-result': 27.5.1 '@jest/transform': 27.5.1 '@jest/types': 27.5.1 - '@types/node': 18.16.0 + '@types/node': 18.16.1 chalk: 4.1.2 emittery: 0.8.1 graceful-fs: 4.2.10 @@ -17125,7 +17094,7 @@ packages: resolution: {integrity: sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g==} engines: {node: '>= 10.14.2'} dependencies: - '@types/node': 18.16.0 + '@types/node': 18.16.1 graceful-fs: 4.2.10 dev: true @@ -17133,7 +17102,7 @@ packages: resolution: {integrity: sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: - '@types/node': 18.16.0 + '@types/node': 18.16.1 graceful-fs: 4.2.10 dev: true @@ -17172,7 +17141,7 @@ packages: engines: {node: '>= 10.14.2'} dependencies: '@jest/types': 26.6.2 - '@types/node': 18.16.0 + '@types/node': 18.16.1 chalk: 4.1.2 graceful-fs: 4.2.10 is-ci: 2.0.0 @@ -17184,7 +17153,7 @@ packages: engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} dependencies: '@jest/types': 27.5.1 - '@types/node': 18.16.0 + '@types/node': 18.16.1 chalk: 4.1.2 ci-info: 3.7.0 graceful-fs: 4.2.10 @@ -17196,7 +17165,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.0.1 - '@types/node': 18.16.0 + '@types/node': 18.16.1 chalk: 4.1.2 ci-info: 3.7.0 graceful-fs: 4.2.10 @@ -17221,7 +17190,7 @@ packages: dependencies: '@jest/test-result': 27.5.1 '@jest/types': 27.5.1 - '@types/node': 18.16.0 + '@types/node': 18.16.1 ansi-escapes: 4.3.2 chalk: 4.1.2 jest-util: 27.5.1 @@ -17232,7 +17201,7 @@ packages: resolution: {integrity: sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==} engines: {node: '>= 10.13.0'} dependencies: - '@types/node': 18.16.0 + '@types/node': 18.16.1 merge-stream: 2.0.0 supports-color: 7.2.0 dev: true @@ -17241,7 +17210,7 @@ packages: resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} engines: {node: '>= 10.13.0'} dependencies: - '@types/node': 18.16.0 + '@types/node': 18.16.1 merge-stream: 2.0.0 supports-color: 8.1.1 dev: true @@ -17420,7 +17389,7 @@ packages: optional: true dependencies: abab: 2.0.6 - acorn: 8.8.1 + acorn: 8.8.2 acorn-globals: 7.0.1 cssom: 0.5.0 cssstyle: 2.3.0 @@ -18480,8 +18449,8 @@ packages: brace-expansion: 2.0.1 dev: true - /minimatch@8.0.4: - resolution: {integrity: sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==} + /minimatch@9.0.0: + resolution: {integrity: sha512-0jJj8AvgKqWN05mrwuqi8QYKx1WmYSUoKSxu5Qhs9prezTz10sxAHGNZe9J9cqIJzta8DWsleh2KaVaLl6Ru2w==} engines: {node: '>=16 || 14 >=14.17'} dependencies: brace-expansion: 2.0.1 @@ -19497,7 +19466,7 @@ packages: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} dependencies: - '@babel/code-frame': 7.18.6 + '@babel/code-frame': 7.21.4 error-ex: 1.3.2 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 @@ -19670,6 +19639,14 @@ packages: resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==} dev: true + /periscopic@3.1.0: + resolution: {integrity: sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==} + dependencies: + '@types/estree': 1.0.1 + estree-walker: 3.0.3 + is-reference: 3.0.1 + dev: true + /picocolors@0.2.1: resolution: {integrity: sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA==} dev: true @@ -19972,14 +19949,6 @@ packages: source-map: 0.6.1 dev: true - /postcss@8.4.19: - resolution: {integrity: sha512-h+pbPsyhlYj6N2ozBmHhHrs9DzGmbaarbLvWipMRO7RLS+v4onj26MPFXA5OBYFxyqYhUJK456SwDcY9H2/zsA==} - engines: {node: ^10 || ^12 || >=14} - dependencies: - nanoid: 3.3.4 - picocolors: 1.0.0 - source-map-js: 1.0.2 - /postcss@8.4.21: resolution: {integrity: sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==} engines: {node: ^10 || ^12 || >=14} @@ -20247,8 +20216,8 @@ packages: - utf-8-validate dev: true - /puppeteer-core@19.8.3(typescript@5.0.3): - resolution: {integrity: sha512-+gPT43K3trUIr+7+tNjCg95vMgM9RkFIeeyck3SXUTBpGkrf6sxfWckncqY8MnzHfRcyapvztKNmqvJ+Ngukyg==} + /puppeteer-core@19.8.5(typescript@5.0.3): + resolution: {integrity: sha512-zoGhim/oBQbkND6h4Xz4X7l5DkWVH9wH7z0mVty5qa/c0P1Yad47t/npVtt2xS10BiQwzztWKx7Pa2nJ5yykdw==} engines: {node: '>=14.14.0'} peerDependencies: typescript: '>= 4.7.4' @@ -20256,6 +20225,7 @@ packages: typescript: optional: true dependencies: + '@puppeteer/browsers': 0.4.0(typescript@5.0.3) chromium-bidi: 0.4.6(devtools-protocol@0.0.1107588) cross-fetch: 3.1.5 debug: 4.3.4(supports-color@8.1.1) @@ -20436,7 +20406,7 @@ packages: hasBin: true dependencies: '@babel/core': 7.21.4 - '@babel/generator': 7.20.7 + '@babel/generator': 7.21.4 '@babel/runtime': 7.18.9 ast-types: 0.14.2 commander: 2.20.3 @@ -20455,7 +20425,7 @@ packages: hasBin: true dependencies: '@babel/core': 7.21.4 - '@babel/generator': 7.20.7 + '@babel/generator': 7.21.4 ast-types: 0.14.2 commander: 2.20.3 doctrine: 3.0.0 @@ -21752,9 +21722,9 @@ packages: peerDependencies: solid-js: ^1.3 dependencies: - '@babel/generator': 7.20.7 + '@babel/generator': 7.21.4 '@babel/helper-module-imports': 7.18.6 - '@babel/types': 7.21.3 + '@babel/types': 7.21.4 solid-js: 1.5.2 dev: true @@ -23148,6 +23118,24 @@ packages: vfile: 4.2.1 dev: true + /unimport@1.3.0(rollup@3.20.2): + resolution: {integrity: sha512-fOkrdxglsHd428yegH0wPH/6IfaSdDeMXtdRGn6en/ccyzc2aaoxiUTMrJyc6Bu+xoa18RJRPMfLUHEzjz8atw==} + dependencies: + '@rollup/pluginutils': 5.0.2(rollup@3.20.2) + escape-string-regexp: 5.0.0 + fast-glob: 3.2.12 + local-pkg: 0.4.3 + magic-string: 0.27.0 + mlly: 1.2.0 + pathe: 1.1.0 + pkg-types: 1.0.2 + scule: 1.0.0 + strip-literal: 1.0.1 + unplugin: 1.3.1 + transitivePeerDependencies: + - rollup + dev: true + /unimport@3.0.5(rollup@3.20.2): resolution: {integrity: sha512-enRW0sVcTBxUZY6R2iumWMUsPbGC5GW9jM89VtF0pFUz9vDPrvEmOAklbSE/a4fqhjW/7dMWBvfLw/IDlBaPdQ==} dependencies: @@ -23334,82 +23322,73 @@ packages: engines: {node: '>= 0.8'} dev: true - /unplugin-auto-import@0.15.2(@vueuse/core@9.13.0)(rollup@3.20.2): - resolution: {integrity: sha512-Wivfu+xccgvEZG8QtZcIvt6napfX9wyOFqM//7FHOtev8+k+dp3ykiqsEl6TODgHmqTTBeQX4Ah1JvRgUNjlkg==} + /unplugin-auto-import@0.12.1(rollup@3.20.2): + resolution: {integrity: sha512-J/3ZORq5YGKG+8D5vLLOgqaHNK77izlVN07mQ752yRLqBNDbJiwPRSnUwwYqH5N6rDay1SqnJCHaUdbJ9QMI2w==} engines: {node: '>=14'} peerDependencies: - '@nuxt/kit': ^3.2.2 '@vueuse/core': '*' peerDependenciesMeta: - '@nuxt/kit': - optional: true '@vueuse/core': optional: true dependencies: '@antfu/utils': 0.7.2 '@rollup/pluginutils': 5.0.2(rollup@3.20.2) - '@vueuse/core': 9.13.0(vue@3.2.47) local-pkg: 0.4.3 - magic-string: 0.30.0 - minimatch: 7.4.5 - unimport: 3.0.5(rollup@3.20.2) + magic-string: 0.27.0 + unimport: 1.3.0(rollup@3.20.2) unplugin: 1.3.1 transitivePeerDependencies: - rollup dev: true - /unplugin-auto-import@0.7.2(esbuild@0.17.15)(rollup@3.20.2)(vite@4.2.1): - resolution: {integrity: sha512-VzaYUa2VByUT70WSFlOXoovyWuwC/8ePKQUC9fhU+BRmvTC7qhCVgChH/NieWMEVgyT+HhacxM+W7xMEOmA+MA==} + /unplugin-auto-import@0.15.2(@vueuse/core@9.13.0)(rollup@3.20.2): + resolution: {integrity: sha512-Wivfu+xccgvEZG8QtZcIvt6napfX9wyOFqM//7FHOtev8+k+dp3ykiqsEl6TODgHmqTTBeQX4Ah1JvRgUNjlkg==} engines: {node: '>=14'} peerDependencies: + '@nuxt/kit': ^3.2.2 '@vueuse/core': '*' peerDependenciesMeta: + '@nuxt/kit': + optional: true '@vueuse/core': optional: true dependencies: - '@antfu/utils': 0.5.2 - '@rollup/pluginutils': 4.2.1 + '@antfu/utils': 0.7.2 + '@rollup/pluginutils': 5.0.2(rollup@3.20.2) + '@vueuse/core': 9.13.0(vue@3.2.47) local-pkg: 0.4.3 - magic-string: 0.26.7 - resolve: 1.22.1 - unplugin: 0.6.3(esbuild@0.17.15)(rollup@3.20.2)(vite@4.2.1) + magic-string: 0.30.0 + minimatch: 7.4.5 + unimport: 3.0.5(rollup@3.20.2) + unplugin: 1.3.1 transitivePeerDependencies: - - esbuild - rollup - - vite - - webpack dev: true - /unplugin-vue-components@0.19.6(esbuild@0.17.15)(rollup@3.20.2)(vite@4.2.1)(vue@3.2.47): - resolution: {integrity: sha512-APvrJ9Hpid1MLT0G4PWerMJgARhNw6dzz0pcCwCxaO2DR7VyvDacMqjOQNC6ukq7FSw3wzD8VH+9i3EFXwkGmw==} + /unplugin-vue-components@0.22.12(rollup@3.20.2)(vue@3.2.47): + resolution: {integrity: sha512-FxyzsuBvMCYPIk+8cgscGBQ345tvwVu+qY5IhE++eorkyvA4Z1TiD/HCiim+Kbqozl10i4K+z+NCa2WO2jexRA==} engines: {node: '>=14'} peerDependencies: '@babel/parser': ^7.15.8 - '@babel/traverse': ^7.15.4 vue: 2 || 3 peerDependenciesMeta: '@babel/parser': optional: true - '@babel/traverse': - optional: true dependencies: - '@antfu/utils': 0.5.2 - '@rollup/pluginutils': 4.2.1 + '@antfu/utils': 0.7.2 + '@rollup/pluginutils': 5.0.2(rollup@3.20.2) chokidar: 3.5.3 debug: 4.3.4(supports-color@8.1.1) fast-glob: 3.2.12 local-pkg: 0.4.3 - magic-string: 0.26.7 + magic-string: 0.27.0 minimatch: 5.1.1 resolve: 1.22.1 - unplugin: 0.6.3(esbuild@0.17.15)(rollup@3.20.2)(vite@4.2.1) + unplugin: 1.3.1 vue: 3.2.47 transitivePeerDependencies: - - esbuild - rollup - supports-color - - vite - - webpack dev: true /unplugin-vue-components@0.24.1(rollup@2.79.1)(vue@3.2.47): @@ -23470,31 +23449,6 @@ packages: - supports-color dev: true - /unplugin@0.6.3(esbuild@0.17.15)(rollup@3.20.2)(vite@4.2.1): - resolution: {integrity: sha512-CoW88FQfCW/yabVc4bLrjikN9HC8dEvMU4O7B6K2jsYMPK0l6iAnd9dpJwqGcmXJKRCU9vwSsy653qg+RK0G6A==} - peerDependencies: - esbuild: '>=0.13' - rollup: ^2.50.0 - vite: ^2.3.0 - webpack: 4 || 5 - peerDependenciesMeta: - esbuild: - optional: true - rollup: - optional: true - vite: - optional: true - webpack: - optional: true - dependencies: - chokidar: 3.5.3 - esbuild: 0.17.15 - rollup: 3.20.2 - vite: 4.2.1(@types/node@18.15.11) - webpack-sources: 3.2.3 - webpack-virtual-modules: 0.4.6 - dev: true - /unplugin@1.3.1: resolution: {integrity: sha512-h4uUTIvFBQRxUKS2Wjys6ivoeofGhxzTe2sRWlooyjHXVttcVfV/JiavNd3d4+jty0SVV0dxGw9AkY9MwiaCEw==} dependencies: @@ -23832,7 +23786,7 @@ packages: optionalDependencies: fsevents: 2.3.2 - /vite@4.2.1(@types/node@18.16.0): + /vite@4.2.1(@types/node@18.16.1): resolution: {integrity: sha512-7MKhqdy0ISo4wnvwtqZkjke6XN4taqQ2TBaTccLIpOKv7Vp2h4Y+NpmWCnGDeSvvn45KxvWgGyb0MkHvY1vgbg==} engines: {node: ^14.18.0 || >=16.0.0} hasBin: true @@ -23857,7 +23811,7 @@ packages: terser: optional: true dependencies: - '@types/node': 18.16.0 + '@types/node': 18.16.1 esbuild: 0.17.15 postcss: 8.4.21 resolve: 1.22.1 @@ -23917,7 +23871,7 @@ packages: dependencies: '@docsearch/css': 3.3.3 '@docsearch/js': 3.3.3(@algolia/client-search@4.14.2) - '@vitejs/plugin-vue': 4.1.0(vite@4.2.1)(vue@3.2.47) + '@vitejs/plugin-vue': 4.2.1(vite@4.2.1)(vue@3.2.47) '@vue/devtools-api': 6.5.0 '@vueuse/core': 9.13.0(vue@3.2.47) body-scroll-lock: 4.0.0-beta.0 @@ -24158,7 +24112,7 @@ packages: resolution: {integrity: sha512-v+43Z4miGKa1JaFAIxgK5AedBgHV/7MI+jd3fJao24R/KWYNgC9GD4BUD6LxC7AChuyRdA1/cN3NjwrPTg0ujg==} engines: {node: ^16.13 || >=18} dependencies: - '@types/node': 18.16.0 + '@types/node': 18.16.1 '@types/ws': 8.5.4 '@wdio/config': 8.6.8 '@wdio/logger': 8.6.6 @@ -24174,17 +24128,17 @@ packages: - utf-8-validate dev: true - /webdriver@8.7.0: - resolution: {integrity: sha512-UYstwTX6OtYJUnkUv6hI1XmSzrPMPqglHPTcanhS+EI1Ve4JmA8bSmkzL08gmiAroBjgLtqzpEcL5KuyAPEiLw==} + /webdriver@8.8.0: + resolution: {integrity: sha512-LqO06orjZlODkQm5npEkuXtBEdVc+tKZAzX468Wra71U9naUZN7YrMjboHvbtsUuiRLWt0RzByO5VCWRS0o/Zg==} engines: {node: ^16.13 || >=18} dependencies: - '@types/node': 18.16.0 + '@types/node': 18.16.1 '@types/ws': 8.5.4 - '@wdio/config': 8.7.0 + '@wdio/config': 8.8.0 '@wdio/logger': 8.6.6 '@wdio/protocols': 8.6.6 - '@wdio/types': 8.7.0 - '@wdio/utils': 8.7.0 + '@wdio/types': 8.8.0 + '@wdio/utils': 8.8.0 deepmerge-ts: 5.0.0 got: 12.6.0 ky: 0.33.3 @@ -24198,7 +24152,7 @@ packages: resolution: {integrity: sha512-fyRdDc7vUBje5II0NdpjTTGh9BeTRtva+pDO52dmHiou1lF5Zths7/RlYpRb8xqYeWnCsAaSb7NTkskDvZxbow==} engines: {node: ^16.13 || >=18} dependencies: - '@types/node': 18.16.0 + '@types/node': 18.16.1 '@wdio/config': 8.6.8 '@wdio/logger': 8.6.6 '@wdio/protocols': 8.6.6 @@ -24231,35 +24185,35 @@ packages: - utf-8-validate dev: true - /webdriverio@8.7.0(typescript@5.0.3): - resolution: {integrity: sha512-drZKdS1IdGeYOKxZWAh/AOHgbz9oGAM3YVcgKun3npLTZGNh7jSfsrUYRmJe+px8Xz7Ay5Qz30QgqtbEqk7kBQ==} + /webdriverio@8.8.0(typescript@5.0.3): + resolution: {integrity: sha512-QMce84O2CX/T3GUowO0/4V16RFE5METrQ3fjeWx0oLq/6rvZJe3X97Tdk5Xnlpcma6Ot+zhIsU8zWsMgi07wCA==} engines: {node: ^16.13 || >=18} dependencies: - '@types/node': 18.16.0 - '@wdio/config': 8.7.0 + '@types/node': 18.16.1 + '@wdio/config': 8.8.0 '@wdio/logger': 8.6.6 '@wdio/protocols': 8.6.6 '@wdio/repl': 8.6.6 - '@wdio/types': 8.7.0 - '@wdio/utils': 8.7.0 + '@wdio/types': 8.8.0 + '@wdio/utils': 8.8.0 archiver: 5.3.1 aria-query: 5.0.2 css-shorthand-properties: 1.1.1 css-value: 0.0.1 - devtools: 8.7.0(typescript@5.0.3) + devtools: 8.8.0(typescript@5.0.3) devtools-protocol: 0.0.1124027 grapheme-splitter: 1.0.4 import-meta-resolve: 2.2.2 is-plain-obj: 4.1.0 lodash.clonedeep: 4.5.0 lodash.zip: 4.2.0 - minimatch: 8.0.4 - puppeteer-core: 19.8.3(typescript@5.0.3) + minimatch: 9.0.0 + puppeteer-core: 19.8.5(typescript@5.0.3) query-selector-shadow-dom: 1.0.1 resq: 1.11.0 rgb2hex: 0.2.5 serialize-error: 8.1.0 - webdriver: 8.7.0 + webdriver: 8.8.0 transitivePeerDependencies: - bufferutil - encoding @@ -24349,10 +24303,6 @@ packages: - supports-color dev: true - /webpack-virtual-modules@0.4.6: - resolution: {integrity: sha512-5tyDlKLqPfMqjT3Q9TAqf2YqjwmnUleZwzJi1A5qXnlBCdj2AtOJ6wAWdglTIDOPgOiOrXeBeFcsQ8+aGQ6QbA==} - dev: true - /webpack-virtual-modules@0.5.0: resolution: {integrity: sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw==} dev: true diff --git a/test/browser/specs/runner.test.mjs b/test/browser/specs/runner.test.mjs index b6a0d460a02d..976cf0293f00 100644 --- a/test/browser/specs/runner.test.mjs +++ b/test/browser/specs/runner.test.mjs @@ -17,7 +17,7 @@ await test('tests are actually running', async () => { const browserResult = await readFile('./browser.json', 'utf-8') const browserResultJson = JSON.parse(browserResult) - assert.ok(browserResultJson.testResults.length === 6, 'Not all the tests have been run') + assert.ok(browserResultJson.testResults.length === 7, 'Not all the tests have been run') for (const result of browserResultJson.testResults) assert.ok(result.status === 'passed', `${result.name} has failed`) diff --git a/test/browser/src/actions.ts b/test/browser/src/actions.ts new file mode 100644 index 000000000000..55ae85133596 --- /dev/null +++ b/test/browser/src/actions.ts @@ -0,0 +1,3 @@ +export function plus(a: number, b: number) { + return a + b +} diff --git a/test/browser/src/calculator.ts b/test/browser/src/calculator.ts new file mode 100644 index 000000000000..9d9d67cfe878 --- /dev/null +++ b/test/browser/src/calculator.ts @@ -0,0 +1,8 @@ +import { plus } from './actions' + +export function calculator(operation: 'plus', a: number, b: number) { + if (operation === 'plus') + return plus(a, b) + + throw new Error('unknown operation') +} diff --git a/test/browser/test/mocked.test.ts b/test/browser/test/mocked.test.ts new file mode 100644 index 000000000000..4441b13ae301 --- /dev/null +++ b/test/browser/test/mocked.test.ts @@ -0,0 +1,30 @@ +import { expect, test, vi } from 'vitest' +import * as actions from '../src/actions' +import { calculator } from '../src/calculator' +import * as calculatorModule from '../src/calculator' + +test('spyOn works on ESM', () => { + vi.spyOn(actions, 'plus').mockReturnValue(30) + expect(calculator('plus', 1, 2)).toBe(30) + vi.mocked(actions.plus).mockRestore() + expect(calculator('plus', 1, 2)).toBe(3) +}) + +test('has module name', () => { + expect(String(actions)).toBe('[object Module]') + expect(actions[Symbol.toStringTag]).toBe('Module') +}) + +test('exports are correct', () => { + expect(Object.keys(actions)).toEqual(['plus']) + expect(Object.keys(calculatorModule)).toEqual(['calculator']) + expect(calculatorModule.calculator).toBe(calculator) +}) + +test('imports are still the same', async () => { + // @ts-expect-error typescript resolution + await expect(import('../src/calculator')).resolves.toBe(calculatorModule) + // @ts-expect-error typescript resolution + // eslint-disable-next-line @typescript-eslint/quotes + await expect(import(`../src/calculator`)).resolves.toBe(calculatorModule) +}) diff --git a/test/core/package.json b/test/core/package.json index 0186820d3b83..998f1603a476 100644 --- a/test/core/package.json +++ b/test/core/package.json @@ -9,6 +9,7 @@ "@vitest/expect": "workspace:*", "@vitest/runner": "workspace:*", "@vitest/utils": "workspace:*", + "acorn": "^8.8.2", "tinyspy": "^1.0.2", "url": "^0.11.0", "vitest": "workspace:*" diff --git a/test/core/test/injector-esm.test.ts b/test/core/test/injector-esm.test.ts new file mode 100644 index 000000000000..e08ac7cac236 --- /dev/null +++ b/test/core/test/injector-esm.test.ts @@ -0,0 +1,927 @@ +import { Parser } from 'acorn' +import { injectVitestModule } from '@vitest/browser/src/node/esmInjector' +import { expect, test } from 'vitest' +import { transformWithEsbuild } from 'vite' + +function parse(code: string, options: any) { + return Parser.parse(code, options) +} + +function injectSimpleCode(code: string) { + return injectVitestModule(code, '/test.js', parse, { + cacheDir: '/tmp', + })?.code +} + +test('default import', async () => { + expect( + injectSimpleCode('import foo from \'vue\';console.log(foo.bar)'), + ).toMatchInlineSnapshot(` + "import { __vi_inject__ as __vi_esm_0__ } from 'vue' + console.log(__vi_esm_0__.default.bar)" + `) +}) + +test('named import', async () => { + expect( + injectSimpleCode( + 'import { ref } from \'vue\';function foo() { return ref(0) }', + ), + ).toMatchInlineSnapshot(` + "import { __vi_inject__ as __vi_esm_0__ } from 'vue' + function foo() { return __vi_esm_0__.ref(0) }" + `) +}) + +test('namespace import', async () => { + expect( + injectSimpleCode( + 'import * as vue from \'vue\';function foo() { return vue.ref(0) }', + ), + ).toMatchInlineSnapshot(` + "import { __vi_inject__ as __vi_esm_0__ } from 'vue' + function foo() { return __vi_esm_0__.ref(0) }" + `) +}) + +test('export function declaration', async () => { + expect(injectSimpleCode('export function foo() {}')) + .toMatchInlineSnapshot(` + "const __vi_inject__ = { [Symbol.toStringTag]: \\"Module\\" }; + function foo() {} + Object.defineProperty(__vi_inject__, \\"foo\\", { enumerable: true, configurable: true, get(){ return foo }}); + export { __vi_inject__ }" + `) +}) + +test('export class declaration', async () => { + expect(await injectSimpleCode('export class foo {}')) + .toMatchInlineSnapshot(` + "const __vi_inject__ = { [Symbol.toStringTag]: \\"Module\\" }; + class foo {} + Object.defineProperty(__vi_inject__, \\"foo\\", { enumerable: true, configurable: true, get(){ return foo }}); + export { __vi_inject__ }" + `) +}) + +test('export var declaration', async () => { + expect(await injectSimpleCode('export const a = 1, b = 2')) + .toMatchInlineSnapshot(` + "const __vi_inject__ = { [Symbol.toStringTag]: \\"Module\\" }; + const a = 1, b = 2 + Object.defineProperty(__vi_inject__, \\"a\\", { enumerable: true, configurable: true, get(){ return a }}); + Object.defineProperty(__vi_inject__, \\"b\\", { enumerable: true, configurable: true, get(){ return b }}); + export { __vi_inject__ }" + `) +}) + +test('export named', async () => { + expect( + injectSimpleCode('const a = 1, b = 2; export { a, b as c }'), + ).toMatchInlineSnapshot(` + "const __vi_inject__ = { [Symbol.toStringTag]: \\"Module\\" }; + const a = 1, b = 2; + Object.defineProperty(__vi_inject__, \\"a\\", { enumerable: true, configurable: true, get(){ return a }}); + Object.defineProperty(__vi_inject__, \\"c\\", { enumerable: true, configurable: true, get(){ return b }}); + export { __vi_inject__ }" + `) +}) + +test('export named from', async () => { + expect( + injectSimpleCode('export { ref, computed as c } from \'vue\''), + ).toMatchInlineSnapshot(` + "const __vi_inject__ = { [Symbol.toStringTag]: \\"Module\\" }; + const { __vi_inject__: __vi_esm_0__ } = await import(\\"vue\\"); + + Object.defineProperty(__vi_inject__, \\"ref\\", { enumerable: true, configurable: true, get(){ return __vi_esm_0__.ref }}); + Object.defineProperty(__vi_inject__, \\"c\\", { enumerable: true, configurable: true, get(){ return __vi_esm_0__.computed }}); + export { __vi_inject__ }" + `) +}) + +test('named exports of imported binding', async () => { + expect( + injectSimpleCode( + 'import {createApp} from \'vue\';export {createApp}', + ), + ).toMatchInlineSnapshot(` + "const __vi_inject__ = { [Symbol.toStringTag]: \\"Module\\" }; + import { __vi_inject__ as __vi_esm_0__ } from 'vue' + + Object.defineProperty(__vi_inject__, \\"createApp\\", { enumerable: true, configurable: true, get(){ return __vi_esm_0__.createApp }}); + export { __vi_inject__ }" + `) +}) + +test('export * from', async () => { + expect( + injectSimpleCode( + 'export * from \'vue\'\n' + 'export * from \'react\'', + ), + ).toMatchInlineSnapshot(` + "const __vi_inject__ = { [Symbol.toStringTag]: \\"Module\\" }; + const { __vi_inject__: __vi_esm_0__ } = await import(\\"vue\\"); + __vi_export_all__(__vi_inject__, __vi_esm_0__); + const { __vi_inject__: __vi_esm_1__ } = await import(\\"react\\"); + __vi_export_all__(__vi_inject__, __vi_esm_1__); + + + export { __vi_inject__ }" + `) +}) + +test('export * as from', async () => { + expect(injectSimpleCode('export * as foo from \'vue\'')) + .toMatchInlineSnapshot(` + "const __vi_inject__ = { [Symbol.toStringTag]: \\"Module\\" }; + const { __vi_inject__: __vi_esm_0__ } = await import(\\"vue\\"); + + Object.defineProperty(__vi_inject__, \\"foo\\", { enumerable: true, configurable: true, get(){ return __vi_esm_0__ }}); + export { __vi_inject__ }" + `) +}) + +test('export default', async () => { + expect( + injectSimpleCode('export default {}'), + ).toMatchInlineSnapshot(` + "const __vi_inject__ = { [Symbol.toStringTag]: \\"Module\\" }; + __vi_inject__.default = {} + export { __vi_inject__ }" + `) +}) + +test('export then import minified', async () => { + expect( + injectSimpleCode( + 'export * from \'vue\';import {createApp} from \'vue\';', + ), + ).toMatchInlineSnapshot(` + "const __vi_inject__ = { [Symbol.toStringTag]: \\"Module\\" }; + import { __vi_inject__ as __vi_esm_0__ } from 'vue' + const { __vi_inject__: __vi_esm_1__ } = await import(\\"vue\\"); + __vi_export_all__(__vi_inject__, __vi_esm_1__); + + export { __vi_inject__ }" + `) +}) + +test('hoist import to top', async () => { + expect( + injectSimpleCode( + 'path.resolve(\'server.js\');import path from \'node:path\';', + ), + ).toMatchInlineSnapshot(` + "import { __vi_inject__ as __vi_esm_0__ } from 'node:path' + __vi_esm_0__.default.resolve('server.js');" + `) +}) + +// test('import.meta', async () => { +// expect( +// injectSimpleCode('console.log(import.meta.url)'), +// ).toMatchInlineSnapshot('"console.log(__vite_ssr_import_meta__.url)"') +// }) + +test('dynamic import', async () => { + const result = injectSimpleCode( + 'export const i = () => import(\'./foo\')', + ) + expect(result).toMatchInlineSnapshot(` + "const __vi_inject__ = { [Symbol.toStringTag]: \\"Module\\" }; + const i = () => __vi_wrap_module__(import('./foo')) + export { __vi_inject__ }" + `) +}) + +test('do not rewrite method definition', async () => { + const result = injectSimpleCode( + 'import { fn } from \'vue\';class A { fn() { fn() } }', + ) + expect(result).toMatchInlineSnapshot(` + "import { __vi_inject__ as __vi_esm_0__ } from 'vue' + class A { fn() { __vi_esm_0__.fn() } }" + `) +}) + +test('do not rewrite when variable is in scope', async () => { + const result = injectSimpleCode( + 'import { fn } from \'vue\';function A(){ const fn = () => {}; return { fn }; }', + ) + expect(result).toMatchInlineSnapshot(` + "import { __vi_inject__ as __vi_esm_0__ } from 'vue' + function A(){ const fn = () => {}; return { fn }; }" + `) +}) + +// #5472 +test('do not rewrite when variable is in scope with object destructuring', async () => { + const result = injectSimpleCode( + 'import { fn } from \'vue\';function A(){ let {fn, test} = {fn: \'foo\', test: \'bar\'}; return { fn }; }', + ) + expect(result).toMatchInlineSnapshot(` + "import { __vi_inject__ as __vi_esm_0__ } from 'vue' + function A(){ let {fn, test} = {fn: 'foo', test: 'bar'}; return { fn }; }" + `) +}) + +// #5472 +test('do not rewrite when variable is in scope with array destructuring', async () => { + const result = injectSimpleCode( + 'import { fn } from \'vue\';function A(){ let [fn, test] = [\'foo\', \'bar\']; return { fn }; }', + ) + expect(result).toMatchInlineSnapshot(` + "import { __vi_inject__ as __vi_esm_0__ } from 'vue' + function A(){ let [fn, test] = ['foo', 'bar']; return { fn }; }" + `) +}) + +// #5727 +test('rewrite variable in string interpolation in function nested arguments', async () => { + const result = injectSimpleCode( + // eslint-disable-next-line no-template-curly-in-string + 'import { fn } from \'vue\';function A({foo = `test${fn}`} = {}){ return {}; }', + ) + expect(result).toMatchInlineSnapshot(` + "import { __vi_inject__ as __vi_esm_0__ } from 'vue' + function A({foo = \`test\${__vi_esm_0__.fn}\`} = {}){ return {}; }" + `) +}) + +// #6520 +test('rewrite variables in default value of destructuring params', async () => { + const result = injectSimpleCode( + 'import { fn } from \'vue\';function A({foo = fn}){ return {}; }', + ) + expect(result).toMatchInlineSnapshot(` + "import { __vi_inject__ as __vi_esm_0__ } from 'vue' + function A({foo = __vi_esm_0__.fn}){ return {}; }" + `) +}) + +test('do not rewrite when function declaration is in scope', async () => { + const result = injectSimpleCode( + 'import { fn } from \'vue\';function A(){ function fn() {}; return { fn }; }', + ) + expect(result).toMatchInlineSnapshot(` + "import { __vi_inject__ as __vi_esm_0__ } from 'vue' + function A(){ function fn() {}; return { fn }; }" + `) +}) + +test('do not rewrite catch clause', async () => { + const result = injectSimpleCode( + 'import {error} from \'./dependency\';try {} catch(error) {}', + ) + expect(result).toMatchInlineSnapshot(` + "import { __vi_inject__ as __vi_esm_0__ } from './dependency' + try {} catch(error) {}" + `) +}) + +// #2221 +test('should declare variable for imported super class', async () => { + expect( + injectSimpleCode( + 'import { Foo } from \'./dependency\';' + 'class A extends Foo {}', + ), + ).toMatchInlineSnapshot(` + "import { __vi_inject__ as __vi_esm_0__ } from './dependency' + const Foo = __vi_esm_0__.Foo; + class A extends Foo {}" + `) + + // exported classes: should prepend the declaration at root level, before the + // first class that uses the binding + expect( + injectSimpleCode( + 'import { Foo } from \'./dependency\';' + + 'export default class A extends Foo {}\n' + + 'export class B extends Foo {}', + ), + ).toMatchInlineSnapshot(` + "const __vi_inject__ = { [Symbol.toStringTag]: \\"Module\\" }; + import { __vi_inject__ as __vi_esm_0__ } from './dependency' + const Foo = __vi_esm_0__.Foo; + class A extends Foo {} + class B extends Foo {} + Object.defineProperty(__vi_inject__, \\"B\\", { enumerable: true, configurable: true, get(){ return B }}); + Object.defineProperty(__vi_inject__, \\"default\\", { enumerable: true, configurable: true, value: A }); + export { __vi_inject__ }" + `) +}) + +// #4049 +test('should handle default export variants', async () => { + // default anonymous functions + expect(injectSimpleCode('export default function() {}\n')) + .toMatchInlineSnapshot(` + "const __vi_inject__ = { [Symbol.toStringTag]: \\"Module\\" }; + __vi_inject__.default = function() {} + + export { __vi_inject__ }" + `) + // default anonymous class + expect(injectSimpleCode('export default class {}\n')) + .toMatchInlineSnapshot(` + "const __vi_inject__ = { [Symbol.toStringTag]: \\"Module\\" }; + __vi_inject__.default = class {} + + export { __vi_inject__ }" + `) + // default named functions + expect( + injectSimpleCode( + 'export default function foo() {}\n' + + 'foo.prototype = Object.prototype;', + ), + ).toMatchInlineSnapshot(` + "const __vi_inject__ = { [Symbol.toStringTag]: \\"Module\\" }; + function foo() {} + foo.prototype = Object.prototype; + Object.defineProperty(__vi_inject__, \\"default\\", { enumerable: true, configurable: true, value: foo }); + export { __vi_inject__ }" + `) + // default named classes + expect( + injectSimpleCode( + 'export default class A {}\n' + 'export class B extends A {}', + ), + ).toMatchInlineSnapshot(` + "const __vi_inject__ = { [Symbol.toStringTag]: \\"Module\\" }; + class A {} + class B extends A {} + Object.defineProperty(__vi_inject__, \\"B\\", { enumerable: true, configurable: true, get(){ return B }}); + Object.defineProperty(__vi_inject__, \\"default\\", { enumerable: true, configurable: true, value: A }); + export { __vi_inject__ }" + `) +}) + +test('overwrite bindings', async () => { + expect( + injectSimpleCode( + 'import { inject } from \'vue\';' + + 'const a = { inject }\n' + + 'const b = { test: inject }\n' + + 'function c() { const { test: inject } = { test: true }; console.log(inject) }\n' + + 'const d = inject\n' + + 'function f() { console.log(inject) }\n' + + 'function e() { const { inject } = { inject: true } }\n' + + 'function g() { const f = () => { const inject = true }; console.log(inject) }\n', + ), + ).toMatchInlineSnapshot(` + "import { __vi_inject__ as __vi_esm_0__ } from 'vue' + const a = { inject: __vi_esm_0__.inject } + const b = { test: __vi_esm_0__.inject } + function c() { const { test: inject } = { test: true }; console.log(inject) } + const d = __vi_esm_0__.inject + function f() { console.log(__vi_esm_0__.inject) } + function e() { const { inject } = { inject: true } } + function g() { const f = () => { const inject = true }; console.log(__vi_esm_0__.inject) } + " + `) +}) + +test('Empty array pattern', async () => { + expect( + injectSimpleCode('const [, LHS, RHS] = inMatch;'), + ).toMatchInlineSnapshot('"const [, LHS, RHS] = inMatch;"') +}) + +test('function argument destructure', async () => { + expect( + injectSimpleCode( + ` +import { foo, bar } from 'foo' +const a = ({ _ = foo() }) => {} +function b({ _ = bar() }) {} +function c({ _ = bar() + foo() }) {} +`, + ), + ).toMatchInlineSnapshot(` + "import { __vi_inject__ as __vi_esm_0__ } from 'foo' + + + const a = ({ _ = __vi_esm_0__.foo() }) => {} + function b({ _ = __vi_esm_0__.bar() }) {} + function c({ _ = __vi_esm_0__.bar() + __vi_esm_0__.foo() }) {} + " + `) +}) + +test('object destructure alias', async () => { + expect( + injectSimpleCode( + ` +import { n } from 'foo' +const a = () => { + const { type: n = 'bar' } = {} + console.log(n) +} +`, + ), + ).toMatchInlineSnapshot(` + "import { __vi_inject__ as __vi_esm_0__ } from 'foo' + + + const a = () => { + const { type: n = 'bar' } = {} + console.log(n) + } + " + `) + + // #9585 + expect( + injectSimpleCode( + ` +import { n, m } from 'foo' +const foo = {} + +{ + const { [n]: m } = foo +} +`, + ), + ).toMatchInlineSnapshot(` + "import { __vi_inject__ as __vi_esm_0__ } from 'foo' + + + const foo = {} + + { + const { [__vi_esm_0__.n]: m } = foo + } + " + `) +}) + +test('nested object destructure alias', async () => { + expect( + injectSimpleCode( + ` +import { remove, add, get, set, rest, objRest } from 'vue' + +function a() { + const { + o: { remove }, + a: { b: { c: [ add ] }}, + d: [{ get }, set, ...rest], + ...objRest + } = foo + + remove() + add() + get() + set() + rest() + objRest() +} + +remove() +add() +get() +set() +rest() +objRest() +`, + ), + ).toMatchInlineSnapshot(` + "import { __vi_inject__ as __vi_esm_0__ } from 'vue' + + + + function a() { + const { + o: { remove }, + a: { b: { c: [ add ] }}, + d: [{ get }, set, ...rest], + ...objRest + } = foo + + remove() + add() + get() + set() + rest() + objRest() + } + + __vi_esm_0__.remove() + __vi_esm_0__.add() + __vi_esm_0__.get() + __vi_esm_0__.set() + __vi_esm_0__.rest() + __vi_esm_0__.objRest() + " + `) +}) + +test('object props and methods', async () => { + expect( + injectSimpleCode( + ` +import foo from 'foo' + +const bar = 'bar' + +const obj = { + foo() {}, + [foo]() {}, + [bar]() {}, + foo: () => {}, + [foo]: () => {}, + [bar]: () => {}, + bar(foo) {} +} +`, + ), + ).toMatchInlineSnapshot(` + "import { __vi_inject__ as __vi_esm_0__ } from 'foo' + + + + const bar = 'bar' + + const obj = { + foo() {}, + [__vi_esm_0__.default]() {}, + [bar]() {}, + foo: () => {}, + [__vi_esm_0__.default]: () => {}, + [bar]: () => {}, + bar(foo) {} + } + " + `) +}) + +test('class props', async () => { + expect( + injectSimpleCode( + ` +import { remove, add } from 'vue' + +class A { + remove = 1 + add = null +} +`, + ), + ).toMatchInlineSnapshot(` + "import { __vi_inject__ as __vi_esm_0__ } from 'vue' + + + + const add = __vi_esm_0__.add; + const remove = __vi_esm_0__.remove; + class A { + remove = 1 + add = null + } + " + `) +}) + +test('class methods', async () => { + expect( + injectSimpleCode( + ` +import foo from 'foo' + +const bar = 'bar' + +class A { + foo() {} + [foo]() {} + [bar]() {} + #foo() {} + bar(foo) {} +} +`, + ), + ).toMatchInlineSnapshot(` + "import { __vi_inject__ as __vi_esm_0__ } from 'foo' + + + + const bar = 'bar' + + class A { + foo() {} + [__vi_esm_0__.default]() {} + [bar]() {} + #foo() {} + bar(foo) {} + } + " + `) +}) + +test('declare scope', async () => { + expect( + injectSimpleCode( + ` +import { aaa, bbb, ccc, ddd } from 'vue' + +function foobar() { + ddd() + + const aaa = () => { + bbb(ccc) + ddd() + } + const bbb = () => { + console.log('hi') + } + const ccc = 1 + function ddd() {} + + aaa() + bbb() + ccc() +} + +aaa() +bbb() +`, + ), + ).toMatchInlineSnapshot(` + "import { __vi_inject__ as __vi_esm_0__ } from 'vue' + + + + function foobar() { + ddd() + + const aaa = () => { + bbb(ccc) + ddd() + } + const bbb = () => { + console.log('hi') + } + const ccc = 1 + function ddd() {} + + aaa() + bbb() + ccc() + } + + __vi_esm_0__.aaa() + __vi_esm_0__.bbb() + " + `) +}) + +test('jsx', async () => { + const code = ` + import React from 'react' + import { Foo, Slot } from 'foo' + + function Bar({ Slot = }) { + return ( + <> + + + ) + } + ` + const id = '/foo.jsx' + const result = await transformWithEsbuild(code, id) + expect(injectSimpleCode(result.code)) + .toMatchInlineSnapshot(` + "import { __vi_inject__ as __vi_esm_0__ } from 'react' + import { __vi_inject__ as __vi_esm_1__ } from 'foo' + + + function Bar({ Slot: Slot2 = /* @__PURE__ */ __vi_esm_0__.default.createElement(__vi_esm_1__.Foo, null) }) { + return /* @__PURE__ */ __vi_esm_0__.default.createElement(__vi_esm_0__.default.Fragment, null, /* @__PURE__ */ __vi_esm_0__.default.createElement(Slot2, null)); + } + " + `) +}) + +test('continuous exports', async () => { + expect( + injectSimpleCode( + ` +export function fn1() { +}export function fn2() { +} + `, + ), + ).toMatchInlineSnapshot(` + "const __vi_inject__ = { [Symbol.toStringTag]: \\"Module\\" }; + + function fn1() { + } + Object.defineProperty(__vi_inject__, \\"fn1\\", { enumerable: true, configurable: true, get(){ return fn1 }});function fn2() { + } + Object.defineProperty(__vi_inject__, \\"fn2\\", { enumerable: true, configurable: true, get(){ return fn2 }}); + + export { __vi_inject__ }" + `) +}) + +// https://github.com/vitest-dev/vitest/issues/1141 +test('export default expression', async () => { + // esbuild transform result of following TS code + // export default function getRandom() { + // return Math.random() + // } + const code = ` +export default (function getRandom() { + return Math.random(); +}); +`.trim() + + expect(injectSimpleCode(code)).toMatchInlineSnapshot(` + "const __vi_inject__ = { [Symbol.toStringTag]: \\"Module\\" }; + __vi_inject__.default = (function getRandom() { + return Math.random(); + }); + export { __vi_inject__ }" + `) + + expect( + injectSimpleCode('export default (class A {});'), + ).toMatchInlineSnapshot(` + "const __vi_inject__ = { [Symbol.toStringTag]: \\"Module\\" }; + __vi_inject__.default = (class A {}); + export { __vi_inject__ }" + `) +}) + +test('track scope in for loops', async () => { + expect( + injectSimpleCode(` +import { test } from './test.js' +for (const test of tests) { + console.log(test) +} +for (let test = 0; test < 10; test++) { + console.log(test) +} +for (const test in tests) { + console.log(test) +}`), + ).toMatchInlineSnapshot(` + "import { __vi_inject__ as __vi_esm_0__ } from './test.js' + + + for (const test of tests) { + console.log(test) + } + for (let test = 0; test < 10; test++) { + console.log(test) + } + for (const test in tests) { + console.log(test) + }" + `) +}) + +// #8002 +// test('with hashbang', async () => { +// expect( +// injectSimpleCode( +// `#!/usr/bin/env node +// console.log("it can parse the hashbang")`, +// ), +// ).toMatchInlineSnapshot(` +// "#!/usr/bin/env node +// console.log(\\"it can parse the hashbang\\")" +// `) +// }) + +// test('import hoisted after hashbang', async () => { +// expect( +// await injectSimpleCode( +// `#!/usr/bin/env node +// import "foo"`, +// ), +// ).toMatchInlineSnapshot(` +// "#!/usr/bin/env node +// const __vite_ssr_import_0__ = await __vite_ssr_import__(\\"foo\\"); +// " +// `) +// }) + +// #10289 +test('track scope by class, function, condition blocks', async () => { + const code = ` +import { foo, bar } from 'foobar' +if (false) { + const foo = 'foo' + console.log(foo) +} else if (false) { + const [bar] = ['bar'] + console.log(bar) +} else { + console.log(foo) + console.log(bar) +} +export class Test { + constructor() { + if (false) { + const foo = 'foo' + console.log(foo) + } else if (false) { + const [bar] = ['bar'] + console.log(bar) + } else { + console.log(foo) + console.log(bar) + } + } +};`.trim() + + expect(injectSimpleCode(code)).toMatchInlineSnapshot(` + "const __vi_inject__ = { [Symbol.toStringTag]: \\"Module\\" }; + import { __vi_inject__ as __vi_esm_0__ } from 'foobar' + + if (false) { + const foo = 'foo' + console.log(foo) + } else if (false) { + const [bar] = ['bar'] + console.log(bar) + } else { + console.log(__vi_esm_0__.foo) + console.log(__vi_esm_0__.bar) + } + class Test { + constructor() { + if (false) { + const foo = 'foo' + console.log(foo) + } else if (false) { + const [bar] = ['bar'] + console.log(bar) + } else { + console.log(__vi_esm_0__.foo) + console.log(__vi_esm_0__.bar) + } + } + } + Object.defineProperty(__vi_inject__, \\"Test\\", { enumerable: true, configurable: true, get(){ return Test }});; + export { __vi_inject__ }" + `) +}) + +// #10386 +test('track var scope by function', async () => { + expect( + injectSimpleCode(` +import { foo, bar } from 'foobar' +function test() { + if (true) { + var foo = () => { var why = 'would' }, bar = 'someone' + } + return [foo, bar] +}`), + ).toMatchInlineSnapshot(` + "import { __vi_inject__ as __vi_esm_0__ } from 'foobar' + + + function test() { + if (true) { + var foo = () => { var why = 'would' }, bar = 'someone' + } + return [foo, bar] + }" + `) +}) + +// #11806 +test('track scope by blocks', async () => { + expect( + injectSimpleCode(` +import { foo, bar, baz } from 'foobar' +function test() { + [foo]; + { + let foo = 10; + let bar = 10; + } + try {} catch (baz){ baz }; + return bar; +}`), + ).toMatchInlineSnapshot(` + "import { __vi_inject__ as __vi_esm_0__ } from 'foobar' + + + function test() { + [__vi_esm_0__.foo]; + { + let foo = 10; + let bar = 10; + } + try {} catch (baz){ baz }; + return __vi_esm_0__.bar; + }" + `) +}) diff --git a/test/core/test/injector-mock.test.ts b/test/core/test/injector-mock.test.ts new file mode 100644 index 000000000000..2ee3fb32a4e0 --- /dev/null +++ b/test/core/test/injector-mock.test.ts @@ -0,0 +1,60 @@ +import { Parser } from 'acorn' +import { hoistMocks } from 'vitest/src/node/hoistMocks' +import { expect, test } from 'vitest' + +function parse(code: string, options: any) { + return Parser.parse(code, options) +} + +function hoistSimpleCode(code: string) { + return hoistMocks(code, '/test.js', parse)?.code.trim() +} + +test('hoists mock, unmock, hoisted', () => { + expect(hoistSimpleCode(` + vi.mock('path', () => {}) + vi.unmock('path') + vi.hoisted(() => {}) + `)).toMatchInlineSnapshot(` + "if (typeof globalThis.vi === \\"undefined\\" && typeof globalThis.vitest === \\"undefined\\") { throw new Error(\\"There are some problems in resolving the mocks API.\\\\nYou may encounter this issue when importing the mocks API from another module other than 'vitest'.\\\\nTo fix this issue you can either:\\\\n- import the mocks API directly from 'vitest'\\\\n- enable the 'globals' options\\") } + vi.mock('path', () => {}) + vi.unmock('path') + vi.hoisted(() => {})" + `) +}) + +test('always hoists import from vitest', () => { + expect(hoistSimpleCode(` + import { vi } from 'vitest' + vi.mock('path', () => {}) + vi.unmock('path') + vi.hoisted(() => {}) + import { test } from 'vitest' + `)).toMatchInlineSnapshot(` + "const { vi } = await import('vitest') + const { test } = await import('vitest') + vi.mock('path', () => {}) + vi.unmock('path') + vi.hoisted(() => {})" + `) +}) + +test('always hoists all imports but they are under mocks', () => { + expect(hoistSimpleCode(` + import { vi } from 'vitest' + import { someValue } from './path.js' + import { someValue2 } from './path2.js' + vi.mock('path', () => {}) + vi.unmock('path') + vi.hoisted(() => {}) + import { test } from 'vitest' + `)).toMatchInlineSnapshot(` + "const { vi } = await import('vitest') + const { test } = await import('vitest') + vi.mock('path', () => {}) + vi.unmock('path') + vi.hoisted(() => {}) + const { someValue } = await import('./path.js') + const { someValue2 } = await import('./path2.js')" + `) +})