Skip to content

Treat a dotfile as having no extension in RemoveExtension and ChangeExtension [patch] - #426

Merged
matt-edmondson merged 1 commit into
mainfrom
fix/325-dotfile-extension
Oct 14, 2026
Merged

matt-edmondson merged 1 commit into
mainfrom
fix/325-dotfile-extension

Conversation

@matt-edmondson

Copy link
Copy Markdown
Contributor

Fixes #325

What changed

AbsoluteFilePath/RelativeFilePath used Path.ChangeExtension, which treats a leading-dot name as all extension. That caused two bugs:

  • RemoveExtension() on /home/user/.bashrc returned /home/user (on /.profile, it returned /), typed as a file path
  • ChangeExtension(".bak") returned /home/user/.bak instead of .bashrc.bak

SemanticFilePath gains two private protected helpers built on the existing FileExtension property, which already applies the dotfile rule from #287:

  • WeakStringWithoutExtension strips only FileExtension. It still drops a trailing dot after the name (file. → file), as Path.ChangeExtension did.
  • WeakStringWithExtension(ext) replaces the extension, or appends one when there is none.

RemoveExtension, ChangeExtension and FileNameWithoutExtension on both file path types now use these helpers, so every extension member follows one rule. For example, .bashrc's FileNameWithoutExtension is now .bashrc instead of an empty string.

Tests

Semantics.Test/Paths/DotfileExtensionTests.cs:

  • /home/user/.bashrc, /.profile, .gitignore, src/.editorconfig: RemoveExtension leaves each path unchanged, and ChangeExtension(".bak") appends to it, on both absolute and relative paths
  • FileNameWithoutExtension returns the whole name for a dotfile
  • src/.config.json loses or replaces only .json, and a dot in a directory name (app.v2/README) is not an extension

With the Semantics.Paths change stashed, 5 of the 7 tests fail; the two that pass check behaviour that was already correct. With the change applied, all 7 pass. The full Semantics.Test suite passes on net10.0 (1648 passed, 0 failed). Semantics.Paths builds for every target framework.

Open PRs #421–#423 touch other Semantics.Paths members, not these.

🤖 Generated with Claude Code

https://claude.ai/code/session_01QbGcYckSzgr6jPyoNYhWvA


Generated by Claude Code

…xtension [patch]

Path.ChangeExtension takes a leading-dot name as all extension, so
RemoveExtension on /home/user/.bashrc returned /home/user typed as a
file, and ChangeExtension renamed the file instead of appending. Both
now strip only FileExtension, which already follows the dotfile rule,
and FileNameWithoutExtension uses the same rule.

Fixes #325

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01QbGcYckSzgr6jPyoNYhWvA
@sonarqubecloud

Copy link
Copy Markdown

@matt-edmondson
matt-edmondson merged commit e0aa211 into main Oct 14, 2026
15 checks passed
@matt-edmondson
matt-edmondson deleted the fix/325-dotfile-extension branch October 14, 2026 01:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RemoveExtension() on a dotfile (.bashrc, .gitignore) returns the parent directory, or /, as a file path

2 participants