diff --git a/README.md b/README.md index 29cc485de39fc4ffed381bbbba335b06f608732e..a92af1f03ee1c666017c37622e2255ac9a805fe0 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,22 @@ # zig-json ![loc](https://sloc.xyz/github/nektro/zig-json) [![license](https://img.shields.io/github/license/nektro/zig-json.svg)](https://github.com/nektro/zig-json/blob/master/LICENSE) -[![discord](https://img.shields.io/discord/551971034593755159.svg?logo=discord)](https://discord.gg/P6Y4zQC) -A JSON library for inspecting arbitrary values. +A JSON library for inspecting arbitrary values. Accepts trailing commas. ## Usage -See `src/main.zig` for an example. + +See `test.zig` for an example. ## Building Example Program + ``` $ zigmod fetch $ zig build ``` ## Built With + - Zig Master & [Zigmod Package Manager](https://github.com/nektro/zigmod) ## License diff --git a/build.zig b/build.zig index 84d11a12b86e8f32000c04aa7284197d73d085fe..d71439d7bd232fcad07efb93f1aabd042728014c 100644 --- a/build.zig +++ b/build.zig @@ -5,19 +5,17 @@ pub fn build(b: *std.Build) void { const target = b.standardTargetOptions(.{}); const mode = b.option(std.builtin.Mode, "mode", "") orelse .Debug; - const exe = b.addTest(.{ + const test_exe = b.addTest(.{ .root_source_file = b.path("test.zig"), .target = target, .optimize = mode, }); - deps.addAllTo(exe); + deps.addAllTo(test_exe); - const run_cmd = b.addRunArtifact(exe); - run_cmd.step.dependOn(b.getInstallStep()); - if (b.args) |args| { - run_cmd.addArgs(args); - } + const test_cmd = b.addRunArtifact(test_exe); + test_cmd.has_side_effects = true; + test_cmd.step.dependOn(b.getInstallStep()); - const run_step = b.step("test", "Run the tests"); - run_step.dependOn(&run_cmd.step); + const test_step = b.step("test", "Run the tests"); + test_step.dependOn(&test_cmd.step); } diff --git a/json.zig b/json.zig index 95a0b682a71942e4010a9c8ee96461fb9a3b53a3..c044c99d5484d0690f52225960415fd677cc8cb6 100644 --- a/json.zig +++ b/json.zig @@ -1 +1,403 @@ const std = @import("std"); +const string = []const u8; +const extras = @import("extras"); +const tracer = @import("tracer"); + +const buf_size = 64; +const Error = std.mem.Allocator.Error; +const ObjectHashMap = std.AutoArrayHashMapUnmanaged(StringIndex, ValueIndex); + +pub fn parse(alloc: std.mem.Allocator, path: string, inreader: anytype) anyerror!Document { + const t = tracer.trace(@src(), "", .{}); + defer t.end(); + + _ = path; + + var counter = std.io.countingReader(inreader); + var buf = std.io.bufferedReader(counter.reader()); + const anyreader = extras.AnyReader.from(buf.reader()); + var p = Parser.init(alloc, anyreader); + defer p.temp.deinit(alloc); + defer p.strings_map.deinit(alloc); + errdefer p.extras.deinit(alloc); + + comptime std.debug.assert(@intFromEnum(Value.zero) == 0); + try p.extras.ensureUnusedCapacity(alloc, std.mem.page_size); + p.extras.appendAssumeCapacity(@intFromEnum(Value.Tag.zero)); + p.extras.appendAssumeCapacity(@intFromEnum(Value.Tag.null)); + p.extras.appendAssumeCapacity(@intFromEnum(Value.Tag.true)); + p.extras.appendAssumeCapacity(@intFromEnum(Value.Tag.false)); + _ = try p.addStr(alloc, ""); + + return .{ + .root = try parseElement(alloc, &p), + .extras = try p.extras.toOwnedSlice(alloc), + }; +} + +fn parseElement(alloc: std.mem.Allocator, p: *Parser) anyerror!ValueIndex { + try parseWs(alloc, p); + const v = try parseValue(alloc, p); + parseWs(alloc, p) catch |err| switch (err) { + error.EndOfStream => {}, + else => |e| return e, + }; + return v; +} + +fn parseValue(alloc: std.mem.Allocator, p: *Parser) anyerror!ValueIndex { + if (try p.eat("null")) |_| return @enumFromInt(1); + if (try p.eat("true")) |_| return @enumFromInt(2); + if (try p.eat("false")) |_| return @enumFromInt(3); + if (try parseNumber(alloc, p)) |v| return v; + if (try parseString(alloc, p)) |v| return @enumFromInt(@intFromEnum(v)); + if (try parseArray(alloc, p)) |v| return v; + if (try parseObject(alloc, p)) |v| return v; + return error.JsonExpectedValue; +} + +fn parseObject(alloc: std.mem.Allocator, p: *Parser) anyerror!?ValueIndex { + _ = try p.eatByte('{') orelse return null; + + var members = ObjectHashMap{}; + defer members.deinit(alloc); + + while (true) { + try parseWs(alloc, p); + if (try p.eatByte('}')) |_| break; + + const key = try parseString(alloc, p) orelse return error.JsonExpectedObjectKey; + try parseWs(alloc, p); + _ = try p.eatByte(':') orelse return error.JsonExpectedObjectColon; + try parseWs(alloc, p); + const value = try parseValue(alloc, p); + try members.put(alloc, key, value); + try parseWs(alloc, p); + _ = try p.eatByte(',') orelse { + _ = try p.eatByte('}') orelse return error.JsonExpectedTODO; + break; + }; + try parseWs(alloc, p); + if (try p.eatByte('}')) |_| break; + } + return try p.addObject(alloc, &members); +} + +fn parseArray(alloc: std.mem.Allocator, p: *Parser) anyerror!?ValueIndex { + _ = try p.eatByte('[') orelse return null; + + var elements = std.ArrayListUnmanaged(ValueIndex){}; + defer elements.deinit(alloc); + + while (true) { + try parseWs(alloc, p); + if (try p.eatByte(']')) |_| break; + + const elem = try parseValue(alloc, p); + try elements.append(alloc, elem); + try parseWs(alloc, p); + _ = try p.eatByte(',') orelse { + _ = try p.eatByte(']') orelse return error.JsonExpectedTODO; + break; + }; + try parseWs(alloc, p); + if (try p.eatByte(']')) |_| break; + } + return try p.addArray(alloc, elements.items); +} + +fn parseString(alloc: std.mem.Allocator, p: *Parser) anyerror!?StringIndex { + var stack_fallback = std.heap.stackFallback(512, alloc); + var characters = std.ArrayList(u8).init(stack_fallback.get()); + defer characters.deinit(); + + _ = try p.eatByte('"') orelse return null; + + while (true) { + const c = try p.shift(); + if (c == '"') { + break; + } + if (c != '\\') { + try characters.append(@intCast(c)); + continue; + } + switch (try p.shift()) { + inline 0x22, 0x5C, 0x2F => |d| try characters.append(d), + 'b' => try characters.append(0x8), + 'f' => try characters.append(0xC), + 'n' => try characters.append(0xA), + 'r' => try characters.append(0xD), + 't' => try characters.append(0x9), + 'u' => { + var o: u32 = 0; + var d = try p.shiftBytesN(4); + if (!extras.matchesAll(u8, &d, std.ascii.isHex)) return error.JsonExpectedTODO; + d = @bitCast(@byteSwap(@as(u32, @bitCast(d)))); + for (d, 0..) |e, i| o += (e * std.math.pow(u32, 2, @intCast(i))); + // + if (o > std.math.maxInt(u21)) return error.JsonExpectedTODO; + var b: [4]u8 = undefined; + const l = std.unicode.utf8Encode(@intCast(o), &b) catch return error.JsonExpectedTODO; + try characters.appendSlice(b[0..l]); + }, + else => return error.JsonExpectedTODO, + } + } + return try p.addStr(alloc, characters.items); +} + +fn parseNumber(alloc: std.mem.Allocator, p: *Parser) anyerror!?ValueIndex { + var stack_fallback = std.heap.stackFallback(512, alloc); + var characters = std.ArrayList(u8).init(stack_fallback.get()); + defer characters.deinit(); + + if (try p.eatByte('-')) |c| { + try characters.append(c); + + if (try p.eatByte('0')) |_| { + return try p.addNumber(alloc, "-0"); + } + } + if (try p.eatByte('0')) |_| { + return try p.addNumber(alloc, "0"); + } + while (try p.eatAnyScalar("0123456789")) |d| { + try characters.append(d); + } + if (characters.items.len == 0) { + return null; + } + if (try p.eatByte('.')) |c| { + try characters.append(c); + const l = characters.items.len; + while (try p.eatAnyScalar("0123456789")) |d| { + try characters.append(d); + } + if (characters.items.len == l) return error.JsonExpectedTODO; + } + if (try p.eatAnyScalar("eE")) |_| { + try characters.append('e'); + try characters.append(try p.eatAnyScalar("+-") orelse return error.JsonExpectedTODO); + const l = characters.items.len; + while (try p.eatAnyScalar("0123456789")) |d| { + try characters.append(d); + } + if (characters.items.len == l) return error.JsonExpectedTODO; + } + + return try p.addNumber(alloc, characters.items); +} + +fn parseWs(alloc: std.mem.Allocator, p: *Parser) !void { + _ = alloc; + while (true) { + if (try p.eatByte(0x20)) |_| continue; // space + if (try p.eatByte(0x0A)) |_| continue; // NL + if (try p.eatByte(0x0D)) |_| continue; // CR + if (try p.eatByte(0x09)) |_| continue; // TAB + break; + } +} + +const Parser = struct { + any: extras.AnyReader, + arena: std.mem.Allocator, + temp: std.ArrayListUnmanaged(u8) = .{}, + idx: usize = 0, + end: bool = false, + line: usize = 1, + col: usize = 1, + extras: std.ArrayListUnmanaged(u8) = .{}, + strings_map: std.StringArrayHashMapUnmanaged(StringIndex) = .{}, + + pub fn init(allocator: std.mem.Allocator, any: extras.AnyReader) Parser { + return .{ + .any = any, + .arena = allocator, + }; + } + + pub fn avail(p: *Parser) usize { + return p.temp.items.len - p.idx; + } + + pub fn slice(p: *Parser) []const u8 { + return p.temp.items[p.idx..]; + } + + pub fn eat(p: *Parser, comptime test_s: string) !?void { + if (test_s.len == 1) { + _ = try p.eatByte(test_s[0]); + return; + } + try p.peekAmt(test_s.len); + if (std.mem.eql(u8, p.slice()[0..test_s.len], test_s)) { + p.idx += test_s.len; + return; + } + return null; + } + + fn peekAmt(p: *Parser, amt: usize) !void { + if (p.avail() >= amt) return; + const diff_amt = amt - p.avail(); + std.debug.assert(diff_amt <= buf_size); + var buf: [buf_size]u8 = undefined; + var target_buf = buf[0..diff_amt]; + const len = try p.any.readAll(target_buf); + if (len == 0) p.end = true; + if (len == 0) return error.EndOfStream; + std.debug.assert(len <= diff_amt); + try p.temp.appendSlice(p.arena, target_buf[0..len]); + if (len != diff_amt) return error.EndOfStream; + } + + pub fn eatByte(p: *Parser, test_c: u8) !?u8 { + try p.peekAmt(1); + if (p.slice()[0] == test_c) { + p.idx += 1; + return test_c; + } + return null; + } + + pub fn eatAnyScalar(p: *Parser, test_s: string) !?u8 { + std.debug.assert(extras.matchesAll(u8, test_s, std.ascii.isASCII)); + try p.peekAmt(1); + if (std.mem.indexOfScalar(u8, test_s, p.slice()[0])) |idx| { + p.idx += 1; + return test_s[idx]; + } + return null; + } + + pub fn shift(p: *Parser) !u21 { + try p.peekAmt(1); + const len = try std.unicode.utf8ByteSequenceLength(p.slice()[0]); + try p.peekAmt(len); + defer p.idx += len; + return std.unicode.utf8Decode(p.slice()[0..len]); + } + + pub fn shiftBytesN(p: *Parser, comptime n: usize) ![n]u8 { + try p.peekAmt(n); + defer p.idx += n; + return p.slice()[0..n].*; + } + + pub fn addObject(p: *Parser, alloc: std.mem.Allocator, members: *ObjectHashMap) !ValueIndex { + const r = p.extras.items.len; + const l = members.entries.len; + if (l > std.math.maxInt(u32)) return error.JsonExpectedTODO; + try p.extras.ensureUnusedCapacity(alloc, 1 + 4 + (l * 4 * 2)); + p.extras.appendAssumeCapacity(@intFromEnum(Value.Tag.object)); + p.extras.appendSliceAssumeCapacity(&std.mem.toBytes(@as(u32, @intCast(l)))); + p.extras.appendSliceAssumeCapacity(std.mem.sliceAsBytes(members.keys())); + p.extras.appendSliceAssumeCapacity(std.mem.sliceAsBytes(members.values())); + return @enumFromInt(r); + } + + pub fn addArray(p: *Parser, alloc: std.mem.Allocator, items: []const ValueIndex) !ValueIndex { + const r = p.extras.items.len; + const l = items.len; + if (l > std.math.maxInt(u32)) return error.JsonExpectedTODO; + try p.extras.ensureUnusedCapacity(alloc, 1 + 4 + (l * 4)); + p.extras.appendAssumeCapacity(@intFromEnum(Value.Tag.array)); + p.extras.appendSliceAssumeCapacity(&std.mem.toBytes(@as(u32, @intCast(l)))); + p.extras.appendSliceAssumeCapacity(std.mem.sliceAsBytes(items)); + return @enumFromInt(r); + } + + pub fn addStr(p: *Parser, alloc: std.mem.Allocator, str: string) !StringIndex { + const adapter: Adapter = .{ .p = p }; + const res = try p.strings_map.getOrPutAdapted(alloc, str, adapter); + if (res.found_existing) return res.value_ptr.*; + errdefer p.strings_map.orderedRemoveAt(res.index); + const r = p.extras.items.len; + const l = str.len; + try p.extras.ensureUnusedCapacity(alloc, 1 + 4 + l); + p.extras.appendAssumeCapacity(@intFromEnum(Value.Tag.string)); + p.extras.appendSliceAssumeCapacity(&std.mem.toBytes(@as(u32, @intCast(l)))); + p.extras.appendSliceAssumeCapacity(str); + res.value_ptr.* = @enumFromInt(r); + return @enumFromInt(r); + } + + const Adapter = struct { + p: *const Parser, + + pub fn hash(ctx: @This(), a: string) u32 { + _ = ctx; + var hasher = std.hash.Wyhash.init(0); + hasher.update(a); + return @truncate(hasher.final()); + } + + pub fn eql(ctx: @This(), a: string, _: string, b_index: usize) bool { + const sidx = ctx.p.strings_map.values()[b_index]; + const b = ctx.p.getStr(sidx); + return std.mem.eql(u8, a, b); + } + }; + + pub fn addNumber(p: *Parser, alloc: std.mem.Allocator, v: []const u8) !ValueIndex { + const r = p.extras.items.len; + const l = v.len; + if (l > std.math.maxInt(u8)) return error.JsonExpectedTODO; + try p.extras.ensureUnusedCapacity(alloc, 1 + 1 + l); + p.extras.appendAssumeCapacity(@intFromEnum(Value.Tag.number)); + p.extras.appendAssumeCapacity(@intCast(l)); + p.extras.appendSliceAssumeCapacity(v); + return @enumFromInt(r); + } + + pub fn getStr(p: *const Parser, sidx: StringIndex) string { + const i: u32 = @intFromEnum(sidx); + std.debug.assert(@as(Value.Tag, @enumFromInt(p.extras.items[i])) == .string); + const l: u32 = @bitCast(p.extras.items[i..][1..][0..4].*); + return p.extras.items[i..][1..][4..][0..l]; + } +}; + +pub const Document = struct { + extras: []const u8, + root: ValueIndex, + + pub fn deinit(doc: *const Document, alloc: std.mem.Allocator) void { + alloc.free(doc.extras); + } +}; + +pub const ValueIndex = enum(u32) { + _, +}; + +pub const StringIndex = enum(u32) { + _, +}; + +pub const ArrayIndex = enum(u32) { + _, +}; + +pub const ObjectIndex = enum(u32) { + _, +}; + +pub const NumberIndex = enum(u32) { + _, +}; + +pub const Value = union(enum) { + zero, + null, + true, + false, + object, + array, + string, + number, + + const Tag = std.meta.Tag(@This()); +}; diff --git a/licenses.txt b/licenses.txt index 6336b470e0dc9933d1fad883c84eaf86174573d6..417ce45cdac3e11e59addf69a6dbe89dc325152b 100644 --- a/licenses.txt +++ b/licenses.txt @@ -1,3 +1,5 @@ MIT: = https://spdx.org/licenses/MIT - This +- git https://github.com/nektro/zig-extras +- git https://github.com/nektro/zig-tracer diff --git a/test.zig b/test.zig index 95a0b682a71942e4010a9c8ee96461fb9a3b53a3..158dc99c0b42d79265b607ba1928ab51b96e3c86 100644 --- a/test.zig +++ b/test.zig @@ -1 +1,259 @@ const std = @import("std"); +const json = @import("json"); + +fn parse_full(buffer: []const u8) !void { + const alloc = std.testing.allocator; + var fbs = std.io.fixedBufferStream(buffer); + var doc = try json.parse(alloc, "", fbs.reader()); + defer doc.deinit(alloc); +} + +test { + try parse_full( + \\[ + \\ { + \\ "id": 131325113, + \\ "author": { + \\ "login": "github-actions[bot]", + \\ "id": 41898282, + \\ "node_id": "MDM6Qm90NDE4OTgyODI=", + \\ "gravatar_id": "", + \\ "type": "Bot", + \\ "site_admin": false + \\ }, + \\ "node_id": "RE_kwDOEpDmIc4H09y5", + \\ "tag_name": "r89", + \\ "target_commitish": "0df96b60dee2a9e76bf12ad8b8ab1d47dba52994", + \\ "name": "r89", + \\ "draft": false, + \\ "prerelease": false, + \\ "created_at": "2023-11-24T08:33:57Z", + \\ "published_at": "2023-11-24T08:38:51Z", + \\ "assets": [ + \\ { + \\ "id": 137211731, + \\ "node_id": "RA_kwDOEpDmIc4ILa9T", + \\ "name": "zigmod-aarch64-linux", + \\ "label": "", + \\ "uploader": { + \\ "login": "github-actions[bot]", + \\ "id": 41898282, + \\ "node_id": "MDM6Qm90NDE4OTgyODI=", + \\ "gravatar_id": "", + \\ "type": "Bot", + \\ "site_admin": false + \\ }, + \\ "content_type": "application/octet-stream", + \\ "state": "uploaded", + \\ "size": 12449224, + \\ "download_count": 28, + \\ "created_at": "2023-11-24T08:38:52Z", + \\ "updated_at": "2023-11-24T08:38:53Z", + \\ }, + \\ { + \\ "id": 137211736, + \\ "node_id": "RA_kwDOEpDmIc4ILa9Y", + \\ "name": "zigmod-aarch64-macos", + \\ "label": "", + \\ "uploader": { + \\ "login": "github-actions[bot]", + \\ "id": 41898282, + \\ "node_id": "MDM6Qm90NDE4OTgyODI=", + \\ "gravatar_id": "", + \\ "type": "Bot", + \\ "site_admin": false + \\ }, + \\ "content_type": "application/octet-stream", + \\ "state": "uploaded", + \\ "size": 9137624, + \\ "download_count": 581, + \\ "created_at": "2023-11-24T08:38:55Z", + \\ "updated_at": "2023-11-24T08:38:56Z", + \\ }, + \\ { + \\ "id": 137211747, + \\ "node_id": "RA_kwDOEpDmIc4ILa9j", + \\ "name": "zigmod-aarch64-windows.exe", + \\ "label": "", + \\ "uploader": { + \\ "login": "github-actions[bot]", + \\ "id": 41898282, + \\ "node_id": "MDM6Qm90NDE4OTgyODI=", + \\ "gravatar_id": "", + \\ "type": "Bot", + \\ "site_admin": false + \\ }, + \\ "content_type": "application/octet-stream", + \\ "state": "uploaded", + \\ "size": 7738880, + \\ "download_count": 23, + \\ "created_at": "2023-11-24T08:39:00Z", + \\ "updated_at": "2023-11-24T08:39:01Z", + \\ }, + \\ { + \\ "id": 137211740, + \\ "node_id": "RA_kwDOEpDmIc4ILa9c", + \\ "name": "zigmod-aarch64-windows.pdb", + \\ "label": "", + \\ "uploader": { + \\ "login": "github-actions[bot]", + \\ "id": 41898282, + \\ "node_id": "MDM6Qm90NDE4OTgyODI=", + \\ "gravatar_id": "", + \\ "type": "Bot", + \\ "site_admin": false + \\ }, + \\ "content_type": "application/octet-stream", + \\ "state": "uploaded", + \\ "size": 3813376, + \\ "download_count": 2, + \\ "created_at": "2023-11-24T08:38:56Z", + \\ "updated_at": "2023-11-24T08:38:57Z", + \\ }, + \\ { + \\ "id": 137211748, + \\ "node_id": "RA_kwDOEpDmIc4ILa9k", + \\ "name": "zigmod-mips64-linux", + \\ "label": "", + \\ "uploader": { + \\ "login": "github-actions[bot]", + \\ "id": 41898282, + \\ "node_id": "MDM6Qm90NDE4OTgyODI=", + \\ "gravatar_id": "", + \\ "type": "Bot", + \\ "site_admin": false + \\ }, + \\ "content_type": "application/octet-stream", + \\ "state": "uploaded", + \\ "size": 12545712, + \\ "download_count": 3, + \\ "created_at": "2023-11-24T08:39:01Z", + \\ "updated_at": "2023-11-24T08:39:03Z", + \\ }, + \\ { + \\ "id": 137211749, + \\ "node_id": "RA_kwDOEpDmIc4ILa9l", + \\ "name": "zigmod-powerpc64le-linux", + \\ "label": "", + \\ "uploader": { + \\ "login": "github-actions[bot]", + \\ "id": 41898282, + \\ "node_id": "MDM6Qm90NDE4OTgyODI=", + \\ "gravatar_id": "", + \\ "type": "Bot", + \\ "site_admin": false + \\ }, + \\ "content_type": "application/octet-stream", + \\ "state": "uploaded", + \\ "size": 11638720, + \\ "download_count": 3, + \\ "created_at": "2023-11-24T08:39:03Z", + \\ "updated_at": "2023-11-24T08:39:04Z", + \\ }, + \\ { + \\ "id": 137211745, + \\ "node_id": "RA_kwDOEpDmIc4ILa9h", + \\ "name": "zigmod-riscv64-linux", + \\ "label": "", + \\ "uploader": { + \\ "login": "github-actions[bot]", + \\ "id": 41898282, + \\ "node_id": "MDM6Qm90NDE4OTgyODI=", + \\ "gravatar_id": "", + \\ "type": "Bot", + \\ "site_admin": false + \\ }, + \\ "content_type": "application/octet-stream", + \\ "state": "uploaded", + \\ "size": 17282528, + \\ "download_count": 4, + \\ "created_at": "2023-11-24T08:38:58Z", + \\ "updated_at": "2023-11-24T08:39:00Z", + \\ }, + \\ { + \\ "id": 137211752, + \\ "node_id": "RA_kwDOEpDmIc4ILa9o", + \\ "name": "zigmod-x86_64-linux", + \\ "label": "", + \\ "uploader": { + \\ "login": "github-actions[bot]", + \\ "id": 41898282, + \\ "node_id": "MDM6Qm90NDE4OTgyODI=", + \\ "gravatar_id": "", + \\ "type": "Bot", + \\ "site_admin": false + \\ }, + \\ "content_type": "application/octet-stream", + \\ "state": "uploaded", + \\ "size": 11913416, + \\ "download_count": 4906, + \\ "created_at": "2023-11-24T08:39:06Z", + \\ "updated_at": "2023-11-24T08:39:07Z", + \\ }, + \\ { + \\ "id": 137211733, + \\ "node_id": "RA_kwDOEpDmIc4ILa9V", + \\ "name": "zigmod-x86_64-macos", + \\ "label": "", + \\ "uploader": { + \\ "login": "github-actions[bot]", + \\ "id": 41898282, + \\ "node_id": "MDM6Qm90NDE4OTgyODI=", + \\ "gravatar_id": "", + \\ "type": "Bot", + \\ "site_admin": false + \\ }, + \\ "content_type": "application/octet-stream", + \\ "state": "uploaded", + \\ "size": 8618320, + \\ "download_count": 795, + \\ "created_at": "2023-11-24T08:38:53Z", + \\ "updated_at": "2023-11-24T08:38:54Z", + \\ }, + \\ { + \\ "id": 137211742, + \\ "node_id": "RA_kwDOEpDmIc4ILa9e", + \\ "name": "zigmod-x86_64-windows.exe", + \\ "label": "", + \\ "uploader": { + \\ "login": "github-actions[bot]", + \\ "id": 41898282, + \\ "node_id": "MDM6Qm90NDE4OTgyODI=", + \\ "gravatar_id": "", + \\ "type": "Bot", + \\ "site_admin": false + \\ }, + \\ "content_type": "application/octet-stream", + \\ "state": "uploaded", + \\ "size": 7557632, + \\ "download_count": 300, + \\ "created_at": "2023-11-24T08:38:57Z", + \\ "updated_at": "2023-11-24T08:38:58Z", + \\ }, + \\ { + \\ "id": 137211751, + \\ "node_id": "RA_kwDOEpDmIc4ILa9n", + \\ "name": "zigmod-x86_64-windows.pdb", + \\ "label": "", + \\ "uploader": { + \\ "login": "github-actions[bot]", + \\ "id": 41898282, + \\ "node_id": "MDM6Qm90NDE4OTgyODI=", + \\ "gravatar_id": "", + \\ "type": "Bot", + \\ "site_admin": false + \\ }, + \\ "content_type": "application/octet-stream", + \\ "state": "uploaded", + \\ "size": 4411392, + \\ "download_count": 8, + \\ "created_at": "2023-11-24T08:39:05Z", + \\ "updated_at": "2023-11-24T08:39:05Z", + \\ } + \\ ], + \\ "body": "
  • 0df96b6 cmd/aq/{install,update}: use proper cachepath (Meghan Denny)
  • \n
  • a1ea508 main: pass proper self_path value (Meghan Denny)
  • \n
  • 09d633b cmd: when running zigmod inside deps folder, use parent deps folder as cachepath (Meghan Denny)
  • \n
  • 65666d0 add self_name arg to all execute() call signatures (Meghan Denny)
  • \n
  • e2d42e8 add deps.addAllLibrariesTo(), closes #84 (Meghan Denny)
  • \n
  • f3aabb5 regenerate deps.zig (Meghan Denny)
  • \n
  • b8cd095 mark versioned dep folders as readonly, closes #53 (Meghan Denny)
  • \n
  • 255cb97 add a buffered reader for parsing zigmod.lock (Meghan Denny)
  • \n
  • a9863df close some file descriptors (Meghan Denny)
  • \n
  • 941ad7c deps: marlersoft/zigwin32: misc confirmed update (Meghan Denny)
  • \n
  • 0e75165 deps: nektro/zig-extras: misc confirmed updates (Meghan Denny)
  • \n
  • 8e4e9ae deps: ziglibs/known-folders: misc confirmed updates (Meghan Denny)
  • \n
  • 8ba1d87 deps: truemedian/hzzp: misc confirmed updates (Meghan Denny)
  • \n
  • ddd0eb7 deps: nektro/iguanaTLS: misc confirmed updates (Meghan Denny)
  • \n
  • 02464e0 build_release.sh: use debug mode, release breaks stack traces (Meghan Denny)
  • \n
  • 6c68f38 build.zig: add a -Doption (Meghan Denny)
  • \n
  • 5403d1a build.zig: move -Dtag option declaration out with other options (Meghan Denny)
  • " + \\ } + \\] + \\ + ); +} diff --git a/zig.mod b/zig.mod index c28a0ed070570c4de57a0475d70bf9dd5b392145..50416059d4359afc125a6e2bc21f0aa636cbc596 100644 --- a/zig.mod +++ b/zig.mod @@ -3,3 +3,6 @@ name: json main: json.zig license: MIT description: "A JSON library for inspecting arbitrary values" +dependencies: + - src: git https://github.com/nektro/zig-extras + - src: git https://github.com/nektro/zig-tracer