2
2
3
3
const path = require ( 'path' )
4
4
const Promise = require ( 'bluebird' )
5
- const fs = require ( './lib/fs ' )
5
+ const fs = require ( 'fs-extra ' )
6
6
7
7
const cloneDeep = require ( 'lodash.clonedeep' )
8
8
const browserify = require ( 'browserify' )
9
9
const watchify = require ( 'watchify' )
10
10
11
11
const debug = require ( 'debug' ) ( 'cypress:browserify' )
12
12
13
+ const typescriptExtensionRegex = / \. t s x ? $ /
14
+ const errorTypes = {
15
+ TYPESCRIPT_AND_TSIFY : 'TYPESCRIPT_AND_TSIFY' ,
16
+ TYPESCRIPT_NONEXISTENT : 'TYPESCRIPT_NONEXISTENT' ,
17
+ TYPESCRIPT_NOT_CONFIGURED : 'TYPESCRIPT_NOT_CONFIGURED' ,
18
+ TYPESCRIPT_NOT_STRING : 'TYPESCRIPT_NOT_STRING' ,
19
+ }
20
+
13
21
const bundles = { }
14
22
15
23
// by default, we transform JavaScript (including some proposal features),
@@ -60,7 +68,17 @@ const defaultOptions = {
60
68
} ,
61
69
}
62
70
63
- const getBrowserifyOptions = ( entry , userBrowserifyOptions = { } , typescriptPath = null ) => {
71
+ const throwError = ( { message, type } ) => {
72
+ const prefix = 'Error running @cypress/browserify-preprocessor:\n\n'
73
+
74
+ const err = new Error ( `${ prefix } ${ message } ` )
75
+
76
+ if ( type ) err . type = type
77
+
78
+ throw err
79
+ }
80
+
81
+ const getBrowserifyOptions = async ( entry , userBrowserifyOptions = { } , typescriptPath = null ) => {
64
82
let browserifyOptions = cloneDeep ( defaultOptions . browserifyOptions )
65
83
66
84
// allow user to override default options
@@ -82,22 +100,38 @@ const getBrowserifyOptions = (entry, userBrowserifyOptions = {}, typescriptPath
82
100
} )
83
101
84
102
if ( typescriptPath ) {
103
+ if ( typeof typescriptPath !== 'string' ) {
104
+ throwError ( {
105
+ type : errorTypes . TYPESCRIPT_NOT_STRING ,
106
+ message : `The 'typescript' option must be a string. You passed: ${ typescriptPath } ` ,
107
+ } )
108
+ }
109
+
110
+ const pathExists = await fs . pathExists ( typescriptPath )
111
+
112
+ if ( ! pathExists ) {
113
+ throwError ( {
114
+ type : errorTypes . TYPESCRIPT_NONEXISTENT ,
115
+ message : `The 'typescript' option must be a valid path to your TypeScript installation. We could not find anything at the following path: ${ typescriptPath } ` ,
116
+ } )
117
+ }
118
+
85
119
const transform = browserifyOptions . transform
86
120
const hasTsifyTransform = transform . some ( ( [ name ] ) => name . includes ( 'tsify' ) )
87
121
const hastsifyPlugin = browserifyOptions . plugin . includes ( 'tsify' )
88
122
89
123
if ( hasTsifyTransform || hastsifyPlugin ) {
90
124
const type = hasTsifyTransform ? 'transform' : 'plugin'
91
125
92
- throw new Error ( `Error running @cypress/browserify-preprocessor:
93
-
94
- It looks like you passed the 'typescript' option and also specified a browserify ${ type } for TypeScript. This may cause conflicts.
126
+ throwError ( {
127
+ type : errorTypes . TYPESCRIPT_AND_TSIFY ,
128
+ message : ` It looks like you passed the 'typescript' option and also specified a browserify ${ type } for TypeScript. This may cause conflicts.
95
129
96
130
Please do one of the following:
97
131
98
132
1) Pass in the 'typescript' option and omit the browserify ${ type } (Recommmended)
99
- 2) Omit the 'typescript' option and continue to use your own browserify ${ type }
100
- ` )
133
+ 2) Omit the 'typescript' option and continue to use your own browserify ${ type } ` ,
134
+ } )
101
135
}
102
136
103
137
browserifyOptions . extensions . push ( '.ts' , '.tsx' )
@@ -135,7 +169,7 @@ const preprocessor = (options = {}) => {
135
169
// when running in the GUI, it will likely get called multiple times
136
170
// with the same filePath, as the user could re-run the tests, causing
137
171
// the supported file and spec file to be requested again
138
- return ( file ) => {
172
+ return async ( file ) => {
139
173
const filePath = file . filePath
140
174
141
175
debug ( 'get:' , filePath )
@@ -157,9 +191,18 @@ const preprocessor = (options = {}) => {
157
191
debug ( 'input:' , filePath )
158
192
debug ( 'output:' , outputPath )
159
193
160
- const browserifyOptions = getBrowserifyOptions ( filePath , options . browserifyOptions , options . typescript )
194
+ const browserifyOptions = await getBrowserifyOptions ( filePath , options . browserifyOptions , options . typescript )
161
195
const watchifyOptions = Object . assign ( { } , defaultOptions . watchifyOptions , options . watchifyOptions )
162
196
197
+ if ( ! options . typescript && typescriptExtensionRegex . test ( filePath ) ) {
198
+ throwError ( {
199
+ type : errorTypes . TYPESCRIPT_NOT_CONFIGURED ,
200
+ message : `You are attempting to preprocess a TypeScript file, but do not have TypeScript configured. Pass the 'typescript' option to enable TypeScript support.
201
+
202
+ The file: ${ filePath } ` ,
203
+ } )
204
+ }
205
+
163
206
const bundler = browserify ( browserifyOptions )
164
207
165
208
if ( file . shouldWatch ) {
@@ -227,7 +270,7 @@ const preprocessor = (options = {}) => {
227
270
} )
228
271
229
272
const bundlePromise = fs
230
- . ensureDirAsync ( path . dirname ( outputPath ) )
273
+ . ensureDir ( path . dirname ( outputPath ) )
231
274
. then ( bundle )
232
275
233
276
// cache the bundle promise, so it can be returned if this function
@@ -253,6 +296,8 @@ const preprocessor = (options = {}) => {
253
296
// provide a clone of the default options
254
297
preprocessor . defaultOptions = JSON . parse ( JSON . stringify ( defaultOptions ) )
255
298
299
+ preprocessor . errorTypes = errorTypes
300
+
256
301
if ( process . env . __TESTING__ ) {
257
302
preprocessor . reset = ( ) => {
258
303
for ( let filePath in bundles ) {
0 commit comments