@@ -163,6 +163,36 @@ pp.parseObjectWhiteBlock = function(node, blockIndentLevel) {
163
163
return this . finishNode ( node , "BlockStatement" ) ;
164
164
} ;
165
165
166
+ pp . tryParseObjectWhiteBlock = function ( node , blockIndentLevel ) {
167
+ const state = this . state . clone ( ) ;
168
+ try {
169
+ return [ this . parseObjectWhiteBlock ( node , blockIndentLevel ) ] ;
170
+ } catch ( err ) {
171
+ this . state = state ;
172
+ return [ null , err ] ;
173
+ }
174
+ } ;
175
+
176
+ pp . rethrowObjParseError = function ( objParseResult , blockParseError ) {
177
+ const objParseError = objParseResult ? objParseResult [ 1 ] : null ;
178
+ if ( objParseError ) {
179
+ if ( objParseError . message === "WRONG_SPECULATIVE_BRANCH" ) {
180
+ throw blockParseError ;
181
+ } else {
182
+ throw objParseError ;
183
+ }
184
+ } else {
185
+ throw blockParseError ;
186
+ }
187
+ } ;
188
+
189
+ pp . parseNonemptyWhiteBlock = function ( node , indentLevel ) {
190
+ this . parseBlockBody ( node , false , false , indentLevel ) ;
191
+ if ( ! node . body . length ) {
192
+ this . unexpected ( node . start , "Expected an Indent or Statement" ) ;
193
+ }
194
+ } ;
195
+
166
196
pp . parseInlineWhiteBlock = function ( node ) {
167
197
if ( this . state . type . startsExpr ) return this . parseMaybeAssign ( ) ;
168
198
// oneline statement case
@@ -179,9 +209,17 @@ pp.parseMultilineWhiteBlock = function(node, indentLevel) {
179
209
return this . parseObjectWhiteBlock ( node , indentLevel ) ;
180
210
}
181
211
182
- this . parseBlockBody ( node , false , false , indentLevel ) ;
183
- if ( ! node . body . length ) {
184
- this . unexpected ( node . start , "Expected an Indent or Statement" ) ;
212
+ if ( this . match ( tt . braceL ) && this . hasPlugin ( "whiteblockPreferred" ) ) {
213
+ const objParseResult = this . tryParseObjectWhiteBlock ( node , indentLevel ) ;
214
+ if ( objParseResult [ 0 ] ) return objParseResult [ 0 ] ;
215
+
216
+ try {
217
+ this . parseNonemptyWhiteBlock ( node , indentLevel ) ;
218
+ } catch ( err ) {
219
+ this . rethrowObjParseError ( objParseResult , err ) ;
220
+ }
221
+ } else {
222
+ this . parseNonemptyWhiteBlock ( node , indentLevel ) ;
185
223
}
186
224
187
225
this . addExtra ( node , "curly" , false ) ;
@@ -198,9 +236,25 @@ pp.parseWhiteBlock = function (isExpression?) {
198
236
return this . parseInlineWhiteBlock ( node ) ;
199
237
}
200
238
201
- if ( this . match ( tt . braceL ) && this . hasPlugin ( "whiteblockOnly" ) ) {
202
- // Parse as object
203
- return this . parseObjectWhiteBlock ( node , indentLevel ) ;
239
+ if ( this . match ( tt . braceL ) ) {
240
+ if ( this . hasPlugin ( "whiteblockOnly" ) ) {
241
+ return this . parseObjectWhiteBlock ( node , indentLevel ) ;
242
+ }
243
+
244
+ let objParseResult = null ;
245
+ if ( this . hasPlugin ( "whiteblockPreferred" ) ) {
246
+ objParseResult = this . tryParseObjectWhiteBlock ( node , indentLevel ) ;
247
+ if ( objParseResult [ 0 ] ) return objParseResult [ 0 ] ;
248
+
249
+ try {
250
+ this . state . nestedBlockLevel ++ ;
251
+ const stmt = this . parseStatement ( false ) ;
252
+ this . state . nestedBlockLevel -- ;
253
+ return stmt ;
254
+ } catch ( err ) {
255
+ this . rethrowObjParseError ( objParseResult , err ) ;
256
+ }
257
+ }
204
258
}
205
259
206
260
this . state . nestedBlockLevel ++ ;
@@ -270,6 +324,35 @@ pp.parseArrowType = function (node) {
270
324
271
325
// largely c/p from parseFunctionBody
272
326
327
+ pp . parseBraceArrowFunctionBody = function ( node , indentLevel ) {
328
+ // In whiteblock-only mode, `{` must be introducing an object
329
+ if ( this . hasPlugin ( "whiteblockOnly" ) ) {
330
+ return this . parseObjectWhiteBlock ( node , indentLevel ) ;
331
+ }
332
+
333
+ // In whiteblock-preferred mode, try to parse an object, otherwise fall back on
334
+ // a braceblock.
335
+ if ( this . hasPlugin ( "whiteblockPreferred" ) ) {
336
+ const objParseResult = this . tryParseObjectWhiteBlock ( node , indentLevel ) ;
337
+ if ( objParseResult [ 0 ] ) return objParseResult [ 0 ] ;
338
+ this . next ( ) ;
339
+
340
+ try {
341
+ this . parseBlockBody ( node , true , false , tt . braceR ) ;
342
+ } catch ( err ) {
343
+ this . rethrowObjParseError ( objParseResult , err ) ;
344
+ }
345
+
346
+ this . addExtra ( node , "curly" , true ) ;
347
+ return this . finishNode ( node , "BlockStatement" ) ;
348
+ }
349
+
350
+ this . next ( ) ;
351
+ this . parseBlockBody ( node , true , false , tt . braceR ) ;
352
+ this . addExtra ( node , "curly" , true ) ;
353
+ return this . finishNode ( node , "BlockStatement" ) ;
354
+ } ;
355
+
273
356
pp . parseArrowFunctionBody = function ( node ) {
274
357
// set and reset state surrounding block
275
358
const oldInAsync = this . state . inAsync ,
@@ -286,17 +369,7 @@ pp.parseArrowFunctionBody = function (node) {
286
369
this . expect ( tt . arrow ) ;
287
370
if ( ! this . isLineBreak ( ) ) {
288
371
if ( this . match ( tt . braceL ) ) {
289
- if ( this . hasPlugin ( "whiteblockOnly" ) ) {
290
- // In whiteblock mode, arrows that start with `{` must be object exprs
291
- node . body = this . parseObjectWhiteBlock ( nodeAtArrow , indentLevel ) ;
292
- } else {
293
- // restart node at brace start instead of arrow start
294
- node . body = this . startNode ( ) ;
295
- this . next ( ) ;
296
- this . parseBlockBody ( node . body , true , false , tt . braceR ) ;
297
- this . addExtra ( node . body , "curly" , true ) ;
298
- node . body = this . finishNode ( node . body , "BlockStatement" ) ;
299
- }
372
+ node . body = this . parseBraceArrowFunctionBody ( this . startNode ( ) , indentLevel ) ;
300
373
} else {
301
374
node . body = this . parseInlineWhiteBlock ( nodeAtArrow ) ;
302
375
}
0 commit comments