Skip to content

Add --rename and --rename-path to rename and move files to close #780 - #785

Merged
mathiasrw merged 11 commits into
mainfrom
fix/780
Oct 23, 2026
Merged

mathiasrw merged 11 commits into
mainfrom
fix/780

Conversation

@mathiasrw

@mathiasrw mathiasrw commented Oct 23, 2026 •

Copy link
Copy Markdown
Owner

Closes #780

Stacked on #784.

Change

  • --rename (-r) does the search and replace on the name of each file, and renames the file to the result. The folder and the content are not touched. A / in a new name stops the run with "/" is not allowed in names. Use --rename-path to move files.
  • --rename-path does it on the whole path, so a / in the replacement moves the file. Folders that are not there are made. The path is the one RexReplace works on: as found, or the full path with --full-path.
> rexreplace '\.markdown$' '.md' '**/*.markdown' --rename
docs/intro.md
docs/setup.md

> rexreplace '^' 'archive/' '*.log' --rename-path
archive/a.log
archive/b.log
  • --replacement-js works as for content: the name (or the path) is the text, and file, name, ext and the rest are about the file before the rename.
  • --keep-backup keeps the old file, so the file is copied and not moved.
  • --rename-force writes over a file that is there already.
  • --rename and --rename-path can not be used together, and --rename-force needs one of them.
  • Piped data can not be renamed, so it is a panic.

Clashes

If planned renames clash the process is halted and no change is applied to any file (exit code 3). A clash is when

  • two files would get the same new path,
  • a new path is another file in the run, renamed or not (like a swap),
  • or a new path is a file outside the run that is there already.

--rename-force only allows the last one. Each clash is one error, with each path on its own line so long paths can be read, and then a panic says that no change is applied to any file:

 ❌ Renames clashing with other files in this run are not allowed.
    From: docs/a.md
    To:   docs/b.md

 ❌ Planned renames clash, so no change is applied to any file
    No further processing.

The paths are compared as absolute paths, so a.md and ./a.md are the same, and the case is ignored, as X.md and x.md are the same file on macOS and Windows. A file can still change only the case of its own name, but only when the new path is really the same file (the same device and inode). On Linux a.md and A.md can be two files, so then it is a clash. Tests for this run only on a file system that is case-sensitive, so on Linux in CI. Just before each rename, the new path is checked again, as the files can have changed since.

The check uses Set.intersection(). src/shim.ts adds it when the runtime does not have it (Node 18 and 20, which the CI tests). It is a few lines of our own, as the shims from es-shims and core-js are spread over many files.

Output

Command stdout stderr Renamed
--rename the new names nothing yes
--rename --simulate the new names the old names no
--rename --output the new names the old names no
--rename --output-match the matches in the names the old names no
  • With --simulate and --output the old name is printed just before the new one, so they come in pairs in a terminal.
  • --verbose tells each step before it is done: Make folder:, Write over:, Rename: or Copy:, and Same name:.
  • The status report has renames, with {old, new} for each file that was renamed, or would be with --simulate and --output. A rename that fails is not in it.
  • --output-match only shows what the pattern finds in the paths. The replacement is not used (it can be a dummy like _), so there is no clash check and nothing in renames.

The README has a section with small examples: renaming, moving, --simulate, a clash and --output-match.

Tests

yarn test-ci passes: the demo on Node and Bun (now with --rename), and 943 Bun tests. test/engine/rename.test.js, test/engine/rename-force.test.js and test/cli/rename.test.js are new.

@mathiasrw
mathiasrw added this pull request to stack #787 October 23, 2026 04:29
@mathiasrw mathiasrw changed the title Add --rename to search and replace in file names to close #780 Add --rename and --rename-path to rename and move files to close #780 Oct 23, 2026
Base automatically changed from fix/783 to main October 23, 2026 09:44
@mathiasrw
mathiasrw merged commit 4e4ccb8 into main Oct 23, 2026
6 of 7 checks passed
@mathiasrw
mathiasrw deleted the fix/780 branch October 23, 2026 09:48
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.

Add --rename to search and replace in file names

1 participant