diff options
author | 2021-05-13 17:44:50 -0700 | |
---|---|---|
committer | 2021-05-13 17:44:50 -0700 | |
commit | ca4120afec54fc20295a4a7d3ce6f8c29eccd84c (patch) | |
tree | 6619890c616bde65b3798b28fb99018b1eac71e3 | |
parent | 2eb09c1fec3a11067066602e2d6613e817a06630 (diff) | |
download | bun-ca4120afec54fc20295a4a7d3ce6f8c29eccd84c.tar.gz bun-ca4120afec54fc20295a4a7d3ce6f8c29eccd84c.tar.zst bun-ca4120afec54fc20295a4a7d3ce6f8c29eccd84c.zip |
bug fixes galore
Former-commit-id: 72439452918caa05a32d4e3607910901fa2f4f85
-rw-r--r-- | src/api/demo/pages/index.js | 2 | ||||
-rw-r--r-- | src/ast/base.zig | 5 | ||||
-rw-r--r-- | src/bundler.zig | 9 | ||||
-rw-r--r-- | src/cache.zig | 1 | ||||
-rw-r--r-- | src/js_ast.zig | 14 | ||||
-rw-r--r-- | src/js_lexer.zig | 7 | ||||
-rw-r--r-- | src/js_parser/js_parser.zig | 163 | ||||
-rw-r--r-- | src/js_printer.zig | 15 | ||||
-rw-r--r-- | src/options.zig | 13 | ||||
-rw-r--r-- | src/resolver/resolver.zig | 98 | ||||
-rw-r--r-- | src/string_immutable.zig | 19 | ||||
-rw-r--r-- | src/test/fixtures/function-args-parse-bug.js | 20 | ||||
-rw-r--r-- | src/test/fixtures/img-bug.js | 61 | ||||
-rw-r--r-- | src/test/fixtures/regexp-validation.js | 1 | ||||
-rw-r--r-- | src/test/fixtures/require-detector.js | 1 |
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"); |