aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--README.md5
-rw-r--r--src/Psc.js108
-rw-r--r--src/bundle.js59
-rw-r--r--src/compile.js58
-rw-r--r--src/ide.js (renamed from src/PscIde.js)42
-rw-r--r--src/index.js48
-rw-r--r--src/purs-module-map.js (renamed from src/PsModuleMap.js)26
7 files changed, 187 insertions, 159 deletions
diff --git a/README.md b/README.md
index c15f03c..d82893d 100644
--- a/README.md
+++ b/README.md
@@ -11,9 +11,12 @@
11Install with [npm](https://npmjs.org/package/purs-loader). 11Install with [npm](https://npmjs.org/package/purs-loader).
12 12
13``` 13```
14// For PureScript 0.9 and newer 14// For PureScript 0.11 and newer
15npm install purs-loader --save-dev 15npm install purs-loader --save-dev
16 16
17// For PureScript 0.9 and 0.10
18npm install purs-loader@purescript-0.9 --save-dev
19
17// For PureScript 0.8 20// For PureScript 0.8
18npm install purs-loader@purescript-0.8 --save-dev 21npm install purs-loader@purescript-0.8 --save-dev
19``` 22```
diff --git a/src/Psc.js b/src/Psc.js
deleted file mode 100644
index ffa32b7..0000000
--- a/src/Psc.js
+++ /dev/null
@@ -1,108 +0,0 @@
1'use strict';
2
3const path = require('path');
4
5const Promise = require('bluebird')
6
7const fs = Promise.promisifyAll(require('fs'))
8
9const spawn = require('cross-spawn')
10
11const debug = require('debug')('purs-loader');
12
13const dargs = require('./dargs');
14
15function compile(psModule) {
16 const options = psModule.options
17 const cache = psModule.cache
18 const stderr = []
19
20 if (cache.compilationStarted) return Promise.resolve(psModule)
21
22 cache.compilationStarted = true
23
24 const args = dargs(Object.assign({
25 _: options.src,
26 output: options.output,
27 }, options.pscArgs))
28
29 debug('spawning compiler %s %o', options.psc, args)
30
31 return (new Promise((resolve, reject) => {
32 debug('compiling PureScript...')
33
34 const compilation = spawn(options.psc, args)
35
36 compilation.stderr.on('data', data => {
37 stderr.push(data.toString());
38 });
39
40 compilation.on('close', code => {
41 debug('finished compiling PureScript.')
42 cache.compilationFinished = true
43 if (code !== 0) {
44 const errorMessage = stderr.join('');
45 if (errorMessage.length) {
46 psModule.emitError(errorMessage);
47 }
48 if (options.watch) {
49 resolve(psModule);
50 }
51 else {
52 reject(new Error('compilation failed'))
53 }
54 } else {
55 const warningMessage = stderr.join('');
56 if (options.warnings && warningMessage.length) {
57 psModule.emitWarning(warningMessage);
58 }
59 resolve(psModule)
60 }
61 })
62 }))
63 .then(compilerOutput => {
64 if (options.bundle) {
65 return bundle(options, cache).then(() => psModule)
66 }
67 return psModule
68 })
69}
70module.exports.compile = compile;
71
72function bundle(options, cache) {
73 if (cache.bundle) return Promise.resolve(cache.bundle)
74
75 const stdout = []
76 const stderr = cache.bundle = []
77
78 const args = dargs(Object.assign({
79 _: [path.join(options.output, '*', '*.js')],
80 output: options.bundleOutput,
81 namespace: options.bundleNamespace,
82 }, options.pscBundleArgs))
83
84 cache.bundleModules.forEach(name => args.push('--module', name))
85
86 debug('spawning bundler %s %o', options.pscBundle, args.join(' '))
87
88 return (new Promise((resolve, reject) => {
89 debug('bundling PureScript...')
90
91 const compilation = spawn(options.pscBundle, args)
92
93 compilation.stdout.on('data', data => stdout.push(data.toString()))
94 compilation.stderr.on('data', data => stderr.push(data.toString()))
95 compilation.on('close', code => {
96 debug('finished bundling PureScript.')
97 if (code !== 0) {
98 const errorMessage = stderr.join('');
99 if (errorMessage.length) {
100 psModule.emitError(errorMessage);
101 }
102 return reject(new Error('bundling failed'))
103 }
104 cache.bundle = stderr
105 resolve(fs.appendFileAsync(options.bundleOutput, `module.exports = ${options.bundleNamespace}`))
106 })
107 }))
108}
diff --git a/src/bundle.js b/src/bundle.js
new file mode 100644
index 0000000..6627ffe
--- /dev/null
+++ b/src/bundle.js
@@ -0,0 +1,59 @@
1'use strict';
2
3const path = require('path');
4
5const Promise = require('bluebird')
6
7const fs = Promise.promisifyAll(require('fs'))
8
9const spawn = require('cross-spawn')
10
11const debug = require('debug')('purs-loader');
12
13const dargs = require('./dargs');
14
15module.exports = function bundle(options, cache) {
16 if (cache.bundle) return Promise.resolve(cache.bundle)
17
18 const stdout = []
19
20 const stderr = cache.bundle = []
21
22 const bundleCommand = options.pscBundle || 'purs';
23
24 const bundleArgs = (options.pscBundle ? [] : [ 'bundle' ]).concat(dargs(Object.assign({
25 _: [path.join(options.output, '*', '*.js')],
26 output: options.bundleOutput,
27 namespace: options.bundleNamespace,
28 }, options.pscBundleArgs)));
29
30 cache.bundleModules.forEach(name => bundleArgs.push('--module', name))
31
32 debug('spawning bundler %s %o', bundleCommand, bundleArgs);
33
34 return (new Promise((resolve, reject) => {
35 debug('bundling PureScript...')
36
37 const compilation = spawn(bundleCommand, bundleArgs)
38
39 compilation.stdout.on('data', data => stdout.push(data.toString()))
40
41 compilation.stderr.on('data', data => stderr.push(data.toString()))
42
43 compilation.on('close', code => {
44 debug('finished bundling PureScript.')
45
46 if (code !== 0) {
47 const errorMessage = stderr.join('');
48 if (errorMessage.length) {
49 psModule.emitError(errorMessage);
50 }
51 return reject(new Error('bundling failed'))
52 }
53
54 cache.bundle = stderr
55
56 resolve(fs.appendFileAsync(options.bundleOutput, `module.exports = ${options.bundleNamespace}`))
57 })
58 }))
59};
diff --git a/src/compile.js b/src/compile.js
new file mode 100644
index 0000000..8b5d87f
--- /dev/null
+++ b/src/compile.js
@@ -0,0 +1,58 @@
1'use strict';
2
3const Promise = require('bluebird');
4
5const spawn = require('cross-spawn');
6
7const debug = require('debug')('purs-loader');
8
9const dargs = require('./dargs');
10
11module.exports = function compile(psModule) {
12 const options = psModule.options
13
14 const cache = psModule.cache
15
16 const stderr = []
17
18 const compileCommand = options.psc || 'purs';
19
20 const compileArgs = (options.psc ? [] : [ 'compile' ]).concat(dargs(Object.assign({
21 _: options.src,
22 output: options.output,
23 }, options.pscArgs)))
24
25 debug('spawning compiler %s %o', compileCommand, compileArgs)
26
27 return new Promise((resolve, reject) => {
28 debug('compiling PureScript...')
29
30 const compilation = spawn(compileCommand, compileArgs)
31
32 compilation.stderr.on('data', data => {
33 stderr.push(data.toString());
34 });
35
36 compilation.on('close', code => {
37 debug('finished compiling PureScript.')
38 if (code !== 0) {
39 const errorMessage = stderr.join('');
40 if (errorMessage.length) {
41 psModule.emitError(errorMessage);
42 }
43 if (options.watch) {
44 resolve(psModule);
45 }
46 else {
47 reject(new Error('compilation failed'))
48 }
49 } else {
50 const warningMessage = stderr.join('');
51 if (options.warnings && warningMessage.length) {
52 psModule.emitWarning(warningMessage);
53 }
54 resolve(psModule)
55 }
56 })
57 });
58};
diff --git a/src/PscIde.js b/src/ide.js
index bf92b38..f839fd5 100644
--- a/src/PscIde.js
+++ b/src/ide.js
@@ -20,7 +20,7 @@ const Psc = require('./Psc');
20 20
21const PsModuleMap = require('./PsModuleMap'); 21const PsModuleMap = require('./PsModuleMap');
22 22
23function connect(psModule) { 23module.exports.connect = function connect(psModule) {
24 const options = psModule.options 24 const options = psModule.options
25 const cache = psModule.cache 25 const cache = psModule.cache
26 26
@@ -31,14 +31,14 @@ function connect(psModule) {
31 const connect_ = () => new Promise((resolve, reject) => { 31 const connect_ = () => new Promise((resolve, reject) => {
32 const args = dargs(options.pscIdeArgs) 32 const args = dargs(options.pscIdeArgs)
33 33
34 debug('attempting to connect to psc-ide-server', args) 34 debug('attempting to run purs ide client: %o', args)
35 35
36 const ideClient = spawn('psc-ide-client', args) 36 const ideClient = spawn('purs', ['ide', 'client'].concat(args))
37 37
38 ideClient.stderr.on('data', data => { 38 ideClient.stderr.on('data', data => {
39 debug(data.toString()) 39 debug(data.toString())
40 cache.ideServer = false 40 cache.ideServer = false
41 reject(new Error('psc-ide-client failed')) 41 reject(new Error('purs ide client failed'))
42 }) 42 })
43 ideClient.stdout.once('data', data => { 43 ideClient.stdout.once('data', data => {
44 debug(data.toString()) 44 debug(data.toString())
@@ -49,11 +49,11 @@ function connect(psModule) {
49 resolve(psModule) 49 resolve(psModule)
50 } else { 50 } else {
51 cache.ideServer = ideServer 51 cache.ideServer = ideServer
52 reject(new Error('psc-ide-client failed')) 52 reject(new Error('purs ide client failed'))
53 } 53 }
54 } else { 54 } else {
55 cache.ideServer = false 55 cache.ideServer = false
56 reject(new Error('psc-ide-client failed')) 56 reject(new Error('purs ide client failed'))
57 } 57 }
58 }) 58 })
59 ideClient.stdin.resume() 59 ideClient.stdin.resume()
@@ -66,24 +66,24 @@ function connect(psModule) {
66 '_': options.src 66 '_': options.src
67 }, options.pscIdeServerArgs)) 67 }, options.pscIdeServerArgs))
68 68
69 debug('attempting to start psc-ide-server', serverArgs) 69 debug('attempting to start purs ide server: %o', serverArgs)
70 70
71 const ideServer = cache.ideServer = spawn('psc-ide-server', serverArgs) 71 const ideServer = cache.ideServer = spawn('purs', ['ide', 'server'].concat(serverArgs))
72 72
73 ideServer.stdout.on('data', data => { 73 ideServer.stdout.on('data', data => {
74 debug('psc-ide-server stdout: %s', data.toString()); 74 debug('purs ide server stdout: %s', data.toString());
75 }); 75 });
76 76
77 ideServer.stderr.on('data', data => { 77 ideServer.stderr.on('data', data => {
78 debug('psc-ide-server stderr: %s', data.toString()); 78 debug('purs ide server stderr: %s', data.toString());
79 }); 79 });
80 80
81 ideServer.on('error', error => { 81 ideServer.on('error', error => {
82 debug('psc-ide-server error: %o', error); 82 debug('purs ide server error: %o', error);
83 }); 83 });
84 84
85 ideServer.on('close', (code, signal) => { 85 ideServer.on('close', (code, signal) => {
86 debug('psc-ide-server close: %s %s', code, signal); 86 debug('purs ide server close: %s %s', code, signal);
87 }); 87 });
88 88
89 return retryPromise((retry, number) => { 89 return retryPromise((retry, number) => {
@@ -91,7 +91,7 @@ function connect(psModule) {
91 if (!cache.ideServer && number === 9) { 91 if (!cache.ideServer && number === 9) {
92 debug(error) 92 debug(error)
93 93
94 console.warn('Failed to connect to or start psc-ide-server. A full compilation will occur on rebuild'); 94 console.warn('Failed to connect to or start purs ide server. A full compilation will occur on rebuild');
95 95
96 return Promise.resolve(psModule) 96 return Promise.resolve(psModule)
97 } 97 }
@@ -104,18 +104,17 @@ function connect(psModule) {
104 minTimeout: 333, 104 minTimeout: 333,
105 maxTimeout: 333, 105 maxTimeout: 333,
106 }) 106 })
107} 107};
108module.exports.connect = connect;
109 108
110function rebuild(psModule) { 109module.exports.rebuild = function rebuild(psModule) {
111 const options = psModule.options 110 const options = psModule.options
112 const cache = psModule.cache 111 const cache = psModule.cache
113 112
114 debug('attempting rebuild with psc-ide-client %s', psModule.srcPath) 113 debug('attempting rebuild with purs ide client %s', psModule.srcPath)
115 114
116 const request = (body) => new Promise((resolve, reject) => { 115 const request = (body) => new Promise((resolve, reject) => {
117 const args = dargs(options.pscIdeArgs) 116 const args = dargs(options.pscIdeArgs)
118 const ideClient = spawn('psc-ide-client', args) 117 const ideClient = spawn('purs', ['ide', 'client'].concat(args))
119 118
120 var stdout = '' 119 var stdout = ''
121 var stderr = '' 120 var stderr = ''
@@ -130,7 +129,7 @@ function rebuild(psModule) {
130 129
131 ideClient.on('close', code => { 130 ideClient.on('close', code => {
132 if (code !== 0) { 131 if (code !== 0) {
133 const error = stderr === '' ? 'Failed to spawn psc-ide-client' : stderr 132 const error = stderr === '' ? 'Failed to spawn purs ide client' : stderr
134 return reject(new Error(error)) 133 return reject(new Error(error))
135 } 134 }
136 135
@@ -187,7 +186,7 @@ function rebuild(psModule) {
187 }) 186 })
188 }) 187 })
189 188
190 debug('psc-ide-client stdin: %o', body); 189 debug('purs ide client stdin: %o', body);
191 190
192 ideClient.stdin.write(JSON.stringify(body)) 191 ideClient.stdin.write(JSON.stringify(body))
193 ideClient.stdin.write('\n') 192 ideClient.stdin.write('\n')
@@ -199,8 +198,7 @@ function rebuild(psModule) {
199 file: psModule.srcPath, 198 file: psModule.srcPath,
200 } 199 }
201 }) 200 })
202} 201};
203module.exports.rebuild = rebuild;
204 202
205function formatIdeResult(result, options, index, length) { 203function formatIdeResult(result, options, index, length) {
206 let numAndErr = `[${index+1}/${length} ${result.errorCode}]` 204 let numAndErr = `[${index+1}/${length} ${result.errorCode}]`
diff --git a/src/index.js b/src/index.js
index 047927c..799f8f9 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,15 +1,27 @@
1'use strict' 1'use strict'
2 2
3const debug = require('debug')('purs-loader') 3const debug = require('debug')('purs-loader')
4
4const loaderUtils = require('loader-utils') 5const loaderUtils = require('loader-utils')
6
5const Promise = require('bluebird') 7const Promise = require('bluebird')
8
6const path = require('path') 9const path = require('path')
7const PsModuleMap = require('./PsModuleMap'); 10
8const Psc = require('./Psc'); 11const PsModuleMap = require('./purs-module-map');
9const PscIde = require('./PscIde'); 12
13const compile = require('./compile');
14
15const bundle = require('./bundle');
16
17const ide = require('./ide');
18
10const toJavaScript = require('./to-javascript'); 19const toJavaScript = require('./to-javascript');
20
11const dargs = require('./dargs'); 21const dargs = require('./dargs');
22
12const spawn = require('cross-spawn').sync 23const spawn = require('cross-spawn').sync
24
13const eol = require('os').EOL 25const eol = require('os').EOL
14 26
15module.exports = function purescriptLoader(source, map) { 27module.exports = function purescriptLoader(source, map) {
@@ -34,9 +46,9 @@ module.exports = function purescriptLoader(source, map) {
34 const defaultDeps = depsPaths(options.pscPackage) 46 const defaultDeps = depsPaths(options.pscPackage)
35 const defaultOptions = { 47 const defaultOptions = {
36 context: config.context, 48 context: config.context,
37 psc: 'psc', 49 psc: null,
38 pscArgs: {}, 50 pscArgs: {},
39 pscBundle: 'psc-bundle', 51 pscBundle: null,
40 pscBundleArgs: {}, 52 pscBundleArgs: {},
41 pscIde: false, 53 pscIde: false,
42 pscIdeColors: options.psc === 'psa', 54 pscIdeColors: options.psc === 'psa',
@@ -102,7 +114,7 @@ module.exports = function purescriptLoader(source, map) {
102 }); 114 });
103 } 115 }
104 116
105 const psModuleName = PsModuleMap.match(source) 117 const psModuleName = PsModuleMap.matchModule(source)
106 const psModule = { 118 const psModule = {
107 name: psModuleName, 119 name: psModuleName,
108 load: js => callback(null, js), 120 load: js => callback(null, js),
@@ -131,8 +143,8 @@ module.exports = function purescriptLoader(source, map) {
131 } 143 }
132 144
133 if (cache.rebuild) { 145 if (cache.rebuild) {
134 return PscIde.connect(psModule) 146 return ide.connect(psModule)
135 .then(PscIde.rebuild) 147 .then(ide.rebuild)
136 .then(toJavaScript) 148 .then(toJavaScript)
137 .then(psModule.load) 149 .then(psModule.load)
138 .catch(psModule.reject) 150 .catch(psModule.reject)
@@ -147,11 +159,21 @@ module.exports = function purescriptLoader(source, map) {
147 cache.deferred.push(psModule) 159 cache.deferred.push(psModule)
148 160
149 if (!cache.compilationStarted) { 161 if (!cache.compilationStarted) {
150 return Psc.compile(psModule) 162 cache.compilationStarted = true;
151 .then(() => PsModuleMap.makeMap(options.src).then(map => { 163
152 debug('rebuilt module map after compile'); 164 return compile(psModule)
153 cache.psModuleMap = map; 165 .then(() => {
154 })) 166 cache.compilationFinished = true;
167
168 const bundlePromise = options.bundle ? bundle(options, cache) : Promise.resolve();
169
170 return bundlePromise.then(() =>
171 PsModuleMap.makeMap(options.src).then(map => {
172 debug('rebuilt module map after compile');
173 cache.psModuleMap = map;
174 })
175 );
176 })
155 .then(() => Promise.map(cache.deferred, psModule => { 177 .then(() => Promise.map(cache.deferred, psModule => {
156 if (typeof cache.ideServer === 'object') cache.ideServer.kill() 178 if (typeof cache.ideServer === 'object') cache.ideServer.kill()
157 return toJavaScript(psModule).then(psModule.load) 179 return toJavaScript(psModule).then(psModule.load)
diff --git a/src/PsModuleMap.js b/src/purs-module-map.js
index 0ae687c..b906d08 100644
--- a/src/PsModuleMap.js
+++ b/src/purs-module-map.js
@@ -14,19 +14,17 @@ const srcModuleRegex = /(?:^|\n)module\s+([\w\.]+)/i;
14 14
15const importModuleRegex = /(?:^|\n)\s*import\s+([\w\.]+)/ig; 15const importModuleRegex = /(?:^|\n)\s*import\s+([\w\.]+)/ig;
16 16
17function matchModule(str) { 17module.exports.matchModule = function matchModule(str) {
18 const matches = str.match(srcModuleRegex); 18 const matches = str.match(srcModuleRegex);
19 return matches && matches[1]; 19 return matches && matches[1];
20} 20};
21module.exports.match = matchModule;
22 21
23function matchImports(str) { 22module.exports.matchImports = function matchImports(str) {
24 const matches = str.match(importModuleRegex); 23 const matches = str.match(importModuleRegex);
25 return (matches || []).map(a => a.replace(/\n?\s*import\s+/i, '')); 24 return (matches || []).map(a => a.replace(/\n?\s*import\s+/i, ''));
26} 25};
27module.exports.matchImports = matchImports;
28 26
29function makeMapEntry(filePurs) { 27module.exports.makeMapEntry = function makeMapEntry(filePurs) {
30 const dirname = path.dirname(filePurs); 28 const dirname = path.dirname(filePurs);
31 29
32 const basename = path.basename(filePurs, '.purs'); 30 const basename = path.basename(filePurs, '.purs');
@@ -41,9 +39,9 @@ function makeMapEntry(filePurs) {
41 39
42 const sourceJs = fileMap.fileJs; 40 const sourceJs = fileMap.fileJs;
43 41
44 const moduleName = matchModule(sourcePurs); 42 const moduleName = module.exports.matchModule(sourcePurs);
45 43
46 const imports = matchImports(sourcePurs); 44 const imports = module.exports.matchImports(sourcePurs);
47 45
48 const map = {}; 46 const map = {};
49 47
@@ -61,18 +59,16 @@ function makeMapEntry(filePurs) {
61 }); 59 });
62 60
63 return result; 61 return result;
64} 62};
65module.exports.makeMapEntry = makeMapEntry;
66 63
67function makeMap(src) { 64module.exports.makeMap = function makeMap(src) {
68 debug('loading PureScript source and FFI files from %o', src); 65 debug('loading PureScript source and FFI files from %o', src);
69 66
70 const globs = [].concat(src); 67 const globs = [].concat(src);
71 68
72 return globby(globs).then(paths => 69 return globby(globs).then(paths =>
73 Promise.all(paths.map(makeMapEntry)).then(result => 70 Promise.all(paths.map(module.exports.makeMapEntry)).then(result =>
74 result.reduce(Object.assign, {}) 71 result.reduce(Object.assign, {})
75 ) 72 )
76 ); 73 );
77} 74};
78module.exports.makeMap = makeMap;