├── index ├── empty.bin ├── empty.rtf ├── empty.zip ├── empty.pgm ├── empty.ppm ├── empty.7z ├── empty.bmp ├── empty.bz2 ├── empty.dib ├── empty.emf ├── empty.gif ├── empty.gz ├── empty.ico ├── empty.j2c ├── empty.jp2 ├── empty.jpc ├── empty.jpe ├── empty.jpg ├── empty.jxr ├── empty.kmz ├── empty.odp ├── empty.ods ├── empty.odt ├── empty.pbm ├── empty.png ├── empty.rle ├── empty.tga ├── empty.tif ├── empty.wdp ├── empty.wmp ├── empty.xz ├── empty.7zip ├── empty.avif ├── empty.bzip2 ├── empty.docx ├── empty.exif ├── empty.gzip ├── empty.heic ├── empty.heif ├── empty.jfif ├── empty.jpeg ├── empty.nupkg ├── empty.pptx ├── empty.tiff ├── empty.webp ├── empty.xlsx ├── empty.pcx ├── empty.dds ├── empty.pdf └── empty.tar ├── files ├── binary │ └── empty.bin ├── document │ ├── empty.rtf │ ├── empty.docx │ ├── empty.odt │ └── empty.pdf ├── archive │ ├── empty.zip │ ├── empty.7z │ ├── empty.gz │ ├── empty.xz │ ├── empty.7zip │ ├── empty.bz2 │ ├── empty.bzip2 │ ├── empty.gzip │ ├── empty.kmz │ ├── empty.nupkg │ └── empty.tar ├── image │ ├── empty.pgm │ ├── empty.ppm │ ├── empty.avif │ ├── empty.bmp │ ├── empty.dib │ ├── empty.emf │ ├── empty.exif │ ├── empty.gif │ ├── empty.heic │ ├── empty.heif │ ├── empty.ico │ ├── empty.j2c │ ├── empty.jfif │ ├── empty.jp2 │ ├── empty.jpc │ ├── empty.jpe │ ├── empty.jpeg │ ├── empty.jpg │ ├── empty.jxr │ ├── empty.pbm │ ├── empty.png │ ├── empty.rle │ ├── empty.tga │ ├── empty.tif │ ├── empty.tiff │ ├── empty.wdp │ ├── empty.webp │ ├── empty.wmp │ ├── empty.pcx │ └── empty.dds ├── sheet │ ├── empty.ods │ └── empty.xlsx └── slide │ ├── empty.odp │ └── empty.pptx ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── config.yml │ ├── feature_request.md │ └── bug_report.md ├── dependabot.yml ├── workflows │ ├── merge-dependabot.yml │ └── on-push-do-doco.yml └── stale.yml ├── docs ├── intro.include.md ├── zzz.png └── zzz.include.md ├── src ├── EmptyFiles │ ├── ClsCompliant.cs │ ├── IsTextFile.cs │ ├── GlobalUsings.cs │ ├── Category.cs │ ├── EmptyFile.cs │ ├── AssemblyLocation.cs │ ├── EmptyFileTargets.md │ ├── Guard.cs │ ├── EmptyFiles.csproj │ ├── ContentTypes.cs │ ├── AllFiles.cs │ └── FileExtensions.cs ├── icon.png ├── key.snk ├── Tests │ ├── GlobalUsings.cs │ ├── ImmutableVersionTests.cs │ ├── Size.cs │ ├── IndexWriter.cs │ ├── Tests.csproj │ ├── SolutionDirectoryFinder.cs │ ├── ContentTypesTests.cs │ ├── ExtensionsTests.cs │ └── Tests.cs ├── global.json ├── mdsnippets.json ├── EmptyFiles.targets ├── EmptyFiles.Tool │ ├── AssemblyInfo.cs │ ├── Program.cs │ └── EmptyFiles.Tool.csproj ├── EmptyFiles.slnx ├── nuget.md ├── Directory.Build.props ├── EmptyFiles.slnx.DotSettings ├── Directory.Packages.props ├── nuget.config ├── appveyor.yml ├── extensions.include.md ├── .editorconfig └── Shared.sln.DotSettings ├── .gitignore ├── .gitattributes ├── license.txt ├── code_of_conduct.md └── readme.md /index/empty.bin: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /files/binary/empty.bin: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /index/empty.rtf: -------------------------------------------------------------------------------- 1 | {\rtf} -------------------------------------------------------------------------------- /files/document/empty.rtf: -------------------------------------------------------------------------------- 1 | {\rtf} -------------------------------------------------------------------------------- /index/empty.zip: -------------------------------------------------------------------------------- 1 | PK -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: VerifyTests 2 | -------------------------------------------------------------------------------- /index/empty.pgm: -------------------------------------------------------------------------------- 1 | P5 2 | 1 1 3 | 255 4 | -------------------------------------------------------------------------------- /index/empty.ppm: -------------------------------------------------------------------------------- 1 | P6 2 | 1 1 3 | 255 4 | -------------------------------------------------------------------------------- /files/archive/empty.zip: -------------------------------------------------------------------------------- 1 | PK -------------------------------------------------------------------------------- /files/image/empty.pgm: -------------------------------------------------------------------------------- 1 | P5 2 | 1 1 3 | 255 4 | -------------------------------------------------------------------------------- /files/image/empty.ppm: -------------------------------------------------------------------------------- 1 | P6 2 | 1 1 3 | 255 4 | -------------------------------------------------------------------------------- /docs/intro.include.md: -------------------------------------------------------------------------------- 1 | A collection of minimal binary files. -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false -------------------------------------------------------------------------------- /src/EmptyFiles/ClsCompliant.cs: -------------------------------------------------------------------------------- 1 | [assembly: CLSCompliant(true)] -------------------------------------------------------------------------------- /docs/zzz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/docs/zzz.png -------------------------------------------------------------------------------- /src/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/src/icon.png -------------------------------------------------------------------------------- /src/key.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/src/key.snk -------------------------------------------------------------------------------- /index/empty.7z: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/index/empty.7z -------------------------------------------------------------------------------- /index/empty.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/index/empty.bmp -------------------------------------------------------------------------------- /index/empty.bz2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/index/empty.bz2 -------------------------------------------------------------------------------- /index/empty.dib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/index/empty.dib -------------------------------------------------------------------------------- /index/empty.emf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/index/empty.emf -------------------------------------------------------------------------------- /index/empty.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/index/empty.gif -------------------------------------------------------------------------------- /index/empty.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/index/empty.gz -------------------------------------------------------------------------------- /index/empty.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/index/empty.ico -------------------------------------------------------------------------------- /index/empty.j2c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/index/empty.j2c -------------------------------------------------------------------------------- /index/empty.jp2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/index/empty.jp2 -------------------------------------------------------------------------------- /index/empty.jpc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/index/empty.jpc -------------------------------------------------------------------------------- /index/empty.jpe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/index/empty.jpe -------------------------------------------------------------------------------- /index/empty.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/index/empty.jpg -------------------------------------------------------------------------------- /index/empty.jxr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/index/empty.jxr -------------------------------------------------------------------------------- /index/empty.kmz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/index/empty.kmz -------------------------------------------------------------------------------- /index/empty.odp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/index/empty.odp -------------------------------------------------------------------------------- /index/empty.ods: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/index/empty.ods -------------------------------------------------------------------------------- /index/empty.odt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/index/empty.odt -------------------------------------------------------------------------------- /index/empty.pbm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/index/empty.pbm -------------------------------------------------------------------------------- /index/empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/index/empty.png -------------------------------------------------------------------------------- /index/empty.rle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/index/empty.rle -------------------------------------------------------------------------------- /index/empty.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/index/empty.tga -------------------------------------------------------------------------------- /index/empty.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/index/empty.tif -------------------------------------------------------------------------------- /index/empty.wdp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/index/empty.wdp -------------------------------------------------------------------------------- /index/empty.wmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/index/empty.wmp -------------------------------------------------------------------------------- /index/empty.xz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/index/empty.xz -------------------------------------------------------------------------------- /index/empty.7zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/index/empty.7zip -------------------------------------------------------------------------------- /index/empty.avif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/index/empty.avif -------------------------------------------------------------------------------- /index/empty.bzip2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/index/empty.bzip2 -------------------------------------------------------------------------------- /index/empty.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/index/empty.docx -------------------------------------------------------------------------------- /index/empty.exif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/index/empty.exif -------------------------------------------------------------------------------- /index/empty.gzip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/index/empty.gzip -------------------------------------------------------------------------------- /index/empty.heic: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/index/empty.heic -------------------------------------------------------------------------------- /index/empty.heif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/index/empty.heif -------------------------------------------------------------------------------- /index/empty.jfif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/index/empty.jfif -------------------------------------------------------------------------------- /index/empty.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/index/empty.jpeg -------------------------------------------------------------------------------- /index/empty.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/index/empty.nupkg -------------------------------------------------------------------------------- /index/empty.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/index/empty.pptx -------------------------------------------------------------------------------- /index/empty.tiff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/index/empty.tiff -------------------------------------------------------------------------------- /index/empty.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/index/empty.webp -------------------------------------------------------------------------------- /index/empty.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/index/empty.xlsx -------------------------------------------------------------------------------- /files/archive/empty.7z: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/files/archive/empty.7z -------------------------------------------------------------------------------- /files/archive/empty.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/files/archive/empty.gz -------------------------------------------------------------------------------- /files/archive/empty.xz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/files/archive/empty.xz -------------------------------------------------------------------------------- /files/image/empty.avif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/files/image/empty.avif -------------------------------------------------------------------------------- /files/image/empty.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/files/image/empty.bmp -------------------------------------------------------------------------------- /files/image/empty.dib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/files/image/empty.dib -------------------------------------------------------------------------------- /files/image/empty.emf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/files/image/empty.emf -------------------------------------------------------------------------------- /files/image/empty.exif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/files/image/empty.exif -------------------------------------------------------------------------------- /files/image/empty.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/files/image/empty.gif -------------------------------------------------------------------------------- /files/image/empty.heic: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/files/image/empty.heic -------------------------------------------------------------------------------- /files/image/empty.heif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/files/image/empty.heif -------------------------------------------------------------------------------- /files/image/empty.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/files/image/empty.ico -------------------------------------------------------------------------------- /files/image/empty.j2c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/files/image/empty.j2c -------------------------------------------------------------------------------- /files/image/empty.jfif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/files/image/empty.jfif -------------------------------------------------------------------------------- /files/image/empty.jp2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/files/image/empty.jp2 -------------------------------------------------------------------------------- /files/image/empty.jpc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/files/image/empty.jpc -------------------------------------------------------------------------------- /files/image/empty.jpe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/files/image/empty.jpe -------------------------------------------------------------------------------- /files/image/empty.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/files/image/empty.jpeg -------------------------------------------------------------------------------- /files/image/empty.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/files/image/empty.jpg -------------------------------------------------------------------------------- /files/image/empty.jxr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/files/image/empty.jxr -------------------------------------------------------------------------------- /files/image/empty.pbm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/files/image/empty.pbm -------------------------------------------------------------------------------- /files/image/empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/files/image/empty.png -------------------------------------------------------------------------------- /files/image/empty.rle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/files/image/empty.rle -------------------------------------------------------------------------------- /files/image/empty.tga: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/files/image/empty.tga -------------------------------------------------------------------------------- /files/image/empty.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/files/image/empty.tif -------------------------------------------------------------------------------- /files/image/empty.tiff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/files/image/empty.tiff -------------------------------------------------------------------------------- /files/image/empty.wdp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/files/image/empty.wdp -------------------------------------------------------------------------------- /files/image/empty.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/files/image/empty.webp -------------------------------------------------------------------------------- /files/image/empty.wmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/files/image/empty.wmp -------------------------------------------------------------------------------- /files/sheet/empty.ods: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/files/sheet/empty.ods -------------------------------------------------------------------------------- /files/sheet/empty.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/files/sheet/empty.xlsx -------------------------------------------------------------------------------- /files/slide/empty.odp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/files/slide/empty.odp -------------------------------------------------------------------------------- /files/slide/empty.pptx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/files/slide/empty.pptx -------------------------------------------------------------------------------- /files/archive/empty.7zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/files/archive/empty.7zip -------------------------------------------------------------------------------- /files/archive/empty.bz2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/files/archive/empty.bz2 -------------------------------------------------------------------------------- /files/archive/empty.bzip2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/files/archive/empty.bzip2 -------------------------------------------------------------------------------- /files/archive/empty.gzip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/files/archive/empty.gzip -------------------------------------------------------------------------------- /files/archive/empty.kmz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/files/archive/empty.kmz -------------------------------------------------------------------------------- /files/archive/empty.nupkg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/files/archive/empty.nupkg -------------------------------------------------------------------------------- /files/document/empty.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/files/document/empty.docx -------------------------------------------------------------------------------- /files/document/empty.odt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VerifyTests/EmptyFiles/HEAD/files/document/empty.odt -------------------------------------------------------------------------------- /src/EmptyFiles/IsTextFile.cs: -------------------------------------------------------------------------------- 1 | namespace EmptyFiles; 2 | 3 | public delegate bool IsTextFile(CharSpan path); -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.suo 2 | *.user 3 | bin/ 4 | obj/ 5 | .vs/ 6 | *.DotSettings.user 7 | .idea/ 8 | *.received.* 9 | nugets/ -------------------------------------------------------------------------------- /src/Tests/GlobalUsings.cs: -------------------------------------------------------------------------------- 1 | global using EmptyFiles; 2 | global using NUnit.Framework; 3 | global using System.Collections.Immutable; -------------------------------------------------------------------------------- /src/global.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdk": { 3 | "version": "10.0.101", 4 | "allowPrerelease": true, 5 | "rollForward": "latestFeature" 6 | } 7 | } -------------------------------------------------------------------------------- /index/empty.pcx: -------------------------------------------------------------------------------- 1 | 2 | `` -------------------------------------------------------------------------------- /src/EmptyFiles/GlobalUsings.cs: -------------------------------------------------------------------------------- 1 | global using System.Diagnostics.CodeAnalysis; 2 | global using System.Collections.Frozen; 3 | global using System.Text; -------------------------------------------------------------------------------- /files/image/empty.pcx: -------------------------------------------------------------------------------- 1 | 2 | `` -------------------------------------------------------------------------------- /index/empty.dds: -------------------------------------------------------------------------------- 1 | DDS | 2 |  DXT1 -------------------------------------------------------------------------------- /files/image/empty.dds: -------------------------------------------------------------------------------- 1 | DDS | 2 |  DXT1 -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: nuget 4 | directory: "/src" 5 | schedule: 6 | interval: daily 7 | open-pull-requests-limit: 10 8 | -------------------------------------------------------------------------------- /src/EmptyFiles/Category.cs: -------------------------------------------------------------------------------- 1 | namespace EmptyFiles; 2 | 3 | public enum Category 4 | { 5 | Archive, 6 | Document, 7 | Image, 8 | Sheet, 9 | Slide, 10 | Binary 11 | } -------------------------------------------------------------------------------- /src/mdsnippets.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/SimonCropp/MarkdownSnippets/master/schema.json", 3 | "TocExcludes": [ "NuGet package", "Release Notes", "Icon" ], 4 | "MaxWidth": 100, 5 | "Convention": "InPlaceOverwrite" 6 | } -------------------------------------------------------------------------------- /index/empty.pdf: -------------------------------------------------------------------------------- 1 | %PDF-1.0 2 | 1 0 obj<>endobj 2 0 obj<>endobj 3 0 obj<>endobj 3 | xref 4 | 0 4 5 | 0000000000 65535 f 6 | 0000000010 00000 n 7 | 0000000053 00000 n 8 | 0000000102 00000 n 9 | trailer<> 10 | startxref 11 | 149 12 | %EOF -------------------------------------------------------------------------------- /files/document/empty.pdf: -------------------------------------------------------------------------------- 1 | %PDF-1.0 2 | 1 0 obj<>endobj 2 0 obj<>endobj 3 0 obj<>endobj 3 | xref 4 | 0 4 5 | 0000000000 65535 f 6 | 0000000010 00000 n 7 | 0000000053 00000 n 8 | 0000000102 00000 n 9 | trailer<> 10 | startxref 11 | 149 12 | %EOF -------------------------------------------------------------------------------- /src/EmptyFiles.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | -------------------------------------------------------------------------------- /src/EmptyFiles.Tool/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | [assembly: InternalsVisibleTo("Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100e191859fcd1deee68b96927c170783ced0c9a471a6424a0a011cfd31156a49dd73c4ad4a88b995fb918c0b43e0c005ef5fb72d53a328a64bde825cb5f2e4c53d66f69fcbb87d6737128b98e677a42091974b5f56093123a2dd6bc738af751b101d41c4f7a996e217b61967a3aa1ae7bc791d19c1cbeef47f0cdd20d288dff1a3")] -------------------------------------------------------------------------------- /src/Tests/ImmutableVersionTests.cs: -------------------------------------------------------------------------------- 1 | #if NETFRAMEWORK 2 | 3 | public class ImmutableVersionTests 4 | { 5 | // work around https://github.com/orgs/VerifyTests/discussions/1366 6 | [Test] 7 | public void AssertVersion() 8 | { 9 | var assemblyName = typeof(ImmutableDictionary).Assembly.GetName(); 10 | AreEqual(new Version(8, 0, 0, 0), assemblyName.Version); 11 | } 12 | } 13 | 14 | #endif -------------------------------------------------------------------------------- /.github/workflows/merge-dependabot.yml: -------------------------------------------------------------------------------- 1 | name: merge-dependabot 2 | on: 3 | pull_request: 4 | jobs: 5 | automerge: 6 | runs-on: ubuntu-latest 7 | if: github.actor == 'dependabot[bot]' 8 | steps: 9 | - name: Dependabot Auto Merge 10 | uses: ahmadnassri/action-dependabot-auto-merge@v2.6.6 11 | with: 12 | target: minor 13 | github-token: ${{ secrets.dependabot }} 14 | command: squash and merge -------------------------------------------------------------------------------- /docs/zzz.include.md: -------------------------------------------------------------------------------- 1 | ### Entity Framework Extensions 2 | 3 | [Entity Framework Extensions](https://entityframework-extensions.net/?utm_source=simoncropp&utm_medium=EmptyFiles) is a major sponsor and is proud to contribute to the development this project. 4 | 5 | [![Entity Framework Extensions](https://raw.githubusercontent.com/VerifyTests/EmptyFiles/refs/heads/main/docs/zzz.png)](https://entityframework-extensions.net/?utm_source=simoncropp&utm_medium=EmptyFiles) -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto eol=lf 2 | *.snk binary 3 | *.png binary 4 | 5 | /files/** binary 6 | /files/**/*.* binary 7 | /files/*.* binary 8 | /index/** binary 9 | /index/*.* binary 10 | 11 | *.verified.txt text eol=lf working-tree-encoding=UTF-8 12 | *.verified.xml text eol=lf working-tree-encoding=UTF-8 13 | *.verified.json text eol=lf working-tree-encoding=UTF-8 14 | 15 | .editorconfig text eol=lf working-tree-encoding=UTF-8 16 | *.sln.DotSettings text eol=lf working-tree-encoding=UTF-8 17 | *.slnx.DotSettings text eol=lf working-tree-encoding=UTF-8 -------------------------------------------------------------------------------- /src/EmptyFiles.Tool/Program.cs: -------------------------------------------------------------------------------- 1 | using EmptyFiles; 2 | 3 | if (args.Length == 0) 4 | { 5 | Console.Error.Write("No input"); 6 | return 1; 7 | } 8 | 9 | var arg = args[0]; 10 | 11 | string path; 12 | if (arg.Any(_ => _ is 13 | '.' or 14 | '/' or 15 | '\\')) 16 | { 17 | path = arg; 18 | } 19 | else 20 | { 21 | path = $"empty.{arg}"; 22 | } 23 | 24 | if (AllFiles.TryCreateFile( 25 | path, 26 | useEmptyStringForTextFiles: true)) 27 | { 28 | return 0; 29 | } 30 | 31 | Console.Error.Write("Unknown extension"); 32 | return 1; -------------------------------------------------------------------------------- /src/EmptyFiles.slnx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/EmptyFiles/EmptyFile.cs: -------------------------------------------------------------------------------- 1 | namespace EmptyFiles; 2 | 3 | public class EmptyFile 4 | { 5 | public string Path { get; } 6 | public DateTime LastWriteTime { get; } 7 | public Category Category { get; } 8 | 9 | internal static EmptyFile Build(string file, Category category) 10 | { 11 | var writeTime = File.GetLastWriteTime(file); 12 | return new(file, writeTime, category); 13 | } 14 | 15 | public EmptyFile(string path, in DateTime lastWriteTime, in Category category) 16 | { 17 | Guard.AgainstNullOrEmpty(path); 18 | Path = path; 19 | LastWriteTime = lastWriteTime; 20 | Category = category; 21 | } 22 | } -------------------------------------------------------------------------------- /src/Tests/Size.cs: -------------------------------------------------------------------------------- 1 | static class Size 2 | { 3 | static string[] SizeSuffixes = 4 | [ 5 | "bytes", 6 | "KB", 7 | "MB" 8 | ]; 9 | 10 | public static string Suffix(long value) 11 | { 12 | if (value == 0) 13 | { 14 | return "0 bytes"; 15 | } 16 | 17 | var mag = (int) Math.Log(value, 1024); 18 | 19 | var adjustedSize = (decimal) value / (1L << (mag * 10)); 20 | 21 | if (Math.Round(adjustedSize, 1) >= 1000) 22 | { 23 | mag += 1; 24 | adjustedSize /= 1024; 25 | } 26 | 27 | return $"{adjustedSize:0.#} {SizeSuffixes[mag]}"; 28 | } 29 | } -------------------------------------------------------------------------------- /src/EmptyFiles/AssemblyLocation.cs: -------------------------------------------------------------------------------- 1 | #pragma warning disable IL3000 2 | 3 | static class AssemblyLocation 4 | { 5 | static AssemblyLocation() 6 | { 7 | var assembly = typeof(AssemblyLocation).Assembly; 8 | #if NET5_0_OR_GREATER 9 | Path = assembly.Location; 10 | #else 11 | var uri = new UriBuilder(assembly.CodeBase); 12 | Path = Uri.UnescapeDataString(uri.Path); 13 | #endif 14 | 15 | if (string.IsNullOrWhiteSpace(Path)) 16 | { 17 | Path = AppContext.BaseDirectory; 18 | } 19 | 20 | Directory = System.IO.Path.GetDirectoryName(Path)!; 21 | } 22 | 23 | public static string Path; 24 | 25 | public static string Directory; 26 | } -------------------------------------------------------------------------------- /src/EmptyFiles/EmptyFileTargets.md: -------------------------------------------------------------------------------- 1 | How it works: 2 | 3 | 1. Inputs="$(MSBuildThisFileFile)" - Tracks the package file timestamp 4 | 2. Outputs="$(EmptyFilesMarker)" - Tracks a marker file in the output directory 5 | 3. MSBuild automatically skips the target if all outputs are newer than all inputs 6 | 4. SkipUnchangedFiles="true" - Additional optimization to skip individual unchanged files 7 | 5. Touch - Updates the marker file timestamp after successful copy 8 | 9 | This will only copy files when: 10 | 11 | 1. The targets is newer than the marker file, OR 12 | 2. The marker file doesn't exist (first build/clean build) 13 | 14 | Benefits: 15 | 16 | * Dramatically reduces IO on incremental builds 17 | * Works with dotnet clean (removes marker file) 18 | * Still respects individual file changes via SkipUnchangedFiles 19 | -------------------------------------------------------------------------------- /.github/workflows/on-push-do-doco.yml: -------------------------------------------------------------------------------- 1 | name: on-push-do-doco 2 | on: 3 | push: 4 | jobs: 5 | release: 6 | runs-on: windows-latest 7 | steps: 8 | - uses: actions/checkout@v4 9 | - name: Run MarkdownSnippets 10 | run: | 11 | dotnet tool install --global MarkdownSnippets.Tool 12 | mdsnippets ${GITHUB_WORKSPACE} 13 | shell: bash 14 | - name: Push changes 15 | run: | 16 | git config --local user.email "action@github.com" 17 | git config --local user.name "GitHub Action" 18 | git commit -m "Doco changes" -a || echo "nothing to commit" 19 | remote="https://${GITHUB_ACTOR}:${{secrets.GITHUB_TOKEN}}@github.com/${GITHUB_REPOSITORY}.git" 20 | branch="${GITHUB_REF:11}" 21 | git push "${remote}" ${branch} || echo "nothing to push" 22 | shell: bash -------------------------------------------------------------------------------- /src/nuget.md: -------------------------------------------------------------------------------- 1 | [Documentation](https://github.com/VerifyTests/EmptyFiles) 2 | 3 | A collection of minimal binary files. 4 | 5 | **See [Milestones](https://github.com/VerifyTests/EmptyFiles/milestones?state=closed) for release notes.** 6 | 7 | 8 | ## Sponsors 9 | 10 | 11 | ### Entity Framework Extensions 12 | 13 | [Entity Framework Extensions](https://entityframework-extensions.net/?utm_source=simoncropp&utm_medium=EmptyFiles) is a major sponsor and is proud to contribute to the development this project. 14 | 15 | [![Entity Framework Extensions](https://raw.githubusercontent.com/VerifyTests/EmptyFiles/refs/heads/main/docs/zzz.png)](https://entityframework-extensions.net/?utm_source=simoncropp&utm_medium=EmptyFiles) 16 | -------------------------------------------------------------------------------- /src/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | CS1591;CS0649;NU5119;NU1608;NU1109 5 | 8.17.1 6 | preview 7 | 1.0.0 8 | A collection of minimal binary files. 9 | false 10 | true 11 | true 12 | true 13 | true 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 7 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 7 5 | # Set to true to ignore issues in a milestone (defaults to false) 6 | exemptMilestones: true 7 | # Comment to post when marking an issue as stale. Set to `false` to disable 8 | markComment: > 9 | This issue has been automatically marked as stale because it has not had 10 | recent activity. It will be closed if no further activity occurs. Thank you 11 | for your contributions. 12 | # Comment to post when closing a stale issue. Set to `false` to disable 13 | closeComment: false 14 | # Optionally, specify configuration settings that are specific to just 'issues' or 'pulls': 15 | pulls: 16 | daysUntilStale: 30 17 | exemptLabels: 18 | - Question 19 | - Bug 20 | - Feature 21 | - Improvement -------------------------------------------------------------------------------- /src/EmptyFiles.slnx.DotSettings: -------------------------------------------------------------------------------- 1 | 2 | ..\Shared.sln.DotSettings 3 | True 4 | True 5 | 1 6 | -------------------------------------------------------------------------------- /src/Tests/IndexWriter.cs: -------------------------------------------------------------------------------- 1 | #if NET9_0 2 | public class IndexWriter 3 | { 4 | static List> files = null!; 5 | 6 | [ModuleInitializer] 7 | public static void Init() => 8 | files = AllFiles 9 | .Files.OrderBy(_ => _.Key) 10 | .ToList(); 11 | [Test] 12 | public void CreateIndex() => 13 | InnerCreateIndex(); 14 | 15 | static void InnerCreateIndex([CallerFilePath] string filePath = "") 16 | { 17 | var rootDirectory = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(filePath)!, @"..\..\")); 18 | var indexPath = Path.Combine(rootDirectory, "index"); 19 | Directory.CreateDirectory(indexPath); 20 | foreach (var toDelete in Directory.EnumerateFiles(indexPath)) 21 | { 22 | File.Delete(toDelete); 23 | } 24 | 25 | foreach (var (key, value) in files) 26 | { 27 | File.Copy(value.Path, Path.Combine(indexPath, $"empty{key}")); 28 | } 29 | } 30 | } 31 | #endif -------------------------------------------------------------------------------- /src/Tests/Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net48 5 | net8.0;net9.0;net10.0;$(TargetFrameworks) 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/Directory.Packages.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | true 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/EmptyFiles/Guard.cs: -------------------------------------------------------------------------------- 1 | static class Guard 2 | { 3 | public static void FileExists(string path, [CallerArgumentExpression("path")] string argumentName = "") 4 | { 5 | AgainstNullOrEmpty(argumentName, path); 6 | if (!File.Exists(path)) 7 | { 8 | throw new ArgumentException($"File not found. Path: {path}"); 9 | } 10 | } 11 | 12 | public static void AgainstNullOrEmpty(string value, [CallerArgumentExpression("value")] string argumentName = "") 13 | { 14 | if (string.IsNullOrWhiteSpace(value)) 15 | { 16 | throw new ArgumentNullException(argumentName); 17 | } 18 | } 19 | 20 | public static string ValidExtension(string extension, [CallerArgumentExpression(nameof(extension))] string argumentName = "") 21 | { 22 | if (extension.Length == 0) 23 | { 24 | throw new ArgumentNullException(argumentName); 25 | } 26 | 27 | if (extension.StartsWith('.')) 28 | { 29 | return extension; 30 | } 31 | 32 | return $".{extension}"; 33 | } 34 | } -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Simon Cropp 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/Tests/SolutionDirectoryFinder.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | 3 | static class SolutionDirectoryFinder 4 | { 5 | public static string Find([CallerFilePath] string testFile = "") 6 | { 7 | var testDirectory = Path.GetDirectoryName(testFile)!; 8 | if (!TryFind(testDirectory, out var solutionDirectory)) 9 | { 10 | throw new("Could not find solution directory"); 11 | } 12 | 13 | return solutionDirectory; 14 | } 15 | 16 | public static bool TryFind(string testDirectory, [NotNullWhen(true)] out string? path) 17 | { 18 | var currentDirectory = testDirectory; 19 | do 20 | { 21 | if (Directory 22 | .GetFiles(currentDirectory, "*.slnx").Length != 0) 23 | { 24 | path = currentDirectory; 25 | return true; 26 | } 27 | 28 | var parent = Directory.GetParent(currentDirectory); 29 | if (parent == null) 30 | { 31 | path = null; 32 | return false; 33 | } 34 | 35 | currentDirectory = parent.FullName; 36 | } while (true); 37 | } 38 | } -------------------------------------------------------------------------------- /src/nuget.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 20 | 21 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/EmptyFiles.Tool/EmptyFiles.Tool.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | net10.0 5 | emptyfile 6 | emptyfile 7 | EmptyFiles.Tool 8 | True 9 | .NET Core Global Tool for creating minimal binary files 10 | true 11 | $(NoWarn);NU5118 12 | LatestMajor 13 | 14 | 15 | 16 | 17 | 18 | true 19 | tools\net10.0\any\EmptyFiles 20 | 21 | 22 | EmptyFiles\%(RecursiveDir)%(Filename)%(Extension) 23 | PreserveNewest 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/appveyor.yml: -------------------------------------------------------------------------------- 1 | image: 2 | - Visual Studio 2022 3 | # - macOS 4 | # - Ubuntu 5 | environment: 6 | DOTNET_NOLOGO: true 7 | DOTNET_CLI_TELEMETRY_OPTOUT: true 8 | DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true 9 | build_script: 10 | - pwsh: | 11 | if ($isWindows) { 12 | Invoke-WebRequest "https://dot.net/v1/dotnet-install.ps1" -OutFile "./dotnet-install.ps1" 13 | ./dotnet-install.ps1 -JSonFile src/global.json -Architecture x64 -InstallDir 'C:\Program Files\dotnet' 14 | } 15 | if ($isMacOS) { 16 | Invoke-WebRequest "https://dot.net/v1/dotnet-install.sh" -OutFile "./dotnet-install.sh" 17 | sudo chmod u+x dotnet-install.sh 18 | sudo ./dotnet-install.sh --jsonfile src/global.json --architecture x64 --install-dir '/usr/local/share/dotnet' 19 | sudo ./dotnet-install.sh --version 9.0.306 --architecture x64 --install-dir '/usr/local/share/dotnet' 20 | } 21 | if ($isLinux) { 22 | Invoke-WebRequest "https://dot.net/v1/dotnet-install.sh" -OutFile "./dotnet-install.sh" 23 | sudo chmod u+x dotnet-install.sh 24 | sudo ./dotnet-install.sh --jsonfile src/global.json --architecture x64 --install-dir '/usr/share/dotnet' 25 | } 26 | - dotnet build src --configuration Release 27 | - dotnet test src --configuration Release --no-build --no-restore 28 | test: off 29 | artifacts: 30 | - path: nugets\*.nupkg -------------------------------------------------------------------------------- /src/extensions.include.md: -------------------------------------------------------------------------------- 1 | 2 | ### Archive 3 | 4 | * .7z (32 bytes) 5 | * .7zip (32 bytes) 6 | * .bz2 (14 bytes) 7 | * .bzip2 (14 bytes) 8 | * .gz (29 bytes) 9 | * .gzip (29 bytes) 10 | * .kmz (292 bytes) 11 | * .nupkg (1.8 KB) 12 | * .tar (1.5 KB) 13 | * .xz (32 bytes) 14 | * .zip (22 bytes) 15 | 16 | ### Document 17 | 18 | * .docx (1.9 KB) 19 | * .odt (2.2 KB) 20 | * .pdf (280 bytes) 21 | * .rtf (6 bytes) 22 | 23 | ### Image 24 | 25 | * .avif (298 bytes) 26 | * .bmp (58 bytes) 27 | * .dds (136 bytes) 28 | * .dib (58 bytes) 29 | * .emf (620 bytes) 30 | * .exif (734 bytes) 31 | * .gif (799 bytes) 32 | * .heic (3.2 KB) 33 | * .heif (209 bytes) 34 | * .ico (70 bytes) 35 | * .j2c (270 bytes) 36 | * .jfif (734 bytes) 37 | * .jp2 (354 bytes) 38 | * .jpc (270 bytes) 39 | * .jpe (734 bytes) 40 | * .jpeg (734 bytes) 41 | * .jpg (734 bytes) 42 | * .jxr (300 bytes) 43 | * .pbm (8 bytes) 44 | * .pcx (131 bytes) 45 | * .pgm (12 bytes) 46 | * .png (119 bytes) 47 | * .ppm (14 bytes) 48 | * .rle (58 bytes) 49 | * .tga (543 bytes) 50 | * .tif (250 bytes) 51 | * .tiff (250 bytes) 52 | * .wdp (300 bytes) 53 | * .webp (228 bytes) 54 | * .wmp (300 bytes) 55 | 56 | ### Sheet 57 | 58 | * .ods (2.7 KB) 59 | * .xlsx (4.5 KB) 60 | 61 | ### Slide 62 | 63 | * .odp (7.8 KB) 64 | * .pptx (13.3 KB) 65 | 66 | ### Binary 67 | 68 | * .bin (0 bytes) 69 | -------------------------------------------------------------------------------- /index/empty.tar: -------------------------------------------------------------------------------- 1 | empty0100777000000000000000000000000013602262730007064 0ustar00 -------------------------------------------------------------------------------- /files/archive/empty.tar: -------------------------------------------------------------------------------- 1 | empty0100777000000000000000000000000013602262730007064 0ustar00 -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: How to raise feature requests 4 | --- 5 | 6 | 7 | Note: New issues raised, where it is clear the submitter has not read the issue template, are likely to be closed with "please read the issue template". Please don't take offense at this. It is simply a time management decision. If someone raises an issue, and can't be bothered to spend the time to read the issue template, then the project maintainers should not be expected to spend the time to read the submitted issue. Often too much time is spent going back and forth in issue comments asking for information that is outlined in the issue template. 8 | 9 | If you are certain the feature will be accepted, it is better to raise a [Pull Request (PR)](https://help.github.com/articles/about-pull-requests/). 10 | 11 | If you are uncertain if the feature will be accepted, outline the proposal below to confirm it is viable, prior to raising a PR that implements the feature. 12 | 13 | Note that even if the feature is a good idea and viable, it may not be accepted since the ongoing effort in maintaining the feature may outweigh the benefit it delivers. 14 | 15 | 16 | #### Is the feature request related to a problem 17 | 18 | A clear and concise description of what the problem is. 19 | 20 | 21 | #### Describe the solution 22 | 23 | A clear and concise proposal of how you intend to implement the feature. 24 | 25 | 26 | #### Describe alternatives considered 27 | 28 | A clear and concise description of any alternative solutions or features you've considered. 29 | 30 | 31 | #### Additional context 32 | 33 | Add any other context about the feature request here. 34 | -------------------------------------------------------------------------------- /src/Tests/ContentTypesTests.cs: -------------------------------------------------------------------------------- 1 | public class ContentTypesTests 2 | { 3 | [Test] 4 | public void TryGetExtension() 5 | { 6 | True(ContentTypes.TryGetExtension("application/json", out var extension)); 7 | AreEqual("json", extension); 8 | True(ContentTypes.TryGetExtension("foo/bar+json", out extension)); 9 | AreEqual("json", extension); 10 | True(ContentTypes.TryGetExtension("text/html; charset=utf-8", out extension)); 11 | AreEqual("html", extension); 12 | True(ContentTypes.TryGetExtension("foo/bin", out extension)); 13 | AreEqual("bin", extension); 14 | } 15 | 16 | [Test] 17 | public void TryGetMediaType() 18 | { 19 | True(ContentTypes.TryGetMediaType("json", out var media)); 20 | AreEqual("application/json", media); 21 | True(ContentTypes.TryGetMediaType("html", out media)); 22 | AreEqual("text/html", media); 23 | True(ContentTypes.TryGetMediaType("bin", out media)); 24 | AreEqual("application/octet-stream", media); 25 | } 26 | 27 | [Test] 28 | public void IsText() 29 | { 30 | True(ContentTypes.IsText("application/json", out var extension)); 31 | AreEqual("json", extension); 32 | True(ContentTypes.IsText("text/html; charset=utf-8", out extension)); 33 | AreEqual("html", extension); 34 | True(ContentTypes.IsText("foo/bar+json", out extension)); 35 | AreEqual("json", extension); 36 | False(ContentTypes.IsText("foo/bin", out extension)); 37 | 38 | True(ContentTypes.IsText("application/json")); 39 | True(ContentTypes.IsText("foo/bar+json")); 40 | False(ContentTypes.IsText("foo/bin")); 41 | } 42 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug fix 3 | about: Create a bug fix to help us improve 4 | --- 5 | 6 | Note: New issues raised, where it is clear the submitter has not read the issue template, are likely to be closed with "please read the issue template". Please don't take offense at this. It is simply a time management decision. If someone raises an issue, and can't be bothered to spend the time to read the issue template, then the project maintainers should not be expected to spend the time to read the submitted issue. Often too much time is spent going back and forth in issue comments asking for information that is outlined in the issue template. 7 | 8 | 9 | #### Preamble 10 | 11 | General questions may be better placed [StackOveflow](https://stackoverflow.com/). 12 | 13 | Where relevant, ensure you are using the current stable versions on your development stack. For example: 14 | 15 | * Visual Studio 16 | * [.NET SDK or .NET Core SDK](https://www.microsoft.com/net/download) 17 | * Any related NuGet packages 18 | 19 | Any code or stack traces must be properly formatted with [GitHub markdown](https://guides.github.com/features/mastering-markdown/). 20 | 21 | 22 | #### Describe the bug 23 | 24 | A clear and concise description of what the bug is. Include any relevant version information. 25 | 26 | A clear and concise description of what you expected to happen. 27 | 28 | Add any other context about the problem here. 29 | 30 | 31 | #### Minimal Repro 32 | 33 | Ensure you have replicated the bug in a minimal solution with the fewest moving parts. Often this will help point to the true cause of the problem. Upload this repro as part of the issue, preferably a public GitHub repository or a downloadable zip. The repro will allow the maintainers of this project to smoke test the any fix. 34 | 35 | #### Submit a PR that fixes the bug 36 | 37 | Submit a [Pull Request (PR)](https://help.github.com/articles/about-pull-requests/) that fixes the bug. Include in this PR a test that verifies the fix. If you were not able to fix the bug, a PR that illustrates your partial progress will suffice. 38 | -------------------------------------------------------------------------------- /src/EmptyFiles/EmptyFiles.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net462;net472;net48 4 | $(TargetFrameworks);net6.0;net7.0;net8.0;net9.0;net10.0 5 | true 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | true 19 | files 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/Tests/ExtensionsTests.cs: -------------------------------------------------------------------------------- 1 | public class ExtensionsTests 2 | { 3 | [Test] 4 | public void IsText() 5 | { 6 | #region IsText 7 | 8 | True(FileExtensions.IsTextFile("file.txt")); 9 | False(FileExtensions.IsTextFile("file.bin")); 10 | True(FileExtensions.IsTextExtension(".txt")); 11 | False(FileExtensions.IsTextExtension(".bin")); 12 | True(FileExtensions.IsTextExtension("txt")); 13 | False(FileExtensions.IsTextExtension("bin")); 14 | 15 | #endregion 16 | 17 | False(FileExtensions.IsTextFile(".StartingWithDot")); 18 | False(FileExtensions.IsTextFile("NoExtension")); 19 | 20 | #region TextViaConvention 21 | 22 | True(FileExtensions.IsTextFile("c:/path/file.txtViaConvention")); 23 | 24 | #endregion 25 | } 26 | 27 | #region AddTextFileConvention 28 | [ModuleInitializer] 29 | public static void AddTextFileConvention() => 30 | // Treat files ending with .txtViaConvention as text files 31 | FileExtensions.AddTextFileConvention(path => path.EndsWith(".txtViaConvention")); 32 | 33 | #endregion 34 | 35 | [Test] 36 | public void IsTextLegacy() 37 | { 38 | #pragma warning disable CS0618 // Type or member is obsolete 39 | True(FileExtensions.IsText("file.txt")); 40 | False(FileExtensions.IsText("file.bin")); 41 | True(FileExtensions.IsText("c:/file.txt")); 42 | False(FileExtensions.IsText("c:/file.bin")); 43 | True(FileExtensions.IsText(".txt")); 44 | True(FileExtensions.IsText("txt")); 45 | False(FileExtensions.IsText(".bin")); 46 | False(FileExtensions.IsText("bin")); 47 | #pragma warning restore CS0618 // Type or member is obsolete 48 | } 49 | 50 | [Test] 51 | public void AddTextExtension() 52 | { 53 | #region AddTextExtension 54 | 55 | FileExtensions.AddTextExtension(".ext1"); 56 | True(FileExtensions.IsTextExtension(".ext1")); 57 | True(FileExtensions.IsTextFile("file.ext1")); 58 | 59 | #endregion 60 | 61 | FileExtensions.AddTextExtension("ext2"); 62 | True(FileExtensions.IsTextExtension("ext2")); 63 | True(FileExtensions.IsTextFile("file.ext2")); 64 | } 65 | 66 | [Test] 67 | public void RemoveTextExtension() 68 | { 69 | #region RemoveTextExtension 70 | 71 | FileExtensions.AddTextExtension(".ext1"); 72 | True(FileExtensions.IsTextExtension(".ext1")); 73 | FileExtensions.RemoveTextExtension(".ext1"); 74 | False(FileExtensions.IsTextExtension(".ext1")); 75 | 76 | #endregion 77 | 78 | FileExtensions.AddTextExtension("ext1"); 79 | True(FileExtensions.IsTextExtension("ext1")); 80 | FileExtensions.RemoveTextExtension("ext1"); 81 | False(FileExtensions.IsTextExtension("ext1")); 82 | } 83 | } -------------------------------------------------------------------------------- /code_of_conduct.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at simon.cropp@gmail.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /src/Tests/Tests.cs: -------------------------------------------------------------------------------- 1 | [TestFixture] 2 | public class Tests 3 | { 4 | [Test] 5 | public void CreateFile_overwrite_binary() 6 | { 7 | AllFiles.CreateFile("foo.bmp"); 8 | AllFiles.CreateFile("foo.bmp"); 9 | True(File.Exists("foo.bmp")); 10 | } 11 | 12 | [Test] 13 | public void CreateFile_NoDir_binary() 14 | { 15 | if (Directory.Exists("myTempDir")) 16 | { 17 | Directory.Delete("myTempDir", true); 18 | } 19 | 20 | AllFiles.CreateFile("myTempDir/foo.bmp"); 21 | True(File.Exists("myTempDir/foo.bmp")); 22 | } 23 | 24 | [Test] 25 | public void CreateFile_preamble() 26 | { 27 | AllFiles.CreateFile("foo.txt", true); 28 | 29 | var preamble = Encoding.UTF8.GetPreamble(); 30 | var bytes = File.ReadAllBytes("foo.txt"); 31 | if (bytes.Length < preamble.Length || 32 | preamble 33 | .Where((p, i) => p != bytes[i]) 34 | .Any()) 35 | { 36 | throw new ArgumentException("Not utf8-BOM"); 37 | } 38 | } 39 | 40 | [Test] 41 | public void CreateFile_overwrite_txt() 42 | { 43 | AllFiles.CreateFile("foo.txt", true); 44 | AllFiles.CreateFile("foo.txt", true); 45 | True(File.Exists("foo.txt")); 46 | } 47 | 48 | [Test] 49 | public void CreateFile_NoDir_txt() 50 | { 51 | if (Directory.Exists("myTempDir")) 52 | { 53 | Directory.Delete("myTempDir", true); 54 | } 55 | 56 | AllFiles.CreateFile("myTempDir/foo.txt", true); 57 | True(File.Exists("myTempDir/foo.txt")); 58 | } 59 | 60 | [Test] 61 | public void TryCreateFile_overwrite_txt() 62 | { 63 | True(AllFiles.TryCreateFile("foo.txt", true)); 64 | True(AllFiles.TryCreateFile("foo.txt", true)); 65 | True(File.Exists("foo.txt")); 66 | } 67 | 68 | [Test] 69 | public void TryCreateFile_NoDir_txt() 70 | { 71 | if (Directory.Exists("myTempDir")) 72 | { 73 | Directory.Delete("myTempDir", true); 74 | } 75 | 76 | True(AllFiles.TryCreateFile("myTempDir/foo.txt", true)); 77 | True(File.Exists("myTempDir/foo.txt")); 78 | } 79 | 80 | [Test] 81 | public void TryCreateFile_overwrite_binary() 82 | { 83 | True(AllFiles.TryCreateFile("foo.bmp")); 84 | True(AllFiles.TryCreateFile("foo.bmp")); 85 | True(File.Exists("foo.bmp")); 86 | } 87 | 88 | [Test] 89 | public void TryCreateFile_NoDir_binary() 90 | { 91 | if (Directory.Exists("myTempDir")) 92 | { 93 | Directory.Delete("myTempDir", true); 94 | } 95 | 96 | True(AllFiles.TryCreateFile("myTempDir/foo.bmp")); 97 | True(File.Exists("myTempDir/foo.bmp")); 98 | } 99 | 100 | [Test] 101 | public void Unknown_extension() 102 | { 103 | Throws(() => AllFiles.GetPathFor("txt")); 104 | False(AllFiles.TryGetPathFor("txt", out var result)); 105 | Null(result); 106 | False(AllFiles.TryGetPathFor(".txt", out result)); 107 | Null(result); 108 | False(AllFiles.TryCreateFile("foo.txt")); 109 | Null(result); 110 | Throws(() => AllFiles.GetPathFor(".txt")); 111 | Throws(() => AllFiles.CreateFile("foo.txt")); 112 | } 113 | 114 | [Test] 115 | public void GetPathFor() 116 | { 117 | #region GetPathFor 118 | 119 | var path = AllFiles.GetPathFor(".jpg"); 120 | 121 | #endregion 122 | 123 | NotNull(path); 124 | True(File.Exists(path)); 125 | 126 | path = AllFiles.GetPathFor("jpg"); 127 | NotNull(path); 128 | True(File.Exists(path)); 129 | } 130 | 131 | [Test] 132 | public void CreateFile() 133 | { 134 | var pathOfFileToCreate = "file.jpg"; 135 | File.Delete(pathOfFileToCreate); 136 | 137 | #region CreateFile 138 | 139 | AllFiles.CreateFile(pathOfFileToCreate); 140 | 141 | #endregion 142 | 143 | True(File.Exists(pathOfFileToCreate)); 144 | File.Delete(pathOfFileToCreate); 145 | 146 | AllFiles.CreateFile("foo.txt", true); 147 | True(File.Exists("foo.txt")); 148 | File.Delete("foo.txt"); 149 | 150 | True(AllFiles.TryCreateFile(pathOfFileToCreate)); 151 | True(File.Exists(pathOfFileToCreate)); 152 | File.Delete(pathOfFileToCreate); 153 | 154 | False(AllFiles.TryCreateFile("foo.txt")); 155 | False(File.Exists("foo.txt")); 156 | File.Delete("foo.txt"); 157 | 158 | True(AllFiles.TryCreateFile("foo.txt", true)); 159 | True(File.Exists("foo.txt")); 160 | File.Delete("foo.txt"); 161 | } 162 | 163 | [Test] 164 | public void IsEmptyFile() 165 | { 166 | #region IsEmptyFile 167 | 168 | var path = AllFiles.GetPathFor(".jpg"); 169 | True(AllFiles.IsEmptyFile(path)); 170 | var temp = Path.GetTempFileName(); 171 | False(AllFiles.IsEmptyFile(temp)); 172 | 173 | #endregion 174 | 175 | File.Delete(temp); 176 | } 177 | 178 | [Test] 179 | public void AllPaths() 180 | { 181 | IsNotEmpty(AllFiles.AllPaths); 182 | 183 | #region AllPaths 184 | 185 | foreach (var path in AllFiles.AllPaths) 186 | { 187 | Trace.WriteLine(path); 188 | } 189 | 190 | #endregion 191 | } 192 | 193 | static string ThisFile([CallerFilePath] string testFile = "") => 194 | testFile; 195 | 196 | //[Test] 197 | #pragma warning disable CA1822 198 | public void UseFile() 199 | #pragma warning restore CA1822 200 | { 201 | var pathToFile = ThisFile(); 202 | 203 | #region UseFile 204 | 205 | AllFiles.UseFile(Category.Document, pathToFile); 206 | IsTrue(AllFiles.DocumentPaths.Contains(pathToFile)); 207 | 208 | #endregion 209 | } 210 | 211 | #if NET9_0 212 | 213 | [Test] 214 | public async Task WriteExtensions() 215 | { 216 | var md = Path.Combine(SolutionDirectoryFinder.Find(), "extensions.include.md"); 217 | File.Delete(md); 218 | await using var writer = File.CreateText(md); 219 | await WriteCategory(writer, "Archive", AllFiles.Archives); 220 | await WriteCategory(writer, "Document", AllFiles.Documents); 221 | await WriteCategory(writer, "Image", AllFiles.Images); 222 | await WriteCategory(writer, "Sheet", AllFiles.Sheets); 223 | await WriteCategory(writer, "Slide", AllFiles.Slides); 224 | await WriteCategory(writer, "Binary", AllFiles.Binary); 225 | } 226 | 227 | static async Task WriteCategory(StreamWriter writer, string category, IReadOnlyDictionary files) 228 | { 229 | await writer.WriteLineAsync(""); 230 | await writer.WriteLineAsync($"### {category}"); 231 | await writer.WriteLineAsync(""); 232 | foreach (var file in files.OrderBy(_ => _.Key)) 233 | { 234 | var size = Size.Suffix(new FileInfo(file.Value.Path).Length); 235 | await writer.WriteLineAsync($" * {file.Key} ({size})"); 236 | } 237 | } 238 | 239 | #endif 240 | } -------------------------------------------------------------------------------- /src/EmptyFiles/ContentTypes.cs: -------------------------------------------------------------------------------- 1 | namespace EmptyFiles; 2 | 3 | public static class ContentTypes 4 | { 5 | static ContentTypes() 6 | { 7 | foreach (var (media, extension) in mediaToExtension) 8 | { 9 | extensionToMedia.TryAdd(extension, media); 10 | } 11 | } 12 | 13 | static Dictionary extensionToMedia = new(StringComparer.OrdinalIgnoreCase); 14 | 15 | public static bool IsText(string? mediaType) => 16 | IsText(mediaType, out _); 17 | 18 | public static bool TryGetMediaType(string extension, [NotNullWhen(true)] out string? mediaType) 19 | { 20 | if (extension.StartsWith('.')) 21 | { 22 | extension = extension[1..]; 23 | } 24 | 25 | return extensionToMedia.TryGetValue(extension, out mediaType); 26 | } 27 | 28 | public static bool IsText(string? mediaType, [NotNullWhen(true)] out string? extension) 29 | { 30 | if (TryGetExtension(mediaType, out extension)) 31 | { 32 | if (FileExtensions.IsTextExtension(extension)) 33 | { 34 | return true; 35 | } 36 | } 37 | 38 | extension = null; 39 | return false; 40 | } 41 | 42 | public static bool TryGetExtension(string? mediaType, [NotNullWhen(true)] out string? extension) 43 | { 44 | if (mediaType == null) 45 | { 46 | extension = null; 47 | return false; 48 | } 49 | 50 | var indexOf = mediaType.IndexOf(';'); 51 | if(indexOf != -1) 52 | { 53 | mediaType = mediaType[..indexOf]; 54 | } 55 | 56 | if (mediaToExtension.TryGetValue(mediaType, out extension)) 57 | { 58 | return true; 59 | } 60 | 61 | var mediaTypeSpan = mediaType.AsSpan(); 62 | var plusIndex = mediaTypeSpan.LastIndexOf('+'); 63 | 64 | if (plusIndex > -1) 65 | { 66 | extension = mediaTypeSpan[(plusIndex + 1)..] 67 | .ToString(); 68 | return true; 69 | } 70 | 71 | var slashIndex = mediaTypeSpan.LastIndexOf('/'); 72 | 73 | if (slashIndex > -1) 74 | { 75 | extension = mediaTypeSpan[(slashIndex + 1)..] 76 | .ToString(); 77 | return true; 78 | } 79 | 80 | return false; 81 | } 82 | 83 | static Dictionary mediaToExtension = new(StringComparer.OrdinalIgnoreCase) 84 | { 85 | //extra 86 | { 87 | "application/graphql", "gql" 88 | }, 89 | { 90 | "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "docx" 91 | }, 92 | { 93 | "application/vnd.openxmlformats-officedocument.wordprocessingml.template", "dotx" 94 | }, 95 | { 96 | "application/vnd.ms-word.document.macroEnabled.12", "docm" 97 | }, 98 | { 99 | "application/vnd.ms-word.template.macroEnabled.12", "dotm" 100 | }, 101 | { 102 | "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "xlsx" 103 | }, 104 | { 105 | "application/vnd.openxmlformats-officedocument.spreadsheetml.template", "xltx" 106 | }, 107 | { 108 | "application/vnd.ms-excel.sheet.macroEnabled.12", "xlsm" 109 | }, 110 | { 111 | "application/vnd.ms-excel.template.macroEnabled.12", "xltm" 112 | }, 113 | { 114 | "application/vnd.ms-excel.addin.macroEnabled.12", "xlam" 115 | }, 116 | { 117 | "application/vnd.ms-excel.sheet.binary.macroEnabled.12", "xlsb" 118 | }, 119 | { 120 | "application/vnd.openxmlformats-officedocument.presentationml.presentation", "pptx" 121 | }, 122 | { 123 | "application/vnd.openxmlformats-officedocument.presentationml.template", "potx" 124 | }, 125 | { 126 | "application/vnd.openxmlformats-officedocument.presentationml.slideshow", "ppsx" 127 | }, 128 | { 129 | "application/vnd.ms-powerpoint.addin.macroEnabled.12", "ppam" 130 | }, 131 | { 132 | "application/vnd.ms-powerpoint.presentation.macroEnabled.12", "pptm" 133 | }, 134 | { 135 | "application/vnd.ms-powerpoint.template.macroEnabled.12", "potm" 136 | }, 137 | { 138 | "application/vnd.ms-powerpoint.slideshow.macroEnabled.12", "ppsm" 139 | }, 140 | 141 | { 142 | "application/fsharp-script", "fsx" 143 | }, 144 | { 145 | "application/msaccess", "adp" 146 | }, 147 | { 148 | "application/msword", "doc" 149 | }, 150 | { 151 | "application/octet-stream", "bin" 152 | }, 153 | { 154 | "application/onenote", "one" 155 | }, 156 | { 157 | "application/postscript", "eps" 158 | }, 159 | { 160 | "application/xml", "xml" 161 | }, 162 | { 163 | "application/soap+xml", "xml" 164 | }, 165 | { 166 | "application/step", "step" 167 | }, 168 | { 169 | "application/vnd.ms-excel", "xls" 170 | }, 171 | { 172 | "application/vnd.ms-powerpoint", "ppt" 173 | }, 174 | { 175 | "application/vnd.ms-works", "wks" 176 | }, 177 | { 178 | "application/vnd.visio", "vsd" 179 | }, 180 | { 181 | "application/x-director", "dir" 182 | }, 183 | { 184 | "application/x-msdos-program", "exe" 185 | }, 186 | { 187 | "application/x-shockwave-flash", "swf" 188 | }, 189 | { 190 | "application/x-x509-ca-cert", "cer" 191 | }, 192 | { 193 | "application/x-zip-compressed", "zip" 194 | }, 195 | { 196 | "application/xhtml+xml", "xhtml" 197 | }, 198 | { 199 | "application/xrd+xml", "xml" 200 | }, 201 | { 202 | "application/json", "json" 203 | }, 204 | { 205 | "audio/aac", "aac" 206 | }, 207 | { 208 | "audio/aiff", "aiff" 209 | }, 210 | { 211 | "audio/basic", "snd" 212 | }, 213 | { 214 | "audio/mid", "midi" 215 | }, 216 | { 217 | "audio/mp4", "m4a" 218 | }, 219 | { 220 | "audio/wav", "wav" 221 | }, 222 | { 223 | "audio/x-m4a", "m4a" 224 | }, 225 | { 226 | "audio/x-mpegurl", "m3u" 227 | }, 228 | { 229 | "audio/x-pn-realaudio", "ra" 230 | }, 231 | { 232 | "audio/x-smd", "smd" 233 | }, 234 | { 235 | "image/bmp", "bmp" 236 | }, 237 | { 238 | "image/heic", ".heic" 239 | }, 240 | { 241 | "image/heic-sequence", "heics" 242 | }, 243 | { 244 | "image/jpeg", "jpg" 245 | }, 246 | { 247 | "image/gif", "gif" 248 | }, 249 | { 250 | "image/pict", "pic" 251 | }, 252 | { 253 | "image/png", "png" 254 | }, 255 | { 256 | "image/x-png", "png" 257 | }, 258 | { 259 | "image/svg+xml", "svg" 260 | }, 261 | { 262 | "image/tiff", "tiff" 263 | }, 264 | { 265 | "image/x-macpaint", "mac" 266 | }, 267 | { 268 | "image/x-quicktime", "qti" 269 | }, 270 | { 271 | "message/rfc822", "eml" 272 | }, 273 | { 274 | "text/calendar", "ics" 275 | }, 276 | { 277 | "text/html", "html" 278 | }, 279 | { 280 | "text/htmx", "htmx" 281 | }, 282 | { 283 | "text/javascript", "js" 284 | }, 285 | { 286 | "text/plain", "txt" 287 | }, 288 | { 289 | "text/scriptlet", "wsc" 290 | }, 291 | { 292 | "text/xml", "xml" 293 | }, 294 | { 295 | "text/csv", "csv" 296 | }, 297 | { 298 | "video/3gpp", "3gp" 299 | }, 300 | { 301 | "video/3gpp2", "3gp2" 302 | }, 303 | { 304 | "video/mp4", "mp4" 305 | }, 306 | { 307 | "video/mpeg", "mpg" 308 | }, 309 | { 310 | "video/quicktime", "mov" 311 | }, 312 | { 313 | "video/vnd.dlna.mpeg-tts", "m2t" 314 | }, 315 | { 316 | "video/x-dv", "dv" 317 | }, 318 | { 319 | "video/x-la-asf", "lsf" 320 | }, 321 | { 322 | "video/x-ms-asf", "asf" 323 | }, 324 | { 325 | "x-world/x-vrml", "xof" 326 | } 327 | }; 328 | } -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # EmptyFiles 2 | 3 | [![Discussions](https://img.shields.io/badge/Verify-Discussions-yellow?svg=true&label=)](https://github.com/orgs/VerifyTests/discussions) 4 | [![Build status](https://ci.appveyor.com/api/projects/status/4mrhpal9rwtqajws/branch/main?svg=true)](https://ci.appveyor.com/project/SimonCropp/EmptyFiles) 5 | [![NuGet Status](https://img.shields.io/nuget/v/EmptyFiles.svg?label=EmptyFiles)](https://www.nuget.org/packages/EmptyFiles/) 6 | [![NuGet Status](https://img.shields.io/nuget/v/EmptyFiles.Tool.svg?label=dotnet%20tool)](https://www.nuget.org/packages/EmptyFiles.Tool/) 7 | 8 | A collection of minimal binary files. 9 | 10 | **See [Milestones](../../milestones?state=closed) for release notes.** 11 | 12 | 13 | ## Sponsors 14 | 15 | 16 | ### Entity Framework Extensions 17 | 18 | [Entity Framework Extensions](https://entityframework-extensions.net/?utm_source=simoncropp&utm_medium=EmptyFiles) is a major sponsor and is proud to contribute to the development this project. 19 | 20 | [![Entity Framework Extensions](https://raw.githubusercontent.com/VerifyTests/EmptyFiles/refs/heads/main/docs/zzz.png)](https://entityframework-extensions.net/?utm_source=simoncropp&utm_medium=EmptyFiles) 21 | 22 | 23 | ### JetBrains 24 | 25 | [![JetBrains logo.](https://resources.jetbrains.com/storage/products/company/brand/logos/jetbrains.svg)](https://jb.gg/OpenSourceSupport) 26 | 27 | 28 | ## NuGet 29 | 30 | * https://nuget.org/packages/EmptyFiles/ 31 | * https://nuget.org/packages/EmptyFiles.Tool/ 32 | 33 | 34 | ## Files 35 | 36 | All files: https://github.com/VerifyTests/EmptyFiles/tree/main/files 37 | 38 | 39 | 40 | ### Archive 41 | 42 | * .7z (32 bytes) 43 | * .7zip (32 bytes) 44 | * .bz2 (14 bytes) 45 | * .bzip2 (14 bytes) 46 | * .gz (29 bytes) 47 | * .gzip (29 bytes) 48 | * .kmz (292 bytes) 49 | * .nupkg (1.8 KB) 50 | * .tar (1.5 KB) 51 | * .xz (32 bytes) 52 | * .zip (22 bytes) 53 | 54 | ### Document 55 | 56 | * .docx (1.9 KB) 57 | * .odt (2.2 KB) 58 | * .pdf (280 bytes) 59 | * .rtf (6 bytes) 60 | 61 | ### Image 62 | 63 | * .avif (298 bytes) 64 | * .bmp (58 bytes) 65 | * .dds (136 bytes) 66 | * .dib (58 bytes) 67 | * .emf (620 bytes) 68 | * .exif (734 bytes) 69 | * .gif (799 bytes) 70 | * .heic (3.2 KB) 71 | * .heif (209 bytes) 72 | * .ico (70 bytes) 73 | * .j2c (270 bytes) 74 | * .jfif (734 bytes) 75 | * .jp2 (354 bytes) 76 | * .jpc (270 bytes) 77 | * .jpe (734 bytes) 78 | * .jpeg (734 bytes) 79 | * .jpg (734 bytes) 80 | * .jxr (300 bytes) 81 | * .pbm (8 bytes) 82 | * .pcx (131 bytes) 83 | * .pgm (12 bytes) 84 | * .png (119 bytes) 85 | * .ppm (14 bytes) 86 | * .rle (58 bytes) 87 | * .tga (543 bytes) 88 | * .tif (250 bytes) 89 | * .tiff (250 bytes) 90 | * .wdp (300 bytes) 91 | * .webp (228 bytes) 92 | * .wmp (300 bytes) 93 | 94 | ### Sheet 95 | 96 | * .ods (2.7 KB) 97 | * .xlsx (4.5 KB) 98 | 99 | ### Slide 100 | 101 | * .odp (7.8 KB) 102 | * .pptx (13.3 KB) 103 | 104 | ### Binary 105 | 106 | * .bin (0 bytes) 107 | 108 | 109 | ## Consuming files as a web resource 110 | 111 | Files can be consumed as a web resource using the following url: 112 | 113 | ``` 114 | https://github.com/VerifyTests/EmptyFiles/raw/main/index/empty.{extension} 115 | ``` 116 | 117 | So for example to consume a jpg use 118 | 119 | ``` 120 | https://github.com/VerifyTests/EmptyFiles/raw/main/index/empty.jpg 121 | ``` 122 | 123 | A 404 will result for non-existent files. 124 | 125 | 126 | ## Tool Usage 127 | 128 | 129 | ### Installation 130 | 131 | Ensure [dotnet CLI is installed](https://docs.microsoft.com/en-us/dotnet/core/tools/). 132 | 133 | Install [EmptyFiles.Tool](https://nuget.org/packages/EmptyFiles.Tool/) 134 | 135 | ```ps 136 | dotnet tool install -g EmptyFiles.Tool 137 | ``` 138 | 139 | 140 | ### Extension only Usage 141 | 142 | ``` 143 | emptyfile bmp 144 | ``` 145 | 146 | Creates `{CurrentDirectory}/empty.bmp` 147 | 148 | 149 | ### File Usage 150 | 151 | ``` 152 | emptyfile myfile.bmp 153 | ``` 154 | 155 | Creates `{CurrentDirectory}/myfile.bmp` 156 | 157 | 158 | ### Path Usage 159 | 160 | ``` 161 | emptyfile path/myfile.bmp 162 | ``` 163 | 164 | Creates `path/myfile.bmp` 165 | 166 | 167 | ## Library Usage 168 | 169 | 170 | ### CreateFile 171 | 172 | Creates a new empty file 173 | 174 | 175 | 176 | ```cs 177 | AllFiles.CreateFile(pathOfFileToCreate); 178 | ``` 179 | snippet source | anchor 180 | 181 | 182 | Throws an exception if the extension is not known. There is also a `TryCreateFile` that will return false if the extension is not known. 183 | 184 | Use the optional `useEmptyStringForTextFiles` to create a empty text file if the extension is text. The file will be UTF8 no BOM as per https://www.unicode.org/versions/Unicode5.0.0/ch02.pdf "Use of a BOM is neither required nor recommended for UTF-8". 185 | 186 | 187 | ### GetPathFor 188 | 189 | Gets the path to an empty file for a given extension 190 | 191 | 192 | 193 | ```cs 194 | var path = AllFiles.GetPathFor(".jpg"); 195 | ``` 196 | snippet source | anchor 197 | 198 | 199 | Throws an exception if the extension is not known. There is also a `TryGetPathFor` that will return false if the extension is not known. 200 | 201 | 202 | ### IsEmptyFile 203 | 204 | Returns true if the target file is an empty file. 205 | 206 | 207 | 208 | ```cs 209 | var path = AllFiles.GetPathFor(".jpg"); 210 | True(AllFiles.IsEmptyFile(path)); 211 | var temp = Path.GetTempFileName(); 212 | False(AllFiles.IsEmptyFile(temp)); 213 | ``` 214 | snippet source | anchor 215 | 216 | 217 | 218 | ### AllPaths 219 | 220 | Enumerates all empty files 221 | 222 | 223 | 224 | ```cs 225 | foreach (var path in AllFiles.AllPaths) 226 | { 227 | Trace.WriteLine(path); 228 | } 229 | ``` 230 | snippet source | anchor 231 | 232 | 233 | 234 | ### UseFile 235 | 236 | Use or replace a file 237 | 238 | 239 | 240 | ```cs 241 | AllFiles.UseFile(Category.Document, pathToFile); 242 | IsTrue(AllFiles.DocumentPaths.Contains(pathToFile)); 243 | ``` 244 | snippet source | anchor 245 | 246 | 247 | 248 | ### Extensions helper 249 | 250 | 251 | #### IsText 252 | 253 | https://github.com/sindresorhus/text-extensions/blob/master/text-extensions.json 254 | 255 | 256 | 257 | ```cs 258 | True(FileExtensions.IsTextFile("file.txt")); 259 | False(FileExtensions.IsTextFile("file.bin")); 260 | True(FileExtensions.IsTextExtension(".txt")); 261 | False(FileExtensions.IsTextExtension(".bin")); 262 | True(FileExtensions.IsTextExtension("txt")); 263 | False(FileExtensions.IsTextExtension("bin")); 264 | ``` 265 | snippet source | anchor 266 | 267 | 268 | 269 | #### AddTextExtension 270 | 271 | 272 | 273 | ```cs 274 | FileExtensions.AddTextExtension(".ext1"); 275 | True(FileExtensions.IsTextExtension(".ext1")); 276 | True(FileExtensions.IsTextFile("file.ext1")); 277 | ``` 278 | snippet source | anchor 279 | 280 | 281 | 282 | #### RemoveTextExtension 283 | 284 | 285 | 286 | ```cs 287 | FileExtensions.AddTextExtension(".ext1"); 288 | True(FileExtensions.IsTextExtension(".ext1")); 289 | FileExtensions.RemoveTextExtension(".ext1"); 290 | False(FileExtensions.IsTextExtension(".ext1")); 291 | ``` 292 | snippet source | anchor 293 | 294 | 295 | 296 | #### AddTextFileConvention 297 | 298 | `AddTextFileConvention` allows the use of a convention based text file detection via a callback. 299 | 300 | At app startup add a convention using `FileExtensions.AddTextFileConvention`: 301 | 302 | 303 | 304 | ```cs 305 | [ModuleInitializer] 306 | public static void AddTextFileConvention() => 307 | // Treat files ending with .txtViaConvention as text files 308 | FileExtensions.AddTextFileConvention(path => path.EndsWith(".txtViaConvention")); 309 | ``` 310 | snippet source | anchor 311 | 312 | 313 | Then any call to `FileExtensions.IsTextFile` will, in addition to checking the known text extensions, also check if any of the added text contentions return true. 314 | 315 | 316 | 317 | ```cs 318 | True(FileExtensions.IsTextFile("c:/path/file.txtViaConvention")); 319 | ``` 320 | snippet source | anchor 321 | 322 | 323 | An alternative approach to a text file convention would be to check if a file has a preamble that matches an known text encoding. 324 | 325 | 326 | ## Icon 327 | 328 | [Hollow](https://thenounproject.com/term/hollow/51835/) designed by [Michael Senkow](https://thenounproject.com/mhsenkow/) from [The Noun Project](https://thenounproject.com). 329 | -------------------------------------------------------------------------------- /src/EmptyFiles/AllFiles.cs: -------------------------------------------------------------------------------- 1 | namespace EmptyFiles; 2 | 3 | public static class AllFiles 4 | { 5 | public static FrozenDictionary Files => files; 6 | 7 | static FrozenDictionary files; 8 | 9 | public static FrozenDictionary Archives => archives; 10 | 11 | static FrozenDictionary archives; 12 | 13 | public static FrozenDictionary Documents => documents; 14 | 15 | static FrozenDictionary documents; 16 | 17 | public static FrozenDictionary Images => images; 18 | 19 | static FrozenDictionary images; 20 | 21 | public static FrozenDictionary Sheets => sheets; 22 | 23 | static FrozenDictionary sheets; 24 | 25 | public static FrozenDictionary Binary => binary; 26 | 27 | static FrozenDictionary binary; 28 | 29 | public static FrozenDictionary Slides => slides; 30 | 31 | static FrozenDictionary slides; 32 | 33 | static AllFiles() 34 | { 35 | var directory = FindEmptyFilesDirectory(); 36 | 37 | archives = AddCategory(archiveExtensions, Category.Archive, directory); 38 | documents = AddCategory(documentExtensions, Category.Document, directory); 39 | images = AddCategory(imageExtensions, Category.Image, directory); 40 | sheets = AddCategory(sheetExtensions, Category.Sheet, directory); 41 | slides = AddCategory(slideExtensions, Category.Slide, directory); 42 | binary = AddCategory(binaryExtensions, Category.Binary, directory); 43 | var all = new Dictionary(); 44 | Append(archives); 45 | Append(documents); 46 | Append(images); 47 | Append(sheets); 48 | Append(slides); 49 | Append(binary); 50 | 51 | files = all.ToFrozenDictionary(); 52 | 53 | void Append(FrozenDictionary files) 54 | { 55 | foreach (var (key, value) in files) 56 | { 57 | all[key] = value; 58 | } 59 | } 60 | } 61 | 62 | static FrozenDictionary AddCategory(FrozenSet extensions, Category category, string emptyDirectory) 63 | { 64 | Dictionary items = []; 65 | var categoryDirectory = Path.Combine( 66 | emptyDirectory, 67 | category 68 | .ToString() 69 | .ToLowerInvariant()); 70 | foreach (var extension in extensions) 71 | { 72 | var file = Path.Combine(categoryDirectory, $"empty{extension}"); 73 | items[extension] = EmptyFile.Build(file, category); 74 | } 75 | 76 | return items.ToFrozenDictionary(); 77 | } 78 | 79 | static string FindEmptyFilesDirectory() 80 | { 81 | var directories = FindDirectories() 82 | .Select(_ => Path.Combine(_, "EmptyFiles")) 83 | .ToList(); 84 | foreach (var directory in directories) 85 | { 86 | if (Directory.Exists(directory)) 87 | { 88 | return directory; 89 | } 90 | } 91 | 92 | throw new( 93 | $""" 94 | Could not find empty files directory. Searched: 95 | {string.Join(Environment.NewLine, directories)} 96 | """); 97 | } 98 | 99 | static IEnumerable FindDirectories() 100 | { 101 | yield return AppDomain.CurrentDomain.BaseDirectory; 102 | yield return AssemblyLocation.Directory; 103 | yield return Environment.CurrentDirectory; 104 | } 105 | 106 | public static void UseFile(Category category, string file) 107 | { 108 | Guard.FileExists(file); 109 | var extension = Path.GetExtension(file); 110 | var emptyFile = EmptyFile.Build(file, category); 111 | switch (category) 112 | { 113 | case Category.Archive: 114 | Init(ref archives, ref archiveExtensions); 115 | break; 116 | case Category.Document: 117 | Init(ref documents, ref documentExtensions); 118 | break; 119 | case Category.Image: 120 | Init(ref images, ref imageExtensions); 121 | break; 122 | case Category.Sheet: 123 | Init(ref sheets, ref sheetExtensions); 124 | break; 125 | case Category.Slide: 126 | Init(ref slides, ref slideExtensions); 127 | break; 128 | case Category.Binary: 129 | Init(ref binary, ref binaryExtensions); 130 | break; 131 | default: 132 | throw new($"Unknown category: {category}"); 133 | } 134 | 135 | void Init(ref FrozenDictionary emptyFiles, ref FrozenSet extensions) 136 | { 137 | var tempDictionary = new Dictionary(); 138 | foreach (var (key, value) in emptyFiles) 139 | { 140 | tempDictionary[key] = value; 141 | } 142 | 143 | tempDictionary[extension] = emptyFile; 144 | emptyFiles = tempDictionary.ToFrozenDictionary(); 145 | var tempSet = new HashSet(extensions) 146 | { 147 | extension 148 | }; 149 | extensions = tempSet.ToFrozenSet(); 150 | } 151 | } 152 | 153 | public static IEnumerable AllPaths => files.Values.Select(_ => _.Path); 154 | 155 | // ReSharper disable once UseSymbolAlias 156 | public static IReadOnlyCollection AllExtensions => files.Keys; 157 | 158 | public static IEnumerable ArchivePaths => archives.Values.Select(_ => _.Path); 159 | 160 | public static FrozenSet ArchiveExtensions => archiveExtensions; 161 | 162 | static FrozenSet archiveExtensions = FrozenSet.ToFrozenSet( 163 | [ 164 | ".7z", 165 | ".7zip", 166 | ".bz2", 167 | ".bzip2", 168 | ".gz", 169 | ".gzip", 170 | ".kmz", 171 | ".nupkg", 172 | ".tar", 173 | ".xz", 174 | ".zip" 175 | ]); 176 | 177 | public static IEnumerable DocumentPaths => documents.Values.Select(_ => _.Path); 178 | 179 | public static FrozenSet DocumentExtensions => documentExtensions; 180 | 181 | static FrozenSet documentExtensions = FrozenSet.ToFrozenSet( 182 | [ 183 | ".docx", 184 | ".odt", 185 | ".pdf", 186 | ".rtf" 187 | ]); 188 | 189 | public static IEnumerable ImagePaths => images.Values.Select(_ => _.Path); 190 | 191 | public static FrozenSet ImageExtensions => imageExtensions; 192 | 193 | static FrozenSet imageExtensions = FrozenSet.ToFrozenSet( 194 | [ 195 | ".avif", 196 | ".bmp", 197 | ".dds", 198 | ".dib", 199 | ".emf", 200 | ".exif", 201 | ".gif", 202 | ".heic", 203 | ".heif", 204 | ".ico", 205 | ".j2c", 206 | ".jfif", 207 | ".jp2", 208 | ".jpc", 209 | ".jpe", 210 | ".jpeg", 211 | ".jpg", 212 | ".jxr", 213 | ".pbm", 214 | ".pcx", 215 | ".pgm", 216 | ".png", 217 | ".ppm", 218 | ".rle", 219 | ".tga", 220 | ".tif", 221 | ".tiff", 222 | ".wdp", 223 | ".webp", 224 | ".wmp" 225 | ]); 226 | 227 | public static IEnumerable SheetPaths => sheets.Values.Select(_ => _.Path); 228 | 229 | public static FrozenSet SheetExtensions => sheetExtensions; 230 | 231 | static FrozenSet sheetExtensions = FrozenSet.ToFrozenSet( 232 | [ 233 | ".ods", 234 | ".xlsx" 235 | ]); 236 | 237 | public static IEnumerable SlidePaths => slides.Values.Select(_ => _.Path); 238 | 239 | public static FrozenSet SlideExtensions => slideExtensions; 240 | 241 | static FrozenSet slideExtensions = FrozenSet.ToFrozenSet( 242 | [ 243 | ".odp", 244 | ".pptx" 245 | ]); 246 | 247 | public static IEnumerable BinaryPaths => binary.Values.Select(_ => _.Path); 248 | 249 | public static FrozenSet BinaryExtensions => binaryExtensions; 250 | 251 | static FrozenSet binaryExtensions = FrozenSet.ToFrozenSet( 252 | [ 253 | ".bin" 254 | ]); 255 | 256 | public static bool IsEmptyFile(string path) 257 | { 258 | Guard.FileExists(path); 259 | var extension = Path.GetExtension(path); 260 | if (!files.TryGetValue(extension, out var emptyFile)) 261 | { 262 | return false; 263 | } 264 | 265 | return File.GetLastWriteTime(path) == emptyFile.LastWriteTime; 266 | } 267 | 268 | public static void CreateFile(string path, bool useEmptyStringForTextFiles = false, Encoding? encoding = null) 269 | { 270 | TryCreateDirectory(path); 271 | var extension = Path.GetExtension(path); 272 | if (useEmptyStringForTextFiles && 273 | FileExtensions.IsTextExtension(extension)) 274 | { 275 | CreateTextFile(path, encoding); 276 | return; 277 | } 278 | 279 | File.Copy(GetPathFor(extension), path, true); 280 | } 281 | 282 | static void CreateTextFile(string path, Encoding? encoding) 283 | { 284 | File.Delete(path); 285 | encoding ??= Encoding.UTF8; 286 | File.WriteAllBytes(path, encoding.GetPreamble()); 287 | } 288 | 289 | public static string GetPathFor(string extension) 290 | { 291 | extension = Guard.ValidExtension(extension); 292 | if (files.TryGetValue(extension, out var emptyFile)) 293 | { 294 | return emptyFile.Path; 295 | } 296 | 297 | throw new($"Unknown extension: {extension}"); 298 | } 299 | 300 | public static bool TryCreateFile(string path, bool useEmptyStringForTextFiles = false, Encoding? encoding = null) 301 | { 302 | Guard.AgainstNullOrEmpty(path); 303 | var extension = Path.GetExtension(path); 304 | 305 | if (useEmptyStringForTextFiles && 306 | FileExtensions.IsTextExtension(extension)) 307 | { 308 | TryCreateDirectory(path); 309 | 310 | CreateTextFile(path, encoding); 311 | return true; 312 | } 313 | 314 | if (!TryGetPathFor(extension, out var source)) 315 | { 316 | return false; 317 | } 318 | 319 | TryCreateDirectory(path); 320 | 321 | File.Copy(source, path, true); 322 | return true; 323 | } 324 | 325 | static void TryCreateDirectory(string path) 326 | { 327 | var directory = Path.GetDirectoryName(path); 328 | 329 | if (!string.IsNullOrWhiteSpace(directory)) 330 | { 331 | Directory.CreateDirectory(directory); 332 | } 333 | } 334 | 335 | public static bool TryGetPathFor(string extension, [NotNullWhen(true)] out string? path) 336 | { 337 | if (files.TryGetValue(extension, out var emptyFile)) 338 | { 339 | path = emptyFile.Path; 340 | return true; 341 | } 342 | 343 | path = null; 344 | return false; 345 | } 346 | } -------------------------------------------------------------------------------- /src/EmptyFiles/FileExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace EmptyFiles; 2 | 3 | public static class FileExtensions 4 | { 5 | public static bool IsTextExtension(string extension) 6 | { 7 | extension = Guard.ValidExtension(extension); 8 | 9 | return textExtensions.Contains(extension); 10 | } 11 | 12 | public static bool IsTextExtension(CharSpan extension) => 13 | IsTextExtension(extension.ToString()); 14 | 15 | public static bool IsTextFile(string path) => 16 | IsTextFile(path.AsSpan()); 17 | 18 | public static bool IsTextFile(CharSpan path) 19 | { 20 | foreach (var convention in textFileConventions) 21 | { 22 | if (convention(path)) 23 | { 24 | return true; 25 | } 26 | } 27 | 28 | var extension = Path.GetExtension(path); 29 | 30 | if (extension.Length == 0) 31 | { 32 | return false; 33 | } 34 | 35 | return IsTextExtension(extension); 36 | } 37 | 38 | public static void RemoveTextExtension(string extension) 39 | { 40 | extension = Guard.ValidExtension(extension); 41 | var copy = new HashSet(textExtensions); 42 | copy.Remove(extension); 43 | textExtensions = copy.ToFrozenSet(); 44 | } 45 | 46 | public static void RemoveTextExtension(CharSpan extension) => 47 | RemoveTextExtension(extension.ToString()); 48 | 49 | public static void RemoveTextExtensions(params string[] extensions) 50 | { 51 | foreach (var extension in extensions) 52 | { 53 | RemoveTextExtension(extension); 54 | } 55 | } 56 | 57 | public static void RemoveTextExtensions(IEnumerable extensions) 58 | { 59 | foreach (var extension in extensions) 60 | { 61 | RemoveTextExtension(extension); 62 | } 63 | } 64 | 65 | public static void AddTextExtension(string extension) 66 | { 67 | extension = Guard.ValidExtension(extension); 68 | var copy = new HashSet(textExtensions) 69 | { 70 | extension 71 | }; 72 | textExtensions = copy.ToFrozenSet(); 73 | } 74 | 75 | public static void AddTextExtension(CharSpan extension) => 76 | AddTextExtension(extension.ToString()); 77 | 78 | public static void AddTextExtensions(params string[] extensions) 79 | { 80 | foreach (var extension in extensions) 81 | { 82 | AddTextExtension(extension); 83 | } 84 | } 85 | 86 | public static void AddTextExtensions(IEnumerable extensions) 87 | { 88 | foreach (var extension in extensions) 89 | { 90 | AddTextExtension(extension); 91 | } 92 | } 93 | 94 | public static void AddTextFileConvention(IsTextFile convention) => 95 | textFileConventions.Add(convention); 96 | 97 | static List textFileConventions = []; 98 | 99 | //From https://github.com/sindresorhus/text-extensions/blob/master/text-extensions.json 100 | static IReadOnlyCollection textExtensions = new HashSet 101 | { 102 | ".ada", 103 | ".adb", 104 | ".ads", 105 | ".applescript", 106 | ".as", 107 | ".asc", 108 | ".ascii", 109 | ".ascx", 110 | ".asm", 111 | ".asmx", 112 | ".asp", 113 | ".aspx", 114 | ".atom", 115 | ".au3", 116 | ".awk", 117 | ".bas", 118 | ".bash", 119 | ".bashrc", 120 | ".bat", 121 | ".bbcolors", 122 | ".bcp", 123 | ".bdsgroup", 124 | ".bdsproj", 125 | ".bib", 126 | ".bicep", 127 | ".bowerrc", 128 | ".c", 129 | ".cbl", 130 | ".cc", 131 | ".cfc", 132 | ".cfg", 133 | ".cfm", 134 | ".cfml", 135 | ".cgi", 136 | ".cjs", 137 | ".clj", 138 | ".cljs", 139 | ".cls", 140 | ".cmake", 141 | ".cmd", 142 | ".cnf", 143 | ".cob", 144 | ".code-snippets", 145 | ".coffee", 146 | ".coffeekup", 147 | ".conf", 148 | ".config", 149 | ".cp", 150 | ".cpp", 151 | ".cpt", 152 | ".cpy", 153 | ".crt", 154 | ".cs", 155 | ".csh", 156 | ".cson", 157 | ".csproj", 158 | ".csr", 159 | ".css", 160 | ".csslintrc", 161 | ".csv", 162 | ".ctl", 163 | ".curlrc", 164 | ".cxx", 165 | ".d", 166 | ".dart", 167 | ".dfm", 168 | ".diff", 169 | ".dof", 170 | ".dpk", 171 | ".dpr", 172 | ".dproj", 173 | ".dtd", 174 | ".dockerfile", 175 | ".eco", 176 | ".editorconfig", 177 | ".ejs", 178 | ".el", 179 | ".elm", 180 | ".emacs", 181 | ".eml", 182 | ".ent", 183 | ".env", 184 | ".erb", 185 | ".erl", 186 | ".eslintignore", 187 | ".eslintrc", 188 | ".ex", 189 | ".exs", 190 | ".f", 191 | ".f03", 192 | ".f77", 193 | ".f90", 194 | ".f95", 195 | ".fish", 196 | ".for", 197 | ".fpp", 198 | ".frm", 199 | ".fs", 200 | ".fsproj", 201 | ".fsx", 202 | ".ftn", 203 | ".gemrc", 204 | ".gemspec", 205 | ".gitattributes", 206 | ".gitconfig", 207 | ".gitignore", 208 | ".gitkeep", 209 | ".gitmodules", 210 | ".go", 211 | ".gpp", 212 | ".gradle", 213 | ".graphql", 214 | ".groovy", 215 | ".groupproj", 216 | ".grunit", 217 | ".gtmpl", 218 | ".gv", 219 | ".gvimrc", 220 | ".h", 221 | ".haml", 222 | ".hbs", 223 | ".hgignore", 224 | ".hh", 225 | ".hpp", 226 | ".hrl", 227 | ".hs", 228 | ".hta", 229 | ".htaccess", 230 | ".htc", 231 | ".htm", 232 | ".html", 233 | ".htmx", 234 | ".htpasswd", 235 | ".hxx", 236 | ".ics", 237 | ".iced", 238 | ".il", 239 | ".iml", 240 | ".inc", 241 | ".inf", 242 | ".info", 243 | ".ini", 244 | ".ino", 245 | ".int", 246 | ".irbrc", 247 | ".itcl", 248 | ".itermcolors", 249 | ".itk", 250 | ".jade", 251 | ".java", 252 | ".jhtm", 253 | ".jhtml", 254 | ".js", 255 | ".javascript", 256 | ".jscsrc", 257 | ".jshintignore", 258 | ".jshintrc", 259 | ".json", 260 | ".json5", 261 | ".jsonld", 262 | ".jsp", 263 | ".jspx", 264 | ".jsx", 265 | ".ksh", 266 | ".less", 267 | ".lhs", 268 | ".lisp", 269 | ".log", 270 | ".ls", 271 | ".lsp", 272 | ".lua", 273 | ".m", 274 | ".m4", 275 | ".mak", 276 | ".map", 277 | ".markdown", 278 | ".master", 279 | ".md", 280 | ".mdown", 281 | ".mdwn", 282 | ".mdx", 283 | ".mermaid", 284 | ".metadata", 285 | ".mht", 286 | ".mhtml", 287 | ".mjs", 288 | ".mk", 289 | ".mkd", 290 | ".mkdn", 291 | ".mkdown", 292 | ".ml", 293 | ".mli", 294 | ".mm", 295 | ".mmd", 296 | ".mxml", 297 | ".nfm", 298 | ".nfo", 299 | ".noon", 300 | ".npmignore", 301 | ".npmrc", 302 | ".nuspec", 303 | ".nvmrc", 304 | ".ops", 305 | ".pas", 306 | ".pasm", 307 | ".patch", 308 | ".pbxproj", 309 | ".pch", 310 | ".pem", 311 | ".pg", 312 | ".php", 313 | ".php3", 314 | ".php4", 315 | ".php5", 316 | ".phpt", 317 | ".phtml", 318 | ".pir", 319 | ".pl", 320 | ".pm", 321 | ".pmc", 322 | ".pod", 323 | ".pot", 324 | ".prettierrc", 325 | ".properties", 326 | ".props", 327 | ".ps1", 328 | ".pt", 329 | ".pug", 330 | ".purs", 331 | ".py", 332 | ".pyx", 333 | ".r", 334 | ".rake", 335 | ".rb", 336 | ".rbw", 337 | ".rc", 338 | ".rdoc", 339 | ".rdoc_options", 340 | ".rels", 341 | ".resx", 342 | ".rexx", 343 | ".rhtml", 344 | ".rjs", 345 | ".rlib", 346 | ".ron", 347 | ".rs", 348 | ".rss", 349 | ".rst", 350 | ".rtf", 351 | ".rvmrc", 352 | ".rxml", 353 | ".s", 354 | ".sass", 355 | ".scala", 356 | ".scm", 357 | ".scss", 358 | ".seestyle", 359 | ".sh", 360 | ".shtml", 361 | ".sln", 362 | ".slnx", 363 | ".slnf", 364 | ".sls", 365 | ".spec", 366 | ".sql", 367 | ".sqlite", 368 | ".sqlproj", 369 | ".srt", 370 | ".ss", 371 | ".sss", 372 | ".st", 373 | ".strings", 374 | ".sty", 375 | ".styl", 376 | ".stylus", 377 | ".sub", 378 | ".sublime-build", 379 | ".sublime-commands", 380 | ".sublime-completions", 381 | ".sublime-keymap", 382 | ".sublime-macro", 383 | ".sublime-menu", 384 | ".sublime-project", 385 | ".sublime-settings", 386 | ".sublime-workspace", 387 | ".sv", 388 | ".svc", 389 | ".svg", 390 | ".swift", 391 | ".t", 392 | ".tcl", 393 | ".tcsh", 394 | ".terminal", 395 | ".tex", 396 | ".text", 397 | ".textile", 398 | ".tg", 399 | ".tk", 400 | ".tmLanguage", 401 | ".tmpl", 402 | ".tmTheme", 403 | ".toml", 404 | ".tpl", 405 | ".ts", 406 | ".tsv", 407 | ".tsx", 408 | ".tt", 409 | ".tt2", 410 | ".ttml", 411 | ".twig", 412 | ".txt", 413 | ".v", 414 | ".vb", 415 | ".vbproj", 416 | ".vbs", 417 | ".vcproj", 418 | ".vcxproj", 419 | ".vh", 420 | ".vhd", 421 | ".vhdl", 422 | ".vim", 423 | ".viminfo", 424 | ".vimrc", 425 | ".vm", 426 | ".vue", 427 | ".webapp", 428 | ".webmanifest", 429 | ".wsc", 430 | ".x-php", 431 | ".xaml", 432 | ".xht", 433 | ".xhtml", 434 | ".xml", 435 | ".xs", 436 | ".xsd", 437 | ".xsl", 438 | ".xslt", 439 | ".y", 440 | ".yaml", 441 | ".yml", 442 | ".zsh", 443 | ".zshrc" 444 | } 445 | .ToFrozenSet(); 446 | 447 | public static IReadOnlyCollection TextExtensions => textExtensions; 448 | 449 | [Obsolete("Use IsTextFile or IsTextExtension")] 450 | public static bool IsText([NotNullWhen(true)] string? extensionOrPath) 451 | { 452 | if (extensionOrPath == null) 453 | { 454 | return false; 455 | } 456 | 457 | if (extensionOrPath.Contains('.') || 458 | extensionOrPath.Contains(Path.DirectorySeparatorChar) || 459 | extensionOrPath.Contains(Path.AltDirectorySeparatorChar)) 460 | { 461 | var extension = Path.GetExtension(extensionOrPath); 462 | return textExtensions.Contains(extension); 463 | } 464 | 465 | return textExtensions.Contains($".{extensionOrPath}"); 466 | } 467 | 468 | [Obsolete("Use IsTextFile or IsTextExtension")] 469 | public static bool IsText(CharSpan extensionOrPath) => 470 | IsText(extensionOrPath.ToString()); 471 | } 472 | -------------------------------------------------------------------------------- /src/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | end_of_line = lf 6 | insert_final_newline = false 7 | 8 | [*.cs] 9 | indent_size = 4 10 | charset = utf-8 11 | 12 | # Redundant accessor body 13 | resharper_redundant_accessor_body_highlighting = error 14 | 15 | # Replace with field keyword 16 | resharper_replace_with_field_keyword_highlighting = error 17 | 18 | # Replace with single call to Single(..) 19 | resharper_replace_with_single_call_to_single_highlighting = error 20 | 21 | # Replace with single call to SingleOrDefault(..) 22 | resharper_replace_with_single_call_to_single_or_default_highlighting = error 23 | 24 | # Replace with single call to LastOrDefault(..) 25 | resharper_replace_with_single_call_to_last_or_default_highlighting = error 26 | 27 | # Element is localizable 28 | resharper_localizable_element_highlighting = none 29 | 30 | # Replace with single call to Last(..) 31 | resharper_replace_with_single_call_to_last_highlighting = error 32 | 33 | # Replace with single call to First(..) 34 | resharper_replace_with_single_call_to_first_highlighting = error 35 | 36 | # Replace with single call to FirstOrDefault(..) 37 | resharper_replace_with_single_call_to_first_or_default_highlighting = error 38 | 39 | # Replace with single call to Any(..) 40 | resharper_replace_with_single_call_to_any_highlighting = error 41 | 42 | # Simplify negative equality expression 43 | resharper_negative_equality_expression_highlighting = error 44 | 45 | # Replace with single call to Count(..) 46 | resharper_replace_with_single_call_to_count_highlighting = error 47 | 48 | # Declare types in namespaces 49 | dotnet_diagnostic.CA1050.severity = none 50 | 51 | # Use Literals Where Appropriate 52 | dotnet_diagnostic.CA1802.severity = error 53 | 54 | # Template should be a static expression 55 | dotnet_diagnostic.CA2254.severity = error 56 | 57 | # Potentially misleading parameter name in lambda or local function 58 | resharper_all_underscore_local_parameter_name_highlighting = none 59 | 60 | # Redundant explicit collection creation in argument of 'params' parameter 61 | resharper_redundant_explicit_params_array_creation_highlighting = error 62 | 63 | # Do not initialize unnecessarily 64 | dotnet_diagnostic.CA1805.severity = error 65 | 66 | # Avoid unsealed attributes 67 | dotnet_diagnostic.CA1813.severity = error 68 | 69 | # Test for empty strings using string length 70 | dotnet_diagnostic.CA1820.severity = none 71 | 72 | # Remove empty finalizers 73 | dotnet_diagnostic.CA1821.severity = error 74 | 75 | # Mark members as static 76 | dotnet_diagnostic.CA1822.severity = error 77 | 78 | # Avoid unused private fields 79 | dotnet_diagnostic.CA1823.severity = error 80 | 81 | # Avoid zero-length array allocations 82 | dotnet_diagnostic.CA1825.severity = error 83 | 84 | # Use property instead of Linq Enumerable method 85 | dotnet_diagnostic.CA1826.severity = error 86 | 87 | # Do not use Count()/LongCount() when Any() can be used 88 | dotnet_diagnostic.CA1827.severity = error 89 | dotnet_diagnostic.CA1828.severity = error 90 | 91 | # Use Length/Count property instead of Enumerable.Count method 92 | dotnet_diagnostic.CA1829.severity = error 93 | 94 | # Prefer strongly-typed Append and Insert method overloads on StringBuilder 95 | dotnet_diagnostic.CA1830.severity = error 96 | 97 | # Use AsSpan instead of Range-based indexers for string when appropriate 98 | dotnet_diagnostic.CA1831.severity = error 99 | 100 | # Use AsSpan instead of Range-based indexers for string when appropriate 101 | dotnet_diagnostic.CA1831.severity = error 102 | dotnet_diagnostic.CA1832.severity = error 103 | dotnet_diagnostic.CA1833.severity = error 104 | 105 | # Use StringBuilder.Append(char) for single character strings 106 | dotnet_diagnostic.CA1834.severity = error 107 | 108 | # Prefer IsEmpty over Count when available 109 | dotnet_diagnostic.CA1836.severity = error 110 | 111 | # Prefer IsEmpty over Count when available 112 | dotnet_diagnostic.CA1836.severity = error 113 | 114 | # Use Environment.ProcessId instead of Process.GetCurrentProcess().Id 115 | dotnet_diagnostic.CA1837.severity = error 116 | 117 | # Use Environment.ProcessPath instead of Process.GetCurrentProcess().MainModule.FileName 118 | dotnet_diagnostic.CA1839.severity = error 119 | 120 | # Use Environment.CurrentManagedThreadId instead of Thread.CurrentThread.ManagedThreadId 121 | dotnet_diagnostic.CA1840.severity = error 122 | 123 | # Prefer Dictionary Contains methods 124 | dotnet_diagnostic.CA1841.severity = error 125 | 126 | # Do not use WhenAll with a single task 127 | dotnet_diagnostic.CA1842.severity = error 128 | 129 | # Do not use WhenAll/WaitAll with a single task 130 | dotnet_diagnostic.CA1842.severity = error 131 | dotnet_diagnostic.CA1843.severity = error 132 | 133 | # Use span-based 'string.Concat' 134 | dotnet_diagnostic.CA1845.severity = error 135 | 136 | # Prefer AsSpan over Substring 137 | dotnet_diagnostic.CA1846.severity = error 138 | 139 | # Use string.Contains(char) instead of string.Contains(string) with single characters 140 | dotnet_diagnostic.CA1847.severity = error 141 | 142 | # Prefer static HashData method over ComputeHash 143 | dotnet_diagnostic.CA1850.severity = error 144 | 145 | # Possible multiple enumerations of IEnumerable collection 146 | dotnet_diagnostic.CA1851.severity = error 147 | 148 | # Unnecessary call to Dictionary.ContainsKey(key) 149 | dotnet_diagnostic.CA1853.severity = error 150 | 151 | # Prefer the IDictionary.TryGetValue(TKey, out TValue) method 152 | dotnet_diagnostic.CA1854.severity = error 153 | 154 | # Use Span.Clear() instead of Span.Fill() 155 | dotnet_diagnostic.CA1855.severity = error 156 | 157 | # Incorrect usage of ConstantExpected attribute 158 | dotnet_diagnostic.CA1856.severity = error 159 | 160 | # The parameter expects a constant for optimal performance 161 | dotnet_diagnostic.CA1857.severity = error 162 | 163 | # Use StartsWith instead of IndexOf 164 | dotnet_diagnostic.CA1858.severity = error 165 | 166 | # Avoid using Enumerable.Any() extension method 167 | dotnet_diagnostic.CA1860.severity = error 168 | 169 | # Avoid constant arrays as arguments 170 | dotnet_diagnostic.CA1861.severity = error 171 | 172 | # Use the StringComparison method overloads to perform case-insensitive string comparisons 173 | dotnet_diagnostic.CA1862.severity = error 174 | 175 | # Prefer the IDictionary.TryAdd(TKey, TValue) method 176 | dotnet_diagnostic.CA1864.severity = error 177 | 178 | # Use string.Method(char) instead of string.Method(string) for string with single char 179 | dotnet_diagnostic.CA1865.severity = error 180 | dotnet_diagnostic.CA1866.severity = error 181 | dotnet_diagnostic.CA1867.severity = error 182 | 183 | # Unnecessary call to 'Contains' for sets 184 | dotnet_diagnostic.CA1868.severity = error 185 | 186 | # Cache and reuse 'JsonSerializerOptions' instances 187 | dotnet_diagnostic.CA1869.severity = error 188 | 189 | # Use a cached 'SearchValues' instance 190 | dotnet_diagnostic.CA1870.severity = error 191 | 192 | # Microsoft .NET properties 193 | trim_trailing_whitespace = true 194 | csharp_preferred_modifier_order = public, private, protected, internal, new, static, abstract, virtual, sealed, readonly, override, extern, unsafe, volatile, async:suggestion 195 | resharper_namespace_body = file_scoped 196 | dotnet_naming_rule.private_constants_rule.severity = warning 197 | dotnet_naming_rule.private_constants_rule.style = lower_camel_case_style 198 | dotnet_naming_rule.private_constants_rule.symbols = private_constants_symbols 199 | dotnet_naming_rule.private_instance_fields_rule.severity = warning 200 | dotnet_naming_rule.private_instance_fields_rule.style = lower_camel_case_style 201 | dotnet_naming_rule.private_instance_fields_rule.symbols = private_instance_fields_symbols 202 | dotnet_naming_rule.private_static_fields_rule.severity = warning 203 | dotnet_naming_rule.private_static_fields_rule.style = lower_camel_case_style 204 | dotnet_naming_rule.private_static_fields_rule.symbols = private_static_fields_symbols 205 | dotnet_naming_rule.private_static_readonly_rule.severity = warning 206 | dotnet_naming_rule.private_static_readonly_rule.style = lower_camel_case_style 207 | dotnet_naming_rule.private_static_readonly_rule.symbols = private_static_readonly_symbols 208 | dotnet_naming_style.lower_camel_case_style.capitalization = camel_case 209 | dotnet_naming_style.upper_camel_case_style.capitalization = pascal_case 210 | dotnet_naming_symbols.private_constants_symbols.applicable_accessibilities = private 211 | dotnet_naming_symbols.private_constants_symbols.applicable_kinds = field 212 | dotnet_naming_symbols.private_constants_symbols.required_modifiers = const 213 | dotnet_naming_symbols.private_instance_fields_symbols.applicable_accessibilities = private 214 | dotnet_naming_symbols.private_instance_fields_symbols.applicable_kinds = field 215 | dotnet_naming_symbols.private_static_fields_symbols.applicable_accessibilities = private 216 | dotnet_naming_symbols.private_static_fields_symbols.applicable_kinds = field 217 | dotnet_naming_symbols.private_static_fields_symbols.required_modifiers = static 218 | dotnet_naming_symbols.private_static_readonly_symbols.applicable_accessibilities = private 219 | dotnet_naming_symbols.private_static_readonly_symbols.applicable_kinds = field 220 | dotnet_naming_symbols.private_static_readonly_symbols.required_modifiers = static, readonly 221 | dotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary:none 222 | dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:none 223 | dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:none 224 | 225 | # ReSharper properties 226 | resharper_object_creation_when_type_not_evident = target_typed 227 | 228 | # ReSharper inspection severities 229 | resharper_arrange_object_creation_when_type_evident_highlighting = error 230 | resharper_arrange_object_creation_when_type_not_evident_highlighting = error 231 | resharper_arrange_redundant_parentheses_highlighting = error 232 | resharper_arrange_static_member_qualifier_highlighting = error 233 | resharper_arrange_this_qualifier_highlighting = error 234 | resharper_arrange_type_member_modifiers_highlighting = none 235 | resharper_built_in_type_reference_style_for_member_access_highlighting = hint 236 | resharper_built_in_type_reference_style_highlighting = hint 237 | resharper_check_namespace_highlighting = none 238 | resharper_convert_to_using_declaration_highlighting = error 239 | resharper_field_can_be_made_read_only_local_highlighting = none 240 | resharper_merge_into_logical_pattern_highlighting = warning 241 | resharper_merge_into_pattern_highlighting = error 242 | resharper_method_has_async_overload_highlighting = warning 243 | # because stop rider giving errors before source generators have run 244 | resharper_partial_type_with_single_part_highlighting = warning 245 | resharper_redundant_base_qualifier_highlighting = warning 246 | resharper_redundant_cast_highlighting = error 247 | resharper_redundant_empty_object_creation_argument_list_highlighting = error 248 | resharper_redundant_empty_object_or_collection_initializer_highlighting = error 249 | resharper_redundant_name_qualifier_highlighting = error 250 | resharper_redundant_suppress_nullable_warning_expression_highlighting = error 251 | resharper_redundant_using_directive_highlighting = error 252 | resharper_redundant_verbatim_string_prefix_highlighting = error 253 | resharper_redundant_lambda_signature_parentheses_highlighting = error 254 | resharper_replace_substring_with_range_indexer_highlighting = warning 255 | resharper_suggest_var_or_type_built_in_types_highlighting = error 256 | resharper_suggest_var_or_type_elsewhere_highlighting = error 257 | resharper_suggest_var_or_type_simple_types_highlighting = error 258 | resharper_unnecessary_whitespace_highlighting = error 259 | resharper_use_await_using_highlighting = warning 260 | resharper_use_deconstruction_highlighting = warning 261 | 262 | # Sort using and Import directives with System.* appearing first 263 | dotnet_sort_system_directives_first = true 264 | 265 | # Avoid "this." and "Me." if not necessary 266 | dotnet_style_qualification_for_field = false:error 267 | dotnet_style_qualification_for_property = false:error 268 | dotnet_style_qualification_for_method = false:error 269 | dotnet_style_qualification_for_event = false:error 270 | 271 | # Use language keywords instead of framework type names for type references 272 | dotnet_style_predefined_type_for_locals_parameters_members = true:error 273 | dotnet_style_predefined_type_for_member_access = true:error 274 | 275 | # Suggest more modern language features when available 276 | dotnet_style_object_initializer = true:error 277 | dotnet_style_collection_initializer = true:error 278 | dotnet_style_coalesce_expression = false:error 279 | dotnet_style_null_propagation = true:error 280 | dotnet_style_explicit_tuple_names = true:error 281 | 282 | # Use collection expression syntax 283 | resharper_use_collection_expression_highlighting = error 284 | 285 | # Prefer "var" everywhere 286 | csharp_style_var_for_built_in_types = true:error 287 | csharp_style_var_when_type_is_apparent = true:error 288 | csharp_style_var_elsewhere = true:error 289 | 290 | # Prefer method-like constructs to have a block body 291 | csharp_style_expression_bodied_methods = true:error 292 | csharp_style_expression_bodied_local_functions = true:error 293 | csharp_style_expression_bodied_constructors = true:error 294 | csharp_style_expression_bodied_operators = true:error 295 | resharper_place_expr_method_on_single_line = false 296 | 297 | # Prefer property-like constructs to have an expression-body 298 | csharp_style_expression_bodied_properties = true:error 299 | csharp_style_expression_bodied_indexers = true:error 300 | csharp_style_expression_bodied_accessors = true:error 301 | 302 | # Suggest more modern language features when available 303 | csharp_style_pattern_matching_over_is_with_cast_check = true:error 304 | csharp_style_pattern_matching_over_as_with_null_check = true:error 305 | csharp_style_inlined_variable_declaration = true:suggestion 306 | csharp_style_throw_expression = true:suggestion 307 | csharp_style_conditional_delegate_call = true:suggestion 308 | 309 | # Newline settings 310 | #csharp_new_line_before_open_brace = all:error 311 | resharper_max_array_initializer_elements_on_line = 1 312 | csharp_new_line_before_else = true 313 | csharp_new_line_before_catch = true 314 | csharp_new_line_before_finally = true 315 | csharp_new_line_before_members_in_object_initializers = true 316 | csharp_new_line_before_members_in_anonymous_types = true 317 | resharper_wrap_before_first_type_parameter_constraint = true 318 | resharper_wrap_extends_list_style = chop_always 319 | resharper_wrap_after_dot_in_method_calls = false 320 | resharper_wrap_before_binary_pattern_op = false 321 | resharper_wrap_object_and_collection_initializer_style = chop_always 322 | resharper_place_simple_initializer_on_single_line = false 323 | 324 | # space 325 | resharper_space_around_lambda_arrow = true 326 | 327 | dotnet_style_require_accessibility_modifiers = never:error 328 | resharper_place_type_constraints_on_same_line = false 329 | resharper_blank_lines_inside_namespace = 0 330 | resharper_blank_lines_after_file_scoped_namespace_directive = 1 331 | resharper_blank_lines_inside_type = 0 332 | 333 | insert_final_newline = false 334 | resharper_place_attribute_on_same_line = false 335 | 336 | #braces https://www.jetbrains.com/help/resharper/EditorConfig_CSHARP_CSharpCodeStylePageImplSchema.html#Braces 337 | resharper_braces_for_ifelse = required 338 | resharper_braces_for_foreach = required 339 | resharper_braces_for_while = required 340 | resharper_braces_for_dowhile = required 341 | resharper_braces_for_lock = required 342 | resharper_braces_for_fixed = required 343 | resharper_braces_for_for = required 344 | 345 | resharper_return_value_of_pure_method_is_not_used_highlighting = error 346 | 347 | 348 | resharper_misleading_body_like_statement_highlighting = error 349 | 350 | resharper_redundant_record_class_keyword_highlighting = error 351 | 352 | resharper_redundant_extends_list_entry_highlighting = error 353 | 354 | resharper_redundant_type_arguments_inside_nameof_highlighting = error 355 | 356 | # Xml files 357 | [*.{xml,config,nuspec,resx,vsixmanifest,csproj,targets,props,fsproj}] 358 | indent_size = 2 359 | # https://www.jetbrains.com/help/resharper/EditorConfig_XML_XmlCodeStylePageSchema.html#resharper_xml_blank_line_after_pi 360 | resharper_blank_line_after_pi = false 361 | resharper_space_before_self_closing = true 362 | ij_xml_space_inside_empty_tag = true 363 | 364 | [*.json] 365 | indent_size = 2 366 | 367 | # Verify settings 368 | [*.{received,verified}.{txt,xml,json,md,sql,csv,html,htm,nuspec,rels}] 369 | charset = utf-8-bom 370 | end_of_line = lf 371 | indent_size = unset 372 | indent_style = unset 373 | insert_final_newline = false 374 | tab_width = unset 375 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /src/Shared.sln.DotSettings: -------------------------------------------------------------------------------- 1 | 2 | False 3 | Quiet 4 | True 5 | True 6 | True 7 | DO_NOT_SHOW 8 | ERROR 9 | ERROR 10 | ERROR 11 | WARNING 12 | ERROR 13 | ERROR 14 | ERROR 15 | ERROR 16 | ERROR 17 | ERROR 18 | ERROR 19 | ERROR 20 | ERROR 21 | ERROR 22 | ERROR 23 | ERROR 24 | ERROR 25 | ERROR 26 | ERROR 27 | ERROR 28 | ERROR 29 | ERROR 30 | ERROR 31 | ERROR 32 | ERROR 33 | ERROR 34 | ERROR 35 | ERROR 36 | ERROR 37 | ERROR 38 | ERROR 39 | ERROR 40 | ERROR 41 | ERROR 42 | ERROR 43 | DO_NOT_SHOW 44 | DO_NOT_SHOW 45 | ERROR 46 | ERROR 47 | ERROR 48 | ERROR 49 | ERROR 50 | ERROR 51 | ERROR 52 | ERROR 53 | ERROR 54 | ERROR 55 | ERROR 56 | ERROR 57 | C90+,E79+,S14+ 58 | ERROR 59 | ERROR 60 | ERROR 61 | ERROR 62 | ERROR 63 | ERROR 64 | ERROR 65 | ERROR 66 | ERROR 67 | ERROR 68 | ERROR 69 | ERROR 70 | ERROR 71 | ERROR 72 | ERROR 73 | ERROR 74 | ERROR 75 | ERROR 76 | ERROR 77 | ERROR 78 | ERROR 79 | ERROR 80 | ERROR 81 | ERROR 82 | ERROR 83 | ERROR 84 | ERROR 85 | ERROR 86 | ERROR 87 | ERROR 88 | ERROR 89 | ERROR 90 | ERROR 91 | ERROR 92 | ERROR 93 | ERROR 94 | ERROR 95 | ERROR 96 | ERROR 97 | ERROR 98 | ERROR 99 | ERROR 100 | ERROR 101 | ERROR 102 | ERROR 103 | ERROR 104 | ERROR 105 | ERROR 106 | ERROR 107 | ERROR 108 | ERROR 109 | ERROR 110 | ERROR 111 | ERROR 112 | ERROR 113 | ERROR 114 | ERROR 115 | ERROR 116 | ERROR 117 | ERROR 118 | ERROR 119 | ERROR 120 | ERROR 121 | ERROR 122 | DO_NOT_SHOW 123 | *.received.* 124 | *.verified.* 125 | ERROR 126 | ERROR 127 | DO_NOT_SHOW 128 | ECMAScript 2016 129 | <?xml version="1.0" encoding="utf-16"?><Profile name="c# Cleanup"><AspOptimizeRegisterDirectives>True</AspOptimizeRegisterDirectives><CSCodeStyleAttributes ArrangeVarStyle="True" ArrangeTypeAccessModifier="True" ArrangeTypeMemberAccessModifier="True" SortModifiers="True" RemoveRedundantParentheses="True" AddMissingParentheses="True" ArrangeBraces="True" ArrangeAttributes="True" ArrangeCodeBodyStyle="True" ArrangeTrailingCommas="True" ArrangeObjectCreation="True" ArrangeDefaultValue="True" ArrangeNamespaces="True" /><CssAlphabetizeProperties>True</CssAlphabetizeProperties><JSStringLiteralQuotesDescriptor>True</JSStringLiteralQuotesDescriptor><CorrectVariableKindsDescriptor>True</CorrectVariableKindsDescriptor><VariablesToInnerScopesDescriptor>True</VariablesToInnerScopesDescriptor><StringToTemplatesDescriptor>True</StringToTemplatesDescriptor><JsInsertSemicolon>True</JsInsertSemicolon><RemoveRedundantQualifiersTs>True</RemoveRedundantQualifiersTs><OptimizeImportsTs>True</OptimizeImportsTs><OptimizeReferenceCommentsTs>True</OptimizeReferenceCommentsTs><PublicModifierStyleTs>True</PublicModifierStyleTs><ExplicitAnyTs>True</ExplicitAnyTs><TypeAnnotationStyleTs>True</TypeAnnotationStyleTs><RelativePathStyleTs>True</RelativePathStyleTs><AsInsteadOfCastTs>True</AsInsteadOfCastTs><RemoveCodeRedundancies>True</RemoveCodeRedundancies><CSUseAutoProperty>True</CSUseAutoProperty><CSMakeFieldReadonly>True</CSMakeFieldReadonly><CSMakeAutoPropertyGetOnly>True</CSMakeAutoPropertyGetOnly><CSArrangeQualifiers>True</CSArrangeQualifiers><CSFixBuiltinTypeReferences>True</CSFixBuiltinTypeReferences><CssReformatCode>True</CssReformatCode><JsReformatCode>True</JsReformatCode><JsFormatDocComments>True</JsFormatDocComments><CSOptimizeUsings><OptimizeUsings>True</OptimizeUsings></CSOptimizeUsings><CSShortenReferences>True</CSShortenReferences><CSReformatCode>True</CSReformatCode><CSharpFormatDocComments>True</CSharpFormatDocComments><FormatAttributeQuoteDescriptor>True</FormatAttributeQuoteDescriptor><HtmlReformatCode>True</HtmlReformatCode><XAMLCollapseEmptyTags>False</XAMLCollapseEmptyTags><IDEA_SETTINGS>&lt;profile version="1.0"&gt; 130 | &lt;option name="myName" value="c# Cleanup" /&gt; 131 | &lt;/profile&gt;</IDEA_SETTINGS><RIDER_SETTINGS>&lt;profile&gt; 132 | &lt;Language id="EditorConfig"&gt; 133 | &lt;Reformat&gt;false&lt;/Reformat&gt; 134 | &lt;/Language&gt; 135 | &lt;Language id="HTML"&gt; 136 | &lt;OptimizeImports&gt;false&lt;/OptimizeImports&gt; 137 | &lt;Reformat&gt;false&lt;/Reformat&gt; 138 | &lt;Rearrange&gt;false&lt;/Rearrange&gt; 139 | &lt;/Language&gt; 140 | &lt;Language id="JSON"&gt; 141 | &lt;Reformat&gt;false&lt;/Reformat&gt; 142 | &lt;/Language&gt; 143 | &lt;Language id="RELAX-NG"&gt; 144 | &lt;Reformat&gt;false&lt;/Reformat&gt; 145 | &lt;/Language&gt; 146 | &lt;Language id="XML"&gt; 147 | &lt;OptimizeImports&gt;false&lt;/OptimizeImports&gt; 148 | &lt;Reformat&gt;false&lt;/Reformat&gt; 149 | &lt;Rearrange&gt;false&lt;/Rearrange&gt; 150 | &lt;/Language&gt; 151 | &lt;/profile&gt;</RIDER_SETTINGS></Profile> 152 | ExpressionBody 153 | ExpressionBody 154 | ExpressionBody 155 | False 156 | NEVER 157 | NEVER 158 | False 159 | False 160 | False 161 | True 162 | False 163 | CHOP_ALWAYS 164 | False 165 | False 166 | RemoveIndent 167 | RemoveIndent 168 | False 169 | True 170 | True 171 | True 172 | True 173 | True 174 | ERROR 175 | DoNothing 176 | --------------------------------------------------------------------------------