]> git.immae.eu Git - github/fretlink/purs-loader.git/blob - src/PursLoader/Loader.purs
5373d2f1e6320c288d59a0b0aa4adec66e147903
[github/fretlink/purs-loader.git] / src / PursLoader / Loader.purs
1 module PursLoader.Loader
2 ( Effects()
3 , loader
4 , loaderFn
5 ) where
6
7 import Prelude (Unit(), ($), (<>), (>>=), (<$>), (++), bind, flip, id, pure, return, unit)
8
9 import Control.Monad.Aff (Aff(), runAff)
10 import Control.Monad.Eff (Eff())
11 import Control.Monad.Eff.Class (liftEff)
12 import Control.Monad.Eff.Exception (error)
13
14 import Data.Array ((!!), concat)
15 import Data.Function (Fn2(), mkFn2)
16 import Data.Maybe (Maybe(..), fromMaybe, maybe)
17 import Data.String (joinWith)
18 import Data.String.Regex (match, noFlags, regex, test)
19
20 import PursLoader.ChildProcess (ChildProcess(), spawn)
21 import PursLoader.FS (FS(), writeFileUtf8, findFileUtf8)
22 import PursLoader.Glob (Glob(), globAll)
23 import PursLoader.LoaderRef (LoaderRef(), Loader(), async, cacheable, query, clearDependencies, addDependency, resourcePath)
24 import PursLoader.LoaderUtil (parseQuery)
25 import PursLoader.Options (loaderFFIOption, loaderSrcOption, pscOptions)
26
27 type Effects eff = (cp :: ChildProcess, fs :: FS, glob :: Glob, loader :: Loader | eff)
28
29 moduleRegex = regex "(?:^|\\n)module\\s+([\\w\\.]+)" noFlags { ignoreCase = true }
30
31 foreignRegex = regex "(?:^|\\n)\\s*foreign import\\s+" noFlags { ignoreCase = true }
32
33 pscCommand = "psc"
34
35 psciCommand = "psci"
36
37 psciFilename = ".psci"
38
39 (!!!) = flip (!!)
40
41 foreign import cwd :: String
42
43 foreign import relative :: String -> String -> String
44
45 mkPsci :: Array (Array String) -> Array (Array String) -> String
46 mkPsci srcs ffis = joinWith "\n" ((loadModule <$> concat srcs) <> (loadForeign <$> concat ffis))
47 where
48 loadModule :: String -> String
49 loadModule a = ":m " ++ relative cwd a
50
51 loadForeign :: String -> String
52 loadForeign a = ":f " ++ relative cwd a
53
54 findFFI :: forall eff. Array (Array String) -> String -> Aff (fs :: FS | eff) (Maybe String)
55 findFFI ffiss name = findFileUtf8 re (concat ffiss)
56 where
57 re = regex ("(?:^|\\n)//\\s*module\\s*" ++ name ++ "\\s*\\n") noFlags
58
59 loader' :: forall eff. LoaderRef -> String -> Aff (Effects eff) (Maybe String)
60 loader' ref source = do
61 liftEff $ cacheable ref
62
63 let parsed = parseQuery $ query ref
64 srcs = fromMaybe [] (loaderSrcOption parsed)
65 ffis = fromMaybe [] (loaderFFIOption parsed)
66 opts = pscOptions parsed
67
68 spawn pscCommand (srcs <> opts)
69
70 srcss <- globAll srcs
71 ffiss <- globAll ffis
72
73 let psciFile = mkPsci srcss ffiss
74
75 writeFileUtf8 psciFilename psciFile
76
77 let moduleName = match moduleRegex source >>= (!!!) 1 >>= id
78 hasForeign = test foreignRegex source
79 result = (\a -> "module.exports = require('" ++ a ++ "');") <$> moduleName
80
81 liftEff (clearDependencies ref)
82 liftEff (addDependency ref (resourcePath ref))
83
84 foreignPath <- if hasForeign
85 then fromMaybe (pure Nothing) (findFFI ffiss <$> moduleName)
86 else pure Nothing
87
88 fromMaybe (pure unit) ((\path -> liftEff (addDependency ref path)) <$> foreignPath)
89
90 return result
91
92 loader :: forall eff. LoaderRef -> String -> Eff (Effects eff) Unit
93 loader ref source = do
94 callback <- async ref
95 runAff (\e -> callback (Just e) "")
96 (maybe (callback (Just (error "Loader has failed to run")) "")
97 (callback Nothing))
98 (loader' ref source)
99
100 loaderFn :: forall eff. Fn2 LoaderRef String (Eff (Effects eff) Unit)
101 loaderFn = mkFn2 loader