@voxgig/sdkgen 4.8.3 → 4.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (201) hide show
  1. package/bin/voxgig-sdkgen +1 -1
  2. package/package.json +1 -1
  3. package/project/.sdk/model/target/zig.aon +9 -0
  4. package/project/.sdk/src/cmp/zig/Package_zig.ts +15 -11
  5. package/project/.sdk/src/cmp/zig/fragment/Entity.fragment.zig +3 -3
  6. package/project/.sdk/src/cmp/zig/fragment/EntityListOp.fragment.zig +3 -3
  7. package/project/.sdk/src/cmp/zig/fragment/Main.fragment.zig +3 -3
  8. package/project/.sdk/src/cmp/zig/utility_zig.ts +50 -1
  9. package/project/.sdk/tm/c/tests/vendor/omni/json.c +2 -2
  10. package/project/.sdk/tm/c/tests/vendor/omni/omni.h +2 -2
  11. package/project/.sdk/tm/c/tests/vendor/omni/runner.c +2 -2
  12. package/project/.sdk/tm/c/tests/vendor/omni/util.c +2 -2
  13. package/project/.sdk/tm/clojure/test/vendor/omni/voxgig/omni/json.clj +2 -2
  14. package/project/.sdk/tm/clojure/test/vendor/omni/voxgig/omni/runner.clj +2 -2
  15. package/project/.sdk/tm/clojure/test/vendor/omni/voxgig/omni/util.clj +2 -2
  16. package/project/.sdk/tm/cpp/test/vendor/omni/json.hpp +2 -2
  17. package/project/.sdk/tm/cpp/test/vendor/omni/omni.hpp +2 -2
  18. package/project/.sdk/tm/cpp/test/vendor/omni/util.hpp +2 -2
  19. package/project/.sdk/tm/csharp/test/vendor/omni/Runner.cs +2 -2
  20. package/project/.sdk/tm/csharp/test/vendor/omni/Util.cs +2 -2
  21. package/project/.sdk/tm/csharp/utility/struct/Struct.cs +1 -1
  22. package/project/.sdk/tm/dart/test/vendor/omni/omni.dart +2 -2
  23. package/project/.sdk/tm/dart/test/vendor/omni/runner.dart +2 -2
  24. package/project/.sdk/tm/dart/test/vendor/omni/util.dart +2 -2
  25. package/project/.sdk/tm/elixir/test/vendor/omni/json.ex +2 -2
  26. package/project/.sdk/tm/elixir/test/vendor/omni/runner.ex +2 -2
  27. package/project/.sdk/tm/elixir/test/vendor/omni/util.ex +2 -2
  28. package/project/.sdk/tm/go/feature/secrets/plugin/capability.go +1 -1
  29. package/project/.sdk/tm/go/feature/secrets/plugin/catalog.go +1 -1
  30. package/project/.sdk/tm/go/feature/secrets/plugin/config.go +1 -1
  31. package/project/.sdk/tm/go/feature/secrets/plugin/depend.go +1 -1
  32. package/project/.sdk/tm/go/feature/secrets/plugin/env.go +1 -1
  33. package/project/.sdk/tm/go/feature/secrets/plugin/export.go +1 -1
  34. package/project/.sdk/tm/go/feature/secrets/plugin/graph.go +1 -1
  35. package/project/.sdk/tm/go/feature/secrets/plugin/host.go +1 -1
  36. package/project/.sdk/tm/go/feature/secrets/plugin/order.go +1 -1
  37. package/project/.sdk/tm/go/feature/secrets/plugin/point.go +1 -1
  38. package/project/.sdk/tm/go/feature/secrets/plugin/ref.go +1 -1
  39. package/project/.sdk/tm/go/feature/secrets/plugin/resolve.go +1 -1
  40. package/project/.sdk/tm/go/feature/secrets/plugin/types.go +1 -1
  41. package/project/.sdk/tm/go/feature/secrets/plugin/util.go +1 -1
  42. package/project/.sdk/tm/go/feature/secrets/plugin/version.go +1 -1
  43. package/project/.sdk/tm/go/feature/secrets/plugins/aws/aws.go +4 -4
  44. package/project/.sdk/tm/go/feature/secrets/plugins/aws/sigv4.go +2 -2
  45. package/project/.sdk/tm/go/feature/secrets/plugins/azuresecrets/azuresecrets.go +2 -2
  46. package/project/.sdk/tm/go/feature/secrets/plugins/boru/boru.go +2 -2
  47. package/project/.sdk/tm/go/feature/secrets/plugins/doppler/doppler.go +2 -2
  48. package/project/.sdk/tm/go/feature/secrets/plugins/gcpsecrets/gcpsecrets.go +2 -2
  49. package/project/.sdk/tm/go/feature/secrets/plugins/hashicorp/hashicorp.go +4 -5
  50. package/project/.sdk/tm/go/feature/secrets/plugins/httpjson/httpjson.go +3 -3
  51. package/project/.sdk/tm/go/feature/secrets/plugins/infisical/infisical.go +3 -4
  52. package/project/.sdk/tm/go/feature/secrets/plugins/onepassword/onepassword.go +2 -2
  53. package/project/.sdk/tm/go/feature/secrets/plugins/secretspec/secretspec.go +2 -2
  54. package/project/.sdk/tm/go/feature/secrets/sekreto/addr.go +2 -2
  55. package/project/.sdk/tm/go/feature/secrets/sekreto/providers.go +5 -2
  56. package/project/.sdk/tm/go/feature/secrets/sekreto/sekreto.go +31 -2
  57. package/project/.sdk/tm/go/test/omni/omni.go +8 -3
  58. package/project/.sdk/tm/go/test/omni/util.go +25 -4
  59. package/project/.sdk/tm/go/utility/struct/voxgigstruct.go +1 -1
  60. package/project/.sdk/tm/java/test/vendor/omni/Json.java +2 -2
  61. package/project/.sdk/tm/java/test/vendor/omni/Runner.java +2 -2
  62. package/project/.sdk/tm/java/test/vendor/omni/Util.java +2 -2
  63. package/project/.sdk/tm/java/utility/struct/Struct.java +1 -1
  64. package/project/.sdk/tm/js/src/utility/StructUtility.js +2 -2
  65. package/project/.sdk/tm/js/test/vendor/omni/index.js +1 -1
  66. package/project/.sdk/tm/js/test/vendor/omni/runner.js +18 -3
  67. package/project/.sdk/tm/js/test/vendor/omni/util.js +25 -8
  68. package/project/.sdk/tm/kotlin/test/vendor/omni/Json.kt +2 -2
  69. package/project/.sdk/tm/kotlin/test/vendor/omni/Runner.kt +2 -2
  70. package/project/.sdk/tm/kotlin/test/vendor/omni/Util.kt +2 -2
  71. package/project/.sdk/tm/kotlin/utility/struct/Struct.kt +1 -1
  72. package/project/.sdk/tm/lean/test/vendor/omni/Omni.lean +2 -2
  73. package/project/.sdk/tm/lua/test/vendor/omni/json.lua +2 -2
  74. package/project/.sdk/tm/lua/test/vendor/omni/regex.lua +2 -2
  75. package/project/.sdk/tm/lua/test/vendor/omni/runner.lua +2 -2
  76. package/project/.sdk/tm/lua/test/vendor/omni/util.lua +2 -2
  77. package/project/.sdk/tm/lua/utility/struct/regex.lua +1 -1
  78. package/project/.sdk/tm/lua/utility/struct/struct.lua +1 -1
  79. package/project/.sdk/tm/ocaml/test/vendor/omni/omni.ml +2 -2
  80. package/project/.sdk/tm/perl/lib/Voxgig/Struct.pm +1 -1
  81. package/project/.sdk/tm/perl/t/vendor/omni/Voxgig/Omni/Runner.pm +1 -1
  82. package/project/.sdk/tm/perl/t/vendor/omni/Voxgig/Omni/Util.pm +1 -1
  83. package/project/.sdk/tm/perl/t/vendor/omni/Voxgig/Omni.pm +1 -1
  84. package/project/.sdk/tm/php/test/vendor/omni/Runner.php +2 -2
  85. package/project/.sdk/tm/php/test/vendor/omni/Util.php +2 -2
  86. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/__init__.py +1 -1
  87. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/capability.py +1 -1
  88. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/catalog.py +1 -1
  89. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/config.py +1 -1
  90. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/depend.py +1 -1
  91. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/env.py +1 -1
  92. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/export.py +1 -1
  93. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/graph.py +1 -1
  94. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/host.py +1 -1
  95. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/order.py +1 -1
  96. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/point.py +1 -1
  97. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/ref.py +1 -1
  98. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/resolve.py +1 -1
  99. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/types.py +1 -1
  100. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_plugin/version.py +1 -1
  101. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/__init__.py +3 -1
  102. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/addr.py +1 -1
  103. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/plugins/aws.py +3 -3
  104. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/plugins/azuresecrets.py +1 -1
  105. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/plugins/boru.py +1 -1
  106. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/plugins/doppler.py +1 -1
  107. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/plugins/gcpsecrets.py +1 -1
  108. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/plugins/hashicorp.py +3 -4
  109. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/plugins/httpjson.py +1 -1
  110. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/plugins/infisical.py +4 -6
  111. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/plugins/onepassword.py +1 -1
  112. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/plugins/secretspec.py +1 -1
  113. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/plugins/sigv4.py +1 -1
  114. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/providers.py +1 -1
  115. package/project/.sdk/tm/py/pkg/feature/secrets/voxgig_sekreto/sekreto.py +21 -1
  116. package/project/.sdk/tm/py/pkg/utility/voxgig_struct/voxgig_struct.py +1 -1
  117. package/project/.sdk/tm/py/test/voxgig_omni/__init__.py +1 -1
  118. package/project/.sdk/tm/py/test/voxgig_omni/runner.py +16 -2
  119. package/project/.sdk/tm/py/test/voxgig_omni/util.py +27 -12
  120. package/project/.sdk/tm/rb/test/vendor/omni/runner.rb +2 -2
  121. package/project/.sdk/tm/rb/test/vendor/omni/util.rb +2 -2
  122. package/project/.sdk/tm/rb/test/vendor/omni/voxgig_omni.rb +2 -2
  123. package/project/.sdk/tm/rust/tests/vendor/omni/json.rs +2 -2
  124. package/project/.sdk/tm/rust/tests/vendor/omni/mod.rs +2 -2
  125. package/project/.sdk/tm/rust/tests/vendor/omni/regex.rs +2 -2
  126. package/project/.sdk/tm/rust/tests/vendor/omni/runner.rs +2 -2
  127. package/project/.sdk/tm/rust/tests/vendor/omni/util.rs +2 -2
  128. package/project/.sdk/tm/scala/sdktest/vendor/omni/Json.scala +2 -2
  129. package/project/.sdk/tm/scala/sdktest/vendor/omni/Runner.scala +2 -2
  130. package/project/.sdk/tm/scala/sdktest/vendor/omni/Util.scala +2 -2
  131. package/project/.sdk/tm/swift/Tests/vendor/omni/Json.swift +2 -2
  132. package/project/.sdk/tm/swift/Tests/vendor/omni/Runner.swift +2 -2
  133. package/project/.sdk/tm/swift/Tests/vendor/omni/Util.swift +2 -2
  134. package/project/.sdk/tm/ts/src/feature/secrets/plugin/Capability.ts +1 -1
  135. package/project/.sdk/tm/ts/src/feature/secrets/plugin/Catalog.ts +1 -1
  136. package/project/.sdk/tm/ts/src/feature/secrets/plugin/Config.ts +1 -1
  137. package/project/.sdk/tm/ts/src/feature/secrets/plugin/Depend.ts +1 -1
  138. package/project/.sdk/tm/ts/src/feature/secrets/plugin/Env.ts +1 -1
  139. package/project/.sdk/tm/ts/src/feature/secrets/plugin/Export.ts +1 -1
  140. package/project/.sdk/tm/ts/src/feature/secrets/plugin/FeatureHost.ts +1 -1
  141. package/project/.sdk/tm/ts/src/feature/secrets/plugin/Graph.ts +1 -1
  142. package/project/.sdk/tm/ts/src/feature/secrets/plugin/Host.ts +1 -1
  143. package/project/.sdk/tm/ts/src/feature/secrets/plugin/Order.ts +1 -1
  144. package/project/.sdk/tm/ts/src/feature/secrets/plugin/Point.ts +1 -1
  145. package/project/.sdk/tm/ts/src/feature/secrets/plugin/Ref.ts +1 -1
  146. package/project/.sdk/tm/ts/src/feature/secrets/plugin/Resolve.ts +1 -1
  147. package/project/.sdk/tm/ts/src/feature/secrets/plugin/Types.ts +1 -1
  148. package/project/.sdk/tm/ts/src/feature/secrets/plugin/Version.ts +1 -1
  149. package/project/.sdk/tm/ts/src/feature/secrets/plugin/index.ts +1 -1
  150. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/Sekreto.ts +1 -1
  151. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/index.ts +1 -1
  152. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/plugins/aws.ts +1 -1
  153. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/plugins/azuresecrets.ts +1 -1
  154. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/plugins/boru.ts +1 -1
  155. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/plugins/doppler.ts +1 -1
  156. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/plugins/gcpsecrets.ts +1 -1
  157. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/plugins/hashicorp.ts +1 -1
  158. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/plugins/httpjson.ts +1 -1
  159. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/plugins/infisical.ts +1 -1
  160. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/plugins/onepassword.ts +1 -1
  161. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/plugins/secretspec.ts +1 -1
  162. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/plugins/sigv4.ts +1 -1
  163. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/addr.ts +1 -1
  164. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/builtin.ts +1 -1
  165. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/dotenv.ts +1 -1
  166. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/env.ts +1 -1
  167. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/file.ts +1 -1
  168. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/memory.ts +1 -1
  169. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/support.ts +1 -1
  170. package/project/.sdk/tm/ts/src/utility/StructUtility.ts +2 -2
  171. package/project/.sdk/tm/ts/test/vendor/omni/Runner.ts +1 -1
  172. package/project/.sdk/tm/ts/test/vendor/omni/Util.ts +1 -1
  173. package/project/.sdk/tm/ts/test/vendor/omni/index.ts +1 -1
  174. package/project/.sdk/tm/zig/Makefile +15 -1
  175. package/project/.sdk/tm/zig/build.zig +23 -5
  176. package/project/.sdk/tm/zig/core/helpers.zig +52 -11
  177. package/project/.sdk/tm/zig/core/mem.zig +17 -1
  178. package/project/.sdk/tm/zig/core/utility.zig +23 -19
  179. package/project/.sdk/tm/zig/feature/audit.zig +2 -2
  180. package/project/.sdk/tm/zig/feature/cache.zig +2 -2
  181. package/project/.sdk/tm/zig/feature/debug.zig +5 -5
  182. package/project/.sdk/tm/zig/feature/netsim.zig +2 -2
  183. package/project/.sdk/tm/zig/feature/paging.zig +2 -2
  184. package/project/.sdk/tm/zig/feature/proxy.zig +15 -8
  185. package/project/.sdk/tm/zig/feature/streaming.zig +5 -5
  186. package/project/.sdk/tm/zig/feature/support.zig +3 -3
  187. package/project/.sdk/tm/zig/feature/telemetry.zig +5 -5
  188. package/project/.sdk/tm/zig/feature/test.zig +10 -5
  189. package/project/.sdk/tm/zig/test/fh.zig +10 -10
  190. package/project/.sdk/tm/zig/test/gotcha_test.zig +5 -5
  191. package/project/.sdk/tm/zig/test/omniresolver.zig +515 -0
  192. package/project/.sdk/tm/zig/test/omnismoke_test.zig +284 -0
  193. package/project/.sdk/tm/zig/test/pipeline_test.zig +8 -8
  194. package/project/.sdk/tm/zig/test/primary_utility_test.zig +144 -154
  195. package/project/.sdk/tm/zig/test/struct_corpus.zig +264 -187
  196. package/project/.sdk/tm/zig/test/vendor/omni/omni.zig +1314 -0
  197. package/project/.sdk/tm/zig/test/vendor/omni/regex.zig +446 -0
  198. package/project/.sdk/tm/zig/utility/voxgigstruct/regex.zig +7 -4
  199. package/project/.sdk/tm/zig/utility/voxgigstruct/struct.zig +356 -157
  200. package/project/sdkgen-package.json +1 -1
  201. package/project/.sdk/tm/zig/test/struct_runner.zig +0 -465
