diff options
author | 2021-08-10 18:26:16 -0700 | |
---|---|---|
committer | 2021-08-10 18:26:16 -0700 | |
commit | 10b4b872a2824b6d7c66030dafc831f0da3309e8 (patch) | |
tree | a26e97e9e7be22c4407ccc628a54eecf09516c1f /src/resolver | |
parent | 0daff24b16487acfb420813793bc432f8ceaf333 (diff) | |
download | bun-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.zig | 80 | ||||
-rw-r--r-- | src/resolver/resolve_path.zig | 27 | ||||
-rw-r--r-- | src/resolver/resolver.zig | 108 |
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, |