]> git.immae.eu Git - github/fretlink/purs-loader.git/blob - src/PursLoader/Loader.purs
d1068b6b91b896939b9cf491cfd694ab168fe91e
[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, const, id, pure, unit)
8
9 import Control.Apply ((*>))
10 import Control.Alt ((<|>))
11 import Control.Bind (join)
12 import Control.Monad.Eff (Eff(), foreachE)
13 import Control.Monad.Eff.Exception (Error(), error)
14
15 import Data.Array ((!!))
16 import Data.Bifunctor (lmap)
17 import Data.Either (Either(..), either)
18 import Data.Foreign.Class (read)
19 import Data.Function (Fn2(), mkFn2)
20 import Data.Maybe (Maybe(..), maybe)
21 import Data.Nullable (toMaybe)
22 import Data.String.Regex (Regex(), match, noFlags, regex)
23
24 import Unsafe.Coerce (unsafeCoerce)
25
26 import PursLoader.LoaderRef
27 ( AsyncCallback()
28 , LoaderRef()
29 , Loader()
30 , async
31 , cacheable
32 , query
33 , clearDependencies
34 , addDependency
35 , resourcePath
36 )
37
38 import PursLoader.Debug (debug)
39 import PursLoader.LoaderUtil (parseQuery)
40 import PursLoader.Options (Options(..))
41 import PursLoader.Path (dirname, relative)
42 import PursLoader.Plugin as Plugin
43
44 type Effects eff = (loader :: Loader | eff)
45
46 loader :: forall eff. LoaderRef -> String -> Eff (Effects eff) Unit
47 loader ref source = do
48 callback <- async ref
49
50 cacheable ref
51
52 debug "Invoke PureScript plugin compilation"
53
54 pluginContext.compile (compile callback)
55 where
56 pluginContext :: Plugin.Context (Effects eff)
57 pluginContext = (unsafeCoerce ref).purescriptWebpackPluginContext
58
59 compile :: AsyncCallback eff -> Plugin.Compile (Effects eff)
60 compile callback error' { srcMap, ffiMap, graph } = do
61 clearDependencies ref
62
63 either (const $ pure unit) (\a -> debug ("Adding PureScript dependency " ++ a)) name
64
65 addDependency ref (resourcePath ref)
66
67 either (\err -> callback (toMaybe error' <|> Just err) "") id
68 (handle <$> name <*> dependencies <*> exports)
69 where
70 handle :: String -> Array String -> String -> Eff (Effects eff) Unit
71 handle name' deps res = do
72 debug ("Adding PureScript transitive dependencies for " ++ name')
73 addTransitive name'
74 foreachE deps addTransitive
75 debug "Generated loader result"
76 debug res
77 callback (toMaybe error') res
78
79 exports :: Either Error String
80 exports = (\a b -> "module.exports = require('" ++ a ++ "')['" ++ b ++ "'];") <$> path <*> name
81
82 dependencies :: Either Error (Array String)
83 dependencies = name >>= Plugin.dependenciesOf graph
84
85 addTransitive :: String -> Eff (Effects eff) Unit
86 addTransitive dep = addDep (Plugin.get srcMap dep) *> addDep (Plugin.get ffiMap dep)
87 where
88 addDep :: Maybe String -> Eff (Effects eff) Unit
89 addDep = maybe (pure unit) (addDependency ref)
90
91 name :: Either Error String
92 name =
93 maybe (Left $ error "Failed to parse module name") Right
94 (join $ match re source >>= \as -> as !! 1)
95 where
96 re :: Regex
97 re = regex "(?:^|\\n)module\\s+([\\w\\.]+)" noFlags { ignoreCase = true }
98
99 path :: Either Error String
100 path = (\(Options opts) -> relative resourceDir opts.bundleOutput) <$> options
101 where
102 options :: Either Error Options
103 options =
104 lmap (const $ error "Failed to parse loader query")
105 (read $ parseQuery (query ref))
106
107 resourceDir :: String
108 resourceDir = dirname (resourcePath ref)
109
110 loaderFn :: forall eff. Fn2 LoaderRef String (Eff (Effects eff) Unit)
111 loaderFn = mkFn2 loader