@@ -1,3 +1,6 @@
1
+ // VENDORED: @voxgig/struct sdk-20260907-0029-0 (zig/src/struct.zig)
2
+ // Source: https://github.com/voxgig/struct @ adda9521c828147573df5a8878408a3f2193ddf4 [tag: sdk-20260907-0029-0]
3
+ // License: MIT (c) voxgig - see repository LICENSE. Do not edit: resync from upstream.
1
4
  // Copyright (c) 2025-2026 Voxgig Ltd. MIT LICENSE.
2
5
 
3
6
  // Voxgig Struct
@@ -17,18 +20,24 @@ pub const StdJsonValue = std.json.Value;
17
20
  // All holders of the same *MapRef / *ListRef see mutations.
18
21
  // ============================================================================
19
22
 
20
- pub const MapData = std.StringArrayHashMap(JsonValue);
21
- pub const ListData = std.ArrayList(JsonValue);
23
+ pub const MapData = std.array_hash_map.String(JsonValue);
24
+ pub const ListData = std.array_list.Managed(JsonValue);
22
25
 
23
26
  pub const MapRef = struct {
24
27
  data: MapData,
28
+ // 0.16 has no managed array hash map - only the unmanaged
29
+ // std.array_hash_map.String - so the allocator that used to live inside
30
+ // MapData lives here instead. Holding it on the ref rather than
31
+ // threading it through every caller keeps this type's API, and so every
32
+ // call site of it, exactly as it was.
33
+ allocator: Allocator,
25
34
 
26
35
  pub fn get(self: *const MapRef, key: []const u8) ?JsonValue {
27
36
  return self.data.get(key);
28
37
  }
29
38
 
30
39
  pub fn put(self: *MapRef, key: []const u8, val: JsonValue) !void {
31
- try self.data.put(key, val);
40
+ try self.data.put(self.allocator, key, val);
32
41
  }
33
42
 
34
43
  pub fn count(self: *const MapRef) usize {
@@ -61,14 +70,7 @@ pub const ListRef = struct {
61
70
  };
62
71
 
63
72
  // Function signature for values stored in the JSON tree.
64
- // Extended for the SDK: a callable carries a captured context pointer so
65
- // custom utilities, injected clocks/keygens and mock transports can hold
66
- // state. Stored by pointer so it survives `clone` (shallow) unchanged.
67
- pub const Callable = struct {
68
- ctx: *anyopaque,
69
- call: *const fn (ctx: *anyopaque, allocator: Allocator, arg: JsonValue) anyerror!JsonValue,
70
- };
71
- pub const JsonFunc = *const Callable;
73
+ pub const JsonFunc = *const fn (allocator: Allocator) anyerror!JsonValue;
72
74
 
73
75
  // Custom value type with pointer-stable containers.
74
76
  pub const JsonValue = union(enum) {
@@ -84,7 +86,7 @@ pub const JsonValue = union(enum) {
84
86
 
85
87
  pub fn makeMap(allocator: Allocator) !JsonValue {
86
88
  const mr = try allocator.create(MapRef);
87
- mr.* = .{ .data = MapData.init(allocator) };
89
+ mr.* = .{ .data = .empty, .allocator = allocator };
88
90
  return JsonValue{ .object = mr };
89
91
  }
90
92
 
@@ -106,10 +108,10 @@ pub fn fromStdJson(allocator: Allocator, jv: StdJsonValue) anyerror!JsonValue {
106
108
  .number_string => |s| JsonValue{ .number_string = s },
107
109
  .object => |obj| {
108
110
  const mr = try allocator.create(MapRef);
109
- mr.* = .{ .data = MapData.init(allocator) };
111
+ mr.* = .{ .data = .empty, .allocator = allocator };
110
112
  var it = obj.iterator();
111
113
  while (it.next()) |kv| {
112
- try mr.data.put(kv.key_ptr.*, try fromStdJson(allocator, kv.value_ptr.*));
114
+ try mr.data.put(allocator, kv.key_ptr.*, try fromStdJson(allocator, kv.value_ptr.*));
113
115
  }
114
116
  return JsonValue{ .object = mr };
115
117
  },
@@ -134,10 +136,10 @@ pub fn toStdJson(allocator: Allocator, v: JsonValue) anyerror!StdJsonValue {
134
136
  .string => |s| StdJsonValue{ .string = s },
135
137
  .number_string => |s| StdJsonValue{ .number_string = s },
136
138
  .object => |mr| {
137
- var obj = std.json.ObjectMap.init(allocator);
139
+ var obj: std.json.ObjectMap = .empty;
138
140
  var it = mr.data.iterator();
139
141
  while (it.next()) |kv| {
140
- try obj.put(kv.key_ptr.*, try toStdJson(allocator, kv.value_ptr.*));
142
+ try obj.put(allocator, kv.key_ptr.*, try toStdJson(allocator, kv.value_ptr.*));
141
143
  }
142
144
  return StdJsonValue{ .object = obj };
143
145
  },
@@ -227,7 +229,7 @@ pub const T_node: i32 = 1 << 6;
227
229
  // TYPENAME maps bit position (via leading zeros count) to type name string.
228
230
  pub const TYPENAME = [_][]const u8{
229
231
  S_any,
230
- S_noval,
232
+ S_nil,
231
233
  S_boolean,
232
234
  S_decimal,
233
235
  S_integer,
@@ -407,7 +409,7 @@ pub fn getelem(allocator: Allocator, val: JsonValue, key: JsonValue, alt: JsonVa
407
409
 
408
410
  // If alt is a function, call it to get the default value.
409
411
  fn resolveAlt(allocator: Allocator, alt: JsonValue) !JsonValue {
410
- if (alt == .function) return try alt.function.call(alt.function.ctx, allocator, JsonValue{ .null = {} });
412
+ if (alt == .function) return try alt.function(allocator);
411
413
  return alt;
412
414
  }
413
415
 
@@ -454,7 +456,7 @@ pub fn getprop(allocator: Allocator, val: JsonValue, key: JsonValue, alt: JsonVa
454
456
  pub fn keysof(allocator: Allocator, val: JsonValue) !JsonValue {
455
457
  if (val == .object) {
456
458
  const obj = val.object;
457
- var key_strs = try std.ArrayList([]const u8).initCapacity(allocator, obj.count());
459
+ var key_strs = try std.array_list.Managed([]const u8).initCapacity(allocator, obj.count());
458
460
  defer key_strs.deinit();
459
461
  var it = obj.iterator();
460
462
  while (it.next()) |kv| {
@@ -501,7 +503,7 @@ pub fn items(allocator: Allocator, val: JsonValue) !JsonValue {
501
503
  if (val == .object) {
502
504
  const obj = val.object;
503
505
  // Get sorted keys
504
- var key_strs = try std.ArrayList([]const u8).initCapacity(allocator, obj.count());
506
+ var key_strs = try std.array_list.Managed([]const u8).initCapacity(allocator, obj.count());
505
507
  defer key_strs.deinit();
506
508
  var it = obj.iterator();
507
509
  while (it.next()) |kv| {
@@ -594,8 +596,8 @@ pub fn clone(allocator: Allocator, val: JsonValue) !JsonValue {
594
596
  return switch (val) {
595
597
  .object => |obj| {
596
598
  const new_obj = try allocator.create(MapRef);
597
- new_obj.* = .{ .data = MapData.init(allocator) };
598
- try new_obj.data.ensureTotalCapacity(@intCast(obj.count()));
599
+ new_obj.* = .{ .data = .empty, .allocator = allocator };
600
+ try new_obj.data.ensureTotalCapacity(allocator, @intCast(obj.count()));
599
601
  var it = obj.iterator();
600
602
  while (it.next()) |kv| {
601
603
  const cloned_val = try clone(allocator, kv.value_ptr.*);
@@ -746,7 +748,7 @@ fn keyStr(buf: *[20]u8, key: JsonValue) []const u8 {
746
748
  // Escape regex special characters.
747
749
  pub fn escre(allocator: Allocator, s: []const u8) ![]const u8 {
748
750
  if (s.len == 0) return S_MT;
749
- var result = std.ArrayList(u8).init(allocator);
751
+ var result = std.array_list.Managed(u8).init(allocator);
750
752
  for (s) |c| {
751
753
  if (isReSpecial(c)) {
752
754
  try result.append('\\');
@@ -817,7 +819,7 @@ pub fn re_find(allocator: Allocator, pattern: []const u8, input: []const u8) ?[]
817
819
  pub fn re_find_all(allocator: Allocator, pattern: []const u8, input: []const u8) ?[][][]const u8 {
818
820
  var re = _re_engine.compile(std.heap.page_allocator, pattern) orelse return null;
819
821
  defer re.deinit();
820
- var rows = std.ArrayList([][]const u8).init(allocator);
822
+ var rows = std.array_list.Managed([][]const u8).init(allocator);
821
823
  defer rows.deinit();
822
824
  var pos: usize = 0;
823
825
  while (pos <= input.len) {
@@ -848,8 +850,8 @@ pub fn re_find_all(allocator: Allocator, pattern: []const u8, input: []const u8)
848
850
  }
849
851
 
850
852
  /// re_replace — replace every match in `input` with `replacement`. The
851
- /// replacement string is taken literally; $& / $1.. substitution is not
852
- /// expanded in this minimal wrapper (matches the engine's current shape).
853
+ /// replacement string supports JS-style refs: $& (whole match), $1..$9
854
+ /// (captures) and $$ (a literal $); anything else is copied verbatim.
853
855
  /// On zero-width match the current rune is emitted and we advance by one
854
856
  /// byte, mirroring the ECMAScript convention used by other ports.
855
857
  pub fn re_replace(allocator: Allocator, pattern: []const u8, input: []const u8, replacement: []const u8) ![]u8 {
@@ -857,7 +859,7 @@ pub fn re_replace(allocator: Allocator, pattern: []const u8, input: []const u8,
857
859
  return allocator.dupe(u8, input);
858
860
  };
859
861
  defer re.deinit();
860
- var out = std.ArrayList(u8).init(allocator);
862
+ var out = std.array_list.Managed(u8).init(allocator);
861
863
  defer out.deinit();
862
864
  var pos: usize = 0;
863
865
  while (pos <= input.len) {
@@ -869,7 +871,31 @@ pub fn re_replace(allocator: Allocator, pattern: []const u8, input: []const u8,
869
871
  const mstart = @as(usize, @intCast(slots[0]));
870
872
  const mend = @as(usize, @intCast(slots[1]));
871
873
  try out.appendSlice(input[pos..mstart]);
872
- try out.appendSlice(replacement);
874
+ var ri: usize = 0;
875
+ while (ri < replacement.len) {
876
+ const ch = replacement[ri];
877
+ if (ch == '$' and ri + 1 < replacement.len) {
878
+ const nc = replacement[ri + 1];
879
+ if (nc == '$') {
880
+ try out.append('$');
881
+ ri += 2;
882
+ continue;
883
+ } else if (nc == '&' or (nc >= '0' and nc <= '9')) {
884
+ const gi: usize = if (nc == '&') 0 else @as(usize, nc - '0');
885
+ if (gi < re.ngroups) {
886
+ const gs = slots[2 * gi];
887
+ const ge = slots[2 * gi + 1];
888
+ if (gs >= 0 and ge >= gs) {
889
+ try out.appendSlice(input[@as(usize, @intCast(gs))..@as(usize, @intCast(ge))]);
890
+ }
891
+ }
892
+ ri += 2;
893
+ continue;
894
+ }
895
+ }
896
+ try out.append(ch);
897
+ ri += 1;
898
+ }
873
899
  if (mend == mstart) {
874
900
  if (mstart < input.len) {
875
901
  try out.append(input[mstart]);
@@ -891,7 +917,7 @@ pub fn re_escape(allocator: Allocator, s: []const u8) ![]const u8 {
891
917
  // URL-encode a string.
892
918
  pub fn escurl(allocator: Allocator, s: []const u8) ![]const u8 {
893
919
  if (s.len == 0) return S_MT;
894
- var result = std.ArrayList(u8).init(allocator);
920
+ var result = std.array_list.Managed(u8).init(allocator);
895
921
  for (s) |c| {
896
922
  if (isUrlSafe(c)) {
897
923
  try result.append(c);
@@ -918,8 +944,8 @@ pub fn join(allocator: Allocator, arr: JsonValue, sep: []const u8, urlMode: bool
918
944
  const sarr: usize = items_list.len;
919
945
 
920
946
  // Filter to non-empty strings
921
- var filtered = std.ArrayList([]const u8).init(allocator);
922
- var indices = std.ArrayList(usize).init(allocator);
947
+ var filtered = std.array_list.Managed([]const u8).init(allocator);
948
+ var indices = std.array_list.Managed(usize).init(allocator);
923
949
  for (items_list, 0..) |item, orig_idx| {
924
950
  if (item == .string and item.string.len > 0) {
925
951
  try filtered.append(item.string);
@@ -930,7 +956,7 @@ pub fn join(allocator: Allocator, arr: JsonValue, sep: []const u8, urlMode: bool
930
956
  if (filtered.items.len == 0) return S_MT;
931
957
 
932
958
  // Process separator handling
933
- var parts = std.ArrayList([]const u8).init(allocator);
959
+ var parts = std.array_list.Managed([]const u8).init(allocator);
934
960
 
935
961
  for (filtered.items, 0..) |s, fi| {
936
962
  var processed = s;
@@ -967,7 +993,7 @@ pub fn join(allocator: Allocator, arr: JsonValue, sep: []const u8, urlMode: bool
967
993
  for (parts.items) |p| total_len += p.len;
968
994
  total_len += sep.len * (parts.items.len - 1);
969
995
 
970
- var result = try std.ArrayList(u8).initCapacity(allocator, total_len);
996
+ var result = try std.array_list.Managed(u8).initCapacity(allocator, total_len);
971
997
  for (parts.items, 0..) |p, i| {
972
998
  try result.appendSlice(p);
973
999
  if (i < parts.items.len - 1) {
@@ -993,7 +1019,7 @@ fn trimRight(s: []const u8, c: u8) []const u8 {
993
1019
  // E.g. "c//d" → "c/d" but "//a" stays "//a".
994
1020
  fn collapseInternal(allocator: Allocator, s: []const u8, sep: u8) ![]const u8 {
995
1021
  if (s.len < 3) return s;
996
- var result = std.ArrayList(u8).init(allocator);
1022
+ var result = std.array_list.Managed(u8).init(allocator);
997
1023
  var i: usize = 0;
998
1024
  while (i < s.len) {
999
1025
  try result.append(s[i]);
@@ -1021,9 +1047,9 @@ pub fn jsonify(allocator: Allocator, val: JsonValue, indent_size: usize, offset:
1021
1047
  if (val == .null) return "null";
1022
1048
 
1023
1049
  // Use the standard JSON stringify
1024
- var result = std.ArrayList(u8).init(allocator);
1025
- try jsonifyWrite(val, result.writer(), indent_size, offset, 0);
1026
- return result.items;
1050
+ var result: std.Io.Writer.Allocating = .init(allocator);
1051
+ try jsonifyWrite(val, &result.writer, indent_size, offset, 0);
1052
+ return result.written();
1027
1053
  }
1028
1054
 
1029
1055
  fn jsonifyWrite(val: JsonValue, writer: anytype, indent_size: usize, offset: usize, depth: usize) !void {
@@ -1110,9 +1136,9 @@ fn writeIndent(writer: anytype, count: usize) !void {
1110
1136
 
1111
1137
  // Compact JSON serialization (no whitespace) for partial injection stringification.
1112
1138
  pub fn jsonifyCompact(allocator: Allocator, val: JsonValue) ![]const u8 {
1113
- var result = std.ArrayList(u8).init(allocator);
1114
- try jsonifyCompactWrite(val, result.writer());
1115
- return result.items;
1139
+ var result: std.Io.Writer.Allocating = .init(allocator);
1140
+ try jsonifyCompactWrite(val, &result.writer);
1141
+ return result.written();
1116
1142
  }
1117
1143
 
1118
1144
  fn jsonifyCompactWrite(val: JsonValue, writer: anytype) !void {
@@ -1214,7 +1240,7 @@ fn stringifyColorInner(allocator: Allocator, val: JsonValue, depth: usize) ![]co
1214
1240
  break :blk try std.fmt.allocPrint(allocator, "{d}", .{f});
1215
1241
  },
1216
1242
  .array => |arr| blk: {
1217
- var result = std.ArrayList(u8).init(allocator);
1243
+ var result = std.array_list.Managed(u8).init(allocator);
1218
1244
  try result.appendSlice(open_color);
1219
1245
  try result.append('[');
1220
1246
  try result.appendSlice(reset);
@@ -1229,12 +1255,12 @@ fn stringifyColorInner(allocator: Allocator, val: JsonValue, depth: usize) ![]co
1229
1255
  break :blk result.items;
1230
1256
  },
1231
1257
  .object => |obj| blk: {
1232
- var key_list = std.ArrayList([]const u8).init(allocator);
1258
+ var key_list = std.array_list.Managed([]const u8).init(allocator);
1233
1259
  var it = obj.iterator();
1234
1260
  while (it.next()) |kv| try key_list.append(kv.key_ptr.*);
1235
1261
  std.mem.sort([]const u8, key_list.items, {}, stringLessThan);
1236
1262
 
1237
- var result = std.ArrayList(u8).init(allocator);
1263
+ var result = std.array_list.Managed(u8).init(allocator);
1238
1264
  try result.appendSlice(open_color);
1239
1265
  try result.append('{');
1240
1266
  try result.appendSlice(reset);
@@ -1269,7 +1295,7 @@ fn stringifyInner(allocator: Allocator, val: JsonValue) ![]const u8 {
1269
1295
  return try std.fmt.allocPrint(allocator, "{d}", .{f});
1270
1296
  },
1271
1297
  .array => |arr| {
1272
- var result = std.ArrayList(u8).init(allocator);
1298
+ var result = std.array_list.Managed(u8).init(allocator);
1273
1299
  try result.append('[');
1274
1300
  for (arr.data.items, 0..) |item, i| {
1275
1301
  const s = try stringifyInner(allocator, item);
@@ -1283,7 +1309,7 @@ fn stringifyInner(allocator: Allocator, val: JsonValue) ![]const u8 {
1283
1309
  },
1284
1310
  .object => |obj| {
1285
1311
  // Sort keys
1286
- var key_list = std.ArrayList([]const u8).init(allocator);
1312
+ var key_list = std.array_list.Managed([]const u8).init(allocator);
1287
1313
  defer key_list.deinit();
1288
1314
  var it = obj.iterator();
1289
1315
  while (it.next()) |kv| {
@@ -1291,7 +1317,7 @@ fn stringifyInner(allocator: Allocator, val: JsonValue) ![]const u8 {
1291
1317
  }
1292
1318
  std.mem.sort([]const u8, key_list.items, {}, stringLessThan);
1293
1319
 
1294
- var result = std.ArrayList(u8).init(allocator);
1320
+ var result = std.array_list.Managed(u8).init(allocator);
1295
1321
  try result.append('{');
1296
1322
  for (key_list.items, 0..) |k, i| {
1297
1323
  const v = obj.get(k).?;
@@ -1313,10 +1339,10 @@ fn stringifyInner(allocator: Allocator, val: JsonValue) ![]const u8 {
1313
1339
 
1314
1340
  // Build a human-friendly path string.
1315
1341
  pub fn pathify(allocator: Allocator, val: JsonValue, from: usize, end: usize) ![]const u8 {
1316
- var path: ?std.ArrayList([]const u8) = null;
1342
+ var path: ?std.array_list.Managed([]const u8) = null;
1317
1343
 
1318
1344
  if (val == .array) {
1319
- path = std.ArrayList([]const u8).init(allocator);
1345
+ path = std.array_list.Managed([]const u8).init(allocator);
1320
1346
  for (val.array.data.items) |item| {
1321
1347
  switch (item) {
1322
1348
  .string => |s| try path.?.append(s),
@@ -1326,10 +1352,10 @@ pub fn pathify(allocator: Allocator, val: JsonValue, from: usize, end: usize) ![
1326
1352
  }
1327
1353
  }
1328
1354
  } else if (val == .string) {
1329
- path = std.ArrayList([]const u8).init(allocator);
1355
+ path = std.array_list.Managed([]const u8).init(allocator);
1330
1356
  try path.?.append(val.string);
1331
1357
  } else if (val == .integer or val == .float) {
1332
- path = std.ArrayList([]const u8).init(allocator);
1358
+ path = std.array_list.Managed([]const u8).init(allocator);
1333
1359
  const num: i64 = if (val == .integer) val.integer else @intFromFloat(@floor(val.float));
1334
1360
  try path.?.append(try std.fmt.allocPrint(allocator, "{d}", .{num}));
1335
1361
  }
@@ -1345,9 +1371,9 @@ pub fn pathify(allocator: Allocator, val: JsonValue, from: usize, end: usize) ![
1345
1371
  }
1346
1372
 
1347
1373
  // Map: replace dots in string parts
1348
- var mapped = std.ArrayList([]const u8).init(allocator);
1374
+ var mapped = std.array_list.Managed([]const u8).init(allocator);
1349
1375
  for (sliced) |part| {
1350
- var replaced = std.ArrayList(u8).init(allocator);
1376
+ var replaced = std.array_list.Managed(u8).init(allocator);
1351
1377
  for (part) |c| {
1352
1378
  if (c != '.') try replaced.append(c);
1353
1379
  }
@@ -1355,7 +1381,7 @@ pub fn pathify(allocator: Allocator, val: JsonValue, from: usize, end: usize) ![
1355
1381
  }
1356
1382
 
1357
1383
  // Join with dots
1358
- var result = std.ArrayList(u8).init(allocator);
1384
+ var result = std.array_list.Managed(u8).init(allocator);
1359
1385
  for (mapped.items, 0..) |part, i| {
1360
1386
  try result.appendSlice(part);
1361
1387
  if (i < mapped.items.len - 1) {
@@ -1366,7 +1392,7 @@ pub fn pathify(allocator: Allocator, val: JsonValue, from: usize, end: usize) ![
1366
1392
  }
1367
1393
 
1368
1394
  // Unknown path — always include colon and stringified value
1369
- var result = std.ArrayList(u8).init(allocator);
1395
+ var result = std.array_list.Managed(u8).init(allocator);
1370
1396
  try result.appendSlice("<unknown-path:");
1371
1397
  const s = try stringify(allocator, val, 47);
1372
1398
  try result.appendSlice(s);
@@ -1492,19 +1518,19 @@ pub fn pad(allocator: Allocator, s: []const u8, padding: i64, padchar: u8) ![]co
1492
1518
  // Walk — depth-first tree traversal with before/after callbacks.
1493
1519
  // ============================================================================
1494
1520
 
1495
- // Pool of path buffers — one std.ArrayList([]const u8) per depth. Allocated
1521
+ // Pool of path buffers — one std.array_list.Managed([]const u8) per depth. Allocated
1496
1522
  // once per top-level walk() call, grown on demand, and mutated in place as
1497
1523
  // siblings are visited. Avoids allocating a fresh path slice per recursive
1498
1524
  // call. Buffers are heap-allocated so that growing the outer list (on
1499
1525
  // deeper recursion) does not invalidate pointers held by shallower frames.
1500
1526
  const WalkPool = struct {
1501
1527
  allocator: Allocator,
1502
- buffers: std.ArrayList(*std.ArrayList([]const u8)),
1528
+ buffers: std.array_list.Managed(*std.array_list.Managed([]const u8)),
1503
1529
 
1504
1530
  fn init(allocator: Allocator) WalkPool {
1505
1531
  return .{
1506
1532
  .allocator = allocator,
1507
- .buffers = std.ArrayList(*std.ArrayList([]const u8)).init(allocator),
1533
+ .buffers = std.array_list.Managed(*std.array_list.Managed([]const u8)).init(allocator),
1508
1534
  };
1509
1535
  }
1510
1536
 
@@ -1517,10 +1543,10 @@ const WalkPool = struct {
1517
1543
  }
1518
1544
 
1519
1545
  // Return the path buffer for the given depth, growing the pool if needed.
1520
- fn at(self: *WalkPool, depth: usize) !*std.ArrayList([]const u8) {
1546
+ fn at(self: *WalkPool, depth: usize) !*std.array_list.Managed([]const u8) {
1521
1547
  while (self.buffers.items.len <= depth) {
1522
- const buf = try self.allocator.create(std.ArrayList([]const u8));
1523
- buf.* = std.ArrayList([]const u8).init(self.allocator);
1548
+ const buf = try self.allocator.create(std.array_list.Managed([]const u8));
1549
+ buf.* = std.array_list.Managed([]const u8).init(self.allocator);
1524
1550
  try self.buffers.append(buf);
1525
1551
  }
1526
1552
  return self.buffers.items[depth];
@@ -1654,7 +1680,7 @@ pub fn merge(allocator: Allocator, val: JsonValue, maxdepth: i32) !JsonValue {
1654
1680
  if (islist(last)) return try JsonValue.makeList(allocator);
1655
1681
  if (ismap(last)) {
1656
1682
  const obj = try allocator.create(MapRef);
1657
- obj.* = .{ .data = MapData.init(allocator) };
1683
+ obj.* = .{ .data = .empty, .allocator = allocator };
1658
1684
  _ = &obj;
1659
1685
  return JsonValue{ .object = obj };
1660
1686
  }
@@ -1820,7 +1846,7 @@ pub fn getpathInj(allocator: Allocator, path_val: JsonValue, store: JsonValue, i
1820
1846
  if (store == .object) {
1821
1847
  if (store.object.get(parts[0])) |v| {
1822
1848
  // If the value is a function, call it.
1823
- if (v == .function) return try v.function.call(v.function.ctx, allocator, JsonValue{ .null = {} });
1849
+ if (v == .function) return try v.function(allocator);
1824
1850
  return v;
1825
1851
  }
1826
1852
  }
@@ -1908,7 +1934,7 @@ pub fn getpathInj(allocator: Allocator, path_val: JsonValue, store: JsonValue, i
1908
1934
  // Build full path from dpath minus ascends, plus remaining parts.
1909
1935
  const dpath = ij.dpath;
1910
1936
  const cutLen = if (ascends > dpath.len) 0 else dpath.len - ascends;
1911
- var fullpath = std.ArrayList([]const u8).init(allocator);
1937
+ var fullpath = std.array_list.Managed([]const u8).init(allocator);
1912
1938
  for (dpath[0..cutLen]) |dp| try fullpath.append(dp);
1913
1939
  if (pI + 1 < numparts) {
1914
1940
  for (parts[pI + 1 .. numparts]) |rp| try fullpath.append(rp);
@@ -1966,7 +1992,7 @@ fn resolvePart(allocator: Allocator, val: JsonValue, part_in: []const u8, inj: ?
1966
1992
  // Handle $$ escape → $.
1967
1993
  var part = part_in;
1968
1994
  if (std.mem.indexOf(u8, part, "$$")) |_| {
1969
- var buf = std.ArrayList(u8).init(allocator);
1995
+ var buf = std.array_list.Managed(u8).init(allocator);
1970
1996
  var i: usize = 0;
1971
1997
  while (i < part.len) {
1972
1998
  if (i + 1 < part.len and part[i] == '$' and part[i + 1] == '$') {
@@ -2121,7 +2147,7 @@ pub const Injection = struct {
2121
2147
  modify: ?ModifyFn = null,
2122
2148
 
2123
2149
  // Shared error collector (pointer so all children share it).
2124
- errs: *std.ArrayList([]const u8),
2150
+ errs: *std.array_list.Managed([]const u8),
2125
2151
 
2126
2152
  // Create a child injection for processing key at keys[key_i].
2127
2153
  pub fn child(self: *Injection, key_i: usize, keys: []const []const u8) !*Injection {
@@ -2248,16 +2274,16 @@ pub fn inject(allocator: Allocator, val: JsonValue, store: JsonValue, inj_opt: ?
2248
2274
  if (inj_opt == null or (inj_opt != null and inj_opt.?.mode == 0)) {
2249
2275
  // Root injection: wrap val in a virtual parent.
2250
2276
  const parent_obj = try allocator.create(MapRef);
2251
- parent_obj.* = .{ .data = MapData.init(allocator) };
2277
+ parent_obj.* = .{ .data = .empty, .allocator = allocator };
2252
2278
  try parent_obj.put(S_DTOP, val);
2253
2279
  const parent_val = JsonValue{ .object = parent_obj };
2254
2280
 
2255
- var errs: *std.ArrayList([]const u8) = undefined;
2281
+ var errs: *std.array_list.Managed([]const u8) = undefined;
2256
2282
  if (inj_opt) |existing| {
2257
2283
  errs = existing.errs;
2258
2284
  } else {
2259
- errs = try allocator.create(std.ArrayList([]const u8));
2260
- errs.* = std.ArrayList([]const u8).init(allocator);
2285
+ errs = try allocator.create(std.array_list.Managed([]const u8));
2286
+ errs.* = std.array_list.Managed([]const u8).init(allocator);
2261
2287
  }
2262
2288
 
2263
2289
  var init_keys = try allocator.alloc([]const u8, 1);
@@ -2303,8 +2329,8 @@ pub fn inject(allocator: Allocator, val: JsonValue, store: JsonValue, inj_opt: ?
2303
2329
 
2304
2330
  if (isnode(val)) {
2305
2331
  // Get sorted keys: normal first, then $ transform keys.
2306
- var normal_keys = std.ArrayList([]const u8).init(allocator);
2307
- var transform_keys = std.ArrayList([]const u8).init(allocator);
2332
+ var normal_keys = std.array_list.Managed([]const u8).init(allocator);
2333
+ var transform_keys = std.array_list.Managed([]const u8).init(allocator);
2308
2334
 
2309
2335
  const all_keys = try keysof(allocator, current);
2310
2336
  if (all_keys == .array) {
@@ -2319,7 +2345,7 @@ pub fn inject(allocator: Allocator, val: JsonValue, store: JsonValue, inj_opt: ?
2319
2345
  }
2320
2346
  }
2321
2347
 
2322
- var node_keys = std.ArrayList([]const u8).init(allocator);
2348
+ var node_keys = std.array_list.Managed([]const u8).init(allocator);
2323
2349
  for (normal_keys.items) |k| try node_keys.append(k);
2324
2350
  for (transform_keys.items) |k| try node_keys.append(k);
2325
2351
 
@@ -2340,7 +2366,7 @@ pub fn inject(allocator: Allocator, val: JsonValue, store: JsonValue, inj_opt: ?
2340
2366
  // Injection may modify child processing state.
2341
2367
  nkI = @as(isize, @bitCast(childinj.key_i));
2342
2368
  node_keys = blk: {
2343
- var nk = std.ArrayList([]const u8).init(allocator);
2369
+ var nk = std.array_list.Managed([]const u8).init(allocator);
2344
2370
  for (childinj.keys) |k| try nk.append(k);
2345
2371
  break :blk nk;
2346
2372
  };
@@ -2357,7 +2383,7 @@ pub fn inject(allocator: Allocator, val: JsonValue, store: JsonValue, inj_opt: ?
2357
2383
 
2358
2384
  nkI = @as(isize, @bitCast(childinj.key_i));
2359
2385
  node_keys = blk: {
2360
- var nk = std.ArrayList([]const u8).init(allocator);
2386
+ var nk = std.array_list.Managed([]const u8).init(allocator);
2361
2387
  for (childinj.keys) |k| try nk.append(k);
2362
2388
  break :blk nk;
2363
2389
  };
@@ -2369,7 +2395,7 @@ pub fn inject(allocator: Allocator, val: JsonValue, store: JsonValue, inj_opt: ?
2369
2395
 
2370
2396
  nkI = @as(isize, @bitCast(childinj.key_i));
2371
2397
  node_keys = blk: {
2372
- var nk = std.ArrayList([]const u8).init(allocator);
2398
+ var nk = std.array_list.Managed([]const u8).init(allocator);
2373
2399
  for (childinj.keys) |k| try nk.append(k);
2374
2400
  break :blk nk;
2375
2401
  };
@@ -2385,19 +2411,21 @@ pub fn inject(allocator: Allocator, val: JsonValue, store: JsonValue, inj_opt: ?
2385
2411
  if (!inj.skip and (result != .null or val != .null)) {
2386
2412
  _ = try inj.setval(result, 0);
2387
2413
  }
2388
- inj.skip = false;
2389
2414
  current = result;
2390
2415
  }
2391
2416
 
2392
2417
  inj.val = current;
2393
2418
 
2394
- // Call modify callback if set (skip suppresses modify too).
2419
+ // Call modify callback if set (skip suppresses modify too — the zig
2420
+ // spelling of the canonical `SKIP !== val` guard around both setval
2421
+ // and modify). Reset skip only after both checks have seen it.
2395
2422
  if (!inj.skip) {
2396
2423
  if (inj.modify) |modify_fn| {
2397
2424
  const mval = getprop(allocator, inj.parent, JsonValue{ .string = inj.key }, .null) catch .null;
2398
2425
  modify_fn(allocator, mval, inj.key, inj.parent, inj, store);
2399
2426
  }
2400
2427
  }
2428
+ inj.skip = false;
2401
2429
 
2402
2430
  // Return value is the top-level result.
2403
2431
  return try getprop(allocator, inj.parent, JsonValue{ .string = S_DTOP }, .null);
@@ -2432,7 +2460,7 @@ fn injectStr(allocator: Allocator, val: []const u8, store: JsonValue, inj: *Inje
2432
2460
 
2433
2461
  // Partial injection: replace each `ref` segment.
2434
2462
  inj.full = false;
2435
- var result = std.ArrayList(u8).init(allocator);
2463
+ var result = std.array_list.Managed(u8).init(allocator);
2436
2464
  var i: usize = 0;
2437
2465
  while (i < val.len) {
2438
2466
  if (val[i] == '`') {
@@ -2492,7 +2520,27 @@ fn resolvePathOrCmd(allocator: Allocator, pathref: []const u8, store: JsonValue,
2492
2520
  return try getpathInj(allocator, JsonValue{ .string = pathref }, store, inj);
2493
2521
  }
2494
2522
 
2495
- // Absolute path from store.
2523
+ // Validation metadata references carry an operator: `$~` injects the
2524
+ // resolved value, while `$=` rewrites the slot as an $EXACT validator
2525
+ // and revisits it. Other absolute paths retain ordinary getpath
2526
+ // semantics (notably the empty path resolves to $TOP, not the store).
2527
+ if (inj.validate_mode and
2528
+ (std.mem.indexOf(u8, pathref, "$~") != null or std.mem.indexOf(u8, pathref, "$=") != null))
2529
+ {
2530
+ const found = try getpathInj(allocator, JsonValue{ .string = pathref }, store, inj);
2531
+ if (std.mem.indexOf(u8, pathref, "$=") != null) {
2532
+ const exact = try allocator.create(ListRef);
2533
+ exact.* = .{ .data = ListData.init(allocator) };
2534
+ try exact.append(JsonValue{ .string = S_BEXACT });
2535
+ try exact.append(found);
2536
+ _ = try inj.setval(JsonValue{ .array = exact }, 0);
2537
+ inj.key_i = std.math.maxInt(usize);
2538
+ inj.skip = true;
2539
+ return .null;
2540
+ }
2541
+ return found;
2542
+ }
2543
+
2496
2544
  return try getpath(allocator, JsonValue{ .string = pathref }, store);
2497
2545
  }
2498
2546
 
@@ -2548,6 +2596,7 @@ fn dispatchCmd(allocator: Allocator, cmd: []const u8, store: JsonValue, inj: *In
2548
2596
  if (std.mem.eql(u8, cmd, "$DECIMAL")) return try cmdValidateType(allocator, inj, S_decimal, T_decimal);
2549
2597
  if (std.mem.eql(u8, cmd, "$BOOLEAN")) return try cmdValidateType(allocator, inj, S_boolean, T_boolean);
2550
2598
  if (std.mem.eql(u8, cmd, "$NULL")) return try cmdValidateType(allocator, inj, S_null, T_null);
2599
+ if (std.mem.eql(u8, cmd, "$NIL")) return try cmdValidateNil(allocator, inj);
2551
2600
  if (std.mem.eql(u8, cmd, "$OBJECT") or std.mem.eql(u8, cmd, "$MAP"))
2552
2601
  return try cmdValidateType(allocator, inj, S_map, T_map);
2553
2602
  if (std.mem.eql(u8, cmd, "$ARRAY") or std.mem.eql(u8, cmd, "$LIST"))
@@ -2562,7 +2611,7 @@ fn dispatchCmd(allocator: Allocator, cmd: []const u8, store: JsonValue, inj: *In
2562
2611
  if (store == .object) {
2563
2612
  if (store.object.get(cmd)) |val| {
2564
2613
  if (val == .function) {
2565
- return try val.function.call(val.function.ctx, allocator, JsonValue{ .null = {} });
2614
+ return try val.function(allocator);
2566
2615
  }
2567
2616
  return val;
2568
2617
  }
@@ -2701,12 +2750,23 @@ fn cmdValidateAny(inj: *Injection) JsonValue {
2701
2750
  return out;
2702
2751
  }
2703
2752
 
2753
+ fn cmdValidateNil(allocator: Allocator, inj: *Injection) anyerror!JsonValue {
2754
+ if (inj.mode != M_VAL) return .null;
2755
+ const out = getprop(allocator, inj.dparent, JsonValue{ .string = inj.key }, .null) catch .null;
2756
+ if (out != .null) {
2757
+ try inj.errs.append(try invalidTypeMsg(allocator, inj.path, S_nil, out));
2758
+ }
2759
+ _ = try inj.setval(out, 0);
2760
+ return out;
2761
+ }
2762
+
2704
2763
  fn cmdValidateOne(allocator: Allocator, inj: *Injection, _: JsonValue) anyerror!JsonValue {
2705
2764
  if (inj.mode != M_VAL) return .null;
2706
2765
  if (inj.parent != .array) return .null;
2707
2766
 
2708
2767
  // Skip remaining keys in the list.
2709
2768
  inj.key_i = inj.keys.len;
2769
+ inj.skip = true;
2710
2770
 
2711
2771
  const parent_items = inj.parent.array.data.items;
2712
2772
  if (parent_items.len < 2) return .null;
@@ -2721,29 +2781,61 @@ fn cmdValidateOne(allocator: Allocator, inj: *Injection, _: JsonValue) anyerror!
2721
2781
  // Try each alternative.
2722
2782
  const alts = parent_items[1..];
2723
2783
  for (alts) |alt| {
2724
- const terrs = std.ArrayList([]const u8).init(allocator);
2725
- const terrs_ptr = try allocator.create(std.ArrayList([]const u8));
2784
+ const terrs = std.array_list.Managed([]const u8).init(allocator);
2785
+ const terrs_ptr = try allocator.create(std.array_list.Managed([]const u8));
2726
2786
  terrs_ptr.* = terrs;
2727
2787
  _ = try validateWalk(allocator, alt, data_val, terrs_ptr, if (inj.path.len > 1) inj.path[1..] else inj.path);
2728
2788
  if (terrs_ptr.items.len == 0) return .null;
2729
2789
  }
2730
2790
 
2731
2791
  // No match — build error message.
2732
- var desc = std.ArrayList(u8).init(allocator);
2792
+ var desc = std.array_list.Managed(u8).init(allocator);
2733
2793
  for (alts, 0..) |alt, i| {
2734
2794
  if (i > 0) try desc.appendSlice(", ");
2735
2795
  try desc.appendSlice(try stringify(allocator, alt, null));
2736
2796
  }
2737
2797
  const prefix = if (alts.len > 1) "one of " else "";
2738
- try inj.errs.append(try invalidTypeMsg(allocator, inj.path, try std.fmt.allocPrint(allocator, "{s}{s}", .{ prefix, desc.items }), data_val));
2798
+ // Canonical does `inj.path = slice(inj.path, -1)`: $ONE wraps the value
2799
+ // in its parent, so the error belongs to the parent's path, not to the
2800
+ // list slot the command happens to occupy. Without this every message
2801
+ // carried a trailing `.0`.
2802
+ const reportpath = if (0 < inj.path.len) inj.path[0 .. inj.path.len - 1] else inj.path;
2803
+ const named = try transformNames(allocator, desc.items);
2804
+ try inj.errs.append(try invalidTypeMsg(allocator, reportpath, try std.fmt.allocPrint(allocator, "{s}{s}", .{ prefix, named }), data_val));
2739
2805
  return .null;
2740
2806
  }
2741
2807
 
2808
+ /// Canonical renders a validator description through R_TRANSFORM_NAME
2809
+ /// (/`\$([A-Z]+)`/g), lowercasing the captured name: the alternatives of
2810
+ /// `["`$ONE`","`$STRING`","`$NUMBER`"]` read back as "string, number", not
2811
+ /// as the spec literals. Applied to the joined description, so every
2812
+ /// command name inside it is rewritten.
2813
+ fn transformNames(allocator: Allocator, src: []const u8) ![]const u8 {
2814
+ var out = std.array_list.Managed(u8).init(allocator);
2815
+ var i: usize = 0;
2816
+ while (i < src.len) {
2817
+ // `$NAME` - backtick, dollar, one or more A-Z, backtick.
2818
+ if (src[i] == '`' and i + 2 < src.len and src[i + 1] == '$') {
2819
+ var j = i + 2;
2820
+ while (j < src.len and src[j] >= 'A' and src[j] <= 'Z') : (j += 1) {}
2821
+ if (j > i + 2 and j < src.len and src[j] == '`') {
2822
+ for (src[i + 2 .. j]) |c| try out.append(c - 'A' + 'a');
2823
+ i = j + 1;
2824
+ continue;
2825
+ }
2826
+ }
2827
+ try out.append(src[i]);
2828
+ i += 1;
2829
+ }
2830
+ return out.items;
2831
+ }
2832
+
2742
2833
  fn cmdValidateExactCmd(allocator: Allocator, inj: *Injection) anyerror!JsonValue {
2743
2834
  if (inj.mode != M_VAL) return .null;
2744
2835
  if (inj.parent != .array) return .null;
2745
2836
 
2746
2837
  inj.key_i = inj.keys.len;
2838
+ inj.skip = true;
2747
2839
 
2748
2840
  const parent_items = inj.parent.array.data.items;
2749
2841
  if (parent_items.len < 2) return .null;
@@ -2764,13 +2856,16 @@ fn cmdValidateExactCmd(allocator: Allocator, inj: *Injection) anyerror!JsonValue
2764
2856
  if (std.mem.eql(u8, sa, sb)) return .null;
2765
2857
  }
2766
2858
 
2767
- var desc = std.ArrayList(u8).init(allocator);
2859
+ var desc = std.array_list.Managed(u8).init(allocator);
2768
2860
  for (alts, 0..) |alt, i| {
2769
2861
  if (i > 0) try desc.appendSlice(", ");
2770
2862
  try desc.appendSlice(try stringify(allocator, alt, null));
2771
2863
  }
2772
2864
  const prefix = if (alts.len > 1) "one of " else "";
2773
- try inj.errs.append(try invalidTypeMsg(allocator, inj.path, try std.fmt.allocPrint(allocator, "exactly equal to {s}{s}", .{ prefix, desc.items }), data_val));
2865
+ // Same parent-path rule as $ONE above.
2866
+ const reportpath = if (0 < inj.path.len) inj.path[0 .. inj.path.len - 1] else inj.path;
2867
+ const root_prefix = if (1 < reportpath.len) "" else "value ";
2868
+ try inj.errs.append(try invalidTypeMsg(allocator, reportpath, try std.fmt.allocPrint(allocator, "{s}exactly equal to {s}{s}", .{ root_prefix, prefix, desc.items }), data_val));
2774
2869
  return .null;
2775
2870
  }
2776
2871
 
@@ -2825,8 +2920,27 @@ fn cmdValidateChildCmd(allocator: Allocator, inj: *Injection, store: JsonValue)
2825
2920
  while (li < dlen) : (li += 1) {
2826
2921
  try inj.parent.array.append(try clone(allocator, child));
2827
2922
  }
2828
- inj.key_i = 0;
2829
- return if (dlen > 0) dparent_val.array.data.items[0] else .null;
2923
+
2924
+ // NOTE: modifying inj! This extends the child value loop in inject
2925
+ // to cover every cloned child.
2926
+ var ckey_i: usize = inj.keys.len;
2927
+ while (ckey_i < inj.parent.array.data.items.len) : (ckey_i += 1) {
2928
+ const ckey = try strkey(allocator, JsonValue{ .integer = @intCast(ckey_i) });
2929
+ inj.keys = appendSlice(allocator, []const u8, inj.keys, ckey) catch inj.keys;
2930
+ }
2931
+
2932
+ // Restart the child value loop at the first element (the loop
2933
+ // increments its signed nkI counter on resume) so that the first
2934
+ // element is also validated against the child template. key_i is
2935
+ // usize: max-usize bit-casts to -1 in inject's nkI — the same wrap
2936
+ // idiom cmdRef already relies on.
2937
+ inj.key_i = std.math.maxInt(usize);
2938
+
2939
+ // Suppress setval (and modify) so the cloned child template stays
2940
+ // in place at the first element for the resumed loop to validate.
2941
+ // This is the zig spelling of the canonical `return SKIP`.
2942
+ inj.skip = true;
2943
+ return .null;
2830
2944
  }
2831
2945
 
2832
2946
  return .null;
@@ -2870,7 +2984,7 @@ fn cmdFormat(allocator: Allocator, inj: *Injection, store: JsonValue) !JsonValue
2870
2984
  return out;
2871
2985
  }
2872
2986
 
2873
- fn applyFormat(allocator: Allocator, name: []const u8, val: JsonValue, errs: *std.ArrayList([]const u8)) !JsonValue {
2987
+ fn applyFormat(allocator: Allocator, name: []const u8, val: JsonValue, errs: *std.array_list.Managed([]const u8)) !JsonValue {
2874
2988
  if (std.mem.eql(u8, name, "upper")) return try walkFormat(allocator, val, fmtUpper);
2875
2989
  if (std.mem.eql(u8, name, "lower")) return try walkFormat(allocator, val, fmtLower);
2876
2990
  if (std.mem.eql(u8, name, "string")) return try walkFormat(allocator, val, fmtString);
@@ -2879,7 +2993,7 @@ fn applyFormat(allocator: Allocator, name: []const u8, val: JsonValue, errs: *st
2879
2993
  if (std.mem.eql(u8, name, "identity")) return val;
2880
2994
  if (std.mem.eql(u8, name, "concat")) {
2881
2995
  if (val == .array) {
2882
- var buf = std.ArrayList(u8).init(allocator);
2996
+ var buf = std.array_list.Managed(u8).init(allocator);
2883
2997
  for (val.array.data.items) |item| {
2884
2998
  if (isnode(item)) continue;
2885
2999
  try buf.appendSlice(try fmtStr(allocator, item));
@@ -2898,7 +3012,7 @@ const FormatFn = *const fn (Allocator, JsonValue) anyerror!JsonValue;
2898
3012
  fn walkFormat(allocator: Allocator, val: JsonValue, fmt_fn: FormatFn) !JsonValue {
2899
3013
  if (val == .object) {
2900
3014
  const new_obj = try allocator.create(MapRef);
2901
- new_obj.* = .{ .data = MapData.init(allocator) };
3015
+ new_obj.* = .{ .data = .empty, .allocator = allocator };
2902
3016
  var it = val.object.iterator();
2903
3017
  while (it.next()) |kv| {
2904
3018
  try new_obj.put(kv.key_ptr.*, try walkFormat(allocator, kv.value_ptr.*, fmt_fn));
@@ -3009,9 +3123,9 @@ fn cmdEach(allocator: Allocator, inj: *Injection, store: JsonValue) !JsonValue {
3009
3123
  JsonValue{ .null = {} };
3010
3124
 
3011
3125
  // Build source value list and key list.
3012
- var src_vals = std.ArrayList(JsonValue).init(allocator);
3013
- var src_keys = std.ArrayList([]const u8).init(allocator);
3014
- var tval_items = std.ArrayList(JsonValue).init(allocator);
3126
+ var src_vals = std.array_list.Managed(JsonValue).init(allocator);
3127
+ var src_keys = std.array_list.Managed([]const u8).init(allocator);
3128
+ var tval_items = std.array_list.Managed(JsonValue).init(allocator);
3015
3129
 
3016
3130
  if (islist(src)) {
3017
3131
  for (src.array.data.items, 0..) |src_item, idx| {
@@ -3031,7 +3145,7 @@ fn cmdEach(allocator: Allocator, inj: *Injection, store: JsonValue) !JsonValue {
3031
3145
  // Add $ANNO with $KEY for map sources.
3032
3146
  if (cclone == .object) {
3033
3147
  const anno = try allocator.create(MapRef);
3034
- anno.* = .{ .data = MapData.init(allocator) };
3148
+ anno.* = .{ .data = .empty, .allocator = allocator };
3035
3149
  try anno.put(S_KEY, pair.array.data.items[0]);
3036
3150
  _ = try setprop(allocator, cclone, JsonValue{ .string = S_BANNO }, JsonValue{ .object = anno });
3037
3151
  }
@@ -3050,7 +3164,7 @@ fn cmdEach(allocator: Allocator, inj: *Injection, store: JsonValue) !JsonValue {
3050
3164
  // Build per-item store: original store + $TOP = src_item.
3051
3165
  // Also merge root data keys for ancestor path access.
3052
3166
  const each_store = try allocator.create(MapRef);
3053
- each_store.* = .{ .data = MapData.init(allocator) };
3167
+ each_store.* = .{ .data = .empty, .allocator = allocator };
3054
3168
  if (store == .object) {
3055
3169
  var sit = store.object.iterator();
3056
3170
  while (sit.next()) |kv| try each_store.put(kv.key_ptr.*, kv.value_ptr.*);
@@ -3100,8 +3214,8 @@ fn cmdPack(allocator: Allocator, inj: *Injection, store: JsonValue) !JsonValue {
3100
3214
  try getpath(allocator, JsonValue{ .string = srcpath }, store);
3101
3215
 
3102
3216
  // Normalize source to list.
3103
- var src_list = std.ArrayList(JsonValue).init(allocator);
3104
- var src_keys = std.ArrayList([]const u8).init(allocator);
3217
+ var src_list = std.array_list.Managed(JsonValue).init(allocator);
3218
+ var src_keys = std.array_list.Managed([]const u8).init(allocator);
3105
3219
  var src_is_map = false;
3106
3220
 
3107
3221
  if (islist(src_raw)) {
@@ -3149,7 +3263,7 @@ fn cmdPack(allocator: Allocator, inj: *Injection, store: JsonValue) !JsonValue {
3149
3263
 
3150
3264
  // Build the output map.
3151
3265
  const result_obj = try allocator.create(MapRef);
3152
- result_obj.* = .{ .data = MapData.init(allocator) };
3266
+ result_obj.* = .{ .data = .empty, .allocator = allocator };
3153
3267
  for (src_list.items, 0..) |src_item, idx| {
3154
3268
  // Resolve the key for this item.
3155
3269
  var item_key: []const u8 = "";
@@ -3158,7 +3272,7 @@ fn cmdPack(allocator: Allocator, inj: *Injection, store: JsonValue) !JsonValue {
3158
3272
  if (std.mem.startsWith(u8, kp, "`")) {
3159
3273
  // Backtick path: inject to resolve.
3160
3274
  const key_store = try allocator.create(MapRef);
3161
- key_store.* = .{ .data = MapData.init(allocator) };
3275
+ key_store.* = .{ .data = .empty, .allocator = allocator };
3162
3276
  if (store == .object) {
3163
3277
  var sit = store.object.iterator();
3164
3278
  while (sit.next()) |kv| try key_store.put(kv.key_ptr.*, kv.value_ptr.*);
@@ -3181,7 +3295,7 @@ fn cmdPack(allocator: Allocator, inj: *Injection, store: JsonValue) !JsonValue {
3181
3295
 
3182
3296
  // Build per-item store.
3183
3297
  const item_store = try allocator.create(MapRef);
3184
- item_store.* = .{ .data = MapData.init(allocator) };
3298
+ item_store.* = .{ .data = .empty, .allocator = allocator };
3185
3299
  if (store == .object) {
3186
3300
  var sit = store.object.iterator();
3187
3301
  while (sit.next()) |kv| try item_store.put(kv.key_ptr.*, kv.value_ptr.*);
@@ -3193,7 +3307,7 @@ fn cmdPack(allocator: Allocator, inj: *Injection, store: JsonValue) !JsonValue {
3193
3307
  // use the resolved item_key (supports $KEY=$COPY → "a" not "0").
3194
3308
  if (child_clone == .object) {
3195
3309
  const anno = try allocator.create(MapRef);
3196
- anno.* = .{ .data = MapData.init(allocator) };
3310
+ anno.* = .{ .data = .empty, .allocator = allocator };
3197
3311
  const anno_val = if (src_is_map)
3198
3312
  JsonValue{ .string = src_keys.items[idx] }
3199
3313
  else
@@ -3204,7 +3318,7 @@ fn cmdPack(allocator: Allocator, inj: *Injection, store: JsonValue) !JsonValue {
3204
3318
 
3205
3319
  // Build dpath for ancestor path resolution using the ORIGINAL store,
3206
3320
  // so `...v100` can resolve back to the root data.
3207
- var dpath_list = std.ArrayList([]const u8).init(allocator);
3321
+ var dpath_list = std.array_list.Managed([]const u8).init(allocator);
3208
3322
  try dpath_list.append(S_DTOP);
3209
3323
  if (srcpath.len > 0) {
3210
3324
  var spit = std.mem.splitScalar(u8, srcpath, '.');
@@ -3218,17 +3332,17 @@ fn cmdPack(allocator: Allocator, inj: *Injection, store: JsonValue) !JsonValue {
3218
3332
 
3219
3333
  // Wrap: {tkey: {src_key: src_item}} so dparent descent works.
3220
3334
  const inner_wrap = try allocator.create(MapRef);
3221
- inner_wrap.* = .{ .data = MapData.init(allocator) };
3335
+ inner_wrap.* = .{ .data = .empty, .allocator = allocator };
3222
3336
  try inner_wrap.put(src_keys.items[idx], src_item);
3223
3337
  const outer_wrap = try allocator.create(MapRef);
3224
- outer_wrap.* = .{ .data = MapData.init(allocator) };
3338
+ outer_wrap.* = .{ .data = .empty, .allocator = allocator };
3225
3339
  try outer_wrap.put(tkey, JsonValue{ .object = inner_wrap });
3226
3340
 
3227
3341
  // Build per-item store: merge original root data keys into the
3228
3342
  // store alongside $TOP = src_item. This way `$COPY` gets the item
3229
3343
  // (via $TOP) and `...v100` can find v100 as a direct store key.
3230
3344
  const pack_store = try allocator.create(MapRef);
3231
- pack_store.* = .{ .data = MapData.init(allocator) };
3345
+ pack_store.* = .{ .data = .empty, .allocator = allocator };
3232
3346
  if (store == .object) {
3233
3347
  var sit = store.object.iterator();
3234
3348
  while (sit.next()) |kv| try pack_store.put(kv.key_ptr.*, kv.value_ptr.*);
@@ -3333,7 +3447,7 @@ fn cmdRef(allocator: Allocator, inj: *Injection, store: JsonValue) !JsonValue {
3333
3447
 
3334
3448
  // Resolve data at these paths.
3335
3449
  const tcur = if (cpath.len > 0) blk: {
3336
- var joined = std.ArrayList(u8).init(allocator);
3450
+ var joined = std.array_list.Managed(u8).init(allocator);
3337
3451
  for (cpath, 0..) |p, pi| {
3338
3452
  if (pi > 0) try joined.append('.');
3339
3453
  try joined.appendSlice(p);
@@ -3379,7 +3493,7 @@ fn cmdRef(allocator: Allocator, inj: *Injection, store: JsonValue) !JsonValue {
3379
3493
  tpath;
3380
3494
  const tval_at: JsonValue = blk2: {
3381
3495
  if (tpath_strip.len == 0) break :blk2 store;
3382
- var joined = std.ArrayList(u8).init(allocator);
3496
+ var joined = std.array_list.Managed(u8).init(allocator);
3383
3497
  for (tpath_strip, 0..) |p, pi| {
3384
3498
  if (pi > 0) joined.append('.') catch break :blk2 .null;
3385
3499
  joined.appendSlice(p) catch break :blk2 .null;
@@ -3475,7 +3589,7 @@ pub fn checkPlacement(
3475
3589
  inj: *Injection,
3476
3590
  ) !bool {
3477
3591
  if ((modes & inj.mode) == 0) {
3478
- var expected = std.ArrayList(u8).init(allocator);
3592
+ var expected = std.array_list.Managed(u8).init(allocator);
3479
3593
  var first = true;
3480
3594
  for ([_]i32{ M_KEYPRE, M_KEYPOST, M_VAL }) |m| {
3481
3595
  if ((modes & m) != 0) {
@@ -3530,7 +3644,7 @@ fn injectChild(allocator: Allocator, child_raw: JsonValue, store: JsonValue, inj
3530
3644
 
3531
3645
  // Build store with correct data context.
3532
3646
  const child_store = try allocator.create(MapRef);
3533
- child_store.* = .{ .data = MapData.init(allocator) };
3647
+ child_store.* = .{ .data = .empty, .allocator = allocator };
3534
3648
  if (store == .object) {
3535
3649
  var sit = store.object.iterator();
3536
3650
  while (sit.next()) |kv| try child_store.put(kv.key_ptr.*, kv.value_ptr.*);
@@ -3546,8 +3660,15 @@ fn injectChild(allocator: Allocator, child_raw: JsonValue, store: JsonValue, inj
3546
3660
  // Transform — public API. Builds store and calls Inject.
3547
3661
  // ============================================================================
3548
3662
 
3549
- pub fn transform(allocator: Allocator, data: JsonValue, spec: JsonValue) !JsonValue {
3550
- if (spec == .null) return spec;
3663
+ /// Canonical `transform` collects injection errors and throws
3664
+ /// `join(errs, ' | ')` when any were collected. This port passed `null` for
3665
+ /// the injection, so no `errs` list existed, nothing was ever collected and
3666
+ /// nothing could be reported - `transform/apply` and `transform/format` had
3667
+ /// no way to produce the messages the corpus asserts. The error channel is
3668
+ /// the same one `validate` already uses: a message beside the value, since
3669
+ /// a Zig error carries no payload.
3670
+ pub fn transform(allocator: Allocator, data: JsonValue, spec: JsonValue) anyerror!struct { out: JsonValue, err: ?[]const u8 } {
3671
+ if (spec == .null) return .{ .out = spec, .err = null };
3551
3672
 
3552
3673
  const spec_clone = try clone(allocator, spec);
3553
3674
  const data_clone = if (data == .null) JsonValue{ .null = {} } else try clone(allocator, data);
@@ -3556,12 +3677,38 @@ pub fn transform(allocator: Allocator, data: JsonValue, spec: JsonValue) !JsonVa
3556
3677
  const orig_spec = try clone(allocator, spec);
3557
3678
 
3558
3679
  const store = try allocator.create(MapRef);
3559
- store.* = .{ .data = MapData.init(allocator) };
3680
+ store.* = .{ .data = .empty, .allocator = allocator };
3560
3681
  try store.put(S_DTOP, data_clone);
3561
3682
  try store.put(S_DSPEC, orig_spec);
3683
+
3684
+ const errs = try allocator.create(std.array_list.Managed([]const u8));
3685
+ errs.* = std.array_list.Managed([]const u8).init(allocator);
3686
+ try store.put(S_DERRS, JsonValue{ .null = {} });
3687
+
3562
3688
  const store_val = JsonValue{ .object = store };
3563
3689
 
3564
- return try inject(allocator, spec_clone, store_val, null);
3690
+ const inj_init = try allocator.create(Injection);
3691
+ inj_init.* = Injection{
3692
+ .allocator = allocator,
3693
+ .mode = 0, // triggers root init
3694
+ .keys = try allocator.alloc([]const u8, 0),
3695
+ .path = try allocator.alloc([]const u8, 0),
3696
+ .nodes = try allocator.alloc(JsonValue, 0),
3697
+ .dpath = try allocator.alloc([]const u8, 0),
3698
+ .errs = errs,
3699
+ };
3700
+
3701
+ const result = try inject(allocator, spec_clone, store_val, inj_init);
3702
+
3703
+ if (0 < errs.items.len) {
3704
+ var msg = std.array_list.Managed(u8).init(allocator);
3705
+ for (errs.items, 0..) |e, i| {
3706
+ if (0 < i) try msg.appendSlice(" | ");
3707
+ try msg.appendSlice(e);
3708
+ }
3709
+ return .{ .out = result, .err = msg.items };
3710
+ }
3711
+ return .{ .out = result, .err = null };
3565
3712
  }
3566
3713
 
3567
3714
  // Transform with a modify callback applied after each injection step.
@@ -3573,7 +3720,7 @@ pub fn transformModify(allocator: Allocator, data: JsonValue, spec: JsonValue, m
3573
3720
  const orig_spec = try clone(allocator, spec);
3574
3721
 
3575
3722
  const store = try allocator.create(MapRef);
3576
- store.* = .{ .data = MapData.init(allocator) };
3723
+ store.* = .{ .data = .empty, .allocator = allocator };
3577
3724
  try store.put(S_DTOP, data_clone);
3578
3725
  try store.put(S_DSPEC, orig_spec);
3579
3726
  const store_val = JsonValue{ .object = store };
@@ -3584,8 +3731,8 @@ pub fn transformModify(allocator: Allocator, data: JsonValue, spec: JsonValue, m
3584
3731
  const empty_path = try allocator.alloc([]const u8, 0);
3585
3732
  const empty_nodes = try allocator.alloc(JsonValue, 0);
3586
3733
  const empty_dpath = try allocator.alloc([]const u8, 0);
3587
- const errs = try allocator.create(std.ArrayList([]const u8));
3588
- errs.* = std.ArrayList([]const u8).init(allocator);
3734
+ const errs = try allocator.create(std.array_list.Managed([]const u8));
3735
+ errs.* = std.array_list.Managed([]const u8).init(allocator);
3589
3736
  inj_init.* = Injection{
3590
3737
  .allocator = allocator,
3591
3738
  .mode = 0, // triggers root initialization in inject
@@ -3615,7 +3762,7 @@ fn resolveSpecialEscapes(allocator: Allocator, pathref: []const u8) []const u8 {
3615
3762
  if (pathref.len <= 3) return pathref;
3616
3763
  if (std.mem.indexOf(u8, pathref, "$BT") == null and
3617
3764
  std.mem.indexOf(u8, pathref, "$DS") == null) return pathref;
3618
- var result = std.ArrayList(u8).init(allocator);
3765
+ var result = std.array_list.Managed(u8).init(allocator);
3619
3766
  var i: usize = 0;
3620
3767
  while (i < pathref.len) {
3621
3768
  if (i + 3 <= pathref.len and std.mem.eql(u8, pathref[i .. i + 3], "$BT")) {
@@ -3639,22 +3786,34 @@ fn resolveSpecialEscapes(allocator: Allocator, pathref: []const u8) []const u8 {
3639
3786
  // Uses the transform/inject infrastructure with type-checking commands.
3640
3787
  // ============================================================================
3641
3788
 
3642
- pub fn validate(allocator: Allocator, data: JsonValue, spec: JsonValue) anyerror!struct { out: JsonValue, err: ?[]const u8 } {
3789
+ // NAMED, not anonymous. Two `struct { ... }` written out separately are two
3790
+ // DISTINCT types in Zig even when their fields match, so while `validate` and
3791
+ // `validateWith` each declared their own, `validate`'s one-line delegation
3792
+ // could not compile: "error union payload cannot cast into error union
3793
+ // payload". Zig analyses lazily, so nothing noticed until a caller appeared -
3794
+ // the SDK's zig target was the first. Fails identically on 0.13 and 0.16.
3795
+ pub const ValidateResult = struct { out: JsonValue, err: ?[]const u8 };
3796
+
3797
+ pub fn validate(allocator: Allocator, data: JsonValue, spec: JsonValue) anyerror!ValidateResult {
3798
+ return validateWith(allocator, data, spec, .null);
3799
+ }
3800
+
3801
+ pub fn validateWith(allocator: Allocator, data: JsonValue, spec: JsonValue, injdef: JsonValue) anyerror!ValidateResult {
3643
3802
  const spec_clone = try clone(allocator, spec);
3644
3803
  const data_clone = if (data == .null) JsonValue{ .null = {} } else try clone(allocator, data);
3645
3804
  const orig_spec = try clone(allocator, spec);
3646
3805
 
3647
3806
  // Build store with data and spec.
3648
3807
  const store = try allocator.create(MapRef);
3649
- store.* = .{ .data = MapData.init(allocator) };
3808
+ store.* = .{ .data = .empty, .allocator = allocator };
3650
3809
  try store.put(S_DTOP, data_clone);
3651
3810
  try store.put(S_DSPEC, orig_spec);
3652
3811
  const store_val = JsonValue{ .object = store };
3653
3812
 
3654
3813
  // Create root injection with validate_mode enabled.
3655
3814
  // This causes dispatchCmd to handle $STRING, $NUMBER, etc.
3656
- const errs = try allocator.create(std.ArrayList([]const u8));
3657
- errs.* = std.ArrayList([]const u8).init(allocator);
3815
+ const errs = try allocator.create(std.array_list.Managed([]const u8));
3816
+ errs.* = std.array_list.Managed([]const u8).init(allocator);
3658
3817
 
3659
3818
  const inj_init = try allocator.create(Injection);
3660
3819
  inj_init.* = Injection{
@@ -3668,12 +3827,23 @@ pub fn validate(allocator: Allocator, data: JsonValue, spec: JsonValue) anyerror
3668
3827
  .dpath = try allocator.alloc([]const u8, 0),
3669
3828
  .errs = errs,
3670
3829
  };
3830
+ if (injdef == .object) {
3831
+ inj_init.meta = injdef.object.get("meta") orelse .null;
3832
+ if (inj_init.meta == .object) {
3833
+ if (inj_init.meta.object.get(S_BEXACT)) |exact| {
3834
+ inj_init.exact_mode = exact == .bool and exact.bool;
3835
+ }
3836
+ }
3837
+ }
3671
3838
 
3672
3839
  const result = try inject(allocator, spec_clone, store_val, inj_init);
3673
3840
 
3674
3841
  if (errs.items.len > 0) {
3675
- var msg = std.ArrayList(u8).init(allocator);
3676
- try msg.appendSlice("Invalid data: ");
3842
+ // Canonical is `throw new Error(join(errs, ' | '))` - the collected
3843
+ // messages and nothing else. This port prefixed "Invalid data: ",
3844
+ // which no other port emits and which the corpus's validate/invalid
3845
+ // entries do not expect.
3846
+ var msg = std.array_list.Managed(u8).init(allocator);
3677
3847
  for (errs.items, 0..) |e, i| {
3678
3848
  if (i > 0) try msg.appendSlice(" | ");
3679
3849
  try msg.appendSlice(e);
@@ -3728,17 +3898,22 @@ fn validationModify(allocator: Allocator, _: JsonValue, key: []const u8, parent:
3728
3898
  // Closed: report unexpected keys.
3729
3899
  const ckeys = keysof(allocator, cval) catch return;
3730
3900
  if (ckeys == .array) {
3731
- var bad = std.ArrayList([]const u8).init(allocator);
3901
+ var bad = std.array_list.Managed([]const u8).init(allocator);
3732
3902
  for (ckeys.array.data.items) |ck| {
3733
3903
  if (ck != .string) continue;
3734
- if (!((pval == .object) and (pval.object.get(ck.string) != null))) {
3904
+ // Literal presence: the shape DECLARES ck even when its value
3905
+ // is JSON null. Canonical uses `NONE === _lookup`; haskey is
3906
+ // Group A (value-based) and would drop records with a null
3907
+ // field from an open ($AND) select. Test object key presence.
3908
+ const present = (pval == .object) and (pval.object.get(ck.string) != null);
3909
+ if (!present) {
3735
3910
  bad.append(ck.string) catch {};
3736
3911
  }
3737
3912
  }
3738
3913
  if (bad.items.len > 0) {
3739
- var badmsg = std.ArrayList(u8).init(allocator);
3914
+ var badmsg = std.array_list.Managed(u8).init(allocator);
3740
3915
  badmsg.appendSlice("Unexpected keys at field ") catch {};
3741
- badmsg.appendSlice(pathifySlice(allocator, if (inj.path.len > 1) inj.path[1..] else inj.path) catch "<root>") catch {};
3916
+ badmsg.appendSlice(pathifySlice(allocator, inj.path[1..]) catch "<root>") catch {};
3742
3917
  badmsg.appendSlice(": ") catch {};
3743
3918
  for (bad.items, 0..) |bk, bi| {
3744
3919
  if (bi > 0) badmsg.appendSlice(", ") catch {};
@@ -3759,8 +3934,11 @@ fn validationModify(allocator: Allocator, _: JsonValue, key: []const u8, parent:
3759
3934
  const a = toStdJson(allocator, cval) catch return;
3760
3935
  const b = toStdJson(allocator, pval) catch return;
3761
3936
  if (!stdJsonEqual(a, b)) {
3762
- const p = pathifySlice(allocator, if (inj.path.len > 1) inj.path[1..] else inj.path) catch "<root>";
3763
- inj.errs.append(std.fmt.allocPrint(allocator, "Value at {s}: {s} should equal {s}.", .{ p, stringify(allocator, cval, null) catch "?", stringify(allocator, pval, null) catch "?" }) catch "exact match error") catch {};
3937
+ const pathmsg = if (1 < inj.path.len)
3938
+ std.fmt.allocPrint(allocator, "at field {s}: ", .{pathifySlice(allocator, inj.path[1..]) catch "<root>"}) catch ""
3939
+ else
3940
+ "";
3941
+ inj.errs.append(std.fmt.allocPrint(allocator, "Value {s}{s} should equal {s}.", .{ pathmsg, stringify(allocator, cval, null) catch "?", stringify(allocator, pval, null) catch "?" }) catch "exact match error") catch {};
3764
3942
  }
3765
3943
  } else {
3766
3944
  // Non-exact: copy data value into spec result.
@@ -3773,7 +3951,7 @@ fn validateWalk(
3773
3951
  allocator: Allocator,
3774
3952
  spec_val: JsonValue,
3775
3953
  data_val: JsonValue,
3776
- errs: *std.ArrayList([]const u8),
3954
+ errs: *std.array_list.Managed([]const u8),
3777
3955
  path: []const []const u8,
3778
3956
  ) anyerror!JsonValue {
3779
3957
  // Type command strings: `$STRING`, `$NUMBER` etc resolve to type checks.
@@ -3869,7 +4047,7 @@ fn validateTypeCheck(
3869
4047
  allocator: Allocator,
3870
4048
  cmd: []const u8,
3871
4049
  data_val: JsonValue,
3872
- errs: *std.ArrayList([]const u8),
4050
+ errs: *std.array_list.Managed([]const u8),
3873
4051
  path: []const []const u8,
3874
4052
  ) anyerror!JsonValue {
3875
4053
  const t = typify(data_val);
@@ -3939,12 +4117,12 @@ fn validateOne(
3939
4117
  allocator: Allocator,
3940
4118
  spec_val: JsonValue,
3941
4119
  data_val: JsonValue,
3942
- errs: *std.ArrayList([]const u8),
4120
+ errs: *std.array_list.Managed([]const u8),
3943
4121
  path: []const []const u8,
3944
4122
  ) anyerror!JsonValue {
3945
4123
  const alts = spec_val.array.data.items[1..];
3946
4124
  for (alts) |alt| {
3947
- var terrs = std.ArrayList([]const u8).init(allocator);
4125
+ var terrs = std.array_list.Managed([]const u8).init(allocator);
3948
4126
  _ = try validateWalk(allocator, alt, data_val, &terrs, path);
3949
4127
  if (terrs.items.len == 0) return data_val;
3950
4128
  }
@@ -3958,7 +4136,7 @@ fn validateExact(
3958
4136
  allocator: Allocator,
3959
4137
  spec_val: JsonValue,
3960
4138
  data_val: JsonValue,
3961
- errs: *std.ArrayList([]const u8),
4139
+ errs: *std.array_list.Managed([]const u8),
3962
4140
  path: []const []const u8,
3963
4141
  ) anyerror!JsonValue {
3964
4142
  const alts = spec_val.array.data.items[1..];
@@ -3981,7 +4159,7 @@ fn validateChild(
3981
4159
  allocator: Allocator,
3982
4160
  spec_val: JsonValue,
3983
4161
  data_val: JsonValue,
3984
- errs: *std.ArrayList([]const u8),
4162
+ errs: *std.array_list.Managed([]const u8),
3985
4163
  path: []const []const u8,
3986
4164
  ) anyerror!JsonValue {
3987
4165
  // [$CHILD, template] — validate each element of data array.
@@ -4006,7 +4184,7 @@ fn validateChildMap(
4006
4184
  allocator: Allocator,
4007
4185
  child_spec: JsonValue,
4008
4186
  data_val: JsonValue,
4009
- errs: *std.ArrayList([]const u8),
4187
+ errs: *std.array_list.Managed([]const u8),
4010
4188
  path: []const []const u8,
4011
4189
  ) anyerror!JsonValue {
4012
4190
  if (data_val != .object) {
@@ -4023,22 +4201,43 @@ fn validateChildMap(
4023
4201
  return data_val;
4024
4202
  }
4025
4203
 
4204
+ /// Canonical `_invalidTypeMsg`:
4205
+ ///
4206
+ /// 'Expected ' +
4207
+ /// (1 < size(path) ? 'field ' + pathify(path, 1) + ' to be ' : '') +
4208
+ /// needtype + ', but found ' +
4209
+ /// (null != v ? typename(vt) + S_VIZ : '') + vs + '.'
4210
+ ///
4211
+ /// Three things this port had wrong, all of them invisible while the driver
4212
+ /// discarded validate's message: the needtype was emitted TWICE (once before
4213
+ /// the field clause and once inside it); the path was rendered whole, so
4214
+ /// every message carried the `$TOP` root element canonical drops with
4215
+ /// `pathify(path, 1)`; and a null value was reported as `null: null` rather
4216
+ /// than `no value`, and only at the root.
4026
4217
  fn invalidTypeMsg(allocator: Allocator, path: []const []const u8, expected: []const u8, val: JsonValue) anyerror![]const u8 {
4027
- const p = try pathifySlice(allocator, path);
4028
- const actual = typename(typify(val));
4029
- const val_str = try stringify(allocator, val, 33);
4030
- if (path.len == 0) {
4031
- if (val == .null) {
4032
- return try std.fmt.allocPrint(allocator, "Expected {s}, but found no value.", .{expected});
4033
- }
4034
- return try std.fmt.allocPrint(allocator, "Expected {s}, but found {s}: {s}.", .{ expected, actual, val_str });
4218
+ var buf = std.array_list.Managed(u8).init(allocator);
4219
+ try buf.appendSlice("Expected ");
4220
+ if (1 < path.len) {
4221
+ try buf.appendSlice("field ");
4222
+ try buf.appendSlice(try pathifySlice(allocator, path[1..]));
4223
+ try buf.appendSlice(" to be ");
4224
+ }
4225
+ try buf.appendSlice(expected);
4226
+ try buf.appendSlice(", but found ");
4227
+ if (val == .null) {
4228
+ try buf.appendSlice("no value");
4229
+ } else {
4230
+ try buf.appendSlice(typename(typify(val)));
4231
+ try buf.appendSlice(S_VIZ);
4232
+ try buf.appendSlice(try stringify(allocator, val, 33));
4035
4233
  }
4036
- return try std.fmt.allocPrint(allocator, "Expected {s}, field {s} to be {s}, but found {s}: {s}.", .{ expected, p, expected, actual, val_str });
4234
+ try buf.append('.');
4235
+ return buf.items;
4037
4236
  }
4038
4237
 
4039
4238
  fn pathifySlice(allocator: Allocator, path: []const []const u8) anyerror![]const u8 {
4040
4239
  if (path.len == 0) return "<root>";
4041
- var buf = std.ArrayList(u8).init(allocator);
4240
+ var buf = std.array_list.Managed(u8).init(allocator);
4042
4241
  for (path, 0..) |p, i| {
4043
4242
  if (i > 0) try buf.append('.');
4044
4243
  try buf.appendSlice(p);
@@ -4094,7 +4293,7 @@ pub fn select(allocator: Allocator, children: JsonValue, query: JsonValue) anyer
4094
4293
  if (!isnode(children)) return try JsonValue.makeList(allocator);
4095
4294
 
4096
4295
  // Normalize children: add $KEY for map/list items.
4097
- var child_list = std.ArrayList(JsonValue).init(allocator);
4296
+ var child_list = std.array_list.Managed(JsonValue).init(allocator);
4098
4297
 
4099
4298
  if (ismap(children)) {
4100
4299
  const pairs = try items(allocator, children);
@@ -4124,7 +4323,7 @@ pub fn select(allocator: Allocator, children: JsonValue, query: JsonValue) anyer
4124
4323
  result_lr.* = .{ .data = ListData.init(allocator) };
4125
4324
 
4126
4325
  for (child_list.items) |child| {
4127
- var terrs = std.ArrayList([]const u8).init(allocator);
4326
+ var terrs = std.array_list.Managed([]const u8).init(allocator);
4128
4327
  const q = try clone(allocator, query);
4129
4328
 
4130
4329
  // Mark all maps in query as open.
@@ -4152,7 +4351,7 @@ fn validateExactMatch(
4152
4351
  allocator: Allocator,
4153
4352
  spec_val: JsonValue,
4154
4353
  data_val: JsonValue,
4155
- errs: *std.ArrayList([]const u8),
4354
+ errs: *std.array_list.Managed([]const u8),
4156
4355
  path: []const []const u8,
4157
4356
  ) anyerror!JsonValue {
4158
4357
  // Operator handling for select queries. Operators ($AND/$OR/$NOT/$CMP)
@@ -4303,12 +4502,12 @@ fn selectAnd(
4303
4502
  allocator: Allocator,
4304
4503
  terms: JsonValue,
4305
4504
  data_val: JsonValue,
4306
- errs: *std.ArrayList([]const u8),
4505
+ errs: *std.array_list.Managed([]const u8),
4307
4506
  path: []const []const u8,
4308
4507
  ) anyerror!JsonValue {
4309
4508
  if (terms != .array) return data_val;
4310
4509
  for (terms.array.data.items) |term| {
4311
- var terrs = std.ArrayList([]const u8).init(allocator);
4510
+ var terrs = std.array_list.Managed([]const u8).init(allocator);
4312
4511
  _ = try validateExactMatch(allocator, term, data_val, &terrs, path);
4313
4512
  if (terrs.items.len > 0) {
4314
4513
  try errs.append("AND condition failed");
@@ -4322,12 +4521,12 @@ fn selectOr(
4322
4521
  allocator: Allocator,
4323
4522
  terms: JsonValue,
4324
4523
  data_val: JsonValue,
4325
- errs: *std.ArrayList([]const u8),
4524
+ errs: *std.array_list.Managed([]const u8),
4326
4525
  path: []const []const u8,
4327
4526
  ) anyerror!JsonValue {
4328
4527
  if (terms != .array) return data_val;
4329
4528
  for (terms.array.data.items) |term| {
4330
- var terrs = std.ArrayList([]const u8).init(allocator);
4529
+ var terrs = std.array_list.Managed([]const u8).init(allocator);
4331
4530
  _ = try validateExactMatch(allocator, term, data_val, &terrs, path);
4332
4531
  if (terrs.items.len == 0) return data_val;
4333
4532
  }
@@ -4339,10 +4538,10 @@ fn selectNot(
4339
4538
  allocator: Allocator,
4340
4539
  term: JsonValue,
4341
4540
  data_val: JsonValue,
4342
- errs: *std.ArrayList([]const u8),
4541
+ errs: *std.array_list.Managed([]const u8),
4343
4542
  path: []const []const u8,
4344
4543
  ) anyerror!JsonValue {
4345
- var terrs = std.ArrayList([]const u8).init(allocator);
4544
+ var terrs = std.array_list.Managed([]const u8).init(allocator);
4346
4545
  _ = try validateExactMatch(allocator, term, data_val, &terrs, path);
4347
4546
  if (terrs.items.len == 0) {
4348
4547
  try errs.append("NOT: condition should not have matched");
@@ -4355,7 +4554,7 @@ fn selectCmp(
4355
4554
  op: []const u8,
4356
4555
  term: JsonValue,
4357
4556
  data_val: JsonValue,
4358
- errs: *std.ArrayList([]const u8),
4557
+ errs: *std.array_list.Managed([]const u8),
4359
4558
  path: []const []const u8,
4360
4559
  ) anyerror!JsonValue {
4361
4560
  _ = path;