diff options
author | 2022-02-18 02:48:20 -0800 | |
---|---|---|
committer | 2022-02-18 02:48:20 -0800 | |
commit | 90f1f326ca758bb45869d56ad50e97fa753074a5 (patch) | |
tree | 870cb5195e898d21a59e7b34cb0892a262b61acd | |
parent | 8383544bb57ba2cc804c047632e7013f07ff3cd3 (diff) | |
download | bun-90f1f326ca758bb45869d56ad50e97fa753074a5.tar.gz bun-90f1f326ca758bb45869d56ad50e97fa753074a5.tar.zst bun-90f1f326ca758bb45869d56ad50e97fa753074a5.zip |
[bun dev] Fix bug with importing `node:` namespace
-rw-r--r-- | src/linker.zig | 38 | ||||
-rw-r--r-- | src/node_module_bundle.zig | 58 |
2 files changed, 94 insertions, 2 deletions
diff --git a/src/linker.zig b/src/linker.zig index 278d57927..8ac15ddd7 100644 --- a/src/linker.zig +++ b/src/linker.zig @@ -287,6 +287,40 @@ pub const Linker = struct { } } + if (linker.options.node_modules_bundle) |node_modules_bundle| { + if (Resolver.isPackagePath(import_record.path.text)) { + const text = import_record.path.text; + + var package_name = text; + if (text[0] == '@') { + if (std.mem.indexOfScalar(u8, text, '/')) |i| { + if (std.mem.indexOfScalar(u8, text[i + 1 ..], '/')) |j| { + package_name = text[0 .. i + 1 + j]; + } + } + } else { + if (std.mem.indexOfScalar(u8, text, '/')) |i| { + package_name = text[0..i]; + } + } + if (package_name.len != text.len) { + if (node_modules_bundle.getPackage(package_name)) |pkg| { + const import_path = text[@minimum(text.len, package_name.len + 1)..]; + if (node_modules_bundle.findModuleIDInPackageIgnoringExtension(pkg, import_path)) |found_module| { + import_record.is_bundled = true; + node_module_bundle_import_path = node_module_bundle_import_path orelse + linker.nodeModuleBundleImportPath(origin); + + import_record.path.text = node_module_bundle_import_path.?; + import_record.module_id = node_modules_bundle.bundle.modules[found_module].id; + needs_bundle = true; + continue :outer; + } + } + } + } + } + var resolved_import_ = brk: { switch (import_record.tag) { else => {}, @@ -632,8 +666,8 @@ pub const Linker = struct { // assumption: already starts with "node:" "{s}/{s}", .{ - origin, - source_path, + strings.withoutTrailingSlash(origin.href), + strings.withoutLeadingSlash(source_path), }, )); } else { diff --git a/src/node_module_bundle.zig b/src/node_module_bundle.zig index 36de005b5..4181dd988 100644 --- a/src/node_module_bundle.zig +++ b/src/node_module_bundle.zig @@ -264,6 +264,64 @@ pub const NodeModuleBundle = struct { ) orelse return null) + package.modules_offset; } + pub fn findModuleIDInPackageIgnoringExtension( + this: *const NodeModuleBundle, + package: *const Api.JavascriptBundledPackage, + _query: string, + ) ?u32 { + const ModuleFinder = struct { + const Self = @This(); + ctx: *const NodeModuleBundle, + pkg: *const Api.JavascriptBundledPackage, + query: string, + + // Since the module doesn't necessarily exist, we use an integer overflow as the module name + pub fn moduleName(context: *const Self, module: *const Api.JavascriptBundledModule) string { + return if (module.path.offset == context.ctx.bundle.manifest_string.len) context.query else context.ctx.str(.{ + .offset = module.path.offset, + .length = module.path.length - @as(u32, module.path_extname_length), + }); + } + + pub fn cmpAsc(context: Self, lhs: Api.JavascriptBundledModule, rhs: Api.JavascriptBundledModule) std.math.Order { + // Comapre the module name + const lhs_name = context.moduleName(&lhs); + const rhs_name = context.moduleName(&rhs); + + const traversal_length = std.math.min(lhs_name.len, rhs_name.len); + + for (lhs_name[0..traversal_length]) |char, i| { + switch (std.math.order(char, rhs_name[i])) { + .lt, .gt => |order| { + return order; + }, + .eq => {}, + } + } + + return std.math.order(lhs_name.len, rhs_name.len); + } + }; + var to_find = Api.JavascriptBundledModule{ + .package_id = 0, + .code = .{}, + .path = .{ + .offset = @truncate(u32, this.bundle.manifest_string.len), + }, + }; + + var finder = ModuleFinder{ .ctx = this, .pkg = package, .query = _query[0 .. _query.len - std.fs.path.extension(_query).len] }; + + const modules = modulesIn(&this.bundle, package); + return @intCast(u32, std.sort.binarySearch( + Api.JavascriptBundledModule, + to_find, + modules, + finder, + ModuleFinder.cmpAsc, + ) orelse return null) + package.modules_offset; + } + pub fn init(container: Api.JavascriptBundleContainer, allocator: std.mem.Allocator) NodeModuleBundle { return NodeModuleBundle{ .container = container, |