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