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.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)
22 import Unsafe.Coerce (unsafeCoerce)
24 import PursLoader.LoaderRef
35 import PursLoader.Debug (debug)
36 import PursLoader.Path (dirname, joinPath, relative)
37 import PursLoader.Plugin as Plugin
39 type Effects eff = (loader :: Loader | eff)
41 loader :: forall eff. LoaderRef -> String -> Eff (Effects eff) Unit
42 loader ref source = do
47 debug "Invoke PureScript plugin compilation"
49 pluginContext.compile (compile callback)
51 pluginContext :: Plugin.Context (Effects eff)
52 pluginContext = (unsafeCoerce ref).purescriptWebpackPluginContext
54 compile :: AsyncCallback eff -> Plugin.Compile (Effects eff)
55 compile callback error' { srcMap, ffiMap, graph } = do
58 either (const $ pure unit) (\a -> debug ("Adding PureScript dependency " ++ a)) name
60 addDependency ref (resourcePath ref)
62 either (\err -> callback (toMaybe error' <|> Just err) "") id
63 (handle <$> name <*> dependencies <*> exports)
65 handle :: String -> Array String -> String -> Eff (Effects eff) Unit
66 handle name' deps res = do
67 debug ("Adding PureScript transitive dependencies for " ++ name')
69 foreachE deps addTransitive
70 debug "Generated loader result"
72 callback (toMaybe error') res
74 exports :: Either Error String
76 if pluginContext.options.bundle
77 then bundleExport <$> name
78 else moduleExport <<< modulePath <$> name
80 bundleExport :: String -> String
81 bundleExport name' = "module.exports = require('" ++ path ++ "')['" ++ name' ++ "'];"
84 path = relative resourceDir pluginContext.options.bundleOutput
86 moduleExport :: String -> String
87 moduleExport path = "module.exports = require('" ++ path ++ "');"
89 modulePath :: String -> String
90 modulePath = relative resourceDir <<< joinPath pluginContext.options.output
93 resourceDir = dirname (resourcePath ref)
95 dependencies :: Either Error (Array String)
97 if pluginContext.options.bundle
98 then name >>= Plugin.dependenciesOf graph
101 addTransitive :: String -> Eff (Effects eff) Unit
102 addTransitive dep = addDep (Plugin.get srcMap dep) *> addDep (Plugin.get ffiMap dep)
104 addDep :: Maybe String -> Eff (Effects eff) Unit
105 addDep = maybe (pure unit) (addDependency ref)
107 name :: Either Error String
109 maybe (Left $ error "Failed to parse module name") Right
110 (join $ match re source >>= \as -> as !! 1)
113 re = regex "(?:^|\\n)module\\s+([\\w\\.]+)" noFlags { ignoreCase = true }
115 loaderFn :: forall eff. Fn2 LoaderRef String (Eff (Effects eff) Unit)
116 loaderFn = mkFn2 loader