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.LoaderUtil (parseQuery)
38 import PursLoader.Options (Options(..))
39 import PursLoader.Path (dirname, relative)
40 import PursLoader.Plugin as Plugin
42 type Effects eff = (loader :: Loader | eff)
44 loader :: forall eff. LoaderRef -> String -> Eff (Effects eff) Unit
45 loader ref source = do
50 pluginContext.compile (compile callback)
52 pluginContext :: Plugin.Context (Effects eff)
53 pluginContext = (unsafeCoerce ref).purescriptWebpackPluginContext
55 compile :: AsyncCallback eff -> Plugin.Compile (Effects eff)
56 compile callback error' { srcMap, ffiMap, graph } = do
59 addDependency ref (resourcePath ref)
61 either (\err -> callback (Just err) "") id
62 (handle <$> name <*> dependencies <*> exports)
64 handle :: String -> Array String -> String -> Eff (Effects eff) Unit
65 handle name' deps res = do
67 foreachE deps addTransitive
68 callback (toMaybe error') res
70 exports :: Either Error String
71 exports = (\a b -> "module.exports = require('" ++ a ++ "')['" ++ b ++ "'];") <$> path <*> name
73 dependencies :: Either Error (Array String)
74 dependencies = name >>= Plugin.dependenciesOf graph
76 addTransitive :: String -> Eff (Effects eff) Unit
77 addTransitive dep = addDep (Plugin.get srcMap dep) *> addDep (Plugin.get ffiMap dep)
79 addDep :: Maybe String -> Eff (Effects eff) Unit
80 addDep = maybe (pure unit) (addDependency ref)
82 name :: Either Error String
84 maybe (Left $ error "Failed to parse module name") Right
85 (join $ match re source >>= \as -> as !! 1)
88 re = regex "(?:^|\\n)module\\s+([\\w\\.]+)" noFlags { ignoreCase = true }
90 path :: Either Error String
91 path = (\(Options opts) -> relative resourceDir opts.bundleOutput) <$> options
93 options :: Either Error Options
95 lmap (const $ error "Failed to parse loader query")
96 (read $ parseQuery (query ref))
99 resourceDir = dirname (resourcePath ref)
101 loaderFn :: forall eff. Fn2 LoaderRef String (Eff (Effects eff) Unit)
102 loaderFn = mkFn2 loader