| ... | @@ -28,6 +28,7 @@ pub const delimiter_windows = ';'; | ... | @@ -28,6 +28,7 @@ pub const delimiter_windows = ';'; |
| 28 | pub const delimiter_posix = ':'; | 28 | pub const delimiter_posix = ':'; |
| 29 | pub const delimiter = if (builtin.os.tag == .windows) delimiter_windows else delimiter_posix; | 29 | pub const delimiter = if (builtin.os.tag == .windows) delimiter_windows else delimiter_posix; |
| 30 | | 30 | |
| | 31 | /// Returns if the given byte is a valid path separator |
| 31 | pub fn isSep(byte: u8) bool { | 32 | pub fn isSep(byte: u8) bool { |
| 32 | if (builtin.os.tag == .windows) { | 33 | if (builtin.os.tag == .windows) { |
| 33 | return byte == '/' or byte == '\\'; | 34 | return byte == '/' or byte == '\\'; |
| ... | @@ -1189,62 +1190,63 @@ fn testRelativeWindows(from: []const u8, to: []const u8, expected_output: []cons | ... | @@ -1189,62 +1190,63 @@ fn testRelativeWindows(from: []const u8, to: []const u8, expected_output: []cons |
| 1189 | /// Examples: | 1190 | /// Examples: |
| 1190 | /// - `"main.zig"` ⇒ `".zig"` | 1191 | /// - `"main.zig"` ⇒ `".zig"` |
| 1191 | /// - `"src/main.zig"` ⇒ `".zig"` | 1192 | /// - `"src/main.zig"` ⇒ `".zig"` |
| 1192 | /// - `".gitignore"` ⇒ `null` | 1193 | /// - `".gitignore"` ⇒ `""` |
| 1193 | /// - `"keep."` ⇒ `null` | 1194 | /// - `"keep."` ⇒ `""` |
| 1194 | /// - `"src.keep.me"` ⇒ `".me"` | 1195 | /// - `"src.keep.me"` ⇒ `".me"` |
| 1195 | pub fn extension(path: []const u8) ?[]const u8 { | 1196 | /// - `"/src/keep.me"` ⇒ `".me"` |
| | 1197 | /// - `"/src/keep.me/"` ⇒ `".me"` |
| | 1198 | pub fn extension(path: []const u8) []const u8 { |
| 1196 | const filename = basename(path); | 1199 | const filename = basename(path); |
| 1197 | return if (std.mem.lastIndexOf(u8, filename, ".")) |index| | 1200 | return if (std.mem.lastIndexOf(u8, filename, ".")) |index| |
| 1198 | if (index == 0 or index == filename.len - 1) | 1201 | if (index == 0 or index == filename.len - 1) |
| 1199 | null | 1202 | "" |
| 1200 | else | 1203 | else |
| 1201 | filename[index..] | 1204 | filename[index..] |
| 1202 | else | 1205 | else |
| 1203 | null; | 1206 | ""; |
| 1204 | } | 1207 | } |
| 1205 | | 1208 | |
| 1206 | fn testExtension(path: []const u8, expected: ?[]const u8) void { | 1209 | fn testExtension(path: []const u8, expected: []const u8) void { |
| 1207 | const actual = extension(path); | 1210 | std.testing.expectEqualStrings(expected, extension(path)); |
| 1208 | | | |
| 1209 | if (expected) |must_be| { | | |
| 1210 | std.testing.expect(actual != null); | | |
| 1211 | std.testing.expectEqualStrings(must_be, actual.?); | | |
| 1212 | } else { | | |
| 1213 | std.testing.expectEqual(expected, actual); | | |
| 1214 | } | | |
| 1215 | } | 1211 | } |
| 1216 | | 1212 | |
| 1217 | test "extension" { | 1213 | test "extension" { |
| 1218 | testExtension("", null); | 1214 | testExtension("", ""); |
| 1219 | testExtension(".", null); | 1215 | testExtension(".", ""); |
| 1220 | testExtension("a.", null); | 1216 | testExtension("a.", ""); |
| 1221 | testExtension("abc.", null); | 1217 | testExtension("abc.", ""); |
| 1222 | testExtension(".a", null); | 1218 | testExtension(".a", ""); |
| 1223 | testExtension(".file", null); | 1219 | testExtension(".file", ""); |
| 1224 | testExtension(".gitignore", null); | 1220 | testExtension(".gitignore", ""); |
| 1225 | testExtension("file.ext", ".ext"); | 1221 | testExtension("file.ext", ".ext"); |
| | 1222 | testExtension("file.ext.", ""); |
| 1226 | testExtension("very-long-file.bruh", ".bruh"); | 1223 | testExtension("very-long-file.bruh", ".bruh"); |
| 1227 | testExtension("a.b.c", ".c"); | 1224 | testExtension("a.b.c", ".c"); |
| 1228 | | 1225 | testExtension("a.b.c/", ".c"); |
| 1229 | testExtension("/", null); | 1226 | |
| 1230 | testExtension("/.", null); | 1227 | testExtension("/", ""); |
| 1231 | testExtension("/a.", null); | 1228 | testExtension("/.", ""); |
| 1232 | testExtension("/abc.", null); | 1229 | testExtension("/a.", ""); |
| 1233 | testExtension("/.a", null); | 1230 | testExtension("/abc.", ""); |
| 1234 | testExtension("/.file", null); | 1231 | testExtension("/.a", ""); |
| 1235 | testExtension("/.gitignore", null); | 1232 | testExtension("/.file", ""); |
| | 1233 | testExtension("/.gitignore", ""); |
| 1236 | testExtension("/file.ext", ".ext"); | 1234 | testExtension("/file.ext", ".ext"); |
| | 1235 | testExtension("/file.ext.", ""); |
| 1237 | testExtension("/very-long-file.bruh", ".bruh"); | 1236 | testExtension("/very-long-file.bruh", ".bruh"); |
| 1238 | testExtension("/a.b.c", ".c"); | 1237 | testExtension("/a.b.c", ".c"); |
| 1239 | | 1238 | testExtension("/a.b.c/", ".c"); |
| 1240 | testExtension("/foo/bar/bam/", null); | 1239 | |
| 1241 | testExtension("/foo/bar/bam/.", null); | 1240 | testExtension("/foo/bar/bam/", ""); |
| 1242 | testExtension("/foo/bar/bam/a.", null); | 1241 | testExtension("/foo/bar/bam/.", ""); |
| 1243 | testExtension("/foo/bar/bam/abc.", null); | 1242 | testExtension("/foo/bar/bam/a.", ""); |
| 1244 | testExtension("/foo/bar/bam/.a", null); | 1243 | testExtension("/foo/bar/bam/abc.", ""); |
| 1245 | testExtension("/foo/bar/bam/.file", null); | 1244 | testExtension("/foo/bar/bam/.a", ""); |
| 1246 | testExtension("/foo/bar/bam/.gitignore", null); | 1245 | testExtension("/foo/bar/bam/.file", ""); |
| | 1246 | testExtension("/foo/bar/bam/.gitignore", ""); |
| 1247 | testExtension("/foo/bar/bam/file.ext", ".ext"); | 1247 | testExtension("/foo/bar/bam/file.ext", ".ext"); |
| | 1248 | testExtension("/foo/bar/bam/file.ext.", ""); |
| 1248 | testExtension("/foo/bar/bam/very-long-file.bruh", ".bruh"); | 1249 | testExtension("/foo/bar/bam/very-long-file.bruh", ".bruh"); |
| 1249 | testExtension("/foo/bar/bam/a.b.c", ".c"); | 1250 | testExtension("/foo/bar/bam/a.b.c", ".c"); |
| | 1251 | testExtension("/foo/bar/bam/a.b.c/", ".c"); |
| 1250 | } | 1252 | } |