diff --git a/src/js_lexer.zig b/src/js_lexer.zig
index 1bfd57d68c..7c0ffef896 100644
--- a/src/js_lexer.zig
+++ b/src/js_lexer.zig
@@ -847,6 +847,10 @@ pub const Lexer = struct {
return std.unicode.utf16leToUtf8Alloc(lexer.alloc, js) catch unreachable;
}
+ pub fn nextInsideJSXElement() void {
+ std.debug.panic("JSX not implemented yet.", .{});
+ }
+
fn scanRegExpValidateAndStep(lexer: *Lexer) void {
if (lexer.code_point == '\\') {
lexer.step();
diff --git a/src/js_parser.zig b/src/js_parser.zig
index 2b3ee185e4..530215b2f9 100644
--- a/src/js_parser.zig
+++ b/src/js_parser.zig
@@ -2959,8 +2959,81 @@ const P = struct {
.is_single_line = is_single_line,
}, loc);
},
- .t_less_than => {},
- .t_import => {},
+ .t_less_than => {
+ // This is a very complicated and highly ambiguous area of TypeScript
+ // syntax. Many similar-looking things are overloaded.
+ //
+ // TS:
+ //
+ // A type cast:
+ // (x)
+ // <[]>(x)
+ // (x)
+ //
+ // An arrow function with type parameters:
+ // (x) => {}
+ // (x) => {}
+ // (x) => {}
+ // (x) => {}
+ //
+ // TSX:
+ //
+ // A JSX element:
+ // (x) => {}
+ // (x) => {}
+ // (x) => {}
+ //
+ // An arrow function with type parameters:
+ // (x) => {}
+ // (x) => {}
+ //
+ // A syntax error:
+ // <[]>(x)
+ // (x)
+ // (x) => {}
+ // (x) => {}
+ if (p.options.ts and p.options.jsx.parse) {
+ var oldLexer = p.lexer;
+
+ p.lexer.next();
+ // Look ahead to see if this should be an arrow function instead
+ var is_ts_arrow_fn = false;
+
+ if (p.lexer.token == .t_identifier) {
+ p.lexer.next();
+ if (p.lexer.token == .t_comma) {
+ is_ts_arrow_fn = true;
+ } else if (p.lexer.token == .t_extends) {
+ p.lexer.next();
+ is_ts_arrow_fn = p.lexer.token != .t_equals and p.lexer.token != .t_greater_than;
+ }
+ }
+
+ // Restore the lexer
+ p.lexer = oldLexer;
+
+ if (is_ts_arrow_fn) {
+ p.skipTypescriptTypeParameters();
+ p.lexer.expect(.t_open_paren);
+ return p.parseParenExpr(loc, ParenExprOpts{ .force_arrow_fn = true }) catch unreachable;
+ }
+ }
+
+ if (p.options.jsx.parse) {
+ notimpl();
+ }
+
+ if (p.options.ts) {
+ notimpl();
+ }
+
+ p.lexer.unexpected();
+ return p.e(E.Missing{}, logger.Loc.Empty);
+ },
+ .t_import => {
+ p.lexer.next();
+ return p.parseImportExpr(loc, level);
+ },
else => {
p.lexer.unexpected();
return p.e(E.Missing{}, logger.Loc.Empty);
@@ -2970,6 +3043,49 @@ const P = struct {
return p.e(E.Missing{}, logger.Loc.Empty);
}
+ // Note: The caller has already parsed the "import" keyword
+ pub fn parseImportExpr(p: *P, loc: logger.Loc, level: Level) Expr {
+ // Parse an "import.meta" expression
+ if (p.lexer.token == .t_dot) {
+ p.es6_import_keyword = js_lexer.rangeOfIdentifier(&p.source, loc);
+ p.lexer.next();
+ if (p.lexer.isContextualKeyword("meta")) {
+ const r = p.lexer.range();
+ p.lexer.next();
+ p.has_import_meta = true;
+ return p.e(E.ImportMeta{}, loc);
+ } else {
+ p.lexer.expectedString("\"meta\"");
+ }
+ }
+
+ if (level.gt(.call)) {
+ const r = js_lexer.rangeOfIdentifier(&p.source, loc);
+ p.log.addRangeError(p.source, r, "Cannot use an \"import\" expression here without parentheses") catch unreachable;
+ }
+ // allow "in" inside call arguments;
+ var old_allow_in = p.allow_in;
+ p.allow_in = true;
+
+ p.lexer.preserve_all_comments_before = true;
+ p.lexer.expect(.t_open_paren);
+ const comments = p.lexer.comments_to_preserve_before;
+ p.lexer.preserve_all_comments_before = false;
+
+ const value = p.parseExpr(.comma);
+ p.lexer.expect(.t_close_paren);
+
+ p.allow_in = old_allow_in;
+ return p.e(E.Import{ .expr = value, .leading_interior_comments = comments orelse &([_]G.Comment{}), .import_record_index = 0 }, loc);
+ }
+
+ pub fn parseJSXElement(loc: logger.Loc) Expr {
+ // Parse the tag
+ //var startRange, startText, startTag := p.parseJSXTag();รท
+ notimpl();
+ return p.e(E.Missing{}, logger.Loc.Empty);
+ }
+
pub fn willNeedBindingPattern(p: *P) bool {
switch (p.lexer.token) {
.t_equals => {