Files
renamer/specs/004-extension-rename/spec.md
2025-10-30 10:31:53 +08:00

7.8 KiB
Raw Blame History

Feature Specification: Extension Command for Multi-Extension Normalization

Feature Branch: 004-extension-rename Created: 2025-10-29 Status: Draft Input: User description: "实现扩展名修改Extension命令类似于 replace 命令,可以支持把多个扩展名更改为一个指定的扩展名"

Clarifications

Session 2025-10-30

  • Q: Should extension comparisons treat casing uniformly or follow the host filesystem? → A: Always case-insensitive
  • Q: How should hidden files be handled when --hidden is omitted? → A: Exclude hidden entries
  • Q: What exit behavior should occur when no files match the given extensions? → A: Exit 0 with notice
  • Q: How should files that already have the target extension be represented? → A: Preview as no-change; skip on apply

User Scenarios & Testing (mandatory)

User Story 1 - Normalize Legacy Extensions in Bulk (Priority: P1)

As a power user cleaning project assets, I want a command to replace multiple file extensions with a single standardized extension so that I can align legacy files (e.g., .jpeg, .JPG) without hand-editing each one.

Why this priority: Delivers the core business value—fast extension normalization across large folders.

Independent Test: In a sample directory containing .jpeg, .JPG, and .png, run renamer extension .jpeg .JPG .png .jpg --dry-run, verify preview shows the new .jpg extension for each, then apply with --yes and confirm filesystem updates.

Acceptance Scenarios:

  1. Given files with extensions .jpeg and .JPG, When the user runs renamer extension .jpeg .JPG .jpg, Then the preview lists each file with the .jpg extension and apply renames successfully.
  2. Given nested directories, When the user adds --recursive, Then all matching extensions in subdirectories are normalized while unrelated files remain untouched.

User Story 2 - Automation-Friendly Extension Updates (Priority: P2)

As an operator integrating renamer into CI scripts, I want deterministic exit codes, ledger entries, and undo support when changing extensions so automated jobs remain auditable and recoverable.

Why this priority: Ensures enterprise workflows can rely on extension updates without risking data loss.

Independent Test: Run renamer extension .yaml .yml .yml --yes --path ./fixtures, verify exit code 0, inspect .renamer ledger for recorded operations, and confirm renamer undo restores originals.

Acceptance Scenarios:

  1. Given a non-interactive environment with --yes, When the command completes without conflicts, Then exit code is 0 and ledger metadata captures original extension list and target extension.
  2. Given a ledger entry exists, When renamer undo runs, Then all files revert to their prior extensions even if the command was executed by automation.

User Story 3 - Validate Extension Inputs and Conflicts (Priority: P3)

As a user preparing an extension migration, I want validation and preview warnings for invalid tokens, duplicate target names, and no-op operations so I can adjust before committing changes.

Why this priority: Reduces support load from misconfigured commands and protects against accidental overwrites.

Independent Test: Run renamer extension .mp3 .MP3 mp3 --dry-run, confirm validation fails because tokens must include leading ., and run a scenario where resulting filenames collide to ensure conflicts abort the apply step.

Acceptance Scenarios:

  1. Given invalid input (e.g., missing leading . or fewer than two arguments), When the command executes, Then it exits with non-zero status and prints actionable guidance.
  2. Given two files that would become the same path after extension normalization, When the preview runs, Then conflicts are listed and the apply step refuses to proceed until resolved.

Edge Cases

  • How does the rename plan surface conflicts when multiple files map to the same normalized extension?
  • When the target extension already matches some files, they appear in preview with a “no change” indicator and are skipped during apply without raising errors.
  • Hidden files and directories remain excluded unless the user supplies --hidden.
  • When no files match in preview or apply, the command must surface a “no candidates found” notice while completing successfully.

Requirements (mandatory)

Functional Requirements

  • FR-001: CLI MUST provide a dedicated extension subcommand that accepts one or more source extensions and a single target extension as positional arguments.
  • FR-002: Preview → confirm workflow MUST mirror existing commands: list original paths, proposed paths, and highlight extension changes before apply.
  • FR-003: Executions MUST append ledger entries capturing original extension list, target extension, affected files, and timestamps to support undo.
  • FR-004: Users MUST be able to undo the most recent extension batch via existing undo mechanics without leaving orphaned files.
  • FR-005: Command MUST respect global scope flags (--path, --recursive, --include-dirs, --hidden, --extensions, --dry-run, --yes) consistent with list and replace, excluding hidden files and directories unless --hidden is explicitly supplied.
  • FR-006: Extension parsing MUST require leading . tokens, deduplicate case-insensitively, warn when duplicates or no-op tokens are supplied, and compare file extensions case-insensitively across all platforms.
  • FR-007: Preview MUST detect target conflicts (two files mapping to the same new path) and block apply until conflicts are resolved.
  • FR-008: Invalid invocations (e.g., fewer than two arguments, empty tokens after trimming) MUST exit with non-zero status and provide remediation tips.
  • FR-009: Help output MUST clearly explain argument order, sequential evaluation rules, and interaction with scope flags.
  • FR-010: When no files match the provided extensions, preview and apply runs MUST emit a clear “no candidates found” message and exit with status 0.
  • FR-011: Preview MUST surface already-targeted files with a “no change” marker, and apply MUST skip them while returning success.

Key Entities

  • ExtensionRequest: Working directory, ordered source extension list, target extension, scope flags, dry-run/apply settings.
  • ExtensionSummary: Totals for candidates, changed files, per-extension match counts, conflicts, and warning messages used for preview and ledger metadata.

Success Criteria (mandatory)

Measurable Outcomes

  • SC-001: Users normalize 500 files extensions (preview + apply) in under 2 minutes end-to-end.
  • SC-002: 95% of beta testers correctly supply arguments (source extensions + target) after reading renamer extension --help without additional guidance.
  • SC-003: Automated regression tests confirm extension change + undo leave the filesystem unchanged in 100% of scripted scenarios.
  • SC-004: Support tickets related to inconsistent file extensions drop by 30% within the first release cycle after launch.

Assumptions

  • Command name will be renamer extension to align with existing verb-noun conventions.
  • Source extensions are literal matches with leading dots; wildcard or regex patterns remain out of scope.
  • Target extension must include a leading dot and is applied case-sensitively as provided.
  • Existing traversal, summary, and ledger infrastructure can be extended from the replace/remove commands.

Dependencies & Risks

  • Requires new extension-specific packages analogous to replace/remove for parser, engine, summary, and CLI wiring.
  • Help/quickstart documentation must be updated to explain argument order and extension validation.
  • Potential filename conflicts after normalization must be detected pre-apply to avoid overwriting files.