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 callback (toMaybe error') res
76 exports :: Either Error String
77 exports = (\a b -> "module.exports = require('" ++ a ++ "')['" ++ b ++ "'];") <$> path <*> name
79 dependencies :: Either Error (Array String)
80 dependencies = name >>= Plugin.dependenciesOf graph
82 addTransitive :: String -> Eff (Effects eff) Unit
83 addTransitive dep = addDep (Plugin.get srcMap dep) *> addDep (Plugin.get ffiMap dep)
85 addDep :: Maybe String -> Eff (Effects eff) Unit
86 addDep = maybe (pure unit) (addDependency ref)
88 name :: Either Error String
90 maybe (Left $ error "Failed to parse module name") Right
91 (join $ match re source >>= \as -> as !! 1)
94 re = regex "(?:^|\\n)module\\s+([\\w\\.]+)" noFlags { ignoreCase = true }
96 path :: Either Error String
97 path = (\(Options opts) -> relative resourceDir opts.bundleOutput) <$> options
99 options :: Either Error Options
101 lmap (const $ error "Failed to parse loader query")
102 (read $ parseQuery (query ref))
104 resourceDir :: String
105 resourceDir = dirname (resourcePath ref)
107 loaderFn :: forall eff. Fn2 LoaderRef String (Eff (Effects eff) Unit)
108 loaderFn = mkFn2 loader