Skip to content

refactor: extract pluralization helper to reduce duplication in cleanup.ts #55

@gsong

Description

@gsong

Summary

The cleanup.ts file contains 10+ instances of repeated pluralization logic that should be extracted into a reusable helper function to improve code maintainability and follow DRY (Don't Repeat Yourself) principles.

Current State

The same pluralization pattern ${count} ${count === 1 ? "singular" : "plural"} appears repeatedly throughout the file:

Line 127:

`Found ${staleFiles.length} stale cache ${staleFiles.length === 1 ? "entry" : "entries"}:`

Line 149:

`[DRY RUN] Would remove ${staleFiles.length} stale cache ${staleFiles.length === 1 ? "entry" : "entries"}`

Line 169:

`Removed ${result.staleCacheEntries} stale cache ${result.staleCacheEntries === 1 ? "entry" : "entries"}.`

Line 215:

`Found invalid server references in ${filesToUpdate.length} cache ${filesToUpdate.length === 1 ? "file" : "files"}:`

Line 231:

`[DRY RUN] Would remove ${totalInvalid} invalid ${totalInvalid === 1 ? "reference" : "references"}`

Line 252:

`[DRY RUN] Would remove ${totalInvalid} invalid ${totalInvalid === 1 ? "reference" : "references"}`

Line 280:

`Updated: ${path} (removed ${invalidConfigs.length} invalid ${invalidConfigs.length === 1 ? "reference" : "references"})`

Line 293:

`Removed ${result.invalidServerReferences} invalid server ${result.invalidServerReferences === 1 ? "reference" : "references"}.`

Line 324:

`Found ${brokenLinks.length} broken ${brokenLinks.length === 1 ? "symlink" : "symlinks"}:`

Line 333:

`[DRY RUN] Would remove ${brokenLinks.length} broken ${brokenLinks.length === 1 ? "symlink" : "symlinks"}`

Line 348:

`[DRY RUN] Would remove ${brokenLinks.length} broken ${brokenLinks.length === 1 ? "symlink" : "symlinks"}` 

Line 368:

`Removed ${result.brokenSymlinks} broken ${result.brokenSymlinks === 1 ? "symlink" : "symlinks"}.`

Proposed Solution

Create a simple pluralize() helper function in src/utils.ts:

/**
 * Format a count with the appropriate singular or plural form
 * @param count - The number to format
 * @param singular - The singular form of the word
 * @param plural - The plural form (optional, defaults to singular + 's')
 * @returns Formatted string with count and appropriate word form
 * @example pluralize(1, "entry") // "1 entry"
 * @example pluralize(5, "entry", "entries") // "5 entries"
 */
export function pluralize(count: number, singular: string, plural?: string): string {
  const pluralForm = plural ?? `${singular}s`;
  return `${count} ${count === 1 ? singular : pluralForm}`;
}

Benefits

  • DRY Principle: Eliminates code duplication
  • Maintainability: Changes to pluralization logic only need to be made in one place
  • Consistency: Ensures uniform formatting across the codebase
  • Readability: Cleaner, more semantic code
  • Testability: Can add unit tests for the helper function

Implementation Steps

  1. Create or update src/utils.ts with the pluralize() function
  2. Add unit tests for the helper function
  3. Update all 10+ instances in src/cleanup.ts to use the helper:
    • Line 127: ${pluralize(staleFiles.length, "entry", "entries")} stale cache
    • Line 149: ${pluralize(staleFiles.length, "entry", "entries")} stale cache
    • Line 169: ${pluralize(result.staleCacheEntries, "entry", "entries")} stale cache
    • Line 215: ${pluralize(filesToUpdate.length, "file")} cache
    • Line 231, 252: ${pluralize(totalInvalid, "reference")} invalid
    • Line 280: ${pluralize(invalidConfigs.length, "reference")} invalid
    • Line 293: ${pluralize(result.invalidServerReferences, "reference")} invalid server
    • Line 324, 333, 348: ${pluralize(brokenLinks.length, "symlink")} broken
    • Line 368: ${pluralize(result.brokenSymlinks, "symlink")} broken
  4. Run tests to ensure no regressions
  5. Update any related documentation if needed

Acceptance Criteria

  • pluralize() helper function created in src/utils.ts
  • Unit tests added for the helper function
  • All instances in cleanup.ts updated to use the helper
  • All existing tests pass
  • Type checking passes
  • No change in runtime behavior

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions