diff --git a/claude.md b/claude.md index 29f6f00..f057e2a 100644 --- a/claude.md +++ b/claude.md @@ -23,14 +23,14 @@ dotnet test src/Tests --configuration Release --filter "FullyQualifiedName~Tests - **src/EmptyFiles.Tool/** — CLI global tool (`emptyfile` command). Targets net10.0. - **src/Tests/** — NUnit tests with Verify snapshot testing. Targets net48 + net8.0 through net11.0. - **src/EmptyFiles.AotTests/** — AOT/trimming compatibility tests (net9.0, PublishAot). -- **files/** — The actual empty template files organized by category: `archive/`, `document/`, `image/`, `sheet/`, `slide/`, `binary/`. +- **files/** — The actual empty template files organized by category: `archive/`, `document/`, `image/`, `map/`, `sheet/`, `slide/`, `binary/`. - **buildTransitive/EmptyFiles.targets** — MSBuild targets included in the NuGet package; copies empty files to output directory on build. ## Architecture Single namespace `EmptyFiles` with four public static API classes: -- **AllFiles** — Main facade. Discovers and loads empty template files from the `files/` directory at static init. Provides file creation (`CreateFile`/`TryCreateFile`), lookup (`GetPathFor`/`TryGetPathFor`), validation (`IsEmptyFile`), and registration (`UseFile`). Files are stored in `FrozenDictionary` per `Category` enum (Archive, Document, Image, Sheet, Slide, Binary). +- **AllFiles** — Main facade. Discovers and loads empty template files from the `files/` directory at static init. Provides file creation (`CreateFile`/`TryCreateFile`), lookup (`GetPathFor`/`TryGetPathFor`), validation (`IsEmptyFile`), and registration (`UseFile`). Files are stored in `FrozenDictionary` per `Category` enum (Archive, Document, Image, Map, Sheet, Slide, Binary). - **FileExtensions** — Text file detection. Maintains a set of ~443 known text extensions and supports custom conventions via `AddTextFileConvention(Func)`. - **ContentTypes** — MIME type mapping between extensions and media types (200+ mappings). - **EmptyFile** — Data class holding `Path`, `LastWriteTime`, and `Category` for each template file. diff --git a/files/map/empty.gpkg b/files/map/empty.gpkg new file mode 100644 index 0000000..2ceddeb Binary files /dev/null and b/files/map/empty.gpkg differ diff --git a/files/map/empty.mbtiles b/files/map/empty.mbtiles new file mode 100644 index 0000000..09e27bd Binary files /dev/null and b/files/map/empty.mbtiles differ diff --git a/files/map/empty.pmtiles b/files/map/empty.pmtiles new file mode 100644 index 0000000..27f790c Binary files /dev/null and b/files/map/empty.pmtiles differ diff --git a/files/map/empty.shp b/files/map/empty.shp new file mode 100644 index 0000000..45d2404 Binary files /dev/null and b/files/map/empty.shp differ diff --git a/files/map/empty.shx b/files/map/empty.shx new file mode 100644 index 0000000..45d2404 Binary files /dev/null and b/files/map/empty.shx differ diff --git a/index/empty.gpkg b/index/empty.gpkg new file mode 100644 index 0000000..2ceddeb Binary files /dev/null and b/index/empty.gpkg differ diff --git a/index/empty.mbtiles b/index/empty.mbtiles new file mode 100644 index 0000000..09e27bd Binary files /dev/null and b/index/empty.mbtiles differ diff --git a/index/empty.pmtiles b/index/empty.pmtiles new file mode 100644 index 0000000..27f790c Binary files /dev/null and b/index/empty.pmtiles differ diff --git a/index/empty.shp b/index/empty.shp new file mode 100644 index 0000000..45d2404 Binary files /dev/null and b/index/empty.shp differ diff --git a/index/empty.shx b/index/empty.shx new file mode 100644 index 0000000..45d2404 Binary files /dev/null and b/index/empty.shx differ diff --git a/readme.md b/readme.md index a845638..59c70d7 100644 --- a/readme.md +++ b/readme.md @@ -90,6 +90,14 @@ All files: https://github.com/VerifyTests/EmptyFiles/tree/main/files * .webp (26 bytes) * .wmp (48 bytes) +### Map + + * .gpkg (5 KB) + * .mbtiles (2 KB) + * .pmtiles (130 bytes) + * .shp (100 bytes) + * .shx (100 bytes) + ### Sheet * .ods (683 bytes) diff --git a/src/EmptyFiles/AllFiles.cs b/src/EmptyFiles/AllFiles.cs index 289b2e5..a7935aa 100644 --- a/src/EmptyFiles/AllFiles.cs +++ b/src/EmptyFiles/AllFiles.cs @@ -18,6 +18,10 @@ public static class AllFiles static FrozenDictionary images; + public static FrozenDictionary Maps => maps; + + static FrozenDictionary maps; + public static FrozenDictionary Sheets => sheets; static FrozenDictionary sheets; @@ -35,6 +39,7 @@ static AllFiles() archives = AddCategory(archiveExtensions, Category.Archive); documents = AddCategory(documentExtensions, Category.Document); images = AddCategory(imageExtensions, Category.Image); + maps = AddCategory(mapExtensions, Category.Map); sheets = AddCategory(sheetExtensions, Category.Sheet); slides = AddCategory(slideExtensions, Category.Slide); binary = AddCategory(binaryExtensions, Category.Binary); @@ -42,6 +47,7 @@ static AllFiles() Append(archives); Append(documents); Append(images); + Append(maps); Append(sheets); Append(slides); Append(binary); @@ -101,6 +107,7 @@ static void ExtractAll(string directory) ExtractCategory(directory, "binary", binary); ExtractCategory(directory, "document", documents); ExtractCategory(directory, "image", images); + ExtractCategory(directory, "map", maps); ExtractCategory(directory, "sheet", sheets); ExtractCategory(directory, "slide", slides); } @@ -147,6 +154,9 @@ public static void UseFile(Category category, string file) case Category.Image: Init(ref images, ref imageExtensions); break; + case Category.Map: + Init(ref maps, ref mapExtensions); + break; case Category.Sheet: Init(ref sheets, ref sheetExtensions); break; @@ -261,6 +271,20 @@ void Init(ref FrozenDictionary emptyFiles, ref FrozenSet MapPaths => maps.Values.Select(_ => _.Path); + + public static FrozenSet MapExtensions => mapExtensions; + + static FrozenSet mapExtensions = FrozenSet.ToFrozenSet( + [ + ".gpkg", + ".mbtiles", + ".pmtiles", + ".shp", + ".shx" + ], + StringComparer.OrdinalIgnoreCase); + public static IEnumerable SheetPaths => sheets.Values.Select(_ => _.Path); public static FrozenSet SheetExtensions => sheetExtensions; diff --git a/src/EmptyFiles/Category.cs b/src/EmptyFiles/Category.cs index 5ce978b..a1ca274 100644 --- a/src/EmptyFiles/Category.cs +++ b/src/EmptyFiles/Category.cs @@ -7,5 +7,6 @@ public enum Category Image, Sheet, Slide, - Binary + Binary, + Map } \ No newline at end of file diff --git a/src/EmptyFiles/EmptyFiles.csproj b/src/EmptyFiles/EmptyFiles.csproj index c5f5253..2c0d510 100644 --- a/src/EmptyFiles/EmptyFiles.csproj +++ b/src/EmptyFiles/EmptyFiles.csproj @@ -27,6 +27,9 @@ EmptyFiles.image.%(Filename)%(Extension) + + EmptyFiles.map.%(Filename)%(Extension) + EmptyFiles.sheet.%(Filename)%(Extension) diff --git a/src/EmptyFiles/FileExtensions.cs b/src/EmptyFiles/FileExtensions.cs index fa4e849..7d5c2a0 100644 --- a/src/EmptyFiles/FileExtensions.cs +++ b/src/EmptyFiles/FileExtensions.cs @@ -235,6 +235,7 @@ public static void AddTextFileConvention(IsTextFile convention) => ".ftn", ".gemrc", ".gemspec", + ".geojson", ".gitattributes", ".gitconfig", ".gitignore", @@ -242,6 +243,7 @@ public static void AddTextFileConvention(IsTextFile convention) => ".gitmodules", ".go", ".gpp", + ".gpx", ".gradle", ".graphql", ".groovy", @@ -295,6 +297,7 @@ public static void AddTextFileConvention(IsTextFile convention) => ".jsp", ".jspx", ".jsx", + ".kml", ".ksh", ".less", ".lhs", diff --git a/src/Tests/ExtensionsTests.cs b/src/Tests/ExtensionsTests.cs index b3fc309..acb822f 100644 --- a/src/Tests/ExtensionsTests.cs +++ b/src/Tests/ExtensionsTests.cs @@ -137,4 +137,19 @@ public async Task BicepParametersAreText(string extension) await Assert.That(FileExtensions.IsTextFile($"main.dev.{extension}")).IsTrue(); await Assert.That(FileExtensions.IsTextFile($"main.dev.{extension}".AsSpan())).IsTrue(); } + + [Test] + [Arguments("geojson")] + [Arguments("gpx")] + [Arguments("kml")] + public async Task MapFormatsAreText(string extension) + { + await Assert.That(FileExtensions.IsTextExtension(extension)).IsTrue(); + await Assert.That(FileExtensions.IsTextExtension(extension.AsSpan())).IsTrue(); + await Assert.That(FileExtensions.IsTextExtension($".{extension}")).IsTrue(); + await Assert.That(FileExtensions.IsTextExtension($".{extension}".AsSpan())).IsTrue(); + await Assert.That(FileExtensions.IsTextFile($"route.{extension}")).IsTrue(); + await Assert.That(AllFiles.TryCreateFile($"route.{extension}", useEmptyStringForTextFiles: true)).IsTrue(); + File.Delete($"route.{extension}"); + } } \ No newline at end of file diff --git a/src/Tests/Tests.cs b/src/Tests/Tests.cs index e690a05..5337701 100644 --- a/src/Tests/Tests.cs +++ b/src/Tests/Tests.cs @@ -366,6 +366,7 @@ public async Task WriteExtensions() await WriteCategory(writer, "Archive", AllFiles.Archives); await WriteCategory(writer, "Document", AllFiles.Documents); await WriteCategory(writer, "Image", AllFiles.Images); + await WriteCategory(writer, "Map", AllFiles.Maps); await WriteCategory(writer, "Sheet", AllFiles.Sheets); await WriteCategory(writer, "Slide", AllFiles.Slides); await WriteCategory(writer, "Binary", AllFiles.Binary); @@ -376,7 +377,11 @@ static async Task WriteCategory(StreamWriter writer, string category, IReadOnlyD await writer.WriteLineAsync(""); await writer.WriteLineAsync($"### {category}"); await writer.WriteLineAsync(""); - foreach (var file in files.OrderBy(_ => _.Key)) + // Exclude the file registered by RegisterUseFile; it is a test fixture, not a shipped template. + var shipped = files + .Where(_ => _.Value.Path != useFileTarget) + .OrderBy(_ => _.Key); + foreach (var file in shipped) { var size = Size.Suffix(new FileInfo(file.Value.Path).Length); await writer.WriteLineAsync($" * {file.Key} ({size})"); diff --git a/src/extensions.include.md b/src/extensions.include.md index f19582f..4a01cd1 100644 --- a/src/extensions.include.md +++ b/src/extensions.include.md @@ -53,6 +53,14 @@ * .webp (26 bytes) * .wmp (48 bytes) +### Map + + * .gpkg (5 KB) + * .mbtiles (2 KB) + * .pmtiles (130 bytes) + * .shp (100 bytes) + * .shx (100 bytes) + ### Sheet * .ods (683 bytes)