Files
bun.sh/src/runtime.zig
Dylan Conway 54e7a6f57a typescript decorators round 2 (#1445)
* __decorateClass, __decorateParam, lit test, wiptest test

* decorator factories test

* parameter decorator test

* test for decorators with constructor parameter properties

* Fix issue with `CryptoKey` and `SubtleCrypto` constructors

* Limit concurrency for GitHub Actions due to issues with cache poisoning
If multiple actions are running, sometimes the cache is poisoned from another action. We need to fix this, but this is an interim measure to make actions less flaky

* Make these tests better

* Move this to dependencies so the .a files upload

* Fixup

* temporary fix

* Limit concurrency for MacOS Object actions

* try againn

* againn

* Make `"tls"` an explicit object we pass instead of implicit top-level options

cc @Electroid @colinhacks

* Update server.zig

* Prefer `BUN_PORT` over `PORT`

* Fix typo in homebrew action

* Run homebrew action when release is edited

* Check published_at instead of draft in GitHub action

* Implement `process.release`

* Add missing dependencies to `make devcontainer`

* Allow overriding node polyfills via `BUN_OVERRIDE_MODULE_PATH`

* Add a stub for io_darwin on linux

cc @sno2 hopefully this helps but i'm not sure

* Add missing `break`

* Download more RAM

* feat(core): optimize zig slice (#1408)

* feat(core): optimize zig slice

* address concerns

* Remove webcrypto from vendor-without-check

* Update default tsconfig (#1418)

Co-authored-by: Colin McDonnell <colinmcd@alum.mit.edu>

* Enable `BUN_OVERRIDE_MODULE_PATH` in `bun wiptest`

* Upgrade WebKit

* space

* Support getting cached values and pending activity in the bindings generator

* Remove ✂️ function

* constructor creation, initializers, handle static and computed fields with decorators

* Updating libuwebsockets C API (#1423)

* fix for repeated regex match calls and fix for '^' in character classes (#1419)

* tests and formatting

* fix for ^ in character class

* formatting

* test for repeated match and exec calls

* create oniguruma regex for each exec/test

* check errorCode from creating oniguruma regexp and always return {} on failure

* oops

* call onig_initialize once

* fix incorrect escaping, removed unnecessary oniguruma settings

* tests for "-" and "^" in character classes

* free regex object before returns

* force gc for some tests

* Update React fizz server (#1432)

* Update fizz server

* Use production build

Co-authored-by: Colin McDonnell <colinmcd@alum.mit.edu>

* more decorator tests

* optional setup function for loading elements, simulate clicks in lit test

* fix createWriteStream (#1433)

* fix createWriteStream

* remove comment

* Update build docs and commands for dev containers (#1438)

* Update build documentation for dev containers

* Add devcontainer-rebuild make target

* Add make devcontainer-sh target

* Fix missing .PHONY for vendor-without-check (#1437)

* Fix check for ninja on Debian/Ubuntu (#1436)

Even though the package is named ninja-build, the ninja binary is still
named ninja, so use `which ninja` to check for it

* Fix #1410

woops

* await on DOMContentLoaded for elements instead of setup function

* avoid lowering class if no decorators

Co-authored-by: Jarred Sumner <709451+Jarred-Sumner@users.noreply.github.com>
Co-authored-by: Ashcon Partovi <ashcon@partovi.net>
Co-authored-by: Carter Snook <cartersnook04@gmail.com>
Co-authored-by: Colin McDonnell <colinmcd94@gmail.com>
Co-authored-by: Colin McDonnell <colinmcd@alum.mit.edu>
Co-authored-by: Ciro Spaciari <ciro.spaciari@gmail.com>
Co-authored-by: Lawrence Chen <54008264+lawrencecchen@users.noreply.github.com>
Co-authored-by: João Paquim <jpaquim@users.noreply.github.com>
2022-11-01 21:25:30 -07:00

579 lines
22 KiB
Zig

const options = @import("./options.zig");
const bun = @import("global.zig");
const string = bun.string;
const Output = bun.Output;
const Global = bun.Global;
const Environment = bun.Environment;
const strings = bun.strings;
const MutableString = bun.MutableString;
const stringZ = bun.stringZ;
const default_allocator = bun.default_allocator;
const C = bun.C;
const std = @import("std");
const resolve_path = @import("./resolver/resolve_path.zig");
const Fs = @import("./fs.zig");
const Schema = @import("./api/schema.zig");
const Ref = @import("ast/base.zig").Ref;
const JSAst = @import("./js_ast.zig");
// packages/bun-cli-*/bun
const BUN_ROOT = "../../";
const Api = Schema.Api;
fn embedDebugFallback(comptime msg: []const u8, comptime code: []const u8) []const u8 {
const FallbackMessage = struct {
pub var has_printed = false;
};
if (!FallbackMessage.has_printed) {
FallbackMessage.has_printed = true;
Output.debug(msg, .{});
}
return code;
}
pub const ErrorCSS = struct {
const ErrorCSSPath = "packages/bun-error/dist/bun-error.css";
const ErrorCSSPathDev = "packages/bun-error/bun-error.css";
pub const ProdSourceContent = @embedFile("../" ++ ErrorCSSPath);
pub inline fn sourceContent() string {
if (comptime Environment.isDebug) {
var out_buffer: [bun.MAX_PATH_BYTES]u8 = undefined;
var dirname = std.fs.selfExeDirPath(&out_buffer) catch unreachable;
var paths = [_]string{ dirname, BUN_ROOT, ErrorCSSPathDev };
const file = std.fs.cwd().openFile(
resolve_path.joinAbsString(dirname, std.mem.span(&paths), .auto),
.{ .mode = .read_only },
) catch return embedDebugFallback(
"Missing packages/bun-error/bun-error.css. Please run \"make bun_error\"",
ProdSourceContent,
);
defer file.close();
return file.readToEndAlloc(default_allocator, (file.stat() catch unreachable).size) catch unreachable;
} else {
return ProdSourceContent;
}
}
};
pub const ReactRefresh = @embedFile("./react-refresh.js");
pub const ErrorJS = struct {
const ErrorJSPath = "packages/bun-error/dist/index.js";
pub const ProdSourceContent = @embedFile("../" ++ ErrorJSPath);
pub inline fn sourceContent() string {
if (comptime Environment.isDebug) {
var out_buffer: [bun.MAX_PATH_BYTES]u8 = undefined;
var dirname = std.fs.selfExeDirPath(&out_buffer) catch unreachable;
var paths = [_]string{ dirname, BUN_ROOT, ErrorJSPath };
const file = std.fs.cwd().openFile(
resolve_path.joinAbsString(dirname, std.mem.span(&paths), .auto),
.{ .mode = .read_only },
) catch return embedDebugFallback(
"Missing " ++ ErrorJSPath ++ ". Please run \"make bun_error\"",
ProdSourceContent,
);
defer file.close();
return file.readToEndAlloc(default_allocator, (file.stat() catch unreachable).size) catch unreachable;
} else {
return ProdSourceContent;
}
}
};
pub const Fallback = struct {
pub const ProdSourceContent = @embedFile("./fallback.out.js");
pub const HTMLTemplate = @embedFile("./fallback.html");
pub const HTMLBackendTemplate = @embedFile("./fallback-backend.html");
const Base64FallbackMessage = struct {
msg: *const Api.FallbackMessageContainer,
allocator: std.mem.Allocator,
pub fn format(this: Base64FallbackMessage, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
var bb = std.ArrayList(u8).init(this.allocator);
defer bb.deinit();
var bb_writer = bb.writer();
const Encoder = Schema.Writer(@TypeOf(bb_writer));
var encoder = Encoder.init(bb_writer);
this.msg.encode(&encoder) catch {};
Base64Encoder.encode(bb.items, @TypeOf(writer), writer) catch {};
}
pub const Base64Encoder = struct {
const alphabet_chars = std.base64.standard_alphabet_chars;
pub fn encode(source: []const u8, comptime Writer: type, writer: Writer) !void {
var acc: u12 = 0;
var acc_len: u4 = 0;
for (source) |v| {
acc = (acc << 8) + v;
acc_len += 8;
while (acc_len >= 6) {
acc_len -= 6;
try writer.writeByte(alphabet_chars[@truncate(u6, (acc >> acc_len))]);
}
}
if (acc_len > 0) {
try writer.writeByte(alphabet_chars[@truncate(u6, (acc << 6 - acc_len))]);
}
}
};
};
pub inline fn scriptContent() string {
if (comptime Environment.isDebug) {
var dirpath = std.fs.path.dirname(@src().file).?;
var env = std.process.getEnvMap(default_allocator) catch unreachable;
const dir = std.mem.replaceOwned(
u8,
default_allocator,
dirpath,
"jarred",
env.get("USER").?,
) catch unreachable;
var runtime_path = std.fs.path.join(default_allocator, &[_]string{ dir, "fallback.out.js" }) catch unreachable;
const file = std.fs.openFileAbsolute(runtime_path, .{}) catch return embedDebugFallback(
"Missing bun/src/fallback.out.js. " ++ "Please run \"make fallback_decoder\"",
ProdSourceContent,
);
defer file.close();
return file.readToEndAlloc(default_allocator, (file.stat() catch unreachable).size) catch unreachable;
} else {
return ProdSourceContent;
}
}
pub const version_hash = @embedFile("./fallback.version");
var version_hash_int: u32 = 0;
pub fn versionHash() u32 {
if (version_hash_int == 0) {
version_hash_int = @truncate(u32, std.fmt.parseInt(u64, version(), 16) catch unreachable);
}
return version_hash_int;
}
pub fn version() string {
return version_hash;
}
pub fn render(
allocator: std.mem.Allocator,
msg: *const Api.FallbackMessageContainer,
preload: string,
entry_point: string,
comptime WriterType: type,
writer: WriterType,
) !void {
const PrintArgs = struct {
blob: Base64FallbackMessage,
preload: string,
fallback: string,
entry_point: string,
};
try writer.print(HTMLTemplate, PrintArgs{
.blob = Base64FallbackMessage{ .msg = msg, .allocator = allocator },
.preload = preload,
.fallback = scriptContent(),
.entry_point = entry_point,
});
}
pub fn renderBackend(
allocator: std.mem.Allocator,
msg: *const Api.FallbackMessageContainer,
comptime WriterType: type,
writer: WriterType,
) !void {
const PrintArgs = struct {
blob: Base64FallbackMessage,
bun_error_css: string,
bun_error: string,
fallback: string,
bun_error_page_css: string,
};
try writer.print(HTMLBackendTemplate, PrintArgs{
.blob = Base64FallbackMessage{ .msg = msg, .allocator = allocator },
.bun_error_css = ErrorCSS.sourceContent(),
.bun_error = ErrorJS.sourceContent(),
.bun_error_page_css = "",
.fallback = scriptContent(),
});
}
};
pub const Runtime = struct {
pub const ProdSourceContent = @embedFile("./runtime.out.js");
pub const ProdSourceContentNode = @embedFile("./runtime.node.out.js");
pub const ProdSourceContentBun = @embedFile("./runtime.bun.out.js");
pub const ProdSourceContentWithRefresh = @embedFile("./runtime.out.refresh.js");
pub inline fn sourceContentWithoutRefresh() string {
if (comptime Environment.isDebug) {
var dirpath = std.fs.path.dirname(@src().file).?;
var env = std.process.getEnvMap(default_allocator) catch unreachable;
const dir = std.mem.replaceOwned(
u8,
default_allocator,
dirpath,
"jarred",
env.get("USER").?,
) catch unreachable;
var runtime_path = std.fs.path.join(default_allocator, &[_]string{ dir, "runtime.out.js" }) catch unreachable;
const file = std.fs.openFileAbsolute(runtime_path, .{}) catch return embedDebugFallback(
"Missing bun/src/runtime.out.js. " ++ "Please run \"make runtime_js_dev\"",
ProdSourceContent,
);
defer file.close();
return file.readToEndAlloc(default_allocator, (file.stat() catch unreachable).size) catch unreachable;
} else {
return ProdSourceContent;
}
}
pub inline fn sourceContent(with_refresh: bool) string {
if (with_refresh) return sourceContentWithRefresh();
return sourceContentWithoutRefresh();
}
pub inline fn sourceContentNode() string {
return ProdSourceContentNode;
}
pub inline fn sourceContentBun() string {
return ProdSourceContentBun;
}
pub inline fn sourceContentWithRefresh() string {
if (comptime Environment.isDebug) {
var dirpath = std.fs.path.dirname(@src().file).?;
var env = std.process.getEnvMap(default_allocator) catch unreachable;
const dir = std.mem.replaceOwned(
u8,
default_allocator,
dirpath,
"jarred",
env.get("USER").?,
) catch unreachable;
var runtime_path = std.fs.path.join(default_allocator, &[_]string{ dir, "runtime.out.refresh.js" }) catch unreachable;
const file = std.fs.openFileAbsolute(runtime_path, .{}) catch return embedDebugFallback(
"Missing bun/src/runtime.out.refresh.js. " ++ "Please run \"make runtime_js_dev\"",
ProdSourceContentWithRefresh,
);
defer file.close();
return file.readToEndAlloc(default_allocator, (file.stat() catch unreachable).size) catch unreachable;
} else {
return ProdSourceContentWithRefresh;
}
}
pub const version_hash = @embedFile("./runtime.version");
var version_hash_int: u32 = 0;
pub fn versionHash() u32 {
if (version_hash_int == 0) {
version_hash_int = @truncate(u32, std.fmt.parseInt(u64, version(), 16) catch unreachable);
}
return version_hash_int;
}
pub inline fn version() string {
return version_hash;
}
const bytecodeCacheFilename = std.fmt.comptimePrint("__runtime.{s}", .{version_hash});
var bytecodeCacheFetcher = Fs.BytecodeCacheFetcher{};
pub fn byteCodeCacheFile(fs: *Fs.FileSystem.RealFS) ?bun.StoredFileDescriptorType {
return bytecodeCacheFetcher.fetch(bytecodeCacheFilename, fs);
}
pub const Features = struct {
react_fast_refresh: bool = false,
hot_module_reloading: bool = false,
is_macro_runtime: bool = false,
top_level_await: bool = false,
auto_import_jsx: bool = false,
allow_runtime: bool = true,
/// Instead of jsx("div", {}, void 0)
/// ->
/// {
/// "type": "div",
/// "props": {},
/// "children": [],
/// key: void 0,
/// $$typeof: Symbol.for("react.element"),
/// }
/// See also https://github.com/babel/babel/commit/3cad2872335e2130f2ff6335027617ebbe9b5a46
/// See also https://github.com/babel/babel/pull/2972
/// See also https://github.com/facebook/react/issues/5138
jsx_optimization_inline: bool = false,
jsx_optimization_hoist: bool = false,
trim_unused_imports: bool = false,
should_fold_numeric_constants: bool = false,
/// Use `import.meta.require()` instead of require()?
/// This is only supported in Bun.
dynamic_require: bool = false,
replace_exports: ReplaceableExport.Map = .{},
hoist_bun_plugin: bool = false,
pub const ReplaceableExport = union(enum) {
delete: void,
replace: JSAst.Expr,
inject: struct {
name: string,
value: JSAst.Expr,
},
pub const Map = std.StringArrayHashMapUnmanaged(ReplaceableExport);
};
};
pub const Names = struct {
pub const ActivateFunction = "activate";
};
pub const GeneratedSymbol = struct {
primary: Ref,
backup: Ref,
ref: Ref,
};
// If you change this, remember to update "runtime.footer.js" and rebuild the runtime.js
pub const Imports = struct {
__name: ?GeneratedSymbol = null,
__toModule: ?GeneratedSymbol = null,
__cJS2eSM: ?GeneratedSymbol = null,
__require: ?GeneratedSymbol = null,
__export: ?GeneratedSymbol = null,
__reExport: ?GeneratedSymbol = null,
__load: ?GeneratedSymbol = null,
@"$$m": ?GeneratedSymbol = null,
@"$$lzy": ?GeneratedSymbol = null,
__HMRModule: ?GeneratedSymbol = null,
__HMRClient: ?GeneratedSymbol = null,
__FastRefreshModule: ?GeneratedSymbol = null,
__exportValue: ?GeneratedSymbol = null,
__exportDefault: ?GeneratedSymbol = null,
__FastRefreshRuntime: ?GeneratedSymbol = null,
__merge: ?GeneratedSymbol = null,
__decorateClass: ?GeneratedSymbol = null,
__decorateParam: ?GeneratedSymbol = null,
pub const all = [_][]const u8{
// __HMRClient goes first
// This is so we can call Bun.activate(true) as soon as possible
"__HMRClient",
"__name",
"__toModule",
"__require",
"__cJS2eSM",
"__export",
"__reExport",
"__load",
"$$m",
"$$lzy",
"__HMRModule",
"__FastRefreshModule",
"__exportValue",
"__exportDefault",
"__FastRefreshRuntime",
"__merge",
"__decorateClass",
"__decorateParam",
};
pub const Name = "bun:wrap";
pub const alt_name = "bun:wrap";
pub const Iterator = struct {
i: usize = 0,
runtime_imports: *Imports,
const Entry = struct {
key: u16,
value: Ref,
};
pub fn next(this: *Iterator) ?Entry {
while (this.i < all.len) {
defer this.i += 1;
switch (this.i) {
0 => {
if (@field(this.runtime_imports, all[0])) |val| {
return Entry{ .key = 0, .value = val.ref };
}
},
1 => {
if (@field(this.runtime_imports, all[1])) |val| {
return Entry{ .key = 1, .value = val.ref };
}
},
2 => {
if (@field(this.runtime_imports, all[2])) |val| {
return Entry{ .key = 2, .value = val.ref };
}
},
3 => {
if (@field(this.runtime_imports, all[3])) |val| {
return Entry{ .key = 3, .value = val.ref };
}
},
4 => {
if (@field(this.runtime_imports, all[4])) |val| {
return Entry{ .key = 4, .value = val.ref };
}
},
5 => {
if (@field(this.runtime_imports, all[5])) |val| {
return Entry{ .key = 5, .value = val.ref };
}
},
6 => {
if (@field(this.runtime_imports, all[6])) |val| {
return Entry{ .key = 6, .value = val.ref };
}
},
7 => {
if (@field(this.runtime_imports, all[7])) |val| {
return Entry{ .key = 7, .value = val.ref };
}
},
8 => {
if (@field(this.runtime_imports, all[8])) |val| {
return Entry{ .key = 8, .value = val.ref };
}
},
9 => {
if (@field(this.runtime_imports, all[9])) |val| {
return Entry{ .key = 9, .value = val.ref };
}
},
10 => {
if (@field(this.runtime_imports, all[10])) |val| {
return Entry{ .key = 10, .value = val.ref };
}
},
11 => {
if (@field(this.runtime_imports, all[11])) |val| {
return Entry{ .key = 11, .value = val.ref };
}
},
12 => {
if (@field(this.runtime_imports, all[12])) |val| {
return Entry{ .key = 12, .value = val.ref };
}
},
13 => {
if (@field(this.runtime_imports, all[13])) |val| {
return Entry{ .key = 13, .value = val.ref };
}
},
14 => {
if (@field(this.runtime_imports, all[14])) |val| {
return Entry{ .key = 14, .value = val.ref };
}
},
15 => {
if (@field(this.runtime_imports, all[15])) |val| {
return Entry{ .key = 15, .value = val.ref };
}
},
16 => {
if (@field(this.runtime_imports, all[16])) |val| {
return Entry{ .key = 16, .value = val.ref };
}
},
17 => {
if (@field(this.runtime_imports, all[17])) |val| {
return Entry{ .key = 17, .value = val.ref };
}
},
else => {
return null;
},
}
}
return null;
}
};
pub fn iter(imports: *Imports) Iterator {
return Iterator{ .runtime_imports = imports };
}
pub fn contains(imports: *const Imports, comptime key: string) bool {
return @field(imports, key) != null;
}
pub fn hasAny(imports: *const Imports) bool {
inline for (all) |field| {
if (@field(imports, field) != null) {
return true;
}
}
return false;
}
pub fn put(imports: *Imports, comptime key: string, generated_symbol: GeneratedSymbol) void {
@field(imports, key) = generated_symbol;
}
pub fn at(
imports: *Imports,
comptime key: string,
) ?Ref {
return (@field(imports, key) orelse return null).ref;
}
pub fn get(
imports: *const Imports,
key: anytype,
) ?Ref {
return switch (key) {
0 => (@field(imports, all[0]) orelse return null).ref,
1 => (@field(imports, all[1]) orelse return null).ref,
2 => (@field(imports, all[2]) orelse return null).ref,
3 => (@field(imports, all[3]) orelse return null).ref,
4 => (@field(imports, all[4]) orelse return null).ref,
5 => (@field(imports, all[5]) orelse return null).ref,
6 => (@field(imports, all[6]) orelse return null).ref,
7 => (@field(imports, all[7]) orelse return null).ref,
8 => (@field(imports, all[8]) orelse return null).ref,
9 => (@field(imports, all[9]) orelse return null).ref,
10 => (@field(imports, all[10]) orelse return null).ref,
11 => (@field(imports, all[11]) orelse return null).ref,
12 => (@field(imports, all[12]) orelse return null).ref,
13 => (@field(imports, all[13]) orelse return null).ref,
14 => (@field(imports, all[14]) orelse return null).ref,
15 => (@field(imports, all[15]) orelse return null).ref,
16 => (@field(imports, all[16]) orelse return null).ref,
17 => (@field(imports, all[17]) orelse return null).ref,
else => null,
};
}
pub fn count(imports: *const Imports) usize {
var i: usize = 0;
inline for (all) |field| {
if (@field(imports, field) != null) {
i += 1;
}
}
return i;
}
};
};