1 module PursLoader.Loader
7 import Prelude (Unit(), ($), (<>), (>>=), (<$>), (++), bind, flip, id, pure, return, unit)
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)
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 import Data.Traversable (sequence)
21 import PursLoader.ChildProcess (ChildProcess(), spawn)
22 import PursLoader.FS (FS(), writeFileUtf8, findFileUtf8)
23 import PursLoader.Glob (Glob(), globAll)
24 import PursLoader.LoaderRef (LoaderRef(), Loader(), async, cacheable, query, clearDependencies, addDependency, resourcePath)
25 import PursLoader.LoaderUtil (parseQuery)
26 import PursLoader.Options (loaderFFIOption, loaderSrcOption, pscOptions)
28 type Effects eff = (cp :: ChildProcess, fs :: FS, glob :: Glob, loader :: Loader | eff)
30 moduleRegex = regex "(?:^|\\n)module\\s+([\\w\\.]+)" noFlags { ignoreCase = true }
32 foreignRegex = regex "(?:^|\\n)\\s*foreign import\\s+" noFlags { ignoreCase = true }
38 psciFilename = ".psci"
42 foreign import cwd :: String
44 foreign import relative :: String -> String -> String
46 foreign import resolve :: String -> String
48 mkPsci :: Array (Array String) -> Array (Array String) -> String
49 mkPsci srcs ffis = joinWith "\n" ((loadModule <$> concat srcs) <> (loadForeign <$> concat ffis))
51 loadModule :: String -> String
52 loadModule a = ":m " ++ relative cwd a
54 loadForeign :: String -> String
55 loadForeign a = ":f " ++ relative cwd a
57 findFFI :: forall eff. Array (Array String) -> String -> Aff (fs :: FS | eff) (Maybe String)
58 findFFI ffiss name = findFileUtf8 re (concat ffiss)
60 re = regex ("(?:^|\\n)//\\s*module\\s*" ++ name ++ "\\s*\\n") noFlags
62 loader' :: forall eff. LoaderRef -> String -> Aff (Effects eff) (Maybe String)
63 loader' ref source = do
64 liftEff $ cacheable ref
66 let parsed = parseQuery $ query ref
67 srcs = fromMaybe [] (loaderSrcOption parsed)
68 ffis = fromMaybe [] (loaderFFIOption parsed)
69 opts = pscOptions parsed
74 let psciFile = mkPsci srcss ffiss
76 writeFileUtf8 psciFilename psciFile
78 let moduleName = match moduleRegex source >>= (!!!) 1 >>= id
79 hasForeign = test foreignRegex source
80 result = (\a -> "module.exports = require('" ++ a ++ "');") <$> moduleName
82 liftEff (clearDependencies ref)
83 liftEff (addDependency ref (resourcePath ref))
84 liftEff (sequence $ (\src -> addDependency ref (resolve src)) <$> concat srcss)
86 foreignPath <- if hasForeign
87 then fromMaybe (pure Nothing) (findFFI ffiss <$> moduleName)
90 fromMaybe (pure unit) ((\path -> liftEff (addDependency ref path)) <$> foreignPath)
92 spawn pscCommand (srcs <> opts)
96 loader :: forall eff. LoaderRef -> String -> Eff (Effects eff) Unit
97 loader ref source = do
99 runAff (\e -> callback (Just e) "")
100 (maybe (callback (Just (error "Loader has failed to run")) "")
104 loaderFn :: forall eff. Fn2 LoaderRef String (Eff (Effects eff) Unit)
105 loaderFn = mkFn2 loader