packages feed

wireform-proto-0.1.0.0: protoc-plugin/Main.hs

{- | protoc plugin for wireform.

Usage: protoc --plugin=protoc-gen-wireform=./protoc-gen-wireform --wireform_out=gen/ foo.proto
-}
module Main where

import Data.Map.Strict qualified as Map
import Data.Maybe (fromMaybe)
import Data.Text qualified as T
import Data.Vector qualified as V
import Proto.CodeGen
import Proto.Google.Protobuf.Compiler.Plugin
import Proto.Google.Protobuf.Compiler.Plugin.Util (pluginMain)
import Proto.Google.Protobuf.Reflection.Descriptor (FileDescriptorProto (..))
import Proto.IDL.Descriptor (fileDescriptorToAST)
import Proto.IDL.Parser.Resolver (ResolvedProto (..))


main :: IO ()
main = pluginMain handleRequest


handleRequest :: CodeGeneratorRequest -> IO CodeGeneratorResponse
handleRequest req = do
  let requestedFiles = V.toList (codeGeneratorRequestFileToGenerate req)
      allProtos = V.toList (codeGeneratorRequestProtoFile req)
      opts = parsePluginOpts (fromMaybe "" (codeGeneratorRequestParameter req))
  let resolvedPairs = fmap fdpToResolved allProtos
      typeReg = buildTypeRegistry opts resolvedPairs
      outputFiles = concatMap (generateForFile opts typeReg requestedFiles) allProtos
  pure
    defaultCodeGeneratorResponse
      { codeGeneratorResponseFile = V.fromList outputFiles
      , codeGeneratorResponseSupportedFeatures = Just 1
      }


parsePluginOpts :: T.Text -> GenerateOpts
parsePluginOpts _param = defaultGenerateOpts


fdpToResolved :: FileDescriptorProto -> (FilePath, ResolvedProto)
fdpToResolved fdp =
  let path = T.unpack (fromMaybe "" (fileDescriptorProtoName fdp))
      pf = fileDescriptorToAST fdp
  in ( path
     , ResolvedProto {rpFile = pf, rpPath = path, rpImports = Map.empty}
     )


generateForFile
  :: GenerateOpts
  -> TypeRegistry
  -> [T.Text]
  -> FileDescriptorProto
  -> [CodeGeneratorResponse'File]
generateForFile opts reg requestedFiles fdp =
  if fromMaybe "" (fileDescriptorProtoName fdp) `elem` requestedFiles
    then
      let filePath = T.unpack (fromMaybe "" (fileDescriptorProtoName fdp))
          pf = fileDescriptorToAST fdp
          moduleName = moduleNameForProto opts filePath pf
          outputPath = T.replace "." "/" moduleName <> ".hs"
          content = generateModuleText opts reg filePath pf
      in
        [ defaultCodeGeneratorResponse'File
            { codeGeneratorResponseFileName = Just outputPath
            , codeGeneratorResponseFileContent = Just content
            }
        ]
    else []