1 module PursLoader.Loader
7 import Prelude (Unit(), ($), (>>=), (<$>), (<*>), (++), bind, const, id, pure, unit)
9 import Control.Apply ((*>))
10 import Control.Bind (join)
11 import Control.Monad.Eff (Eff(), foreachE)
12 import Control.Monad.Eff.Exception (Error(), error)
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)
23 import Unsafe.Coerce (unsafeCoerce)
25 import PursLoader.LoaderRef
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
43 type Effects eff = (loader :: Loader | eff)
45 loader :: forall eff. LoaderRef -> String -> Eff (Effects eff) Unit
46 loader ref source = do
51 debug "Invoke PureScript plugin compilation"
53 pluginContext.compile (compile callback)
55 pluginContext :: Plugin.Context (Effects eff)
56 pluginContext = (unsafeCoerce ref).purescriptWebpackPluginContext
58 compile :: AsyncCallback eff -> Plugin.Compile (Effects eff)
59 compile callback error' { srcMap, ffiMap, graph } = do
62 either (const $ pure unit) (\a -> debug ("Adding PureScript dependency " ++ a)) name
64 addDependency ref (resourcePath ref)
66 either (\err -> callback (Just err) "") id
67 (handle <$> name <*> dependencies <*> exports)
69 handle :: String -> Array String -> String -> Eff (Effects eff) Unit
70 handle name' deps res = do
71 debug ("Adding PureScript transitive dependencies for " ++ name')
73 foreachE deps addTransitive
74 debug "Generated loader result"
76 callback (toMaybe error') res
78 exports :: Either Error String
79 exports = (\a b -> "module.exports = require('" ++ a ++ "')['" ++ b ++ "'];") <$> path <*> name
81 dependencies :: Either Error (Array String)
82 dependencies = name >>= Plugin.dependenciesOf graph
84 addTransitive :: String -> Eff (Effects eff) Unit
85 addTransitive dep = addDep (Plugin.get srcMap dep) *> addDep (Plugin.get ffiMap dep)
87 addDep :: Maybe String -> Eff (Effects eff) Unit
88 addDep = maybe (pure unit) (addDependency ref)
90 name :: Either Error String
92 maybe (Left $ error "Failed to parse module name") Right
93 (join $ match re source >>= \as -> as !! 1)
96 re = regex "(?:^|\\n)module\\s+([\\w\\.]+)" noFlags { ignoreCase = true }
98 path :: Either Error String
99 path = (\(Options opts) -> relative resourceDir opts.bundleOutput) <$> options
101 options :: Either Error Options
103 lmap (const $ error "Failed to parse loader query")
104 (read $ parseQuery (query ref))
106 resourceDir :: String
107 resourceDir = dirname (resourcePath ref)
109 loaderFn :: forall eff. Fn2 LoaderRef String (Eff (Effects eff) Unit)
110 loaderFn = mkFn2 loader