]> git.immae.eu Git - github/fretlink/purs-loader.git/blobdiff - src/PursLoader/Loader.purs
Bumping version number to 0.6.0-beta.1
[github/fretlink/purs-loader.git] / src / PursLoader / Loader.purs
index 0cd077d143d49ef712fd6c0f8d8f1b5e9300b7ca..5e00f7ec24b59c4b8971640345cc89d510bc5da3 100644 (file)
@@ -4,25 +4,27 @@ module PursLoader.Loader
   , loaderFn
   ) where
 
-import Prelude (Unit(), ($), (>>=), (<$>), (<*>), (<<<), (++), bind, const)
+import Prelude (Unit(), ($), (>>=), (<$>), (<*>), (++), bind, const, id, pure, unit)
 
+import Control.Apply ((*>))
 import Control.Bind (join)
-import Control.Monad.Eff (Eff())
+import Control.Monad.Eff (Eff(), foreachE)
 import Control.Monad.Eff.Exception (Error(), error)
 
 import Data.Array ((!!))
+import Data.Bifunctor (lmap)
+import Data.Either (Either(..), either)
+import Data.Foreign.Class (read)
 import Data.Function (Fn2(), mkFn2)
 import Data.Maybe (Maybe(..), maybe)
-import Data.Either (either)
-import Data.Foreign (Foreign())
-import Data.Foreign.Class (read)
-import Data.Foreign.Null (runNull)
+import Data.Nullable (toMaybe)
 import Data.String.Regex (Regex(), match, noFlags, regex)
 
 import Unsafe.Coerce (unsafeCoerce)
 
 import PursLoader.LoaderRef
-  ( LoaderRef()
+  ( AsyncCallback()
+  , LoaderRef()
   , Loader()
   , async
   , cacheable
@@ -32,47 +34,75 @@ import PursLoader.LoaderRef
   , resourcePath
   )
 
+import PursLoader.Debug (debug)
 import PursLoader.LoaderUtil (parseQuery)
-import PursLoader.Options (runOptions)
+import PursLoader.Options (Options(..))
 import PursLoader.Path (dirname, relative)
+import PursLoader.Plugin as Plugin
 
 type Effects eff = (loader :: Loader | eff)
 
-type PurescriptWebpackPluginContext eff = { compile :: (Foreign -> Eff (Effects eff) Unit) -> Eff (Effects eff) Unit }
-
 loader :: forall eff. LoaderRef -> String -> Eff (Effects eff) Unit
 loader ref source = do
   callback <- async ref
 
   cacheable ref
 
-  let parsed = parseQuery $ query ref
-
-      options = either (const Nothing) (Just <<< runOptions) (read parsed)
-
-      moduleName = join $ match moduleRegex source >>= \as -> as !! 1
-
-      resourceDir = dirname (resourcePath ref)
+  debug "Invoke PureScript plugin compilation"
 
-      modulePath = (\opts -> relative resourceDir opts.pscBundle) <$> options
-
-      result = (\path name -> "module.exports = require('" ++ path ++ "')['" ++ name ++ "'];") <$> modulePath <*> moduleName
-
-  clearDependencies ref
-
-  addDependency ref (resourcePath ref)
-
-  pluginContext.compile (\err -> maybe (callback (Just $ error "Failed to run loader") "")
-                                       (callback (compileError err)) result)
+  pluginContext.compile (compile callback)
   where
-  moduleRegex :: Regex
-  moduleRegex = regex "(?:^|\\n)module\\s+([\\w\\.]+)" noFlags { ignoreCase = true }
-
-  pluginContext :: PurescriptWebpackPluginContext eff
+  pluginContext :: Plugin.Context (Effects eff)
   pluginContext = (unsafeCoerce ref).purescriptWebpackPluginContext
 
-  compileError :: Foreign -> Maybe Error
-  compileError value = either (const $ Just (error "Failed to compile")) ((<$>) error) (runNull <$> read value)
+  compile :: AsyncCallback eff -> Plugin.Compile (Effects eff)
+  compile callback error' { srcMap, ffiMap, graph } = do
+    clearDependencies ref
+
+    either (const $ pure unit) (\a -> debug ("Adding PureScript dependency " ++ a)) name
+
+    addDependency ref (resourcePath ref)
+
+    either (\err -> callback (Just err) "") id
+           (handle <$> name <*> dependencies <*> exports)
+    where
+    handle :: String -> Array String -> String -> Eff (Effects eff) Unit
+    handle name' deps res = do
+      debug ("Adding PureScript transitive dependencies for " ++ name')
+      addTransitive name'
+      foreachE deps addTransitive
+      callback (toMaybe error') res
+
+    exports :: Either Error String
+    exports = (\a b -> "module.exports = require('" ++ a ++ "')['" ++ b ++ "'];") <$> path <*> name
+
+    dependencies :: Either Error (Array String)
+    dependencies = name >>= Plugin.dependenciesOf graph
+
+    addTransitive :: String -> Eff (Effects eff) Unit
+    addTransitive dep = addDep (Plugin.get srcMap dep) *> addDep (Plugin.get ffiMap dep)
+      where
+      addDep :: Maybe String -> Eff (Effects eff) Unit
+      addDep = maybe (pure unit) (addDependency ref)
+
+    name :: Either Error String
+    name =
+      maybe (Left $ error "Failed to parse module name") Right
+            (join $ match re source >>= \as -> as !! 1)
+      where
+      re :: Regex
+      re = regex "(?:^|\\n)module\\s+([\\w\\.]+)" noFlags { ignoreCase = true }
+
+    path :: Either Error String
+    path = (\(Options opts) -> relative resourceDir opts.bundleOutput) <$> options
+      where
+      options :: Either Error Options
+      options =
+        lmap (const $ error "Failed to parse loader query")
+             (read $ parseQuery (query ref))
+
+      resourceDir :: String
+      resourceDir = dirname (resourcePath ref)
 
 loaderFn :: forall eff. Fn2 LoaderRef String (Eff (Effects eff) Unit)
 loaderFn = mkFn2 loader