Skip to content

Expose buffa CodeGenConfig directly instead of replicating every field #34

@iainmcgin

Description

@iainmcgin

Background

connectrpc_codegen::codegen::Options currently mirrors a hand-picked subset of buffa_codegen::CodeGenConfig fields one-by-one (strict_utf8_mapping, generate_json, extern_paths, and as of #TBD, emit_register_fn). Options::to_buffa_config() then copies each into a fresh CodeGenConfig.

This was fine while only two or three knobs mattered, but every new buffa option (generate_text, generate_arbitrary, bytes_fields, preserve_unknown_fields, allow_message_set, …) requires:

  1. a new field on Options,
  2. a new line in to_buffa_config(),
  3. a new builder method on connectrpc_build::Config,
  4. a new plugin parameter token in generate(),
  5. a CHANGELOG entry, and a release.

A recent example: a downstream user needed emit_register_fn=false to suppress the per-file register_types collision when include!ing multiple generated files into the same module — a one-line buffa change that required a five-touchpoint plumbing PR and a patch release.

Proposal

For v0.4.0, replace per-field forwarding with direct passthrough of buffa's CodeGenConfig. Several shapes are viable:

A. Embed the buffa config in Options:

pub struct Options {
    pub buffa: buffa_codegen::CodeGenConfig,
    pub extern_paths: Vec<(String, String)>, // still set by plugin parser
    // ...connectrpc-specific fields
}

connectrpc_build::Config gains fn buffa_config(self, cfg: CodeGenConfig) -> Self. Existing convenience methods (generate_json, strict_utf8_mapping) stay as thin shims that mutate self.options.buffa.<field> for the common cases.

B. Escape-hatch closure:

pub fn with_buffa_config(self, f: impl FnOnce(&mut CodeGenConfig)) -> Self

Users mutate the underlying buffa config in place. Less intrusive but discoverability is worse.

Constraints to preserve in either shape:

  • connectrpc forces generate_views = true (the service stubs require view types). Whatever shape we pick must apply this override after the user's config, not before.
  • extern_paths is also populated by the protoc plugin's parameter parser (buffa_module=, extern_path=), so it can't simply be "whatever the user passed in".
  • Options is #[non_exhaustive], so the migration is non-breaking on the additive side; we'd be free to remove the per-field shims in the same release if we want to keep the surface small.

Migration

Re-export buffa_codegen::CodeGenConfig from connectrpc_codegen so downstream users don't need a direct buffa-codegen dependency.

Mark this for v0.4.0 — the per-field shims can either be removed (breaking, sweep through all of them at once) or kept as deprecated wrappers.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions