aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2021-05-13 17:44:50 -0700
committerGravatar Jarred Sumner <jarred@jarredsumner.com> 2021-05-13 17:44:50 -0700
commitca4120afec54fc20295a4a7d3ce6f8c29eccd84c (patch)
tree6619890c616bde65b3798b28fb99018b1eac71e3 /src
parent2eb09c1fec3a11067066602e2d6613e817a06630 (diff)
downloadbun-ca4120afec54fc20295a4a7d3ce6f8c29eccd84c.tar.gz
bun-ca4120afec54fc20295a4a7d3ce6f8c29eccd84c.tar.zst
bun-ca4120afec54fc20295a4a7d3ce6f8c29eccd84c.zip
bug fixes galore
Former-commit-id: 72439452918caa05a32d4e3607910901fa2f4f85
Diffstat (limited to 'src')
-rw-r--r--src/api/demo/pages/index.js2
-rw-r--r--src/ast/base.zig5
-rw-r--r--src/bundler.zig9
-rw-r--r--src/cache.zig1
-rw-r--r--src/js_ast.zig14
-rw-r--r--src/js_lexer.zig7
-rw-r--r--src/js_parser/js_parser.zig163
-rw-r--r--src/js_printer.zig15
-rw-r--r--src/options.zig13
-rw-r--r--src/resolver/resolver.zig98
-rw-r--r--src/string_immutable.zig19
-rw-r--r--src/test/fixtures/function-args-parse-bug.js20
-rw-r--r--src/test/fixtures/img-bug.js61
-rw-r--r--src/test/fixtures/regexp-validation.js1
-rw-r--r--src/test/fixtures/require-detector.js1
15 files changed, 309 insertions, 120 deletions
diff --git a/src/api/demo/pages/index.js b/src/api/demo/pages/index.js
index 2f5fcc6d6..9523fbc8b 100644
--- a/src/api/demo/pages/index.js
+++ b/src/api/demo/pages/index.js
@@ -1,7 +1,7 @@
import Head from "next/head";
import Image from "next/image";
import styles from "../styles/Home.module.css";
-import "../lib/api.ts";
+// import "../lib/api.ts";
export default function Home() {
return (
<div className={styles.container}>
diff --git a/src/ast/base.zig b/src/ast/base.zig
index 9e42818de..904ad97bd 100644
--- a/src/ast/base.zig
+++ b/src/ast/base.zig
@@ -33,6 +33,9 @@ pub const Ref = packed struct {
.inner_index = std.math.maxInt(Ref.Int),
.source_index = std.math.maxInt(Ref.Int),
};
+ pub fn toInt(int: anytype) Int {
+ return std.math.cast(Ref.Int, int) catch 0;
+ }
pub fn isNull(self: *const Ref) bool {
return self.source_index == std.math.maxInt(Ref.Int) and self.inner_index == std.math.maxInt(Ref.Int);
}
@@ -41,7 +44,7 @@ pub const Ref = packed struct {
return self.source_index == std.math.maxInt(Ref.Int);
}
- pub fn isSourceIndexNull(int: Ref.Int) bool {
+ pub fn isSourceIndexNull(int: anytype) bool {
return int == std.math.maxInt(Ref.Int);
}
diff --git a/src/bundler.zig b/src/bundler.zig
index cfbc147ca..6ea4d41a8 100644
--- a/src/bundler.zig
+++ b/src/bundler.zig
@@ -110,7 +110,7 @@ pub const Bundler = struct {
) !void {
var allocator = bundler.allocator;
const relative_path = try std.fs.path.relative(bundler.allocator, bundler.fs.top_level_dir, result.source.path.text);
- var out_parts = [_]string{ bundler.options.output_dir, relative_path };
+ var out_parts = [_]string{ bundler.fs.top_level_dir, relative_path };
const out_path = try std.fs.path.join(bundler.allocator, &out_parts);
const ast = result.ast;
@@ -175,7 +175,10 @@ pub const Bundler = struct {
.loader = loader,
};
},
- else => Global.panic("Unsupported loader {s}", .{loader}),
+ .css => {
+ return null;
+ },
+ else => Global.panic("Unsupported loader {s} for path: {s}", .{ loader, source.path.text }),
}
return null;
@@ -419,7 +422,7 @@ pub const Transformer = struct {
ast = res.ast;
},
else => {
- Global.panic("Unsupported loader: {s}", .{loader});
+ Global.panic("Unsupported loader: {s} for path: {s}", .{ loader, source.path.text });
},
}
diff --git a/src/cache.zig b/src/cache.zig
index 9c877fc93..88fa6e9ea 100644
--- a/src/cache.zig
+++ b/src/cache.zig
@@ -148,7 +148,6 @@ pub const Cache = struct {
source: *const logger.Source,
) anyerror!?js_ast.Ast {
var temp_log = logger.Log.init(allocator);
- defer temp_log.deinit();
var parser = js_parser.Parser.init(opts, &temp_log, source, defines, allocator) catch |err| {
temp_log.appendTo(log) catch {};
diff --git a/src/js_ast.zig b/src/js_ast.zig
index 66954a5bb..eb7f41ffd 100644
--- a/src/js_ast.zig
+++ b/src/js_ast.zig
@@ -361,7 +361,7 @@ pub const G = struct {
flags: Flags.Function = Flags.Function.None,
};
pub const Arg = struct {
- ts_decorators: ?ExprNodeList = null,
+ ts_decorators: ExprNodeList = &([_]Expr{}),
binding: BindingNodeIndex,
default: ?ExprNodeIndex = null,
@@ -951,7 +951,11 @@ pub const E = struct {
}
pub fn string(s: *String, allocator: *std.mem.Allocator) !string {
- return try std.unicode.utf16leToUtf8Alloc(allocator, s.value);
+ if (s.isUTF8()) {
+ return s.utf8;
+ } else {
+ return strings.toUTF8Alloc(allocator, s.value);
+ }
}
pub fn jsonStringify(s: *const String, options: anytype, writer: anytype) !void {
@@ -1011,16 +1015,16 @@ pub const E = struct {
};
pub const Require = struct {
- import_record_index: Ref.Int = 0,
+ import_record_index: u32 = 0,
};
pub const RequireOrRequireResolve = struct {
- import_record_index: Ref.Int = 0,
+ import_record_index: u32 = 0,
};
pub const Import = struct {
expr: ExprNodeIndex,
- import_record_index: Ref.Int,
+ import_record_index: u32,
// Comments inside "import()" expressions have special meaning for Webpack.
// Preserving comments inside these expressions makes it possible to use
diff --git a/src/js_lexer.zig b/src/js_lexer.zig
index d41700b54..fa161f2cd 100644
--- a/src/js_lexer.zig
+++ b/src/js_lexer.zig
@@ -134,9 +134,9 @@ pub const Lexer = struct {
var msg = self.log.addRangeError(self.source, r, errorMessage);
self.prev_error_loc = r.loc;
- if (panic) {
- return Error.ParserError;
- }
+ // if (panic) {
+ // return Error.ParserError;
+ // }
}
fn doPanic(self: *LexerType, content: []const u8) void {
@@ -1189,6 +1189,7 @@ pub const Lexer = struct {
},
}
}
+ return;
},
'[' => {
try lexer.step();
diff --git a/src/js_parser/js_parser.zig b/src/js_parser/js_parser.zig
index 90ce8d678..0e7227c7c 100644
--- a/src/js_parser/js_parser.zig
+++ b/src/js_parser/js_parser.zig
@@ -1393,7 +1393,7 @@ pub const Parser = struct {
// }
// }
// p.popScope();
- var parts_slice: []js_ast.Part = undefined;
+ var parts_slice: []js_ast.Part = &([_]js_ast.Part{});
if (before.items.len > 0 or after.items.len > 0) {
const before_len = before.items.len;
@@ -1789,7 +1789,7 @@ pub const P = struct {
p.import_records_for_current_part.append(import_record_index) catch unreachable;
return p.e(E.Import{
.expr = arg,
- .import_record_index = @intCast(Ref.Int, import_record_index),
+ .import_record_index = Ref.toInt(import_record_index),
// .leading_interior_comments = arg.data.e_string.
}, state.loc);
}
@@ -1809,6 +1809,25 @@ pub const P = struct {
}
pub fn transposeRequire(p: *P, arg: Expr, transpose_state: anytype) Expr {
+ switch (arg.data) {
+ .e_string => |str| {
+ // Ignore calls to require() if the control flow is provably dead here.
+ // We don't want to spend time scanning the required files if they will
+ // never be used.
+ if (p.is_control_flow_dead) {
+ return Expr{ .data = nullExprData, .loc = arg.loc };
+ }
+
+ const import_record_index = p.addImportRecord(.require, arg.loc, str.string(p.allocator) catch unreachable);
+ p.import_records.items[import_record_index].handles_import_errors = p.fn_or_arrow_data_visit.try_body_count != 0;
+ p.import_records_for_current_part.append(import_record_index) catch unreachable;
+
+ p.ignoreUsage(p.require_ref);
+ return p.e(E.Require{ .import_record_index = import_record_index }, arg.loc);
+ },
+ else => {},
+ }
+
return arg;
}
@@ -2225,9 +2244,9 @@ pub const P = struct {
p.hoistSymbols(p.module_scope);
- p.require_ref = try p.newSymbol(.unbound, "require");
- p.exports_ref = try p.newSymbol(.hoisted, "exports");
- p.module_ref = try p.newSymbol(.hoisted, "module");
+ p.require_ref = try p.declareCommonJSSymbol(.unbound, "require");
+ p.exports_ref = try p.declareCommonJSSymbol(.hoisted, "exports");
+ p.module_ref = try p.declareCommonJSSymbol(.hoisted, "module");
}
pub fn hoistSymbols(p: *P, scope: *js_ast.Scope) void {
@@ -2385,7 +2404,7 @@ pub const P = struct {
properties.append(B.Property{
.flags = Flags.Property{
- .is_spread = item.kind == .spread,
+ .is_spread = item.kind == .spread or item.flags.is_spread,
.is_computed = item.flags.is_computed,
},
@@ -2485,7 +2504,7 @@ pub const P = struct {
}
var name: ?js_ast.LocRef = null;
- var nameText: string = undefined;
+ var nameText: string = "";
// The name is optional for "export default function() {}" pseudo-statements
if (!opts.is_name_optional or p.lexer.token == T.t_identifier) {
@@ -2629,7 +2648,7 @@ pub const P = struct {
continue;
}
- var ts_decorators: []ExprNodeIndex = undefined;
+ var ts_decorators: []ExprNodeIndex = &([_]ExprNodeIndex{});
if (opts.allow_ts_decorators) {
ts_decorators = try p.parseTypeScriptDecorators();
}
@@ -2722,7 +2741,9 @@ pub const P = struct {
try p.lexer.next();
}
- func.args = args.toOwnedSlice();
+ if (args.items.len > 0) {
+ func.args = args.toOwnedSlice();
+ }
// Reserve the special name "arguments" in this scope. This ensures that it
// shadows any variable called "arguments" in any parent scopes. But only do
@@ -2849,8 +2870,8 @@ pub const P = struct {
pub fn newSymbol(p: *P, kind: Symbol.Kind, identifier: string) !js_ast.Ref {
const ref = js_ast.Ref{
- .source_index = @intCast(Ref.Int, p.source.index),
- .inner_index = @intCast(Ref.Int, p.symbols.items.len),
+ .source_index = Ref.toInt(p.source.index),
+ .inner_index = Ref.toInt(p.symbols.items.len),
};
try p.symbols.append(Symbol{
.kind = kind,
@@ -2861,7 +2882,6 @@ pub const P = struct {
if (p.options.ts) {
try p.ts_use_counts.append(0);
}
-
return ref;
}
@@ -3179,10 +3199,10 @@ pub const P = struct {
}
try p.lexer.next();
- var namespace_ref: js_ast.Ref = undefined;
+ var namespace_ref: js_ast.Ref = js_ast.Ref.None;
var alias: ?js_ast.G.ExportStarAlias = null;
- var path_loc: logger.Loc = undefined;
- var path_text: string = undefined;
+ var path_loc: logger.Loc = logger.Loc.Empty;
+ var path_text: string = "";
if (p.lexer.isContextualKeyword("as")) {
// "export * as ns from 'path'"
@@ -3673,7 +3693,7 @@ pub const P = struct {
p.es6_import_keyword = p.lexer.range();
try p.lexer.next();
var stmt: S.Import = S.Import{
- .namespace_ref = undefined,
+ .namespace_ref = Ref.None,
.import_record_index = std.math.maxInt(u32),
};
var was_originally_bare_import = false;
@@ -3727,7 +3747,7 @@ pub const P = struct {
}
var importClause = try p.parseImportClause();
stmt = S.Import{
- .namespace_ref = undefined,
+ .namespace_ref = Ref.None,
.import_record_index = std.math.maxInt(u32),
.items = importClause.items,
.is_single_line = importClause.is_single_line,
@@ -3743,7 +3763,7 @@ pub const P = struct {
}
const default_name = p.lexer.identifier;
- stmt = S.Import{ .namespace_ref = undefined, .import_record_index = std.math.maxInt(u32), .default_name = LocRef{
+ stmt = S.Import{ .namespace_ref = Ref.None, .import_record_index = std.math.maxInt(u32), .default_name = LocRef{
.loc = p.lexer.loc(),
.ref = try p.storeNameInRef(default_name),
} };
@@ -4434,7 +4454,7 @@ pub const P = struct {
}
pub fn parsePropertyBinding(p: *P) anyerror!B.Property {
- var key: js_ast.Expr = undefined;
+ var key: js_ast.Expr = Expr{ .loc = logger.Loc.Empty, .data = Prefill.Data.EMissing };
var is_computed = false;
switch (p.lexer.token) {
@@ -4816,8 +4836,8 @@ pub const P = struct {
var scope = p.current_scope;
if (p.isStrictMode()) {
var why: string = "";
- var notes: []logger.Data = undefined;
- var where: logger.Range = undefined;
+ var notes: []logger.Data = &[_]logger.Data{};
+ var where: logger.Range = logger.Range.None;
switch (scope.strict_mode) {
.implicit_strict_mode_import => {
where = p.es6_import_keyword;
@@ -4852,6 +4872,49 @@ pub const P = struct {
return true;
}
+ pub fn declareCommonJSSymbol(p: *P, kind: Symbol.Kind, name: string) !Ref {
+ const member = p.module_scope.members.get(name);
+
+ // If the code declared this symbol using "var name", then this is actually
+ // not a collision. For example, node will let you do this:
+ //
+ // var exports;
+ // module.exports.foo = 123;
+ // console.log(exports.foo);
+ //
+ // This works because node's implementation of CommonJS wraps the entire
+ // source file like this:
+ //
+ // (function(require, exports, module, __filename, __dirname) {
+ // var exports;
+ // module.exports.foo = 123;
+ // console.log(exports.foo);
+ // })
+ //
+ // Both the "exports" argument and "var exports" are hoisted variables, so
+ // they don't collide.
+ if (member) |_member| {
+ if (p.symbols.items[_member.ref.inner_index].kind == .hoisted and kind == .hoisted and !p.has_es_module_syntax) {
+ return _member.ref;
+ }
+ }
+
+ // Create a new symbol if we didn't merge with an existing one above
+ const ref = try p.newSymbol(kind, name);
+
+ if (member == null) {
+ try p.module_scope.members.put(name, Scope.Member{ .ref = ref, .loc = logger.Loc.Empty });
+ return ref;
+ }
+
+ // If the variable was declared, then it shadows this symbol. The code in
+ // this module will be unable to reference this symbol. However, we must
+ // still add the symbol to the scope so it gets minified (automatically-
+ // generated code may still reference the symbol).
+ try p.module_scope.generated.append(ref);
+ return ref;
+ }
+
pub fn declareSymbol(p: *P, kind: Symbol.Kind, loc: logger.Loc, name: string) !Ref {
// p.checkForNonBMPCodePoint(loc, name)
@@ -4870,7 +4933,7 @@ pub const P = struct {
switch (p.canMergeSymbols(scope, symbol.kind, kind)) {
.forbidden => {
const r = js_lexer.rangeOfIdentifier(p.source, loc);
- var notes: []logger.Data = undefined;
+ var notes: []logger.Data = &[_]logger.Data{};
notes = &([_]logger.Data{logger.rangeData(p.source, r, try std.fmt.allocPrint(p.allocator, "{s} has already been declared", .{name}))});
try p.log.addRangeErrorWithNotes(p.source, r, try std.fmt.allocPrint(p.allocator, "{s} was originally declared here", .{name}), notes);
return existing.ref;
@@ -5072,11 +5135,11 @@ pub const P = struct {
pub fn storeNameInRef(p: *P, name: string) !js_ast.Ref {
if (@ptrToInt(p.source.contents.ptr) <= @ptrToInt(name.ptr) and (@ptrToInt(name.ptr) + name.len) <= (@ptrToInt(p.source.contents.ptr) + p.source.contents.len)) {
- const start = @intCast(Ref.Int, @ptrToInt(name.ptr) - @ptrToInt(p.source.contents.ptr));
- const end = @intCast(Ref.Int, name.len);
+ const start = Ref.toInt(@ptrToInt(name.ptr) - @ptrToInt(p.source.contents.ptr));
+ const end = Ref.toInt(name.len);
return js_ast.Ref{ .source_index = start, .inner_index = end, .is_source_contents_slice = true };
} else if (p.allocated_names.capacity > 0) {
- const inner_index = @intCast(Ref.Int, p.allocated_names.items.len);
+ const inner_index = Ref.toInt(p.allocated_names.items.len);
try p.allocated_names.append(name);
return js_ast.Ref{ .source_index = std.math.maxInt(Ref.Int), .inner_index = inner_index };
} else {
@@ -5338,7 +5401,7 @@ pub const P = struct {
}
pub fn parseProperty(p: *P, kind: Property.Kind, opts: *PropertyOpts, errors: ?*DeferredErrors) anyerror!?G.Property {
- var key: Expr = undefined;
+ var key: Expr = Expr{ .loc = logger.Loc.Empty, .data = Prefill.Data.EMissing };
var key_range = p.lexer.range();
var is_computed = false;
@@ -5659,7 +5722,7 @@ pub const P = struct {
switch (key.data) {
.e_private_identifier => |private| {
var declare: Symbol.Kind = undefined;
- var suffix: string = undefined;
+ var suffix: string = "";
switch (kind) {
.get => {
if (opts.is_static) {
@@ -5932,7 +5995,7 @@ pub const P = struct {
return _parseSuffix(p, left, level, errors orelse &DeferredErrors.None, flags);
}
pub fn _parseSuffix(p: *P, _left: Expr, level: Level, errors: *DeferredErrors, flags: Expr.EFlags) anyerror!Expr {
- var expr: Expr = undefined;
+ var expr: Expr = Expr{ .loc = logger.Loc.Empty, .data = Prefill.Data.EMissing };
var left = _left;
var loc = p.lexer.loc();
var optional_chain: ?js_ast.OptionalChain = null;
@@ -5961,7 +6024,7 @@ pub const P = struct {
}
// Stop now if this token is forbidden to follow a TypeScript "as" cast
- if (p.lexer.loc().start == p.forbid_suffix_after_as_loc.start) {
+ if (p.forbid_suffix_after_as_loc.start > -1 and p.lexer.loc().start == p.forbid_suffix_after_as_loc.start) {
return left;
}
@@ -6152,7 +6215,7 @@ pub const P = struct {
// }
//
// This matches the behavior of the TypeScript compiler.
- if (flags != .ts_decorator) {
+ if (flags == .ts_decorator) {
return left;
}
@@ -7063,7 +7126,7 @@ pub const P = struct {
const dots_loc = p.lexer.loc();
try p.lexer.next();
items.append(
- try p.parseExprOrBindings(.comma, &self_errors),
+ p.e(E.Spread{ .value = try p.parseExprOrBindings(.comma, &self_errors) }, dots_loc),
) catch unreachable;
},
else => {
@@ -7446,7 +7509,7 @@ pub const P = struct {
// Fragments of the form "React.Fragment" are not parsed as fragments.
if (@as(JSXTag.TagType, tag.data) == .tag) {
start_tag = tag.data.tag;
- var spread_loc: logger.Loc = undefined;
+ var spread_loc: logger.Loc = logger.Loc.Empty;
var props = List(G.Property).init(p.allocator);
var key_prop_i: i32 = -1;
var spread_prop_i: i32 = -1;
@@ -7916,7 +7979,7 @@ pub const P = struct {
// In an ES6 module, "this" is supposed to be undefined. Instead of
// doing this at runtime using "fn.call(undefined)", we do it at
// compile time using expression substitution here.
- return p.e(E.Undefined{}, loc);
+ return Expr{ .loc = loc, .data = nullValueExpr };
} else {
// In a CommonJS module, "this" is supposed to be the same as "exports".
// Instead of doing this at runtime using "fn.call(module.exports)", we
@@ -8949,8 +9012,8 @@ pub const P = struct {
var duplicate_args_check_ptr: ?*StringBoolMap = if (duplicate_args_check != null) &duplicate_args_check.? else null;
while (i < args.len) : (i += 1) {
- if (args[i].ts_decorators) |decs| {
- args[i].ts_decorators = p.visitTSDecorators(decs);
+ if (args[i].ts_decorators.len > 0) {
+ args[i].ts_decorators = p.visitTSDecorators(args[i].ts_decorators);
}
p.visitBinding(args[i].binding, duplicate_args_check_ptr);
@@ -9218,7 +9281,7 @@ pub const P = struct {
// something else without paying the cost of a whole-tree traversal during
// module linking just to rewrite these EDot expressions.
if (p.import_items_for_namespace.get(id.ref)) |*import_items| {
- var item: LocRef = undefined;
+ var item: LocRef = LocRef{ .loc = logger.Loc.Empty, .ref = null };
if (!import_items.contains(name)) {
item = LocRef{ .loc = name_loc, .ref = p.newSymbol(.import, name) catch unreachable };
@@ -9425,7 +9488,7 @@ pub const P = struct {
.stmt => |s2| {
switch (s2.data) {
.s_function => |func| {
- var name: string = undefined;
+ var name: string = "";
if (func.func.name) |func_loc| {
name = p.loadNameFromRef(func_loc.ref.?);
} else {
@@ -9436,9 +9499,9 @@ pub const P = struct {
p.visitFunc(&func.func, func.func.open_parens_loc);
stmts.append(stmt.*) catch unreachable;
- if (func.func.name != null and func.func.name.?.ref != null) {
- stmts.append(p.keepStmtSymbolName(func.func.name.?.loc, func.func.name.?.ref.?, name)) catch unreachable;
- }
+ // if (func.func.name != null and func.func.name.?.ref != null) {
+ // stmts.append(p.keepStmtSymbolName(func.func.name.?.loc, func.func.name.?.ref.?, name)) catch unreachable;
+ // }
// prevent doubling export default function name
return;
},
@@ -9807,14 +9870,14 @@ pub const P = struct {
stmts.appendAssumeCapacity(stmt.*);
}
- stmts.appendAssumeCapacity(
- // i wonder if this will crash
- p.keepStmtSymbolName(
- data.func.name.?.loc,
- data.func.name.?.ref.?,
- p.symbols.items[data.func.name.?.ref.?.inner_index].original_name,
- ),
- );
+ // stmts.appendAssumeCapacity(
+ // // i wonder if this will crash
+ // p.keepStmtSymbolName(
+ // data.func.name.?.loc,
+ // data.func.name.?.ref.?,
+ // p.symbols.items[data.func.name.?.ref.?.inner_index].original_name,
+ // ),
+ // );
return;
},
.s_class => |data| {
@@ -9878,7 +9941,7 @@ pub const P = struct {
for (data.values) |*enum_value| {
// gotta allocate here so it lives after this function stack frame goes poof
const name = p.lexer.utf16ToString(enum_value.name);
- var assign_target: Expr = undefined;
+ var assign_target: Expr = Expr{ .loc = logger.Loc.Empty, .data = Prefill.Data.EMissing };
var enum_value_type: EnumValueType = EnumValueType.unknown;
if (enum_value.value != null) {
enum_value.value = p.visitExpr(enum_value.value.?);
@@ -10299,7 +10362,7 @@ pub const P = struct {
}
pub fn findLabelSymbol(p: *P, loc: logger.Loc, name: string) FindLabelSymbolResult {
- var res = FindLabelSymbolResult{ .ref = undefined, .is_loop = false };
+ var res = FindLabelSymbolResult{ .ref = Ref.None, .is_loop = false };
var _scope: ?*Scope = p.current_scope;
diff --git a/src/js_printer.zig b/src/js_printer.zig
index 43390f25f..243ce33da 100644
--- a/src/js_printer.zig
+++ b/src/js_printer.zig
@@ -262,6 +262,8 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
p: *Printer,
) void {
const n = p.js.len();
+ if (n <= 0) return;
+
switch (p.js.list.items[n - 1]) {
' ', '\n' => {},
else => {
@@ -659,7 +661,7 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
}
}
- pub fn printRequireOrImportExpr(p: *Printer, import_record_index: Ref.Int, leading_interior_comments: []G.Comment, _level: Level, flags: ExprFlag) void {
+ pub fn printRequireOrImportExpr(p: *Printer, import_record_index: u32, leading_interior_comments: []G.Comment, _level: Level, flags: ExprFlag) void {
var level = _level;
assert(p.import_records.len > import_record_index);
const record = p.import_records[import_record_index];
@@ -678,7 +680,7 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
// First, we will assert to make detecting this case a little clearer for us in development.
if (std.builtin.mode == std.builtin.Mode.Debug) {
- Global.panic("Internal error: {s} is an external require, which should never happen.", .{record});
+ // Global.panic("Internal error: {s} is an external require, which should never happen.", .{record});
}
p.printSpaceBeforeIdentifier();
@@ -689,7 +691,10 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
// so that's require("foo").default.bar rather than require("foo").bar
// We are assuming that the target import has been converted into something with an "export default".
// If it's not esm, the code won't work anyway
- p.printFmt("/* require(\"{s}\") */(await import(", .{record.path.text});
+ p.js.growIfNeeded("/* require(\"\") */(await import(".len + record.path.text.len) catch unreachable;
+ p.print("/* require(\"");
+ p.print(record.path.text);
+ p.print("*/(await import(");
p.addSourceMapping(record.range.loc);
p.printQuotedUTF8(record.path.text, true);
p.print(").default)");
@@ -1302,10 +1307,9 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
},
.e_reg_exp => |e| {
const n = p.js.len();
- const tail = p.js.list.items[n - 1];
// Avoid forming a single-line comment
- if (n > 0 and tail == '/') {
+ if (n > 0 and p.js.list.items[n - 1] == '/') {
p.print(" ");
}
@@ -1636,6 +1640,7 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
if (item.kind == .spread) {
p.print("...");
p.printExpr(item.value.?, .comma, ExprFlag.None());
+ return;
}
if (item.flags.is_static) {
diff --git a/src/options.zig b/src/options.zig
index 7daa14804..4a2141a8a 100644
--- a/src/options.zig
+++ b/src/options.zig
@@ -170,7 +170,7 @@ pub const Loader = enum {
pub const defaultLoaders = std.ComptimeStringMap(Loader, .{
.{ ".jsx", Loader.jsx },
.{ ".json", Loader.json },
- .{ ".js", Loader.js },
+ .{ ".js", Loader.jsx },
.{ ".mjs", Loader.js },
.{ ".css", Loader.css },
.{ ".ts", Loader.ts },
@@ -320,6 +320,15 @@ pub const BundleOptions = struct {
loader_values[i] = loader;
}
+
+ var loaders = try stringHashMapFromArrays(std.StringHashMap(Loader), allocator, transform.loader_keys, loader_values);
+ comptime const default_loader_ext = [_]string{ ".jsx", ".json", ".js", ".mjs", ".css", ".ts", ".tsx" };
+ inline for (default_loader_ext) |ext| {
+ if (!loaders.contains(ext)) {
+ try loaders.put(ext, defaultLoaders.get(ext).?);
+ }
+ }
+
var user_defines = try stringHashMapFromArrays(defines.RawDefines, allocator, transform.define_keys, transform.define_values);
if (transform.define_keys.len == 0) {
try user_defines.put("process.env.NODE_ENV", "development");
@@ -334,7 +343,7 @@ pub const BundleOptions = struct {
allocator,
resolved_defines,
),
- .loaders = try stringHashMapFromArrays(std.StringHashMap(Loader), allocator, transform.loader_keys, loader_values),
+ .loaders = loaders,
.write = transform.write orelse false,
.external = ExternalModules.init(allocator, &fs.fs, fs.top_level_dir, transform.external, log),
.entry_points = transform.entry_points,
diff --git a/src/resolver/resolver.zig b/src/resolver/resolver.zig
index 6cc078a78..afa190c4c 100644
--- a/src/resolver/resolver.zig
+++ b/src/resolver/resolver.zig
@@ -464,68 +464,68 @@ pub const Resolver = struct {
return null;
}
}
+ }
- if (check_package) {
- // Check for external packages first
- if (r.opts.external.node_modules.count() > 0) {
- var query = import_path;
- while (true) {
- if (r.opts.external.node_modules.exists(query)) {
- if (r.debug_logs) |*debug| {
- debug.addNoteFmt("The path \"{s}\" was marked as external by the user", .{query}) catch {};
- }
- return Result{
- .path_pair = .{ .primary = Path.init(query) },
- .is_external = true,
- };
+ if (check_package) {
+ // Check for external packages first
+ if (r.opts.external.node_modules.count() > 0) {
+ var query = import_path;
+ while (true) {
+ if (r.opts.external.node_modules.exists(query)) {
+ if (r.debug_logs) |*debug| {
+ debug.addNoteFmt("The path \"{s}\" was marked as external by the user", .{query}) catch {};
}
-
- // If the module "foo" has been marked as external, we also want to treat
- // paths into that module such as "foo/bar" as external too.
- var slash = strings.lastIndexOfChar(query, '/') orelse break;
- query = query[0..slash];
+ return Result{
+ .path_pair = .{ .primary = Path.init(query) },
+ .is_external = true,
+ };
}
+
+ // If the module "foo" has been marked as external, we also want to treat
+ // paths into that module such as "foo/bar" as external too.
+ var slash = strings.lastIndexOfChar(query, '/') orelse break;
+ query = query[0..slash];
}
+ }
- const source_dir_info = (r.dirInfoCached(source_dir) catch null) orelse return null;
-
- // Support remapping one package path to another via the "browser" field
- if (source_dir_info.enclosing_browser_scope) |browser_scope| {
- if (browser_scope.package_json) |package_json| {
- if (r.checkBrowserMap(package_json, import_path)) |remapped| {
- if (remapped.len == 0) {
- // "browser": {"module": false}
- if (r.loadNodeModules(import_path, kind, source_dir_info)) |node_module| {
- var pair = node_module.path_pair;
- pair.primary.is_disabled = true;
- if (pair.secondary != null) {
- pair.secondary.?.is_disabled = true;
- }
- return Result{
- .path_pair = pair,
- .diff_case = node_module.diff_case,
- .is_from_node_modules = true,
- };
+ const source_dir_info = (r.dirInfoCached(source_dir) catch null) orelse return null;
+
+ // Support remapping one package path to another via the "browser" field
+ if (source_dir_info.enclosing_browser_scope) |browser_scope| {
+ if (browser_scope.package_json) |package_json| {
+ if (r.checkBrowserMap(package_json, import_path)) |remapped| {
+ if (remapped.len == 0) {
+ // "browser": {"module": false}
+ if (r.loadNodeModules(import_path, kind, source_dir_info)) |node_module| {
+ var pair = node_module.path_pair;
+ pair.primary.is_disabled = true;
+ if (pair.secondary != null) {
+ pair.secondary.?.is_disabled = true;
}
- } else {
- var primary = Path.init(import_path);
- primary.is_disabled = true;
return Result{
- .path_pair = PathPair{ .primary = primary },
- // this might not be null? i think it is
- .diff_case = null,
+ .path_pair = pair,
+ .diff_case = node_module.diff_case,
+ .is_from_node_modules = true,
};
}
+ } else {
+ var primary = Path.init(import_path);
+ primary.is_disabled = true;
+ return Result{
+ .path_pair = PathPair{ .primary = primary },
+ // this might not be null? i think it is
+ .diff_case = null,
+ };
}
}
}
+ }
- if (r.resolveWithoutRemapping(source_dir_info, import_path, kind)) |res| {
- result = Result{ .path_pair = res.path_pair, .diff_case = res.diff_case };
- } else {
- // Note: node's "self references" are not currently supported
- return null;
- }
+ if (r.resolveWithoutRemapping(source_dir_info, import_path, kind)) |res| {
+ result = Result{ .path_pair = res.path_pair, .diff_case = res.diff_case };
+ } else {
+ // Note: node's "self references" are not currently supported
+ return null;
}
}
diff --git a/src/string_immutable.zig b/src/string_immutable.zig
index 55d94917b..663b714ea 100644
--- a/src/string_immutable.zig
+++ b/src/string_immutable.zig
@@ -142,6 +142,25 @@ pub fn eqlUtf16(comptime self: string, other: JavascriptString) bool {
return std.mem.eql(u16, std.unicode.utf8ToUtf16LeStringLiteral(self), other);
}
+pub fn toUTF8Alloc(allocator: *std.mem.Allocator, js: JavascriptString) !string {
+ var temp = std.mem.zeroes([4]u8);
+ var list = std.ArrayList(u8).initCapacity(allocator, js.len) catch unreachable;
+ var i: usize = 0;
+ while (i < js.len) : (i += 1) {
+ var r1 = @intCast(i32, js[i]);
+ if (r1 >= 0xD800 and r1 <= 0xDBFF and i + 1 < js.len) {
+ const r2 = @intCast(i32, js[i] + 1);
+ if (r2 >= 0xDC00 and r2 <= 0xDFFF) {
+ r1 = (r1 - 0xD800) << 10 | (r2 - 0xDC00) + 0x10000;
+ i += 1;
+ }
+ }
+ const width = encodeWTF8Rune(&temp, r1);
+ list.appendSlice(temp[0..width]) catch unreachable;
+ }
+ return list.toOwnedSlice();
+}
+
// Check utf16 string equals utf8 string without allocating extra memory
pub fn utf16EqlString(text: []u16, str: string) bool {
if (text.len > str.len) {
diff --git a/src/test/fixtures/function-args-parse-bug.js b/src/test/fixtures/function-args-parse-bug.js
new file mode 100644
index 000000000..79dc5d6e5
--- /dev/null
+++ b/src/test/fixtures/function-args-parse-bug.js
@@ -0,0 +1,20 @@
+"use strict";
+exports.__esModule = true;
+exports.defaultHead = defaultHead;
+exports.default = void 0;
+var _react = _interopRequireWildcard(require("react"));
+var _sideEffect = _interopRequireDefault(require("./side-effect"));
+var _ampContext = require("./amp-context");
+var _headManagerContext = require("./head-manager-context");
+var _amp = require("./amp");
+function _interopRequireDefault(obj) {
+ return obj && obj.__esModule ? obj : { default: obj };
+}
+function _getRequireWildcardCache() {
+ if (typeof WeakMap !== "function") return null;
+ var cache = new WeakMap();
+ _getRequireWildcardCache = function () {
+ return cache;
+ };
+ return cache;
+}
diff --git a/src/test/fixtures/img-bug.js b/src/test/fixtures/img-bug.js
new file mode 100644
index 000000000..207f59a09
--- /dev/null
+++ b/src/test/fixtures/img-bug.js
@@ -0,0 +1,61 @@
+function get() {
+ if (true) {
+ if (true) {
+ if (true) {
+ console.log("HI");
+ if (true) {
+ return { hi: () => true };
+ }
+ }
+ }
+
+ if (true) {
+ if (true) {
+ if (true) {
+ return { hi: () => true };
+ }
+ }
+ }
+ }
+}
+// function getWidths(width, layout, sizes) {
+// if (sizes && (layout === "fill" || layout === "responsive")) {
+// // Find all the "vw" percent sizes used in the sizes prop
+// const percentSizes = [...sizes.matchAll(/(^|\s)(1?\d?\d)vw/g)].map((m) =>
+// parseInt(m[2])
+// );
+// if (percentSizes.length) {
+
+// // const smallestRatio = Math.min(...percentSizes) * 0.01;
+// // return {
+// // widths: allSizes.filter(
+// // (s) => s >= configDeviceSizes[0] * smallestRatio
+// // ),
+// // kind: "w",
+// // };
+// }
+// return { widths: allSizes, kind: "w" };
+// }
+// if (
+// typeof width !== "number" ||
+// layout === "fill" ||
+// layout === "responsive"
+// ) {
+// return { widths: configDeviceSizes, kind: "w" };
+// }
+// // const widths = [
+// // ...new Set( // > This means that most OLED screens that say they are 3x resolution,
+// // // > are actually 3x in the green color, but only 1.5x in the red and
+// // // > blue colors. Showing a 3x resolution image in the app vs a 2x
+// // // > resolution image will be visually the same, though the 3x image
+// // // > takes significantly more data. Even true 3x resolution screens are
+// // // > wasteful as the human eye cannot see that level of detail without
+// // // > something like a magnifying glass.
+// // // https://blog.twitter.com/engineering/en_us/topics/infrastructure/2019/capping-image-fidelity-on-ultra-high-resolution-devices.html
+// // [width, width * 2 /*, width * 3*/].map(
+// // (w) => allSizes.find((p) => p >= w) || allSizes[allSizes.length - 1]
+// // )
+// // ),
+// // ];
+// // return { widths, kind: "x" };
+// }
diff --git a/src/test/fixtures/regexp-validation.js b/src/test/fixtures/regexp-validation.js
new file mode 100644
index 000000000..579109c72
--- /dev/null
+++ b/src/test/fixtures/regexp-validation.js
@@ -0,0 +1 @@
+/(^|\s)(1?\d?\d)vw/g.test("hi");
diff --git a/src/test/fixtures/require-detector.js b/src/test/fixtures/require-detector.js
new file mode 100644
index 000000000..c203d8019
--- /dev/null
+++ b/src/test/fixtures/require-detector.js
@@ -0,0 +1 @@
+const foo = require("react");