const std = @import("std"); /// Decode a base64 string, used for parsing out build artifacts generated by the CLI program's /// build.zig which are stored in the executable as a module. pub fn base64Decode(allocator: std.mem.Allocator, input: []const u8) ![]const u8 { const decoder = std.base64.Base64Decoder.init( std.base64.url_safe_no_pad.alphabet_chars, std.base64.url_safe_no_pad.pad_char, ); const size = try decoder.calcSizeForSlice(input); const ptr = try allocator.alloc(u8, size); try decoder.decode(ptr, input); return ptr; } /// Print a success confirmation. pub fn printSuccess() void { std.debug.print(" ✅\n", .{}); } /// Print a failure confirmation. pub fn printFailure() void { std.debug.print(" ❌\n", .{}); } /// Verifies that cwd is the root of a Jetzig project pub fn detectJetzigProjectDir() !std.fs.Dir { var dir = try std.fs.cwd().openDir(".", .{}); const max_parent_dirs: usize = 100; // Prevent symlink loops or other weird stuff. for (0..max_parent_dirs) |_| { if (try isPath(dir, "build.zig", .file) and try isPath(dir, "src/app/views", .dir)) return dir; dir = dir.openDir("..", .{}) catch |err| { switch (err) { error.FileNotFound, error.NotDir => { std.debug.print( "Encountered unexpected detecting Jetzig project directory: {s}\n", .{@errorName(err)}, ); return error.JetzigCommandError; }, else => return err, } }; continue; } std.debug.print( \\Exceeded maximum parent directory depth. \\Unable to detect Jetzig project directory. \\ , .{}, ); return error.JetzigCommandError; } fn isPath(dir: std.fs.Dir, sub_path: []const u8, path_type: enum { file, dir }) !bool { switch (path_type) { .file => { _ = dir.statFile(sub_path) catch |err| { switch (err) { error.FileNotFound => return false, else => return err, } }; return true; }, .dir => { var test_dir = dir.openDir(sub_path, .{}) catch |err| { switch (err) { error.FileNotFound, error.NotDir => return false, else => return err, } }; test_dir.close(); return true; }, } } // Strip leading and trailing whitespace from a u8 slice. pub fn strip(input: []const u8) []const u8 { return std.mem.trim(u8, input, &std.ascii.whitespace); } /// Attempts to confirm if a string input is in CamelCase. False if the first character is /// not alphabetic lower-case or if the input contains underscores. pub fn isCamelCase(input: []const u8) bool { if (input.len == 0) return false; if (!std.mem.containsAtLeast(u8, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", 1, &[_]u8{input[0]})) return false; if (std.mem.containsAtLeast(u8, input, 1, "_")) return false; return true; }