@@ -1,295 +0,0 @@
1−{-# OPTIONS_GHC -Wall #-}
2−{-# LANGUAGE OverloadedStrings #-}
3−module Generate.Output
4− ( Mode(..)
5− , Mode.Target(..)
6− , generate
7− , generateReplFile
8− , noDebugUsesInPackage
9− , Output(..)
10− , output
11− )
12− where
13−
14−
15−import Control.Concurrent.MVar (MVar, putMVar)
16−import Control.Monad.Trans (liftIO)
17−import qualified Data.ByteString.Builder as B
18−import qualified Data.Map as Map
19−import Data.Monoid ((<>))
20−import qualified Data.Name as Name
21−import qualified System.Directory as Dir
22−import qualified System.FilePath as FP
23−import System.FilePath ((</>))
24−
25−import qualified Elm.Compiler as Compiler
26−import qualified Elm.Compiler.Objects as Obj
27−import qualified Elm.Interface as I
28−import qualified Elm.ModuleName as ModuleName
29−import qualified Elm.Package as Pkg
30−import qualified Elm.Project.Json as Project
31−import qualified Elm.Project.Summary as Summary
32−import qualified File.Args as Args
33−import qualified File.Crawl as Crawl
34−import qualified File.IO as IO
35−import qualified Generate.Functions as Functions
36−import qualified Generate.Html as Html
37−import qualified Generate.Nitpick as Nitpick
38−import qualified Generate.JavaScript.Mode as Mode
39−import qualified Reporting.Exit as Exit
40−import qualified Reporting.Exit.Make as E
41−import qualified Reporting.Render.Type.Localizer as L
42−import qualified Reporting.Task as Task
43−import qualified Stuff.Paths as Paths
44−import Terminal.Args (Parser(..))
45−
46−
47−
48−-- GENERATE
49−
50−
51−data Mode = Debug | Dev | Prod
52−
53−
54−generate
55− :: Mode
56− -> Mode.Target
57− -> Maybe Output
58− -> Summary.Summary
59− -> Crawl.Result
60− -> Map.Map ModuleName.Raw Compiler.Artifacts
61− -> Task.Task ()
62−generate mode target maybeOutput summary graph@(Crawl.Graph args locals _ _ _) artifacts =
63− case args of
64− Args.Pkg _ ->
65− return ()
66−
67− Args.Roots name names ->
68− do objectGraph <- organize summary graph
69−
70− realMode <-
71− case mode of
72− Debug ->
73− do interfaces <- getInterfaces summary locals artifacts
74− return $ Mode.debug target interfaces
75−
76− Dev ->
77− return $ Mode.dev target
78−
79− Prod ->
80− do noDebugUses summary objectGraph
81− return $ Mode.prod target objectGraph
82−
83− generateMonolith realMode maybeOutput summary objectGraph (name:names)
84−
85−
86−getInterfaces
87− :: Summary.Summary
88− -> Map.Map ModuleName.Raw a
89− -> Map.Map ModuleName.Raw Compiler.Artifacts
90− -> Task.Task I.Interfaces
91−getInterfaces (Summary.Summary root project _ interfaces _) locals artifacts =
92− let
93− pkg =
94− Project.getName project
95−
96− addArtifact home (Compiler.Artifacts elmi _ _) ifaces =
97− (ModuleName.Canonical pkg home, elmi) : ifaces
98−
99− addInterface home iface ifaces =
100− (ModuleName.Canonical pkg home, iface) : ifaces
101−
102− readInterface home _ =
103− IO.readBinary (Paths.elmi root home)
104− in
105− do cached <- Map.traverseWithKey readInterface (Map.difference locals artifacts)
106− return $
107− Map.union interfaces $ Map.fromList $
108− Map.foldrWithKey addInterface (Map.foldrWithKey addArtifact [] artifacts) cached
109−
110−
111−
112−-- GENERATE MONOLITH
113−
114−
115−generateMonolith
116− :: Mode.Mode
117− -> Maybe Output
118− -> Summary.Summary
119− -> Obj.Graph
120− -> [ModuleName.Raw]
121− -> Task.Task ()
122−generateMonolith mode maybeOutput (Summary.Summary _ project _ _ _) graph rootNames =
123− do let pkg = Project.getName project
124− let roots = map (ModuleName.Canonical pkg) rootNames
125− case Obj.generate mode graph roots of
126− Obj.None ->
127− return ()
128−
129− Obj.Some name _names builder ->
130− let
131− monolith =
132− "(function(scope){\n'use strict';"
133− <> Functions.functions <> builder <> "}(this));"
134− in
135− liftIO $
136− case maybeOutput of
137− Nothing ->
138− IO.writeBuilder "index.html" (Html.sandwich name monolith)
139−
140− Just output_ ->
141− case output_ of
142− None ->
143− return ()
144−
145− JavaScript maybeDir fileName ->
146− do path <- toWritablePath maybeDir fileName
147− IO.writeBuilder path monolith
148−
149− HtmlBuilder mvar ->
150− putMVar mvar (Html.sandwich name monolith)
151−
152− Html maybeDir fileName ->
153− do path <- toWritablePath maybeDir fileName
154− IO.writeBuilder path (Html.sandwich name monolith)
155−
156−
157−
158−-- GENERATE REPL MONOLITH
159−
160−
161−generateReplFile
162− :: Bool
163− -> L.Localizer
164− -> Summary.Summary
165− -> Crawl.Result
166− -> I.Interface
167− -> Name.Name
168− -> Task.Task FilePath
169−generateReplFile noColors localizer summary@(Summary.Summary _ project _ _ _) graph iface name =
170− do
171− objectGraph <- organize summary graph
172−
173− let home = ModuleName.Canonical (Project.getName project) Name.replModule
174− let builder = Obj.generateForRepl (not noColors) localizer objectGraph iface home name
175−
176− liftIO $ IO.writeBuilder (Paths.temp "js") $
177− replRecovery <> "(function(){\n'use strict';" <> Functions.functions <> builder <> "}());"
178−
179− return (Paths.temp "js")
180−
181−
182−replRecovery :: B.Builder
183−replRecovery =
184− "process.on('uncaughtException', function(err) { process.stderr.write(err.toString()); process.exit(1); });"
185−
186−
187−
188−-- ORGANIZE
189−
190−
191−organize :: Summary.Summary -> Crawl.Result -> Task.Task Obj.Graph
192−organize (Summary.Summary root _ _ _ deps) (Crawl.Graph _ locals _ _ _) =
193− do localObjs <- Obj.unions <$> traverse (loadModuleObj root) (Map.keys locals)
194− foreignObjs <- Obj.unions <$> traverse loadPackageObj (Map.toList deps)
195− return (Obj.union localObjs foreignObjs)
196−
197−
198−loadModuleObj :: FilePath -> ModuleName.Raw -> Task.Task Obj.Graph
199−loadModuleObj root name =
200− IO.readBinary (Paths.elmo root name)
201−
202−
203−loadPackageObj :: ( Pkg.Name, (Pkg.Version, deps) ) -> Task.Task Obj.Graph
204−loadPackageObj ( name, (version,_) ) =
205− do dir <- Task.getPackageCacheDirFor name version
206− IO.readBinary (dir </> "objs.dat")
207−
208−
209−
210−-- NO DEBUG USES
211−
212−
213−noDebugUses :: Summary.Summary -> Obj.Graph -> Task.Task ()
214−noDebugUses (Summary.Summary _ project _ _ _) graph =
215− case Nitpick.findDebugUses (Project.getName project) graph of
216− [] ->
217− return ()
218−
219− m:ms ->
220− Task.throw (Exit.Make (E.CannotOptimizeDebugValues m ms))
221−
222−
223−noDebugUsesInPackage :: Summary.Summary -> Crawl.Result -> Task.Task ()
224−noDebugUsesInPackage summary graph =
225− noDebugUses summary =<< organize summary graph
226−
227−
228−
229−-- OUTPUT
230−
231−
232−data Output
233− = None
234− | Html (Maybe FilePath) FilePath
235− | JavaScript (Maybe FilePath) FilePath
236− | HtmlBuilder (MVar B.Builder)
237−
238−
239−toWritablePath :: Maybe FilePath -> FilePath -> IO FilePath
240−toWritablePath maybeDir fileName =
241− case maybeDir of
242− Nothing ->
243− do return fileName
244−
245− Just dir ->
246− do Dir.createDirectoryIfMissing True dir
247− return (dir </> fileName)
248−
249−
250−
251−-- OUTPUT PARSER
252−
253−
254−output :: Parser Output
255−output =
256− Parser
257− { _singular = "output file"
258− , _plural = "output files"
259− , _parser = parseOutput
260− , _suggest = \_ -> return []
261− , _examples = exampleOutput
262− }
263−
264−
265−parseOutput :: String -> Maybe Output
266−parseOutput string =
267− if string == "/dev/null" || string == "NUL" || string == "$null" then
268− Just None
269−
270− else if FP.takeExtension string == ".html" && length string > 5 then
271− splitOutput Html string
272−
273− else if FP.takeExtension string == ".js" && length string > 3 then
274− splitOutput JavaScript string
275−
276− else
277− Nothing
278−
279−
280−splitOutput :: (Maybe FilePath -> FilePath -> Output) -> String -> Maybe Output
281−splitOutput toOutput string =
282− case FP.splitPath string of
283− [] ->
284− Nothing
285−
286− [name] ->
287− Just $ toOutput Nothing name
288−
289− segments ->
290− Just $ toOutput (Just (FP.joinPath (init segments))) (last segments)
291−
292−
293−exampleOutput :: String -> IO [String]
294−exampleOutput _ =
295− return [ "elm.js", "index.html", "/dev/null" ]