From 248664082410b9f48cabd02eec054299f73d88e7 Mon Sep 17 00:00:00 2001 From: Stephen Jennings Date: Wed, 15 Apr 2026 15:15:42 -0700 Subject: [PATCH] fix: Tolerate missing directories when formatting from stdin When formatting code passed via stdin, and using `--stdin-path`, the path passed may not exist. This is the case when using CSharpier as a [jj] fix tool: Commits are not checked out, so the directory containing the file being formatted may not actually exist on disk. When this happened, CSharpier was throwing a DirectoryNotFoundException from FindForDirectoryName in CSharpierConfigParser. Instead, we can predict this exception and check for configuration in the parent directory, until we find one that does exist. jj: https://jj-vcs.dev --- Src/CSharpier.Cli/CommandLineFormatter.cs | 9 +++++++++ Src/CSharpier.Cli/Options/OptionsProvider.cs | 5 ++++- Src/CSharpier.Tests/CommandLineFormatterTests.cs | 14 ++++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/Src/CSharpier.Cli/CommandLineFormatter.cs b/Src/CSharpier.Cli/CommandLineFormatter.cs index d8728908c..83c8fbdf5 100644 --- a/Src/CSharpier.Cli/CommandLineFormatter.cs +++ b/Src/CSharpier.Cli/CommandLineFormatter.cs @@ -40,6 +40,15 @@ CancellationToken cancellationToken filePath = directoryPath; directoryPath = fileSystem.Path.GetDirectoryName(directoryPath); ArgumentNullException.ThrowIfNull(directoryPath); + + // The directory from --stdin-path may not exist on disk. + // Walk up to the nearest existing ancestor for config resolution. + while (!fileSystem.Directory.Exists(directoryPath)) + { + directoryPath = fileSystem.Path.GetDirectoryName(directoryPath); + ArgumentNullException.ThrowIfNull(directoryPath); + } + pathSupplied = true; } // otherwise someone is running this as a single command and not sending a path diff --git a/Src/CSharpier.Cli/Options/OptionsProvider.cs b/Src/CSharpier.Cli/Options/OptionsProvider.cs index da223bbf8..132326b79 100644 --- a/Src/CSharpier.Cli/Options/OptionsProvider.cs +++ b/Src/CSharpier.Cli/Options/OptionsProvider.cs @@ -253,7 +253,10 @@ searchingDirectory is not null && !dictionary.TryGetValue(searchingDirectory.FullName, out result) ) { - if (shouldConsiderDirectory(searchingDirectory.FullName)) + if ( + this.fileSystem.Directory.Exists(searchingDirectory.FullName) + && shouldConsiderDirectory(searchingDirectory.FullName) + ) { dictionary[searchingDirectory.FullName] = result = await createFileAsync( searchingDirectory.FullName diff --git a/Src/CSharpier.Tests/CommandLineFormatterTests.cs b/Src/CSharpier.Tests/CommandLineFormatterTests.cs index 3cc6dae43..59f439415 100644 --- a/Src/CSharpier.Tests/CommandLineFormatterTests.cs +++ b/Src/CSharpier.Tests/CommandLineFormatterTests.cs @@ -781,6 +781,20 @@ public void Should_Format_StandardInput_And_Not_Consider_Gitignore_When_No_Path_ result.OutputLines.First().Should().Be(FormattedClassContent); } + [Test] + public void Should_Format_StandardInput_When_StdinFilePath_Directory_Does_Not_Exist() + { + var context = new TestContext(); + var result = Format( + context, + standardInFileContents: UnformattedClassContent, + directoryOrFilePaths: "NonExistent/SubDir/File.cs" + ); + + result.OutputLines.Should().ContainSingle(); + result.OutputLines.First().Should().Be(FormattedClassContent); + } + [Test] public void File_With_Mismatched_Line_Endings_In_Verbatim_String_Should_Pass_Validation() {