1
1
import type { Plugin } from 'vite'
2
- import type { Declaration , ExportDefaultDeclaration , ExportNamedDeclaration , Expression , Pattern , Positioned , Program } from './esmWalker'
3
- import MagicString from 'magic-string'
2
+ import type { AutomockOptions } from './automock'
4
3
import { cleanUrl } from '../utils'
5
- import {
4
+ import { automockModule } from './automock'
6
5
7
- getArbitraryModuleIdentifier ,
6
+ export type { AutomockOptions as AutomockPluginOptions } from './automock'
8
7
9
- } from './esmWalker'
10
-
11
- export interface AutomockPluginOptions {
12
- /**
13
- * @default "__vitest_mocker__"
14
- */
15
- globalThisAccessor ?: string
16
- }
17
-
18
- export function automockPlugin ( options : AutomockPluginOptions = { } ) : Plugin {
8
+ export function automockPlugin ( options : AutomockOptions = { } ) : Plugin {
19
9
return {
20
10
name : 'vitest:automock' ,
21
11
enforce : 'post' ,
@@ -31,162 +21,3 @@ export function automockPlugin(options: AutomockPluginOptions = {}): Plugin {
31
21
} ,
32
22
}
33
23
}
34
-
35
- // TODO: better source map replacement
36
- export function automockModule (
37
- code : string ,
38
- mockType : 'automock' | 'autospy' ,
39
- parse : ( code : string ) => any ,
40
- options : AutomockPluginOptions = { } ,
41
- ) : MagicString {
42
- const globalThisAccessor = options . globalThisAccessor || '"__vitest_mocker__"'
43
- const ast = parse ( code ) as Program
44
-
45
- const m = new MagicString ( code )
46
-
47
- const allSpecifiers : { name : string ; alias ?: string } [ ] = [ ]
48
- let importIndex = 0
49
- for ( const _node of ast . body ) {
50
- if ( _node . type === 'ExportAllDeclaration' ) {
51
- throw new Error (
52
- `automocking files with \`export *\` is not supported in browser mode because it cannot be statically analysed` ,
53
- )
54
- }
55
-
56
- if ( _node . type === 'ExportNamedDeclaration' ) {
57
- const node = _node as Positioned < ExportNamedDeclaration >
58
- const declaration = node . declaration // export const name
59
-
60
- function traversePattern ( expression : Pattern ) {
61
- // export const test = '1'
62
- if ( expression . type === 'Identifier' ) {
63
- allSpecifiers . push ( { name : expression . name } )
64
- }
65
- // export const [test, ...rest] = [1, 2, 3]
66
- else if ( expression . type === 'ArrayPattern' ) {
67
- expression . elements . forEach ( ( element ) => {
68
- if ( ! element ) {
69
- return
70
- }
71
- traversePattern ( element )
72
- } )
73
- }
74
- else if ( expression . type === 'ObjectPattern' ) {
75
- expression . properties . forEach ( ( property ) => {
76
- // export const { ...rest } = {}
77
- if ( property . type === 'RestElement' ) {
78
- traversePattern ( property )
79
- }
80
- // export const { test, test2: alias } = {}
81
- else if ( property . type === 'Property' ) {
82
- traversePattern ( property . value )
83
- }
84
- else {
85
- property satisfies never
86
- }
87
- } )
88
- }
89
- else if ( expression . type === 'RestElement' ) {
90
- traversePattern ( expression . argument )
91
- }
92
- // const [name[1], name[2]] = []
93
- // cannot be used in export
94
- else if ( expression . type === 'AssignmentPattern' ) {
95
- throw new Error (
96
- `AssignmentPattern is not supported. Please open a new bug report.` ,
97
- )
98
- }
99
- // const test = thing.func()
100
- // cannot be used in export
101
- else if ( expression . type === 'MemberExpression' ) {
102
- throw new Error (
103
- `MemberExpression is not supported. Please open a new bug report.` ,
104
- )
105
- }
106
- else {
107
- expression satisfies never
108
- }
109
- }
110
-
111
- if ( declaration ) {
112
- if ( declaration . type === 'FunctionDeclaration' ) {
113
- allSpecifiers . push ( { name : declaration . id . name } )
114
- }
115
- else if ( declaration . type === 'VariableDeclaration' ) {
116
- declaration . declarations . forEach ( ( declaration ) => {
117
- traversePattern ( declaration . id )
118
- } )
119
- }
120
- else if ( declaration . type === 'ClassDeclaration' ) {
121
- allSpecifiers . push ( { name : declaration . id . name } )
122
- }
123
- else {
124
- declaration satisfies never
125
- }
126
- m . remove ( node . start , ( declaration as Positioned < Declaration > ) . start )
127
- }
128
-
129
- const specifiers = node . specifiers || [ ]
130
- const source = node . source
131
-
132
- if ( ! source && specifiers . length ) {
133
- specifiers . forEach ( ( specifier ) => {
134
- allSpecifiers . push ( {
135
- alias : getArbitraryModuleIdentifier ( specifier . exported ) ,
136
- name : getArbitraryModuleIdentifier ( specifier . local ) ,
137
- } )
138
- } )
139
- m . remove ( node . start , node . end )
140
- }
141
- else if ( source && specifiers . length ) {
142
- const importNames : [ string , string ] [ ] = [ ]
143
-
144
- specifiers . forEach ( ( specifier ) => {
145
- const importedName = `__vitest_imported_${ importIndex ++ } __`
146
- importNames . push ( [ getArbitraryModuleIdentifier ( specifier . local ) , importedName ] )
147
- allSpecifiers . push ( {
148
- name : importedName ,
149
- alias : getArbitraryModuleIdentifier ( specifier . exported ) ,
150
- } )
151
- } )
152
-
153
- const importString = `import { ${ importNames
154
- . map ( ( [ name , alias ] ) => `${ name } as ${ alias } ` )
155
- . join ( ', ' ) } } from '${ source . value } '`
156
-
157
- m . overwrite ( node . start , node . end , importString )
158
- }
159
- }
160
- if ( _node . type === 'ExportDefaultDeclaration' ) {
161
- const node = _node as Positioned < ExportDefaultDeclaration >
162
- const declaration = node . declaration as Positioned < Expression >
163
- allSpecifiers . push ( { name : '__vitest_default' , alias : 'default' } )
164
- m . overwrite ( node . start , declaration . start , `const __vitest_default = ` )
165
- }
166
- }
167
- const moduleObject = `
168
- const __vitest_current_es_module__ = {
169
- __esModule: true,
170
- ${ allSpecifiers . map ( ( { name } ) => `["${ name } "]: ${ name } ,` ) . join ( '\n ' ) }
171
- }
172
- const __vitest_mocked_module__ = globalThis[${ globalThisAccessor } ].mockObject(__vitest_current_es_module__, "${ mockType } ")
173
- `
174
- const assigning = allSpecifiers
175
- . map ( ( { name } , index ) => {
176
- return `const __vitest_mocked_${ index } __ = __vitest_mocked_module__["${ name } "]`
177
- } )
178
- . join ( '\n' )
179
-
180
- const redeclarations = allSpecifiers
181
- . map ( ( { name, alias } , index ) => {
182
- return ` __vitest_mocked_${ index } __ as ${ alias || name } ,`
183
- } )
184
- . join ( '\n' )
185
- const specifiersExports = `
186
- export {
187
- ${ redeclarations }
188
- }
189
- `
190
- m . append ( moduleObject + assigning + specifiersExports )
191
- return m
192
- }
0 commit comments