diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig index 552187638b..af62ff0b89 100644 --- a/src/bun.js/bindings/bindings.zig +++ b/src/bun.js/bindings/bindings.zig @@ -4508,40 +4508,6 @@ pub const JSValue = enum(i64) { ); try buffered_writer.flush(); - - const count: usize = brk: { - var total: usize = 0; - var remain = out.list.items; - while (strings.indexOfChar(remain, '`')) |i| { - total += 1; - remain = remain[i + 1 ..]; - } - break :brk total; - }; - - if (count > 0) { - var result = try out.allocator.alloc(u8, count + out.list.items.len); - var input = out.list.items; - - var input_i: usize = 0; - var result_i: usize = 0; - while (strings.indexOfChar(input[input_i..], '`')) |i| { - bun.copy(u8, result[result_i..], input[input_i .. input_i + i]); - result_i += i; - result[result_i] = '\\'; - result[result_i + 1] = '`'; - result_i += 2; - input_i += i + 1; - } - - if (result_i != result.len) { - bun.copy(u8, result[result_i..], input[input_i..]); - } - - out.deinit(); - out.list.items = result; - out.list.capacity = result.len; - } } pub fn jestPrettyFormat(this: JSValue, out: *MutableString, globalObject: *JSGlobalObject) !void { diff --git a/src/bun.js/test/expect.zig b/src/bun.js/test/expect.zig index 642c5ec36d..92eab545e0 100644 --- a/src/bun.js/test/expect.zig +++ b/src/bun.js/test/expect.zig @@ -2704,7 +2704,7 @@ pub const Expect = struct { error.FailedToOpenSnapshotFile => globalThis.throw("Failed to open snapshot file for test file: {s}", .{test_file_path}), error.FailedToMakeSnapshotDirectory => globalThis.throw("Failed to make snapshot directory for test file: {s}", .{test_file_path}), error.FailedToWriteSnapshotFile => globalThis.throw("Failed write to snapshot file: {s}", .{test_file_path}), - error.ParseError => globalThis.throw("Failed to parse snapshot file for: {s}", .{test_file_path}), + error.SyntaxError, error.ParseError => globalThis.throw("Failed to parse snapshot file for: {s}", .{test_file_path}), else => globalThis.throw("Failed to snapshot value: {any}", .{value.toFmt(&formatter)}), } return .zero; diff --git a/src/bun.js/test/snapshot.zig b/src/bun.js/test/snapshot.zig index e8d46bb378..39536232a7 100644 --- a/src/bun.js/test/snapshot.zig +++ b/src/bun.js/test/snapshot.zig @@ -84,27 +84,29 @@ pub const Snapshots = struct { var pretty_value = try MutableString.init(this.allocator, 0); try value.jestSnapshotPrettyFormat(&pretty_value, globalObject); - const serialized_length = "\nexports[`".len + name_with_counter.len + "`] = `".len + pretty_value.list.items.len + "`;\n".len; - try this.file_buf.ensureUnusedCapacity(serialized_length); - this.file_buf.appendSliceAssumeCapacity("\nexports[`"); - this.file_buf.appendSliceAssumeCapacity(name_with_counter); - this.file_buf.appendSliceAssumeCapacity("`] = `"); - this.file_buf.appendSliceAssumeCapacity(pretty_value.list.items); - this.file_buf.appendSliceAssumeCapacity("`;\n"); + const estimated_length = "\nexports[`".len + name_with_counter.len + "`] = `".len + pretty_value.list.items.len + "`;\n".len; + try this.file_buf.ensureUnusedCapacity(estimated_length + 10); + try this.file_buf.writer().print( + "\nexports[`{}`] = `{}`;\n", + .{ + strings.formatEscapes(name_with_counter, .{ .quote_char = '`' }), + strings.formatEscapes(pretty_value.list.items, .{ .quote_char = '`' }), + }, + ); this.added += 1; try this.values.put(name_hash, pretty_value.toOwnedSlice()); return null; } - pub fn parseFile(this: *Snapshots) !void { + pub fn parseFile(this: *Snapshots, file: File) !void { if (this.file_buf.items.len == 0) return; const vm = VirtualMachine.get(); const opts = js_parser.Parser.Options.init(vm.bundler.options.jsx, .js); var temp_log = logger.Log.init(this.allocator); - const test_file = Jest.runner.?.files.get(this._current_file.?.id); + const test_file = Jest.runner.?.files.get(file.id); const test_filename = test_file.source.path.name.filename; const dir_path = test_file.source.path.name.dirWithTrailingSlash(); @@ -245,6 +247,7 @@ pub const Snapshots = struct { .id = file_id, .file = fd.asFile(), }; + errdefer file.file.close(); if (this.update_snapshots) { try this.file_buf.appendSlice(file_header); @@ -263,8 +266,8 @@ pub const Snapshots = struct { } } + try this.parseFile(file); this._current_file = file; - try this.parseFile(); } return JSC.Maybe(void).success; diff --git a/src/bundler/entry_points.zig b/src/bundler/entry_points.zig index ac4e4fbb70..141c9c6ad4 100644 --- a/src/bundler/entry_points.zig +++ b/src/bundler/entry_points.zig @@ -202,7 +202,7 @@ pub const ServerEntryPoint = struct { \\ , .{ - strings.QuoteEscapeFormat{ .data = path_to_use }, + strings.formatEscapes(path_to_use, .{ .quote_char = '\'' }), }, ); } @@ -225,7 +225,7 @@ pub const ServerEntryPoint = struct { \\ , .{ - strings.QuoteEscapeFormat{ .data = path_to_use }, + strings.formatEscapes(path_to_use, .{ .quote_char = '"' }), }, ); }; diff --git a/src/string_immutable.zig b/src/string_immutable.zig index 4ffa1e05a2..17da87c930 100644 --- a/src/string_immutable.zig +++ b/src/string_immutable.zig @@ -6519,24 +6519,25 @@ pub const visible = struct { }; }; -pub const QuoteEscapeFormat = struct { - data: []const u8, - - pub fn format(self: QuoteEscapeFormat, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void { - var i: usize = 0; - while (std.mem.indexOfAnyPos(u8, self.data, i, "\"\n\\")) |j| : (i = j + 1) { - try writer.writeAll(self.data[i..j]); - try writer.writeAll(switch (self.data[j]) { - '"' => "\\\"", - '\n' => "\\n", - '\\' => "\\\\", - else => unreachable, - }); - } - if (i == self.data.len) return; - try writer.writeAll(self.data[i..]); - } +pub const QuoteEscapeFormatFlags = struct { + quote_char: u8, + ascii_only: bool = false, + json: bool = false, + str_encoding: Encoding = .utf8, }; +/// usage: print(" string: '{'}' ", .{formatEscapesJS("hello'world!")}); +pub fn formatEscapes(str: []const u8, comptime flags: QuoteEscapeFormatFlags) QuoteEscapeFormat(flags) { + return .{ .data = str }; +} +fn QuoteEscapeFormat(comptime flags: QuoteEscapeFormatFlags) type { + return struct { + data: []const u8, + + pub fn format(self: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void { + try bun.js_printer.writePreQuotedString(self.data, @TypeOf(writer), writer, flags.quote_char, false, flags.json, flags.str_encoding); + } + }; +} /// Generic. Works on []const u8, []const u16, etc pub inline fn indexOfScalar(input: anytype, scalar: std.meta.Child(@TypeOf(input))) ?usize { diff --git a/test/bundler/transpiler/__snapshots__/transpiler.test.js.snap b/test/bundler/transpiler/__snapshots__/transpiler.test.js.snap index 50a51491f4..8e21dd38d1 100644 --- a/test/bundler/transpiler/__snapshots__/transpiler.test.js.snap +++ b/test/bundler/transpiler/__snapshots__/transpiler.test.js.snap @@ -143,561 +143,6 @@ __bun_temp_ref_6$ && await __bun_temp_ref_6$; }" `; -exports[`Bun.Transpiler using top level 1`] = ` -"import { -__callDispose as __callDispose, -__using as __using -} from "bun:wrap"; -export function c(e) { - let __bun_temp_ref_1$ = []; - try { - const f = __using(__bun_temp_ref_1$, g(a), 0); - return f.h; - } catch (__bun_temp_ref_2$) { - var __bun_temp_ref_3$ = __bun_temp_ref_2$, __bun_temp_ref_4$ = 1; - } finally { - __callDispose(__bun_temp_ref_1$, __bun_temp_ref_3$, __bun_temp_ref_4$); - } -} -import {using} from "n"; -let __bun_temp_ref_5$ = []; -try { - var a = __using(__bun_temp_ref_5$, b, 0); - var j = __using(__bun_temp_ref_5$, c(i), 1); - var k = __using(__bun_temp_ref_5$, l(m), 0); - var o = __using(__bun_temp_ref_5$, using, 0); - var p = __using(__bun_temp_ref_5$, await using, 1); - var q = r; -} catch (__bun_temp_ref_6$) { - var __bun_temp_ref_7$ = __bun_temp_ref_6$, __bun_temp_ref_8$ = 1; -} finally { - var __bun_temp_ref_9$ = __callDispose(__bun_temp_ref_5$, __bun_temp_ref_7$, __bun_temp_ref_8$); - __bun_temp_ref_9$ && await __bun_temp_ref_9$; -} - -export { - k, - q -}; -" -`; - -exports[`Bun.Transpiler using statements work right 1`] = ` -"let __bun_temp_ref_1$ = []; -try { -const x = __using(__bun_temp_ref_1$, a, 0); -} catch (__bun_temp_ref_2$) { -var __bun_temp_ref_3$ = __bun_temp_ref_2$, __bun_temp_ref_4$ = 1; -} finally { -__callDispose(__bun_temp_ref_1$, __bun_temp_ref_3$, __bun_temp_ref_4$); -}" -`; - -exports[`Bun.Transpiler using statements work right 2`] = ` -"let __bun_temp_ref_1$ = []; -try { -const x = __using(__bun_temp_ref_1$, a, 1); -} catch (__bun_temp_ref_2$) { -var __bun_temp_ref_3$ = __bun_temp_ref_2$, __bun_temp_ref_4$ = 1; -} finally { -var __bun_temp_ref_5$ = __callDispose(__bun_temp_ref_1$, __bun_temp_ref_3$, __bun_temp_ref_4$); -__bun_temp_ref_5$ && await __bun_temp_ref_5$; -}" -`; - -exports[`Bun.Transpiler using statements work right 3`] = ` -"for (const __bun_temp_ref_1$ of b) { -let __bun_temp_ref_2$ = []; -try { -const a = __using(__bun_temp_ref_2$, __bun_temp_ref_1$, 0); -c(a); -} catch (__bun_temp_ref_3$) { -var __bun_temp_ref_4$ = __bun_temp_ref_3$, __bun_temp_ref_5$ = 1; -} finally { -__callDispose(__bun_temp_ref_2$, __bun_temp_ref_4$, __bun_temp_ref_5$); -} -}" -`; - -exports[`Bun.Transpiler using statements work right 4`] = ` -"for await (const __bun_temp_ref_1$ of b) { -let __bun_temp_ref_2$ = []; -try { -const a = __using(__bun_temp_ref_2$, __bun_temp_ref_1$, 0); -c(a); -} catch (__bun_temp_ref_3$) { -var __bun_temp_ref_4$ = __bun_temp_ref_3$, __bun_temp_ref_5$ = 1; -} finally { -__callDispose(__bun_temp_ref_2$, __bun_temp_ref_4$, __bun_temp_ref_5$); -} -}" -`; - -exports[`Bun.Transpiler using statements work right 5`] = ` -"for (const __bun_temp_ref_1$ of b) { -let __bun_temp_ref_2$ = []; -try { -const a = __using(__bun_temp_ref_2$, __bun_temp_ref_1$, 1); -c(a); -} catch (__bun_temp_ref_3$) { -var __bun_temp_ref_4$ = __bun_temp_ref_3$, __bun_temp_ref_5$ = 1; -} finally { -var __bun_temp_ref_6$ = __callDispose(__bun_temp_ref_2$, __bun_temp_ref_4$, __bun_temp_ref_5$); -__bun_temp_ref_6$ && await __bun_temp_ref_6$; -} -}" -`; - -exports[`Bun.Transpiler using statements work right 6`] = ` -"for await (const __bun_temp_ref_1$ of b) { -let __bun_temp_ref_2$ = []; -try { -const a = __using(__bun_temp_ref_2$, __bun_temp_ref_1$, 1); -c(a); -} catch (__bun_temp_ref_3$) { -var __bun_temp_ref_4$ = __bun_temp_ref_3$, __bun_temp_ref_5$ = 1; -} finally { -var __bun_temp_ref_6$ = __callDispose(__bun_temp_ref_2$, __bun_temp_ref_4$, __bun_temp_ref_5$); -__bun_temp_ref_6$ && await __bun_temp_ref_6$; -} -}" -`; - -exports[`Bun.Transpiler using statements work right 7`] = ` -"for (const __bun_temp_ref_1$ of b) { -let __bun_temp_ref_2$ = []; -try { -const a = __using(__bun_temp_ref_2$, __bun_temp_ref_1$, 0); -c(a); -a(c); -} catch (__bun_temp_ref_3$) { -var __bun_temp_ref_4$ = __bun_temp_ref_3$, __bun_temp_ref_5$ = 1; -} finally { -__callDispose(__bun_temp_ref_2$, __bun_temp_ref_4$, __bun_temp_ref_5$); -} -}" -`; - -exports[`Bun.Transpiler using statements work right 8`] = ` -"for await (const __bun_temp_ref_1$ of b) { -let __bun_temp_ref_2$ = []; -try { -const a = __using(__bun_temp_ref_2$, __bun_temp_ref_1$, 0); -c(a); -a(c); -} catch (__bun_temp_ref_3$) { -var __bun_temp_ref_4$ = __bun_temp_ref_3$, __bun_temp_ref_5$ = 1; -} finally { -__callDispose(__bun_temp_ref_2$, __bun_temp_ref_4$, __bun_temp_ref_5$); -} -}" -`; - -exports[`Bun.Transpiler using statements work right 9`] = ` -"for (const __bun_temp_ref_1$ of b) { -let __bun_temp_ref_2$ = []; -try { -const a = __using(__bun_temp_ref_2$, __bun_temp_ref_1$, 1); -c(a); -a(c); -} catch (__bun_temp_ref_3$) { -var __bun_temp_ref_4$ = __bun_temp_ref_3$, __bun_temp_ref_5$ = 1; -} finally { -var __bun_temp_ref_6$ = __callDispose(__bun_temp_ref_2$, __bun_temp_ref_4$, __bun_temp_ref_5$); -__bun_temp_ref_6$ && await __bun_temp_ref_6$; -} -}" -`; - -exports[`Bun.Transpiler using statements work right 10`] = ` -"for await (const __bun_temp_ref_1$ of b) { -let __bun_temp_ref_2$ = []; -try { -const a = __using(__bun_temp_ref_2$, __bun_temp_ref_1$, 1); -c(a); -a(c); -} catch (__bun_temp_ref_3$) { -var __bun_temp_ref_4$ = __bun_temp_ref_3$, __bun_temp_ref_5$ = 1; -} finally { -var __bun_temp_ref_6$ = __callDispose(__bun_temp_ref_2$, __bun_temp_ref_4$, __bun_temp_ref_5$); -__bun_temp_ref_6$ && await __bun_temp_ref_6$; -} -}" -`; - -exports[`Bun.Transpiler using top level 1`] = ` -"import { -__callDispose as __callDispose, -__using as __using -} from "bun:wrap"; -export function c(e) { - let __bun_temp_ref_1$ = []; - try { - const f = __using(__bun_temp_ref_1$, g(a), 0); - return f.h; - } catch (__bun_temp_ref_2$) { - var __bun_temp_ref_3$ = __bun_temp_ref_2$, __bun_temp_ref_4$ = 1; - } finally { - __callDispose(__bun_temp_ref_1$, __bun_temp_ref_3$, __bun_temp_ref_4$); - } -} -import {using} from "n"; -let __bun_temp_ref_5$ = []; -try { - var a = __using(__bun_temp_ref_5$, b, 0); - var j = __using(__bun_temp_ref_5$, c(i), 1); - var k = __using(__bun_temp_ref_5$, l(m), 0); - var o = __using(__bun_temp_ref_5$, using, 0); - var p = __using(__bun_temp_ref_5$, await using, 1); - var q = r; -} catch (__bun_temp_ref_6$) { - var __bun_temp_ref_7$ = __bun_temp_ref_6$, __bun_temp_ref_8$ = 1; -} finally { - var __bun_temp_ref_9$ = __callDispose(__bun_temp_ref_5$, __bun_temp_ref_7$, __bun_temp_ref_8$); - __bun_temp_ref_9$ && await __bun_temp_ref_9$; -} - -export { - k, - q -}; -" -`; - -exports[`Bun.Transpiler using statements work right 1`] = ` -"let __bun_temp_ref_1$ = []; -try { -const x = __using(__bun_temp_ref_1$, a, 0); -} catch (__bun_temp_ref_2$) { -var __bun_temp_ref_3$ = __bun_temp_ref_2$, -__bun_temp_ref_4$ = 1; -} finally { -__callDispose(__bun_temp_ref_1$, __bun_temp_ref_3$, __bun_temp_ref_4$); -}" -`; - -exports[`Bun.Transpiler using statements work right 2`] = ` -"let __bun_temp_ref_1$ = []; -try { -const x = __using(__bun_temp_ref_1$, a, 1); -} catch (__bun_temp_ref_2$) { -var __bun_temp_ref_3$ = __bun_temp_ref_2$, -__bun_temp_ref_4$ = 1; -} finally { -var __bun_temp_ref_5$ = __callDispose(__bun_temp_ref_1$, __bun_temp_ref_3$, __bun_temp_ref_4$); -__bun_temp_ref_5$ && await __bun_temp_ref_5$; -}" -`; - -exports[`Bun.Transpiler using statements work right 3`] = ` -"for (const __bun_temp_ref_1$ of b) { -let __bun_temp_ref_2$ = []; -try { -const a = __using(__bun_temp_ref_2$, __bun_temp_ref_1$, 0); -c(a); -} catch (__bun_temp_ref_3$) { -var __bun_temp_ref_4$ = __bun_temp_ref_3$, -__bun_temp_ref_5$ = 1; -} finally { -__callDispose(__bun_temp_ref_2$, __bun_temp_ref_4$, __bun_temp_ref_5$); -} -}" -`; - -exports[`Bun.Transpiler using statements work right 4`] = ` -"for await (const __bun_temp_ref_1$ of b) { -let __bun_temp_ref_2$ = []; -try { -const a = __using(__bun_temp_ref_2$, __bun_temp_ref_1$, 0); -c(a); -} catch (__bun_temp_ref_3$) { -var __bun_temp_ref_4$ = __bun_temp_ref_3$, -__bun_temp_ref_5$ = 1; -} finally { -__callDispose(__bun_temp_ref_2$, __bun_temp_ref_4$, __bun_temp_ref_5$); -} -}" -`; - -exports[`Bun.Transpiler using statements work right 5`] = ` -"for (const __bun_temp_ref_1$ of b) { -let __bun_temp_ref_2$ = []; -try { -const a = __using(__bun_temp_ref_2$, __bun_temp_ref_1$, 1); -c(a); -} catch (__bun_temp_ref_3$) { -var __bun_temp_ref_4$ = __bun_temp_ref_3$, -__bun_temp_ref_5$ = 1; -} finally { -var __bun_temp_ref_6$ = __callDispose(__bun_temp_ref_2$, __bun_temp_ref_4$, __bun_temp_ref_5$); -__bun_temp_ref_6$ && await __bun_temp_ref_6$; -} -}" -`; - -exports[`Bun.Transpiler using statements work right 6`] = ` -"for await (const __bun_temp_ref_1$ of b) { -let __bun_temp_ref_2$ = []; -try { -const a = __using(__bun_temp_ref_2$, __bun_temp_ref_1$, 1); -c(a); -} catch (__bun_temp_ref_3$) { -var __bun_temp_ref_4$ = __bun_temp_ref_3$, -__bun_temp_ref_5$ = 1; -} finally { -var __bun_temp_ref_6$ = __callDispose(__bun_temp_ref_2$, __bun_temp_ref_4$, __bun_temp_ref_5$); -__bun_temp_ref_6$ && await __bun_temp_ref_6$; -} -}" -`; - -exports[`Bun.Transpiler using statements work right 7`] = ` -"for (const __bun_temp_ref_1$ of b) { -let __bun_temp_ref_2$ = []; -try { -const a = __using(__bun_temp_ref_2$, __bun_temp_ref_1$, 0); -c(a); -a(c); -} catch (__bun_temp_ref_3$) { -var __bun_temp_ref_4$ = __bun_temp_ref_3$, -__bun_temp_ref_5$ = 1; -} finally { -__callDispose(__bun_temp_ref_2$, __bun_temp_ref_4$, __bun_temp_ref_5$); -} -}" -`; - -exports[`Bun.Transpiler using statements work right 8`] = ` -"for await (const __bun_temp_ref_1$ of b) { -let __bun_temp_ref_2$ = []; -try { -const a = __using(__bun_temp_ref_2$, __bun_temp_ref_1$, 0); -c(a); -a(c); -} catch (__bun_temp_ref_3$) { -var __bun_temp_ref_4$ = __bun_temp_ref_3$, -__bun_temp_ref_5$ = 1; -} finally { -__callDispose(__bun_temp_ref_2$, __bun_temp_ref_4$, __bun_temp_ref_5$); -} -}" -`; - -exports[`Bun.Transpiler using statements work right 9`] = ` -"for (const __bun_temp_ref_1$ of b) { -let __bun_temp_ref_2$ = []; -try { -const a = __using(__bun_temp_ref_2$, __bun_temp_ref_1$, 1); -c(a); -a(c); -} catch (__bun_temp_ref_3$) { -var __bun_temp_ref_4$ = __bun_temp_ref_3$, -__bun_temp_ref_5$ = 1; -} finally { -var __bun_temp_ref_6$ = __callDispose(__bun_temp_ref_2$, __bun_temp_ref_4$, __bun_temp_ref_5$); -__bun_temp_ref_6$ && await __bun_temp_ref_6$; -} -}" -`; - -exports[`Bun.Transpiler using statements work right 10`] = ` -"for await (const __bun_temp_ref_1$ of b) { -let __bun_temp_ref_2$ = []; -try { -const a = __using(__bun_temp_ref_2$, __bun_temp_ref_1$, 1); -c(a); -a(c); -} catch (__bun_temp_ref_3$) { -var __bun_temp_ref_4$ = __bun_temp_ref_3$, -__bun_temp_ref_5$ = 1; -} finally { -var __bun_temp_ref_6$ = __callDispose(__bun_temp_ref_2$, __bun_temp_ref_4$, __bun_temp_ref_5$); -__bun_temp_ref_6$ && await __bun_temp_ref_6$; -} -}" -`; - -exports[`Bun.Transpiler using top level 1`] = ` -"import { __callDispose as __callDispose, __using as __using } from "bun:wrap"; -export function c(e) { - let __bun_temp_ref_1$ = []; - try { - const f = __using(__bun_temp_ref_1$, g(a), 0); - return f.h; - } catch (__bun_temp_ref_2$) { - var __bun_temp_ref_3$ = __bun_temp_ref_2$, - __bun_temp_ref_4$ = 1; - } finally { - __callDispose(__bun_temp_ref_1$, __bun_temp_ref_3$, __bun_temp_ref_4$); - } -} -import { using } from "n"; -let __bun_temp_ref_5$ = []; -try { - var a = __using(__bun_temp_ref_5$, b, 0); - var j = __using(__bun_temp_ref_5$, c(i), 1); - var k = __using(__bun_temp_ref_5$, l(m), 0); - var o = __using(__bun_temp_ref_5$, using, 0); - var p = __using(__bun_temp_ref_5$, await using, 1); - var q = r; -} catch (__bun_temp_ref_6$) { - var __bun_temp_ref_7$ = __bun_temp_ref_6$, - __bun_temp_ref_8$ = 1; -} finally { - var __bun_temp_ref_9$ = __callDispose(__bun_temp_ref_5$, __bun_temp_ref_7$, __bun_temp_ref_8$); - __bun_temp_ref_9$ && await __bun_temp_ref_9$; -} - -export { - k, - q -}; -" -`; - -exports[`Bun.Transpiler using statements work right 1`] = ` -"let __bun_temp_ref_1$ = []; -try { -const x = __using(__bun_temp_ref_1$, a, 0); -} catch (__bun_temp_ref_2$) { -var __bun_temp_ref_3$ = __bun_temp_ref_2$, __bun_temp_ref_4$ = 1; -} finally { -__callDispose(__bun_temp_ref_1$, __bun_temp_ref_3$, __bun_temp_ref_4$); -}" -`; - -exports[`Bun.Transpiler using statements work right 2`] = ` -"let __bun_temp_ref_1$ = []; -try { -const x = __using(__bun_temp_ref_1$, a, 1); -} catch (__bun_temp_ref_2$) { -var __bun_temp_ref_3$ = __bun_temp_ref_2$, __bun_temp_ref_4$ = 1; -} finally { -var __bun_temp_ref_5$ = __callDispose(__bun_temp_ref_1$, __bun_temp_ref_3$, __bun_temp_ref_4$); -__bun_temp_ref_5$ && await __bun_temp_ref_5$; -}" -`; - -exports[`Bun.Transpiler using statements work right 3`] = ` -"for (const __bun_temp_ref_1$ of b) { -let __bun_temp_ref_2$ = []; -try { -const a = __using(__bun_temp_ref_2$, __bun_temp_ref_1$, 0); -c(a); -} catch (__bun_temp_ref_3$) { -var __bun_temp_ref_4$ = __bun_temp_ref_3$, __bun_temp_ref_5$ = 1; -} finally { -__callDispose(__bun_temp_ref_2$, __bun_temp_ref_4$, __bun_temp_ref_5$); -} -}" -`; - -exports[`Bun.Transpiler using statements work right 4`] = ` -"for await (const __bun_temp_ref_1$ of b) { -let __bun_temp_ref_2$ = []; -try { -const a = __using(__bun_temp_ref_2$, __bun_temp_ref_1$, 0); -c(a); -} catch (__bun_temp_ref_3$) { -var __bun_temp_ref_4$ = __bun_temp_ref_3$, __bun_temp_ref_5$ = 1; -} finally { -__callDispose(__bun_temp_ref_2$, __bun_temp_ref_4$, __bun_temp_ref_5$); -} -}" -`; - -exports[`Bun.Transpiler using statements work right 5`] = ` -"for (const __bun_temp_ref_1$ of b) { -let __bun_temp_ref_2$ = []; -try { -const a = __using(__bun_temp_ref_2$, __bun_temp_ref_1$, 1); -c(a); -} catch (__bun_temp_ref_3$) { -var __bun_temp_ref_4$ = __bun_temp_ref_3$, __bun_temp_ref_5$ = 1; -} finally { -var __bun_temp_ref_6$ = __callDispose(__bun_temp_ref_2$, __bun_temp_ref_4$, __bun_temp_ref_5$); -__bun_temp_ref_6$ && await __bun_temp_ref_6$; -} -}" -`; - -exports[`Bun.Transpiler using statements work right 6`] = ` -"for await (const __bun_temp_ref_1$ of b) { -let __bun_temp_ref_2$ = []; -try { -const a = __using(__bun_temp_ref_2$, __bun_temp_ref_1$, 1); -c(a); -} catch (__bun_temp_ref_3$) { -var __bun_temp_ref_4$ = __bun_temp_ref_3$, __bun_temp_ref_5$ = 1; -} finally { -var __bun_temp_ref_6$ = __callDispose(__bun_temp_ref_2$, __bun_temp_ref_4$, __bun_temp_ref_5$); -__bun_temp_ref_6$ && await __bun_temp_ref_6$; -} -}" -`; - -exports[`Bun.Transpiler using statements work right 7`] = ` -"for (const __bun_temp_ref_1$ of b) { -let __bun_temp_ref_2$ = []; -try { -const a = __using(__bun_temp_ref_2$, __bun_temp_ref_1$, 0); -c(a); -a(c); -} catch (__bun_temp_ref_3$) { -var __bun_temp_ref_4$ = __bun_temp_ref_3$, __bun_temp_ref_5$ = 1; -} finally { -__callDispose(__bun_temp_ref_2$, __bun_temp_ref_4$, __bun_temp_ref_5$); -} -}" -`; - -exports[`Bun.Transpiler using statements work right 8`] = ` -"for await (const __bun_temp_ref_1$ of b) { -let __bun_temp_ref_2$ = []; -try { -const a = __using(__bun_temp_ref_2$, __bun_temp_ref_1$, 0); -c(a); -a(c); -} catch (__bun_temp_ref_3$) { -var __bun_temp_ref_4$ = __bun_temp_ref_3$, __bun_temp_ref_5$ = 1; -} finally { -__callDispose(__bun_temp_ref_2$, __bun_temp_ref_4$, __bun_temp_ref_5$); -} -}" -`; - -exports[`Bun.Transpiler using statements work right 9`] = ` -"for (const __bun_temp_ref_1$ of b) { -let __bun_temp_ref_2$ = []; -try { -const a = __using(__bun_temp_ref_2$, __bun_temp_ref_1$, 1); -c(a); -a(c); -} catch (__bun_temp_ref_3$) { -var __bun_temp_ref_4$ = __bun_temp_ref_3$, __bun_temp_ref_5$ = 1; -} finally { -var __bun_temp_ref_6$ = __callDispose(__bun_temp_ref_2$, __bun_temp_ref_4$, __bun_temp_ref_5$); -__bun_temp_ref_6$ && await __bun_temp_ref_6$; -} -}" -`; - -exports[`Bun.Transpiler using statements work right 10`] = ` -"for await (const __bun_temp_ref_1$ of b) { -let __bun_temp_ref_2$ = []; -try { -const a = __using(__bun_temp_ref_2$, __bun_temp_ref_1$, 1); -c(a); -a(c); -} catch (__bun_temp_ref_3$) { -var __bun_temp_ref_4$ = __bun_temp_ref_3$, __bun_temp_ref_5$ = 1; -} finally { -var __bun_temp_ref_6$ = __callDispose(__bun_temp_ref_2$, __bun_temp_ref_4$, __bun_temp_ref_5$); -__bun_temp_ref_6$ && await __bun_temp_ref_6$; -} -}" -`; - exports[`Bun.Transpiler using top level 1`] = ` "import { __callDispose as __callDispose, __using as __using } from "bun:wrap"; export function c(e) { diff --git a/test/js/bun/test/__snapshots__/test-interop.js.snap b/test/js/bun/test/__snapshots__/test-interop.js.snap index eb56d73084..c626a5ab56 100644 --- a/test/js/bun/test/__snapshots__/test-interop.js.snap +++ b/test/js/bun/test/__snapshots__/test-interop.js.snap @@ -1,11 +1,3 @@ // Bun Snapshot v1, https://goo.gl/fbAQLP exports[`expect() toMatchSnapshot to return undefined 1`] = `"abc"`; - -exports[`expect() toMatchSnapshot to return undefined 1`] = `"abc"`; - -exports[`expect() toMatchSnapshot to return undefined 1`] = `"abc"`; - -exports[`expect() toMatchSnapshot to return undefined 1`] = `"abc"`; - -exports[`expect() toMatchSnapshot to return undefined 1`] = `"abc"`; diff --git a/test/js/bun/test/snapshot-tests/snapshots/__snapshots__/snapshot.test.ts.snap b/test/js/bun/test/snapshot-tests/snapshots/__snapshots__/snapshot.test.ts.snap index 47112120bc..d8f0026646 100644 --- a/test/js/bun/test/snapshot-tests/snapshots/__snapshots__/snapshot.test.ts.snap +++ b/test/js/bun/test/snapshot-tests/snapshots/__snapshots__/snapshot.test.ts.snap @@ -368,3 +368,186 @@ exports[`most types: testing 7 2`] = `9`; exports[`most types: testing 7 3`] = `8`; exports[`most types: undefined 1`] = `undefined`; + +exports[`snapshots dollars 1`] = ` +"// Bun Snapshot v1, https://goo.gl/fbAQLP + +exports[\`abc 1\`] = \`"$"\`; +" +`; + +exports[`snapshots backslash 1`] = ` +"// Bun Snapshot v1, https://goo.gl/fbAQLP + +exports[\`abc 1\`] = \`"\\\\"\`; +" +`; + +exports[`snapshots dollars curly 1`] = ` +"// Bun Snapshot v1, https://goo.gl/fbAQLP + +exports[\`abc 1\`] = \`"\\\${}"\`; +" +`; + +exports[`snapshots dollars curly 2 1`] = ` +"// Bun Snapshot v1, https://goo.gl/fbAQLP + +exports[\`abc 1\`] = \`"\\\${"\`; +" +`; + +exports[`snapshots stuff 1`] = ` +"// Bun Snapshot v1, https://goo.gl/fbAQLP + +exports[\`abc 1\`] = \` +"æ™ + +!!!!*5897yhduN"'\\\`Il" +\`; +" +`; + +exports[`snapshots stuff 2 1`] = ` +"// Bun Snapshot v1, https://goo.gl/fbAQLP + +exports[\`abc 1\`] = \` +"æ™ + +!!!!*5897yh!uN"'\\\`Il" +\`; +" +`; + +exports[`snapshots regexp 1 1`] = ` +"// Bun Snapshot v1, https://goo.gl/fbAQLP + +exports[\`abc 1\`] = \`/\\\${1..}/\`; +" +`; + +exports[`snapshots regexp 2 1`] = ` +"// Bun Snapshot v1, https://goo.gl/fbAQLP + +exports[\`abc 1\`] = \`/\\\${2..}/\`; +" +`; + +exports[`snapshots string 1`] = ` +"// Bun Snapshot v1, https://goo.gl/fbAQLP + +exports[\`abc 1\`] = \`"abc"\`; +" +`; + +exports[`snapshots string with newline 1`] = ` +"// Bun Snapshot v1, https://goo.gl/fbAQLP + +exports[\`abc 1\`] = \` +"qwerty +ioup" +\`; +" +`; + +exports[`snapshots null byte 1`] = ` +"// Bun Snapshot v1, https://goo.gl/fbAQLP + +exports[\`abc 1\`] = \`"1 \\x00"\`; +" +`; + +exports[`snapshots null byte 2 1`] = ` +"// Bun Snapshot v1, https://goo.gl/fbAQLP + +exports[\`abc 1\`] = \`"2 \\x00"\`; +" +`; + +exports[`snapshots backticks 1`] = ` +"// Bun Snapshot v1, https://goo.gl/fbAQLP + +exports[\`abc 1\`] = \`"This is \\\`wrong\\\`"\`; +" +`; + +exports[`snapshots unicode 1`] = ` +"// Bun Snapshot v1, https://goo.gl/fbAQLP + +exports[\`abc 1\`] = \`"😊abc\\\`\\\${def} �, � "\`; +" +`; + +exports[`snapshots jest newline oddity 1`] = ` +"// Bun Snapshot v1, https://goo.gl/fbAQLP + +exports[\`abc 1\`] = \` +" +" +\`; +" +`; + +exports[`snapshots grow file for new snapshot 1`] = ` +"// Bun Snapshot v1, https://goo.gl/fbAQLP + +exports[\`abc 1\`] = \`"hello"\`; +" +`; + +exports[`snapshots grow file for new snapshot 2`] = ` +"// Bun Snapshot v1, https://goo.gl/fbAQLP + +exports[\`abc 1\`] = \`"hello"\`; + +exports[\`def 1\`] = \`"hello"\`; +" +`; + +exports[`snapshots grow file for new snapshot 3`] = ` +"// Bun Snapshot v1, https://goo.gl/fbAQLP + +exports[\`abc 1\`] = \`"goodbye"\`; + +exports[\`def 1\`] = \`"hello"\`; +" +`; + +exports[`snapshots backtick in test name 1`] = ` +"// Bun Snapshot v1, https://goo.gl/fbAQLP + +exports[\`\\\` 1\`] = \`"abc"\`; +" +`; + +exports[`snapshots dollars curly in test name 1`] = ` +"// Bun Snapshot v1, https://goo.gl/fbAQLP + +exports[\`\\\${} 1\`] = \`"abc"\`; +" +`; + +exports[`snapshots #15283 1`] = ` +"// Bun Snapshot v1, https://goo.gl/fbAQLP + +exports[\`Should work 1\`] = \`"This is \\\`wrong\\\`"\`; +" +`; + +exports[`snapshots #15283 unicode 1`] = ` +"// Bun Snapshot v1, https://goo.gl/fbAQLP + +exports[\`Should work 1\`] = \`"😊This is \\\`wrong\\\`"\`; +" +`; + +exports[`snapshots replaces file that fails to parse when update flag is used 1`] = ` +"// Bun Snapshot v1, https://goo.gl/fbAQLP + +exports[\`t1 1\`] = \`"abc def ghi jkl"\`; + +exports[\`t2 1\`] = \`"abc\\\`def"\`; + +exports[\`t3 1\`] = \`"abc def ghi"\`; +" +`; diff --git a/test/js/bun/test/snapshot-tests/snapshots/more.test.ts b/test/js/bun/test/snapshot-tests/snapshots/more.test.ts index 38214d3199..74b1a457e6 100644 --- a/test/js/bun/test/snapshot-tests/snapshots/more.test.ts +++ b/test/js/bun/test/snapshot-tests/snapshots/more.test.ts @@ -1,7 +1,7 @@ import { describe, expect, test } from "bun:test"; describe("d0", () => { - test.todo("snapshot serialize edgecases", () => { + test("snapshot serialize edgecases", () => { expect(1).toMatchSnapshot(); expect("1\b2\n3\r4").toMatchSnapshot(); expect("\r\n").toMatchSnapshot(); @@ -47,7 +47,7 @@ describe("d0", () => { describe("d0", () => { describe("d1", () => { - test.todo("t1", () => { + test("t1", () => { expect("hello`snapshot\\").toEqual("hello`snapshot\\"); expect("hello`snapshot\\").toMatchSnapshot(); }); @@ -58,7 +58,7 @@ describe("d0", () => { test("t3", () => { expect("hello snapshot").toMatchSnapshot(); }); - test.todo("t4", () => { + test("t4", () => { expect("hello`snapshot\\").toMatchSnapshot(); }); }); diff --git a/test/js/bun/test/snapshot-tests/snapshots/snapshot.test.ts b/test/js/bun/test/snapshot-tests/snapshots/snapshot.test.ts index 5b68833f7d..8451d85370 100644 --- a/test/js/bun/test/snapshot-tests/snapshots/snapshot.test.ts +++ b/test/js/bun/test/snapshot-tests/snapshots/snapshot.test.ts @@ -1,4 +1,6 @@ -import { expect, it, test } from "bun:test"; +import { $ } from "bun"; +import { describe, expect, it, test } from "bun:test"; +import { bunExe, tempDirWithFiles } from "harness"; function test1000000(arg1: any, arg218718132: any) {} @@ -164,3 +166,160 @@ test("most types", () => { it("should work with expect.anything()", () => { // expect({ a: 0 }).toMatchSnapshot({ a: expect.anything() }); }); + +function defaultWrap(a: string): string { + return `test("abc", () => { expect(${a}).toMatchSnapshot() });`; +} + +class SnapshotTester { + dir: string; + targetSnapshotContents: string; + isFirst: boolean = true; + constructor() { + this.dir = tempDirWithFiles("snapshotTester", { "snapshot.test.ts": "" }); + this.targetSnapshotContents = ""; + } + test( + label: string, + contents: string, + opts: { shouldNotError?: boolean; shouldGrow?: boolean; skipSnapshot?: boolean } = {}, + ) { + test(label, async () => await this.update(contents, opts)); + } + async update( + contents: string, + opts: { shouldNotError?: boolean; shouldGrow?: boolean; skipSnapshot?: boolean; forceUpdate?: boolean } = {}, + ) { + const isFirst = this.isFirst; + this.isFirst = false; + await Bun.write(this.dir + "/snapshot.test.ts", contents); + + if (!opts.shouldNotError) { + if (!isFirst) { + // make sure it fails first: + expect((await $`cd ${this.dir} && ${bunExe()} test ./snapshot.test.ts`.nothrow().quiet()).exitCode).not.toBe(0); + // make sure the existing snapshot is unchanged: + expect(await Bun.file(this.dir + "/__snapshots__/snapshot.test.ts.snap").text()).toBe( + this.targetSnapshotContents, + ); + } + // update snapshots now, using -u flag unless this is the first run + await $`cd ${this.dir} && ${bunExe()} test ${isFirst && !opts.forceUpdate ? "" : "-u"} ./snapshot.test.ts`.quiet(); + // make sure the snapshot changed & didn't grow + const newContents = await this.getSnapshotContents(); + if (!isFirst) { + expect(newContents).not.toStartWith(this.targetSnapshotContents); + } + if (!opts.skipSnapshot) expect(newContents).toMatchSnapshot(); + this.targetSnapshotContents = newContents; + } + // run, make sure snapshot does not change + await $`cd ${this.dir} && ${bunExe()} test ./snapshot.test.ts`.quiet(); + if (!opts.shouldGrow) { + expect(await Bun.file(this.dir + "/__snapshots__/snapshot.test.ts.snap").text()).toBe( + this.targetSnapshotContents, + ); + } else { + this.targetSnapshotContents = await this.getSnapshotContents(); + } + } + async setSnapshotFile(contents: string) { + await Bun.write(this.dir + "/__snapshots__/snapshot.test.ts.snap", contents); + this.isFirst = true; + } + async getSnapshotContents(): Promise { + return await Bun.file(this.dir + "/__snapshots__/snapshot.test.ts.snap").text(); + } +} + +describe("snapshots", async () => { + const t = new SnapshotTester(); + await t.update(defaultWrap("''"), { skipSnapshot: true }); + + t.test("dollars", defaultWrap("`\\$`")); + t.test("backslash", defaultWrap("`\\\\`")); + t.test("dollars curly", defaultWrap("`\\${}`")); + t.test("dollars curly 2", defaultWrap("`\\${`")); + t.test("stuff", defaultWrap(`\`æ™\n\r!!!!*5897yhduN\\"\\'\\\`Il\``)); + t.test("stuff 2", defaultWrap(`\`æ™\n\r!!!!*5897yh!uN\\"\\'\\\`Il\``)); + + t.test("regexp 1", defaultWrap("/${1..}/")); + t.test("regexp 2", defaultWrap("/${2..}/")); + t.test("string", defaultWrap('"abc"')); + t.test("string with newline", defaultWrap('"qwerty\\nioup"')); + + t.test("null byte", defaultWrap('"1 \x00"')); + t.test("null byte 2", defaultWrap('"2 \\x00"')); + + t.test("backticks", defaultWrap("`This is \\`wrong\\``")); + t.test("unicode", defaultWrap("'😊abc`${def} " + "😊".substring(0, 1) + ", " + "😊".substring(1, 2) + " '")); + + test("jest newline oddity", async () => { + await t.update(defaultWrap("'\\n'")); + await t.update(defaultWrap("'\\r'"), { shouldNotError: true }); + await t.update(defaultWrap("'\\r\\n'"), { shouldNotError: true }); + }); + + test("don't grow file on error", async () => { + await t.setSnapshotFile("exports[`snap 1`] = `hello`goodbye`;"); + try { + await t.update(/*js*/ ` + test("t1", () => {expect("abc def ghi jkl").toMatchSnapshot();}) + test("t2", () => {expect("abc\`def").toMatchSnapshot();}) + test("t3", () => {expect("abc def ghi").toMatchSnapshot();}) + `); + } catch (e) {} + expect(await t.getSnapshotContents()).toBe("exports[`snap 1`] = `hello`goodbye`;"); + }); + + test("replaces file that fails to parse when update flag is used", async () => { + await t.setSnapshotFile("exports[`snap 1`] = `hello`goodbye`;"); + await t.update( + /*js*/ ` + test("t1", () => {expect("abc def ghi jkl").toMatchSnapshot();}) + test("t2", () => {expect("abc\`def").toMatchSnapshot();}) + test("t3", () => {expect("abc def ghi").toMatchSnapshot();}) + `, + { forceUpdate: true }, + ); + expect(await t.getSnapshotContents()).toBe( + '// Bun Snapshot v1, https://goo.gl/fbAQLP\n\nexports[`t1 1`] = `"abc def ghi jkl"`;\n\nexports[`t2 1`] = `"abc\\`def"`;\n\nexports[`t3 1`] = `"abc def ghi"`;\n', + ); + }); + + test("grow file for new snapshot", async () => { + const t4 = new SnapshotTester(); + await t4.update(/*js*/ ` + test("abc", () => { expect("hello").toMatchSnapshot() }); + `); + await t4.update( + /*js*/ ` + test("abc", () => { expect("hello").toMatchSnapshot() }); + test("def", () => { expect("goodbye").toMatchSnapshot() }); + `, + { shouldNotError: true, shouldGrow: true }, + ); + await t4.update(/*js*/ ` + test("abc", () => { expect("hello").toMatchSnapshot() }); + test("def", () => { expect("hello").toMatchSnapshot() }); + `); + await t4.update(/*js*/ ` + test("abc", () => { expect("goodbye").toMatchSnapshot() }); + test("def", () => { expect("hello").toMatchSnapshot() }); + `); + }); + + const t2 = new SnapshotTester(); + t2.test("backtick in test name", `test("\`", () => {expect("abc").toMatchSnapshot();})`); + const t3 = new SnapshotTester(); + t3.test("dollars curly in test name", `test("\${}", () => {expect("abc").toMatchSnapshot();})`); + + const t15283 = new SnapshotTester(); + t15283.test( + "#15283", + `it("Should work", () => { + expect(\`This is \\\`wrong\\\`\`).toMatchSnapshot(); + });`, + ); + t15283.test("#15283 unicode", `it("Should work", () => {expect(\`😊This is \\\`wrong\\\`\`).toMatchSnapshot()});`); +}); diff --git a/test/regression/issue/03830.test.ts b/test/regression/issue/03830.test.ts index a4272dd96f..e55856d950 100644 --- a/test/regression/issue/03830.test.ts +++ b/test/regression/issue/03830.test.ts @@ -15,7 +15,10 @@ it("macros should not lead to seg faults under any given input", async () => { // Create a directory with our test file mkdirSync(testDir, { recursive: true }); writeFileSync(join(testDir, "macro.ts"), "export function fn(str) { return str; }"); - writeFileSync(join(testDir, "index.ts"), "import { fn } from './macro' assert { type: 'macro' };\nfn(`©${''}`);"); + writeFileSync( + join(testDir, "index.ts"), + "import { fn } from './macro' assert { type: 'macro' };\nfn(`©${Number(0)}`);", + ); testDir = realpathSync(testDir); const { stderr, exitCode } = Bun.spawnSync({ diff --git a/test/regression/issue/__snapshots__/03830.test.ts.snap b/test/regression/issue/__snapshots__/03830.test.ts.snap index ebaa50fa2e..da75c83eb3 100644 --- a/test/regression/issue/__snapshots__/03830.test.ts.snap +++ b/test/regression/issue/__snapshots__/03830.test.ts.snap @@ -1,42 +1,7 @@ // Bun Snapshot v1, https://goo.gl/fbAQLP exports[`macros should not lead to seg faults under any given input 1`] = ` -"2 | fn(\`©${''}\`); - ^ -error: "Cannot convert argument type to JS" error in macro - at [dir]/index.ts:2:1" -`; - -exports[`macros should not lead to seg faults under any given input 1`] = ` -"2 | fn(\`©${''}\`); - ^ -error: "Cannot convert argument type to JS" error in macro - at [dir]/index.ts:2:1" -`; - -exports[`macros should not lead to seg faults under any given input 1`] = ` -"2 | fn(\`©${''}\`); - ^ -error: "Cannot convert argument type to JS" error in macro - at [dir]/index.ts:2:1" -`; - -exports[`macros should not lead to seg faults under any given input 1`] = ` -"2 | fn(\`©${''}\`); - ^ -error: "Cannot convert argument type to JS" error in macro - at [dir]/index.ts:2:1" -`; - -exports[`macros should not lead to seg faults under any given input 1`] = ` -"2 | fn(\`©${''}\`); - ^ -error: "Cannot convert argument type to JS" error in macro - at [dir]/index.ts:2:1" -`; - -exports[`macros should not lead to seg faults under any given input 1`] = ` -"2 | fn(\`©${''}\`); +"2 | fn(\`©\${Number(0)}\`); ^ error: "Cannot convert argument type to JS" error in macro at [dir]/index.ts:2:1"