we (web engine): Experimental web browser project to understand the limits of Claude
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

Fix export default anonymous function/class parsing

export default function() {} and export default class {} are valid
JavaScript but the parser incorrectly required a name. Check whether
the function/class has a name and route to expression parsing when
anonymous.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

+59 -4
+59 -4
crates/js/src/parser.rs
··· 1222 1222 // `export default ...` 1223 1223 if self.eat(&TokenKind::Default) { 1224 1224 if matches!(self.peek_kind(), TokenKind::Function) { 1225 - let decl = self.parse_function_declaration()?; 1225 + // Named function → declaration, anonymous → default expression 1226 + let has_name = matches!(self.peek_ahead(1), TokenKind::Identifier(_)) 1227 + || (matches!(self.peek_ahead(1), TokenKind::Star) 1228 + && matches!(self.peek_ahead(2), TokenKind::Identifier(_))); 1229 + if has_name { 1230 + let decl = self.parse_function_declaration()?; 1231 + return Ok(Stmt { 1232 + kind: StmtKind::Export(ExportDecl::Declaration(Box::new(decl))), 1233 + span: self.span_from(start), 1234 + }); 1235 + } 1236 + let expr = self.parse_function_expression()?; 1226 1237 return Ok(Stmt { 1227 - kind: StmtKind::Export(ExportDecl::Declaration(Box::new(decl))), 1238 + kind: StmtKind::Export(ExportDecl::Default(expr)), 1228 1239 span: self.span_from(start), 1229 1240 }); 1230 1241 } 1231 1242 if matches!(self.peek_kind(), TokenKind::Class) { 1232 - let decl = self.parse_class_declaration()?; 1243 + // Named class → declaration, anonymous → default expression 1244 + if matches!(self.peek_ahead(1), TokenKind::Identifier(_)) { 1245 + let decl = self.parse_class_declaration()?; 1246 + return Ok(Stmt { 1247 + kind: StmtKind::Export(ExportDecl::Declaration(Box::new(decl))), 1248 + span: self.span_from(start), 1249 + }); 1250 + } 1251 + let expr = self.parse_class_expression()?; 1233 1252 return Ok(Stmt { 1234 - kind: StmtKind::Export(ExportDecl::Declaration(Box::new(decl))), 1253 + kind: StmtKind::Export(ExportDecl::Default(expr)), 1235 1254 span: self.span_from(start), 1236 1255 }); 1237 1256 } ··· 3462 3481 match &prog.body[0].kind { 3463 3482 StmtKind::Export(ExportDecl::Declaration(_)) => {} 3464 3483 _ => panic!("expected export declaration"), 3484 + } 3485 + } 3486 + 3487 + #[test] 3488 + fn test_export_default_anonymous_function() { 3489 + let prog = Parser::parse_module("export default function() {}").unwrap(); 3490 + match &prog.body[0].kind { 3491 + StmtKind::Export(ExportDecl::Default(expr)) => { 3492 + assert!(matches!(expr.kind, ExprKind::Function(ref def) if def.id.is_none())); 3493 + } 3494 + _ => panic!("expected export default anonymous function"), 3495 + } 3496 + } 3497 + 3498 + #[test] 3499 + fn test_export_default_anonymous_class() { 3500 + let prog = Parser::parse_module("export default class {}").unwrap(); 3501 + match &prog.body[0].kind { 3502 + StmtKind::Export(ExportDecl::Default(expr)) => { 3503 + assert!(matches!(expr.kind, ExprKind::Class(ref def) if def.id.is_none())); 3504 + } 3505 + _ => panic!("expected export default anonymous class"), 3506 + } 3507 + } 3508 + 3509 + #[test] 3510 + fn test_export_default_anonymous_generator() { 3511 + let prog = Parser::parse_module("export default function*() {}").unwrap(); 3512 + match &prog.body[0].kind { 3513 + StmtKind::Export(ExportDecl::Default(expr)) => { 3514 + assert!(matches!( 3515 + expr.kind, 3516 + ExprKind::Function(ref def) if def.id.is_none() && def.is_generator 3517 + )); 3518 + } 3519 + _ => panic!("expected export default anonymous generator"), 3465 3520 } 3466 3521 } 3467 3522