git.iko.soy/rowtype-yoga/purescript-native
on e655652 help sign in
136 lines 4.9 kB history raw
1{-# LANGUAGE FlexibleContexts #-}
2{-# LANGUAGE ScopedTypeVariables #-}
3{-# LANGUAGE TupleSections #-}
4{-# LANGUAGE RecordWildCards #-}
6-- | Bundles compiled PureScript modules for the browser.
7module Main (main) where
9import Data.Maybe
10import Data.Traversable (for)
11import Data.Version (showVersion)
13import Control.Applicative
14import Control.Monad
15import Control.Monad.Error.Class
16import Control.Monad.Trans.Except
17import Control.Monad.IO.Class
19import System.FilePath (takeFileName, takeDirectory)
20import System.FilePath.Glob (glob)
21import System.Exit (exitFailure)
22import System.IO (stderr, stdout, hPutStrLn, hSetEncoding, utf8)
23import System.Directory (createDirectoryIfMissing)
25import Language.PureScript.Bundle
27import Options.Applicative as Opts
29import qualified Paths_purescript as Paths
31-- | Command line options.
32data Options = Options
33 { optionsInputFiles :: [FilePath]
34 , optionsOutputFile :: Maybe FilePath
35 , optionsEntryPoints :: [String]
36 , optionsMainModule :: Maybe String
37 , optionsNamespace :: String
38 , optionsRequirePath :: Maybe FilePath
39 } deriving Show
41-- | Given a filename, assuming it is in the correct place on disk, infer a ModuleIdentifier.
42guessModuleIdentifier :: (MonadError ErrorMessage m) => FilePath -> m ModuleIdentifier
43guessModuleIdentifier filename = ModuleIdentifier (takeFileName (takeDirectory filename)) <$> guessModuleType (takeFileName filename)
44 where
45 guessModuleType "index.js" = pure Regular
46 guessModuleType "foreign.js" = pure Foreign
47 guessModuleType name = throwError $ UnsupportedModulePath name
49-- | The main application function.
50-- This function parses the input files, performs dead code elimination, filters empty modules
51-- and generates and prints the final Javascript bundle.
52app :: (MonadError ErrorMessage m, MonadIO m) => Options -> m String
53app Options{..} = do
54 inputFiles <- concat <$> mapM (liftIO . glob) optionsInputFiles
55 when (null inputFiles) . liftIO $ do
56 hPutStrLn stderr "psc-bundle: No input files."
57 exitFailure
58 input <- for inputFiles $ \filename -> do
59 js <- liftIO (readFile filename)
60 mid <- guessModuleIdentifier filename
61 length js `seq` return (mid, js) -- evaluate readFile till EOF before returning, not to exhaust file handles
63 let entryIds = map (`ModuleIdentifier` Regular) optionsEntryPoints
65 bundle input entryIds optionsMainModule optionsNamespace optionsRequirePath
67-- | Command line options parser.
68options :: Parser Options
69options = Options <$> some inputFile
70 <*> optional outputFile
71 <*> many entryPoint
72 <*> optional mainModule
73 <*> namespace
74 <*> optional requirePath
75 where
76 inputFile :: Parser FilePath
77 inputFile = strArgument $
78 metavar "FILE"
79 <> help "The input .js file(s)"
81 outputFile :: Parser FilePath
82 outputFile = strOption $
83 short 'o'
84 <> long "output"
85 <> help "The output .js file"
87 entryPoint :: Parser String
88 entryPoint = strOption $
89 short 'm'
90 <> long "module"
91 <> help "Entry point module name(s). All code which is not a transitive dependency of an entry point module will be removed."
93 mainModule :: Parser String
94 mainModule = strOption $
95 long "main"
96 <> help "Generate code to run the main method in the specified module."
98 namespace :: Parser String
99 namespace = strOption $
100 short 'n'
101 <> long "namespace"
102 <> Opts.value "PS"
103 <> showDefault
104 <> help "Specify the namespace that PureScript modules will be exported to when running in the browser."
106 requirePath :: Parser FilePath
107 requirePath = strOption $
108 short 'r'
109 <> long "require-path"
110 <> help "The path prefix used in require() calls in the generated JavaScript [deprecated]"
112-- | Make it go.
113main :: IO ()
114main = do
115 hSetEncoding stdout utf8
116 hSetEncoding stderr utf8
117 opts <- execParser (info (version <*> helper <*> options) infoModList)
118 when (isJust (optionsRequirePath opts)) $ hPutStrLn stderr "The require-path option is deprecated and will be removed in PureScript 0.9."
119 output <- runExceptT (app opts)
120 case output of
121 Left err -> do
122 hPutStrLn stderr (unlines (printErrorMessage err))
123 exitFailure
124 Right js ->
125 case optionsOutputFile opts of
126 Just outputFile -> do
127 createDirectoryIfMissing True (takeDirectory outputFile)
128 writeFile outputFile js
129 Nothing -> putStrLn js
130 where
131 infoModList = fullDesc <> headerInfo <> footerInfo
132 headerInfo = header "psc-bundle - Bundles compiled PureScript modules for the browser"
133 footerInfo = footer $ "psc-bundle " ++ showVersion Paths.version
135 version :: Parser (a -> a)
136 version = abortOption (InfoMsg (showVersion Paths.version)) $ long "version" <> help "Show the version number" <> hidden