lyft / protoc-gen-star

protoc plugin library for efficient proto-based code generation

Home Page:https://godoc.org/github.com/lyft/protoc-gen-star

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Question: How to gofmt for injection artifacts?

huangjunwen opened this issue · comments

First thanks very much for this library, it saves me so much time ~

Then here is my question: I use AddGeneratorTemplateInjection to generate fragments of output files, for example,

package {{ PackageName .File }}

// @@protoc_insertion_point(imports)

...

I have to generate the rest part of file to gather which external packages need to be imported before injecting the "import" part. But i found that gofmt post processor does not work for injection artifacts. (this makes sense since it should apply to a whole file) . Is there any way to gofmt the whole file for each output ?

Howdy! I'm glad it's helpful 😁

I explored this a bit initially but was unsuccessful, especially since a particular fragment has unknown indentation and the injected-into file might not even come from the same plugin. I'm not sure it's possible with just the injection body. You could explore using https://golang.org/pkg/go/format/#Node somehow to operate against a fragment.

Yes, I think it's not easy to do gofmt at artifact's level. How about writing a PostProcessor to gather all output files' path. Then do the gofmt in the end, like this ?

func (c *fileCollector) Match(a pgs.Artifact) bool {
  var n string
  switch a := a.(type) {
  case pgs.GeneratorFile:
    n = a.Name
  case pgs.GeneratorTemplateFile:
    n = a.Name
  case pgs.CustomFile:
    n = a.Name
  case pgs.CustomTemplateFile:
    n = a.Name
  ...
  }
  // Is `n` the full path of the output file?
  c.files = append(c.files, n)
  return false
}

Well, I think this may not work too. Since files maybe not written to disk when the plugin is running.

I have found a workaround now, but only work for fragments that contains only top level declarations :

  1. For each fragment, run parser.ParseFile(..., parser.PackageClauseOnly), if no error, then it should be a valid go file. Use format.Source directly.
  2. Otherwise, insert a fake package clause at the beginning.
  3. Now it becomes valid, format.Source it.
  4. Trim the package clause and return.