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