diff options
Diffstat (limited to 'src/install/npm.zig')
-rw-r--r-- | src/install/npm.zig | 124 |
1 files changed, 106 insertions, 18 deletions
diff --git a/src/install/npm.zig b/src/install/npm.zig index 9f3f2952c..4cf1c2b71 100644 --- a/src/install/npm.zig +++ b/src/install/npm.zig @@ -68,8 +68,20 @@ pub const Registry = struct { pub fn fromAPI(name: string, registry_: Api.NpmRegistry, allocator: std.mem.Allocator, env: *DotEnv.Loader) !Scope { var registry = registry_; + + // Support $ENV_VAR for registry URLs + if (strings.startsWithChar(registry_.url, '$')) { + // If it became "$ENV_VAR/", then we need to remove the trailing slash + if (env.get(strings.trim(registry_.url[1..], "/"))) |replaced_url| { + if (replaced_url.len > 1) { + registry.url = replaced_url; + } + } + } + var url = URL.parse(registry.url); var auth: string = ""; + var needs_normalize = false; if (registry.token.len == 0) { outer: { @@ -79,10 +91,12 @@ pub const Registry = struct { url.pathname = pathname; url.path = pathname; } - + var needs_to_check_slash = true; while (strings.lastIndexOfChar(pathname, ':')) |colon| { var segment = pathname[colon + 1 ..]; pathname = pathname[0..colon]; + needs_to_check_slash = false; + needs_normalize = true; if (pathname.len > 1 and pathname[pathname.len - 1] == '/') { pathname = pathname[0 .. pathname.len - 1]; } @@ -113,6 +127,47 @@ pub const Registry = struct { continue; } } + + // In this case, there is only one. + if (needs_to_check_slash) { + if (strings.lastIndexOfChar(pathname, '/')) |last_slash| { + var remain = pathname[last_slash + 1 ..]; + if (strings.indexOfChar(remain, '=')) |eql_i| { + const segment = remain[0..eql_i]; + var value = remain[eql_i + 1 ..]; + + // https://github.com/yarnpkg/yarn/blob/6db39cf0ff684ce4e7de29669046afb8103fce3d/src/registries/npm-registry.js#L364 + // Bearer Token + if (strings.eqlComptime(segment, "_authToken")) { + registry.token = value; + pathname = pathname[0 .. last_slash + 1]; + needs_normalize = true; + break :outer; + } + + if (strings.eqlComptime(segment, "_auth")) { + auth = value; + pathname = pathname[0 .. last_slash + 1]; + needs_normalize = true; + break :outer; + } + + if (strings.eqlComptime(segment, "username")) { + registry.username = value; + pathname = pathname[0 .. last_slash + 1]; + needs_normalize = true; + break :outer; + } + + if (strings.eqlComptime(segment, "_password")) { + registry.password = value; + pathname = pathname[0 .. last_slash + 1]; + needs_normalize = true; + break :outer; + } + } + } + } } registry.username = env.getAuto(registry.username); @@ -133,6 +188,16 @@ pub const Registry = struct { registry.token = env.getAuto(registry.token); + if (needs_normalize) { + url = URL.parse( + try std.fmt.allocPrint(allocator, "{s}://{}/{s}/", .{ + url.displayProtocol(), + url.displayHost(), + strings.trim(url.pathname, "/"), + }), + ); + } + return Scope{ .name = name, .url = url, .token = registry.token, .auth = auth }; } }; @@ -262,12 +327,18 @@ pub const OperatingSystem = enum(u16) { return (@intFromEnum(this) & linux) != 0; } else if (comptime Environment.isMac) { return (@intFromEnum(this) & darwin) != 0; + } else if (comptime Environment.isWindows) { + return (@intFromEnum(this) & win32) != 0; } else { return false; } } - const NameMap = ComptimeStringMap(u16, .{ + pub inline fn has(this: OperatingSystem, other: u16) bool { + return (@intFromEnum(this) & other) != 0; + } + + pub const NameMap = ComptimeStringMap(u16, .{ .{ "aix", aix }, .{ "darwin", darwin }, .{ "freebsd", freebsd }, @@ -318,7 +389,7 @@ pub const Architecture = enum(u16) { pub const all_value: u16 = arm | arm64 | ia32 | mips | mipsel | ppc | ppc64 | s390 | s390x | x32 | x64; - const NameMap = ComptimeStringMap(u16, .{ + pub const NameMap = ComptimeStringMap(u16, .{ .{ "arm", arm }, .{ "arm64", arm64 }, .{ "ia32", ia32 }, @@ -332,6 +403,10 @@ pub const Architecture = enum(u16) { .{ "x64", x64 }, }); + pub inline fn has(this: Architecture, other: u16) bool { + return (@intFromEnum(this) & other) != 0; + } + pub fn isMatch(this: Architecture) bool { if (comptime Environment.isAarch64) { return (@intFromEnum(this) & arm64) != 0; @@ -733,29 +808,39 @@ pub const PackageManifest = struct { return this.findByVersion(left.version); } - const releases = this.pkg.releases.keys.get(this.versions); + if (this.findByDistTag("latest")) |result| { + if (group.satisfies(result.version)) { + if (group.flags.isSet(Semver.Query.Group.Flags.pre)) { + if (left.version.order(result.version, this.string_buf, this.string_buf) == .eq) { + // if prerelease, use latest if semver+tag match range exactly + return result; + } + } else { + return result; + } + } + } - if (group.flags.isSet(Semver.Query.Group.Flags.pre)) { - const prereleases = this.pkg.prereleases.keys.get(this.versions); - var i = prereleases.len; + { + const releases = this.pkg.releases.keys.get(this.versions); + var i = releases.len; + // For now, this is the dumb way while (i > 0) : (i -= 1) { - const version = prereleases[i - 1]; - const packages = this.pkg.prereleases.values.get(this.package_versions); + const version = releases[i - 1]; + const packages = this.pkg.releases.values.get(this.package_versions); if (group.satisfies(version)) { return .{ .version = version, .package = &packages[i - 1] }; } } - } else if (this.findByDistTag("latest")) |result| { - if (group.satisfies(result.version)) return result; } - { - var i = releases.len; - // // For now, this is the dumb way + if (group.flags.isSet(Semver.Query.Group.Flags.pre)) { + const prereleases = this.pkg.prereleases.keys.get(this.versions); + var i = prereleases.len; while (i > 0) : (i -= 1) { - const version = releases[i - 1]; - const packages = this.pkg.releases.values.get(this.package_versions); + const version = prereleases[i - 1]; + const packages = this.pkg.prereleases.values.get(this.package_versions); if (group.satisfies(version)) { return .{ .version = version, .package = &packages[i - 1] }; @@ -796,7 +881,7 @@ pub const PackageManifest = struct { } } - var result = PackageManifest{}; + var result: PackageManifest = bun.serializable(PackageManifest{}); var string_pool = String.Builder.StringPool.init(default_allocator); defer string_pool.deinit(); @@ -1029,6 +1114,9 @@ pub const PackageManifest = struct { var dependency_values = version_extern_strings; var dependency_names = all_dependency_names_and_values; var prev_extern_bin_group = extern_strings_bin_entries; + const empty_version = bun.serializable(PackageVersion{ + .bin = Bin.init(), + }); for (versions) |prop| { const version_name = prop.key.?.asString(allocator) orelse continue; @@ -1048,7 +1136,7 @@ pub const PackageManifest = struct { } if (!parsed_version.valid) continue; - var package_version = PackageVersion{}; + var package_version: PackageVersion = empty_version; if (prop.value.?.asProperty("cpu")) |cpu| { package_version.cpu = Architecture.all; |