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);
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];
// 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