aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2021-05-30 23:35:43 -0700
committerGravatar Jarred Sumner <jarred@jarredsumner.com> 2021-05-30 23:35:43 -0700
commit87d01c9f4a315341c1c5f57e09e29df88ce9c996 (patch)
treed1612d7198224cb6901edd119ff1e9da0e434ac3
parentdd72bf5ab657af89d45ee629e8432d9b860a2351 (diff)
downloadbun-87d01c9f4a315341c1c5f57e09e29df88ce9c996.tar.gz
bun-87d01c9f4a315341c1c5f57e09e29df88ce9c996.tar.zst
bun-87d01c9f4a315341c1c5f57e09e29df88ce9c996.zip
Fix printing bugs
Former-commit-id: 52f37e4fe4c8873617abcbc3b3af61e8f1d79edc
-rw-r--r--src/bundler.zig20
-rw-r--r--src/global.zig7
-rw-r--r--src/js_ast.zig18
-rw-r--r--src/js_parser/js_parser.zig14
-rw-r--r--src/js_printer.zig147
-rw-r--r--src/json_parser.zig12
-rw-r--r--src/options.zig2
-rw-r--r--src/resolver/resolve_path.zig30
8 files changed, 206 insertions, 44 deletions
diff --git a/src/bundler.zig b/src/bundler.zig
index 13a28edd4..0dfc59ae4 100644
--- a/src/bundler.zig
+++ b/src/bundler.zig
@@ -117,7 +117,7 @@ pub const Bundler = struct {
}
defer relative_path_allocator.reset();
- var pretty = try relative_paths_list.append(bundler.fs.relativeTo(source_path));
+ var pretty = try relative_paths_list.append(bundler.fs.relative(source_dir, source_path));
var pathname = Fs.PathName.init(pretty);
var absolute_pathname = Fs.PathName.init(source_path);
@@ -224,11 +224,12 @@ pub const Bundler = struct {
const ast = result.ast;
for (ast.import_records) |*import_record| {
- const source_dir = std.fs.path.dirname(file_path.text) orelse file_path.text;
+ const source_dir = file_path.name.dir;
if (bundler.resolver.resolve(source_dir, import_record.path.text, import_record.kind)) |*resolved_import| {
bundler.processImportRecord(
- source_dir,
+ // Include trailing slash
+ file_path.text[0 .. source_dir.len + 1],
resolved_import,
import_record,
) catch continue;
@@ -283,8 +284,7 @@ pub const Bundler = struct {
const output_file = try bundler.print(
result,
);
- js_ast.Expr.Data.Store.reset();
- js_ast.Stmt.Data.Store.reset();
+
return output_file;
}
@@ -534,7 +534,7 @@ pub const Bundler = struct {
// 100.00 µs std.fifo.LinearFifo(resolver.resolver.Result,std.fifo.LinearFifoBufferType { .Dynamic = {}}).writeItemAssumeCapacity
if (bundler.options.resolve_mode != .lazy) {
- try bundler.resolve_queue.ensureUnusedCapacity(1000);
+ try bundler.resolve_queue.ensureUnusedCapacity(24);
}
var entry_points = try allocator.alloc(Resolver.Resolver.Result, bundler.options.entry_points.len);
@@ -592,10 +592,16 @@ pub const Bundler = struct {
entry = __entry;
}
+ defer {
+ js_ast.Expr.Data.Store.reset();
+ js_ast.Stmt.Data.Store.reset();
+ }
+
const result = bundler.resolver.resolve(bundler.fs.top_level_dir, entry, .entry_point) catch |err| {
Output.printError("Error resolving \"{s}\": {s}\n", .{ entry, @errorName(err) });
continue;
};
+
const key = result.path_pair.primary.text;
if (bundler.resolve_results.contains(key)) {
continue;
@@ -614,6 +620,8 @@ pub const Bundler = struct {
switch (bundler.options.resolve_mode) {
.lazy, .dev, .bundle => {
while (bundler.resolve_queue.readItem()) |item| {
+ defer js_ast.Expr.Data.Store.reset();
+ defer js_ast.Stmt.Data.Store.reset();
const output_file = bundler.buildWithResolveResult(item) catch continue orelse continue;
bundler.output_files.append(output_file) catch unreachable;
}
diff --git a/src/global.zig b/src/global.zig
index 4e95b7d1f..e99baf378 100644
--- a/src/global.zig
+++ b/src/global.zig
@@ -36,6 +36,13 @@ pub const FeatureFlags = struct {
// This doesn't really seem to do anything for us
pub const disable_filesystem_cache = false and std.Target.current.os.tag == .macos;
+ pub const css_in_js_import_behavior = CSSModulePolyfill.facade;
+
+ pub const CSSModulePolyfill = enum {
+ // When you import a .css file and you reference the import in JavaScript
+ // Just return whatever the property key they referenced was
+ facade,
+ };
};
pub const enableTracing = true;
diff --git a/src/js_ast.zig b/src/js_ast.zig
index d1c136847..00e76d27e 100644
--- a/src/js_ast.zig
+++ b/src/js_ast.zig
@@ -1000,7 +1000,7 @@ pub const E = struct {
};
pub const Object = struct {
- properties: []G.Property = &([_]G.Property{}),
+ properties: []G.Property,
comma_after_spread: ?logger.Loc = null,
is_single_line: bool = false,
is_parenthesized: bool = false,
@@ -1545,6 +1545,13 @@ pub const Stmt = struct {
s_type_script,
s_while,
s_with,
+
+ pub fn isExportLike(tag: Tag) bool {
+ return switch (tag) {
+ .s_export_clause, .s_export_default, .s_export_equals, .s_export_from, .s_export_star, .s_empty => true,
+ else => false,
+ };
+ }
};
pub const Data = union(Tag) {
@@ -1891,9 +1898,10 @@ pub const Expr = struct {
pub fn asProperty(expr: *const Expr, name: string) ?Query {
if (std.meta.activeTag(expr.data) != .e_object) return null;
- const obj = expr.getObject();
+ const obj = expr.data.e_object;
+ if (@ptrToInt(obj.properties.ptr) == 0) return null;
- for (obj.properties) |*prop| {
+ for (obj.properties) |prop| {
const value = prop.value orelse continue;
const key = prop.key orelse continue;
if (std.meta.activeTag(key.data) != .e_string) continue;
@@ -2052,7 +2060,7 @@ pub const Expr = struct {
return Expr{
.loc = loc,
.data = Data{
- .e_boolean = bool_values[@boolToInt(st.value)],
+ .e_boolean = st,
},
};
},
@@ -2868,7 +2876,7 @@ pub const Expr = struct {
e_require_or_require_resolve: *E.RequireOrRequireResolve,
e_import: *E.Import,
- e_boolean: *E.Boolean,
+ e_boolean: E.Boolean,
e_number: *E.Number,
e_big_int: *E.BigInt,
e_string: *E.String,
diff --git a/src/js_parser/js_parser.zig b/src/js_parser/js_parser.zig
index 5ab16f072..3dea00dda 100644
--- a/src/js_parser/js_parser.zig
+++ b/src/js_parser/js_parser.zig
@@ -1692,7 +1692,7 @@ var jsxChildrenKeyData = Expr.Data{ .e_string = &Prefill.String.Children };
var nullExprValueData = E.Null{};
var falseExprValueData = E.Boolean{ .value = false };
var nullValueExpr = Expr.Data{ .e_null = nullExprValueData };
-var falseValueExpr = Expr.Data{ .e_boolean = &falseExprValueData };
+var falseValueExpr = Expr.Data{ .e_boolean = E.Boolean{ .value = false } };
// P is for Parser!
// public only because of Binding.ToExpr
@@ -9663,7 +9663,7 @@ pub const P = struct {
.bin_strict_eq => {
const equality = SideEffects.eql(e_.left.data, e_.right.data, p);
if (equality.ok) {
- return p.e(E.Boolean{ .value = equality.ok }, expr.loc);
+ return p.e(E.Boolean{ .value = equality.equal }, expr.loc);
}
// const after_op_loc = locAfterOp(e_.);
@@ -9673,7 +9673,7 @@ pub const P = struct {
.bin_loose_ne => {
const equality = SideEffects.eql(e_.left.data, e_.right.data, p);
if (equality.ok) {
- return p.e(E.Boolean{ .value = !equality.ok }, expr.loc);
+ return p.e(E.Boolean{ .value = !equality.equal }, expr.loc);
}
// const after_op_loc = locAfterOp(e_.);
// TODO: warn about equality check
@@ -9687,7 +9687,7 @@ pub const P = struct {
.bin_strict_ne => {
const equality = SideEffects.eql(e_.left.data, e_.right.data, p);
if (equality.ok) {
- return p.e(E.Boolean{ .value = !equality.ok }, expr.loc);
+ return p.e(E.Boolean{ .value = !equality.equal }, expr.loc);
}
},
.bin_nullish_coalescing => {
@@ -11034,7 +11034,7 @@ pub const P = struct {
// The "else" clause is optional
if (data.no) |no| {
- if (effects.ok and !effects.value) {
+ if (effects.ok and effects.value) {
const old = p.is_control_flow_dead;
p.is_control_flow_dead = true;
defer p.is_control_flow_dead = old;
@@ -11515,7 +11515,7 @@ pub const P = struct {
},
name_loc,
),
- p.e(E.Object{}, name_loc),
+ p.e(E.Object{ .properties = &[_]G.Property{} }, name_loc),
p.allocator,
),
},
@@ -11534,7 +11534,7 @@ pub const P = struct {
.right = Expr.assign(
p.e(E.Identifier{ .ref = name_ref }, name_loc),
p.e(
- E.Object{},
+ E.Object{ .properties = &[_]G.Property{} },
name_loc,
),
p.allocator,
diff --git a/src/js_printer.zig b/src/js_printer.zig
index aa0684517..f3432eb33 100644
--- a/src/js_printer.zig
+++ b/src/js_printer.zig
@@ -140,6 +140,7 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
writer: MutableString.Writer,
allocator: *std.mem.Allocator,
renamer: rename.Renamer,
+ prev_stmt_tag: Stmt.Tag = .s_empty,
const Printer = @This();
pub fn comptime_flush(p: *Printer) void {}
@@ -743,7 +744,11 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
p.printIndent();
}
p.addSourceMapping(record.range.loc);
+
+ p.print("import(");
p.printQuotedUTF8(record.path.text, true);
+ p.print(")");
+
if (leading_interior_comments.len > 0) {
p.printNewline();
p.options.unindent();
@@ -994,6 +999,7 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
if (wrap) {
p.print("(");
}
+
p.printSpaceBeforeIdentifier();
p.print("import(");
if (e.leading_interior_comments.len > 0) {
@@ -1294,14 +1300,14 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
// If this was originally a template literal, print it as one as long as we're not minifying
if (e.prefer_template) {
p.print("`");
- p.printString(e, '`');
+ p.printStringContent(e, '`');
p.print("`");
return;
}
const c = p.bestQuoteCharForString(e.value, true);
p.print(c);
- p.printString(e, c);
+ p.printStringContent(e, c);
p.print(c);
},
.e_template => |e| {
@@ -1321,7 +1327,7 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
if (e.tag != null) {
p.print(e.head.utf8);
} else {
- p.printString(&e.head, '`');
+ p.printStringContent(&e.head, '`');
}
}
@@ -1333,7 +1339,7 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
if (e.tag != null) {
p.print(part.tail.utf8);
} else {
- p.printString(&part.tail, '`');
+ p.printStringContent(&part.tail, '`');
}
}
}
@@ -1663,12 +1669,49 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
p.print(")");
}
- pub fn printString(p: *Printer, str: *const E.String, c: u8) void {
+ // This assumes the string has already been quoted.
+ pub fn printStringContent(p: *Printer, str: *const E.String, c: u8) void {
if (!str.isUTF8()) {
+ // its already quoted for us!
p.printQuotedUTF16(str.value, c);
} else {
- // its already quoted for us!
- p.print(str.utf8);
+ p.printUTF8StringEscapedQuotes(str.utf8, c);
+ }
+ }
+
+ // Add one outer branch so the inner loop does fewer branches
+ pub fn printUTF8StringEscapedQuotes(p: *Printer, str: string, c: u8) void {
+ switch (c) {
+ '`' => _printUTF8StringEscapedQuotes(p, str, '`'),
+ '"' => _printUTF8StringEscapedQuotes(p, str, '"'),
+ '\'' => _printUTF8StringEscapedQuotes(p, str, '\''),
+ else => unreachable,
+ }
+ }
+
+ pub fn _printUTF8StringEscapedQuotes(p: *Printer, str: string, comptime c: u8) void {
+ var utf8 = str;
+ var i: usize = 0;
+ // Walk the string searching for quote characters
+ // Escape any we find
+ // Skip over already-escaped strings
+ while (i < utf8.len) : (i += 1) {
+ switch (utf8[i]) {
+ '\\' => {
+ i += 1;
+ },
+ c => {
+ p.print(utf8[0..i]);
+ p.print("\\" ++ &[_]u8{c});
+ utf8 = utf8[i + 1 ..];
+ i = 0;
+ },
+
+ else => {},
+ }
+ }
+ if (utf8.len > 0) {
+ p.print(utf8);
}
}
@@ -1758,7 +1801,30 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
p.addSourceMapping(_key.loc);
if (key.isUTF8()) {
p.printSpaceBeforeIdentifier();
- p.printIdentifier(key.utf8);
+ var allow_shorthand: bool = true;
+ // In react/cjs/react.development.js, there's part of a function like this:
+ // var escaperLookup = {
+ // "=": "=0",
+ // ":": "=2"
+ // };
+ // While each of those property keys are ASCII, a subset of ASCII is valid as the start of an identifier
+ // "=" and ":" are not valid
+ // So we need to check
+ if (js_lexer.isIdentifierStart(@intCast(js_lexer.CodePoint, key.utf8[0]))) {
+ p.print(key.utf8);
+ } else {
+ allow_shorthand = false;
+ const quote = p.bestQuoteCharForString(key.utf8, true);
+ if (quote == '`') {
+ p.print('[');
+ }
+ p.print(quote);
+ p.printUTF8StringEscapedQuotes(key.utf8, quote);
+ p.print(quote);
+ if (quote == '`') {
+ p.print(']');
+ }
+ }
// Use a shorthand property if the names are the same
if (item.value) |val| {
@@ -1773,7 +1839,9 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
if (item.initializer) |initial| {
p.printInitializer(initial);
}
- return;
+ if (allow_shorthand) {
+ return;
+ }
}
// if (strings) {}
},
@@ -1784,7 +1852,9 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
if (item.initializer) |initial| {
p.printInitializer(initial);
}
- return;
+ if (allow_shorthand) {
+ return;
+ }
}
}
},
@@ -2055,6 +2125,18 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
}
pub fn printStmt(p: *Printer, stmt: Stmt) !void {
+ const prev_stmt_tag = p.prev_stmt_tag;
+
+ // Give an extra newline for readaiblity
+ defer {
+ //
+ if (std.meta.activeTag(stmt.data) != .s_import and prev_stmt_tag == .s_import) {
+ p.printNewline();
+ }
+
+ p.prev_stmt_tag = std.meta.activeTag(stmt.data);
+ }
+
debug("<printStmt>: {s}\n", .{stmt});
defer debug("</printStmt>: {s}\n", .{stmt});
p.comptime_flush();
@@ -2086,6 +2168,11 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
p.printNewline();
},
.s_class => |s| {
+ // Give an extra newline for readaiblity
+ if (prev_stmt_tag != .s_empty) {
+ p.printNewline();
+ }
+
p.printIndent();
p.printSpaceBeforeIdentifier();
if (s.is_export) {
@@ -2102,6 +2189,11 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
p.printNewline();
},
.s_export_default => |s| {
+ // Give an extra newline for export default for readability
+ if (!prev_stmt_tag.isExportLike()) {
+ p.printNewline();
+ }
+
p.printIndent();
p.printSpaceBeforeIdentifier();
p.print("export default");
@@ -2158,6 +2250,10 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
}
},
.s_export_star => |s| {
+ // Give an extra newline for readaiblity
+ if (!prev_stmt_tag.isExportLike()) {
+ p.printNewline();
+ }
p.printIndent();
p.printSpaceBeforeIdentifier();
p.print("export");
@@ -2177,6 +2273,10 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
p.printSemicolonAfterStatement();
},
.s_export_clause => |s| {
+ // Give an extra newline for export default for readability
+ if (!prev_stmt_tag.isExportLike()) {
+ p.printNewline();
+ }
p.printIndent();
p.printSpaceBeforeIdentifier();
p.print("export");
@@ -2218,6 +2318,10 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
p.printSemicolonAfterStatement();
},
.s_export_from => |s| {
+ // Give an extra newline for readaiblity
+ if (!prev_stmt_tag.isExportLike()) {
+ p.printNewline();
+ }
p.printIndent();
p.printSpaceBeforeIdentifier();
p.print("export");
@@ -2479,9 +2583,32 @@ pub fn NewPrinter(comptime ascii_only: bool) type {
p.needs_semicolon = false;
},
.s_import => |s| {
+ if (FeatureFlags.css_in_js_import_behavior == .facade) {
+ // TODO: check loader instead
+ if (strings.eqlComptime(p.import_records[s.import_record_index].path.name.ext, ".css")) {
+ // This comment exists to let tooling authors know where CSS files originated
+ // To parse this, you just look for a line that starts with //@import url("
+ p.print("//@import url(\"");
+ // We do not URL escape here.
+ p.print(p.import_records[s.import_record_index].path.text);
+
+ // If they actually use the code, then we emit a facade that just echos whatever they write
+ if (s.default_name) |name| {
+ p.print("\"); css-module-facade\nvar ");
+ p.printSymbol(name.ref.?);
+ p.print(" = new Proxy({}, {get(_,className,__){return className;}});\n");
+ } else {
+ p.print("\"); css-import-facade\n");
+ }
+
+ return;
+ }
+ }
+
var item_count: usize = 0;
p.printIndent();
p.printSpaceBeforeIdentifier();
+
p.print("import");
p.printSpace();
diff --git a/src/json_parser.zig b/src/json_parser.zig
index 134de57b5..65a7205ec 100644
--- a/src/json_parser.zig
+++ b/src/json_parser.zig
@@ -158,17 +158,7 @@ fn JSONLikeParser(opts: js_lexer.JSONOptions) type {
}
}
- var str: E.String = undefined;
- if (p.lexer.string_literal_is_ascii) {
- str = E.String{
- .utf8 = p.lexer.string_literal_slice,
- };
- } else {
- const value = p.lexer.stringLiteralUTF16();
- str = E.String{
- .value = value,
- };
- }
+ var str = p.lexer.toEString();
const is_duplicate = duplicates.exists(p.lexer.string_literal_slice);
if (!is_duplicate) {
duplicates.put(p.lexer.string_literal_slice) catch unreachable;
diff --git a/src/options.zig b/src/options.zig
index 22d335aa3..b9e5350f6 100644
--- a/src/options.zig
+++ b/src/options.zig
@@ -523,7 +523,7 @@ pub const BundleOptions = struct {
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");
+ try user_defines.put("process.env.NODE_ENV", "\"development\"");
}
var resolved_defines = try defines.DefineData.from_input(user_defines, log, allocator);
diff --git a/src/resolver/resolve_path.zig b/src/resolver/resolve_path.zig
index d5e56b418..cc1b4ae9f 100644
--- a/src/resolver/resolve_path.zig
+++ b/src/resolver/resolve_path.zig
@@ -174,7 +174,9 @@ pub fn relativeToCommonPath(
comptime separator: u8,
comptime always_copy: bool,
) []const u8 {
- const common_path = if (_common_path.len > 0 and _common_path[0] == separator) _common_path[1..] else _common_path;
+ const has_leading_separator = _common_path.len > 0 and _common_path[0] == separator;
+
+ const common_path = if (has_leading_separator) _common_path[1..] else _common_path;
var shortest = std.math.min(normalized_from.len, normalized_to.len);
@@ -213,6 +215,8 @@ pub fn relativeToCommonPath(
// For example: from='/foo/bar/baz'; to='/foo/bar'
if (normalized_from[common_path.len - 1] == separator) {
last_common_separator = common_path.len - 1;
+ } else if (normalized_from[common_path.len] == separator) {
+ last_common_separator = common_path.len;
} else if (common_path.len == 0) {
// We get here if `to` is the root.
// For example: from='/foo/bar'; to='/'
@@ -227,10 +231,10 @@ pub fn relativeToCommonPath(
var out_slice: []u8 = buf[0..0];
if (normalized_from.len > 0) {
- var i: usize = last_common_separator;
+ var i: usize = @boolToInt(normalized_from[0] == separator) + 1 + last_common_separator;
while (i <= normalized_from.len) : (i += 1) {
- if (i == normalized_from.len or normalized_from[i] == separator) {
+ if (i == normalized_from.len or (normalized_from[i] == separator and i + 1 < normalized_from.len)) {
if (out_slice.len == 0) {
out_slice = buf[0 .. out_slice.len + 2];
out_slice[0] = '.';
@@ -265,7 +269,7 @@ pub fn relativeToCommonPath(
std.mem.copy(u8, out_slice[start..], tail);
}
- return buf[0 .. out_slice.len + 1];
+ return buf[0..out_slice.len];
}
pub fn relativeNormalized(from: []const u8, to: []const u8, comptime platform: Platform, comptime always_copy: bool) []const u8 {
@@ -274,6 +278,24 @@ pub fn relativeNormalized(from: []const u8, to: []const u8, comptime platform: P
return relativeToCommonPath(common_path, from, to, &relative_to_common_path_buf, comptime platform.separator(), always_copy);
}
+pub fn dirname(str: []const u8, comptime platform: Platform) []const u8 {
+ switch (comptime platform.resolve()) {
+ .loose => {
+ const separator = lastIndexOfSeparatorLoose(str);
+ return str[0 .. separator + 1];
+ },
+ .posix => {
+ const separator = lastIndexOfSeparatorPosix(str);
+ return str[0 .. separator + 1];
+ },
+ .windows => {
+ const separator = lastIndexOfSeparatorWindows(str) orelse return std.fs.path.diskDesignatorWindows(str);
+ return str[0 .. separator + 1];
+ },
+ else => unreachable,
+ }
+}
+
threadlocal var relative_from_buf: [4096]u8 = undefined;
threadlocal var relative_to_buf: [4096]u8 = undefined;
pub fn relative(from: []const u8, to: []const u8) []const u8 {