module PursLoader.Loader
- ( LoaderEff()
+ ( Effects()
, loader
, loaderFn
) where
import Control.Monad.Eff.Class (liftEff)
import Control.Monad.Eff.Exception (error)
-import Data.Array ((!!), catMaybes, concat, filter, null)
-import Data.Foldable (foldl)
+import Data.Array ((!!))
import Data.Function (Fn2(), mkFn2)
import Data.Maybe (Maybe(..), fromMaybe, maybe)
-import Data.Set (Set(), empty, insert, member, toList, unions)
-import Data.String (joinWith, split)
-import Data.String.Regex (Regex(), match, noFlags, regex)
-import Data.StrMap (StrMap(), fromList, lookup)
-import Data.Traversable (sequence)
-import Data.Tuple.Nested (tuple2)
+import Data.String.Regex (match, noFlags, regex)
import PursLoader.ChildProcess (ChildProcess(), spawn)
-import PursLoader.FS (FS(), readFileUtf8, readFileUtf8Sync)
-import PursLoader.Glob (Glob(), glob)
-import PursLoader.LoaderRef (LoaderRef(), Loader(), async, cacheable, clearDependencies, addDependency, query, resourcePath)
+import PursLoader.LoaderRef (LoaderRef(), Loader(), async, cacheable, query)
import PursLoader.LoaderUtil (getRemainingRequest, parseQuery)
-import PursLoader.OS (eol)
-import PursLoader.Options (pscMakeOptions, pscMakeDefaultOutput, pscMakeOutputOption)
-import PursLoader.Path (dirname, join, relative, resolve)
+import PursLoader.Options (loaderSrcOption, pscOptions)
-foreign import cwd "var cwd = process.cwd();" :: String
+type Effects eff = (loader :: Loader, cp :: ChildProcess | eff)
moduleRegex = regex "(?:^|\\n)module\\s+([\\w\\.]+)" noFlags { ignoreCase = true }
-importRegex = regex "^\\s*import\\s+(?:qualified\\s+)?([\\w\\.]+)" noFlags { ignoreCase = true }
-
-bowerPattern = join [ "bower_components", "purescript-*", "src" ]
-
-pscMakeCommand = "psc-make"
-
-indexFilename = "index.js"
+pscCommand = "psc"
(!!!) = flip (!!)
-pursPattern :: String -> String
-pursPattern root = join [ "{" ++ joinWith "," [ bowerPattern, root ] ++ "}"
- , "**"
- , "*.purs"
- ]
-
-type GraphModule = { file :: String, imports :: [String] }
-
-type Graph = StrMap GraphModule
-
-mkGraph :: forall eff. [String] -> Eff (fs :: FS | eff) Graph
-mkGraph files = (fromList <<< catMaybes) <$> sequence (parse <$> files)
- where parse file = do source <- readFileUtf8Sync file
- let key = match moduleRegex source >>= (!!!) 1
- lines = split eol source
- imports = catMaybes $ (\a -> match importRegex a >>= (!!!) 1) <$> lines
- return $ (\a -> tuple2 a { file: file, imports: imports }) <$> key
-
-mkDeps :: forall eff. String -> Graph -> [String]
-mkDeps key graph = toList $ go empty key
- where
- go :: Set String -> String -> Set String
- go acc key =
- let node = fromMaybe {file: "", imports: []} (lookup key graph)
- uniq = filter (not <<< flip member acc) node.imports
- acc' = foldl (flip insert) acc node.imports
- in if null uniq
- then acc'
- else unions $ go acc' <$> uniq
-
-addDeps :: forall eff. LoaderRef -> Graph -> [String] -> Eff (loader :: Loader | eff) Unit
-addDeps ref graph deps = const unit <$> (sequence $ add <$> deps)
- where add dep = let res = lookup dep graph
- path = (\a -> resolve a.file) <$> res
- in maybe (pure unit) (addDependency ref) path
-
-type LoaderAff eff a = Aff (loader :: Loader, glob :: Glob, cp :: ChildProcess, fs :: FS | eff) a
-
-loader' :: forall eff. LoaderRef -> String -> LoaderAff eff (Maybe String)
+loader' :: forall eff. LoaderRef -> String -> Aff (Effects eff) (Maybe String)
loader' ref source = do
liftEff $ cacheable ref
let request = getRemainingRequest ref
- root = dirname $ relative cwd request
parsed = parseQuery $ query ref
- opts = pscMakeOptions parsed
- pattern = pursPattern root
- key = match moduleRegex source >>= (!!!) 1
-
- files <- glob pattern
- graph <- liftEff $ mkGraph files
-
- let deps = fromMaybe [] $ flip mkDeps graph <$> key
- outputPath = fromMaybe pscMakeDefaultOutput $ pscMakeOutputOption parsed
- indexPath = (\a -> join [ outputPath, a, indexFilename ]) <$> key
-
- liftEff $ clearDependencies ref
- liftEff $ addDependency ref (resourcePath ref)
- liftEff $ addDeps ref graph deps
-
- spawn pscMakeCommand (opts <> files)
- indexFile <- sequence $ readFileUtf8 <$> indexPath
- return indexFile
+ srcs = fromMaybe [] (loaderSrcOption parsed)
+ opts = pscOptions parsed
+ moduleName = match moduleRegex source >>= (!!!) 1
+ result = (\a -> "module.exports = require('" ++ a ++ "');") <$> moduleName
-type LoaderEff eff a = Eff (loader :: Loader, glob :: Glob, cp :: ChildProcess, fs :: FS | eff) a
+ spawn pscCommand (srcs <> opts)
+ return result
-loader :: forall eff. LoaderRef -> String -> LoaderEff eff Unit
+loader :: forall eff. LoaderRef -> String -> Eff (Effects eff) Unit
loader ref source = do
callback <- async ref
runAff (\e -> callback (Just e) "")
- (maybe (callback (Just $ error "Loader has failed to run") "")
+ (maybe (callback (Just (error "Loader has failed to run")) "")
(callback Nothing))
(loader' ref source)
-loaderFn :: forall eff. Fn2 LoaderRef String (LoaderEff eff Unit)
+loaderFn :: forall eff. Fn2 LoaderRef String (Eff (Effects eff) Unit)
loaderFn = mkFn2 loader