MIRROR: javascript for 馃悳's, a tiny runtime with big ambitions
1const std = @import("std");
2const root = @import("root.zig");
3
4const ListCallback =
5 *const fn ([*:0]const u8, [*:0]const u8, ?*anyopaque) callconv(.c) void;
6
7const PkgDeps = struct {
8 deps: ?std.json.ObjectMap,
9 dev_deps: ?std.json.ObjectMap,
10 nm_path: []const u8,
11 arena: std.mem.Allocator,
12 parsed: std.json.Parsed(std.json.Value),
13
14 pub fn deinit(self: *PkgDeps) void {
15 self.parsed.deinit();
16 }
17
18 pub fn count(self: *const PkgDeps) u32 {
19 var c: u32 = 0;
20 if (self.deps) |d| c += @intCast(d.count());
21 if (self.dev_deps) |d| c += @intCast(d.count());
22 return c;
23 }
24};
25
26fn emitPkg(pd: *PkgDeps, name: []const u8, cb: ListCallback, ud: ?*anyopaque) void {
27 const pkg_json = std.fmt.allocPrint(pd.arena, "{s}/{s}/package.json", .{pd.nm_path, name}) catch return;
28 const content = std.fs.cwd().readFileAlloc(pd.arena, pkg_json, 256 * 1024) catch return;
29 const parsed = std.json.parseFromSlice(std.json.Value, pd.arena, content, .{}) catch return;
30 defer parsed.deinit();
31
32 const ver = if (parsed.value.object.get("version")) |v| if (v == .string) v.string else "?" else "?";
33 cb(pd.arena.dupeZ(u8, name) catch return, pd.arena.dupeZ(u8, ver) catch return, ud);
34}
35
36pub fn get_dependencies(ctx: ?*root.PkgContext, base_path: ?[]const u8, include_dev: bool) ?PkgDeps {
37 const c = ctx orelse return null;
38 _ = c.arena_state.reset(.retain_capacity);
39 const arena = c.arena_state.allocator();
40
41 const pkg_json_path = if (base_path) |bp| std.fmt.allocPrint(arena, "{s}/package.json", .{bp}) catch return null
42 else arena.dupe(u8, "package.json") catch return null;
43
44 const nm_path = if (base_path) |bp| std.fmt.allocPrint(arena, "{s}/node_modules", .{bp}) catch return null
45 else arena.dupe(u8, "node_modules") catch return null;
46
47 const content = std.fs.cwd().readFileAlloc(arena, pkg_json_path, 1024 * 1024) catch return null;
48 const parsed = std.json.parseFromSlice(std.json.Value, arena, content, .{}) catch return null;
49
50 const deps_val = parsed.value.object.get("dependencies");
51 const deps = if (deps_val) |v| if (v == .object) v.object else null else null;
52
53 const dev_deps = if (include_dev) blk: {
54 const dev_val = parsed.value.object.get("devDependencies");
55 break :blk if (dev_val) |v| if (v == .object) v.object else null else null;
56 } else null;
57
58 if (deps == null and dev_deps == null) {
59 var p = parsed;
60 p.deinit();
61 return null;
62 }
63
64 return .{ .deps = deps, .dev_deps = dev_deps, .nm_path = nm_path, .arena = arena, .parsed = parsed };
65}
66
67pub fn list_dependencies(pd: *PkgDeps, cb: ListCallback, ud: ?*anyopaque) void {
68 if (pd.deps) |d| for (d.keys()) |n| emitPkg(pd, n, cb, ud);
69 if (pd.dev_deps) |d| for (d.keys()) |n| emitPkg(pd, n, cb, ud);
70}