usingnamespace @import("imports.zig"); const NodeFallbackModules = @import("../node_fallbacks.zig"); // Dear reader, // There are some things you should know about this file to make it easier for humans to read // "P" is the internal parts of the parser // "p.e" allocates a new Expr // "p.b" allocates a new Binding // "p.s" allocates a new Stmt // We do it this way so if we want to refactor how these are allocated in the future, we only have to modify one function to change it everywhere // Everything in JavaScript is either an Expression, a Binding, or a Statement. // Expression: foo(1) // Statement: let a = 1; // Binding: 1 // While the names for Expr, Binding, and Stmt are directly copied from esbuild, those were likely inspired by Go's parser. // which is another example of a very fast parser. const TemplatePartTuple = std.meta.Tuple(&[_]type{ []E.TemplatePart, logger.Loc }); const ScopeOrderList = std.ArrayListUnmanaged(?ScopeOrder); const JSXFactoryName = "JSX"; const JSXAutomaticName = "jsx_module"; const MacroRefs = std.AutoArrayHashMap(Ref, u32); const BunJSX = struct { pub threadlocal var bun_jsx_identifier: E.Identifier = undefined; }; pub fn ExpressionTransposer( comptime Kontext: type, visitor: fn (ptr: *Kontext, arg: Expr, state: anytype) Expr, ) type { return struct { pub const Context = Kontext; pub const This = @This(); context: *Context, pub fn init(c: *Context) This { return This{ .context = c, }; } pub fn maybeTransposeIf(self: *This, arg: Expr, state: anytype) Expr { switch (arg.data) { .e_if => |ex| { ex.yes = self.maybeTransposeIf(ex.yes, state); ex.no = self.maybeTransposeIf(ex.no, state); return arg; }, else => { return visitor(self.context, arg, state); }, } } }; } pub fn locAfterOp(e: E.Binary) logger.Loc { if (e.left.loc.start < e.right.loc.start) { return e.right.loc; } else { // handle the case when we have transposed the operands return e.left.loc; } } const ExportsStringName = "exports"; // We must prevent collisions from generated names. // We want to avoid adding a pass over all the symbols in the file. // To do that: // For every generated symbol, we reserve two backup symbol names // If any usages of the preferred ref, we swap original_name with the backup // If any usages of the backup ref, we swap original_name with the internal // We *assume* the internal name is never used. // In practice, it is possible. But, the internal names are so crazy long you'd have to be deliberately trying to use them. const GeneratedSymbol = @import("../runtime.zig").Runtime.GeneratedSymbol; pub const ImportScanner = struct { stmts: []Stmt = &([_]Stmt{}), kept_import_equals: bool = false, removed_import_equals: bool = false, pub fn scan(comptime P: type, p: P, stmts: []Stmt, comptime convert_exports: bool) !ImportScanner { var scanner = ImportScanner{}; var stmts_end: usize = 0; for (stmts) |_stmt, _stmt_i| { // zls needs the hint, it seems. var stmt: Stmt = _stmt; switch (stmt.data) { .s_import => |st| { var record: *ImportRecord = &p.import_records.items[st.import_record_index]; if (strings.eqlComptime(record.path.namespace, "macro")) { record.is_unused = true; record.path.is_disabled = true; continue; } // The official TypeScript compiler always removes unused imported // symbols. However, we deliberately deviate from the official // TypeScript compiler's behavior doing this in a specific scenario: // we are not bundling, symbol renaming is off, and the tsconfig.json // "importsNotUsedAsValues" setting is present and is not set to // "remove". // // This exists to support the use case of compiling partial modules for // compile-to-JavaScript languages such as Svelte. These languages try // to reference imports in ways that are impossible for esbuild to know // about when esbuild is only given a partial module to compile. Here // is an example of some Svelte code that might use esbuild to convert // TypeScript to JavaScript: // // //
//

Hello {name}!

// //
// // Tools that use esbuild to compile TypeScript code inside a Svelte // file like this only give esbuild the contents of the