1 module PursLoader.Loader
7 import Prelude (Unit(), ($), (>>=), (<$>), (<*>), (++), bind, const, id, pure, unit)
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)
15 import Data.Array ((!!))
16 import Data.Bifunctor (lmap)
17 import Data.Either (Either(..), either)
18 import Data.Foreign.Class (read)
19 import Data.Function (Fn2(), mkFn2)
20 import Data.Maybe (Maybe(..), maybe)
21 import Data.Nullable (toMaybe)
22 import Data.String.Regex (Regex(), match, noFlags, regex)
24 import Unsafe.Coerce (unsafeCoerce)
26 import PursLoader.LoaderRef
38 import PursLoader.Debug (debug)
39 import PursLoader.LoaderUtil (parseQuery)
40 import PursLoader.Options (Options(..))
41 import PursLoader.Path (dirname, relative)
42 import PursLoader.Plugin as Plugin
44 type Effects eff = (loader :: Loader | eff)
46 loader :: forall eff. LoaderRef -> String -> Eff (Effects eff) Unit
47 loader ref source = do
52 debug "Invoke PureScript plugin compilation"
54 pluginContext.compile (compile callback)
56 pluginContext :: Plugin.Context (Effects eff)
57 pluginContext = (unsafeCoerce ref).purescriptWebpackPluginContext
59 compile :: AsyncCallback eff -> Plugin.Compile (Effects eff)
60 compile callback error' { srcMap, ffiMap, graph } = do
63 either (const $ pure unit) (\a -> debug ("Adding PureScript dependency " ++ a)) name
65 addDependency ref (resourcePath ref)
67 either (\err -> callback (toMaybe error' <|> Just err) "") id
68 (handle <$> name <*> dependencies <*> exports)
70 handle :: String -> Array String -> String -> Eff (Effects eff) Unit
71 handle name' deps res = do
72 debug ("Adding PureScript transitive dependencies for " ++ name')
74 foreachE deps addTransitive
75 debug "Generated loader result"
77 callback (toMaybe error') res
79 exports :: Either Error String
80 exports = (\a b -> "module.exports = require('" ++ a ++ "')['" ++ b ++ "'];") <$> path <*> name
82 dependencies :: Either Error (Array String)
83 dependencies = name >>= Plugin.dependenciesOf graph
85 addTransitive :: String -> Eff (Effects eff) Unit
86 addTransitive dep = addDep (Plugin.get srcMap dep) *> addDep (Plugin.get ffiMap dep)
88 addDep :: Maybe String -> Eff (Effects eff) Unit
89 addDep = maybe (pure unit) (addDependency ref)
91 name :: Either Error String
93 maybe (Left $ error "Failed to parse module name") Right
94 (join $ match re source >>= \as -> as !! 1)
97 re = regex "(?:^|\\n)module\\s+([\\w\\.]+)" noFlags { ignoreCase = true }
99 path :: Either Error String
100 path = (\(Options opts) -> relative resourceDir opts.bundleOutput) <$> options
102 options :: Either Error Options
104 lmap (const $ error "Failed to parse loader query")
105 (read $ parseQuery (query ref))
107 resourceDir :: String
108 resourceDir = dirname (resourcePath ref)
110 loaderFn :: forall eff. Fn2 LoaderRef String (Eff (Effects eff) Unit)
111 loaderFn = mkFn2 loader