git.iko.soy/rowtype-yoga/purescript-native
on golang help sign in
Merge pull request #2474 from nwolverson/bundle-sourcemaps
766d7fePhil Freeman
psc-bundle/Main.hs+32−7
@@ -9,6 +9,8 @@ module Main (main) where
9import Data.Traversable (for)
9import Data.Traversable (for)
10import Data.Version (showVersion)
10import Data.Version (showVersion)
11import Data.Monoid ((<>))
11import Data.Monoid ((<>))
12+import Data.Aeson (encode)
13+import Data.Maybe (isNothing)
12
14
13import Control.Applicative
15import Control.Applicative
14import Control.Monad
16import Control.Monad
@@ -16,12 +18,15 @@ import Control.Monad.Error.Class
16import Control.Monad.Trans.Except
18import Control.Monad.Trans.Except
17import Control.Monad.IO.Class
19import Control.Monad.IO.Class
18
20
19−import System.FilePath (takeDirectory)
21+import System.FilePath (takeDirectory, (</>), (<.>), takeFileName)
20import System.FilePath.Glob (glob)
22import System.FilePath.Glob (glob)
21import System.Exit (exitFailure)
23import System.Exit (exitFailure)
22import System.IO (stderr, stdout, hPutStrLn, hSetEncoding, utf8)
24import System.IO (stderr, stdout, hPutStrLn, hSetEncoding, utf8)
23import System.IO.UTF8 (readUTF8File, writeUTF8File)
25import System.IO.UTF8 (readUTF8File, writeUTF8File)
24−import System.Directory (createDirectoryIfMissing)
26+import System.Directory (createDirectoryIfMissing, getCurrentDirectory)
27+
28+import qualified Data.ByteString.Lazy as B
29+import qualified Data.ByteString.UTF8 as BU8
25
30
26import Language.PureScript.Bundle
31import Language.PureScript.Bundle
27
32
@@ -30,6 +35,9 @@ import qualified Options.Applicative as Opts
30
35
31import qualified Paths_purescript as Paths
36import qualified Paths_purescript as Paths
32
37
38+import SourceMap
39+import SourceMap.Types
40+
33-- | Command line options.
41-- | Command line options.
34data Options = Options
42data Options = Options
35 { optionsInputFiles :: [FilePath]
43 { optionsInputFiles :: [FilePath]
@@ -37,25 +45,32 @@ data Options = Options
37 , optionsEntryPoints :: [String]
45 , optionsEntryPoints :: [String]
38 , optionsMainModule :: Maybe String
46 , optionsMainModule :: Maybe String
39 , optionsNamespace :: String
47 , optionsNamespace :: String
48+ , optionsSourceMaps :: Bool
40 } deriving Show
49 } deriving Show
41
50
42-- | The main application function.
51-- | The main application function.
43-- This function parses the input files, performs dead code elimination, filters empty modules
52-- This function parses the input files, performs dead code elimination, filters empty modules
44-- and generates and prints the final Javascript bundle.
53-- and generates and prints the final Javascript bundle.
45−app :: (MonadError ErrorMessage m, MonadIO m) => Options -> m String
54+app :: (MonadError ErrorMessage m, MonadIO m) => Options -> m (Maybe SourceMapping, String)
46app Options{..} = do
55app Options{..} = do
47 inputFiles <- concat <$> mapM (liftIO . glob) optionsInputFiles
56 inputFiles <- concat <$> mapM (liftIO . glob) optionsInputFiles
48 when (null inputFiles) . liftIO $ do
57 when (null inputFiles) . liftIO $ do
49 hPutStrLn stderr "psc-bundle: No input files."
58 hPutStrLn stderr "psc-bundle: No input files."
50 exitFailure
59 exitFailure
60+ when (isNothing optionsOutputFile && optionsSourceMaps == True) . liftIO $ do
61+ hPutStrLn stderr "psc-bundle: Source maps only supported when output file specified."
62+ exitFailure
63+
51 input <- for inputFiles $ \filename -> do
64 input <- for inputFiles $ \filename -> do
52 js <- liftIO (readUTF8File filename)
65 js <- liftIO (readUTF8File filename)
53 mid <- guessModuleIdentifier filename
66 mid <- guessModuleIdentifier filename
54− length js `seq` return (mid, js) -- evaluate readFile till EOF before returning, not to exhaust file handles
67+ length js `seq` return (mid, Just filename, js) -- evaluate readFile till EOF before returning, not to exhaust file handles
55
68
56 let entryIds = map (`ModuleIdentifier` Regular) optionsEntryPoints
69 let entryIds = map (`ModuleIdentifier` Regular) optionsEntryPoints
57
70
71+ currentDir <- liftIO getCurrentDirectory
72+ let outFile = if optionsSourceMaps then fmap (currentDir </>) optionsOutputFile else Nothing
58− bundle input entryIds optionsMainModule optionsNamespace
73+ bundleSM input entryIds optionsMainModule optionsNamespace outFile
59
74
60-- | Command line options parser.
75-- | Command line options parser.
61options :: Parser Options
76options :: Parser Options
@@ -64,6 +79,7 @@ options = Options <$> some inputFile
64 <*> many entryPoint
79 <*> many entryPoint
65 <*> optional mainModule
80 <*> optional mainModule
66 <*> namespace
81 <*> namespace
82+ <*> sourceMaps
67 where
83 where
68 inputFile :: Parser FilePath
84 inputFile :: Parser FilePath
69 inputFile = Opts.strArgument $
85 inputFile = Opts.strArgument $
@@ -95,6 +111,11 @@ options = Options <$> some inputFile
95 <> Opts.showDefault
111 <> Opts.showDefault
96 <> Opts.help "Specify the namespace that PureScript modules will be exported to when running in the browser."
112 <> Opts.help "Specify the namespace that PureScript modules will be exported to when running in the browser."
97
113
114+ sourceMaps :: Parser Bool
115+ sourceMaps = Opts.switch $
116+ Opts.long "source-maps"
117+ <> Opts.help "Whether to generate source maps for the bundle (requires --output)."
118+
98-- | Make it go.
119-- | Make it go.
99main :: IO ()
120main :: IO ()
100main = do
121main = do
@@ -106,11 +127,15 @@ main = do
106 Left err -> do
127 Left err -> do
107 hPutStrLn stderr (unlines (printErrorMessage err))
128 hPutStrLn stderr (unlines (printErrorMessage err))
108 exitFailure
129 exitFailure
109− Right js ->
130+ Right (sourcemap, js) ->
110 case optionsOutputFile opts of
131 case optionsOutputFile opts of
111 Just outputFile -> do
132 Just outputFile -> do
112 createDirectoryIfMissing True (takeDirectory outputFile)
133 createDirectoryIfMissing True (takeDirectory outputFile)
134+ case sourcemap of
135+ Just sm -> do
136+ writeUTF8File outputFile $ js ++ "\n//# sourceMappingURL=" ++ (takeFileName outputFile <.> "map") ++ "\n"
137+ writeUTF8File (outputFile <.> "map") $ BU8.toString . B.toStrict . encode $ generate sm
113− writeUTF8File outputFile js
138+ Nothing -> writeUTF8File outputFile js
114 Nothing -> putStrLn js
139 Nothing -> putStrLn js
115 where
140 where
116 infoModList = Opts.fullDesc <> headerInfo <> footerInfo
141 infoModList = Opts.fullDesc <> headerInfo <> footerInfo
purescript.cabal+6−1
@@ -457,14 +457,19 @@ executable psc-bundle
457 other-modules: Paths_purescript
457 other-modules: Paths_purescript
458 other-extensions:
458 other-extensions:
459 build-depends: base >=4 && <5,
459 build-depends: base >=4 && <5,
460+ bytestring -any,
460 purescript -any,
461 purescript -any,
461 directory -any,
462 directory -any,
463+ aeson >= 0.8 && < 1.0,
462 filepath -any,
464 filepath -any,
463 Glob -any,
465 Glob -any,
464 mtl -any,
466 mtl -any,
465 optparse-applicative >= 0.12.1,
467 optparse-applicative >= 0.12.1,
468+ sourcemap >= 0.1.6,
466 transformers -any,
469 transformers -any,
467− transformers-compat -any
470+ transformers-compat -any,
471+ utf8-string >= 1 && < 2
472+
468 ghc-options: -Wall -O2
473 ghc-options: -Wall -O2
469 hs-source-dirs: psc-bundle
474 hs-source-dirs: psc-bundle
470
475
src/Language/PureScript/Bundle.hs+104−31
@@ -6,6 +6,7 @@
6-- and generates the final Javascript bundle.
6-- and generates the final Javascript bundle.
7module Language.PureScript.Bundle
7module Language.PureScript.Bundle
8 ( bundle
8 ( bundle
9+ , bundleSM
9 , guessModuleIdentifier
10 , guessModuleIdentifier
10 , ModuleIdentifier(..)
11 , ModuleIdentifier(..)
11 , moduleName
12 , moduleName
@@ -19,6 +20,7 @@ import Prelude.Compat
19
20
20import Control.Monad
21import Control.Monad
21import Control.Monad.Error.Class
22import Control.Monad.Error.Class
23+import Control.Arrow ((&&&))
22
24
23import Data.Char (chr, digitToInt)
25import Data.Char (chr, digitToInt)
24import Data.Generics (everything, everywhere, mkQ, mkT)
26import Data.Generics (everything, everywhere, mkQ, mkT)
@@ -33,7 +35,9 @@ import Language.JavaScript.Parser.AST
33
35
34import qualified Paths_purescript as Paths
36import qualified Paths_purescript as Paths
35
37
36−import System.FilePath (takeFileName, takeDirectory)
38+import System.FilePath (takeFileName, takeDirectory, takeDirectory, makeRelative)
39+
40+import SourceMap.Types
37
41
38-- | The type of error messages. We separate generation and rendering of errors using a data
42-- | The type of error messages. We separate generation and rendering of errors using a data
39-- type, in case we need to match on error types later.
43-- type, in case we need to match on error types later.
@@ -98,10 +102,11 @@ data ModuleElement
98 | Member JSStatement Bool String JSExpression [Key]
102 | Member JSStatement Bool String JSExpression [Key]
99 | ExportsList [(ExportType, String, JSExpression, [Key])]
103 | ExportsList [(ExportType, String, JSExpression, [Key])]
100 | Other JSStatement
104 | Other JSStatement
105+ | Skip JSStatement
101 deriving (Show)
106 deriving (Show)
102
107
103-- | A module is just a list of elements of the types listed above.
108-- | A module is just a list of elements of the types listed above.
104−data Module = Module ModuleIdentifier [ModuleElement] deriving (Show)
109+data Module = Module ModuleIdentifier (Maybe FilePath) [ModuleElement] deriving (Show)
105
110
106-- | Prepare an error message for consumption by humans.
111-- | Prepare an error message for consumption by humans.
107printErrorMessage :: ErrorMessage -> [String]
112printErrorMessage :: ErrorMessage -> [String]
@@ -159,7 +164,7 @@ checkImportPath name _ _ = Left name
159--
164--
160-- where name is the name of a member defined in the current module.
165-- where name is the name of a member defined in the current module.
161withDeps :: Module -> Module
166withDeps :: Module -> Module
162−withDeps (Module modulePath es) = Module modulePath (map expandDeps es)
167+withDeps (Module modulePath fn es) = Module modulePath fn (map expandDeps es)
163 where
168 where
164 -- | Collects all modules which are imported, so that we can identify dependencies of the first type.
169 -- | Collects all modules which are imported, so that we can identify dependencies of the first type.
165 imports :: [(String, ModuleIdentifier)]
170 imports :: [(String, ModuleIdentifier)]
@@ -248,9 +253,9 @@ trailingCommaList (JSCTLNone l) = commaList l
248--
253--
249-- Each type of module element is matched using pattern guards, and everything else is bundled into the
254-- Each type of module element is matched using pattern guards, and everything else is bundled into the
250-- Other constructor.
255-- Other constructor.
251−toModule :: forall m. (MonadError ErrorMessage m) => S.Set String -> ModuleIdentifier -> JSAST -> m Module
256+toModule :: forall m. (MonadError ErrorMessage m) => S.Set String -> ModuleIdentifier -> Maybe FilePath -> JSAST -> m Module
252−toModule mids mid top
257+toModule mids mid filename top
253− | JSAstProgram smts _ <- top = Module mid <$> traverse toModuleElement smts
258+ | JSAstProgram smts _ <- top = Module mid filename <$> traverse toModuleElement smts
254 | otherwise = err InvalidTopLevel
259 | otherwise = err InvalidTopLevel
255 where
260 where
256 err = throwError . ErrorInModule mid
261 err = throwError . ErrorInModule mid
@@ -389,7 +394,7 @@ compile modules entryPoints = filteredModules
389 -- | The vertex set
394 -- | The vertex set
390 verts :: [(ModuleElement, Key, [Key])]
395 verts :: [(ModuleElement, Key, [Key])]
391 verts = do
396 verts = do
392− Module mid els <- modules
397+ Module mid _ els <- modules
393 concatMap (toVertices mid) els
398 concatMap (toVertices mid) els
394 where
399 where
395 -- | Create a set of vertices for a module element.
400 -- | Create a set of vertices for a module element.
@@ -425,14 +430,21 @@ compile modules entryPoints = filteredModules
425 filteredModules = map filterUsed modules
430 filteredModules = map filterUsed modules
426 where
431 where
427 filterUsed :: Module -> Module
432 filterUsed :: Module -> Module
428− filterUsed (Module mid ds) = Module mid (map filterExports (go ds))
433+ filterUsed (Module mid fn ds) = Module mid fn (map filterExports (go ds))
429 where
434 where
430 go :: [ModuleElement] -> [ModuleElement]
435 go :: [ModuleElement] -> [ModuleElement]
431 go [] = []
436 go [] = []
432 go (d : rest)
437 go (d : rest)
433− | not (isDeclUsed d) = go rest
438+ | not (isDeclUsed d) = skipDecl d : go rest
434 | otherwise = d : go rest
439 | otherwise = d : go rest
435
440
441+ skipDecl :: ModuleElement -> ModuleElement
442+ skipDecl (Require s _ _) = Skip s
443+ skipDecl (Member s _ _ _ _) = Skip s
444+ skipDecl (ExportsList _) = Skip (JSEmptyStatement JSNoAnnot)
445+ skipDecl (Other s) = Skip s
446+ skipDecl (Skip s) = Skip s
447+
436 -- | Filter out the exports for members which aren't used.
448 -- | Filter out the exports for members which aren't used.
437 filterExports :: ModuleElement -> ModuleElement
449 filterExports :: ModuleElement -> ModuleElement
438 filterExports (ExportsList exps) = ExportsList (filter (\(_, nm, _, _) -> isKeyUsed (mid, nm)) exps)
450 filterExports (ExportsList exps) = ExportsList (filter (\(_, nm, _, _) -> isKeyUsed (mid, nm)) exps)
@@ -453,7 +465,7 @@ sortModules :: [Module] -> [Module]
453sortModules modules = map (\v -> case nodeFor v of (n, _, _) -> n) (reverse (topSort graph))
465sortModules modules = map (\v -> case nodeFor v of (n, _, _) -> n) (reverse (topSort graph))
454 where
466 where
455 (graph, nodeFor, _) = graphFromEdges $ do
467 (graph, nodeFor, _) = graphFromEdges $ do
456− m@(Module mid els) <- modules
468+ m@(Module mid _ els) <- modules
457 return (m, mid, mapMaybe getKey els)
469 return (m, mid, mapMaybe getKey els)
458
470
459 getKey :: ModuleElement -> Maybe ModuleIdentifier
471 getKey :: ModuleElement -> Maybe ModuleIdentifier
@@ -466,12 +478,13 @@ sortModules modules = map (\v -> case nodeFor v of (n, _, _) -> n) (reverse (top
466--
478--
467-- If a module is empty, we don't want to generate code for it.
479-- If a module is empty, we don't want to generate code for it.
468isModuleEmpty :: Module -> Bool
480isModuleEmpty :: Module -> Bool
469−isModuleEmpty (Module _ els) = all isElementEmpty els
481+isModuleEmpty (Module _ _ els) = all isElementEmpty els
470 where
482 where
471 isElementEmpty :: ModuleElement -> Bool
483 isElementEmpty :: ModuleElement -> Bool
472 isElementEmpty (ExportsList exps) = null exps
484 isElementEmpty (ExportsList exps) = null exps
473 isElementEmpty Require{} = True
485 isElementEmpty Require{} = True
474 isElementEmpty (Other _) = True
486 isElementEmpty (Other _) = True
487+ isElementEmpty (Skip _) = True
475 isElementEmpty _ = False
488 isElementEmpty _ = False
476
489
477-- | Generate code for a set of modules, including a call to main().
490-- | Generate code for a set of modules, including a call to main().
@@ -490,16 +503,62 @@ isModuleEmpty (Module _ els) = all isElementEmpty els
490codeGen :: Maybe String -- ^ main module
503codeGen :: Maybe String -- ^ main module
491 -> String -- ^ namespace
504 -> String -- ^ namespace
492 -> [Module] -- ^ input modules
505 -> [Module] -- ^ input modules
506+ -> Maybe String -- ^ output filename
493− -> String
507+ -> (Maybe SourceMapping, String)
494−codeGen optionsMainModule optionsNamespace ms = renderToString (JSAstProgram (prelude : concatMap moduleToJS ms ++ maybe [] runMain optionsMainModule) JSNoAnnot)
508+codeGen optionsMainModule optionsNamespace ms outFileOpt = (fmap sourceMapping outFileOpt, rendered)
495 where
509 where
496− moduleToJS :: Module -> [JSStatement]
510+ rendered = renderToString (JSAstProgram (prelude : concatMap fst modulesJS ++ maybe [] runMain optionsMainModule) JSNoAnnot)
497− moduleToJS (Module mn ds) = wrap (moduleName mn) (indent (concatMap declToJS ds))
511+
512+ sourceMapping :: String -> SourceMapping
513+ sourceMapping outFile = SourceMapping {
514+ smFile = outFile,
515+ smSourceRoot = Nothing,
516+ smMappings = concat $
517+ zipWith3 (\file (pos :: Int) positions ->
518+ map (\(porig, pgen) -> Mapping {
519+ mapOriginal = Just (Pos (fromIntegral $ porig + 1) 0)
520+ , mapSourceFile = pathToFile <$> file
521+ , mapGenerated = (Pos (fromIntegral $ pos + pgen) 0)
522+ , mapName = Nothing
523+ })
524+ (offsets (0,0) (Right 1 : positions)))
525+ moduleFns
526+ (scanl (+) (3 + moduleLength [prelude]) (map (3+) moduleLengths)) -- 3 lines between each module & at top
527+ (map snd modulesJS)
528+ }
498 where
529 where
530+ pathToFile = makeRelative (takeDirectory outFile)
531+
532+ offsets (m, n) (Left d:rest) = offsets (m+d, n) rest
533+ offsets (m, n) (Right d:rest) = map ((m+) &&& (n+)) [0 .. d - 1] ++ offsets (m+d, n+d) rest
534+ offsets _ _ = []
535+
536+ moduleLength :: [JSStatement] -> Int
537+ moduleLength = everything (+) (mkQ 0 countw)
538+ where
539+ countw :: CommentAnnotation -> Int
540+ countw (WhiteSpace _ s) = length (filter (== '\n') s)
541+ countw _ = 0
542+
543+ moduleLengths :: [Int]
544+ moduleLengths = map (sum . map (either (const 0) id) . snd) modulesJS
545+ moduleFns = map (\(Module _ fn _) -> fn) ms
546+
547+ modulesJS = map moduleToJS ms
548+
549+ moduleToJS :: Module -> ([JSStatement], [Either Int Int])
550+ moduleToJS (Module mn _ ds) = (wrap (moduleName mn) (indent (concat jsDecls)), lengths)
551+ where
552+ (jsDecls, lengths) = unzip $ map declToJS ds
553+
554+ withLength :: [JSStatement] -> ([JSStatement], Either Int Int)
555+ withLength n = (n, Right $ moduleLength n)
556+
499− declToJS :: ModuleElement -> [JSStatement]
557+ declToJS :: ModuleElement -> ([JSStatement], Either Int Int)
500− declToJS (Member n _ _ _ _) = [n]
558+ declToJS (Member n _ _ _ _) = withLength [n]
501− declToJS (Other n) = [n]
559+ declToJS (Other n) = withLength [n]
560+ declToJS (Skip n) = ([], Left $ moduleLength [n])
502− declToJS (Require _ nm req) =
561+ declToJS (Require _ nm req) = withLength
503 [
562 [
504 JSVariable lfsp
563 JSVariable lfsp
505 (cList [
564 (cList [
@@ -507,9 +566,10 @@ codeGen optionsMainModule optionsNamespace ms = renderToString (JSAstProgram (p
507 (JSVarInit sp $ either require (moduleReference sp . moduleName) req )
566 (JSVarInit sp $ either require (moduleReference sp . moduleName) req )
508 ]) (JSSemi JSNoAnnot)
567 ]) (JSSemi JSNoAnnot)
509 ]
568 ]
510− declToJS (ExportsList exps) = map toExport exps
569+ declToJS (ExportsList exps) = withLength $ map toExport exps
511
570
512 where
571 where
572+
513 toExport :: (ExportType, String, JSExpression, [Key]) -> JSStatement
573 toExport :: (ExportType, String, JSExpression, [Key]) -> JSStatement
514 toExport (_, nm, val, _) =
574 toExport (_, nm, val, _) =
515 JSAssignStatement
575 JSAssignStatement
@@ -612,26 +672,39 @@ codeGen optionsMainModule optionsNamespace ms = renderToString (JSAstProgram (p
612-- | The bundling function.
672-- | The bundling function.
613-- This function performs dead code elimination, filters empty modules
673-- This function performs dead code elimination, filters empty modules
614-- and generates and prints the final Javascript bundle.
674-- and generates and prints the final Javascript bundle.
615−bundle :: (MonadError ErrorMessage m)
675+bundleSM :: (MonadError ErrorMessage m)
616− => [(ModuleIdentifier, String)] -- ^ The input modules. Each module should be javascript rendered from 'Language.PureScript.Make' or @psc@.
676+ => [(ModuleIdentifier, Maybe FilePath, String)] -- ^ The input modules. Each module should be javascript rendered from 'Language.PureScript.Make' or @psc@.
617 -> [ModuleIdentifier] -- ^ Entry points. These module identifiers are used as the roots for dead-code elimination
677 -> [ModuleIdentifier] -- ^ Entry points. These module identifiers are used as the roots for dead-code elimination
618 -> Maybe String -- ^ An optional main module.
678 -> Maybe String -- ^ An optional main module.
619 -> String -- ^ The namespace (e.g. PS).
679 -> String -- ^ The namespace (e.g. PS).
680+ -> Maybe FilePath -- ^ The output file name (if there is one - in which case generate source map)
620− -> m String
681+ -> m (Maybe SourceMapping, String)
621−bundle inputStrs entryPoints mainModule namespace = do
682+bundleSM inputStrs entryPoints mainModule namespace outFilename = do
683+ let mid (a,_,_) = a
622 forM_ mainModule $ \mname ->
684 forM_ mainModule $ \mname ->
623− when (mname `notElem` map (moduleName . fst) inputStrs) (throwError (MissingMainModule mname))
685+ when (mname `notElem` map (moduleName . mid) inputStrs) (throwError (MissingMainModule mname))
624 forM_ entryPoints $ \mIdent ->
686 forM_ entryPoints $ \mIdent ->
625− when (mIdent `notElem` map fst inputStrs) (throwError (MissingEntryPoint (moduleName mIdent)))
687+ when (mIdent `notElem` map mid inputStrs) (throwError (MissingEntryPoint (moduleName mIdent)))
626− input <- forM inputStrs $ \(ident, js) -> do
688+ input <- forM inputStrs $ \(ident, filename, js) -> do
627 ast <- either (throwError . ErrorInModule ident . UnableToParseModule) pure $ parse js (moduleName ident)
689 ast <- either (throwError . ErrorInModule ident . UnableToParseModule) pure $ parse js (moduleName ident)
628− return (ident, ast)
690+ return (ident, filename, ast)
629
691
630− let mids = S.fromList (map (moduleName . fst) input)
692+ let mids = S.fromList (map (moduleName . mid) input)
631
693
632− modules <- traverse (fmap withDeps . uncurry (toModule mids)) input
694+ modules <- traverse (fmap withDeps . (\(a,fn,c) -> toModule mids a fn c)) input
633
695
634 let compiled = compile modules entryPoints
696 let compiled = compile modules entryPoints
635 sorted = sortModules (filter (not . isModuleEmpty) compiled)
697 sorted = sortModules (filter (not . isModuleEmpty) compiled)
636
698
637− return (codeGen mainModule namespace sorted)
699+ return (codeGen mainModule namespace sorted outFilename)
700+
701+-- | The bundling function.
702+-- This function performs dead code elimination, filters empty modules
703+-- and generates and prints the final Javascript bundle.
704+bundle :: (MonadError ErrorMessage m)
705+ => [(ModuleIdentifier, String)] -- ^ The input modules. Each module should be javascript rendered from 'Language.PureScript.Make' or @psc@.
706+ -> [ModuleIdentifier] -- ^ Entry points. These module identifiers are used as the roots for dead-code elimination
707+ -> Maybe String -- ^ An optional main module.
708+ -> String -- ^ The namespace (e.g. PS).
709+ -> m String
710+bundle inputStrs entryPoints mainModule namespace = snd <$> bundleSM (map (\(a,b) -> (a,Nothing,b)) inputStrs) entryPoints mainModule namespace Nothing