Skip to content

Commit

Permalink
Adding an option to format generated files that are typically exclude…
Browse files Browse the repository at this point in the history
…d. (#1104)

closes #1055

Co-authored-by: Lasath Fernando <[email protected]>
  • Loading branch information
belav and shocklateboy92 authored Jan 9, 2024
1 parent 130efe2 commit fefebfe
Show file tree
Hide file tree
Showing 9 changed files with 128 additions and 35 deletions.
14 changes: 4 additions & 10 deletions Src/CSharpier.Cli.Tests/CliTests.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,13 @@
using System;
using System.IO;
namespace CSharpier.Cli.Tests;

using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using CliWrap;
using CliWrap.Buffered;
using FluentAssertions;
using NUnit.Framework;

namespace CSharpier.Cli.Tests;

using System.Collections.Generic;
using System.Linq;
using System.Reflection.Metadata;

// these tests are kind of nice as c# because they run in the same place.
// except the one test that has issues with console input redirection
// they used to be powershell, but doing the multiple file thing didn't work
Expand Down
21 changes: 15 additions & 6 deletions Src/CSharpier.Cli/CommandLineFormatter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,21 +51,26 @@ CancellationToken cancellationToken
);

if (
!GeneratedCodeUtilities.IsGeneratedCodeFile(filePath)
&& !optionsProvider.IsIgnored(filePath)
(
commandLineOptions.IncludeGenerated
|| !GeneratedCodeUtilities.IsGeneratedCodeFile(filePath)
) && !optionsProvider.IsIgnored(filePath)
)
{
var fileIssueLogger = new FileIssueLogger(
commandLineOptions.OriginalDirectoryOrFilePaths[0],
logger
);

var printerOptions = optionsProvider.GetPrinterOptionsFor(filePath);
printerOptions.IncludeGenerated = commandLineOptions.IncludeGenerated;

await PerformFormattingSteps(
fileToFormatInfo,
new StdOutFormattedFileWriter(console),
commandLineFormatterResult,
fileIssueLogger,
optionsProvider.GetPrinterOptionsFor(filePath),
printerOptions,
commandLineOptions,
FormattingCacheFactory.NullCache,
cancellationToken
Expand Down Expand Up @@ -187,15 +192,19 @@ CancellationToken cancellationToken

async Task FormatFile(string actualFilePath, string originalFilePath)
{
var printerOptions = optionsProvider.GetPrinterOptionsFor(actualFilePath);
if (
GeneratedCodeUtilities.IsGeneratedCodeFile(actualFilePath)
|| optionsProvider.IsIgnored(actualFilePath)
(
!commandLineOptions.IncludeGenerated
&& GeneratedCodeUtilities.IsGeneratedCodeFile(actualFilePath)
) || optionsProvider.IsIgnored(actualFilePath)
)
{
return;
}

var printerOptions = optionsProvider.GetPrinterOptionsFor(actualFilePath);
printerOptions.IncludeGenerated = commandLineOptions.IncludeGenerated;

await FormatPhysicalFile(
actualFilePath,
originalFilePath,
Expand Down
6 changes: 6 additions & 0 deletions Src/CSharpier.Cli/CommandLineOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public class CommandLineOptions
public bool PipeMultipleFiles { get; init; }
public bool NoCache { get; init; }
public bool NoMSBuildCheck { get; init; }
public bool IncludeGenerated { get; init; }
public string? StandardInFileContents { get; init; }
public string? ConfigPath { get; init; }
public string[] OriginalDirectoryOrFilePaths { get; init; } = Array.Empty<string>();
Expand All @@ -27,6 +28,7 @@ internal delegate Task<int> Handler(
bool pipeMultipleFiles,
bool noCache,
bool noMSBuildCheck,
bool includeGenerated,
string config,
LogLevel logLevel,
CancellationToken cancellationToken
Expand Down Expand Up @@ -59,6 +61,10 @@ public static RootCommand Create()
new[] { "--no-msbuild-check" },
"Bypass the check to determine if a csproj files references a different version of CSharpier.MsBuild."
),
new Option(
new[] { "--include-generated" },
"Include files generated by the SDK and files that begin with <autogenerated /> comments"
),
new Option(
new[] { "--fast" },
"Skip comparing syntax tree of formatted file to original file to validate changes."
Expand Down
2 changes: 2 additions & 0 deletions Src/CSharpier.Cli/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public static async Task<int> Run(
bool pipeMultipleFiles,
bool noCache,
bool noMSBuildCheck,
bool includeGenerated,
string configPath,
LogLevel logLevel,
CancellationToken cancellationToken
Expand Down Expand Up @@ -81,6 +82,7 @@ CancellationToken cancellationToken
Fast = fast,
SkipWrite = skipWrite,
WriteStdout = writeStdout || standardInFileContents != null,
IncludeGenerated = includeGenerated,
ConfigPath = actualConfigPath
};

Expand Down
53 changes: 53 additions & 0 deletions Src/CSharpier.Tests/CommandLineFormatterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,57 @@ public void Format_Skips_Generated_Files(string fileName)
result.OutputLines.FirstOrDefault().Should().StartWith("Formatted 0 files in ");
}

[TestCase("TemporaryGeneratedFile_Tester.cs")]
[TestCase("TestFile.designer.cs")]
[TestCase("TestFile.generated.cs")]
[TestCase("TestFile.g.cs")]
[TestCase("TestFile.g.i.cs")]
public void Format_Formats_Generated_Files_When_Include_Generated(string fileName)
{
var context = new TestContext();
var unformattedFilePath = fileName;
context.WhenAFileExists(unformattedFilePath, UnformattedClassContent);

var result = this.Format(context, includeGenerated: true);

result.OutputLines.FirstOrDefault().Should().StartWith("Formatted 1 files in ");
}

[TestCase("// <autogenerated />")]
[TestCase("/* <autogenerated /> */")]
[TestCase("// <auto-generated />")]
[TestCase("/* <auto-generated /> */")]
public void Format_Skips_Auto_Generated_Comment_File(string comment)
{
var context = new TestContext();
var unformattedContent = $"{comment}\n{UnformattedClassContent}";
context.WhenAFileExists("AutoGenerated.cs", unformattedContent);

var result = this.Format(context);

result.ExitCode.Should().Be(0);
context.GetFileContent("AutoGenerated.cs").Should().Be(unformattedContent);
}

[TestCase("// <autogenerated />")]
[TestCase("/* <autogenerated /> */")]
[TestCase("// <auto-generated />")]
[TestCase("/* <auto-generated /> */")]
public void Format_Formats_Auto_Generated_Comment_File_When_Include_Generated(string comment)
{
var context = new TestContext();
var unformattedContent = $"{comment}\n{UnformattedClassContent}";
context.WhenAFileExists("AutoGenerated.cs", unformattedContent);

var result = this.Format(context, includeGenerated: true);

result.ExitCode.Should().Be(0);
context
.GetFileContent("AutoGenerated.cs")
.Should()
.Be($"{comment}\n{FormattedClassContent}");
}

[TestCase("File.cs", "File.cs")]
[TestCase("File.cs", "*.cs")]
[TestCase("SubFolder/File.cs", "*.cs")]
Expand Down Expand Up @@ -581,6 +632,7 @@ private FormatResult Format(
bool skipWrite = false,
bool check = false,
bool writeStdout = false,
bool includeGenerated = false,
string? standardInFileContents = null,
params string[] directoryOrFilePaths
)
Expand Down Expand Up @@ -610,6 +662,7 @@ params string[] directoryOrFilePaths
Check = check,
WriteStdout = writeStdout || standardInFileContents != null,
StandardInFileContents = standardInFileContents,
IncludeGenerated = includeGenerated
},
context.FileSystem,
fakeConsole,
Expand Down
5 changes: 4 additions & 1 deletion Src/CSharpier/CSharpFormatter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,10 @@ CancellationToken cancellationToken
);
}

if (GeneratedCodeUtilities.BeginsWithAutoGeneratedComment(rootNode))
if (
!printerOptions.IncludeGenerated
&& GeneratedCodeUtilities.BeginsWithAutoGeneratedComment(rootNode)
)
{
return new CodeFormatterResult { Code = syntaxTree.ToString() };
}
Expand Down
1 change: 1 addition & 0 deletions Src/CSharpier/PrinterOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ internal class PrinterOptions
public int Width { get; set; } = 100;
public EndOfLine EndOfLine { get; set; } = EndOfLine.Auto;
public bool TrimInitialLines { get; init; } = true;
public bool IncludeGenerated { get; set; } = false;

public const int WidthUsedByTests = 100;

Expand Down
28 changes: 18 additions & 10 deletions docs/CLI.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,19 @@ Arguments:
<directoryOrFile> One or more paths to a directory containing files to format or a file to format. If a path is not specified the current directory is used

Options:
--check Check that files are formatted. Will not write any changes.
--loglevel Specify the log level - Debug, Information (default), Warning, Error, None
--no-cache Bypass the cache to determine if a file needs to be formatted.
--fast Skip comparing syntax tree of formatted file to original file to validate changes.
--skip-write Skip writing changes. Generally used for testing to ensure csharpier doesn't throw any errors or cause syntax tree validation failures.
--write-stdout Write the results of formatting any files to stdout.
--pipe-multiple-files Keep csharpier running so that multiples files can be piped to it via stdin
--config-path Path to the CSharpier configuration file
--version Show version information
-?, -h, --help Show help and usage information
--check Check that files are formatted. Will not write any changes.
--loglevel <loglevel> Specify the log level - Debug, Information (default), Warning, Error, None [default: Information]
--no-cache Bypass the cache to determine if a file needs to be formatted.
--no-msbuild-check Bypass the check to determine if a csproj files references a different version of CSharpier.MsBuild.
--include-generated Include files generated by the SDK and files that begin with <autogenerated /> comments
--fast Skip comparing syntax tree of formatted file to original file to validate changes.
--skip-write Skip writing changes. Generally used for testing to ensure csharpier doesn't throw any errors or cause syntax tree validation failures.
--write-stdout Write the results of formatting any files to stdout.
--pipe-multiple-files Keep csharpier running so that multiples files can be piped to it via stdin
--config-path <config-path> Path to the CSharpier configuration file
--version Show version information
-?, -h, --help Show help and usage information



```
Expand Down Expand Up @@ -66,6 +69,11 @@ By default the following are used as cache keys and a file is only formatted if

The cache is stored at `[LocalApplicationData]/CSharpier/.formattingCache`.

### --include-generated
_First available in 0.27.0_

By default CSharpier ignores any files generated by the SDK or that begin with a comment that contains `<autogenerated` or `<auto-generated`. This option can be used to format those files.

### --fast
CSharpier validates the changes it makes to a file.
It does this by comparing the syntax tree before and after formatting, but ignoring any whitespace trivia in the syntax tree.
Expand Down
33 changes: 25 additions & 8 deletions docs/Ignore.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,40 @@
title: Ignoring Code
hide_table_of_contents: true
---
Use `.csharpierignore` to bypass formatting specific files and folders.

Csharpier will ignore the following files
- Any file that begins with ```TemporaryGeneratedFile_```
- Any file that ends with ```.designer.cs```
- Any file that ends with ```.generated.cs```
- Any file that ends with ```.g.cs```
- Any file that ends with ```.g.i.cs```
- Any file that begins with a comment that contains ```<autogenerated``` or ```<auto-generated```
Use `csharpier-ignore` comments to bypass formatting specific parts of files.

## Ignoring Files `.csharpierignore`

Add a ```.csharpierignore``` file to ignore additional files and folders. The file uses [gitignore syntax](https://git-scm.com/docs/gitignore#_pattern_format)
Add a `.csharpierignore` file to ignore additional files and folders. The file uses [gitignore syntax](https://git-scm.com/docs/gitignore#_pattern_format)

Example
```
Uploads/
**/App_Data/*.cs
```

### Files Ignored by Default

Csharpier will ignore the following files

#### SDK Generated Files
_See [Configuration](CLI.md) for including these files_

- Any file that begins with `TemporaryGeneratedFile_`
- Any file that ends with `.designer.cs`
- Any file that ends with `.generated.cs`
- Any file that ends with `.g.cs`
- Any file that ends with `.g.i.cs`
- Any file that begins with a comment that contains `<autogenerated` or `<auto-generated`

#### Node Module Files

- Any file that matches the gitignore syntax `**/node_modules/**/*.cs`

## Ignoring Code

Add a `// csharpier-ignore` comment to exclude the next node from formatting. This is valid on statements and members.

```c#
Expand Down

0 comments on commit fefebfe

Please sign in to comment.