mirror of
https://github.com/oven-sh/bun
synced 2026-02-11 03:18:53 +00:00
Fixes ENG-21287
Build times, from `bun run build && echo '//' >> src/main.zig && time
bun run build`
|Platform|0.14.1|0.15.2|Speedup|
|-|-|-|-|
|macos debug asan|126.90s|106.27s|1.19x|
|macos debug noasan|60.62s|50.85s|1.19x|
|linux debug asan|292.77s|241.45s|1.21x|
|linux debug noasan|146.58s|130.94s|1.12x|
|linux debug use_llvm=false|n/a|78.27s|1.87x|
|windows debug asan|177.13s|142.55s|1.24x|
Runtime performance:
- next build memory usage may have gone up by 5%. Otherwise seems the
same. Some code with writers may have gotten slower, especially one
instance of a counting writer and a few instances of unbuffered writers
that now have vtable overhead.
- File size reduced by 800kb (from 100.2mb to 99.4mb)
Improvements:
- `@export` hack is no longer needed for watch
- native x86_64 backend for linux builds faster. to use it, set use_llvm
false and no_link_obj false. also set `ASAN_OPTIONS=detect_leaks=0`
otherwise it will spam the output with tens of thousands of lines of
debug info errors. may need to use the zig lldb fork for debugging.
- zig test-obj, which we will be able to use for zig unit tests
Still an issue:
- false 'dependency loop' errors remain in watch mode
- watch mode crashes observed
Follow-up:
- [ ] search `comptime Writer: type` and `comptime W: type` and remove
- [ ] remove format_mode in our zig fork
- [ ] remove deprecated.zig autoFormatLabelFallback
- [ ] remove deprecated.zig autoFormatLabel
- [ ] remove deprecated.BufferedWriter and BufferedReader
- [ ] remove override_no_export_cpp_apis as it is no longer needed
- [ ] css Parser(W) -> Parser, and remove all the comptime writer: type
params
- [ ] remove deprecated writer fully
Files that add lines:
```
649 src/deprecated.zig
167 scripts/pack-codegen-for-zig-team.ts
54 scripts/cleartrace-impl.js
46 scripts/cleartrace.ts
43 src/windows.zig
18 src/fs.zig
17 src/bun.js/ConsoleObject.zig
16 src/output.zig
12 src/bun.js/test/debug.zig
12 src/bun.js/node/node_fs.zig
8 src/env_loader.zig
7 src/css/printer.zig
7 src/cli/init_command.zig
7 src/bun.js/node.zig
6 src/string/escapeRegExp.zig
6 src/install/PnpmMatcher.zig
5 src/bun.js/webcore/Blob.zig
4 src/crash_handler.zig
4 src/bun.zig
3 src/install/lockfile/bun.lock.zig
3 src/cli/update_interactive_command.zig
3 src/cli/pack_command.zig
3 build.zig
2 src/Progress.zig
2 src/install/lockfile/lockfile_json_stringify_for_debugging.zig
2 src/css/small_list.zig
2 src/bun.js/webcore/prompt.zig
1 test/internal/ban-words.test.ts
1 test/internal/ban-limits.json
1 src/watcher/WatcherTrace.zig
1 src/transpiler.zig
1 src/shell/builtin/cp.zig
1 src/js_printer.zig
1 src/io/PipeReader.zig
1 src/install/bin.zig
1 src/css/selectors/selector.zig
1 src/cli/run_command.zig
1 src/bun.js/RuntimeTranspilerStore.zig
1 src/bun.js/bindings/JSRef.zig
1 src/bake/DevServer.zig
```
Files that remove lines:
```
-1 src/test/recover.zig
-1 src/sql/postgres/SocketMonitor.zig
-1 src/sql/mysql/MySQLRequestQueue.zig
-1 src/sourcemap/CodeCoverage.zig
-1 src/css/values/color_js.zig
-1 src/compile_target.zig
-1 src/bundler/linker_context/convertStmtsForChunk.zig
-1 src/bundler/bundle_v2.zig
-1 src/bun.js/webcore/blob/read_file.zig
-1 src/ast/base.zig
-2 src/sql/postgres/protocol/ArrayList.zig
-2 src/shell/builtin/mkdir.zig
-2 src/install/PackageManager/patchPackage.zig
-2 src/install/PackageManager/PackageManagerDirectories.zig
-2 src/fmt.zig
-2 src/css/declaration.zig
-2 src/css/css_parser.zig
-2 src/collections/baby_list.zig
-2 src/bun.js/bindings/ZigStackFrame.zig
-2 src/ast/E.zig
-3 src/StandaloneModuleGraph.zig
-3 src/deps/picohttp.zig
-3 src/deps/libuv.zig
-3 src/btjs.zig
-4 src/threading/Futex.zig
-4 src/shell/builtin/touch.zig
-4 src/meta.zig
-4 src/install/lockfile.zig
-4 src/css/selectors/parser.zig
-5 src/shell/interpreter.zig
-5 src/css/error.zig
-5 src/bun.js/web_worker.zig
-5 src/bun.js.zig
-6 src/cli/test_command.zig
-6 src/bun.js/VirtualMachine.zig
-6 src/bun.js/uuid.zig
-6 src/bun.js/bindings/JSValue.zig
-9 src/bun.js/test/pretty_format.zig
-9 src/bun.js/api/BunObject.zig
-14 src/install/install_binding.zig
-14 src/fd.zig
-14 src/bun.js/node/path.zig
-14 scripts/pack-codegen-for-zig-team.sh
-17 src/bun.js/test/diff_format.zig
```
`git diff --numstat origin/main...HEAD | awk '{ print ($1-$2)"\t"$3 }' |
sort -rn`
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Dylan Conway <dylan.conway567@gmail.com>
Co-authored-by: Meghan Denny <meghan@bun.com>
Co-authored-by: tayor.fish <contact@taylor.fish>
1720 lines
70 KiB
Zig
1720 lines
70 KiB
Zig
pub const YarnLock = struct {
|
|
const Entry = struct {
|
|
specs: []const []const u8,
|
|
version: string,
|
|
resolved: ?string = null,
|
|
integrity: ?string = null,
|
|
dependencies: ?bun.StringHashMap(string) = null,
|
|
optionalDependencies: ?bun.StringHashMap(string) = null,
|
|
peerDependencies: ?bun.StringHashMap(string) = null,
|
|
devDependencies: ?bun.StringHashMap(string) = null,
|
|
commit: ?string = null,
|
|
workspace: bool = false,
|
|
file: ?string = null,
|
|
os: ?[]const []const u8 = null,
|
|
cpu: ?[]const []const u8 = null,
|
|
git_repo_name: ?string = null,
|
|
|
|
pub fn deinit(self: *Entry, allocator: Allocator) void {
|
|
allocator.free(self.specs);
|
|
if (self.dependencies) |*deps| {
|
|
deps.deinit();
|
|
}
|
|
if (self.optionalDependencies) |*deps| {
|
|
deps.deinit();
|
|
}
|
|
if (self.peerDependencies) |*deps| {
|
|
deps.deinit();
|
|
}
|
|
if (self.devDependencies) |*deps| {
|
|
deps.deinit();
|
|
}
|
|
if (self.os) |os_list| {
|
|
allocator.free(os_list);
|
|
}
|
|
if (self.cpu) |cpu_list| {
|
|
allocator.free(cpu_list);
|
|
}
|
|
if (self.git_repo_name) |name| {
|
|
allocator.free(name);
|
|
}
|
|
}
|
|
|
|
pub fn getNameFromSpec(spec: []const u8) []const u8 {
|
|
const unquoted = if (spec[0] == '"' and spec[spec.len - 1] == '"')
|
|
spec[1 .. spec.len - 1]
|
|
else
|
|
spec;
|
|
|
|
if (unquoted[0] == '@') {
|
|
if (strings.indexOf(unquoted[1..], "@")) |second_at| {
|
|
const end_idx = second_at + 1;
|
|
return unquoted[0..end_idx];
|
|
}
|
|
return unquoted;
|
|
}
|
|
|
|
if (strings.indexOf(unquoted, "@npm:")) |npm_idx| {
|
|
return unquoted[0..npm_idx];
|
|
} else if (strings.indexOf(unquoted, "@https://")) |url_idx| {
|
|
return unquoted[0..url_idx];
|
|
} else if (strings.indexOf(unquoted, "@git+")) |git_idx| {
|
|
return unquoted[0..git_idx];
|
|
} else if (strings.indexOf(unquoted, "@github:")) |gh_idx| {
|
|
return unquoted[0..gh_idx];
|
|
} else if (strings.indexOf(unquoted, "@file:")) |file_idx| {
|
|
return unquoted[0..file_idx];
|
|
} else if (strings.indexOf(unquoted, "@")) |idx| {
|
|
return unquoted[0..idx];
|
|
}
|
|
return unquoted;
|
|
}
|
|
|
|
pub fn getVersionFromSpec(spec: []const u8) ?[]const u8 {
|
|
const unquoted = if (spec[0] == '"' and spec[spec.len - 1] == '"')
|
|
spec[1 .. spec.len - 1]
|
|
else
|
|
spec;
|
|
|
|
if (unquoted[0] == '@') {
|
|
if (strings.indexOfChar(unquoted[1..], '@')) |second_at_pos| {
|
|
const version_start = second_at_pos + "@".len + 1;
|
|
const version_part = unquoted[version_start..];
|
|
|
|
if (strings.hasPrefixComptime(version_part, "npm:") and version_part.len > 4) {
|
|
return version_part["npm:".len..];
|
|
}
|
|
return version_part;
|
|
}
|
|
return null;
|
|
} else if (strings.indexOf(unquoted, "@npm:")) |npm_idx| {
|
|
const after_npm = npm_idx + "npm:".len + 1;
|
|
if (after_npm < unquoted.len) {
|
|
return unquoted[after_npm..];
|
|
}
|
|
return null;
|
|
} else if (strings.indexOf(unquoted, "@https://")) |url_idx| {
|
|
const after_at = url_idx + '@'.len;
|
|
if (after_at < unquoted.len) {
|
|
return unquoted[after_at..];
|
|
}
|
|
return null;
|
|
} else if (strings.indexOf(unquoted, "@git+")) |git_idx| {
|
|
const after_at = git_idx + '@'.len;
|
|
if (after_at < unquoted.len) {
|
|
return unquoted[after_at..];
|
|
}
|
|
return null;
|
|
} else if (strings.indexOf(unquoted, "@github:")) |gh_idx| {
|
|
const after_at = gh_idx + '@'.len;
|
|
if (after_at < unquoted.len) {
|
|
return unquoted[after_at..];
|
|
}
|
|
return null;
|
|
} else if (strings.indexOf(unquoted, "@file:")) |file_idx| {
|
|
const after_at = file_idx + '@'.len;
|
|
if (after_at < unquoted.len) {
|
|
return unquoted[after_at..];
|
|
}
|
|
return null;
|
|
} else if (strings.indexOf(unquoted, "@")) |idx| {
|
|
const after_at = idx + '@'.len;
|
|
if (after_at < unquoted.len) {
|
|
return unquoted[after_at..];
|
|
}
|
|
return null;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
pub fn isGitDependency(version: []const u8) bool {
|
|
return strings.hasPrefixComptime(version, "git+") or
|
|
strings.hasPrefixComptime(version, "git://") or
|
|
strings.hasPrefixComptime(version, "github:") or
|
|
strings.hasPrefixComptime(version, "https://github.com/");
|
|
}
|
|
|
|
pub fn isNpmAlias(version: []const u8) bool {
|
|
return strings.hasPrefixComptime(version, "npm:");
|
|
}
|
|
|
|
pub fn isRemoteTarball(version: []const u8) bool {
|
|
return strings.hasPrefixComptime(version, "https://") and strings.endsWithComptime(version, ".tgz");
|
|
}
|
|
|
|
pub fn isWorkspaceDependency(version: []const u8) bool {
|
|
return strings.hasPrefixComptime(version, "workspace:") or
|
|
strings.eqlComptime(version, "*");
|
|
}
|
|
|
|
pub fn isFileDependency(version: []const u8) bool {
|
|
return strings.hasPrefixComptime(version, "file:") or
|
|
strings.hasPrefixComptime(version, "./") or
|
|
strings.hasPrefixComptime(version, "../");
|
|
}
|
|
|
|
pub fn parseGitUrl(self: *const YarnLock, version: []const u8) !struct { url: []const u8, commit: ?[]const u8, owner: ?[]const u8, repo: ?[]const u8 } {
|
|
var url = version;
|
|
var commit: ?[]const u8 = null;
|
|
var owner: ?[]const u8 = null;
|
|
var repo: ?[]const u8 = null;
|
|
|
|
if (strings.hasPrefixComptime(url, "git+")) {
|
|
url = url[4..];
|
|
}
|
|
|
|
if (strings.indexOf(url, "#")) |hash_idx| {
|
|
commit = url[hash_idx + 1 ..];
|
|
url = url[0..hash_idx];
|
|
}
|
|
|
|
if (strings.hasPrefixComptime(version, "github:")) {
|
|
const github_path = version["github:".len..];
|
|
const path_without_commit = if (strings.indexOf(github_path, "#")) |idx| github_path[0..idx] else github_path;
|
|
|
|
if (strings.indexOf(path_without_commit, "/")) |slash_idx| {
|
|
owner = path_without_commit[0..slash_idx];
|
|
repo = path_without_commit[slash_idx + 1 ..];
|
|
}
|
|
url = try std.fmt.allocPrint(
|
|
self.allocator,
|
|
"https://github.com/{s}",
|
|
.{path_without_commit},
|
|
);
|
|
} else if (strings.contains(url, "github.com")) {
|
|
var remaining = url;
|
|
if (strings.indexOf(remaining, "github.com/")) |idx| {
|
|
remaining = remaining[idx + "github.com/".len ..];
|
|
}
|
|
if (strings.indexOf(remaining, "/")) |slash_idx| {
|
|
owner = remaining[0..slash_idx];
|
|
const after_owner = remaining[slash_idx + 1 ..];
|
|
if (strings.endsWithComptime(after_owner, ".git")) {
|
|
repo = after_owner[0 .. after_owner.len - ".git".len];
|
|
} else {
|
|
repo = after_owner;
|
|
}
|
|
}
|
|
}
|
|
|
|
return .{ .url = url, .commit = commit, .owner = owner, .repo = repo };
|
|
}
|
|
|
|
pub fn parseNpmAlias(version: []const u8) struct { package: []const u8, version: []const u8 } {
|
|
if (version.len <= 4) {
|
|
return .{ .package = "", .version = "*" };
|
|
}
|
|
|
|
const npm_part = version[4..];
|
|
if (strings.indexOf(npm_part, "@")) |at_idx| {
|
|
return .{
|
|
.package = npm_part[0..at_idx],
|
|
.version = if (at_idx + 1 < npm_part.len) npm_part[at_idx + 1 ..] else "*",
|
|
};
|
|
}
|
|
return .{ .package = npm_part, .version = "*" };
|
|
}
|
|
|
|
pub fn getPackageNameFromResolvedUrl(url: []const u8) ?[]const u8 {
|
|
if (strings.indexOf(url, "/-/")) |dash_idx| {
|
|
var slash_count: usize = 0;
|
|
var last_slash: usize = 0;
|
|
var second_last_slash: usize = 0;
|
|
|
|
var i = dash_idx;
|
|
while (i > 0) : (i -= 1) {
|
|
if (url[i - 1] == '/') {
|
|
slash_count += 1;
|
|
if (slash_count == 1) {
|
|
last_slash = i - 1;
|
|
} else if (slash_count == 2) {
|
|
second_last_slash = i - 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (last_slash < dash_idx and url[last_slash + 1] == '@') {
|
|
return url[second_last_slash + 1 .. dash_idx];
|
|
} else {
|
|
return url[last_slash + 1 .. dash_idx];
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
};
|
|
|
|
entries: std.array_list.Managed(Entry),
|
|
allocator: Allocator,
|
|
|
|
pub fn init(allocator: Allocator) YarnLock {
|
|
return .{
|
|
.entries = std.array_list.Managed(Entry).init(allocator),
|
|
.allocator = allocator,
|
|
};
|
|
}
|
|
|
|
pub fn deinit(self: *YarnLock) void {
|
|
for (self.entries.items) |*entry| {
|
|
entry.deinit(self.allocator);
|
|
}
|
|
self.entries.deinit();
|
|
}
|
|
|
|
pub fn parse(self: *YarnLock, content: []const u8) !void {
|
|
var lines = strings.split(content, "\n");
|
|
var current_entry: ?Entry = null;
|
|
var current_specs = std.array_list.Managed([]const u8).init(self.allocator);
|
|
defer current_specs.deinit();
|
|
|
|
var current_deps: ?bun.StringHashMap(string) = null;
|
|
var current_optional_deps: ?bun.StringHashMap(string) = null;
|
|
var current_peer_deps: ?bun.StringHashMap(string) = null;
|
|
var current_dev_deps: ?bun.StringHashMap(string) = null;
|
|
var current_dep_type: ?DependencyType = null;
|
|
|
|
while (lines.next()) |line_| {
|
|
const line = std.mem.trimRight(u8, line_, " \r\t");
|
|
if (line.len == 0 or line[0] == '#') continue;
|
|
|
|
var indent: usize = 0;
|
|
while (indent < line.len and line[indent] == ' ') indent += 1;
|
|
|
|
const trimmed = strings.trim(line[indent..], " \r\t");
|
|
if (trimmed.len == 0) continue;
|
|
|
|
if (indent == 0 and strings.endsWithComptime(trimmed, ":")) {
|
|
if (current_entry) |*entry| {
|
|
entry.dependencies = current_deps;
|
|
entry.optionalDependencies = current_optional_deps;
|
|
entry.peerDependencies = current_peer_deps;
|
|
entry.devDependencies = current_dev_deps;
|
|
try self.consolidateAndAppendEntry(entry.*);
|
|
}
|
|
|
|
current_specs.clearRetainingCapacity();
|
|
const specs_str = trimmed[0 .. trimmed.len - 1];
|
|
var specs_it = strings.split(specs_str, ",");
|
|
while (specs_it.next()) |spec| {
|
|
const spec_trimmed = strings.trim(spec, " \"");
|
|
try current_specs.append(try self.allocator.dupe(u8, spec_trimmed));
|
|
}
|
|
|
|
current_entry = Entry{
|
|
.specs = try self.allocator.dupe([]const u8, current_specs.items),
|
|
.version = undefined,
|
|
};
|
|
|
|
for (current_specs.items) |spec| {
|
|
if (strings.indexOf(spec, "@file:")) |at_index| {
|
|
const file_path = spec[at_index + 6 ..];
|
|
current_entry.?.file = try self.allocator.dupe(u8, file_path);
|
|
break;
|
|
}
|
|
}
|
|
|
|
current_deps = null;
|
|
current_optional_deps = null;
|
|
current_peer_deps = null;
|
|
current_dev_deps = null;
|
|
current_dep_type = null;
|
|
continue;
|
|
}
|
|
|
|
if (current_entry == null) continue;
|
|
|
|
if (indent > 0) {
|
|
if (strings.eqlComptime(trimmed, "dependencies:")) {
|
|
current_dep_type = .production;
|
|
current_deps = bun.StringHashMap(string).init(self.allocator);
|
|
continue;
|
|
}
|
|
|
|
if (strings.eqlComptime(trimmed, "optionalDependencies:")) {
|
|
current_dep_type = .optional;
|
|
current_optional_deps = bun.StringHashMap(string).init(self.allocator);
|
|
continue;
|
|
}
|
|
|
|
if (strings.eqlComptime(trimmed, "peerDependencies:")) {
|
|
current_dep_type = .peer;
|
|
current_peer_deps = bun.StringHashMap(string).init(self.allocator);
|
|
continue;
|
|
}
|
|
|
|
if (strings.eqlComptime(trimmed, "devDependencies:")) {
|
|
current_dep_type = .development;
|
|
current_dev_deps = bun.StringHashMap(string).init(self.allocator);
|
|
continue;
|
|
}
|
|
|
|
if (current_dep_type) |dep_type| {
|
|
if (strings.indexOf(trimmed, " ")) |space_idx| {
|
|
const key = strings.trim(trimmed[0..space_idx], " \"");
|
|
const value = strings.trim(trimmed[space_idx + 1 ..], " \"");
|
|
const map = switch (dep_type) {
|
|
.production => ¤t_deps.?,
|
|
.optional => ¤t_optional_deps.?,
|
|
.peer => ¤t_peer_deps.?,
|
|
.development => ¤t_dev_deps.?,
|
|
};
|
|
try map.put(key, value);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (strings.indexOf(trimmed, " ")) |space_idx| {
|
|
const key = strings.trim(trimmed[0..space_idx], " ");
|
|
const value = strings.trim(trimmed[space_idx + 1 ..], " \"");
|
|
|
|
if (strings.eqlComptime(key, "version")) {
|
|
current_entry.?.version = value;
|
|
|
|
if (Entry.isWorkspaceDependency(value)) {
|
|
current_entry.?.workspace = true;
|
|
} else if (Entry.isFileDependency(value)) {
|
|
current_entry.?.file = if (strings.hasPrefixComptime(value, "file:") and value.len > "file:".len) value["file:".len..] else value;
|
|
} else if (Entry.isGitDependency(value)) {
|
|
const git_info = try Entry.parseGitUrl(self, value);
|
|
current_entry.?.resolved = git_info.url;
|
|
current_entry.?.commit = git_info.commit;
|
|
if (git_info.repo) |repo_name| {
|
|
current_entry.?.git_repo_name = try self.allocator.dupe(u8, repo_name);
|
|
}
|
|
} else if (Entry.isNpmAlias(value)) {
|
|
const alias_info = Entry.parseNpmAlias(value);
|
|
current_entry.?.version = alias_info.version;
|
|
} else if (Entry.isRemoteTarball(value)) {
|
|
current_entry.?.resolved = value;
|
|
}
|
|
} else if (strings.eqlComptime(key, "resolved")) {
|
|
current_entry.?.resolved = value;
|
|
if (Entry.isGitDependency(value)) {
|
|
const git_info = try Entry.parseGitUrl(self, value);
|
|
current_entry.?.resolved = git_info.url;
|
|
current_entry.?.commit = git_info.commit;
|
|
if (git_info.repo) |repo_name| {
|
|
current_entry.?.git_repo_name = try self.allocator.dupe(u8, repo_name);
|
|
}
|
|
}
|
|
} else if (strings.eqlComptime(key, "integrity")) {
|
|
current_entry.?.integrity = value;
|
|
} else if (strings.eqlComptime(key, "os")) {
|
|
var os_list = std.array_list.Managed([]const u8).init(self.allocator);
|
|
var os_it = strings.split(value[1 .. value.len - 1], ",");
|
|
while (os_it.next()) |os| {
|
|
const trimmed_os = strings.trim(os, " \"");
|
|
try os_list.append(trimmed_os);
|
|
}
|
|
current_entry.?.os = try os_list.toOwnedSlice();
|
|
} else if (strings.eqlComptime(key, "cpu")) {
|
|
var cpu_list = std.array_list.Managed([]const u8).init(self.allocator);
|
|
var cpu_it = strings.split(value[1 .. value.len - 1], ",");
|
|
while (cpu_it.next()) |cpu| {
|
|
const trimmed_cpu = strings.trim(cpu, " \"");
|
|
try cpu_list.append(trimmed_cpu);
|
|
}
|
|
current_entry.?.cpu = try cpu_list.toOwnedSlice();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (current_entry) |*entry| {
|
|
entry.dependencies = current_deps;
|
|
entry.optionalDependencies = current_optional_deps;
|
|
entry.peerDependencies = current_peer_deps;
|
|
entry.devDependencies = current_dev_deps;
|
|
try self.consolidateAndAppendEntry(entry.*);
|
|
}
|
|
}
|
|
|
|
fn findEntryBySpec(self: *YarnLock, spec: []const u8) ?*Entry {
|
|
for (self.entries.items) |*entry| {
|
|
for (entry.specs) |entry_spec| {
|
|
if (strings.eql(entry_spec, spec)) {
|
|
return entry;
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
fn consolidateAndAppendEntry(self: *YarnLock, new_entry: Entry) !void {
|
|
if (new_entry.specs.len == 0) return;
|
|
const package_name = Entry.getNameFromSpec(new_entry.specs[0]);
|
|
|
|
for (self.entries.items) |*existing_entry| {
|
|
if (existing_entry.specs.len == 0) continue;
|
|
const existing_name = Entry.getNameFromSpec(existing_entry.specs[0]);
|
|
|
|
if (strings.eql(package_name, existing_name) and
|
|
strings.eql(new_entry.version, existing_entry.version))
|
|
{
|
|
const old_specs = existing_entry.specs;
|
|
const combined_specs = try self.allocator.alloc([]const u8, old_specs.len + new_entry.specs.len);
|
|
@memcpy(combined_specs[0..old_specs.len], old_specs);
|
|
@memcpy(combined_specs[old_specs.len..], new_entry.specs);
|
|
|
|
self.allocator.free(old_specs);
|
|
existing_entry.specs = combined_specs;
|
|
|
|
self.allocator.free(new_entry.specs);
|
|
return;
|
|
}
|
|
}
|
|
|
|
try self.entries.append(new_entry);
|
|
}
|
|
};
|
|
|
|
const DependencyType = enum {
|
|
production,
|
|
development,
|
|
optional,
|
|
peer,
|
|
};
|
|
fn processDeps(
|
|
deps: bun.StringHashMap(string),
|
|
dep_type: DependencyType,
|
|
yarn_lock_: *YarnLock,
|
|
string_buf_: *Semver.String.Buf,
|
|
deps_buf: []Dependency,
|
|
res_buf: []Install.PackageID,
|
|
log: *logger.Log,
|
|
manager: *Install.PackageManager,
|
|
yarn_entry_to_package_id: []const Install.PackageID,
|
|
) ![]Install.PackageID {
|
|
var deps_it = deps.iterator();
|
|
var count: usize = 0;
|
|
var dep_spec_name_stack = std.heap.stackFallback(1024, bun.default_allocator);
|
|
const temp_allocator = dep_spec_name_stack.get();
|
|
|
|
while (deps_it.next()) |dep| {
|
|
const dep_name = dep.key_ptr.*;
|
|
const dep_version = dep.value_ptr.*;
|
|
const dep_spec = try std.fmt.allocPrint(
|
|
temp_allocator,
|
|
"{s}@{s}",
|
|
.{ dep_name, dep_version },
|
|
);
|
|
defer temp_allocator.free(dep_spec);
|
|
|
|
if (yarn_lock_.findEntryBySpec(dep_spec)) |dep_entry| {
|
|
const dep_name_hash = stringHash(dep_name);
|
|
const dep_name_str = try string_buf_.appendWithHash(dep_name, dep_name_hash);
|
|
|
|
const parsed_version = if (YarnLock.Entry.isNpmAlias(dep_version)) blk: {
|
|
const alias_info = YarnLock.Entry.parseNpmAlias(dep_version);
|
|
break :blk alias_info.version;
|
|
} else dep_version;
|
|
|
|
deps_buf[count] = Dependency{
|
|
.name = dep_name_str,
|
|
.name_hash = dep_name_hash,
|
|
.version = Dependency.parse(
|
|
yarn_lock_.allocator,
|
|
dep_name_str,
|
|
dep_name_hash,
|
|
parsed_version,
|
|
&Semver.SlicedString.init(parsed_version, parsed_version),
|
|
log,
|
|
manager,
|
|
) orelse Dependency.Version{},
|
|
.behavior = .{
|
|
.prod = dep_type == .production,
|
|
.optional = dep_type == .optional,
|
|
.dev = dep_type == .development,
|
|
.peer = dep_type == .peer,
|
|
.workspace = dep_entry.workspace,
|
|
},
|
|
};
|
|
var found_package_id: ?Install.PackageID = null;
|
|
outer: for (yarn_lock_.entries.items, 0..) |entry_, yarn_idx| {
|
|
for (entry_.specs) |entry_spec| {
|
|
if (strings.eql(entry_spec, dep_spec)) {
|
|
found_package_id = yarn_entry_to_package_id[yarn_idx];
|
|
break :outer;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (found_package_id) |pkg_id| {
|
|
res_buf[count] = pkg_id;
|
|
count += 1;
|
|
}
|
|
}
|
|
}
|
|
return res_buf[0..count];
|
|
}
|
|
|
|
pub fn migrateYarnLockfile(
|
|
this: *Lockfile,
|
|
manager: *Install.PackageManager,
|
|
allocator: Allocator,
|
|
log: *logger.Log,
|
|
data: string,
|
|
dir: bun.FD,
|
|
) !LoadResult {
|
|
// todo yarn v2+ support
|
|
if (!strings.containsComptime(data, "# yarn lockfile v1")) {
|
|
return error.UnsupportedYarnLockfileVersion;
|
|
}
|
|
|
|
var yarn_lock = YarnLock.init(allocator);
|
|
defer yarn_lock.deinit();
|
|
|
|
try yarn_lock.parse(data);
|
|
|
|
this.initEmpty(allocator);
|
|
Install.initializeStore();
|
|
bun.analytics.Features.yarn_migration += 1;
|
|
|
|
var string_buf = this.stringBuf();
|
|
|
|
var num_deps: u32 = 0;
|
|
var root_dep_count: u32 = 0;
|
|
var root_dep_count_from_package_json: u32 = 0;
|
|
|
|
var root_dependencies = std.array_list.Managed(struct { name: []const u8, version: []const u8, dep_type: DependencyType }).init(allocator);
|
|
defer {
|
|
for (root_dependencies.items) |dep| {
|
|
allocator.free(dep.name);
|
|
allocator.free(dep.version);
|
|
}
|
|
root_dependencies.deinit();
|
|
}
|
|
|
|
{
|
|
// read package.json to get specified dependencies
|
|
const package_json_fd = bun.sys.File.openat(dir, "package.json", bun.O.RDONLY, 0).unwrap() catch return error.InvalidPackageJSON;
|
|
defer package_json_fd.close();
|
|
const package_json_contents = package_json_fd.readToEnd(allocator).unwrap() catch return error.InvalidPackageJSON;
|
|
defer allocator.free(package_json_contents);
|
|
|
|
const package_json_source = brk: {
|
|
var package_json_path_buf: bun.PathBuffer = undefined;
|
|
const package_json_path = bun.getFdPath(package_json_fd.handle, &package_json_path_buf) catch return error.InvalidPackageJSON;
|
|
break :brk logger.Source.initPathString(package_json_path, package_json_contents);
|
|
};
|
|
const package_json_expr = JSON.parsePackageJSONUTF8WithOpts(
|
|
&package_json_source,
|
|
log,
|
|
allocator,
|
|
.{
|
|
.is_json = true,
|
|
.allow_comments = true,
|
|
.allow_trailing_commas = true,
|
|
.guess_indentation = true,
|
|
},
|
|
) catch return error.InvalidPackageJSON;
|
|
|
|
const package_json = package_json_expr.root;
|
|
|
|
const package_name: ?[]const u8 = blk: {
|
|
if (package_json.asProperty("name")) |name_prop| {
|
|
if (name_prop.expr.data == .e_string) {
|
|
const name_slice = name_prop.expr.data.e_string.string(allocator) catch "";
|
|
if (name_slice.len > 0) {
|
|
break :blk try allocator.dupe(u8, name_slice);
|
|
}
|
|
}
|
|
}
|
|
break :blk null;
|
|
};
|
|
defer if (package_name) |name| allocator.free(name);
|
|
const package_name_hash = if (package_name) |name| String.Builder.stringHash(name) else 0;
|
|
|
|
const sections = [_]struct { key: []const u8, dep_type: DependencyType }{
|
|
.{ .key = "dependencies", .dep_type = .production },
|
|
.{ .key = "devDependencies", .dep_type = .development },
|
|
.{ .key = "optionalDependencies", .dep_type = .optional },
|
|
.{ .key = "peerDependencies", .dep_type = .peer },
|
|
};
|
|
for (sections) |section_info| {
|
|
const prop = package_json.asProperty(section_info.key) orelse continue;
|
|
if (prop.expr.data != .e_object) continue;
|
|
|
|
for (prop.expr.data.e_object.properties.slice()) |p| {
|
|
const key = p.key orelse continue;
|
|
if (key.data != .e_string) continue;
|
|
|
|
const name_slice = key.data.e_string.string(allocator) catch continue;
|
|
const value = p.value orelse continue;
|
|
if (value.data != .e_string) continue;
|
|
|
|
const version_slice = value.data.e_string.string(allocator) catch continue;
|
|
if (version_slice.len == 0) continue;
|
|
|
|
const name = try allocator.dupe(u8, name_slice);
|
|
const version = try allocator.dupe(u8, version_slice);
|
|
try root_dependencies.append(.{
|
|
.name = name,
|
|
.version = version,
|
|
.dep_type = section_info.dep_type,
|
|
});
|
|
root_dep_count_from_package_json += 1;
|
|
}
|
|
}
|
|
|
|
root_dep_count = @max(root_dep_count_from_package_json, 10);
|
|
num_deps += root_dep_count;
|
|
|
|
for (yarn_lock.entries.items) |entry| {
|
|
if (entry.dependencies) |deps| {
|
|
num_deps += @intCast(deps.count());
|
|
}
|
|
if (entry.optionalDependencies) |deps| {
|
|
num_deps += @intCast(deps.count());
|
|
}
|
|
if (entry.peerDependencies) |deps| {
|
|
num_deps += @intCast(deps.count());
|
|
}
|
|
if (entry.devDependencies) |deps| {
|
|
num_deps += @intCast(deps.count());
|
|
}
|
|
}
|
|
|
|
const num_packages = @as(u32, @intCast(yarn_lock.entries.items.len + 1));
|
|
|
|
try this.buffers.dependencies.ensureTotalCapacity(allocator, num_deps);
|
|
try this.buffers.resolutions.ensureTotalCapacity(allocator, num_deps);
|
|
try this.packages.ensureTotalCapacity(allocator, num_packages);
|
|
try this.package_index.ensureTotalCapacity(num_packages);
|
|
|
|
const root_name = if (package_name) |name| try string_buf.appendWithHash(name, package_name_hash) else try string_buf.append("");
|
|
|
|
try this.packages.append(allocator, Lockfile.Package{
|
|
.name = root_name,
|
|
.name_hash = package_name_hash,
|
|
.resolution = Resolution.init(.{ .root = {} }),
|
|
.dependencies = .{},
|
|
.resolutions = .{},
|
|
.meta = .{
|
|
.id = 0,
|
|
.origin = .local,
|
|
.arch = .all,
|
|
.os = .all,
|
|
.man_dir = String{},
|
|
.has_install_script = .false,
|
|
.integrity = Integrity{},
|
|
},
|
|
.bin = Bin.init(),
|
|
.scripts = .{},
|
|
});
|
|
|
|
if (package_json.asProperty("resolutions")) |resolutions| {
|
|
var root_package = this.packages.get(0);
|
|
var string_builder = this.stringBuilder();
|
|
|
|
if (resolutions.expr.data == .e_object) {
|
|
string_builder.cap += resolutions.expr.data.e_object.properties.len * 128;
|
|
}
|
|
if (string_builder.cap > 0) {
|
|
try string_builder.allocate();
|
|
}
|
|
try this.overrides.parseAppend(manager, this, &root_package, log, &package_json_source, package_json, &string_builder);
|
|
this.packages.set(0, root_package);
|
|
}
|
|
}
|
|
|
|
var dependencies_buf = this.buffers.dependencies.items.ptr[0..num_deps];
|
|
var resolutions_buf = this.buffers.resolutions.items.ptr[0..num_deps];
|
|
|
|
var yarn_entry_to_package_id = try allocator.alloc(Install.PackageID, yarn_lock.entries.items.len);
|
|
defer allocator.free(yarn_entry_to_package_id);
|
|
|
|
const VersionInfo = struct {
|
|
version: string,
|
|
package_id: Install.PackageID,
|
|
yarn_idx: usize,
|
|
};
|
|
|
|
var package_versions = bun.StringHashMap(VersionInfo).init(allocator);
|
|
defer package_versions.deinit();
|
|
|
|
var scoped_packages = bun.StringHashMap(std.array_list.Managed(VersionInfo)).init(allocator);
|
|
defer {
|
|
var it = scoped_packages.iterator();
|
|
while (it.next()) |entry| {
|
|
entry.value_ptr.deinit();
|
|
}
|
|
scoped_packages.deinit();
|
|
}
|
|
|
|
var next_package_id: Install.PackageID = 1; // 0 is root
|
|
|
|
for (yarn_lock.entries.items, 0..) |entry, yarn_idx| {
|
|
var is_npm_alias = false;
|
|
var is_direct_url = false;
|
|
for (entry.specs) |spec| {
|
|
if (strings.contains(spec, "@npm:")) {
|
|
is_npm_alias = true;
|
|
break;
|
|
}
|
|
if (strings.contains(spec, "@https://") or strings.contains(spec, "@http://")) {
|
|
is_direct_url = true;
|
|
}
|
|
}
|
|
|
|
const name = if (is_npm_alias and entry.resolved != null)
|
|
YarnLock.Entry.getPackageNameFromResolvedUrl(entry.resolved.?) orelse YarnLock.Entry.getNameFromSpec(entry.specs[0])
|
|
else if (is_direct_url)
|
|
YarnLock.Entry.getNameFromSpec(entry.specs[0])
|
|
else if (entry.git_repo_name) |repo_name|
|
|
repo_name
|
|
else
|
|
YarnLock.Entry.getNameFromSpec(entry.specs[0]);
|
|
const version = entry.version;
|
|
|
|
if (package_versions.get(name)) |existing| {
|
|
if (!strings.eql(existing.version, version)) {
|
|
var list = scoped_packages.get(name) orelse std.array_list.Managed(VersionInfo).init(allocator);
|
|
|
|
var found_existing = false;
|
|
var found_new = false;
|
|
for (list.items) |item| {
|
|
if (strings.eql(item.version, existing.version)) found_existing = true;
|
|
if (strings.eql(item.version, version)) found_new = true;
|
|
}
|
|
|
|
if (!found_existing) {
|
|
try list.append(.{
|
|
.yarn_idx = existing.yarn_idx,
|
|
.version = existing.version,
|
|
.package_id = existing.package_id,
|
|
});
|
|
}
|
|
|
|
if (!found_new) {
|
|
const package_id = next_package_id;
|
|
next_package_id += 1;
|
|
try list.append(.{
|
|
.yarn_idx = yarn_idx,
|
|
.version = version,
|
|
.package_id = package_id,
|
|
});
|
|
yarn_entry_to_package_id[yarn_idx] = package_id;
|
|
} else {
|
|
for (list.items) |item| {
|
|
if (strings.eql(item.version, version)) {
|
|
yarn_entry_to_package_id[yarn_idx] = item.package_id;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
try scoped_packages.put(name, list);
|
|
} else {
|
|
yarn_entry_to_package_id[yarn_idx] = existing.package_id;
|
|
}
|
|
} else {
|
|
const package_id = next_package_id;
|
|
next_package_id += 1;
|
|
yarn_entry_to_package_id[yarn_idx] = package_id;
|
|
try package_versions.put(name, .{
|
|
.version = version,
|
|
.package_id = package_id,
|
|
.yarn_idx = yarn_idx,
|
|
});
|
|
}
|
|
}
|
|
|
|
var package_id_to_yarn_idx = try allocator.alloc(usize, next_package_id);
|
|
defer allocator.free(package_id_to_yarn_idx);
|
|
@memset(package_id_to_yarn_idx, std.math.maxInt(usize));
|
|
|
|
var created_packages = bun.StringHashMap(bool).init(allocator);
|
|
defer created_packages.deinit();
|
|
|
|
for (yarn_lock.entries.items, 0..) |entry, yarn_idx| {
|
|
var is_npm_alias = false;
|
|
for (entry.specs) |spec| {
|
|
if (strings.contains(spec, "@npm:")) {
|
|
is_npm_alias = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
var is_direct_url_dep = false;
|
|
for (entry.specs) |spec| {
|
|
if (strings.contains(spec, "@https://") or strings.contains(spec, "@http://")) {
|
|
is_direct_url_dep = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
const base_name = if (is_npm_alias and entry.resolved != null)
|
|
YarnLock.Entry.getPackageNameFromResolvedUrl(entry.resolved.?) orelse YarnLock.Entry.getNameFromSpec(entry.specs[0])
|
|
else
|
|
YarnLock.Entry.getNameFromSpec(entry.specs[0]);
|
|
const package_id = yarn_entry_to_package_id[yarn_idx];
|
|
|
|
if (package_id < package_id_to_yarn_idx.len and package_id_to_yarn_idx[package_id] != std.math.maxInt(usize)) {
|
|
continue;
|
|
}
|
|
|
|
package_id_to_yarn_idx[package_id] = yarn_idx;
|
|
|
|
const name_to_use = blk: {
|
|
if (entry.commit != null and entry.git_repo_name != null) {
|
|
break :blk entry.git_repo_name.?;
|
|
} else if (entry.resolved) |resolved| {
|
|
if (is_direct_url_dep or YarnLock.Entry.isRemoteTarball(resolved) or strings.endsWithComptime(resolved, ".tgz")) {
|
|
// https://registry.npmjs.org/package/-/package-version.tgz
|
|
if (strings.contains(resolved, "registry.npmjs.org/") or strings.contains(resolved, "registry.yarnpkg.com/")) {
|
|
if (strings.indexOf(resolved, "/-/")) |separator_idx| {
|
|
if (strings.indexOf(resolved, "registry.")) |registry_idx| {
|
|
const after_registry = resolved[registry_idx..];
|
|
if (strings.indexOf(after_registry, "/")) |domain_slash| {
|
|
const package_start = registry_idx + domain_slash + 1;
|
|
const extracted_name = resolved[package_start..separator_idx];
|
|
break :blk extracted_name;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break :blk base_name;
|
|
}
|
|
}
|
|
break :blk base_name;
|
|
};
|
|
|
|
const name_hash = stringHash(name_to_use);
|
|
|
|
try this.packages.append(allocator, Lockfile.Package{
|
|
.name = try string_buf.appendWithHash(name_to_use, name_hash),
|
|
.name_hash = name_hash,
|
|
.resolution = blk: {
|
|
if (entry.workspace) {
|
|
break :blk Resolution.init(.{ .workspace = try string_buf.append(base_name) });
|
|
} else if (entry.file) |file| {
|
|
if (strings.endsWithComptime(file, ".tgz") or strings.endsWithComptime(file, ".tar.gz")) {
|
|
break :blk Resolution.init(.{ .local_tarball = try string_buf.append(file) });
|
|
} else {
|
|
break :blk Resolution.init(.{ .folder = try string_buf.append(file) });
|
|
}
|
|
} else if (entry.commit) |commit| {
|
|
if (entry.resolved) |resolved| {
|
|
var owner_str: []const u8 = "";
|
|
var repo_str: []const u8 = resolved;
|
|
|
|
if (strings.contains(resolved, "github.com/")) {
|
|
if (strings.indexOf(resolved, "github.com/")) |idx| {
|
|
const after_github = resolved[idx + "github.com/".len ..];
|
|
if (strings.indexOf(after_github, "/")) |slash_idx| {
|
|
owner_str = after_github[0..slash_idx];
|
|
repo_str = after_github[slash_idx + 1 ..];
|
|
if (strings.endsWithComptime(repo_str, ".git")) {
|
|
repo_str = repo_str[0 .. repo_str.len - 4];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const actual_name = if (entry.git_repo_name) |repo_name| repo_name else repo_str;
|
|
|
|
if (owner_str.len > 0 and repo_str.len > 0) {
|
|
break :blk Resolution.init(.{
|
|
.github = .{
|
|
.owner = try string_buf.append(owner_str),
|
|
.repo = try string_buf.append(repo_str),
|
|
.committish = try string_buf.append(commit[0..@min("github:".len, commit.len)]),
|
|
.resolved = String{},
|
|
.package_name = try string_buf.append(actual_name),
|
|
},
|
|
});
|
|
} else {
|
|
break :blk Resolution.init(.{
|
|
.git = .{
|
|
.owner = try string_buf.append(owner_str),
|
|
.repo = try string_buf.append(repo_str),
|
|
.committish = try string_buf.append(commit),
|
|
.resolved = String{},
|
|
.package_name = try string_buf.append(actual_name),
|
|
},
|
|
});
|
|
}
|
|
}
|
|
break :blk Resolution{};
|
|
} else if (entry.resolved) |resolved| {
|
|
if (is_direct_url_dep) {
|
|
break :blk Resolution.init(.{
|
|
.remote_tarball = try string_buf.append(resolved),
|
|
});
|
|
}
|
|
|
|
if (YarnLock.Entry.isRemoteTarball(resolved)) {
|
|
break :blk Resolution.init(.{
|
|
.remote_tarball = try string_buf.append(resolved),
|
|
});
|
|
} else if (strings.endsWithComptime(resolved, ".tgz")) {
|
|
break :blk Resolution.init(.{
|
|
.remote_tarball = try string_buf.append(resolved),
|
|
});
|
|
}
|
|
|
|
const version = try string_buf.append(entry.version);
|
|
const result = Semver.Version.parse(version.sliced(this.buffers.string_bytes.items));
|
|
if (!result.valid) {
|
|
break :blk Resolution{};
|
|
}
|
|
|
|
const is_default_registry = strings.hasPrefixComptime(resolved, "https://registry.yarnpkg.com/") or
|
|
strings.hasPrefixComptime(resolved, "https://registry.npmjs.org/");
|
|
|
|
const url = if (is_default_registry) String{} else try string_buf.append(resolved);
|
|
|
|
break :blk Resolution.init(.{
|
|
.npm = .{
|
|
.url = url,
|
|
.version = result.version.min(),
|
|
},
|
|
});
|
|
} else {
|
|
break :blk Resolution{};
|
|
}
|
|
},
|
|
.dependencies = .{},
|
|
.resolutions = .{},
|
|
.meta = .{
|
|
.id = package_id,
|
|
.origin = .npm,
|
|
.arch = if (entry.cpu) |cpu_list| arch: {
|
|
var arch = Npm.Architecture.none.negatable();
|
|
for (cpu_list) |cpu| {
|
|
arch.apply(cpu);
|
|
}
|
|
break :arch arch.combine();
|
|
} else .all,
|
|
.os = if (entry.os) |os_list| os: {
|
|
var os = Npm.OperatingSystem.none.negatable();
|
|
for (os_list) |os_str| {
|
|
os.apply(os_str);
|
|
}
|
|
break :os os.combine();
|
|
} else .all,
|
|
.man_dir = String{},
|
|
.has_install_script = .false,
|
|
.integrity = if (entry.integrity) |integrity|
|
|
Integrity.parse(integrity)
|
|
else
|
|
Integrity{},
|
|
},
|
|
.bin = Bin.init(),
|
|
.scripts = .{},
|
|
});
|
|
}
|
|
|
|
var dependencies_list = this.packages.items(.dependencies);
|
|
var resolution_list = this.packages.items(.resolutions);
|
|
|
|
var actual_root_dep_count: u32 = 0;
|
|
|
|
if (root_dependencies.items.len > 0) {
|
|
for (root_dependencies.items) |dep| {
|
|
const dep_spec = try std.fmt.allocPrint(allocator, "{s}@{s}", .{ dep.name, dep.version });
|
|
defer allocator.free(dep_spec);
|
|
|
|
var found_idx: ?usize = null;
|
|
for (yarn_lock.entries.items, 0..) |entry, idx| {
|
|
for (entry.specs) |spec| {
|
|
if (strings.eql(spec, dep_spec)) {
|
|
found_idx = idx;
|
|
break;
|
|
}
|
|
}
|
|
if (found_idx != null) break;
|
|
}
|
|
|
|
if (found_idx) |idx| {
|
|
const name_hash = stringHash(dep.name);
|
|
const dep_name_string = try string_buf.appendWithHash(dep.name, name_hash);
|
|
const version_string = try string_buf.append(dep.version);
|
|
|
|
dependencies_buf[actual_root_dep_count] = Dependency{
|
|
.name = dep_name_string,
|
|
.name_hash = name_hash,
|
|
.version = Dependency.parse(
|
|
allocator,
|
|
dep_name_string,
|
|
name_hash,
|
|
version_string.slice(this.buffers.string_bytes.items),
|
|
&version_string.sliced(this.buffers.string_bytes.items),
|
|
log,
|
|
manager,
|
|
) orelse Dependency.Version{},
|
|
.behavior = .{
|
|
.prod = dep.dep_type == .production,
|
|
.dev = dep.dep_type == .development,
|
|
.optional = dep.dep_type == .optional,
|
|
.peer = dep.dep_type == .peer,
|
|
.workspace = false,
|
|
},
|
|
};
|
|
|
|
resolutions_buf[actual_root_dep_count] = yarn_entry_to_package_id[idx];
|
|
actual_root_dep_count += 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
dependencies_list[0] = .{
|
|
.off = 0,
|
|
.len = actual_root_dep_count,
|
|
};
|
|
resolution_list[0] = .{
|
|
.off = 0,
|
|
.len = actual_root_dep_count,
|
|
};
|
|
|
|
dependencies_buf = dependencies_buf[actual_root_dep_count..];
|
|
resolutions_buf = resolutions_buf[actual_root_dep_count..];
|
|
|
|
for (yarn_lock.entries.items, 0..) |entry, yarn_idx| {
|
|
const package_id = yarn_entry_to_package_id[yarn_idx];
|
|
if (package_id == Install.invalid_package_id) continue;
|
|
|
|
const dependencies_start = dependencies_buf.ptr;
|
|
const resolutions_start = resolutions_buf.ptr;
|
|
if (entry.dependencies) |deps| {
|
|
const processed = try processDeps(deps, .production, &yarn_lock, &string_buf, dependencies_buf, resolutions_buf, log, manager, yarn_entry_to_package_id);
|
|
dependencies_buf = dependencies_buf[processed.len..];
|
|
resolutions_buf = resolutions_buf[processed.len..];
|
|
}
|
|
|
|
if (entry.optionalDependencies) |deps| {
|
|
const processed = try processDeps(deps, .optional, &yarn_lock, &string_buf, dependencies_buf, resolutions_buf, log, manager, yarn_entry_to_package_id);
|
|
dependencies_buf = dependencies_buf[processed.len..];
|
|
resolutions_buf = resolutions_buf[processed.len..];
|
|
}
|
|
|
|
if (entry.peerDependencies) |deps| {
|
|
const processed = try processDeps(deps, .peer, &yarn_lock, &string_buf, dependencies_buf, resolutions_buf, log, manager, yarn_entry_to_package_id);
|
|
dependencies_buf = dependencies_buf[processed.len..];
|
|
resolutions_buf = resolutions_buf[processed.len..];
|
|
}
|
|
|
|
if (entry.devDependencies) |deps| {
|
|
const processed = try processDeps(deps, .development, &yarn_lock, &string_buf, dependencies_buf, resolutions_buf, log, manager, yarn_entry_to_package_id);
|
|
dependencies_buf = dependencies_buf[processed.len..];
|
|
resolutions_buf = resolutions_buf[processed.len..];
|
|
}
|
|
|
|
const deps_len = @intFromPtr(dependencies_buf.ptr) - @intFromPtr(dependencies_start);
|
|
const deps_off = @intFromPtr(dependencies_start) - @intFromPtr(this.buffers.dependencies.items.ptr);
|
|
dependencies_list[package_id] = .{
|
|
.off = @intCast(deps_off / @sizeOf(Dependency)),
|
|
.len = @intCast(deps_len / @sizeOf(Dependency)),
|
|
};
|
|
resolution_list[package_id] = .{
|
|
.off = @intCast((@intFromPtr(resolutions_start) - @intFromPtr(this.buffers.resolutions.items.ptr)) / @sizeOf(Install.PackageID)),
|
|
.len = @intCast((@intFromPtr(resolutions_buf.ptr) - @intFromPtr(resolutions_start)) / @sizeOf(Install.PackageID)),
|
|
};
|
|
}
|
|
|
|
this.buffers.dependencies.items.len = @intCast((@intFromPtr(dependencies_buf.ptr) - @intFromPtr(this.buffers.dependencies.items.ptr)) / @sizeOf(Dependency));
|
|
this.buffers.resolutions.items.len = this.buffers.dependencies.items.len;
|
|
|
|
try this.buffers.hoisted_dependencies.ensureTotalCapacity(allocator, this.buffers.dependencies.items.len * 2);
|
|
|
|
try this.buffers.trees.append(allocator, Tree{
|
|
.id = 0,
|
|
.parent = Tree.invalid_id,
|
|
.dependency_id = Tree.root_dep_id,
|
|
.dependencies = .{
|
|
.off = 0,
|
|
.len = 0,
|
|
},
|
|
});
|
|
|
|
var package_dependents = try allocator.alloc(std.array_list.Managed(Install.PackageID), next_package_id);
|
|
defer {
|
|
for (package_dependents) |*list| {
|
|
list.deinit();
|
|
}
|
|
allocator.free(package_dependents);
|
|
}
|
|
for (package_dependents) |*list| {
|
|
list.* = std.array_list.Managed(Install.PackageID).init(allocator);
|
|
}
|
|
|
|
for (yarn_lock.entries.items, 0..) |entry, yarn_idx| {
|
|
const parent_package_id = yarn_entry_to_package_id[yarn_idx];
|
|
|
|
const dep_maps = [_]?bun.StringHashMap(string){
|
|
entry.dependencies,
|
|
entry.optionalDependencies,
|
|
entry.peerDependencies,
|
|
entry.devDependencies,
|
|
};
|
|
|
|
for (dep_maps) |maybe_deps| {
|
|
if (maybe_deps) |deps| {
|
|
var deps_it = deps.iterator();
|
|
while (deps_it.next()) |dep| {
|
|
const dep_name = dep.key_ptr.*;
|
|
const dep_version = dep.value_ptr.*;
|
|
const dep_spec = try std.fmt.allocPrint(allocator, "{s}@{s}", .{ dep_name, dep_version });
|
|
defer allocator.free(dep_spec);
|
|
|
|
if (yarn_lock.findEntryBySpec(dep_spec)) |dep_entry| {
|
|
for (yarn_lock.entries.items, 0..) |*e, idx| {
|
|
var found = false;
|
|
for (e.specs) |spec| {
|
|
for (dep_entry.specs) |dep_spec_item| {
|
|
if (strings.eql(spec, dep_spec_item)) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (found) break;
|
|
}
|
|
|
|
if (found) {
|
|
const dep_package_id = yarn_entry_to_package_id[idx];
|
|
try package_dependents[dep_package_id].append(parent_package_id);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (root_dependencies.items) |dep| {
|
|
const dep_spec = try std.fmt.allocPrint(allocator, "{s}@{s}", .{ dep.name, dep.version });
|
|
defer allocator.free(dep_spec);
|
|
|
|
for (yarn_lock.entries.items, 0..) |entry, idx| {
|
|
for (entry.specs) |spec| {
|
|
if (strings.eql(spec, dep_spec)) {
|
|
const dep_package_id = yarn_entry_to_package_id[idx];
|
|
try package_dependents[dep_package_id].append(0); // 0 is root package
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
var packages_slice = this.packages.slice();
|
|
|
|
var scoped_it = scoped_packages.iterator();
|
|
while (scoped_it.next()) |entry| {
|
|
const base_name = entry.key_ptr.*;
|
|
const versions = entry.value_ptr.*;
|
|
|
|
std.sort.pdq(VersionInfo, versions.items, {}, struct {
|
|
fn lessThan(_: void, a: VersionInfo, b: VersionInfo) bool {
|
|
return a.package_id < b.package_id;
|
|
}
|
|
}.lessThan);
|
|
|
|
const original_name_hash = stringHash(base_name);
|
|
if (this.package_index.getPtr(original_name_hash)) |original_entry| {
|
|
switch (original_entry.*) {
|
|
.id => {
|
|
_ = this.package_index.remove(original_name_hash);
|
|
},
|
|
.ids => |*existing_ids| {
|
|
existing_ids.deinit(this.allocator);
|
|
_ = this.package_index.remove(original_name_hash);
|
|
},
|
|
}
|
|
} else {}
|
|
}
|
|
|
|
var final_check_it = scoped_packages.iterator();
|
|
while (final_check_it.next()) |entry| {
|
|
const base_name = entry.key_ptr.*;
|
|
const versions = entry.value_ptr.*;
|
|
|
|
for (versions.items) |version_info| {
|
|
const package_id = version_info.package_id;
|
|
|
|
var found_in_index = false;
|
|
var check_it = this.package_index.iterator();
|
|
while (check_it.next()) |index_entry| {
|
|
switch (index_entry.value_ptr.*) {
|
|
.id => |id| {
|
|
if (id == package_id) {
|
|
found_in_index = true;
|
|
break;
|
|
}
|
|
},
|
|
.ids => |ids| {
|
|
for (ids.items) |id| {
|
|
if (id == package_id) {
|
|
found_in_index = true;
|
|
break;
|
|
}
|
|
}
|
|
if (found_in_index) break;
|
|
},
|
|
}
|
|
}
|
|
|
|
if (!found_in_index) {
|
|
const fallback_name = try std.fmt.allocPrint(allocator, "{s}#{}", .{ base_name, package_id });
|
|
defer allocator.free(fallback_name);
|
|
|
|
const fallback_hash = stringHash(fallback_name);
|
|
try this.getOrPutID(package_id, fallback_hash);
|
|
}
|
|
}
|
|
}
|
|
|
|
var package_names = try allocator.alloc([]const u8, next_package_id);
|
|
defer allocator.free(package_names);
|
|
@memset(package_names, "");
|
|
|
|
for (yarn_lock.entries.items, 0..) |entry, yarn_idx| {
|
|
const package_id = yarn_entry_to_package_id[yarn_idx];
|
|
if (package_names[package_id].len == 0) {
|
|
package_names[package_id] = YarnLock.Entry.getNameFromSpec(entry.specs[0]);
|
|
}
|
|
}
|
|
|
|
var root_packages = bun.StringHashMap(PackageID).init(allocator);
|
|
defer root_packages.deinit();
|
|
|
|
var usage_count = bun.StringHashMap(u32).init(allocator);
|
|
defer usage_count.deinit();
|
|
for (yarn_lock.entries.items, 0..) |_, entry_idx| {
|
|
const package_id = yarn_entry_to_package_id[entry_idx];
|
|
if (package_id == Install.invalid_package_id) continue;
|
|
const base_name = package_names[package_id];
|
|
|
|
for (yarn_lock.entries.items) |dep_entry| {
|
|
if (dep_entry.dependencies) |deps| {
|
|
var deps_iter = deps.iterator();
|
|
while (deps_iter.next()) |dep| {
|
|
if (strings.eql(dep.key_ptr.*, base_name)) {
|
|
const count = usage_count.get(base_name) orelse 0;
|
|
try usage_count.put(base_name, count + 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (yarn_lock.entries.items, 0..) |_, entry_idx| {
|
|
const package_id = yarn_entry_to_package_id[entry_idx];
|
|
if (package_id == Install.invalid_package_id) continue;
|
|
const base_name = package_names[package_id];
|
|
|
|
if (root_packages.get(base_name) == null) {
|
|
try root_packages.put(base_name, package_id);
|
|
const name_hash = stringHash(base_name);
|
|
try this.getOrPutID(package_id, name_hash);
|
|
}
|
|
}
|
|
|
|
var scoped_names = std.AutoHashMap(PackageID, []const u8).init(allocator);
|
|
defer scoped_names.deinit();
|
|
var scoped_count: u32 = 0;
|
|
for (yarn_lock.entries.items, 0..) |_, entry_idx| {
|
|
const package_id = yarn_entry_to_package_id[entry_idx];
|
|
if (package_id == Install.invalid_package_id) continue;
|
|
const base_name = package_names[package_id];
|
|
|
|
if (root_packages.get(base_name)) |root_pkg_id| {
|
|
if (root_pkg_id == package_id) {
|
|
continue;
|
|
}
|
|
} else {
|
|
continue;
|
|
}
|
|
|
|
var scoped_name: ?[]const u8 = null;
|
|
for (yarn_lock.entries.items, 0..) |dep_entry, dep_entry_idx| {
|
|
const dep_package_id = yarn_entry_to_package_id[dep_entry_idx];
|
|
if (dep_package_id == Install.invalid_package_id) continue;
|
|
|
|
if (dep_entry.dependencies) |deps| {
|
|
var deps_iter = deps.iterator();
|
|
while (deps_iter.next()) |dep| {
|
|
if (strings.eql(dep.key_ptr.*, base_name)) {
|
|
if (dep_package_id != package_id) {
|
|
const parent_name = package_names[dep_package_id];
|
|
|
|
const potential_name = try std.fmt.allocPrint(allocator, "{s}/{s}", .{ parent_name, base_name });
|
|
|
|
var name_already_used = false;
|
|
var value_iter = scoped_names.valueIterator();
|
|
while (value_iter.next()) |existing_name| {
|
|
if (strings.eql(existing_name.*, potential_name)) {
|
|
name_already_used = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!name_already_used) {
|
|
scoped_name = potential_name;
|
|
break;
|
|
} else {
|
|
allocator.free(potential_name);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (scoped_name != null) break;
|
|
}
|
|
}
|
|
|
|
if (scoped_name == null) {
|
|
const version_str = switch (this.packages.get(package_id).resolution.tag) {
|
|
.npm => brk: {
|
|
var version_buf: [64]u8 = undefined;
|
|
const formatted = std.fmt.bufPrint(&version_buf, "{f}", .{this.packages.get(package_id).resolution.value.npm.version.fmt(this.buffers.string_bytes.items)}) catch "";
|
|
break :brk formatted;
|
|
},
|
|
else => "unknown",
|
|
};
|
|
scoped_name = try std.fmt.allocPrint(allocator, "{s}@{s}", .{ base_name, version_str });
|
|
}
|
|
|
|
if (scoped_name) |final_scoped_name| {
|
|
const name_hash = stringHash(final_scoped_name);
|
|
try this.getOrPutID(package_id, name_hash);
|
|
try scoped_names.put(package_id, final_scoped_name);
|
|
scoped_count += 1;
|
|
}
|
|
}
|
|
|
|
for (yarn_lock.entries.items, 0..) |entry, yarn_idx| {
|
|
const package_id = yarn_entry_to_package_id[yarn_idx];
|
|
if (package_id == Install.invalid_package_id) continue;
|
|
|
|
if (entry.resolved) |resolved| {
|
|
if (YarnLock.Entry.getPackageNameFromResolvedUrl(resolved)) |real_name| {
|
|
for (entry.specs) |spec| {
|
|
const alias_name = YarnLock.Entry.getNameFromSpec(spec);
|
|
|
|
if (!strings.eql(alias_name, real_name)) {
|
|
const alias_hash = stringHash(alias_name);
|
|
try this.getOrPutID(package_id, alias_hash);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
this.buffers.trees.items[0].dependencies = .{ .off = 0, .len = 0 };
|
|
|
|
var spec_to_package_id = bun.StringHashMap(Install.PackageID).init(allocator);
|
|
defer spec_to_package_id.deinit();
|
|
|
|
for (yarn_lock.entries.items, 0..) |entry, yarn_idx| {
|
|
const package_id = yarn_entry_to_package_id[yarn_idx];
|
|
if (package_id == Install.invalid_package_id) continue;
|
|
|
|
for (entry.specs) |spec| {
|
|
try spec_to_package_id.put(spec, package_id);
|
|
}
|
|
}
|
|
|
|
const root_deps_off = @as(u32, @intCast(this.buffers.dependencies.items.len));
|
|
const root_resolutions_off = @as(u32, @intCast(this.buffers.resolutions.items.len));
|
|
|
|
if (root_dependencies.items.len > 0) {
|
|
for (root_dependencies.items) |root_dep| {
|
|
_ = @as(DependencyID, @intCast(this.buffers.dependencies.items.len));
|
|
|
|
const name_hash = stringHash(root_dep.name);
|
|
const dep_name_string = try string_buf.appendWithHash(root_dep.name, name_hash);
|
|
const dep_version_string = try string_buf.append(root_dep.version);
|
|
const sliced_string = Semver.SlicedString.init(dep_version_string.slice(this.buffers.string_bytes.items), dep_version_string.slice(this.buffers.string_bytes.items));
|
|
|
|
var parsed_version = Dependency.parse(
|
|
allocator,
|
|
dep_name_string,
|
|
name_hash,
|
|
dep_version_string.slice(this.buffers.string_bytes.items),
|
|
&sliced_string,
|
|
log,
|
|
manager,
|
|
) orelse Dependency.Version{};
|
|
|
|
parsed_version.literal = dep_version_string;
|
|
|
|
const dep = Dependency{
|
|
.name_hash = name_hash,
|
|
.name = dep_name_string,
|
|
.version = parsed_version,
|
|
.behavior = .{
|
|
.prod = root_dep.dep_type == .production,
|
|
.dev = root_dep.dep_type == .development,
|
|
.optional = root_dep.dep_type == .optional,
|
|
.peer = root_dep.dep_type == .peer,
|
|
.workspace = false,
|
|
},
|
|
};
|
|
|
|
try this.buffers.dependencies.append(allocator, dep);
|
|
|
|
const dep_spec = try std.fmt.allocPrint(allocator, "{s}@{s}", .{ root_dep.name, root_dep.version });
|
|
defer allocator.free(dep_spec);
|
|
|
|
if (spec_to_package_id.get(dep_spec)) |pkg_id| {
|
|
try this.buffers.resolutions.append(allocator, pkg_id);
|
|
} else {
|
|
try this.buffers.resolutions.append(allocator, Install.invalid_package_id);
|
|
}
|
|
}
|
|
}
|
|
|
|
packages_slice.items(.dependencies)[0] = .{
|
|
.off = root_deps_off,
|
|
.len = @as(u32, @intCast(root_dependencies.items.len)),
|
|
};
|
|
packages_slice.items(.resolutions)[0] = .{
|
|
.off = root_resolutions_off,
|
|
.len = @as(u32, @intCast(root_dependencies.items.len)),
|
|
};
|
|
|
|
for (yarn_lock.entries.items, 0..) |entry, yarn_idx| {
|
|
const package_id = yarn_entry_to_package_id[yarn_idx];
|
|
if (package_id == Install.invalid_package_id) continue;
|
|
|
|
var dep_count: u32 = 0;
|
|
const deps_off = @as(u32, @intCast(this.buffers.dependencies.items.len));
|
|
const resolutions_off = @as(u32, @intCast(this.buffers.resolutions.items.len));
|
|
|
|
if (entry.dependencies) |deps| {
|
|
var dep_iter = deps.iterator();
|
|
while (dep_iter.next()) |dep_entry| {
|
|
const dep_name = dep_entry.key_ptr.*;
|
|
const dep_version_literal = dep_entry.value_ptr.*;
|
|
|
|
const name_hash = stringHash(dep_name);
|
|
const dep_name_string = try string_buf.appendWithHash(dep_name, name_hash);
|
|
const dep_version_string = try string_buf.append(dep_version_literal);
|
|
const sliced_string = Semver.SlicedString.init(dep_version_string.slice(this.buffers.string_bytes.items), dep_version_string.slice(this.buffers.string_bytes.items));
|
|
|
|
var parsed_version = Dependency.parse(
|
|
allocator,
|
|
dep_name_string,
|
|
name_hash,
|
|
dep_version_string.slice(this.buffers.string_bytes.items),
|
|
&sliced_string,
|
|
log,
|
|
manager,
|
|
) orelse Dependency.Version{};
|
|
|
|
parsed_version.literal = dep_version_string;
|
|
|
|
try this.buffers.dependencies.append(allocator, Dependency{
|
|
.name = dep_name_string,
|
|
.name_hash = name_hash,
|
|
.version = parsed_version,
|
|
.behavior = .{ .prod = true },
|
|
});
|
|
|
|
const dep_spec = try std.fmt.allocPrint(allocator, "{s}@{s}", .{ dep_name, dep_version_literal });
|
|
defer allocator.free(dep_spec);
|
|
|
|
if (spec_to_package_id.get(dep_spec)) |res_pkg_id| {
|
|
try this.buffers.resolutions.append(allocator, res_pkg_id);
|
|
} else {
|
|
try this.buffers.resolutions.append(allocator, Install.invalid_package_id);
|
|
}
|
|
|
|
dep_count += 1;
|
|
}
|
|
}
|
|
|
|
if (entry.optionalDependencies) |optional_deps| {
|
|
var opt_dep_iter = optional_deps.iterator();
|
|
while (opt_dep_iter.next()) |dep_entry| {
|
|
const dep_name = dep_entry.key_ptr.*;
|
|
const dep_version_literal = dep_entry.value_ptr.*;
|
|
|
|
const name_hash = stringHash(dep_name);
|
|
const dep_name_string = try string_buf.appendWithHash(dep_name, name_hash);
|
|
|
|
const dep_version_string = try string_buf.append(dep_version_literal);
|
|
const sliced_string = Semver.SlicedString.init(dep_version_string.slice(this.buffers.string_bytes.items), dep_version_string.slice(this.buffers.string_bytes.items));
|
|
|
|
var parsed_version = Dependency.parse(
|
|
allocator,
|
|
dep_name_string,
|
|
name_hash,
|
|
dep_version_string.slice(this.buffers.string_bytes.items),
|
|
&sliced_string,
|
|
log,
|
|
manager,
|
|
) orelse Dependency.Version{};
|
|
|
|
parsed_version.literal = dep_version_string;
|
|
|
|
try this.buffers.dependencies.append(allocator, Dependency{
|
|
.name = dep_name_string,
|
|
.name_hash = name_hash,
|
|
.version = parsed_version,
|
|
.behavior = .{ .optional = true },
|
|
});
|
|
|
|
const dep_spec = try std.fmt.allocPrint(allocator, "{s}@{s}", .{ dep_name, dep_version_literal });
|
|
defer allocator.free(dep_spec);
|
|
|
|
if (spec_to_package_id.get(dep_spec)) |res_pkg_id| {
|
|
try this.buffers.resolutions.append(allocator, res_pkg_id);
|
|
} else {
|
|
try this.buffers.resolutions.append(allocator, Install.invalid_package_id);
|
|
}
|
|
|
|
dep_count += 1;
|
|
}
|
|
}
|
|
|
|
if (entry.peerDependencies) |peer_deps| {
|
|
var peer_dep_iter = peer_deps.iterator();
|
|
while (peer_dep_iter.next()) |dep_entry| {
|
|
const dep_name = dep_entry.key_ptr.*;
|
|
const dep_version_literal = dep_entry.value_ptr.*;
|
|
|
|
const name_hash = stringHash(dep_name);
|
|
const dep_name_string = try string_buf.appendWithHash(dep_name, name_hash);
|
|
|
|
const dep_version_string = try string_buf.append(dep_version_literal);
|
|
const sliced_string = Semver.SlicedString.init(dep_version_string.slice(this.buffers.string_bytes.items), dep_version_string.slice(this.buffers.string_bytes.items));
|
|
|
|
var parsed_version = Dependency.parse(
|
|
allocator,
|
|
dep_name_string,
|
|
name_hash,
|
|
dep_version_string.slice(this.buffers.string_bytes.items),
|
|
&sliced_string,
|
|
log,
|
|
manager,
|
|
) orelse Dependency.Version{};
|
|
|
|
parsed_version.literal = dep_version_string;
|
|
|
|
try this.buffers.dependencies.append(allocator, Dependency{
|
|
.name = dep_name_string,
|
|
.name_hash = name_hash,
|
|
.version = parsed_version,
|
|
.behavior = .{ .peer = true },
|
|
});
|
|
|
|
const dep_spec = try std.fmt.allocPrint(allocator, "{s}@{s}", .{ dep_name, dep_version_literal });
|
|
defer allocator.free(dep_spec);
|
|
|
|
if (spec_to_package_id.get(dep_spec)) |res_pkg_id| {
|
|
try this.buffers.resolutions.append(allocator, res_pkg_id);
|
|
} else {
|
|
try this.buffers.resolutions.append(allocator, Install.invalid_package_id);
|
|
}
|
|
|
|
dep_count += 1;
|
|
}
|
|
}
|
|
|
|
if (entry.devDependencies) |dev_deps| {
|
|
var dev_dep_iter = dev_deps.iterator();
|
|
while (dev_dep_iter.next()) |dep_entry| {
|
|
const dep_name = dep_entry.key_ptr.*;
|
|
const dep_version_literal = dep_entry.value_ptr.*;
|
|
|
|
const name_hash = stringHash(dep_name);
|
|
const dep_name_string = try string_buf.appendWithHash(dep_name, name_hash);
|
|
|
|
const dep_version_string = try string_buf.append(dep_version_literal);
|
|
const sliced_string = Semver.SlicedString.init(dep_version_string.slice(this.buffers.string_bytes.items), dep_version_string.slice(this.buffers.string_bytes.items));
|
|
|
|
var parsed_version = Dependency.parse(
|
|
allocator,
|
|
dep_name_string,
|
|
name_hash,
|
|
dep_version_string.slice(this.buffers.string_bytes.items),
|
|
&sliced_string,
|
|
log,
|
|
manager,
|
|
) orelse Dependency.Version{};
|
|
|
|
parsed_version.literal = dep_version_string;
|
|
|
|
try this.buffers.dependencies.append(allocator, Dependency{
|
|
.name = dep_name_string,
|
|
.name_hash = name_hash,
|
|
.version = parsed_version,
|
|
.behavior = .{ .dev = true },
|
|
});
|
|
|
|
const dep_spec = try std.fmt.allocPrint(allocator, "{s}@{s}", .{ dep_name, dep_version_literal });
|
|
defer allocator.free(dep_spec);
|
|
|
|
if (spec_to_package_id.get(dep_spec)) |res_pkg_id| {
|
|
try this.buffers.resolutions.append(allocator, res_pkg_id);
|
|
} else {
|
|
try this.buffers.resolutions.append(allocator, Install.invalid_package_id);
|
|
}
|
|
|
|
dep_count += 1;
|
|
}
|
|
}
|
|
|
|
packages_slice.items(.dependencies)[package_id] = .{
|
|
.off = deps_off,
|
|
.len = dep_count,
|
|
};
|
|
|
|
packages_slice.items(.resolutions)[package_id] = .{
|
|
.off = resolutions_off,
|
|
.len = dep_count,
|
|
};
|
|
}
|
|
|
|
try this.resolve(log);
|
|
|
|
try this.fetchNecessaryPackageMetadataAfterYarnOrPnpmMigration(manager, true);
|
|
|
|
if (Environment.allow_assert) {
|
|
try this.verifyData();
|
|
}
|
|
|
|
this.meta_hash = try this.generateMetaHash(false, this.packages.len);
|
|
|
|
const result = LoadResult{ .ok = .{
|
|
.lockfile = this,
|
|
.migrated = .yarn,
|
|
.loaded_from_binary_lockfile = false,
|
|
.serializer_result = .{},
|
|
.format = .binary,
|
|
} };
|
|
|
|
return result;
|
|
}
|
|
|
|
const string = []const u8;
|
|
|
|
const Dependency = @import("./dependency.zig");
|
|
const Npm = @import("./npm.zig");
|
|
const std = @import("std");
|
|
const Bin = @import("./bin.zig").Bin;
|
|
const Integrity = @import("./integrity.zig").Integrity;
|
|
const Resolution = @import("./resolution.zig").Resolution;
|
|
const Allocator = std.mem.Allocator;
|
|
|
|
const Semver = @import("../semver.zig");
|
|
const String = Semver.String;
|
|
const stringHash = String.Builder.stringHash;
|
|
|
|
const Install = @import("./install.zig");
|
|
const DependencyID = Install.DependencyID;
|
|
const PackageID = Install.PackageID;
|
|
|
|
const Lockfile = @import("./lockfile.zig");
|
|
const LoadResult = Lockfile.LoadResult;
|
|
const Tree = Lockfile.Tree;
|
|
|
|
const bun = @import("bun");
|
|
const Environment = bun.Environment;
|
|
const JSON = bun.json;
|
|
const logger = bun.logger;
|
|
const strings = bun.strings;
|