-- | A Shakespearean module for Babel

module Text.Babel where

import           Data.Default
import           Language.Haskell.TH.Quote
import           Language.Haskell.TH.Syntax
import           System.Directory
import           System.Process
import           Text.Julius
import           Text.Shakespeare

newtype BabelArgs = BabelArgs [String]
                  deriving (Eq, Ord, Read, Show)

instance Default BabelArgs where
    def = BabelArgs ["--presets", "es2015", "--source-maps", "inline", "--source-file-name", "babel.es6.js"]

-- | es2015 compiles down to Javascript
babelSettings :: Q ShakespeareSettings
babelSettings = babelSettingsWithArgs def

babelSettingsWithArgs :: BabelArgs -> Q ShakespeareSettings
babelSettingsWithArgs (BabelArgs args) = do
  jsettings <- javascriptSettings
  exe <- qRunIO babelExePath
  return $ jsettings { varChar = '#'
                     , preConversion = Just PreConvert
                                       { preConvert = ReadProcess exe args
                                       , preEscapeIgnoreBalanced = "'\""
                                       , preEscapeIgnoreLine = "//"
                                       , wrapInsertion = Just WrapInsertion
                                                         { wrapInsertionIndent = Nothing
                                                         , wrapInsertionStartBegin = ";(function("
                                                         , wrapInsertionSeparator = ", "
                                                         , wrapInsertionStartClose = "){"
                                                         , wrapInsertionEnd = "})"
                                                         , wrapInsertionAddParens = False
                                                         }}}

babelExePath :: IO FilePath
babelExePath = do
    (_, bin, _) <- readProcessWithExitCode "npm" ["bin"] []
    let npmBabel = takeWhile (/= '\n') bin ++ "/" ++ "babel"
    npmExist <- doesFileExist npmBabel
    return $ if npmExist
             then npmBabel
             else "babel"

-- | Read inline
babel :: QuasiQuoter
babel = babelWithArgs def

babelWithArgs :: BabelArgs -> QuasiQuoter
babelWithArgs bArgs = QuasiQuoter { quoteExp = \s -> babelSettingsWithArgs bArgs >>= \rs -> quoteExp (shakespeare rs) s }

-- | Read in a es2015 file
babelFile :: FilePath -> Q Exp
babelFile = babelFileWithArgs def

babelFileWithArgs :: BabelArgs -> FilePath -> Q Exp
babelFileWithArgs bArgs fp = do
    rs <- babelSettingsWithArgs bArgs
    shakespeareFile rs fp

-- | Read in a es2015 file when develop
babelFileReload :: FilePath -> Q Exp
babelFileReload = babelFileReloadWithArgs def

babelFileReloadWithArgs :: BabelArgs -> FilePath -> Q Exp
babelFileReloadWithArgs bArgs fp = do
    rs <- babelSettingsWithArgs bArgs
    shakespeareFileReload rs fp