- mise for toolchain management
- macOS (uses Foundation/FileManager)
git clone https://github.com/your-org/swift-md-bulk-renamer.git
cd swift-md-bulk-renamer
mise installThis installs the pinned Swift version from mise.toml.
swift build # compile library and CLI
swift test # run all tests
swift run mvmd # run CLI
mise r test # run tests (mise task)Sources/
├── swift-md-bulk-renamer/ # Library
│ ├── Instruction.swift # Rename pair with NonemptyString fields
│ ├── NonemptyString.swift # Non-empty string wrapper type
│ ├── Parser.swift # Markdown table → [Instruction]
│ ├── Generator.swift # [Instruction] → Markdown table
│ ├── PathValidation.swift # Path safety checks
│ ├── Planner.swift # Conflict detection, dry-run
│ └── Executor.swift # FileManager operations
└── mvmd/ # CLI executable
└── main.swift # ArgumentParser command
Tests/
└── swift-md-bulk-renamer-tests/
├── NonemptyStringTests.swift
├── ParserTests.swift
├── PathValidationTests.swift
├── PlannerTests.swift
├── ExecutorTests.swift
└── CLITests.swift
| Package | Purpose |
|---|---|
| swift-markdown | Parse Markdown tables |
| swift-argument-parser | CLI arguments |
- Indent with tabs
- Use Swift Testing framework
- Backtick test names:
@Test func `rejects absolute paths`() throws {
#expect(throws: PathValidationError.absolutePath("/etc")) {
try validatePath("/etc")
}
}Data flow:
- Parser reads Markdown, extracts first 2-column table →
[Instruction] - PathValidation checks each instruction for unsafe paths
- Planner validates no conflicts, checks sources exist →
Plan - Executor performs renames via FileManager
Key types:
NonemptyString— wrapper ensuring non-empty, trimmed stringsInstruction— rename pair (from: NonemptyString, to: NonemptyString)Plan— validated instructions ready to execute
Tests use temp directories for filesystem operations. Each test cleans up after itself.
swift test # all tests
swift test --filter ParserTests # specific suite
swift test --filter "rejects absolute" # by name pattern