aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/PursLoader
diff options
context:
space:
mode:
authoreric thul <thul.eric@gmail.com>2015-12-25 18:41:33 -0500
committereric thul <thul.eric@gmail.com>2015-12-25 18:41:33 -0500
commit63d6a244462d050e119bde54a7063bae8a17e987 (patch)
treecce47ed541fa9ee8b2950945a89608b1c06fb8c9 /src/PursLoader
parent2e2da2be94720a739c595ec179a7ed49480ce753 (diff)
downloadpurs-loader-63d6a244462d050e119bde54a7063bae8a17e987.tar.gz
purs-loader-63d6a244462d050e119bde54a7063bae8a17e987.tar.zst
purs-loader-63d6a244462d050e119bde54a7063bae8a17e987.zip
Splitting PSC functionality into a separate plugin
The loader creates shim modules that reference their corresponding PureScript module that is bundled by the PureScript webpack plugin, which invokes `psc` and `psc-bundle`. Resolves #31 and resolves #32
Diffstat (limited to 'src/PursLoader')
-rw-r--r--src/PursLoader/ChildProcess.js40
-rw-r--r--src/PursLoader/ChildProcess.purs23
-rw-r--r--src/PursLoader/FS.js36
-rw-r--r--src/PursLoader/FS.purs38
-rw-r--r--src/PursLoader/Glob.js18
-rw-r--r--src/PursLoader/Glob.purs22
-rw-r--r--src/PursLoader/Loader.purs139
-rw-r--r--src/PursLoader/LoaderRef.purs13
-rw-r--r--src/PursLoader/Options.purs132
-rw-r--r--src/PursLoader/Path.js (renamed from src/PursLoader/Loader.js)11
-rw-r--r--src/PursLoader/Path.purs14
11 files changed, 91 insertions, 395 deletions
diff --git a/src/PursLoader/ChildProcess.js b/src/PursLoader/ChildProcess.js
deleted file mode 100644
index d62aef6..0000000
--- a/src/PursLoader/ChildProcess.js
+++ /dev/null
@@ -1,40 +0,0 @@
1'use strict';
2
3// module PursLoader.ChildProcess
4
5var child_process = require('child_process');
6
7var chalk = require('chalk');
8
9function spawnFn(command, args, errback, callback) {
10 return function(){
11 var process = child_process.spawn(command, args);
12
13 var stdout = new Buffer(0);
14
15 var stderr = new Buffer(0);
16
17 process.stdout.on('data', function(data){
18 stdout = Buffer.concat([stdout, new Buffer(data)]);
19 });
20
21 process.stderr.on('data', function(data){
22 stderr = Buffer.concat([stderr, new Buffer(data)]);
23 });
24
25 process.on('close', function(code){
26 var output = stdout.toString('utf-8');
27
28 var error = stderr.toString('utf-8');
29
30 if (error.length > 0) {
31 console.error('\n' + chalk.red('*') + ' ' + error);
32 }
33
34 if (code !== 0) errback(new Error('Process terminated with code ' + code))();
35 else callback(output)();
36 });
37 };
38}
39
40exports.spawnFn = spawnFn;
diff --git a/src/PursLoader/ChildProcess.purs b/src/PursLoader/ChildProcess.purs
deleted file mode 100644
index 3bd960b..0000000
--- a/src/PursLoader/ChildProcess.purs
+++ /dev/null
@@ -1,23 +0,0 @@
1module PursLoader.ChildProcess
2 ( ChildProcess()
3 , spawn
4 ) where
5
6import Prelude (Unit(), ($))
7
8import Control.Monad.Aff (Aff(), makeAff)
9import Control.Monad.Eff (Eff())
10import Control.Monad.Eff.Exception (Error())
11
12import Data.Function
13
14foreign import data ChildProcess :: !
15
16spawn :: forall eff. String -> Array String -> Aff (cp :: ChildProcess | eff) String
17spawn command args = makeAff $ runFn4 spawnFn command args
18
19foreign import spawnFn :: forall eff. Fn4 String
20 (Array String)
21 (Error -> Eff (cp :: ChildProcess | eff) Unit)
22 (String -> Eff (cp :: ChildProcess | eff) Unit)
23 (Eff (cp :: ChildProcess | eff) Unit)
diff --git a/src/PursLoader/FS.js b/src/PursLoader/FS.js
deleted file mode 100644
index 1a7f5b0..0000000
--- a/src/PursLoader/FS.js
+++ /dev/null
@@ -1,36 +0,0 @@
1'use strict';
2
3// module PursLoader.FS
4
5var fs = require('fs');
6
7var async = require('async');
8
9function writeFileUtf8Fn(filepath, contents, errback, callback) {
10 return function(){
11 fs.writeFile(filepath, contents, function(error){
12 if (error) errback(error)();
13 else callback()();
14 });
15 };
16}
17
18function findFileUtf8Fn(nothing, just, regex, filepaths, errback, callback) {
19 return function(){
20 function findFile(filepath, callback) {
21 fs.readFile(filepath, {encoding: 'utf-8'}, function(error, result){
22 if (error) callback(false);
23 else callback(regex.test(result));
24 });
25 }
26
27 async.detect(filepaths, findFile, function(result){
28 if (!result) callback(nothing)();
29 else callback(just(result))();
30 });
31 };
32}
33
34exports.writeFileUtf8Fn = writeFileUtf8Fn;
35
36exports.findFileUtf8Fn = findFileUtf8Fn;
diff --git a/src/PursLoader/FS.purs b/src/PursLoader/FS.purs
deleted file mode 100644
index 969e3d0..0000000
--- a/src/PursLoader/FS.purs
+++ /dev/null
@@ -1,38 +0,0 @@
1module PursLoader.FS
2 ( FS()
3 , writeFileUtf8
4 , findFileUtf8
5 ) where
6
7import Prelude (Unit(), ($))
8
9import Control.Monad.Aff (Aff(), makeAff)
10import Control.Monad.Eff (Eff())
11import Control.Monad.Eff.Exception (Error())
12
13import Data.Maybe (Maybe(..))
14import Data.String.Regex (Regex())
15
16import Data.Function
17
18foreign import data FS :: !
19
20writeFileUtf8 :: forall eff. String -> String -> Aff (fs :: FS | eff) Unit
21writeFileUtf8 filepath contents = makeAff $ runFn4 writeFileUtf8Fn filepath contents
22
23foreign import writeFileUtf8Fn :: forall eff. Fn4 String
24 String
25 (Error -> Eff (fs :: FS | eff) Unit)
26 (Unit -> Eff (fs :: FS | eff) Unit)
27 (Eff (fs :: FS | eff) Unit)
28
29findFileUtf8 :: forall eff. Regex -> Array String -> Aff (fs :: FS | eff) (Maybe String)
30findFileUtf8 regexp filepaths = makeAff $ runFn6 findFileUtf8Fn Nothing Just regexp filepaths
31
32foreign import findFileUtf8Fn :: forall eff. Fn6 (Maybe String)
33 (String -> Maybe String)
34 Regex
35 (Array String)
36 (Error -> Eff (fs :: FS | eff) Unit)
37 (Maybe String -> Eff (fs :: FS | eff) Unit)
38 (Eff (fs :: FS | eff) Unit)
diff --git a/src/PursLoader/Glob.js b/src/PursLoader/Glob.js
deleted file mode 100644
index 960ae9a..0000000
--- a/src/PursLoader/Glob.js
+++ /dev/null
@@ -1,18 +0,0 @@
1'use strict';
2
3// module PursLoader.Glob
4
5var glob = require('glob');
6
7var async = require('async');
8
9function globAllFn(patterns, errback, callback) {
10 return function(){
11 async.map(patterns, glob, function(error, result){
12 if (error) errback(new Error(error))();
13 else callback(result)();
14 });
15 };
16}
17
18exports.globAllFn = globAllFn;
diff --git a/src/PursLoader/Glob.purs b/src/PursLoader/Glob.purs
deleted file mode 100644
index 45eeb56..0000000
--- a/src/PursLoader/Glob.purs
+++ /dev/null
@@ -1,22 +0,0 @@
1module PursLoader.Glob
2 ( Glob()
3 , globAll
4 ) where
5
6import Prelude (Unit(), ($))
7
8import Control.Monad.Aff (Aff(), makeAff)
9import Control.Monad.Eff (Eff())
10import Control.Monad.Eff.Exception (Error())
11
12import Data.Function
13
14foreign import data Glob :: !
15
16globAll :: forall eff. Array String -> Aff (glob :: Glob | eff) (Array (Array String))
17globAll patterns = makeAff $ runFn3 globAllFn patterns
18
19foreign import globAllFn :: forall eff. Fn3 (Array String)
20 (Error -> Eff (glob :: Glob | eff) Unit)
21 ((Array (Array String)) -> Eff (glob :: Glob | eff) Unit)
22 (Eff (glob :: Glob | eff) Unit)
diff --git a/src/PursLoader/Loader.purs b/src/PursLoader/Loader.purs
index a91667c..0cd077d 100644
--- a/src/PursLoader/Loader.purs
+++ b/src/PursLoader/Loader.purs
@@ -4,122 +4,75 @@ module PursLoader.Loader
4 , loaderFn 4 , loaderFn
5 ) where 5 ) where
6 6
7import Prelude (Unit(), ($), (<>), (>>=), (<$>), (++), bind, flip, id, pure, return, unit, show) 7import Prelude (Unit(), ($), (>>=), (<$>), (<*>), (<<<), (++), bind, const)
8 8
9import Control.Monad.Aff (Aff(), runAff) 9import Control.Bind (join)
10import Control.Monad.Eff (Eff()) 10import Control.Monad.Eff (Eff())
11import Control.Monad.Eff.Class (liftEff) 11import Control.Monad.Eff.Exception (Error(), error)
12import Control.Monad.Eff.Exception (throwException, error, EXCEPTION())
13 12
14import Data.Array ((!!), concat) 13import Data.Array ((!!))
15import Data.Function (Fn2(), mkFn2) 14import Data.Function (Fn2(), mkFn2)
16import Data.Maybe (Maybe(..), fromMaybe, maybe) 15import Data.Maybe (Maybe(..), maybe)
17import Data.Either (Either(..)) 16import Data.Either (either)
18import Data.String (joinWith) 17import Data.Foreign (Foreign())
19import Data.String.Regex (Regex(), match, noFlags, regex, test)
20import Data.Traversable (sequence)
21import Data.Foreign (F())
22import Data.Foreign.Class (read) 18import Data.Foreign.Class (read)
19import Data.Foreign.Null (runNull)
20import Data.String.Regex (Regex(), match, noFlags, regex)
21
22import Unsafe.Coerce (unsafeCoerce)
23
24import PursLoader.LoaderRef
25 ( LoaderRef()
26 , Loader()
27 , async
28 , cacheable
29 , query
30 , clearDependencies
31 , addDependency
32 , resourcePath
33 )
23 34
24import PursLoader.ChildProcess (ChildProcess(), spawn)
25import PursLoader.FS (FS(), writeFileUtf8, findFileUtf8)
26import PursLoader.Glob (Glob(), globAll)
27import PursLoader.LoaderRef (LoaderRef(), Loader(), async, cacheable, query, clearDependencies, addDependency, resourcePath)
28import PursLoader.LoaderUtil (parseQuery) 35import PursLoader.LoaderUtil (parseQuery)
29import PursLoader.Options (loaderFFIOption, loaderSrcOption, pscOptions, Options(), output) 36import PursLoader.Options (runOptions)
37import PursLoader.Path (dirname, relative)
30 38
31type Effects eff = (cp :: ChildProcess, fs :: FS, glob :: Glob, loader :: Loader, err :: EXCEPTION | eff) 39type Effects eff = (loader :: Loader | eff)
32 40
33moduleRegex :: Regex 41type PurescriptWebpackPluginContext eff = { compile :: (Foreign -> Eff (Effects eff) Unit) -> Eff (Effects eff) Unit }
34moduleRegex = regex "(?:^|\\n)module\\s+([\\w\\.]+)" noFlags { ignoreCase = true }
35 42
36foreignRegex :: Regex 43loader :: forall eff. LoaderRef -> String -> Eff (Effects eff) Unit
37foreignRegex = regex "(?:^|\\n)\\s*foreign import\\s+" noFlags { ignoreCase = true } 44loader ref source = do
38 45 callback <- async ref
39pscCommand :: String
40pscCommand = "psc"
41
42psciCommand :: String
43psciCommand = "psci"
44
45psciFilename :: String
46psciFilename = ".psci"
47
48(!!!) :: forall a. Int -> Array a -> Maybe a
49(!!!) = flip (!!)
50
51foreign import cwd :: String
52
53foreign import relative :: String -> String -> String
54
55foreign import resolve :: String -> String
56
57foreign import dirname :: String -> String
58
59foreign import joinPath :: String -> String -> String
60
61mkPsci :: Array (Array String) -> Array (Array String) -> String
62mkPsci srcs ffis = joinWith "\n" ((loadModule <$> concat srcs) <> (loadForeign <$> concat ffis))
63 where
64 loadModule :: String -> String
65 loadModule a = ":m " ++ relative cwd a
66
67 loadForeign :: String -> String
68 loadForeign a = ":f " ++ relative cwd a
69
70findFFI :: forall eff. Array (Array String) -> String -> Aff (fs :: FS | eff) (Maybe String)
71findFFI ffiss name = findFileUtf8 re (concat ffiss)
72 where
73 re = regex ("(?:^|\\n)//\\s*module\\s*" ++ name ++ "\\s*\\n") noFlags
74 46
75loader' :: forall eff. LoaderRef -> String -> Aff (Effects eff) (Maybe String) 47 cacheable ref
76loader' ref source = do
77 liftEff $ cacheable ref
78 48
79 let parsed = parseQuery $ query ref 49 let parsed = parseQuery $ query ref
80 srcs = fromMaybe [] (loaderSrcOption parsed)
81 ffis = fromMaybe [] (loaderFFIOption parsed)
82 50
83 case read parsed :: F Options of 51 options = either (const Nothing) (Just <<< runOptions) (read parsed)
84 Left e -> liftEff (throwException (error (show e)))
85 Right opts -> do
86 let pscOpts = pscOptions opts
87 52
88 srcss <- globAll srcs 53 moduleName = join $ match moduleRegex source >>= \as -> as !! 1
89 ffiss <- globAll ffis
90 54
91 let psciFile = mkPsci srcss ffiss 55 resourceDir = dirname (resourcePath ref)
92 56
93 writeFileUtf8 psciFilename psciFile 57 modulePath = (\opts -> relative resourceDir opts.pscBundle) <$> options
94 58
95 let moduleName = match moduleRegex source >>= (!!!) 1 >>= id 59 result = (\path name -> "module.exports = require('" ++ path ++ "')['" ++ name ++ "'];") <$> modulePath <*> moduleName
96 hasForeign = test foreignRegex source
97 outputDir = resolve (output opts)
98 resourceDir = dirname (resourcePath ref)
99 result = (\a -> "module.exports = require('" ++ relative resourceDir (joinPath outputDir a) ++ "');") <$> moduleName
100 60
101 liftEff do 61 clearDependencies ref
102 clearDependencies ref
103 addDependency ref (resourcePath ref)
104 sequence $ (\src -> addDependency ref (resolve src)) <$> concat srcss
105 62
106 foreignPath <- if hasForeign 63 addDependency ref (resourcePath ref)
107 then fromMaybe (pure Nothing) (findFFI ffiss <$> moduleName)
108 else pure Nothing
109 64
110 fromMaybe (pure unit) ((\path -> liftEff (addDependency ref path)) <$> foreignPath) 65 pluginContext.compile (\err -> maybe (callback (Just $ error "Failed to run loader") "")
111 66 (callback (compileError err)) result)
112 spawn pscCommand (srcs <> pscOpts) 67 where
68 moduleRegex :: Regex
69 moduleRegex = regex "(?:^|\\n)module\\s+([\\w\\.]+)" noFlags { ignoreCase = true }
113 70
114 return result 71 pluginContext :: PurescriptWebpackPluginContext eff
72 pluginContext = (unsafeCoerce ref).purescriptWebpackPluginContext
115 73
116loader :: forall eff. LoaderRef -> String -> Eff (Effects eff) Unit 74 compileError :: Foreign -> Maybe Error
117loader ref source = do 75 compileError value = either (const $ Just (error "Failed to compile")) ((<$>) error) (runNull <$> read value)
118 callback <- async ref
119 runAff (\e -> callback (Just e) "")
120 (maybe (callback (Just (error "Loader has failed to run")) "")
121 (callback Nothing))
122 (loader' ref source)
123 76
124loaderFn :: forall eff. Fn2 LoaderRef String (Eff (Effects eff) Unit) 77loaderFn :: forall eff. Fn2 LoaderRef String (Eff (Effects eff) Unit)
125loaderFn = mkFn2 loader 78loaderFn = mkFn2 loader
diff --git a/src/PursLoader/LoaderRef.purs b/src/PursLoader/LoaderRef.purs
index 33c4f7e..87d6006 100644
--- a/src/PursLoader/LoaderRef.purs
+++ b/src/PursLoader/LoaderRef.purs
@@ -1,6 +1,7 @@
1module PursLoader.LoaderRef 1module PursLoader.LoaderRef
2 ( LoaderRef() 2 ( LoaderRef()
3 , Loader() 3 , Loader()
4 , AsyncCallback()
4 , async 5 , async
5 , cacheable 6 , cacheable
6 , query 7 , query
@@ -17,16 +18,18 @@ import Control.Monad.Eff.Exception (Error())
17import Data.Function (Fn3(), runFn3) 18import Data.Function (Fn3(), runFn3)
18import Data.Maybe (Maybe(), fromMaybe, isJust) 19import Data.Maybe (Maybe(), fromMaybe, isJust)
19 20
21type AsyncCallback eff = Maybe Error -> String -> Eff (loader :: Loader | eff) Unit
22
20data LoaderRef 23data LoaderRef
21 24
22foreign import data Loader :: ! 25foreign import data Loader :: !
23 26
24foreign import asyncFn :: forall eff a. Fn3 (Maybe Error -> Boolean) 27foreign import asyncFn :: forall eff. Fn3 (Maybe Error -> Boolean)
25 (Error -> Maybe Error -> Error) 28 (Error -> Maybe Error -> Error)
26 LoaderRef 29 LoaderRef
27 (Eff (loader :: Loader | eff) (Maybe Error -> a -> Eff (loader :: Loader | eff) Unit)) 30 (Eff (loader :: Loader | eff) (AsyncCallback eff))
28 31
29async :: forall eff a. LoaderRef -> Eff (loader :: Loader | eff) (Maybe Error -> a -> Eff (loader :: Loader | eff) Unit) 32async :: forall eff. LoaderRef -> Eff (loader :: Loader | eff) (Maybe Error -> String -> Eff (loader :: Loader | eff) Unit)
30async ref = runFn3 asyncFn isJust fromMaybe ref 33async ref = runFn3 asyncFn isJust fromMaybe ref
31 34
32foreign import cacheable :: forall eff. LoaderRef -> Eff (loader :: Loader | eff) Unit 35foreign import cacheable :: forall eff. LoaderRef -> Eff (loader :: Loader | eff) Unit
diff --git a/src/PursLoader/Options.purs b/src/PursLoader/Options.purs
index 3657d1a..132096c 100644
--- a/src/PursLoader/Options.purs
+++ b/src/PursLoader/Options.purs
@@ -1,122 +1,30 @@
1module PursLoader.Options 1module PursLoader.Options
2 ( pscOptions 2 ( Options()
3 , loaderSrcOption 3 , runOptions
4 , loaderFFIOption
5 , Options()
6 , output
7 ) where 4 ) where
8 5
9import Prelude ((<>), (<$>), (<<<), (++), (<*>), ($), const, id) 6import Prelude ((<$>), (<<<), id)
10 7
11import Data.Array (concat) 8import Data.Foreign.Class (IsForeign, readProp)
12import Data.Either (either) 9import Data.Foreign.NullOrUndefined (runNullOrUndefined)
10import Data.Maybe (maybe)
13 11
14import Data.Foreign (Foreign()) 12import PursLoader.Path (joinPath)
15import Data.Foreign.Class (IsForeign, read, readProp)
16import Data.Foreign.NullOrUndefined (NullOrUndefined(..), runNullOrUndefined)
17 13
18import Data.Maybe (Maybe(..), maybe, fromMaybe) 14newtype Options = Options { pscBundle :: String }
19 15
20noPreludeOpt :: String 16type Options_ = { pscBundle :: String }
21noPreludeOpt = "no-prelude"
22 17
23noOptsOpt :: String 18runOptions :: Options -> Options_
24noOptsOpt = "no-opts" 19runOptions (Options options) = options
25
26noMagicDoOpt :: String
27noMagicDoOpt = "no-magic-do"
28
29noTcoOpt :: String
30noTcoOpt = "no-tco"
31
32verboseErrorsOpt :: String
33verboseErrorsOpt = "verbose-errors"
34
35outputOpt :: String
36outputOpt = "output"
37
38commentsOpt :: String
39commentsOpt = "comments"
40
41noPrefixOpt :: String
42noPrefixOpt = "no-prefix"
43
44requirePathOpt :: String
45requirePathOpt = "require-path"
46
47srcOpt :: String
48srcOpt = "src"
49
50ffiOpt :: String
51ffiOpt = "ffi"
52
53newtype Options
54 = Options { noPrelude :: NullOrUndefined Boolean
55 , noOpts :: NullOrUndefined Boolean
56 , noMagicDo :: NullOrUndefined Boolean
57 , noTco :: NullOrUndefined Boolean
58 , verboseErrors :: NullOrUndefined Boolean
59 , comments :: NullOrUndefined Boolean
60 , output :: String
61 , noPrefix :: NullOrUndefined Boolean
62 , requirePath :: String
63 , src :: NullOrUndefined (Array String)
64 , ffi :: NullOrUndefined (Array String)
65 }
66
67output :: Options -> String
68output (Options o) = o.output
69 20
70instance isForeignOptions :: IsForeign Options where 21instance isForeignOptions :: IsForeign Options where
71 read obj = Options <$> ({ noPrelude: _ 22 read obj =
72 , noOpts: _ 23 Options <$> ({ pscBundle: _ }
73 , noMagicDo: _ 24 <$> (maybe pscBundleDefault id <<< runNullOrUndefined <$> readProp pscBundle obj))
74 , noTco: _ 25 where
75 , verboseErrors: _ 26 pscBundle :: String
76 , comments: _ 27 pscBundle = "pscBundle"
77 , output: _ 28
78 , noPrefix: _ 29 pscBundleDefault :: String
79 , requirePath: "../" 30 pscBundleDefault = joinPath "output" "bundle.js"
80 , src: _
81 , ffi: _
82 } <$> readProp noPreludeOpt obj
83 <*> readProp noOptsOpt obj
84 <*> readProp noMagicDoOpt obj
85 <*> readProp noTcoOpt obj
86 <*> readProp verboseErrorsOpt obj
87 <*> readProp commentsOpt obj
88 <*> (maybe "output" id <<< runNullOrUndefined <$> readProp outputOpt obj)
89 <*> readProp noPrefixOpt obj
90 <*> readProp srcOpt obj
91 <*> readProp ffiOpt obj)
92
93class LoaderOption a where
94 opt :: String -> NullOrUndefined a -> Array String
95
96instance booleanLoaderOption :: LoaderOption Boolean where
97 opt key val = maybe [] (\a -> if a then ["--" ++ key] else []) (runNullOrUndefined val)
98
99instance stringLoaderOption :: LoaderOption String where
100 opt key val = maybe [] (\a -> ["--" ++ key ++ "=" ++ a]) (runNullOrUndefined val)
101
102instance arrayLoaderOption :: (LoaderOption a) => LoaderOption (Array a) where
103 opt key val = concat (opt key <$> (NullOrUndefined <<< Just)
104 <$> (fromMaybe [] (runNullOrUndefined val)))
105
106pscOptions :: Options -> Array String
107pscOptions (Options a) = opt noPreludeOpt a.noPrelude <>
108 opt noOptsOpt a.noOpts <>
109 opt noMagicDoOpt a.noMagicDo <>
110 opt noTcoOpt a.noTco <>
111 opt verboseErrorsOpt a.verboseErrors <>
112 opt commentsOpt a.comments <>
113 opt outputOpt (NullOrUndefined $ Just a.output) <>
114 opt noPrefixOpt a.noPrefix <>
115 opt requirePathOpt (NullOrUndefined $ Just a.requirePath) <>
116 opt ffiOpt a.ffi
117
118loaderSrcOption :: Foreign -> Maybe (Array String)
119loaderSrcOption query = either (const Nothing) (\(Options a) -> runNullOrUndefined a.src) (read query)
120
121loaderFFIOption :: Foreign -> Maybe (Array String)
122loaderFFIOption query = either (const Nothing) (\(Options a) -> runNullOrUndefined a.ffi) (read query)
diff --git a/src/PursLoader/Loader.js b/src/PursLoader/Path.js
index 45e9c2f..878f256 100644
--- a/src/PursLoader/Loader.js
+++ b/src/PursLoader/Path.js
@@ -1,27 +1,22 @@
1'use strict' 1'use strict'
2 2
3// module PursLoader.Loader 3// module PursLoader.Path
4 4
5var path = require('path'); 5var path = require('path');
6 6
7var cwd = process.cwd();
8
9function relative(from) { 7function relative(from) {
10 return function(to){ 8 return function(to){
11 return path.relative(from, to); 9 return path.relative(from, to);
12 }; 10 };
13} 11}
12exports.relative = relative;
13
14 14
15function joinPath(a) { 15function joinPath(a) {
16 return function(b) { 16 return function(b) {
17 return path.join(a, b); 17 return path.join(a, b);
18 }; 18 };
19} 19}
20
21exports.cwd = cwd;
22
23exports.relative = relative;
24
25exports.joinPath = joinPath; 20exports.joinPath = joinPath;
26 21
27exports.resolve = path.resolve; 22exports.resolve = path.resolve;
diff --git a/src/PursLoader/Path.purs b/src/PursLoader/Path.purs
new file mode 100644
index 0000000..98cad5a
--- /dev/null
+++ b/src/PursLoader/Path.purs
@@ -0,0 +1,14 @@
1module PursLoader.Path
2 ( relative
3 , resolve
4 , dirname
5 , joinPath
6 ) where
7
8foreign import relative :: String -> String -> String
9
10foreign import resolve :: String -> String
11
12foreign import dirname :: String -> String
13
14foreign import joinPath :: String -> String -> String