From f3386b2ee9a4ac567867accf721e9bef8cc99b33 Mon Sep 17 00:00:00 2001 From: Art Chaidarun Date: Sun, 17 Aug 2025 17:17:21 -0400 Subject: [PATCH 1/4] Run Claude --- .editorconfig | 4 ++++ Dockerfile | 1 + README.md | 1 + entry.ts | 14 ++++++++++++++ test/after/hello.cs | 18 ++++++++++++++++++ test/before/hello.cs | 15 +++++++++++++++ 6 files changed, 53 insertions(+) create mode 100644 test/after/hello.cs create mode 100644 test/before/hello.cs diff --git a/.editorconfig b/.editorconfig index 711fa53..593c9e8 100644 --- a/.editorconfig +++ b/.editorconfig @@ -14,6 +14,10 @@ max_line_length=100 indent_size=2 max_line_length=80 +[*.cs] +indent_size=2 +max_line_length=100 + [*.py] combine_as_imports=true force_grid_wrap=0 diff --git a/Dockerfile b/Dockerfile index bb66920..9e6a019 100644 --- a/Dockerfile +++ b/Dockerfile @@ -40,6 +40,7 @@ apk add --no-cache --virtual .build-deps \ py3-pip \ python3-dev apk add --no-cache \ + dotnet8-sdk \ libxslt \ nodejs \ python3 diff --git a/README.md b/README.md index 1d5622c..a314ee5 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ This repo currently contains a single [pre-commit](https://pre-commit.com/) hook - [xsltproc](http://www.xmlsoft.org/xslt/xsltproc.html) from libxslt v10139 for XML - [terraform fmt](https://github.com/hashicorp/terraform) v1.9.8 for Terraform - [ClangFormat](https://clang.llvm.org/docs/ClangFormat.html) v18.1.8 for C++, Protobuf +- [dotnet format](https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-format) for C# - [SVGO](https://github.com/svg/svgo) v3.3.2 for SVG - [Taplo](https://taplo.tamasfe.dev/) v0.9.3 for TOML - Custom regex transformations (basically [sed](https://en.wikipedia.org/wiki/Sed)), for example: diff --git a/entry.ts b/entry.ts index 7d0c5e4..ce9252d 100644 --- a/entry.ts +++ b/entry.ts @@ -80,6 +80,7 @@ const enum HookName { Autoflake = "autoflake", Black = "Black", ClangFormat = "ClangFormat", + DotnetFormat = "dotnet format", EsLint = "ESLint", Gofmt = "gofmt", GoogleJavaFormat = "google-java-format", @@ -191,6 +192,19 @@ const HOOKS: Record = { include: /\.(cpp|proto$)/, runAfter: [HookName.Sed], }), + [HookName.DotnetFormat]: createLockableHook({ + action: sources => + run( + "dotnet", + "format", + "--include", + sources.join(","), + "--verbosity", + "quiet", + ), + include: /\.cs$/, + runAfter: [HookName.Sed], + }), [HookName.EsLint]: createLockableHook({ action: async sources => { try { diff --git a/test/after/hello.cs b/test/after/hello.cs new file mode 100644 index 0000000..d416dc5 --- /dev/null +++ b/test/after/hello.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; + +namespace HelloWorld +{ + public class Program + { + public static void Main(string[] args) + { + Console.WriteLine("Hello, World!"); + var numbers = new List { 1, 2, 3 }; + foreach (var number in numbers) + { + Console.WriteLine($"Number: {number}"); + } + } + } +} \ No newline at end of file diff --git a/test/before/hello.cs b/test/before/hello.cs new file mode 100644 index 0000000..0dd88fa --- /dev/null +++ b/test/before/hello.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; + +namespace HelloWorld{ +public class Program +{ +public static void Main(string[]args) +{ +Console.WriteLine("Hello, World!"); +var numbers=new List{1,2,3}; +foreach(var number in numbers){ +Console.WriteLine($"Number: {number}");} +} +} +} \ No newline at end of file From 3f92c2c8ad4065a65ee79146f0b2af205e1d8f09 Mon Sep 17 00:00:00 2001 From: Art Chaidarun Date: Sun, 17 Aug 2025 17:25:25 -0400 Subject: [PATCH 2/4] Fix by hand --- .editorconfig | 6 +----- README.md | 2 +- entry.ts | 8 ++++++-- test/after/hello.cs | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.editorconfig b/.editorconfig index 593c9e8..7e6ed17 100644 --- a/.editorconfig +++ b/.editorconfig @@ -6,7 +6,7 @@ trim_trailing_whitespace=true [makefile] indent_style=tab -[*.{gradle,java,kt,kts,sh,xml,yaml,yml}] +[*.{cs,gradle,java,kt,kts,sh,xml,yaml,yml}] indent_size=2 max_line_length=100 @@ -14,10 +14,6 @@ max_line_length=100 indent_size=2 max_line_length=80 -[*.cs] -indent_size=2 -max_line_length=100 - [*.py] combine_as_imports=true force_grid_wrap=0 diff --git a/README.md b/README.md index a314ee5..e437377 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ This repo currently contains a single [pre-commit](https://pre-commit.com/) hook - [xsltproc](http://www.xmlsoft.org/xslt/xsltproc.html) from libxslt v10139 for XML - [terraform fmt](https://github.com/hashicorp/terraform) v1.9.8 for Terraform - [ClangFormat](https://clang.llvm.org/docs/ClangFormat.html) v18.1.8 for C++, Protobuf -- [dotnet format](https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-format) for C# +- [dotnet format](https://docs.microsoft.com/en-us/dotnet/core/tools/dotnet-format) v8.0.111 for C# - [SVGO](https://github.com/svg/svgo) v3.3.2 for SVG - [Taplo](https://taplo.tamasfe.dev/) v0.9.3 for TOML - Custom regex transformations (basically [sed](https://en.wikipedia.org/wiki/Sed)), for example: diff --git a/entry.ts b/entry.ts index ce9252d..107e1b8 100644 --- a/entry.ts +++ b/entry.ts @@ -197,10 +197,14 @@ const HOOKS: Record = { run( "dotnet", "format", - "--include", - sources.join(","), + // TODO: Also format `style`, which fails with "Could not find a MSBuild + // project file or solution file". Generate a temporary project file? + "whitespace", "--verbosity", "quiet", + "--folder", + "--include", + ...sources, ), include: /\.cs$/, runAfter: [HookName.Sed], diff --git a/test/after/hello.cs b/test/after/hello.cs index d416dc5..338fe49 100644 --- a/test/after/hello.cs +++ b/test/after/hello.cs @@ -15,4 +15,4 @@ public static void Main(string[] args) } } } -} \ No newline at end of file +} From e747dad81454ce70a45b5284d02f798314162db0 Mon Sep 17 00:00:00 2001 From: Art Chaidarun Date: Sun, 17 Aug 2025 18:23:26 -0400 Subject: [PATCH 3/4] Enable `dotnet format style` --- .editorconfig | 6 +++ Makefile | 2 +- entry.ts | 95 ++++++++++++++++++++++++++------------------ test/after/hello.cs | 12 ++---- test/before/hello.cs | 15 ++++--- 5 files changed, 75 insertions(+), 55 deletions(-) diff --git a/.editorconfig b/.editorconfig index 7e6ed17..29bab96 100644 --- a/.editorconfig +++ b/.editorconfig @@ -10,6 +10,12 @@ indent_style=tab indent_size=2 max_line_length=100 +; https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/style-rules/ +; https://google.github.io/styleguide/csharp-style.html#whitespace-rules +[*.cs] +csharp_new_line_before_open_brace = none +dotnet_diagnostic.IDE0011.severity = error + [*.{js,jsx,ts,tsx}] indent_size=2 max_line_length=80 diff --git a/Makefile b/Makefile index 7c918af..21f83c1 100644 --- a/Makefile +++ b/Makefile @@ -48,7 +48,7 @@ shell: # Runs tests .PHONY: test test: - docker run --rm -v "$${PWD}/test:/test" "$$(docker build --network=host -q .)" sh -c \ + docker run --rm --init -v "$${PWD}/test:/test" "$$(docker build --network=host -q .)" sh -c \ 'cd /tmp \ && cp -r /test/before actual \ && cp -r /test/after expected \ diff --git a/entry.ts b/entry.ts index 107e1b8..2608b8a 100644 --- a/entry.ts +++ b/entry.ts @@ -1,7 +1,8 @@ #!/usr/bin/env node import { exec } from "child_process"; -import { createReadStream, readFile, writeFile } from "fs"; +import { createReadStream } from "fs"; +import { readFile, unlink, writeFile } from "fs/promises"; import { createInterface } from "readline"; /** @@ -49,32 +50,26 @@ const run = (...args: string[]) => export const isTruthy = (value: T): value is NonNullable => !!value; /** Reads a file, transforms its contents, and writes the result if different */ -const transformFile = (path: string, transform: (before: string) => string) => - new Promise((resolve, reject) => { - readFile(path, "utf8", (err, data) => { - // File unreadable - if (err) { - reject(err); - return; - } - - // File empty - if (data === "") { - resolve(); - return; - } +const transformFile = async ( + path: string, + transform: (before: string) => string, +) => { + const data = await readFile(path, "utf8"); + + // File empty + if (data === "") { + return; + } - // File unmodified - const after = transform(data); - if (data === after) { - resolve(); - return; - } + // File unmodified + const after = transform(data); + if (data === after) { + return; + } - // File modified - writeFile(path, after, "utf8", err => (err ? reject(err) : resolve())); - }); - }); + // File modified + await writeFile(path, after, "utf8"); +}; const enum HookName { Autoflake = "autoflake", @@ -193,19 +188,43 @@ const HOOKS: Record = { runAfter: [HookName.Sed], }), [HookName.DotnetFormat]: createLockableHook({ - action: sources => - run( - "dotnet", - "format", - // TODO: Also format `style`, which fails with "Could not find a MSBuild - // project file or solution file". Generate a temporary project file? - "whitespace", - "--verbosity", - "quiet", - "--folder", - "--include", - ...sources, - ), + action: async sources => { + // Create project file + const projectFile = `dotnet-format-${Math.random()}.csproj`; + await writeFile( + projectFile, + ` + + net8.0 + + + ${sources.map(s => ``).join("")} + + `, + ); + try { + await run( + "dotnet", + "format", + "style", + "--verbosity", + "quiet", + projectFile, + ); + await run( + "dotnet", + "format", + "whitespace", + "--verbosity", + "quiet", + "--folder", + "--include", + ...sources, + ); + } finally { + await unlink(projectFile); + } + }, include: /\.cs$/, runAfter: [HookName.Sed], }), diff --git a/test/after/hello.cs b/test/after/hello.cs index 338fe49..fa00de6 100644 --- a/test/after/hello.cs +++ b/test/after/hello.cs @@ -1,16 +1,12 @@ using System; using System.Collections.Generic; -namespace HelloWorld -{ - public class Program - { - public static void Main(string[] args) - { +namespace HelloWorld { + public class Program { + public static void Main(string[] args) { Console.WriteLine("Hello, World!"); var numbers = new List { 1, 2, 3 }; - foreach (var number in numbers) - { + foreach (var number in numbers) { Console.WriteLine($"Number: {number}"); } } diff --git a/test/before/hello.cs b/test/before/hello.cs index 0dd88fa..c5a09d7 100644 --- a/test/before/hello.cs +++ b/test/before/hello.cs @@ -1,15 +1,14 @@ -using System; + using System ; using System.Collections.Generic; namespace HelloWorld{ -public class Program -{ -public static void Main(string[]args) + public class Program +{public static void Main(string[]args) { Console.WriteLine("Hello, World!"); -var numbers=new List{1,2,3}; -foreach(var number in numbers){ -Console.WriteLine($"Number: {number}");} +var numbers=new List{1,2,3}; +foreach (var number in numbers) +Console.WriteLine($"Number: {number}"); +} } } -} \ No newline at end of file From ae93294c80675a76c55674fdbcc5bd2f9ee9ac8b Mon Sep 17 00:00:00 2001 From: Art Chaidarun Date: Wed, 8 Oct 2025 02:41:42 -0400 Subject: [PATCH 4/4] Optimize --- entry.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/entry.ts b/entry.ts index 2608b8a..dd48d4e 100644 --- a/entry.ts +++ b/entry.ts @@ -195,6 +195,7 @@ const HOOKS: Record = { projectFile, ` + false net8.0 @@ -207,19 +208,17 @@ const HOOKS: Record = { "dotnet", "format", "style", + projectFile, "--verbosity", "quiet", - projectFile, ); await run( "dotnet", "format", "whitespace", + projectFile, "--verbosity", "quiet", - "--folder", - "--include", - ...sources, ); } finally { await unlink(projectFile);