smithy4s icon indicating copy to clipboard operation
smithy4s copied to clipboard

Feature request: Flag to Mark Generated Code as Package Private

Open bpholt opened this issue 1 year ago • 5 comments

Motivation: allowing libraries to generate smithy4s clients intended for use only within the library, avoiding binary compatibility issues caused by differences in the generated code over time.

Such a feature would remove the need for the Scalafix referenced in #1589.

bpholt avatar Sep 25 '24 22:09 bpholt

I'm not necessarily opposed to it but you'd have to propose semantics (in this issue) and implement them yourself once @kubukoz and I have agreed to it.

Baccata avatar Oct 02 '24 08:10 Baccata

I finally have a usecase so I want it 😅

We usually configure this kind of thing via traits or metadata. I would use Validated Newtypes as inspiration, and implement both:

  • apply the trait explicitly if you want fine-grained control and need only a small number of private shapes
  • set metadata if you want a large blast radius.

I wouldn't apply the metadata globally, though.

metadata smithy4sExtraModifiers = [
  {
    "selector": "[id|namespace=foo.bar] ~>"
    "modifiers": "private[foo]" // allow anything here, if it's broken it won't compile, and we'll futureproof ourselves by letting people add `open` or whatever they desire from day 1
  }
]

Selectors are flexible enough that you can choose any number of shapes, filter them by transitive relationships and so on.


Implementation-wise, I would have a transformation that adds the trait based on the metadata's selectors, then the codegen can just look for the trait (that's also pretty much how the validated newtypes work).

The big question I have is: do we want to retain that information in the model, for further codegen runs? Validated newtypes are retained in CodegenRecord, but that's because it was necessary to know what to generate on the use-site - we probably don't need that here.

kubukoz avatar Feb 17 '25 17:02 kubukoz

TBH I'd like selector-based metadata application in validated newtypes too. Maybe this could be the general pattern for configuring such things.

kubukoz avatar Feb 24 '25 12:02 kubukoz

In the meantime, another idea came up - a transformation that will apply a trait to all shapes matching a given selector. We have something similar internally @ JOB, and it works pretty well.

Think something like this:

metadata applyTraits = [
  {
    selector: "shape"
    traits: [
      {
        id: smithy.api#documentation
        node: "foo bar"
      }
    ]
  }
  // other entries for other traits etc., ordered.
]

Having this would mean we can always simply rely on traits, which should simplify the internal implementation details.

I'd proceed in this ticket without such utilities, just implement it based on a trait.

kubukoz avatar May 26 '25 23:05 kubukoz

The trait itself would be:

@smithy4s.meta#modifiers(["private[mylib]", "open"]) //whatever you want, really

making it an array lets Smithy merge traits by concatenation, in case someone adds a value via the apply keyword.

kubukoz avatar May 26 '25 23:05 kubukoz