x"
+ try p.lexer.next();
+ try p.skipTypeScriptType(.lowest);
+ try p.lexer.expectGreaterThan(false);
+ return p.parsePrefix(level, errors, flags);
+ }
+
+ try p.lexer.unexpected();
+ return error.SyntaxError;
+ },
+ .t_import => {
+ try p.lexer.next();
+ return p.parseImportExpr(loc, level);
+ },
+ else => {
+ try p.lexer.unexpected();
+ return error.SyntaxError;
+ },
+ }
+ return error.SyntaxError;
+ }
+
+ // esbuild's version of this function is much more complicated.
+ // I'm not sure why defines is strictly relevant for this case
+ // and I imagine all the allocations cause some performance
+ // guessing it's concurrency-related
+ pub fn jsxStringsToMemberExpression(p: *P, loc: logger.Loc, ref: Ref) Expr {
+ p.recordUsage(ref);
+ return p.e(E.Identifier{ .ref = ref }, loc);
+ }
+
+ // Note: The caller has already parsed the "import" keyword
+ pub fn parseImportExpr(p: *P, loc: logger.Loc, level: Level) anyerror!Expr {
+ // Parse an "import.meta" expression
+ if (p.lexer.token == .t_dot) {
+ p.es6_import_keyword = js_lexer.rangeOfIdentifier(p.source, loc);
+ try p.lexer.next();
+ if (p.lexer.isContextualKeyword("meta")) {
+ const r = p.lexer.range();
+ try p.lexer.next();
+ p.has_import_meta = true;
+ return p.e(E.ImportMeta{}, loc);
+ } else {
+ try 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;
+ try p.lexer.expect(.t_open_paren);
+ const comments = p.lexer.comments_to_preserve_before.toOwnedSlice();
+ p.lexer.preserve_all_comments_before = false;
+
+ const value = try p.parseExpr(.comma);
+ try p.lexer.expect(.t_close_paren);
+
+ p.allow_in = old_allow_in;
+ return p.e(E.Import{ .expr = value, .leading_interior_comments = comments, .import_record_index = 0 }, loc);
+ }
+
+ const JSXTag = struct {
+ pub const TagType = enum { fragment, tag };
+ pub const Data = union(TagType) {
+ fragment: u1,
+ tag: Expr,
+
+ pub fn asExpr(d: *const Data) ?ExprNodeIndex {
+ switch (d.*) {
+ .tag => |tag| {
+ return tag;
+ },
+ else => {
+ return null;
+ },
+ }
+ }
+ };
+ data: Data,
+ range: logger.Range,
+ name: string = "",
+
+ pub fn parse(p: *P) !JSXTag {
+ const loc = p.lexer.loc();
+
+ // A missing tag is a fragment
+ if (p.lexer.token == .t_greater_than) {
+ return JSXTag{
+ .range = logger.Range{ .loc = loc, .len = 0 },
+ .data = Data{ .fragment = 1 },
+ };
+ }
+
+ // The tag is an identifier
+ var name = p.lexer.identifier;
+ var tag_range = p.lexer.range();
+ try p.lexer.expectInsideJSXElement(.t_identifier);
+
+ // Certain identifiers are strings
+ // = 'a' and name[0] <= 'z')) {
+ return JSXTag{
+ .data = Data{ .tag = p.e(E.String{
+ .utf8 = name,
+ }, loc) },
+ .range = tag_range,
+ };
+ }
+
+ // Otherwise, this is an identifier
+ //