@@ -4,16 +4,22 @@ const types = @import("../types.zig");
44const errors = @import ("../errors.zig" );
55const utils = @import ("../utils.zig" );
66
7- /// Check if a file exists
7+ // Zig 0.16+ IO helper
8+ var io_instance : std.Io.Threaded = .init_single_threaded ;
9+ fn getIo () std.Io {
10+ return io_instance .io ();
11+ }
12+
13+ /// Check if a file exists using cross-platform Io.Dir
814fn fileExists (path : []const u8 ) bool {
9- const file = std .fs . cwd ().openFile (path , .{}) catch return false ;
10- file .close ();
15+ const file = std .Io . Dir . cwd ().openFile (getIo (), path , .{ . mode = .read_only }) catch return false ;
16+ file .close (getIo () );
1117 return true ;
1218}
1319
1420/// Strip single-line (//) and multi-line (/* */) comments from JSON content
1521fn stripJsonComments (allocator : std.mem.Allocator , content : []const u8 ) ! []const u8 {
16- var result : std .ArrayList (u8 ) = .empty ;
22+ var result = std .ArrayList (u8 ){} ;
1723 try result .ensureTotalCapacity (allocator , content .len );
1824 errdefer result .deinit (allocator );
1925
@@ -64,7 +70,7 @@ fn stripJsonComments(allocator: std.mem.Allocator, content: []const u8) ![]const
6470 try result .append (allocator , c );
6571 }
6672
67- return try result .toOwnedSlice (allocator );
73+ return result .toOwnedSlice (allocator );
6874}
6975
7076/// File loader service for discovering and loading configuration files
@@ -150,18 +156,33 @@ pub const FileLoader = struct {
150156 return self .loadTypeScriptConfig (path );
151157 }
152158
153- // Open file
154- const file = std .fs . cwd ().openFile (path , .{}) catch | err | {
159+ // Use cross-platform Io.Dir for file access
160+ const file = std .Io . Dir . cwd ().openFile (getIo (), path , .{ . mode = .read_only }) catch | err | {
155161 return switch (err ) {
156162 error .FileNotFound = > errors .ZigConfigError .ConfigFileNotFound ,
157163 error .AccessDenied = > errors .ZigConfigError .ConfigFilePermissionDenied ,
158164 else = > errors .ZigConfigError .ConfigFileInvalid ,
159165 };
160166 };
161- defer file .close ();
167+ defer file .close (getIo ());
168+
169+ // Read file content using Io.File (cross-platform)
170+ var content = std .ArrayList (u8 ).empty ;
171+ defer content .deinit (self .allocator );
172+
173+ var buf : [4096 ]u8 = undefined ;
174+ while (true ) {
175+ const bufs = [_ ][]u8 {& buf };
176+ const n = file .readStreaming (getIo (), & bufs ) catch {
177+ return errors .ZigConfigError .ConfigFileInvalid ;
178+ };
179+ if (n == 0 ) break ;
180+ content .appendSlice (self .allocator , buf [0.. n ]) catch {
181+ return errors .ZigConfigError .ConfigFileInvalid ;
182+ };
183+ }
162184
163- // Read file content
164- const owned_content = file .readToEndAlloc (self .allocator , 1024 * 1024 ) catch {
185+ const owned_content = content .toOwnedSlice (self .allocator ) catch {
165186 return errors .ZigConfigError .ConfigFileInvalid ;
166187 };
167188 defer self .allocator .free (owned_content );
@@ -205,17 +226,16 @@ pub const FileLoader = struct {
205226 ) catch return errors .ZigConfigError .ConfigFileInvalid ;
206227 defer self .allocator .free (script );
207228
208- // Use std.process.Child to execute bun
209- const result = std .process .Child .run (.{
210- .allocator = self .allocator ,
229+ // Use cross-platform std.process.run to execute bun
230+ const result = std .process .run (self .allocator , getIo (), .{
211231 .argv = &.{ "bun" , "-e" , script },
212232 }) catch {
213233 return errors .ZigConfigError .ConfigFileInvalid ;
214234 };
215235 defer self .allocator .free (result .stdout );
216236 defer self .allocator .free (result .stderr );
217237
218- if (result .term != .Exited or result .term .Exited != 0 ) {
238+ if (result .term != .exited or result .term .exited != 0 ) {
219239 return errors .ZigConfigError .ConfigFileInvalid ;
220240 }
221241
@@ -240,12 +260,12 @@ pub const FileLoader = struct {
240260 /// Get file modification time for cache invalidation
241261 pub fn getModTime (self : * FileLoader , path : []const u8 ) ! i64 {
242262 _ = self ;
243- // Open file and use stat
244- const file = std .fs . cwd ().openFile (path , .{}) catch return error .FileNotFound ;
245- defer file .close ();
246- const stat = try file .stat ();
247- // mtime is in nanoseconds (i128) , convert to seconds
248- return @intCast (@divTrunc (stat .mtime , std .time .ns_per_s ));
263+ // Open file using cross-platform Io.Dir and use File. stat
264+ const file = std .Io . Dir . cwd ().openFile (getIo (), path , .{ . mode = .read_only }) catch return error .FileNotFound ;
265+ defer file .close (getIo () );
266+ const stat = try file .stat (getIo () );
267+ // mtime is in nanoseconds, convert to seconds
268+ return @intCast (@divTrunc (stat .mtime . nanoseconds , std .time .ns_per_s ));
249269 }
250270};
251271
@@ -274,9 +294,9 @@ test "FileLoader.findConfigFile finds in project root" {
274294 var tmp = std .testing .tmpDir (.{});
275295 defer tmp .cleanup ();
276296
277- const file = try tmp .dir .createFile ("test.json" , .{});
278- defer file .close ();
279- try file .writeAll ( "{}" );
297+ const file = try tmp .dir .createFile (getIo (), "test.json" , .{});
298+ defer file .close (getIo () );
299+ try file .writePositionalAll ( getIo (), "{}" , 0 );
280300
281301 const cwd = try tmpDirRealPath (allocator , & tmp , "." );
282302 defer allocator .free (cwd );
@@ -310,9 +330,9 @@ test "FileLoader.loadConfigFile parses JSON" {
310330 var tmp = std .testing .tmpDir (.{});
311331 defer tmp .cleanup ();
312332
313- const file = try tmp .dir .createFile ("test.json" , .{});
314- defer file .close ();
315- try file .writeAll ( "{\" key\" : \" value\" }" );
333+ const file = try tmp .dir .createFile (getIo (), "test.json" , .{});
334+ defer file .close (getIo () );
335+ try file .writePositionalAll ( getIo (), "{\" key\" : \" value\" }" , 0 );
316336
317337 const path = try tmpDirRealPath (allocator , & tmp , "test.json" );
318338 defer allocator .free (path );
0 commit comments