wip fix live bindings

This commit is contained in:
Jarred Sumner
2021-12-15 15:16:53 -08:00
parent c07de8c4d3
commit 8af6ad7278
6 changed files with 358 additions and 417 deletions

View File

@@ -438,6 +438,8 @@ s2n-mac:
CC=$(CC) CXX=$(CXX) cmake --build ./build -j$(CPUS); \
CC=$(CC) CXX=$(CXX) CTEST_PARALLEL_LEVEL=$(CPUS) ninja -C build
cp $(DEPS_DIR)/s2n-tls/build/lib/libs2n.a $(DEPS_DIR)/libs2n.a
libcrypto-old:
unlink $(DEPS_DIR)/libcrypto.a || echo "";
ln $(LIBCRYPTO_STATIC_LIB) $(DEPS_DIR)/libcrypto.a || echo "";

View File

@@ -1 +1 @@
2bbe5942da63d2ba
796022f759787f0a

View File

@@ -44,61 +44,64 @@ pub const ImportRecord = struct {
range: logger.Range,
path: fs.Path,
// 0 is invalid
/// 0 is invalid
module_id: u32 = 0,
source_index: Ref.Int = std.math.maxInt(Ref.Int),
print_mode: PrintMode = .normal,
// True for the following cases:
//
// try { require('x') } catch { handle }
// try { await import('x') } catch { handle }
// try { require.resolve('x') } catch { handle }
// import('x').catch(handle)
// import('x').then(_, handle)
//
// In these cases we shouldn't generate an error if the path could not be
// resolved.
/// True for the following cases:
///
/// try { require('x') } catch { handle }
/// try { await import('x') } catch { handle }
/// try { require.resolve('x') } catch { handle }
/// import('x').catch(handle)
/// import('x').then(_, handle)
///
/// In these cases we shouldn't generate an error if the path could not be
/// resolved.
handles_import_errors: bool = false,
is_internal: bool = false,
// This tells the printer that we should print as export var $moduleID = ...
// Instead of using the path.
/// This tells the printer that we should print as export var $moduleID = ...
/// Instead of using the path.
is_bundled: bool = false,
// 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.
/// 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 = 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.
/// 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 = 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.
/// 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 = false,
// If true, this "export * from 'path'" statement is evaluated at run-time by
// calling the "__reExport()" helper function
/// 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 = false,
// Tell the printer to wrap this call to "require()" in "__toModule(...)"
/// Tell the printer to wrap this call to "require()" in "__toModule(...)"
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.
/// 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 = false,
// If true, this was originally written as a bare "import 'file'" statement
/// If true, this was originally written as a bare "import 'file'" statement
was_originally_bare_import: bool = false,
was_originally_require: bool = false,
/// If a macro used <import>, it will be tracked here.
was_injected_by_macro: bool = false,
kind: ImportKind,
pub const PrintMode = enum {

View File

@@ -417,6 +417,7 @@ pub const G = struct {
pub const NamespaceAlias = struct {
namespace_ref: Ref,
alias: string,
import_record_index: u32 = std.math.maxInt(u32),
};
pub const ExportStarAlias = struct {
@@ -974,6 +975,8 @@ pub const E = struct {
// false, this could potentially have been a member access expression such
// as "ns.foo" off of an imported namespace object.
was_originally_identifier: bool = false,
was_from_macro: bool = false,
};
// This is similar to EIdentifier but it represents class-private fields and

View File

@@ -20,6 +20,8 @@ const ScopeOrderList = std.ArrayListUnmanaged(?ScopeOrder);
const JSXFactoryName = "JSX";
const JSXAutomaticName = "jsx_module";
// kept as a static reference
const exports_string_name: string = "exports";
const MacroRefs = std.AutoArrayHashMap(Ref, u32);
// If we are currently in a hoisted child of the module scope, relocate these
@@ -437,124 +439,77 @@ pub const ImportScanner = struct {
}
}
if (p.options.trim_unused_imports) {
if (st.star_name_loc != null or did_remove_star_loc) {
// -- Original Comment --
// If we're bundling a star import and the namespace is only ever
// used for property accesses, then convert each unique property to
// a clause item in the import statement and remove the star import.
// That will cause the bundler to bundle them more efficiently when
// both this module and the imported module are in the same group.
//
// Before:
//
// import * as ns from 'foo'
// console.log(ns.a, ns.b)
//
// After:
//
// import {a, b} from 'foo'
// console.log(a, b)
//
// This is not done if the namespace itself is used, because in that
// case the code for the namespace will have to be generated. This is
// determined by the symbol count because the parser only counts the
// star import as used if it was used for something other than a
// property access:
//
// import * as ns from 'foo'
// console.log(ns, ns.a, ns.b)
//
// -- Original Comment --
if (st.star_name_loc != null or did_remove_star_loc) {
// -- Original Comment --
// If we're bundling a star import and the namespace is only ever
// used for property accesses, then convert each unique property to
// a clause item in the import statement and remove the star import.
// That will cause the bundler to bundle them more efficiently when
// both this module and the imported module are in the same group.
//
// Before:
//
// import * as ns from 'foo'
// console.log(ns.a, ns.b)
//
// After:
//
// import {a, b} from 'foo'
// console.log(a, b)
//
// This is not done if the namespace itself is used, because in that
// case the code for the namespace will have to be generated. This is
// determined by the symbol count because the parser only counts the
// star import as used if it was used for something other than a
// property access:
//
// import * as ns from 'foo'
// console.log(ns, ns.a, ns.b)
//
// -- Original Comment --
// jarred: we don't use the same grouping mechanism as esbuild
// but, we do this anyway.
// The reasons why are:
// * It makes static analysis for other tools simpler.
// * I imagine browsers may someday do some optimizations
// when it's "easier" to know only certain modules are used
// For example, if you're importing a component from a design system
// it's really stupid to import all 1,000 components from that design system
// when you just want <Button />
const namespace_ref = st.namespace_ref;
const convert_star_to_clause = !p.options.enable_bundling and !p.options.can_import_from_bundle and p.symbols.items[namespace_ref.inner_index].use_count_estimate == 0;
// jarred: we don't use the same grouping mechanism as esbuild
// but, we do this anyway.
// The reasons why are:
// * It makes static analysis for other tools simpler.
// * I imagine browsers may someday do some optimizations
// when it's "easier" to know only certain modules are used
// For example, if you're importing a component from a design system
// it's really stupid to import all 1,000 components from that design system
// when you just want <Button />
const namespace_ref = st.namespace_ref;
const convert_star_to_clause = !p.options.enable_bundling and !p.options.can_import_from_bundle and p.symbols.items[namespace_ref.inner_index].use_count_estimate == 0;
if (convert_star_to_clause and !keep_unused_imports) {
st.star_name_loc = null;
}
if (convert_star_to_clause and !keep_unused_imports) {
st.star_name_loc = null;
}
// "import_items_for_namespace" has property accesses off the namespace
if (p.import_items_for_namespace.getPtr(namespace_ref)) |import_items| {
var count = import_items.count();
if (count > 0) {
// Sort keys for determinism
var sorted: []string = try p.allocator.alloc(string, count);
var iter = import_items.iterator();
var i: usize = 0;
while (iter.next()) |item| {
sorted[i] = item.key_ptr.*;
i += 1;
}
strings.sortAsc(sorted);
const default_name: string = if (st.default_name != null)
p.loadNameFromRef(st.default_name.?.ref.?)
else
"";
defer p.allocator.free(sorted);
if (convert_star_to_clause) {
// Create an import clause for these items. Named imports will be
// automatically created later on since there is now a clause.
var items = try p.allocator.alloc(js_ast.ClauseItem, count);
try p.declared_symbols.ensureUnusedCapacity(count);
i = 0;
for (sorted) |alias| {
const name: LocRef = import_items.get(alias) orelse unreachable;
const original_name = p.symbols.items[name.ref.?.inner_index].original_name;
items[i] = js_ast.ClauseItem{
.alias = alias,
.alias_loc = name.loc,
.name = name,
.original_name = original_name,
};
p.declared_symbols.appendAssumeCapacity(js_ast.DeclaredSymbol{
.ref = name.ref.?,
.is_top_level = true,
});
for (st.items) |item| {
const is_default = strings.eqlComptime(item.alias, "default");
record.contains_default_alias = record.contains_default_alias or is_default;
i += 1;
}
const name: LocRef = item.name;
const name_ref = name.ref.?;
if (st.items.len > 0) {
p.panic("The syntax \"import {{x}}, * as y from 'path'\" isn't valid", .{});
}
try p.named_imports.put(name_ref, js_ast.NamedImport{
.alias = item.alias,
.alias_loc = name.loc,
.namespace_ref = st.namespace_ref,
.import_record_index = st.import_record_index,
});
st.items = items;
} else {
// If we aren't converting this star import to a clause, still
// create named imports for these property accesses. This will
// cause missing imports to generate useful warnings.
//
// It will also improve bundling efficiency for internal imports
// by still converting property accesses off the namespace into
// bare identifiers even if the namespace is still needed.
for (sorted) |alias| {
const name: LocRef = import_items.get(alias) orelse unreachable;
const name_ref = name.ref.?;
try p.named_imports.put(name_ref, js_ast.NamedImport{
.alias = alias,
.alias_loc = name.loc,
.namespace_ref = st.namespace_ref,
.import_record_index = st.import_record_index,
});
record.contains_default_alias = record.contains_default_alias or strings.eqlComptime(alias, "default");
// Make sure the printer prints this as a property access
var symbol: *Symbol = &p.symbols.items[name_ref.inner_index];
symbol.namespace_alias = G.NamespaceAlias{ .namespace_ref = st.namespace_ref, .alias = alias };
}
}
}
}
// Make sure the printer prints this as a property access
var symbol: *Symbol = &p.symbols.items[name_ref.inner_index];
symbol.namespace_alias = G.NamespaceAlias{
.namespace_ref = st.namespace_ref,
.alias = item.original_name,
.import_record_index = st.import_record_index,
};
}
}
@@ -2002,11 +1957,8 @@ pub const Parser = struct {
// The problem with our scan pass approach is type-only imports.
// We don't have accurate symbol counts.
// So we don't have a good way to distuingish between a type-only import and not.
switch (comptime ParserType) {
TSXImportScanner, TypeScriptImportScanner => {
p.parse_pass_symbol_uses = &scan_pass.used_symbols;
},
else => {},
if (comptime ParserType.parser_features.typescript) {
p.parse_pass_symbol_uses = &scan_pass.used_symbols;
}
// Parse the file in the first pass, but do not bind symbols
@@ -2020,31 +1972,28 @@ pub const Parser = struct {
_ = try p.parseStmtsUpTo(js_lexer.T.t_end_of_file, &opts);
//
switch (comptime ParserType) {
TSXImportScanner, TypeScriptImportScanner => {
for (scan_pass.import_records.items) |*import_record| {
// Mark everything as unused
// Except:
// - export * as ns from 'foo';
// - export * from 'foo';
// - import 'foo';
// - import("foo")
// - require("foo")
import_record.is_unused = import_record.is_unused or
(import_record.kind == .stmt and
!import_record.was_originally_bare_import and
!import_record.calls_run_time_re_export_fn);
}
if (comptime ParserType.parser_features.typescript) {
for (scan_pass.import_records.items) |*import_record| {
// Mark everything as unused
// Except:
// - export * as ns from 'foo';
// - export * from 'foo';
// - import 'foo';
// - import("foo")
// - require("foo")
import_record.is_unused = import_record.is_unused or
(import_record.kind == .stmt and
!import_record.was_originally_bare_import and
!import_record.calls_run_time_re_export_fn);
}
var iter = scan_pass.used_symbols.iterator();
while (iter.next()) |entry| {
const val = entry.value_ptr;
if (val.used) {
scan_pass.import_records.items[val.import_record_index].is_unused = false;
}
var iter = scan_pass.used_symbols.iterator();
while (iter.next()) |entry| {
const val = entry.value_ptr;
if (val.used) {
scan_pass.import_records.items[val.import_record_index].is_unused = false;
}
},
else => {},
}
}
// Symbol use counts are unavailable
@@ -2269,7 +2218,7 @@ pub const Parser = struct {
declared_symbols[declared_symbols_i] = .{ .ref = automatic_namespace_ref, .is_top_level = true };
declared_symbols_i += 1;
const automatic_identifier = p.e(E.Identifier{ .ref = automatic_namespace_ref }, loc);
const automatic_identifier = p.e(E.ImportIdentifier{ .ref = automatic_namespace_ref }, loc);
const dot_call_target = brk: {
if (p.options.can_import_from_bundle or p.options.enable_bundling) {
break :brk automatic_identifier;
@@ -2374,7 +2323,7 @@ pub const Parser = struct {
}
if (jsx_classic_symbol.use_count_estimate > 0) {
const classic_identifier = p.e(E.Identifier{ .ref = classic_namespace_ref }, loc);
const classic_identifier = p.e(E.ImportIdentifier{ .ref = classic_namespace_ref }, loc);
const dot_call_target = brk: {
// var react = $aopaSD123();
@@ -2905,7 +2854,7 @@ pub fn NewParser(
const NamedImportsType = if (only_scan_imports_and_do_not_visit) *js_ast.Ast.NamedImports else js_ast.Ast.NamedImports;
const NeedsJSXType = if (only_scan_imports_and_do_not_visit) bool else void;
const ParsePassSymbolUsageType = if (only_scan_imports_and_do_not_visit and is_typescript_enabled) *ScanPassResult.ParsePassSymbolUsageMap else void;
pub const parser_features = js_parser_features;
const P = @This();
pub const jsx_transform_type: JSXTransformType = js_parser_jsx;
macro: MacroState = undefined,
@@ -3248,8 +3197,7 @@ pub fn NewParser(
const args = p.allocator.alloc(Expr, 1) catch unreachable;
args[0] = p.e(
E.Identifier{
.can_be_removed_if_unused = true,
E.ImportIdentifier{
.ref = namespace_ref,
},
arg.loc,
@@ -6268,6 +6216,8 @@ pub fn NewParser(
@intCast(u16, @boolToInt(stmt.default_name != null)) +
@intCast(u16, @boolToInt(stmt.star_name_loc != null));
try item_refs.ensureUnusedCapacity(total_count);
// Link the default item to the namespace
if (stmt.default_name) |*name_loc| {
const name = p.loadNameFromRef(name_loc.ref orelse unreachable);
@@ -6300,10 +6250,11 @@ pub fn NewParser(
remap_count += 1;
}
}
item_refs.putAssumeCapacity(name, name_loc.*);
}
if (stmt.items.len > 0) {
try item_refs.ensureCapacity(@intCast(u32, stmt.items.len));
for (stmt.items) |*item| {
const name = p.loadNameFromRef(item.name.ref orelse unreachable);
const ref = try p.declareSymbol(.import, item.name.loc, name);
@@ -9672,9 +9623,8 @@ pub fn NewParser(
const record_id = p.addImportRecord(.stmt, this.loc, import_data.path);
var record: *ImportRecord = &p.import_records.items[record_id];
record.was_injected_by_macro = true;
p.macro.imports.ensureUnusedCapacity(import_data.import.items.len) catch unreachable;
var import = import_data.import;
import.import_record_index = record_id;
@@ -9697,10 +9647,9 @@ pub fn NewParser(
p.macro.imports.putAssumeCapacity(js_ast.Macro.JSNode.SymbolMap.generateImportHash(import_hash_name, import_data.path), name_ref);
// Ensure we don't accidentally think this is an export from
clause.original_name = "";
}
p.macro.prepend_stmts.append(p.s(import, this.loc)) catch unreachable;
p.macro.prepend_stmts.append(p.visitSingleStmt(p.s(import, this.loc), StmtsKind.none)) catch unreachable;
}
};
@@ -11336,6 +11285,7 @@ pub fn NewParser(
if (p.macro.refs.get(ref)) |import_record_id| {
const name = p.symbols.items[ref.inner_index].original_name;
const record = &p.import_records.items[import_record_id];
const prepend_offset = p.macro.prepend_stmts.items.len;
// We must visit it to convert inline_identifiers and record usage
const macro_result = (p.options.macro_context.call(
record.path.text,
@@ -11349,6 +11299,7 @@ pub fn NewParser(
MacroVisitor,
MacroVisitor{ .p = p, .loc = expr.loc },
) catch return expr);
if (macro_result.data != .e_template) {
return p.visitExpr(macro_result);
}
@@ -11367,16 +11318,18 @@ pub fn NewParser(
p.panic("Internal error: missing identifier from macro: {d}", .{id});
};
const ident = E.ImportIdentifier{
.was_originally_identifier = false,
.ref = ref,
};
if (!p.is_control_flow_dead) {
p.recordUsage(ref);
}
return p.e(ident, expr.loc);
return p.e(
E.ImportIdentifier{
.was_originally_identifier = false,
.was_from_macro = true,
.ref = ref,
},
expr.loc,
);
},
.e_binary => |e_| {
@@ -12618,7 +12571,7 @@ pub fn NewParser(
}
fn jsxStringsToMemberExpressionAutomatic(p: *P, loc: logger.Loc, is_static: bool) Expr {
return p.jsxStringsToMemberExpression(loc, if (is_static and !p.options.jsx.development) p.jsxs_runtime.ref else p.jsx_runtime.ref);
return p.jsxStringsToMemberExpression(loc, if (is_static) p.jsxs_runtime.ref else p.jsx_runtime.ref);
}
fn maybeRelocateVarsToTopLevel(p: *P, decls: []G.Decl, mode: RelocateVars.Mode) RelocateVars {
@@ -12859,7 +12812,7 @@ pub fn NewParser(
// When bundling, replace ExportDefault with __exportDefault(exportsRef, expr);
if (p.options.enable_bundling) {
var export_default_args = p.allocator.alloc(Expr, 2) catch unreachable;
export_default_args[0] = p.e(E.Identifier{ .ref = p.exports_ref }, expr.loc);
export_default_args[0] = p.@"module.exports"(expr.loc);
export_default_args[1] = data.value.expr;
stmts.append(p.s(S.SExpr{ .value = p.callRuntime(expr.loc, "__exportDefault", export_default_args) }, expr.loc)) catch unreachable;
return;
@@ -12882,7 +12835,7 @@ pub fn NewParser(
if (p.options.enable_bundling) {
var export_default_args = p.allocator.alloc(Expr, 2) catch unreachable;
export_default_args[0] = p.e(E.Identifier{ .ref = p.exports_ref }, s2.loc);
export_default_args[0] = p.@"module.exports"(s2.loc);
if (had_name) {
export_default_args[1] = p.e(E.Identifier{ .ref = func.func.name.?.ref.? }, s2.loc);
@@ -12910,7 +12863,7 @@ pub fn NewParser(
if (p.options.enable_bundling) {
var export_default_args = p.allocator.alloc(Expr, 2) catch unreachable;
export_default_args[0] = p.e(E.Identifier{ .ref = p.exports_ref }, s2.loc);
export_default_args[0] = p.@"module.exports"(s2.loc);
const class_name_ref = brk: {
if (class.class.class_name) |class_name_ref| {
@@ -12943,7 +12896,7 @@ pub fn NewParser(
.s_export_equals => |data| {
if (p.options.enable_bundling) {
var export_default_args = p.allocator.alloc(Expr, 2) catch unreachable;
export_default_args[0] = p.e(E.Identifier{ .ref = p.exports_ref }, stmt.loc);
export_default_args[0] = p.@"module.exports"(stmt.loc);
export_default_args[1] = data.value;
stmts.append(p.s(S.SExpr{ .value = p.callRuntime(stmt.loc, "__exportDefault", export_default_args) }, stmt.loc)) catch unreachable;
@@ -14363,6 +14316,10 @@ pub fn NewParser(
}
}
pub inline fn @"module.exports"(p: *P, loc: logger.Loc) Expr {
return p.e(E.Dot{ .name = exports_string_name, .name_loc = loc, .target = p.e(E.Identifier{ .ref = p.module_ref }, loc) }, loc);
}
// This assumes that the open parenthesis has already been parsed by the caller
pub fn parseParenExpr(p: *P, loc: logger.Loc, level: Level, opts: ParenExprOpts) anyerror!Expr {
var items_list = List(Expr).init(p.allocator);
@@ -15107,11 +15064,15 @@ pub fn NewParser(
update_function_args[0] = G.Arg{ .binding = p.b(B.Identifier{ .ref = p.exports_ref }, logger.Loc.Empty) };
while (named_exports_iter.next()) |named_export| {
const named_export_value = named_export.value_ptr.*;
// Do not try to HMR export {foo} from 'bar';
if (named_imports.get(named_export.value_ptr.ref)) |named_import| {
if (named_imports.get(named_export_value.ref)) |named_import| {
if (named_import.is_exported) continue;
}
const named_export_symbol: Symbol = p.symbols.items[named_export_value.ref.inner_index];
var export_name_string = export_name_string_remainder[0 .. named_export.key_ptr.len + "$$hmr_".len];
export_name_string_remainder = export_name_string_remainder[export_name_string.len..];
std.mem.copy(u8, export_name_string, "$$hmr_");
@@ -15121,15 +15082,23 @@ pub fn NewParser(
var body_stmts = export_all_function_body_stmts[named_export_i .. named_export_i + 1];
body_stmts[0] = p.s(
S.Return{ .value = p.e(E.Identifier{
.ref = named_export.value_ptr.ref,
}, logger.Loc.Empty) },
// was this originally a named import?
// preserve the identifier
S.Return{ .value = if (named_export_symbol.namespace_alias != null)
p.e(E.ImportIdentifier{
.ref = named_export_value.ref,
.was_originally_identifier = true,
}, logger.Loc.Empty)
else
p.e(E.Identifier{
.ref = named_export_value.ref,
}, logger.Loc.Empty) },
logger.Loc.Empty,
);
export_clauses[named_export_i] = js_ast.ClauseItem{
.original_name = "",
.alias = named_export.key_ptr.*,
.alias_loc = named_export.value_ptr.alias_loc,
.alias_loc = named_export_value.alias_loc,
.name = .{ .ref = name_ref, .loc = logger.Loc.Empty },
};

View File

@@ -1561,37 +1561,31 @@ pub fn NewPrinter(
}
},
.e_import_identifier => |e| {
if (e.ref.is_source_contents_slice or e.was_from_macro) {
p.printSymbol(e.ref);
return;
}
// Potentially use a property access instead of an identifier
const ref = p.symbols.follow(e.ref);
var didPrint = false;
if (p.symbols.get(ref)) |symbol| {
if (p.symbols.get(e.ref)) |symbol| {
if (symbol.import_item_status == .missing) {
p.printUndefined(level);
didPrint = true;
} else if (symbol.namespace_alias) |namespace| {
// this feels crashy
var wrap = false;
didPrint = true;
if (p.call_target) |target| {
wrap = e.was_originally_identifier and target.e_import_identifier.ref.eql(expr.data.e_import_identifier.ref);
wrap = e.was_originally_identifier and (target == .e_identifier and
target.e_identifier.ref.eql(expr.data.e_import_identifier.ref));
}
if (wrap) {
p.print("(0, ");
}
p.printSymbol(namespace.namespace_ref);
const alias = namespace.alias;
if (p.canPrintIdentifier(alias)) {
p.print(".");
p.printIdentifier(alias);
} else {
p.print("[");
p.printQuotedUTF8(alias, true);
p.print("]");
}
didPrint = true;
p.printNamespaceAlias(namespace);
if (wrap) {
p.print(")");
@@ -1869,6 +1863,26 @@ pub fn NewPrinter(
}
}
pub fn printNamespaceAlias(p: *Printer, namespace: G.NamespaceAlias) void {
const import_record = &p.import_records[namespace.import_record_index];
if (import_record.module_id > 0 and !import_record.contains_import_star) {
p.print("$");
p.printModuleId(import_record.module_id);
} else {
p.printSymbol(namespace.namespace_ref);
}
if (p.canPrintIdentifier(namespace.alias)) {
p.print(".");
p.printIdentifier(namespace.alias);
} else {
p.print("[");
p.printQuotedUTF8(namespace.alias, true);
p.print("]");
}
}
pub fn printProperty(p: *Printer, item: G.Property) void {
debugl("<printProperty>");
defer debugl("</printProperty>");
@@ -2321,16 +2335,16 @@ pub fn NewPrinter(
p.printSymbol(nameRef);
p.printFunc(s.func);
if (rewrite_esm_to_cjs and s.func.flags.is_export) {
p.printSemicolonAfterStatement();
p.print("var ");
p.printSymbol(nameRef);
p.print(" = ");
p.printSymbol(nameRef);
p.printSemicolonAfterStatement();
} else {
p.printNewline();
}
// if (rewrite_esm_to_cjs and s.func.flags.is_export) {
// p.printSemicolonAfterStatement();
// p.print("var ");
// p.printSymbol(nameRef);
// p.print(" = ");
// p.printSymbol(nameRef);
// p.printSemicolonAfterStatement();
// } else {
p.printNewline();
// }
if (rewrite_esm_to_cjs and s.func.flags.is_export) {
p.printIndent();
@@ -2603,10 +2617,64 @@ pub fn NewPrinter(
if (!prev_stmt_tag.isExportLike()) {
p.printNewline();
}
p.printIndent();
p.printSpaceBeforeIdentifier();
p.print("export");
p.printSpace();
// This transforms code like this:
// import {Foo, Bar} from 'bundled-module';
// export {Foo, Bar};
// into
// export var Foo = $$bundledModule.Foo; (where $$bundledModule is created at import time)
// This is necessary unfortunately because export statements do not allow dot expressions
// The correct approach here is to invert the logic
// instead, make the entire module behave like a CommonJS module
// and export that one instead
// This particular code segment does the transform inline by adding an extra pass over export clauses
// and then swapRemove'ing them as we go
var array = std.ArrayListUnmanaged(js_ast.ClauseItem){ .items = s.items, .capacity = s.items.len };
{
var i: usize = 0;
while (i < array.items.len) {
const item: js_ast.ClauseItem = array.items[i];
if (item.original_name.len > 0) {
if (p.symbols.get(item.name.ref.?)) |symbol| {
if (symbol.namespace_alias) |namespace| {
const import_record = p.import_records[namespace.import_record_index];
if (import_record.is_bundled) {
p.print("var ");
p.printSymbol(item.name.ref.?);
p.print("= ");
p.printNamespaceAlias(namespace);
p.printSemicolonAfterStatement();
_ = array.swapRemove(i);
if (i < array.items.len) {
p.printIndent();
p.printSpaceBeforeIdentifier();
p.print("export");
p.printSpace();
}
continue;
}
}
}
}
i += 1;
}
if (array.items.len == 0) {
return;
}
s.items = array.items;
}
p.print("{");
if (!s.is_single_line) {
@@ -2625,6 +2693,7 @@ pub fn NewPrinter(
p.printNewline();
p.printIndent();
}
const name = p.renamer.nameForSymbol(item.name.ref.?);
p.printIdentifier(name);
if (!strings.eql(name, item.alias)) {
@@ -3056,6 +3125,7 @@ pub fn NewPrinter(
for (s.items) |item, i| {
p.print(item.alias);
const name = p.renamer.nameForSymbol(item.name.ref.?);
if (!strings.eql(name, item.alias)) {
p.print(": ");
p.printSymbol(item.name.ref.?);
@@ -3137,69 +3207,7 @@ pub fn NewPrinter(
p.print(" = () => ({default: {}});\n");
}
if (s.items.len > 0) {
p.printIndent();
p.printSpaceBeforeIdentifier();
p.print("var { ");
if (s.default_name) |default_name| {
p.print("default: ");
p.printSymbol(default_name.ref.?);
p.print(", ");
for (s.items) |item, i| {
p.print(item.alias);
const name = p.renamer.nameForSymbol(item.name.ref.?);
if (!strings.eql(name, item.alias)) {
p.print(": ");
p.printSymbol(item.name.ref.?);
}
if (i < s.items.len - 1) {
p.print(", ");
}
}
} else {
for (s.items) |item, i| {
p.print(item.alias);
const name = p.renamer.nameForSymbol(item.name.ref.?);
if (!strings.eql(name, item.alias)) {
p.print(":");
p.printSymbol(item.name.ref.?);
}
if (i < s.items.len - 1) {
p.print(", ");
}
}
}
p.print("} = ");
p.printLoadFromBundleWithoutCall(s.import_record_index);
p.print("()");
p.printSemicolonAfterStatement();
} else if (s.default_name) |default_name| {
p.printIndent();
p.printSpaceBeforeIdentifier();
p.print("var {default: ");
p.printSymbol(default_name.ref.?);
p.print("} = ");
p.printLoadFromBundleWithoutCall(s.import_record_index);
p.print("()");
p.printSemicolonAfterStatement();
} else if (record.contains_import_star) {
p.print("var ");
p.printSymbol(s.namespace_ref);
p.print(" = ");
p.printLoadFromBundleWithoutCall(s.import_record_index);
p.print("()");
p.printSemicolonAfterStatement();
}
p.printBundledImport(record, s, stmt);
return;
}
@@ -3366,25 +3374,44 @@ pub fn NewPrinter(
return;
}
const import_record = p.import_records[s.import_record_index];
const is_disabled = import_record.path.is_disabled;
const module_id = import_record.module_id;
switch (ImportVariant.determine(&record, p.symbols.get(s.namespace_ref).?, s)) {
.path_only => {
p.printLoadFromBundle(s.import_record_index);
p.printSemicolonAfterStatement();
if (!is_disabled) {
p.printCallModuleID(module_id);
p.printSemicolonAfterStatement();
}
},
.import_star => {
p.print("var ");
p.printSymbol(s.namespace_ref);
p.print(" = ");
p.printLoadFromBundle(s.import_record_index);
p.printSemicolonAfterStatement();
},
.import_default => {
p.print("var ");
p.printSymbol(s.default_name.?.ref.?);
p.print(" = ");
p.printLoadFromBundle(s.import_record_index);
if (!bun) {
p.print(".default");
.import_items_and_default, .import_default => {
if (!is_disabled) {
p.print("var $");
p.printModuleId(module_id);
p.print(" = ");
p.printLoadFromBundle(s.import_record_index);
if (s.default_name) |default_name| {
p.print(", ");
p.printSymbol(default_name.ref.?);
p.print(" = ");
p.print("(\"default\" in $");
p.printModuleId(module_id);
p.print(" ? $");
p.printModuleId(module_id);
p.print(".default : $");
p.printModuleId(module_id);
p.print(")");
}
} else {
if (s.default_name) |default_name| {
p.print("var ");
p.printSymbol(default_name.ref.?);
p.print(" = ");
p.printDisabledImport();
}
}
p.printSemicolonAfterStatement();
@@ -3394,141 +3421,64 @@ pub fn NewPrinter(
p.printSymbol(s.namespace_ref);
p.print(" = ");
p.printLoadFromBundle(s.import_record_index);
p.print(", ");
p.printSymbol(s.default_name.?.ref.?);
p.print(" = ");
p.printSymbol(s.namespace_ref);
if (!bun) {
p.print(".default");
}
p.printSemicolonAfterStatement();
},
.import_items => {
p.print("var {");
for (s.items) |*item, i| {
if (i != 0) {
p.print(",");
if (s.is_single_line) {
p.printSpace();
}
}
p.printClauseAlias(item.alias);
const name = p.renamer.nameForSymbol(item.name.ref.?);
if (!strings.eql(name, item.alias)) {
p.printSpace();
p.print(":");
p.printSpaceBeforeIdentifier();
p.printIdentifier(name);
}
}
p.print("}");
p.print(" = ");
p.printLoadFromBundle(s.import_record_index);
p.printSemicolonAfterStatement();
},
.import_items_and_default => {
p.print("var {");
var need_comma = false;
if (s.default_name) |default_name| {
if (default_name.ref) |ref| {
p.print("default: ");
p.printSymbol(ref);
need_comma = true;
p.print(", ");
p.printSymbol(default_name.ref.?);
p.print(" = ");
if (!bun) {
p.print("(\"default\" in ");
p.printSymbol(s.namespace_ref);
p.print(" ? ");
p.printSymbol(s.namespace_ref);
p.print(".default : ");
p.printSymbol(s.namespace_ref);
p.print(")");
} else {
p.printSymbol(s.namespace_ref);
}
}
for (s.items) |*item, i| {
if (need_comma)
p.print(",");
defer need_comma = true;
p.printClauseAlias(item.alias);
const name = p.renamer.nameForSymbol(item.name.ref.?);
if (!strings.eql(name, item.alias)) {
p.printSpace();
p.print(":");
p.printSpaceBeforeIdentifier();
p.printIdentifier(name);
}
}
p.print("}");
p.print(" = ");
p.printLoadFromBundle(s.import_record_index);
p.printSemicolonAfterStatement();
},
.import_items_and_star => {
.import_star => {
p.print("var ");
p.printSymbol(s.namespace_ref);
p.print(" = ");
p.printLoadFromBundle(s.import_record_index);
p.print(", {");
for (s.items) |*item, i| {
if (i > 0) {
p.print(",");
}
p.printClauseAlias(item.alias);
const name = p.renamer.nameForSymbol(item.name.ref.?);
if (!strings.eql(name, item.alias)) {
p.printSpace();
p.print(":");
p.printSpaceBeforeIdentifier();
p.printIdentifier(name);
}
}
p.print("} = ");
p.printSymbol(s.namespace_ref);
p.printSemicolonAfterStatement();
},
.import_items_and_default_and_star => {
else => {
p.print("var $");
p.printModuleIdAssumeEnabled(module_id);
p.print(" = ");
p.printLoadFromBundle(s.import_record_index);
p.printSemicolonAfterStatement();
},
}
const items = s.items;
if (items.len > 0 and !is_disabled) {
for (items) |item| {
const ref = item.name.ref.?;
const symbol = p.symbols.get(ref) orelse continue;
p.printIndent();
p.print("var ");
p.printSymbol(s.namespace_ref);
p.printSymbol(ref);
p.print(" = ");
p.printLoadFromBundle(s.import_record_index);
p.print(", {");
const default_name = s.default_name.?.ref.?;
p.print("default: ");
p.printSymbol(default_name);
for (s.items) |*item, i| {
p.print(",");
p.printClauseAlias(item.alias);
const name = p.renamer.nameForSymbol(item.name.ref.?);
if (!strings.eql(name, item.alias)) {
p.printSpace();
p.print(":");
p.printIdentifier(name);
}
if (!import_record.contains_import_star) {
p.print("$");
p.printModuleId(module_id);
} else {
p.printSymbol(s.namespace_ref);
}
p.print("}");
p.print(" = ");
p.printSymbol(s.namespace_ref);
p.print(".");
p.printSymbol(ref);
p.printSemicolonAfterStatement();
},
// .path_only => {
// p.printLoadFromBundle(s.import_record_index);
// p.print("/* ");
// p.printSymbol(s.namespace_ref);
// p.print(" */");
// p.printSemicolonAfterStatement();
// },
}
}
}
pub fn printLoadFromBundle(p: *Printer, import_record_index: u32) void {
@@ -3542,18 +3492,32 @@ pub fn NewPrinter(
p.print("()");
}
}
inline fn printDisabledImport(p: *Printer) void {
p.print("(() => ({}))");
}
pub fn printLoadFromBundleWithoutCall(p: *Printer, import_record_index: u32) void {
const record = p.import_records[import_record_index];
if (record.path.is_disabled) {
p.print("(() => ({}))");
p.printDisabledImport();
return;
}
@call(.{ .modifier = .always_inline }, printModuleId, .{ p, p.import_records[import_record_index].module_id });
}
pub fn printCallModuleID(p: *Printer, module_id: u32) void {
printModuleId(p, module_id);
p.print("()");
}
inline fn printModuleId(p: *Printer, module_id: u32) void {
std.debug.assert(module_id != 0); // either module_id is forgotten or it should be disabled
p.printModuleIdAssumeEnabled(module_id);
}
inline fn printModuleIdAssumeEnabled(p: *Printer, module_id: u32) void {
p.print("$");
std.fmt.formatInt(module_id, 16, .lower, .{}, p) catch unreachable;
}