Skip to content

[Refactor] Introduce builder pattern for Emitter construction #49

@sorafujitani

Description

@sorafujitani

Summary

Introduce a builder pattern for Emitter construction to improve API ergonomics and support future configuration options.

Background

File: ext/rfmt/src/emitter/mod.rs:29-52

impl Emitter {
    pub fn new(config: Config) -> Self { ... }
    pub fn with_source(config: Config, source: String) -> Self { ... }
}

Problem

Multiple constructors with different parameter combinations:

  • Hard to extend without breaking changes
  • Unclear which constructor to use
  • No compile-time validation of required fields

Proposed Solution

Step 1: Define EmitterBuilder

#[derive(Debug, Default)]
pub struct EmitterBuilder {
    config: Option<Config>,
    source: Option<String>,
}

impl EmitterBuilder {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn config(mut self, config: Config) -> Self {
        self.config = Some(config);
        self
    }

    pub fn source(mut self, source: impl Into<String>) -> Self {
        self.source = Some(source.into());
        self
    }

    pub fn build(self) -> Emitter {
        Emitter {
            config: self.config.unwrap_or_default(),
            source: self.source,
            // ... other fields initialized to defaults
        }
    }
}

Step 2: Add convenience method on Emitter

impl Emitter {
    pub fn builder() -> EmitterBuilder {
        EmitterBuilder::new()
    }

    // Keep existing constructors for backward compatibility
    pub fn new(config: Config) -> Self {
        Self::builder().config(config).build()
    }

    pub fn with_source(config: Config, source: String) -> Self {
        Self::builder().config(config).source(source).build()
    }
}

Usage

// Before
let emitter = Emitter::with_source(config, source);

// After (both work)
let emitter = Emitter::with_source(config, source);  // backward compatible
let emitter = Emitter::builder()
    .config(config)
    .source(source)
    .build();

Benefits

  1. Extensible - New options don't require new constructors
  2. Discoverable - IDE autocomplete shows all options
  3. Backward compatible - Existing code continues to work

Files to Modify

  • ext/rfmt/src/emitter/mod.rs - Add EmitterBuilder

Acceptance Criteria

  • EmitterBuilder struct implemented
  • Emitter::builder() method added
  • Existing constructors preserved for backward compatibility
  • All existing tests pass
  • Documentation added for builder pattern

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions