Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an Elixir codegen #50

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ RUN cabal v2-install -j --lib
WORKDIR /src/json-autotype
RUN ls *.cabal
RUN cabal v2-install -j --dependencies-only --keep-going --lib || (sleep 60; cabal v2-install -j --dependencies-only --lib)
COPY README.md /src/README.md
RUN cabal v2-install -j exe:json-autotype --symlink-bindir=/usr/bin
RUN mkdir /workdir
WORKDIR /workdir
Expand Down
3 changes: 1 addition & 2 deletions json-alt/json-alt.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@ cabal-version: 1.12
-- This file has been generated from package.yaml by hpack version 0.34.4.
--
-- see: https://github.com/sol/hpack
--

name: json-alt
version: 1.0.1
version: 1.0.0
synopsis: Union 'alternative' or Either that has untagged JSON encoding.
description: Parsing JSON with Aeson often requires decoding fields
that have more than one Haskell type.
Expand Down
1 change: 1 addition & 0 deletions json-autotype/common/CommonCLI.hs
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,5 @@ tyOptParser = TyOptions
langOpts :: Parser Lang
langOpts = flag Haskell Haskell (long "haskell")
<|> flag Haskell Elm (long "elm")
<|> flag Haskell Elixir (long "elixir")

4 changes: 3 additions & 1 deletion json-autotype/json-autotype.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ cabal-version: 1.12
-- see: https://github.com/sol/hpack

name: json-autotype
version: 3.1.3
version: 3.1.2
synopsis: Automatic type declaration for JSON input data
description: Generates datatype declarations with Aeson''s ''Data.Aeson.FromJSON''
.
Expand Down Expand Up @@ -95,6 +95,8 @@ library
Data.Aeson.AutoType.Nested
other-modules:
Data.Aeson.AutoType.CodeGen.Common
Data.Aeson.AutoType.CodeGen.Elixir
Data.Aeson.AutoType.CodeGen.ElixirFormat
Data.Aeson.AutoType.Plugin.Subtype
Paths_json_autotype
hs-source-dirs:
Expand Down
4 changes: 4 additions & 0 deletions json-autotype/src/Data/Aeson/AutoType/CodeGen.hs
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,28 @@ import System.Exit

import Data.Aeson.AutoType.CodeGen.Haskell
import Data.Aeson.AutoType.CodeGen.Elm
import Data.Aeson.AutoType.CodeGen.Elixir

-- | Available output languages.
data Lang = Haskell
| HaskellStrict
| Elm
| Elixir

-- | Default output filname is used, when there is no explicit output file path, or it is "-" (stdout).
-- Default module name is consistent with it.
defaultOutputFilename :: Lang -> FilePath
defaultOutputFilename Haskell = defaultHaskellFilename
defaultOutputFilename HaskellStrict = defaultHaskellFilename
defaultOutputFilename Elm = defaultElmFilename
defaultOutputFilename Elixir = defaultElixirFilename

-- | Write a Haskell module to an output file, or stdout if `-` filename is given.
writeModule :: Lang -> FilePath -> Text -> Map.HashMap Text Type -> IO ()
writeModule Haskell = writeHaskellModule
writeModule HaskellStrict = writeHaskellModule
writeModule Elm = writeElmModule
writeModule Elixir = writeElixirModule

-- | Run module in a given language.
runModule :: Lang -> FilePath -> [String] -> IO ExitCode
Expand Down
84 changes: 84 additions & 0 deletions json-autotype/src/Data/Aeson/AutoType/CodeGen/Elixir.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
{-# LANGUAGE CPP #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE OverloadedStrings #-}
-- | Wrappers for generating prologue and epilogue code in Elixir.
module Data.Aeson.AutoType.CodeGen.Elixir(
writeElixirModule
, defaultElixirFilename
, importedModules
, requiredPackages
, generateModuleImports
, ModuleImport
) where

import qualified Data.Text as Text
import qualified Data.Text.IO as Text
import Data.Text hiding (unwords)
import qualified Data.HashMap.Strict as Map
import Control.Arrow (first)
import Control.Exception (assert)
import Data.Default
import Data.Monoid ((<>))
import System.FilePath
import System.IO
import System.Process (system)
import qualified System.Environment (lookupEnv)
import System.Exit (ExitCode)

import Data.Aeson.AutoType.Format
import Data.Aeson.AutoType.Type
import Data.Aeson.AutoType.CodeGen.Generic(src)
import Data.Aeson.AutoType.CodeGen.ElixirFormat
import Data.Aeson.AutoType.Util

-- | Default output filname is used, when there is no explicit output file path, or it is "-" (stdout).
-- Default module name is consistent with it.
defaultElixirFilename :: FilePath
defaultElixirFilename = "JSONTypes.ex"

-- | Generate module header
header :: Text -> Text
header _moduleName = ""

-- | Alias for indicating that this is item in module imports list.
type ModuleImport = Text

-- | Given a list of imports, generate source code.
generateModuleImports :: [ModuleImport] -> Text
generateModuleImports = Text.unlines
. fmap ("import " <>)

-- | List of packages required by modules below.
-- Keep and maintain together.
requiredPackages :: [Text]
requiredPackages = ["aeson", "json-alt", "base", "bytestring", "text"]

-- | List of modules to import
importedModules :: [ModuleImport]
importedModules = []

-- | Epilogue for generated code:
--
-- * function to use parser to get data from `Text`
-- * main function in case we use `runghc` for testing parser immediately
epilogue :: Text -> Text
epilogue _toplevelName = ""

-- | Write a Elixir module to an output file, or stdout if `-` filename is given.
writeElixirModule :: FilePath -> Text -> Map.HashMap Text Type -> IO ()
writeElixirModule outputFilename toplevelName types =
withFileOrHandle outputFilename WriteMode stdout $ \hOut ->
assert (extension == ".ex" || extension == ".exs") $ do
Text.hPutStrLn hOut $ header $ toplevelName
-- We write types as Elixir type declarations to output handle
Text.hPutStrLn hOut $ displaySplitTypes types
Text.hPutStrLn hOut $ epilogue toplevelName
where
(moduleName, extension) =
first normalizeTypeName' $
splitExtension $
if outputFilename == "-"
then defaultElixirFilename
else outputFilename
normalizeTypeName' = Text.unpack . normalizeTypeName . Text.pack
Loading