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