aboutsummaryrefslogtreecommitdiff
path: root/src/resolver
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2021-08-10 18:26:16 -0700
committerGravatar Jarred Sumner <jarred@jarredsumner.com> 2021-08-10 18:26:16 -0700
commit10b4b872a2824b6d7c66030dafc831f0da3309e8 (patch)
treea26e97e9e7be22c4407ccc628a54eecf09516c1f /src/resolver
parent0daff24b16487acfb420813793bc432f8ceaf333 (diff)
downloadbun-10b4b872a2824b6d7c66030dafc831f0da3309e8.tar.gz
bun-10b4b872a2824b6d7c66030dafc831f0da3309e8.tar.zst
bun-10b4b872a2824b6d7c66030dafc831f0da3309e8.zip
This is alot
Former-commit-id: 4b2a396611ec03270dc768b70e488b0f5eee2a37
Diffstat (limited to 'src/resolver')
-rw-r--r--src/resolver/package_json.zig80
-rw-r--r--src/resolver/resolve_path.zig27
-rw-r--r--src/resolver/resolver.zig108
3 files changed, 165 insertions, 50 deletions
diff --git a/src/resolver/package_json.zig b/src/resolver/package_json.zig
index 07d58ff6f..7862de15c 100644
--- a/src/resolver/package_json.zig
+++ b/src/resolver/package_json.zig
@@ -84,40 +84,50 @@ pub const PackageJSON = struct {
pub fn loadFrameworkWithPreference(package_json: *const PackageJSON, pair: *FrameworkRouterPair, json: js_ast.Expr, allocator: *std.mem.Allocator, comptime load_framework: LoadFramework) void {
const framework_object = json.asProperty("framework") orelse return;
- if (framework_object.expr.asProperty("router")) |router| {
- if (router.expr.asProperty("dir")) |route_dir| {
- if (route_dir.expr.asString(allocator)) |str| {
- if (str.len > 0) {
- pair.router.dir = str;
- pair.loaded_routes = true;
- }
+ if (framework_object.expr.asProperty("static")) |static_prop| {
+ if (static_prop.expr.asString(allocator)) |str| {
+ if (str.len > 0) {
+ pair.router.static_dir = str;
}
}
+ }
- if (router.expr.asProperty("extensions")) |extensions_expr| {
- if (extensions_expr.expr.asArray()) |*array| {
- const count = array.array.items.len;
- var valid_count: usize = 0;
-
- while (array.next()) |expr| {
- if (expr.data != .e_string) continue;
- const e_str: *const js_ast.E.String = expr.data.e_string;
- if (e_str.utf8.len == 0 or e_str.utf8[0] != '.') continue;
- valid_count += 1;
+ if (!pair.router.routes_enabled) {
+ if (framework_object.expr.asProperty("router")) |router| {
+ if (router.expr.asProperty("dir")) |route_dir| {
+ if (route_dir.expr.asString(allocator)) |str| {
+ if (str.len > 0) {
+ pair.router.dir = str;
+ pair.loaded_routes = true;
+ }
}
+ }
- if (valid_count > 0) {
- var extensions = allocator.alloc(string, valid_count) catch unreachable;
- array.index = 0;
- var i: usize = 0;
+ if (router.expr.asProperty("extensions")) |extensions_expr| {
+ if (extensions_expr.expr.asArray()) |*array| {
+ const count = array.array.items.len;
+ var valid_count: usize = 0;
- // We don't need to allocate the strings because we keep the package.json source string in memory
while (array.next()) |expr| {
if (expr.data != .e_string) continue;
const e_str: *const js_ast.E.String = expr.data.e_string;
if (e_str.utf8.len == 0 or e_str.utf8[0] != '.') continue;
- extensions[i] = e_str.utf8;
- i += 1;
+ valid_count += 1;
+ }
+
+ if (valid_count > 0) {
+ var extensions = allocator.alloc(string, valid_count) catch unreachable;
+ array.index = 0;
+ var i: usize = 0;
+
+ // We don't need to allocate the strings because we keep the package.json source string in memory
+ while (array.next()) |expr| {
+ if (expr.data != .e_string) continue;
+ const e_str: *const js_ast.E.String = expr.data.e_string;
+ if (e_str.utf8.len == 0 or e_str.utf8[0] != '.') continue;
+ extensions[i] = e_str.utf8;
+ i += 1;
+ }
}
}
}
@@ -130,6 +140,15 @@ pub const PackageJSON = struct {
if (loadFrameworkExpression(pair.framework, env.expr, allocator)) {
pair.framework.package = package_json.name;
pair.framework.development = true;
+ if (env.expr.asProperty("static")) |static_prop| {
+ if (static_prop.expr.asString(allocator)) |str| {
+ if (str.len > 0) {
+ pair.router.static_dir = str;
+ pair.router.static_dir_enabled = true;
+ }
+ }
+ }
+
return;
}
}
@@ -139,6 +158,16 @@ pub const PackageJSON = struct {
if (loadFrameworkExpression(pair.framework, env.expr, allocator)) {
pair.framework.package = package_json.name;
pair.framework.development = false;
+
+ if (env.expr.asProperty("static")) |static_prop| {
+ if (static_prop.expr.asString(allocator)) |str| {
+ if (str.len > 0) {
+ pair.router.static_dir = str;
+ pair.router.static_dir_enabled = true;
+ }
+ }
+ }
+
return;
}
}
@@ -159,8 +188,9 @@ pub const PackageJSON = struct {
dirname_fd: StoredFileDescriptorType,
comptime generate_hash: bool,
) ?PackageJSON {
- const parts = [_]string{ input_path, "package.json" };
+ // TODO: remove this extra copy
+ const parts = [_]string{ input_path, "package.json" };
const package_json_path_ = r.fs.abs(&parts);
const package_json_path = r.fs.filename_store.append(@TypeOf(package_json_path_), package_json_path_) catch unreachable;
diff --git a/src/resolver/resolve_path.zig b/src/resolver/resolve_path.zig
index 212b2ff4d..e451db36f 100644
--- a/src/resolver/resolve_path.zig
+++ b/src/resolver/resolve_path.zig
@@ -648,6 +648,15 @@ pub fn joinAbsString(_cwd: []const u8, parts: anytype, comptime _platform: Platf
);
}
+pub fn joinAbsStringZ(_cwd: []const u8, parts: anytype, comptime _platform: Platform) [:0]const u8 {
+ return joinAbsStringBufZ(
+ _cwd,
+ &parser_join_input_buffer,
+ parts,
+ _platform,
+ );
+}
+
pub fn joinStringBuf(buf: []u8, _parts: anytype, comptime _platform: Platform) []const u8 {
if (FeatureFlags.use_std_path_join) {
var alloc = std.heap.FixedBufferAllocator.init(buf);
@@ -701,8 +710,19 @@ pub fn joinStringBuf(buf: []u8, _parts: anytype, comptime _platform: Platform) [
}
pub fn joinAbsStringBuf(_cwd: []const u8, buf: []u8, _parts: anytype, comptime _platform: Platform) []const u8 {
+ return _joinAbsStringBuf(false, []const u8, _cwd, buf, _parts, _platform);
+}
+
+pub fn joinAbsStringBufZ(_cwd: []const u8, buf: []u8, _parts: anytype, comptime _platform: Platform) [:0]const u8 {
+ return _joinAbsStringBuf(true, [:0]const u8, _cwd, buf, _parts, _platform);
+}
+
+inline fn _joinAbsStringBuf(comptime is_sentinel: bool, comptime ReturnType: type, _cwd: []const u8, buf: []u8, _parts: anytype, comptime _platform: Platform) ReturnType {
var parts: []const []const u8 = _parts;
if (parts.len == 0) {
+ if (comptime is_sentinel) {
+ unreachable;
+ }
return _cwd;
}
@@ -779,7 +799,12 @@ pub fn joinAbsStringBuf(_cwd: []const u8, buf: []u8, _parts: anytype, comptime _
std.mem.copy(u8, buf[leading_separator.len .. result.len + leading_separator.len], result);
- return buf[0 .. result.len + leading_separator.len];
+ if (comptime is_sentinel) {
+ buf.ptr[result.len + leading_separator.len + 1] = 0;
+ return buf[0 .. result.len + leading_separator.len :0];
+ } else {
+ return buf[0 .. result.len + leading_separator.len];
+ }
}
pub fn isSepPosix(char: u8) bool {
diff --git a/src/resolver/resolver.zig b/src/resolver/resolver.zig
index cf517498b..3488a693d 100644
--- a/src/resolver/resolver.zig
+++ b/src/resolver/resolver.zig
@@ -49,13 +49,13 @@ pub const PathPair = struct {
pub const Iter = struct {
index: u2,
ctx: *PathPair,
- pub fn next(i: *Iter) ?Path {
+ pub fn next(i: *Iter) ?*Path {
const ind = i.index;
i.index += 1;
switch (ind) {
- 0 => return i.ctx.primary,
- 1 => return i.ctx.secondary,
+ 0 => return &i.ctx.primary,
+ 1 => return if (i.ctx.secondary) |*sec| sec else null,
else => return null,
}
}
@@ -402,6 +402,7 @@ pub fn NewResolver(cache_files: bool) type {
std.mem.copy(u8, out, realpath);
out[out.len - 1] = '/';
pair.router.dir = out;
+ pair.router.routes_enabled = true;
}
}
@@ -488,17 +489,56 @@ pub fn NewResolver(cache_files: bool) type {
r.mutex.lock();
defer r.mutex.unlock();
-
- const result = r.resolveWithoutSymlinks(source_dir, import_path, kind) catch |err| {
+ errdefer (r.flushDebugLogs(.fail) catch {});
+ var result = (try r.resolveWithoutSymlinks(source_dir, import_path, kind)) orelse {
r.flushDebugLogs(.fail) catch {};
- return err;
+ return error.ModuleNotFound;
};
- defer {
- if (result == null) r.flushDebugLogs(.fail) catch {} else r.flushDebugLogs(.success) catch {};
+ try r.finalizeResult(&result);
+ r.flushDebugLogs(.success) catch {};
+ return result;
+ }
+
+ pub fn finalizeResult(r: *ThisResolver, result: *Result) !void {
+ if (result.package_json) |package_json| {
+ result.module_type = switch (package_json.module_type) {
+ .esm, .cjs => package_json.module_type,
+ .unknown => result.module_type,
+ };
}
- return result orelse return error.ModuleNotFound;
+ var iter = result.path_pair.iter();
+ while (iter.next()) |path| {
+ var dir: *DirInfo = (r.readDirInfo(path.name.dir) catch continue) orelse continue;
+ if (dir.getEntries()) |entries| {
+ if (entries.get(path.name.filename)) |query| {
+ const symlink_path = query.entry.symlink(&r.fs.fs);
+ if (symlink_path.len > 0) {
+ path.non_symlink = path.text;
+ // Is this entry itself a symlink?
+ path.text = symlink_path;
+ path.name = Fs.PathName.init(path.text);
+
+ if (r.debug_logs) |*debug| {
+ debug.addNoteFmt("Resolved symlink \"{s}\" to \"{s}\"", .{ path.non_symlink, path.text }) catch {};
+ }
+ } else if (dir.abs_real_path.len > 0) {
+ path.non_symlink = path.text;
+ var parts = [_]string{ dir.abs_real_path, query.entry.base };
+ var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined;
+ var out = r.fs.absBuf(&parts, &buf);
+ const symlink = try Fs.FileSystem.FilenameStore.instance.append(@TypeOf(out), out);
+ if (r.debug_logs) |*debug| {
+ debug.addNoteFmt("Resolved symlink \"{s}\" to \"{s}\"", .{ symlink, path.text }) catch {};
+ }
+ query.entry.cache.symlink = symlink;
+
+ path.name = Fs.PathName.init(path.text);
+ }
+ }
+ }
+ }
}
pub fn resolveWithoutSymlinks(r: *ThisResolver, source_dir: string, import_path: string, kind: ast.ImportKind) !?Result {
@@ -716,7 +756,7 @@ pub fn NewResolver(cache_files: bool) type {
}
var iter = result.path_pair.iter();
- while (iter.next()) |*path| {
+ while (iter.next()) |path| {
const dirname = std.fs.path.dirname(path.text) orelse continue;
const base_dir_info = ((r.dirInfoCached(dirname) catch null)) orelse continue;
const dir_info = base_dir_info.getEnclosingBrowserScope() orelse continue;
@@ -752,11 +792,13 @@ pub fn NewResolver(cache_files: bool) type {
}
// This is a fallback, hopefully not called often. It should be relatively quick because everything should be in the cache.
- fn packageJSONForResolvedNodeModuleWithIgnoreMissingName(r: *ThisResolver, result: *const Result, comptime ignore_missing_name: bool) ?*const PackageJSON {
- var current_dir = std.fs.path.dirname(result.path_pair.primary.text);
- while (current_dir != null) {
- var dir_info = (r.dirInfoCached(current_dir orelse unreachable) catch null) orelse return null;
-
+ fn packageJSONForResolvedNodeModuleWithIgnoreMissingName(
+ r: *ThisResolver,
+ result: *const Result,
+ comptime ignore_missing_name: bool,
+ ) ?*const PackageJSON {
+ var dir_info = (r.dirInfoCached(result.path_pair.primary.name.dir) catch null) orelse return null;
+ while (true) {
if (dir_info.package_json) |pkg| {
// if it doesn't have a name, assume it's something just for adjusting the main fields (react-bootstrap does this)
// In that case, we really would like the top-level package that you download from NPM
@@ -765,13 +807,15 @@ pub fn NewResolver(cache_files: bool) type {
if (pkg.name.len > 0) {
return pkg;
}
+ } else {
+ return pkg;
}
}
- current_dir = std.fs.path.dirname(current_dir.?);
+ dir_info = dir_info.getParent() orelse return null;
}
- return null;
+ unreachable;
}
pub fn loadNodeModules(r: *ThisResolver, import_path: string, kind: ast.ImportKind, _dir_info: *DirInfo) ?MatchResult {
@@ -916,24 +960,31 @@ pub fn NewResolver(cache_files: bool) type {
r: *ThisResolver,
path: string,
) !?*DirInfo {
- return try r.dirInfoCachedMaybeLog(path, true);
+ return try r.dirInfoCachedMaybeLog(path, true, true);
}
pub fn readDirInfo(
r: *ThisResolver,
path: string,
) !?*DirInfo {
- return try r.dirInfoCachedMaybeLog(path, false);
+ return try r.dirInfoCachedMaybeLog(path, false, true);
}
pub fn readDirInfoIgnoreError(
r: *ThisResolver,
path: string,
) ?*const DirInfo {
- return r.dirInfoCachedMaybeLog(path, false) catch null;
+ return r.dirInfoCachedMaybeLog(path, false, true) catch null;
}
- inline fn dirInfoCachedMaybeLog(r: *ThisResolver, path: string, comptime enable_logging: bool) !?*DirInfo {
+ pub inline fn readDirInfoCacheOnly(
+ r: *ThisResolver,
+ path: string,
+ ) ?*DirInfo {
+ return r.dir_cache.get(path);
+ }
+
+ inline fn dirInfoCachedMaybeLog(r: *ThisResolver, path: string, comptime enable_logging: bool, comptime follow_symlinks: bool) !?*DirInfo {
const top_result = try r.dir_cache.getOrPut(path);
if (top_result.status != .unknown) {
return r.dir_cache.atIndex(top_result.index);
@@ -1021,9 +1072,18 @@ pub fn NewResolver(cache_files: bool) type {
var _open_dir: anyerror!std.fs.Dir = undefined;
if (open_dir_count > 0) {
- _open_dir = _open_dirs[open_dir_count - 1].openDir(std.fs.path.basename(queue_top.unsafe_path), .{ .iterate = true });
+ _open_dir = _open_dirs[open_dir_count - 1].openDir(
+ std.fs.path.basename(queue_top.unsafe_path),
+ .{ .iterate = true, .no_follow = !follow_symlinks },
+ );
} else {
- _open_dir = std.fs.openDirAbsolute(queue_top.unsafe_path, .{ .iterate = true });
+ _open_dir = std.fs.openDirAbsolute(
+ queue_top.unsafe_path,
+ .{
+ .iterate = true,
+ .no_follow = !follow_symlinks,
+ },
+ );
}
const open_dir = _open_dir catch |err| {
@@ -1684,7 +1744,7 @@ pub fn NewResolver(cache_files: bool) type {
debug.addNoteFmt("Found file \"{s}\" ", .{base}) catch {};
}
const abs_path_parts = [_]string{ query.entry.dir, query.entry.base };
- const abs_path = r.fs.filename_store.append(string, r.fs.joinBuf(&abs_path_parts, &TemporaryBuffer.ExtensionPathBuf)) catch unreachable;
+ const abs_path = r.fs.filename_store.append(string, r.fs.absBuf(&abs_path_parts, &TemporaryBuffer.ExtensionPathBuf)) catch unreachable;
return LoadResult{
.path = abs_path,