aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--.gitignore5
-rw-r--r--MODULE.md226
-rw-r--r--bower.json16
-rw-r--r--entry.js11
-rw-r--r--gulpfile.js68
-rw-r--r--index.js164
-rw-r--r--package.json38
-rw-r--r--src/ChildProcess.purs40
-rw-r--r--src/FS.purs45
-rw-r--r--src/Glob.purs31
-rw-r--r--src/Loader.purs114
-rw-r--r--src/LoaderRef.purs75
-rw-r--r--src/LoaderUtil.purs20
-rw-r--r--src/OS.purs3
-rw-r--r--src/Options.purs72
-rw-r--r--src/Path.purs36
-rw-r--r--webpack.config.js29
17 files changed, 814 insertions, 179 deletions
diff --git a/.gitignore b/.gitignore
index 8cde684..e58d33a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,10 @@
1.psci
1npm-debug.log 2npm-debug.log
3index.json
4index.js
2node_modules/ 5node_modules/
6bower_components/
7build/
3example/node_modules/ 8example/node_modules/
4example/bower_components/ 9example/bower_components/
5example/dist/ 10example/dist/
diff --git a/MODULE.md b/MODULE.md
new file mode 100644
index 0000000..39d9d3a
--- /dev/null
+++ b/MODULE.md
@@ -0,0 +1,226 @@
1# Module Documentation
2
3## Module PursLoader.ChildProcess
4
5#### `ChildProcess`
6
7``` purescript
8data ChildProcess :: !
9```
10
11
12#### `spawn`
13
14``` purescript
15spawn :: forall eff. String -> [String] -> Aff (cp :: ChildProcess | eff) String
16```
17
18
19
20## Module PursLoader.FS
21
22#### `FS`
23
24``` purescript
25data FS :: !
26```
27
28
29#### `readFileUtf8`
30
31``` purescript
32readFileUtf8 :: forall eff. String -> Aff (fs :: FS | eff) String
33```
34
35
36#### `readFileUtf8Sync`
37
38``` purescript
39readFileUtf8Sync :: forall eff. String -> Eff (fs :: FS | eff) String
40```
41
42
43
44## Module PursLoader.Glob
45
46#### `Glob`
47
48``` purescript
49data Glob :: !
50```
51
52
53#### `glob`
54
55``` purescript
56glob :: forall eff. String -> Aff (glob :: Glob | eff) [String]
57```
58
59
60
61## Module PursLoader.Loader
62
63#### `LoaderEff`
64
65``` purescript
66type LoaderEff eff a = Eff (fs :: FS, cp :: ChildProcess, glob :: Glob, loader :: Loader | eff) a
67```
68
69
70#### `loader`
71
72``` purescript
73loader :: forall eff. LoaderRef -> String -> LoaderEff eff Unit
74```
75
76
77#### `loaderFn`
78
79``` purescript
80loaderFn :: forall eff. Fn2 LoaderRef String (LoaderEff eff Unit)
81```
82
83
84
85## Module PursLoader.LoaderRef
86
87#### `LoaderRef`
88
89``` purescript
90data LoaderRef
91```
92
93
94#### `Loader`
95
96``` purescript
97data Loader :: !
98```
99
100
101#### `async`
102
103``` purescript
104async :: forall eff a. LoaderRef -> Eff (loader :: Loader | eff) (Maybe Error -> a -> Eff (loader :: Loader | eff) Unit)
105```
106
107
108#### `cacheable`
109
110``` purescript
111cacheable :: forall eff. LoaderRef -> Eff (loader :: Loader | eff) Unit
112```
113
114
115#### `clearDependencies`
116
117``` purescript
118clearDependencies :: forall eff. LoaderRef -> Eff (loader :: Loader | eff) Unit
119```
120
121
122#### `resourcePath`
123
124``` purescript
125resourcePath :: LoaderRef -> String
126```
127
128
129#### `addDependency`
130
131``` purescript
132addDependency :: forall eff. LoaderRef -> String -> Eff (loader :: Loader | eff) Unit
133```
134
135
136#### `query`
137
138``` purescript
139query :: LoaderRef -> String
140```
141
142
143
144## Module PursLoader.LoaderUtil
145
146#### `getRemainingRequest`
147
148``` purescript
149getRemainingRequest :: LoaderRef -> String
150```
151
152
153#### `parseQuery`
154
155``` purescript
156parseQuery :: String -> Foreign
157```
158
159
160
161## Module PursLoader.OS
162
163#### `eol`
164
165``` purescript
166eol :: String
167```
168
169
170
171## Module PursLoader.Options
172
173#### `isForeignOptions`
174
175``` purescript
176instance isForeignOptions :: IsForeign Options
177```
178
179
180#### `pscMakeOutputOption`
181
182``` purescript
183pscMakeOutputOption :: Foreign -> Maybe String
184```
185
186
187#### `pscMakeOptions`
188
189``` purescript
190pscMakeOptions :: Foreign -> [String]
191```
192
193
194
195## Module PursLoader.Path
196
197#### `dirname`
198
199``` purescript
200dirname :: String -> String
201```
202
203
204#### `join`
205
206``` purescript
207join :: [String] -> String
208```
209
210
211#### `relative`
212
213``` purescript
214relative :: String -> String -> String
215```
216
217
218#### `resolve`
219
220``` purescript
221resolve :: String -> String
222```
223
224
225
226
diff --git a/bower.json b/bower.json
new file mode 100644
index 0000000..dddddf9
--- /dev/null
+++ b/bower.json
@@ -0,0 +1,16 @@
1{
2 "name": "purs-loader",
3 "private": true,
4 "devDependencies": {
5 "purescript-aff": "~0.9.1",
6 "purescript-exceptions": "~0.2.3",
7 "purescript-strings": "~0.4.5",
8 "purescript-maybe": "~0.2.2",
9 "purescript-foreign": "~0.4.2",
10 "purescript-foldable-traversable": "~0.3.1",
11 "purescript-tuples": "~0.3.4",
12 "purescript-maps": "~0.3.3",
13 "purescript-arrays": "~0.3.7",
14 "purescript-monad-eff": "~0.1.0"
15 }
16}
diff --git a/entry.js b/entry.js
new file mode 100644
index 0000000..87f52d3
--- /dev/null
+++ b/entry.js
@@ -0,0 +1,11 @@
1'use strict';
2
3var pursLoader = require('PursLoader.Loader');
4
5function loader(source) {
6 var ref = this;
7 var result = pursLoader.loaderFn(ref, source);
8 return result();
9}
10
11module.exports = loader;
diff --git a/gulpfile.js b/gulpfile.js
new file mode 100644
index 0000000..e217480
--- /dev/null
+++ b/gulpfile.js
@@ -0,0 +1,68 @@
1'use strict';
2
3var path = require('path');
4
5var gulp = require('gulp');
6
7var gutil = require('gulp-util');
8
9var plumber = require('gulp-plumber');
10
11var purescript = require('gulp-purescript');
12
13var sequence = require('run-sequence');
14
15var del = require('del');
16
17var config = { del: ['build', 'index.js']
18 , purescript: { src: [ 'bower_components/purescript-*/src/**/*.purs*'
19 , 'src/**/*.purs'
20 ]
21 , dest: 'build'
22 , docs: 'MODULE.md'
23 }
24 }
25 ;
26
27function error(e) {
28 gutil.log(gutil.colors.magenta('>>>> Error <<<<') + '\n' + e.toString().trim());
29 this.emit('end');
30}
31
32gulp.task('del', function(cb){
33 del(config.del, cb);
34});
35
36gulp.task('make', function(){
37 return gulp.src(config.purescript.src).
38 pipe(plumber()).
39 pipe(purescript.pscMake({output: config.purescript.dest})).
40 on('error', error);
41});
42
43gulp.task('psci', function(){
44 return gulp.src(config.purescript.src).
45 pipe(plumber()).
46 pipe(purescript.dotPsci()).
47 on('error', error);
48});
49
50gulp.task('docs', function(){
51 return gulp.src(config.purescript.src[1]).
52 pipe(plumber()).
53 pipe(purescript.pscDocs()).
54 on('error', error).
55 pipe(gulp.dest(config.purescript.docs));
56});
57
58gulp.task('watch', function(){
59 gulp.watch(config.purescript.src, ['make']);
60});
61
62gulp.task('default', function(callback){
63 sequence('del', 'make', ['psci', 'docs'], callback);
64});
65
66gulp.task('build', function(callback){
67 sequence('del', 'make', callback);
68});
diff --git a/index.js b/index.js
deleted file mode 100644
index 449c841..0000000
--- a/index.js
+++ /dev/null
@@ -1,164 +0,0 @@
1'use strict';
2
3var os = require('os');
4
5var cp = require('child_process');
6
7var path = require('path')
8
9var fs = require('fs');
10
11var glob = require('glob');
12
13var lodash = require('lodash');
14
15var chalk = require('chalk');
16
17var lu = require('loader-utils');
18
19var cwd = process.cwd();
20
21var MODULE_RE = /(?:^|\n)module\s+([\w\.]+)/i;
22
23var IMPORT_RE = /^\s*import\s+(?:qualified\s+)?([\w\.]+)/i;
24
25var BOWER_PATTERN = path.join('bower_components', 'purescript-*', 'src');
26
27var PSC_MAKE = 'psc-make';
28
29var OUTPUT = 'output';
30
31var OPTIONS = {
32 'no-prelude': '--no-prelude',
33 'no-opts': '--no-opts',
34 'no-magic-do': '--no-magic-do',
35 'no-tco': '--no-tco',
36 'verbose-errors': '--verbose-errors',
37 'output': '--output'
38};
39
40function pattern(root) {
41 var as = [ BOWER_PATTERN, root ];
42 return path.join('{' + as.join(',') + '}', '**', '*.purs');
43}
44
45function mkOptions(query) {
46 return lodash.foldl(lodash.keys(query), function(acc, k){
47 var h = function(v){return acc.concat(query[k] && OPTIONS[k] ? [v] : []);}
48 if (k === OUTPUT) return h(OPTIONS[k] + '=' + query[k]);
49 else return h(OPTIONS[k]);
50 }, []);
51}
52
53function mkGraph(files) {
54 var graph = {};
55
56 files.forEach(function(file){
57 var source = fs.readFileSync(file, {encoding: 'utf-8'});
58
59 var result = MODULE_RE.exec(source);
60
61 var module = result ? result[1] : null;
62
63 var imports =
64 lodash.foldl(source.split(os.EOL), function(b, a){
65 var result = IMPORT_RE.exec(a);
66 if (result) b.push(result[1]);
67 return b;
68 }, [])
69 ;
70
71 if (module) {
72 graph[module] = {
73 file: file,
74 imports: imports || []
75 };
76 }
77 });
78
79 return graph;
80}
81
82function findDeps(graph, module) {
83 function go(acc, module){
84 var node = graph[module];
85
86 var imports = node && node.imports;
87
88 if (lodash.isEmpty(imports)) return acc;
89 else {
90 var deps =
91 lodash.map(imports, function(i){
92 return go(acc.concat(imports), i);
93 })
94 ;
95 return lodash.flatten(deps);
96 }
97 }
98
99 return lodash.unique(go([], module));
100}
101
102function loader(source) {
103 this.cacheable && this.cacheable();
104
105 this.clearDependencies();
106
107 this.addDependency(this.resourcePath);
108
109 var callback = this.async();
110
111 var request = lu.getRemainingRequest(this)
112
113 var root = path.dirname(path.relative(cwd, request));
114
115 var query = lu.parseQuery(this.query);
116
117 var opts = mkOptions(query);
118
119 var that = this;
120
121 glob(pattern(root), function(e, files){
122 if (e !== null) callback(e);
123 else {
124 var cmd = cp.spawn(PSC_MAKE, opts.concat(files));
125
126 var graph = mkGraph(files);
127
128 cmd.on('close', function(e){
129 if (e) callback(e);
130 else {
131 var result = MODULE_RE.exec(source);
132
133 var module = result ? result[1] : '';
134
135 var dependencies = findDeps(graph, module);
136
137 var indexPath = path.join(query[OUTPUT] || OUTPUT, module, 'index.js');
138
139 fs.readFile(indexPath, 'utf-8', function(e, output){
140 if (e) callback(e);
141 else {
142 dependencies.forEach(function(dep){
143 var module = graph[dep];
144 if (module) that.addDependency(path.resolve(module.file));
145 });
146
147 callback(null, output);
148 }
149 });
150 }
151 });
152
153 cmd.stdout.on('data', function(stdout){
154 console.log('Stdout from \'' + chalk.cyan(PSC_MAKE) + '\'\n' + chalk.magenta(stdout));
155 });
156
157 cmd.stderr.on('data', function(stderr){
158 console.log('Stderr from \'' + chalk.cyan(PSC_MAKE) + '\'\n' + chalk.magenta(stderr));
159 });
160 }
161 });
162}
163
164module.exports = loader;
diff --git a/package.json b/package.json
index 4d458b8..56c6b39 100644
--- a/package.json
+++ b/package.json
@@ -2,24 +2,32 @@
2 "name": "purs-loader", 2 "name": "purs-loader",
3 "version": "0.0.3", 3 "version": "0.0.3",
4 "description": "PureScript loader for webpack", 4 "description": "PureScript loader for webpack",
5 "main": "index.js", 5 "license": "MIT",
6 "scripts": { 6 "repository": "ethul/purs-loader",
7 "test": "echo \"Error: no test specified\" && exit 1" 7 "author": {
8 "name": "Eric Thul",
9 "email": "thul.eric@gmail.com"
8 }, 10 },
9 "repository": { 11 "scripts": {
10 "type": "git", 12 "build": "npm run-script build:compile && npm run-script build:package",
11 "url": "git@github.com:ethul/purs-loader.git" 13 "build:compile": "gulp build",
14 "build:package": "./node_modules/.bin/webpack --progress --colors --profile --bail",
15 "build:json": "./node_modules/.bin/webpack --progress --colors --profile --bail --json > index.json"
12 }, 16 },
13 "author": "Eric Thul", 17 "files": [
14 "license": "MIT", 18 "index.js"
15 "bugs": { 19 ],
16 "url": "https://github.com/ethul/purs-loader/issues" 20 "devDependencies": {
21 "del": "^1.1.1",
22 "gulp": "^3.8.11",
23 "gulp-plumber": "^1.0.0",
24 "gulp-purescript": "^0.3.1",
25 "gulp-util": "^3.0.4",
26 "run-sequence": "^1.0.2",
27 "webpack": "^1.8.4"
17 }, 28 },
18 "homepage": "https://github.com/ethul/purs-loader",
19 "dependencies": { 29 "dependencies": {
20 "chalk": "^0.5.1", 30 "glob": "^5.0.3",
21 "glob": "4.0.6", 31 "loader-utils": "^0.2.6"
22 "loader-utils": "^0.2.3",
23 "lodash": "^2.4.1"
24 } 32 }
25} 33}
diff --git a/src/ChildProcess.purs b/src/ChildProcess.purs
new file mode 100644
index 0000000..c9ff23b
--- /dev/null
+++ b/src/ChildProcess.purs
@@ -0,0 +1,40 @@
1module PursLoader.ChildProcess
2 ( ChildProcess()
3 , spawn
4 ) where
5
6import Control.Monad.Aff (Aff(), makeAff)
7import Control.Monad.Eff (Eff())
8import Control.Monad.Eff.Exception (Error())
9
10import Data.Function
11
12foreign import data ChildProcess :: !
13
14spawn :: forall eff. String -> [String] -> Aff (cp :: ChildProcess | eff) String
15spawn command args = makeAff $ runFn4 spawnFn command args
16
17foreign import spawnFn """
18function spawnFn(command, args, errback, callback) {
19 return function(){
20 var child_process = require('child_process');
21
22 var process = child_process.spawn(command, args);
23
24 var stdout = new Buffer(0);
25
26 process.stdout.on('data', function(data){
27 stdout = Buffer.concat([stdout, new Buffer(data)]);
28 });
29
30 process.on('close', function(code){
31 if (code !== 0) errback(new Error(stdout.toString()))();
32 else callback(stdout.toString())();
33 });
34 };
35}
36""" :: forall eff. Fn4 String
37 [String]
38 (Error -> Eff (cp :: ChildProcess | eff) Unit)
39 (String -> Eff (cp :: ChildProcess | eff) Unit)
40 (Eff (cp :: ChildProcess | eff) Unit)
diff --git a/src/FS.purs b/src/FS.purs
new file mode 100644
index 0000000..68fe2f9
--- /dev/null
+++ b/src/FS.purs
@@ -0,0 +1,45 @@
1module PursLoader.FS
2 ( FS()
3 , readFileUtf8
4 , readFileUtf8Sync
5 ) where
6
7import Control.Monad.Aff (Aff(), makeAff)
8import Control.Monad.Eff (Eff())
9import Control.Monad.Eff.Exception (Error())
10
11import Data.Function
12
13foreign import data FS :: !
14
15readFileUtf8 :: forall eff. String -> Aff (fs :: FS | eff) String
16readFileUtf8 filepath = makeAff $ runFn3 readFileUtf8Fn filepath
17
18readFileUtf8Sync :: forall eff. String -> Eff (fs :: FS | eff) String
19readFileUtf8Sync filepath = readFileUtf8SyncFn filepath
20
21foreign import readFileUtf8Fn """
22function readFileUtf8Fn(filepath, errback, callback) {
23 return function(){
24 var fs = require('fs');
25
26 fs.readFile(filepath, 'utf-8', function(e, data){
27 if (e) errback(e)();
28 else callback(data)();
29 });
30 };
31}
32""" :: forall eff. Fn3 String
33 (Error -> Eff (fs :: FS | eff) Unit)
34 (String -> Eff (fs :: FS | eff) Unit)
35 (Eff (fs :: FS | eff) Unit)
36
37foreign import readFileUtf8SyncFn """
38function readFileUtf8SyncFn(filepath) {
39 return function(){
40 var fs = require('fs');
41
42 return fs.readFileSync(filepath, {encoding: 'utf-8'});
43 };
44}
45""" :: forall eff. String -> (Eff (fs :: FS | eff) String)
diff --git a/src/Glob.purs b/src/Glob.purs
new file mode 100644
index 0000000..7bc9212
--- /dev/null
+++ b/src/Glob.purs
@@ -0,0 +1,31 @@
1module PursLoader.Glob
2 ( Glob()
3 , glob
4 ) where
5
6import Control.Monad.Aff (Aff(), makeAff)
7import Control.Monad.Eff (Eff())
8import Control.Monad.Eff.Exception (Error())
9
10import Data.Function
11
12foreign import data Glob :: !
13
14glob :: forall eff. String -> Aff (glob :: Glob | eff) [String]
15glob pattern = makeAff $ runFn3 globFn pattern
16
17foreign import globFn """
18function globFn(pattern, errback, callback) {
19 return function(){
20 var glob = require('glob');
21
22 glob(pattern, function(e, data){
23 if (e) errback(e)();
24 else callback(data)();
25 });
26 };
27}
28""" :: forall eff. Fn3 String
29 (Error -> Eff (glob :: Glob | eff) Unit)
30 ([String] -> Eff (glob :: Glob | eff) Unit)
31 (Eff (glob :: Glob | eff) Unit)
diff --git a/src/Loader.purs b/src/Loader.purs
new file mode 100644
index 0000000..523aa7a
--- /dev/null
+++ b/src/Loader.purs
@@ -0,0 +1,114 @@
1module PursLoader.Loader
2 ( LoaderEff()
3 , loader
4 , loaderFn
5 ) where
6
7import Control.Monad.Aff (Aff(), runAff)
8import Control.Monad.Eff (Eff())
9import Control.Monad.Eff.Class (liftEff)
10import Control.Monad.Eff.Exception (error)
11
12import Data.Array ((!!), catMaybes, concat, nub, null)
13import Data.Function (Fn2(), mkFn2)
14import Data.Maybe (Maybe(..), fromMaybe, maybe)
15import Data.String (joinWith, split)
16import Data.String.Regex (Regex(), match, noFlags, regex)
17import Data.StrMap (StrMap(), fromList, lookup)
18import Data.Traversable (sequence)
19import Data.Tuple.Nested (tuple2)
20
21import PursLoader.ChildProcess (ChildProcess(), spawn)
22import PursLoader.FS (FS(), readFileUtf8, readFileUtf8Sync)
23import PursLoader.Glob (Glob(), glob)
24import PursLoader.LoaderRef (LoaderRef(), Loader(), async, cacheable, clearDependencies, addDependency, query, resourcePath)
25import PursLoader.LoaderUtil (getRemainingRequest, parseQuery)
26import PursLoader.OS (eol)
27import PursLoader.Options (pscMakeOptions, pscMakeDefaultOutput, pscMakeOutputOption)
28import PursLoader.Path (dirname, join, relative, resolve)
29
30foreign import cwd "var cwd = process.cwd();" :: String
31
32moduleRegex = regex "(?:^|\\n)module\\s+([\\w\\.]+)" noFlags { ignoreCase = true }
33
34importRegex = regex "^\\s*import\\s+(?:qualified\\s+)?([\\w\\.]+)" noFlags { ignoreCase = true }
35
36bowerPattern = join [ "bower_components", "purescript-*", "src" ]
37
38pscMakeCommand = "psc-make"
39
40indexFilename = "index.js"
41
42(!!!) = flip (!!)
43
44pursPattern :: String -> String
45pursPattern root = join [ "{" ++ joinWith "," [ bowerPattern, root ] ++ "}"
46 , "**"
47 , "*.purs"
48 ]
49
50type GraphModule = { file :: String, imports :: [String] }
51
52type Graph = StrMap GraphModule
53
54mkGraph :: forall eff. [String] -> Eff (fs :: FS | eff) Graph
55mkGraph files = (fromList <<< catMaybes) <$> sequence (parse <$> files)
56 where parse file = do source <- readFileUtf8Sync file
57 let key = match moduleRegex source >>= (!!!) 1
58 lines = split eol source
59 imports = catMaybes $ (\a -> match importRegex a >>= (!!!) 1) <$> lines
60 return $ (\a -> tuple2 a { file: file, imports: imports }) <$> key
61
62mkDeps :: forall eff. String -> Graph -> [String]
63mkDeps key graph = nub $ go [] key
64 where go acc key =
65 maybe acc (\a -> if null a.imports
66 then acc
67 else concat $ go (acc <> a.imports) <$> a.imports) (lookup key graph)
68
69addDeps :: forall eff. LoaderRef -> Graph -> [String] -> Eff (loader :: Loader | eff) Unit
70addDeps ref graph deps = const unit <$> (sequence $ add <$> deps)
71 where add dep = let res = lookup dep graph
72 path = (\a -> resolve a.file) <$> res
73 in maybe (pure unit) (addDependency ref) path
74
75type LoaderAff eff a = Aff (loader :: Loader, glob :: Glob, cp :: ChildProcess, fs :: FS | eff) a
76
77loader' :: forall eff. LoaderRef -> String -> LoaderAff eff (Maybe String)
78loader' ref source = do
79 liftEff $ cacheable ref
80
81 let request = getRemainingRequest ref
82 root = dirname $ relative cwd request
83 parsed = parseQuery $ query ref
84 opts = pscMakeOptions parsed
85 pattern = pursPattern root
86 key = match moduleRegex source >>= (!!!) 1
87
88 files <- glob pattern
89 graph <- liftEff $ mkGraph files
90
91 let deps = fromMaybe [] $ flip mkDeps graph <$> key
92 outputPath = fromMaybe pscMakeDefaultOutput $ pscMakeOutputOption parsed
93 indexPath = (\a -> join [ outputPath, a, indexFilename ]) <$> key
94
95 liftEff $ clearDependencies ref
96 liftEff $ addDependency ref (resourcePath ref)
97 liftEff $ addDeps ref graph deps
98
99 spawn pscMakeCommand (opts <> files)
100 indexFile <- sequence $ readFileUtf8 <$> indexPath
101 return indexFile
102
103type LoaderEff eff a = Eff (loader :: Loader, glob :: Glob, cp :: ChildProcess, fs :: FS | eff) a
104
105loader :: forall eff. LoaderRef -> String -> LoaderEff eff Unit
106loader ref source = do
107 callback <- async ref
108 runAff (\e -> callback (Just e) "")
109 (maybe (callback (Just $ error "Loader has failed to run") "")
110 (callback Nothing))
111 (loader' ref source)
112
113loaderFn :: forall eff. Fn2 LoaderRef String (LoaderEff eff Unit)
114loaderFn = mkFn2 loader
diff --git a/src/LoaderRef.purs b/src/LoaderRef.purs
new file mode 100644
index 0000000..2d62754
--- /dev/null
+++ b/src/LoaderRef.purs
@@ -0,0 +1,75 @@
1module PursLoader.LoaderRef
2 ( LoaderRef()
3 , Loader()
4 , async
5 , cacheable
6 , clearDependencies
7 , resourcePath
8 , addDependency
9 , query
10 ) where
11
12import Control.Monad.Eff (Eff())
13import Control.Monad.Eff.Exception (Error())
14
15import Data.Foreign (Foreign())
16import Data.Function (Fn3(), runFn3)
17import Data.Maybe (Maybe(), fromMaybe, isJust)
18
19data LoaderRef
20
21foreign import data Loader :: !
22
23foreign import asyncFn """
24function asyncFn(isJust, fromMaybe, ref){
25 return function(){
26 var callback = ref.async();
27 return function(error){
28 return function(value){
29 return function(){
30 return isJust(error) ? callback(fromMaybe(new Error())(error))
31 : callback(null, value);
32 };
33 };
34 };
35 };
36}""" :: forall eff a. Fn3 (Maybe Error -> Boolean)
37 (Error -> Maybe Error -> Error)
38 LoaderRef
39 (Eff (loader :: Loader | eff) (Maybe Error -> a -> Eff (loader :: Loader | eff) Unit))
40
41async :: forall eff a. LoaderRef -> Eff (loader :: Loader | eff) (Maybe Error -> a -> Eff (loader :: Loader | eff) Unit)
42async ref = runFn3 asyncFn isJust fromMaybe ref
43
44foreign import cacheable """
45function cacheable(ref){
46 return function(){
47 return ref.cacheable && ref.cacheable();
48 };
49}""" :: forall eff. LoaderRef -> Eff (loader :: Loader | eff) Unit
50
51foreign import clearDependencies """
52function clearDependencies(ref){
53 return function(){
54 return ref.clearDependencies();
55 };
56}""" :: forall eff. LoaderRef -> Eff (loader :: Loader | eff) Unit
57
58foreign import resourcePath """
59function resourcePath(ref){
60 return ref.resourcePath;
61}""" :: LoaderRef -> String
62
63foreign import addDependency """
64function addDependency(ref){
65 return function(dep){
66 return function(){
67 return ref.addDependency(dep);
68 };
69 };
70}""" :: forall eff. LoaderRef -> String -> Eff (loader :: Loader | eff) Unit
71
72foreign import query """
73function query(ref){
74 return ref.query;
75}""" :: LoaderRef -> String
diff --git a/src/LoaderUtil.purs b/src/LoaderUtil.purs
new file mode 100644
index 0000000..f22be44
--- /dev/null
+++ b/src/LoaderUtil.purs
@@ -0,0 +1,20 @@
1module PursLoader.LoaderUtil
2 ( getRemainingRequest
3 , parseQuery
4 ) where
5
6import Data.Foreign (Foreign())
7
8import PursLoader.LoaderRef (LoaderRef())
9
10foreign import getRemainingRequest """
11function getRemainingRequest(ref){
12 var loaderUtils = require('loader-utils');
13 return loaderUtils.getRemainingRequest(ref);
14}""" :: LoaderRef -> String
15
16foreign import parseQuery """
17function parseQuery(query){
18 var loaderUtils = require('loader-utils');
19 return loaderUtils.parseQuery(query);
20}""" :: String -> Foreign
diff --git a/src/OS.purs b/src/OS.purs
new file mode 100644
index 0000000..590c3d6
--- /dev/null
+++ b/src/OS.purs
@@ -0,0 +1,3 @@
1module PursLoader.OS (eol) where
2
3foreign import eol "var eol = require('os').EOL;" :: String
diff --git a/src/Options.purs b/src/Options.purs
new file mode 100644
index 0000000..b96cddc
--- /dev/null
+++ b/src/Options.purs
@@ -0,0 +1,72 @@
1module PursLoader.Options
2 ( pscMakeOptions
3 , pscMakeDefaultOutput
4 , pscMakeOutputOption
5 ) where
6
7import Data.Either (either)
8
9import Data.Foreign (Foreign(), F())
10import Data.Foreign.Class (IsForeign, read, readProp)
11import Data.Foreign.NullOrUndefined (NullOrUndefined(), runNullOrUndefined)
12
13import Data.Maybe (Maybe(..), maybe)
14
15noPreludeOpt = "no-prelude"
16
17noOptsOpt = "no-opts"
18
19noMagicDoOpt = "no-magic-do"
20
21noTcoOpt = "no-tco"
22
23verboseErrorsOpt = "verbose-errors"
24
25outputOpt = "output"
26
27pscMakeDefaultOutput = "output"
28
29newtype Options
30 = Options { noPrelude :: NullOrUndefined Boolean
31 , noOpts :: NullOrUndefined Boolean
32 , noMagicDo :: NullOrUndefined Boolean
33 , noTco :: NullOrUndefined Boolean
34 , verboseErrors :: NullOrUndefined Boolean
35 , output :: NullOrUndefined String
36 }
37
38instance isForeignOptions :: IsForeign Options where
39 read obj = (\a b c d e f ->
40 Options { noPrelude: a
41 , noOpts: b
42 , noMagicDo: c
43 , noTco: d
44 , verboseErrors: e
45 , output: f
46 }) <$> readProp noPreludeOpt obj
47 <*> readProp noOptsOpt obj
48 <*> readProp noMagicDoOpt obj
49 <*> readProp noTcoOpt obj
50 <*> readProp verboseErrorsOpt obj
51 <*> readProp outputOpt obj
52
53booleanOpt :: String -> NullOrUndefined Boolean -> [String]
54booleanOpt key opt = maybe [] (\a -> if a then ["--" ++ key] else []) (runNullOrUndefined opt)
55
56stringOpt :: String -> NullOrUndefined String -> [String]
57stringOpt key opt = maybe [] (\a -> ["--" ++ key ++ "=" ++ a]) (runNullOrUndefined opt)
58
59pscMakeOutputOption :: Foreign -> Maybe String
60pscMakeOutputOption query = either (const Nothing)
61 (\(Options a) -> runNullOrUndefined a.output)
62 (read query)
63
64pscMakeOptions :: Foreign -> [String]
65pscMakeOptions query = either (const []) fold parsed
66 where parsed = read query :: F Options
67 fold (Options a) = booleanOpt noPreludeOpt a.noPrelude <>
68 booleanOpt noOptsOpt a.noOpts <>
69 booleanOpt noMagicDoOpt a.noMagicDo <>
70 booleanOpt noTcoOpt a.noTco <>
71 booleanOpt verboseErrorsOpt a.verboseErrors <>
72 stringOpt outputOpt a.output
diff --git a/src/Path.purs b/src/Path.purs
new file mode 100644
index 0000000..e071e35
--- /dev/null
+++ b/src/Path.purs
@@ -0,0 +1,36 @@
1module PursLoader.Path
2 ( dirname
3 , join
4 , relative
5 , resolve
6 ) where
7
8foreign import dirname """
9function dirname(filepath) {
10 var path = require('path');
11 return path.dirname(filepath);
12}
13""" :: String -> String
14
15foreign import join """
16function join(parts) {
17 var path = require('path');
18 return path.join.apply(path, parts);
19}
20""" :: [String] -> String
21
22foreign import relative """
23function relative(from) {
24 return function(to){
25 var path = require('path');
26 return path.relative(from, to);
27 };
28}
29""" :: String -> String -> String
30
31foreign import resolve """
32function resolve(filepath) {
33 var path = require('path');
34 return path.resolve(filepath);
35}
36""" :: String -> String
diff --git a/webpack.config.js b/webpack.config.js
new file mode 100644
index 0000000..11b9069
--- /dev/null
+++ b/webpack.config.js
@@ -0,0 +1,29 @@
1'use strict';
2
3var path = require('path');
4
5var webpack = require('webpack');
6
7var noErrorsPlugin = webpack.NoErrorsPlugin;
8
9var dedupePlugin = webpack.optimize.DedupePlugin;
10
11var config
12 = { cache: true
13 , target: 'node'
14 , entry: { index: './entry' }
15 , externals: { 'glob': 'commonjs glob'
16 , 'loader-utils': 'commonjs loader-utils'
17 }
18 , output: { path: __dirname
19 , filename: '[name].js'
20 , libraryTarget: 'commonjs2'
21 }
22 , plugins: [ new noErrorsPlugin()
23 , new dedupePlugin()
24 ]
25 , resolve: { modulesDirectories: [ 'build' ] }
26 }
27 ;
28
29module.exports = config;