mirror of
https://github.com/oven-sh/bun
synced 2026-02-02 15:08:46 +00:00
exports!
This commit is contained in:
@@ -35,30 +35,30 @@ pub const ImportRecord = struct {
|
||||
// Sometimes the parser creates an import record and decides it isn't needed.
|
||||
// For example, TypeScript code may have import statements that later turn
|
||||
// out to be type-only imports after analyzing the whole file.
|
||||
is_unused: bool,
|
||||
is_unused: bool = false,
|
||||
|
||||
// If this is true, the import contains syntax like "* as ns". This is used
|
||||
// to determine whether modules that have no exports need to be wrapped in a
|
||||
// CommonJS wrapper or not.
|
||||
contains_import_star: bool,
|
||||
contains_import_star: bool = false,
|
||||
|
||||
// If this is true, the import contains an import for the alias "default",
|
||||
// either via the "import x from" or "import {default as x} from" syntax.
|
||||
contains_default_alias: bool,
|
||||
contains_default_alias: bool = false,
|
||||
|
||||
// If true, this "export * from 'path'" statement is evaluated at run-time by
|
||||
// calling the "__reExport()" helper function
|
||||
calls_run_time_re_export_fn: bool,
|
||||
calls_run_time_re_export_fn: bool = false,
|
||||
|
||||
// Tell the printer to wrap this call to "require()" in "__toModule(...)"
|
||||
wrap_with_to_module: bool,
|
||||
wrap_with_to_module: bool = false,
|
||||
|
||||
// True for require calls like this: "try { require() } catch {}". In this
|
||||
// case we shouldn't generate an error if the path could not be resolved.
|
||||
is_inside_try_body: bool,
|
||||
is_inside_try_body: bool = false,
|
||||
|
||||
// If true, this was originally written as a bare "import 'file'" statement
|
||||
was_originally_bare_import: bool,
|
||||
was_originally_bare_import: bool = false,
|
||||
|
||||
kind: ImportKind,
|
||||
};
|
||||
|
||||
558
src/js_ast.zig
558
src/js_ast.zig
@@ -237,6 +237,15 @@ pub const G = struct {
|
||||
alias: string,
|
||||
};
|
||||
|
||||
pub const ExportStarAlias = struct {
|
||||
loc: logger.Loc,
|
||||
|
||||
// Although this alias name starts off as being the same as the statement's
|
||||
// namespace symbol, it may diverge if the namespace symbol name is minified.
|
||||
// The original alias name is preserved here to avoid this scenario.
|
||||
original_name: string,
|
||||
};
|
||||
|
||||
pub const Class = struct {
|
||||
class_keyword: logger.Range = logger.Range.None,
|
||||
ts_decorators: ExprNodeList = &([_]Expr{}),
|
||||
@@ -822,252 +831,228 @@ pub const Stmt = struct {
|
||||
|
||||
var None = S.Empty{};
|
||||
|
||||
pub fn init(st: anytype, loc: logger.Loc) Stmt {
|
||||
if (@typeInfo(@TypeOf(st)) != .Pointer) {
|
||||
pub fn init(origData: anytype, loc: logger.Loc) Stmt {
|
||||
if (@typeInfo(@TypeOf(origData)) != .Pointer) {
|
||||
@compileError("Stmt.init needs a pointer.");
|
||||
}
|
||||
|
||||
switch (@TypeOf(st.*)) {
|
||||
switch (@TypeOf(origData.*)) {
|
||||
S.Block => {
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_block = st } };
|
||||
},
|
||||
S.SExpr => {
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_expr = st } };
|
||||
},
|
||||
S.Comment => {
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_comment = st } };
|
||||
},
|
||||
S.Directive => {
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_directive = st } };
|
||||
},
|
||||
S.ExportClause => {
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_export_clause = st } };
|
||||
},
|
||||
S.Empty => {
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_empty = st } };
|
||||
},
|
||||
S.TypeScript => {
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_type_script = st } };
|
||||
},
|
||||
S.Debugger => {
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_debugger = st } };
|
||||
},
|
||||
S.ExportFrom => {
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_export_from = st } };
|
||||
},
|
||||
S.ExportDefault => {
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_export_default = st } };
|
||||
},
|
||||
S.Enum => {
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_enum = st } };
|
||||
},
|
||||
S.Namespace => {
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_namespace = st } };
|
||||
},
|
||||
S.Function => {
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_function = st } };
|
||||
},
|
||||
S.Class => {
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_class = st } };
|
||||
},
|
||||
S.If => {
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_if = st } };
|
||||
},
|
||||
S.For => {
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_for = st } };
|
||||
},
|
||||
S.ForIn => {
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_for_in = st } };
|
||||
},
|
||||
S.ForOf => {
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_for_of = st } };
|
||||
},
|
||||
S.DoWhile => {
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_do_while = st } };
|
||||
},
|
||||
S.While => {
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_while = st } };
|
||||
},
|
||||
S.With => {
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_with = st } };
|
||||
},
|
||||
S.Try => {
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_try = st } };
|
||||
},
|
||||
S.Switch => {
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_switch = st } };
|
||||
},
|
||||
S.Import => {
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_import = st } };
|
||||
},
|
||||
S.Return => {
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_return = st } };
|
||||
},
|
||||
S.Throw => {
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_throw = st } };
|
||||
},
|
||||
S.Local => {
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_local = st } };
|
||||
return Stmt.comptime_init("s_block", S.Block, origData, loc);
|
||||
},
|
||||
S.Break => {
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_break = st } };
|
||||
return Stmt.comptime_init("s_break", S.Break, origData, loc);
|
||||
},
|
||||
S.Class => {
|
||||
return Stmt.comptime_init("s_class", S.Class, origData, loc);
|
||||
},
|
||||
S.Comment => {
|
||||
return Stmt.comptime_init("s_comment", S.Comment, origData, loc);
|
||||
},
|
||||
S.Continue => {
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_continue = st } };
|
||||
return Stmt.comptime_init("s_continue", S.Continue, origData, loc);
|
||||
},
|
||||
S.Debugger => {
|
||||
return Stmt.comptime_init("s_debugger", S.Debugger, origData, loc);
|
||||
},
|
||||
S.Directive => {
|
||||
return Stmt.comptime_init("s_directive", S.Directive, origData, loc);
|
||||
},
|
||||
S.DoWhile => {
|
||||
return Stmt.comptime_init("s_do_while", S.DoWhile, origData, loc);
|
||||
},
|
||||
S.Empty => {
|
||||
return Stmt.comptime_init("s_empty", S.Empty, origData, loc);
|
||||
},
|
||||
S.Enum => {
|
||||
return Stmt.comptime_init("s_enum", S.Enum, origData, loc);
|
||||
},
|
||||
S.ExportClause => {
|
||||
return Stmt.comptime_init("s_export_clause", S.ExportClause, origData, loc);
|
||||
},
|
||||
S.ExportDefault => {
|
||||
return Stmt.comptime_init("s_export_default", S.ExportDefault, origData, loc);
|
||||
},
|
||||
S.ExportEquals => {
|
||||
return Stmt.comptime_init("s_export_equals", S.ExportEquals, origData, loc);
|
||||
},
|
||||
S.ExportFrom => {
|
||||
return Stmt.comptime_init("s_export_from", S.ExportFrom, origData, loc);
|
||||
},
|
||||
S.ExportStar => {
|
||||
return Stmt.comptime_init("s_export_star", S.ExportStar, origData, loc);
|
||||
},
|
||||
S.SExpr => {
|
||||
return Stmt.comptime_init("s_expr", S.SExpr, origData, loc);
|
||||
},
|
||||
S.ForIn => {
|
||||
return Stmt.comptime_init("s_for_in", S.ForIn, origData, loc);
|
||||
},
|
||||
S.ForOf => {
|
||||
return Stmt.comptime_init("s_for_of", S.ForOf, origData, loc);
|
||||
},
|
||||
S.For => {
|
||||
return Stmt.comptime_init("s_for", S.For, origData, loc);
|
||||
},
|
||||
S.Function => {
|
||||
return Stmt.comptime_init("s_function", S.Function, origData, loc);
|
||||
},
|
||||
S.If => {
|
||||
return Stmt.comptime_init("s_if", S.If, origData, loc);
|
||||
},
|
||||
S.Import => {
|
||||
return Stmt.comptime_init("s_import", S.Import, origData, loc);
|
||||
},
|
||||
S.Label => {
|
||||
return Stmt.comptime_init("s_label", S.Label, origData, loc);
|
||||
},
|
||||
S.LazyExport => {
|
||||
return Stmt.comptime_init("s_lazy_export", S.LazyExport, origData, loc);
|
||||
},
|
||||
S.Local => {
|
||||
return Stmt.comptime_init("s_local", S.Local, origData, loc);
|
||||
},
|
||||
S.Namespace => {
|
||||
return Stmt.comptime_init("s_namespace", S.Namespace, origData, loc);
|
||||
},
|
||||
S.Return => {
|
||||
return Stmt.comptime_init("s_return", S.Return, origData, loc);
|
||||
},
|
||||
S.Switch => {
|
||||
return Stmt.comptime_init("s_switch", S.Switch, origData, loc);
|
||||
},
|
||||
S.Throw => {
|
||||
return Stmt.comptime_init("s_throw", S.Throw, origData, loc);
|
||||
},
|
||||
S.Try => {
|
||||
return Stmt.comptime_init("s_try", S.Try, origData, loc);
|
||||
},
|
||||
S.TypeScript => {
|
||||
return Stmt.comptime_init("s_type_script", S.TypeScript, origData, loc);
|
||||
},
|
||||
S.While => {
|
||||
return Stmt.comptime_init("s_while", S.While, origData, loc);
|
||||
},
|
||||
S.With => {
|
||||
return Stmt.comptime_init("s_with", S.With, origData, loc);
|
||||
},
|
||||
else => {
|
||||
@compileError("Invalid type in Stmt.init");
|
||||
},
|
||||
}
|
||||
}
|
||||
fn comptime_alloc(allocator: *std.mem.Allocator, comptime tag_name: string, comptime typename: type, origData: anytype, loc: logger.Loc) callconv(.Inline) Stmt {
|
||||
var st = allocator.create(typename) catch unreachable;
|
||||
st.* = origData;
|
||||
return Stmt{ .loc = loc, .data = @unionInit(Data, tag_name, st) };
|
||||
}
|
||||
|
||||
fn comptime_init(comptime tag_name: string, comptime typename: type, origData: anytype, loc: logger.Loc) callconv(.Inline) Stmt {
|
||||
return Stmt{ .loc = loc, .data = @unionInit(Data, tag_name, origData) };
|
||||
}
|
||||
|
||||
pub fn alloc(allocator: *std.mem.Allocator, origData: anytype, loc: logger.Loc) Stmt {
|
||||
switch (@TypeOf(origData)) {
|
||||
S.Block => {
|
||||
var st = allocator.create(S.Block) catch unreachable;
|
||||
st.* = origData;
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_block = st } };
|
||||
},
|
||||
S.SExpr => {
|
||||
var st = allocator.create(S.SExpr) catch unreachable;
|
||||
st.* = origData;
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_expr = st } };
|
||||
},
|
||||
S.Comment => {
|
||||
var st = allocator.create(S.Comment) catch unreachable;
|
||||
st.* = origData;
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_comment = st } };
|
||||
},
|
||||
S.Directive => {
|
||||
var st = allocator.create(S.Directive) catch unreachable;
|
||||
st.* = origData;
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_directive = st } };
|
||||
},
|
||||
S.ExportClause => {
|
||||
var st = allocator.create(S.ExportClause) catch unreachable;
|
||||
st.* = origData;
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_export_clause = st } };
|
||||
},
|
||||
S.Empty => {
|
||||
var st = allocator.create(S.Empty) catch unreachable;
|
||||
st.* = origData;
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_empty = st } };
|
||||
},
|
||||
S.TypeScript => {
|
||||
var st = allocator.create(S.TypeScript) catch unreachable;
|
||||
st.* = origData;
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_type_script = st } };
|
||||
},
|
||||
S.Debugger => {
|
||||
var st = allocator.create(S.Debugger) catch unreachable;
|
||||
st.* = origData;
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_debugger = st } };
|
||||
},
|
||||
S.ExportFrom => {
|
||||
var st = allocator.create(S.ExportFrom) catch unreachable;
|
||||
st.* = origData;
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_export_from = st } };
|
||||
},
|
||||
S.ExportDefault => {
|
||||
var st = allocator.create(S.ExportDefault) catch unreachable;
|
||||
st.* = origData;
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_export_default = st } };
|
||||
},
|
||||
S.Enum => {
|
||||
var st = allocator.create(S.Enum) catch unreachable;
|
||||
st.* = origData;
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_enum = st } };
|
||||
},
|
||||
S.Namespace => {
|
||||
var st = allocator.create(S.Namespace) catch unreachable;
|
||||
st.* = origData;
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_namespace = st } };
|
||||
},
|
||||
S.Function => {
|
||||
var st = allocator.create(S.Function) catch unreachable;
|
||||
st.* = origData;
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_function = st } };
|
||||
},
|
||||
S.Class => {
|
||||
var st = allocator.create(S.Class) catch unreachable;
|
||||
st.* = origData;
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_class = st } };
|
||||
},
|
||||
S.If => {
|
||||
var st = allocator.create(S.If) catch unreachable;
|
||||
st.* = origData;
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_if = st } };
|
||||
},
|
||||
S.For => {
|
||||
var st = allocator.create(S.For) catch unreachable;
|
||||
st.* = origData;
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_for = st } };
|
||||
},
|
||||
S.ForIn => {
|
||||
var st = allocator.create(S.ForIn) catch unreachable;
|
||||
st.* = origData;
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_for_in = st } };
|
||||
},
|
||||
S.ForOf => {
|
||||
var st = allocator.create(S.ForOf) catch unreachable;
|
||||
st.* = origData;
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_for_of = st } };
|
||||
},
|
||||
S.DoWhile => {
|
||||
var st = allocator.create(S.DoWhile) catch unreachable;
|
||||
st.* = origData;
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_do_while = st } };
|
||||
},
|
||||
S.While => {
|
||||
var st = allocator.create(S.While) catch unreachable;
|
||||
st.* = origData;
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_while = st } };
|
||||
},
|
||||
S.With => {
|
||||
var st = allocator.create(S.With) catch unreachable;
|
||||
st.* = origData;
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_with = st } };
|
||||
},
|
||||
S.Try => {
|
||||
var st = allocator.create(S.Try) catch unreachable;
|
||||
st.* = origData;
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_try = st } };
|
||||
},
|
||||
S.Switch => {
|
||||
var st = allocator.create(S.Switch) catch unreachable;
|
||||
st.* = origData;
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_switch = st } };
|
||||
},
|
||||
S.Import => {
|
||||
var st = allocator.create(S.Import) catch unreachable;
|
||||
st.* = origData;
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_import = st } };
|
||||
},
|
||||
S.Return => {
|
||||
var st = allocator.create(S.Return) catch unreachable;
|
||||
st.* = origData;
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_return = st } };
|
||||
},
|
||||
S.Throw => {
|
||||
var st = allocator.create(S.Throw) catch unreachable;
|
||||
st.* = origData;
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_throw = st } };
|
||||
},
|
||||
S.Local => {
|
||||
var st = allocator.create(S.Local) catch unreachable;
|
||||
st.* = origData;
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_local = st } };
|
||||
return Stmt.comptime_alloc(allocator, "s_block", S.Block, origData, loc);
|
||||
},
|
||||
S.Break => {
|
||||
var st = allocator.create(S.Break) catch unreachable;
|
||||
st.* = origData;
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_break = st } };
|
||||
return Stmt.comptime_alloc(allocator, "s_break", S.Break, origData, loc);
|
||||
},
|
||||
S.Class => {
|
||||
return Stmt.comptime_alloc(allocator, "s_class", S.Class, origData, loc);
|
||||
},
|
||||
S.Comment => {
|
||||
return Stmt.comptime_alloc(allocator, "s_comment", S.Comment, origData, loc);
|
||||
},
|
||||
S.Continue => {
|
||||
var st = allocator.create(S.Continue) catch unreachable;
|
||||
st.* = origData;
|
||||
return Stmt{ .loc = loc, .data = Data{ .s_continue = st } };
|
||||
return Stmt.comptime_alloc(allocator, "s_continue", S.Continue, origData, loc);
|
||||
},
|
||||
S.Debugger => {
|
||||
return Stmt.comptime_alloc(allocator, "s_debugger", S.Debugger, origData, loc);
|
||||
},
|
||||
S.Directive => {
|
||||
return Stmt.comptime_alloc(allocator, "s_directive", S.Directive, origData, loc);
|
||||
},
|
||||
S.DoWhile => {
|
||||
return Stmt.comptime_alloc(allocator, "s_do_while", S.DoWhile, origData, loc);
|
||||
},
|
||||
S.Empty => {
|
||||
return Stmt.comptime_alloc(allocator, "s_empty", S.Empty, origData, loc);
|
||||
},
|
||||
S.Enum => {
|
||||
return Stmt.comptime_alloc(allocator, "s_enum", S.Enum, origData, loc);
|
||||
},
|
||||
S.ExportClause => {
|
||||
return Stmt.comptime_alloc(allocator, "s_export_clause", S.ExportClause, origData, loc);
|
||||
},
|
||||
S.ExportDefault => {
|
||||
return Stmt.comptime_alloc(allocator, "s_export_default", S.ExportDefault, origData, loc);
|
||||
},
|
||||
S.ExportEquals => {
|
||||
return Stmt.comptime_alloc(allocator, "s_export_equals", S.ExportEquals, origData, loc);
|
||||
},
|
||||
S.ExportFrom => {
|
||||
return Stmt.comptime_alloc(allocator, "s_export_from", S.ExportFrom, origData, loc);
|
||||
},
|
||||
S.ExportStar => {
|
||||
return Stmt.comptime_alloc(allocator, "s_export_star", S.ExportStar, origData, loc);
|
||||
},
|
||||
S.SExpr => {
|
||||
return Stmt.comptime_alloc(allocator, "s_expr", S.SExpr, origData, loc);
|
||||
},
|
||||
S.ForIn => {
|
||||
return Stmt.comptime_alloc(allocator, "s_for_in", S.ForIn, origData, loc);
|
||||
},
|
||||
S.ForOf => {
|
||||
return Stmt.comptime_alloc(allocator, "s_for_of", S.ForOf, origData, loc);
|
||||
},
|
||||
S.For => {
|
||||
return Stmt.comptime_alloc(allocator, "s_for", S.For, origData, loc);
|
||||
},
|
||||
S.Function => {
|
||||
return Stmt.comptime_alloc(allocator, "s_function", S.Function, origData, loc);
|
||||
},
|
||||
S.If => {
|
||||
return Stmt.comptime_alloc(allocator, "s_if", S.If, origData, loc);
|
||||
},
|
||||
S.Import => {
|
||||
return Stmt.comptime_alloc(allocator, "s_import", S.Import, origData, loc);
|
||||
},
|
||||
S.Label => {
|
||||
return Stmt.comptime_alloc(allocator, "s_label", S.Label, origData, loc);
|
||||
},
|
||||
S.LazyExport => {
|
||||
return Stmt.comptime_alloc(allocator, "s_lazy_export", S.LazyExport, origData, loc);
|
||||
},
|
||||
S.Local => {
|
||||
return Stmt.comptime_alloc(allocator, "s_local", S.Local, origData, loc);
|
||||
},
|
||||
S.Namespace => {
|
||||
return Stmt.comptime_alloc(allocator, "s_namespace", S.Namespace, origData, loc);
|
||||
},
|
||||
S.Return => {
|
||||
return Stmt.comptime_alloc(allocator, "s_return", S.Return, origData, loc);
|
||||
},
|
||||
S.Switch => {
|
||||
return Stmt.comptime_alloc(allocator, "s_switch", S.Switch, origData, loc);
|
||||
},
|
||||
S.Throw => {
|
||||
return Stmt.comptime_alloc(allocator, "s_throw", S.Throw, origData, loc);
|
||||
},
|
||||
S.Try => {
|
||||
return Stmt.comptime_alloc(allocator, "s_try", S.Try, origData, loc);
|
||||
},
|
||||
S.TypeScript => {
|
||||
return Stmt.comptime_alloc(allocator, "s_type_script", S.TypeScript, origData, loc);
|
||||
},
|
||||
S.While => {
|
||||
return Stmt.comptime_alloc(allocator, "s_while", S.While, origData, loc);
|
||||
},
|
||||
S.With => {
|
||||
return Stmt.comptime_alloc(allocator, "s_with", S.With, origData, loc);
|
||||
},
|
||||
|
||||
else => {
|
||||
@compileError("Invalid type in Stmt.init");
|
||||
},
|
||||
@@ -1076,66 +1061,74 @@ pub const Stmt = struct {
|
||||
|
||||
pub const Tag = packed enum {
|
||||
s_block,
|
||||
s_comment,
|
||||
s_directive,
|
||||
s_export_clause,
|
||||
s_empty,
|
||||
s_type_script,
|
||||
s_debugger,
|
||||
s_export_from,
|
||||
s_export_default,
|
||||
s_enum,
|
||||
s_namespace,
|
||||
s_function,
|
||||
s_break,
|
||||
s_class,
|
||||
s_if,
|
||||
s_for,
|
||||
s_comment,
|
||||
s_continue,
|
||||
s_debugger,
|
||||
s_directive,
|
||||
s_do_while,
|
||||
s_empty,
|
||||
s_enum,
|
||||
s_export_clause,
|
||||
s_export_default,
|
||||
s_export_equals,
|
||||
s_export_from,
|
||||
s_export_star,
|
||||
s_expr,
|
||||
s_for_in,
|
||||
s_for_of,
|
||||
s_do_while,
|
||||
s_for,
|
||||
s_function,
|
||||
s_if,
|
||||
s_import,
|
||||
s_label,
|
||||
s_lazy_export,
|
||||
s_local,
|
||||
s_namespace,
|
||||
s_return,
|
||||
s_switch,
|
||||
s_throw,
|
||||
s_try,
|
||||
s_type_script,
|
||||
s_while,
|
||||
s_with,
|
||||
s_try,
|
||||
s_switch,
|
||||
s_import,
|
||||
s_return,
|
||||
s_throw,
|
||||
s_local,
|
||||
s_break,
|
||||
s_continue,
|
||||
s_expr,
|
||||
};
|
||||
|
||||
pub const Data = union(Tag) {
|
||||
s_block: *S.Block,
|
||||
s_expr: *S.SExpr,
|
||||
s_comment: *S.Comment,
|
||||
s_directive: *S.Directive,
|
||||
s_export_clause: *S.ExportClause,
|
||||
s_empty: *S.Empty,
|
||||
s_type_script: *S.TypeScript,
|
||||
s_debugger: *S.Debugger,
|
||||
s_export_from: *S.ExportFrom,
|
||||
s_export_default: *S.ExportDefault,
|
||||
s_enum: *S.Enum,
|
||||
s_namespace: *S.Namespace,
|
||||
s_function: *S.Function,
|
||||
s_break: *S.Break,
|
||||
s_class: *S.Class,
|
||||
s_if: *S.If,
|
||||
s_for: *S.For,
|
||||
s_comment: *S.Comment,
|
||||
s_continue: *S.Continue,
|
||||
s_debugger: *S.Debugger,
|
||||
s_directive: *S.Directive,
|
||||
s_do_while: *S.DoWhile,
|
||||
s_empty: *S.Empty,
|
||||
s_enum: *S.Enum,
|
||||
s_export_clause: *S.ExportClause,
|
||||
s_export_default: *S.ExportDefault,
|
||||
s_export_equals: *S.ExportEquals,
|
||||
s_export_from: *S.ExportFrom,
|
||||
s_export_star: *S.ExportStar,
|
||||
s_expr: *S.SExpr,
|
||||
s_for_in: *S.ForIn,
|
||||
s_for_of: *S.ForOf,
|
||||
s_do_while: *S.DoWhile,
|
||||
s_for: *S.For,
|
||||
s_function: *S.Function,
|
||||
s_if: *S.If,
|
||||
s_import: *S.Import,
|
||||
s_label: *S.Label,
|
||||
s_lazy_export: *S.LazyExport,
|
||||
s_local: *S.Local,
|
||||
s_namespace: *S.Namespace,
|
||||
s_return: *S.Return,
|
||||
s_switch: *S.Switch,
|
||||
s_throw: *S.Throw,
|
||||
s_try: *S.Try,
|
||||
s_type_script: *S.TypeScript,
|
||||
s_while: *S.While,
|
||||
s_with: *S.With,
|
||||
s_try: *S.Try,
|
||||
s_switch: *S.Switch,
|
||||
s_import: *S.Import,
|
||||
s_return: *S.Return,
|
||||
s_throw: *S.Throw,
|
||||
s_local: *S.Local,
|
||||
s_break: *S.Break,
|
||||
s_continue: *S.Continue,
|
||||
};
|
||||
|
||||
pub fn caresAboutScope(self: *Stmt) bool {
|
||||
@@ -2141,10 +2134,25 @@ pub const S = struct {
|
||||
|
||||
pub const Directive = struct { value: JavascriptString, legacy_octal_loc: logger.Loc };
|
||||
|
||||
pub const ExportClause = struct { items: []ClauseItem };
|
||||
pub const ExportClause = struct { items: []ClauseItem, is_single_line: bool = false };
|
||||
|
||||
pub const Empty = struct {};
|
||||
|
||||
pub const ExportStar = struct {
|
||||
namespace_ref: Ref,
|
||||
alias: ?G.ExportStarAlias = null,
|
||||
import_record_index: u32,
|
||||
};
|
||||
|
||||
// This is an "export = value;" statement in TypeScript
|
||||
pub const ExportEquals = struct { value: ExprNodeIndex };
|
||||
|
||||
// The decision of whether to export an expression using "module.exports" or
|
||||
// "export default" is deferred until linking using this statement kind
|
||||
pub const LazyExport = struct { value: ExprNodeIndex };
|
||||
|
||||
pub const Label = struct { name: LocRef, stmt: StmtNodeIndex };
|
||||
|
||||
// This is a stand-in for a TypeScript type declaration
|
||||
pub const TypeScript = struct {};
|
||||
|
||||
@@ -2194,9 +2202,13 @@ pub const S = struct {
|
||||
// May be a SConst, SLet, SVar, or SExpr
|
||||
init: StmtNodeIndex, value: ExprNodeIndex, body: StmtNodeIndex };
|
||||
|
||||
pub const ForOf = struct { is_await: bool,
|
||||
// May be a SConst, SLet, SVar, or SExpr
|
||||
init: StmtNodeIndex, value: ExprNodeIndex, body: StmtNodeIndex };
|
||||
pub const ForOf = struct {
|
||||
is_await: bool = false,
|
||||
// May be a SConst, SLet, SVar, or SExpr
|
||||
init: StmtNodeIndex,
|
||||
value: ExprNodeIndex,
|
||||
body: StmtNodeIndex,
|
||||
};
|
||||
|
||||
pub const DoWhile = struct { body: StmtNodeIndex, test_: ExprNodeIndex };
|
||||
|
||||
|
||||
@@ -303,7 +303,7 @@ pub const Lexer = struct {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn expectContextualKeyword(self: *Lexer, keyword: string) void {
|
||||
pub fn expectContextualKeyword(self: *Lexer, comptime keyword: string) void {
|
||||
if (!self.isContextualKeyword(keyword)) {
|
||||
self.addError(self.start, "\"{s}\"", .{keyword}, true);
|
||||
}
|
||||
@@ -765,7 +765,7 @@ pub const Lexer = struct {
|
||||
return self.source.contents[self.start..self.end];
|
||||
}
|
||||
|
||||
pub fn isContextualKeyword(self: *Lexer, keyword: string) bool {
|
||||
pub fn isContextualKeyword(self: *Lexer, comptime keyword: string) bool {
|
||||
return self.token == .t_identifier and strings.eql(self.raw(), keyword);
|
||||
}
|
||||
|
||||
@@ -844,7 +844,7 @@ pub const Lexer = struct {
|
||||
|
||||
// TODO: use wtf-8 encoding.
|
||||
pub fn utf16ToString(lexer: *Lexer, js: JavascriptString) string {
|
||||
return std.unicode.utf16leToUtf8Alloc(lexer.alloc, js) catch unreachable;
|
||||
return std.unicode.utf16leToUtf8Alloc(lexer.allocator, js) catch unreachable;
|
||||
}
|
||||
|
||||
pub fn nextInsideJSXElement() void {
|
||||
|
||||
@@ -5,10 +5,13 @@ const importRecord = @import("import_record.zig");
|
||||
const js_ast = @import("js_ast.zig");
|
||||
const options = @import("options.zig");
|
||||
const alloc = @import("alloc.zig");
|
||||
|
||||
const fs = @import("fs.zig");
|
||||
usingnamespace @import("strings.zig");
|
||||
usingnamespace @import("ast/base.zig");
|
||||
usingnamespace js_ast.G;
|
||||
|
||||
const ImportKind = importRecord.ImportKind;
|
||||
const BindingNodeIndex = js_ast.BindingNodeIndex;
|
||||
const StmtNodeIndex = js_ast.StmtNodeIndex;
|
||||
const ExprNodeIndex = js_ast.ExprNodeIndex;
|
||||
@@ -65,6 +68,8 @@ const ThenCatchChain = struct {
|
||||
has_catch: bool = false,
|
||||
};
|
||||
|
||||
const ParsedPath = struct { loc: logger.Loc, text: string };
|
||||
|
||||
const StrictModeFeature = enum {
|
||||
with_statement,
|
||||
delete_bare_name,
|
||||
@@ -305,6 +310,8 @@ pub const Parser = struct {
|
||||
}
|
||||
};
|
||||
|
||||
const ExportClauseResult = struct { clauses: []js_ast.ClauseItem = &([_]js_ast.ClauseItem{}), is_single_line: bool = false };
|
||||
|
||||
const DeferredTsDecorators = struct {
|
||||
values: []js_ast.Expr,
|
||||
|
||||
@@ -1461,8 +1468,83 @@ const P = struct {
|
||||
p.lexer.expectOrInsertSemicolon();
|
||||
return p.s(S.ExportDefault{ .default_name = createDefaultName(p, loc) catch unreachable, .value = js_ast.StmtOrExpr{ .expr = expr } }, loc);
|
||||
},
|
||||
T.t_asterisk => {
|
||||
if (!opts.is_module_scope and !(opts.is_namespace_scope or !opts.is_typescript_declare)) {
|
||||
p.lexer.unexpected();
|
||||
}
|
||||
|
||||
p.lexer.next();
|
||||
var namespace_ref: js_ast.Ref = undefined;
|
||||
var alias: ?js_ast.G.ExportStarAlias = null;
|
||||
var path_loc: logger.Loc = undefined;
|
||||
var path_text: string = undefined;
|
||||
|
||||
if (p.lexer.isContextualKeyword("as")) {
|
||||
// "export * as ns from 'path'"
|
||||
const name = p.lexer.identifier;
|
||||
namespace_ref = p.storeNameInRef(name) catch unreachable;
|
||||
alias = G.ExportStarAlias{ .loc = p.lexer.loc(), .original_name = name };
|
||||
if (!p.lexer.isIdentifierOrKeyword()) {
|
||||
p.lexer.expect(.t_identifier);
|
||||
}
|
||||
p.checkForNonBMPCodePoint((alias orelse unreachable).loc, name);
|
||||
p.lexer.next();
|
||||
p.lexer.expectContextualKeyword("from");
|
||||
const parsedPath = p.parsePath();
|
||||
path_loc = parsedPath.loc;
|
||||
path_text = parsedPath.text;
|
||||
} else {
|
||||
// "export * from 'path'"
|
||||
p.lexer.expectContextualKeyword("from");
|
||||
const parsedPath = p.parsePath();
|
||||
path_loc = parsedPath.loc;
|
||||
path_text = parsedPath.text;
|
||||
var path_name = fs.PathName.init(strings.append(p.allocator, path_text, "_star") catch unreachable);
|
||||
namespace_ref = p.storeNameInRef(path_name.nonUniqueNameString(p.allocator) catch unreachable) catch unreachable;
|
||||
}
|
||||
|
||||
var import_record_index = p.addImportRecord(ImportKind.stmt, path_loc, path_text);
|
||||
p.lexer.expectOrInsertSemicolon();
|
||||
return p.s(S.ExportStar{
|
||||
.namespace_ref = namespace_ref,
|
||||
.alias = alias,
|
||||
.import_record_index = import_record_index,
|
||||
}, loc);
|
||||
},
|
||||
T.t_open_brace => {
|
||||
if (!opts.is_module_scope and !(opts.is_namespace_scope or !opts.is_typescript_declare)) {
|
||||
p.lexer.unexpected();
|
||||
}
|
||||
|
||||
const export_clause = p.parseExportClause();
|
||||
if (p.lexer.isContextualKeyword("from")) {
|
||||
p.lexer.expectContextualKeyword("from");
|
||||
const parsedPath = p.parsePath();
|
||||
const import_record_index = p.addImportRecord(.stmt, parsedPath.loc, parsedPath.text);
|
||||
var path_name = fs.PathName.init(strings.append(p.allocator, "import_", parsedPath.text) catch unreachable);
|
||||
const namespace_ref = p.storeNameInRef(path_name.nonUniqueNameString(p.allocator) catch unreachable) catch unreachable;
|
||||
p.lexer.expectOrInsertSemicolon();
|
||||
return p.s(S.ExportFrom{ .items = export_clause.clauses, .is_single_line = export_clause.is_single_line, .namespace_ref = namespace_ref, .import_record_index = import_record_index }, loc);
|
||||
}
|
||||
p.lexer.expectOrInsertSemicolon();
|
||||
return p.s(S.ExportClause{ .items = export_clause.clauses, .is_single_line = export_clause.is_single_line }, loc);
|
||||
},
|
||||
T.t_equals => {
|
||||
// "export = value;"
|
||||
|
||||
p.es6_export_keyword = previousExportKeyword; // This wasn't an ESM export statement after all
|
||||
if (p.options.ts) {
|
||||
p.lexer.next();
|
||||
var value = p.parseExpr(.lowest);
|
||||
p.lexer.expectOrInsertSemicolon();
|
||||
return p.s(S.ExportEquals{ .value = value }, loc);
|
||||
}
|
||||
p.lexer.unexpected();
|
||||
return Stmt.empty();
|
||||
},
|
||||
else => {
|
||||
notimpl();
|
||||
p.lexer.unexpected();
|
||||
return Stmt.empty();
|
||||
},
|
||||
}
|
||||
},
|
||||
@@ -1475,6 +1557,114 @@ const P = struct {
|
||||
return js_ast.Stmt.empty();
|
||||
}
|
||||
|
||||
pub fn parseExportClause(p: *P) ExportClauseResult {
|
||||
var items = List(js_ast.ClauseItem).initCapacity(p.allocator, 1) catch unreachable;
|
||||
var first_keyword_item_loc = logger.Loc{};
|
||||
p.lexer.expect(.t_open_brace);
|
||||
var is_single_line = !p.lexer.has_newline_before;
|
||||
|
||||
while (p.lexer.token != .t_close_brace) {
|
||||
var alias = p.lexer.identifier;
|
||||
var alias_loc = p.lexer.loc();
|
||||
|
||||
var name = LocRef{
|
||||
.loc = alias_loc,
|
||||
.ref = p.storeNameInRef(alias) catch unreachable,
|
||||
};
|
||||
var original_name = alias;
|
||||
|
||||
// The name can actually be a keyword if we're really an "export from"
|
||||
// statement. However, we won't know until later. Allow keywords as
|
||||
// identifiers for now and throw an error later if there's no "from".
|
||||
//
|
||||
// // This is fine
|
||||
// export { default } from 'path'
|
||||
//
|
||||
// // This is a syntax error
|
||||
// export { default }
|
||||
//
|
||||
if (p.lexer.token != .t_identifier) {
|
||||
if (!p.lexer.isIdentifierOrKeyword()) {
|
||||
p.lexer.expect(.t_identifier);
|
||||
}
|
||||
if (first_keyword_item_loc.start == 0) {
|
||||
first_keyword_item_loc = p.lexer.loc();
|
||||
}
|
||||
}
|
||||
|
||||
p.checkForNonBMPCodePoint(alias_loc, alias);
|
||||
p.lexer.next();
|
||||
|
||||
if (p.lexer.isContextualKeyword("as")) {
|
||||
p.lexer.next();
|
||||
alias = p.lexer.identifier;
|
||||
alias_loc = p.lexer.loc();
|
||||
|
||||
// The alias may be a keyword
|
||||
if (!p.lexer.isIdentifierOrKeyword()) {
|
||||
p.lexer.expect(.t_identifier);
|
||||
}
|
||||
p.checkForNonBMPCodePoint(alias_loc, alias);
|
||||
p.lexer.next();
|
||||
}
|
||||
|
||||
items.append(js_ast.ClauseItem{
|
||||
.alias = alias,
|
||||
.alias_loc = alias_loc,
|
||||
.name = name,
|
||||
.original_name = original_name,
|
||||
}) catch unreachable;
|
||||
|
||||
// we're done if there's no comma
|
||||
if (p.lexer.token != .t_comma) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (p.lexer.has_newline_before) {
|
||||
is_single_line = false;
|
||||
}
|
||||
p.lexer.next();
|
||||
if (p.lexer.has_newline_before) {
|
||||
is_single_line = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (p.lexer.has_newline_before) {
|
||||
is_single_line = false;
|
||||
}
|
||||
p.lexer.expect(.t_close_brace);
|
||||
|
||||
// Throw an error here if we found a keyword earlier and this isn't an
|
||||
// "export from" statement after all
|
||||
if (first_keyword_item_loc.start != 0 and !p.lexer.isContextualKeyword("from")) {
|
||||
const r = js_lexer.rangeOfIdentifier(&p.source, first_keyword_item_loc);
|
||||
p.lexer.addRangeError(r, "Expected identifier but found \"{s}\"", .{p.source.textForRange(r)}, true);
|
||||
}
|
||||
|
||||
return ExportClauseResult{
|
||||
.clauses = items.toOwnedSlice(),
|
||||
.is_single_line = is_single_line,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn parsePath(p: *P) ParsedPath {
|
||||
var path = ParsedPath{
|
||||
.loc = p.lexer.loc(),
|
||||
.text = p.lexer.utf16ToString(p.lexer.string_literal),
|
||||
};
|
||||
|
||||
if (p.lexer.token == .t_no_substitution_template_literal) {
|
||||
p.lexer.next();
|
||||
} else {
|
||||
p.lexer.expect(.t_string_literal);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
// TODO:
|
||||
pub fn checkForNonBMPCodePoint(p: *P, loc: logger.Loc, name: string) void {}
|
||||
|
||||
pub fn parseStmtsUpTo(p: *P, eend: js_lexer.T, opts: *ParseStatementOptions) ![]Stmt {
|
||||
var stmts = try StmtList.initCapacity(p.allocator, 1);
|
||||
|
||||
@@ -1970,6 +2160,17 @@ const P = struct {
|
||||
return p.parseSuffix(expr, level, errors, flags);
|
||||
}
|
||||
|
||||
pub fn addImportRecord(p: *P, kind: ImportKind, loc: logger.Loc, name: string) u32 {
|
||||
var index = p.import_records.items.len;
|
||||
const record = ImportRecord{
|
||||
.kind = kind,
|
||||
.range = p.source.rangeOfString(loc),
|
||||
.path = fs.Path.init(name),
|
||||
};
|
||||
p.import_records.append(record) catch unreachable;
|
||||
return @intCast(u32, index);
|
||||
}
|
||||
|
||||
pub fn popScope(p: *P) void {
|
||||
const current_scope = p.current_scope orelse unreachable;
|
||||
// We cannot rename anything inside a scope containing a direct eval() call
|
||||
|
||||
@@ -266,6 +266,33 @@ pub const Source = struct {
|
||||
return Range{ .loc = loc };
|
||||
}
|
||||
|
||||
pub fn rangeOfString(self: *Source, loc: Loc) Range {
|
||||
const text = self.contents[loc.i()..];
|
||||
|
||||
if (text.len == 0) {
|
||||
return Range.None;
|
||||
}
|
||||
|
||||
const quote = text[0];
|
||||
|
||||
if (quote == '"' or quote == '\'') {
|
||||
var i: usize = 1;
|
||||
var c: u8 = undefined;
|
||||
while (i < text.len) {
|
||||
c = text[i];
|
||||
|
||||
if (c == quote) {
|
||||
return Range{ .loc = loc, .len = @intCast(i32, i + 1) };
|
||||
} else if (c == '\\') {
|
||||
i += 1;
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return Range{ .loc = loc, .len = 0 };
|
||||
}
|
||||
|
||||
pub fn rangeOfOperatorAfter(self: *Source, loc: Loc, op: string) Range {
|
||||
const text = self.contents[loc.i()..];
|
||||
const index = strings.index(text, op);
|
||||
|
||||
@@ -29,6 +29,10 @@ pub fn eql(self: string, other: anytype) bool {
|
||||
return std.mem.eql(u8, self, other);
|
||||
}
|
||||
|
||||
pub fn append(allocator: *std.mem.Allocator, self: string, other: string) !string {
|
||||
return std.fmt.allocPrint(allocator, "{s}{s}", .{ self, other });
|
||||
}
|
||||
|
||||
pub fn index(self: string, str: string) i32 {
|
||||
if (std.mem.indexOf(u8, self, str)) |i| {
|
||||
return @intCast(i32, i);
|
||||
|
||||
Reference in New Issue
Block a user