diff options
-rw-r--r-- | lib/bundle.js | 63 | ||||
-rw-r--r-- | lib/compile.js | 64 | ||||
-rw-r--r-- | lib/dargs.js | 7 | ||||
-rw-r--r-- | lib/ide.js | 270 | ||||
-rw-r--r-- | lib/index.js | 434 | ||||
-rw-r--r-- | lib/purs-module-map.js | 78 | ||||
-rw-r--r-- | lib/source-maps.js | 61 | ||||
-rw-r--r-- | lib/to-javascript.js | 152 | ||||
-rw-r--r-- | lib/utils.js | 64 |
9 files changed, 1193 insertions, 0 deletions
diff --git a/lib/bundle.js b/lib/bundle.js new file mode 100644 index 0000000..943e08b --- /dev/null +++ b/lib/bundle.js | |||
@@ -0,0 +1,63 @@ | |||
1 | 'use strict'; | ||
2 | |||
3 | var path = require('path'); | ||
4 | |||
5 | var Promise = require('bluebird'); | ||
6 | |||
7 | var fs = Promise.promisifyAll(require('fs')); | ||
8 | |||
9 | var spawn = require('cross-spawn'); | ||
10 | |||
11 | var debug = require('debug')('purs-loader'); | ||
12 | |||
13 | var dargs = require('./dargs'); | ||
14 | |||
15 | module.exports = function bundle(options, bundleModules) { | ||
16 | var stdout = []; | ||
17 | |||
18 | var stderr = []; | ||
19 | |||
20 | var bundleCommand = options.pscBundle || 'purs'; | ||
21 | |||
22 | var bundleArgs = (options.pscBundle ? [] : ['bundle']).concat(dargs(Object.assign({ | ||
23 | _: [path.join(options.output, '*', '*.js')], | ||
24 | output: options.bundleOutput, | ||
25 | namespace: options.bundleNamespace | ||
26 | }, options.pscBundleArgs))); | ||
27 | |||
28 | bundleModules.forEach(function (name) { | ||
29 | return bundleArgs.push('--module', name); | ||
30 | }); | ||
31 | |||
32 | debug('bundle: %s %O', bundleCommand, bundleArgs); | ||
33 | |||
34 | return new Promise(function (resolve, reject) { | ||
35 | debug('bundling PureScript...'); | ||
36 | |||
37 | var compilation = spawn(bundleCommand, bundleArgs); | ||
38 | |||
39 | compilation.stdout.on('data', function (data) { | ||
40 | return stdout.push(data.toString()); | ||
41 | }); | ||
42 | |||
43 | compilation.stderr.on('data', function (data) { | ||
44 | return stderr.push(data.toString()); | ||
45 | }); | ||
46 | |||
47 | compilation.on('close', function (code) { | ||
48 | debug('finished bundling PureScript.'); | ||
49 | |||
50 | if (code !== 0) { | ||
51 | var errorMessage = stderr.join(''); | ||
52 | |||
53 | if (errorMessage.length) { | ||
54 | psModule.emitError(errorMessage); | ||
55 | } | ||
56 | |||
57 | reject(new Error('bundling failed')); | ||
58 | } else { | ||
59 | resolve(fs.appendFileAsync(options.bundleOutput, 'module.exports = ' + options.bundleNamespace)); | ||
60 | } | ||
61 | }); | ||
62 | }); | ||
63 | }; \ No newline at end of file | ||
diff --git a/lib/compile.js b/lib/compile.js new file mode 100644 index 0000000..a1bf211 --- /dev/null +++ b/lib/compile.js | |||
@@ -0,0 +1,64 @@ | |||
1 | 'use strict'; | ||
2 | |||
3 | var Promise = require('bluebird'); | ||
4 | |||
5 | var spawn = require('cross-spawn'); | ||
6 | |||
7 | var debug_ = require('debug'); | ||
8 | |||
9 | var debug = debug_('purs-loader'); | ||
10 | |||
11 | var debugVerbose = debug_('purs-loader:verbose'); | ||
12 | |||
13 | var dargs = require('./dargs'); | ||
14 | |||
15 | module.exports = function compile(psModule) { | ||
16 | var options = psModule.options; | ||
17 | |||
18 | var compileCommand = options.psc || 'purs'; | ||
19 | |||
20 | var compileArgs = (options.psc ? [] : ['compile']).concat(dargs(Object.assign({ | ||
21 | _: options.src, | ||
22 | output: options.output | ||
23 | }, options.pscArgs))); | ||
24 | |||
25 | var stderr = []; | ||
26 | |||
27 | debug('compile %s %O', compileCommand, compileArgs); | ||
28 | |||
29 | return new Promise(function (resolve, reject) { | ||
30 | debug('compiling PureScript...'); | ||
31 | |||
32 | var compilation = spawn(compileCommand, compileArgs); | ||
33 | |||
34 | compilation.stderr.on('data', function (data) { | ||
35 | stderr.push(data.toString()); | ||
36 | }); | ||
37 | |||
38 | compilation.stdout.on('data', function (data) { | ||
39 | debugVerbose(data.toString()); | ||
40 | }); | ||
41 | |||
42 | compilation.on('close', function (code) { | ||
43 | debug('finished compiling PureScript.'); | ||
44 | |||
45 | if (code !== 0) { | ||
46 | var errorMessage = stderr.join(''); | ||
47 | if (errorMessage.length) { | ||
48 | psModule.emitError(errorMessage); | ||
49 | } | ||
50 | if (options.watch) { | ||
51 | resolve(psModule); | ||
52 | } else { | ||
53 | reject(new Error('compilation failed')); | ||
54 | } | ||
55 | } else { | ||
56 | var warningMessage = stderr.join(''); | ||
57 | if (options.warnings && warningMessage.length) { | ||
58 | psModule.emitWarning(warningMessage); | ||
59 | } | ||
60 | resolve(psModule); | ||
61 | } | ||
62 | }); | ||
63 | }); | ||
64 | }; \ No newline at end of file | ||
diff --git a/lib/dargs.js b/lib/dargs.js new file mode 100644 index 0000000..191ab44 --- /dev/null +++ b/lib/dargs.js | |||
@@ -0,0 +1,7 @@ | |||
1 | 'use strict'; | ||
2 | |||
3 | var dargs = require('dargs'); | ||
4 | |||
5 | module.exports = function (obj) { | ||
6 | return dargs(obj, { ignoreFalse: true }); | ||
7 | }; \ No newline at end of file | ||
diff --git a/lib/ide.js b/lib/ide.js new file mode 100644 index 0000000..6087e1c --- /dev/null +++ b/lib/ide.js | |||
@@ -0,0 +1,270 @@ | |||
1 | 'use strict'; | ||
2 | |||
3 | var path = require('path'); | ||
4 | |||
5 | var Promise = require('bluebird'); | ||
6 | |||
7 | var fs = Promise.promisifyAll(require('fs')); | ||
8 | |||
9 | var retryPromise = require('promise-retry'); | ||
10 | |||
11 | var spawn = require('cross-spawn'); | ||
12 | |||
13 | var colors = require('chalk'); | ||
14 | |||
15 | var debug_ = require('debug'); | ||
16 | |||
17 | var debug = debug_('purs-loader'); | ||
18 | |||
19 | var debugVerbose = debug_('purs-loader:verbose'); | ||
20 | |||
21 | var dargs = require('./dargs'); | ||
22 | |||
23 | var compile = require('./compile'); | ||
24 | |||
25 | var PsModuleMap = require('./purs-module-map'); | ||
26 | |||
27 | function UnknownModuleError() { | ||
28 | this.name = 'UnknownModuleError'; | ||
29 | this.stack = new Error().stack; | ||
30 | } | ||
31 | |||
32 | UnknownModuleError.prototype = Object.create(Error.prototype); | ||
33 | |||
34 | UnknownModuleError.prototype.constructor = UnknownModuleError; | ||
35 | |||
36 | module.exports.UnknownModuleError = UnknownModuleError; | ||
37 | |||
38 | function spawnIdeClient(body, options) { | ||
39 | var ideClientCommand = options.pscIdeClient || 'purs'; | ||
40 | |||
41 | var ideClientArgs = (options.pscIdeClient ? [] : ['ide', 'client']).concat(dargs(options.pscIdeClientArgs)); | ||
42 | |||
43 | var stderr = []; | ||
44 | |||
45 | var stdout = []; | ||
46 | |||
47 | debug('ide client %s %o %O', ideClientCommand, ideClientArgs, body); | ||
48 | |||
49 | return new Promise(function (resolve, reject) { | ||
50 | var ideClient = spawn(ideClientCommand, ideClientArgs); | ||
51 | |||
52 | ideClient.stderr.on('data', function (data) { | ||
53 | stderr.push(data.toString()); | ||
54 | }); | ||
55 | |||
56 | ideClient.stdout.on('data', function (data) { | ||
57 | stdout.push(data.toString()); | ||
58 | }); | ||
59 | |||
60 | ideClient.on('close', function (code) { | ||
61 | if (code !== 0) { | ||
62 | var errorMessage = stderr.join(''); | ||
63 | |||
64 | reject(new Error('ide client failed: ' + errorMessage)); | ||
65 | } else { | ||
66 | var result = stdout.join(''); | ||
67 | |||
68 | resolve(result); | ||
69 | } | ||
70 | }); | ||
71 | |||
72 | ideClient.stdin.resume(); | ||
73 | |||
74 | ideClient.stdin.write(JSON.stringify(body)); | ||
75 | |||
76 | ideClient.stdin.write('\n'); | ||
77 | }); | ||
78 | } | ||
79 | |||
80 | function formatIdeResult(result, options, index, length) { | ||
81 | var numAndErr = '[' + (index + 1) + '/' + length + ' ' + result.errorCode + ']'; | ||
82 | numAndErr = options.pscIdeColors ? colors.yellow(numAndErr) : numAndErr; | ||
83 | |||
84 | function makeResult() { | ||
85 | return Promise.resolve('\n' + numAndErr + ' ' + result.message); | ||
86 | } | ||
87 | |||
88 | function makeResultSnippet(filename, pos) { | ||
89 | var srcPath = path.relative(options.context, filename); | ||
90 | var fileAndPos = srcPath + ':' + pos.startLine + ':' + pos.startColumn; | ||
91 | |||
92 | return fs.readFileAsync(filename, 'utf8').then(function (source) { | ||
93 | var lines = source.split('\n').slice(pos.startLine - 1, pos.endLine); | ||
94 | var endsOnNewline = pos.endColumn === 1 && pos.startLine !== pos.endLine; | ||
95 | var up = options.pscIdeColors ? colors.red('^') : '^'; | ||
96 | var down = options.pscIdeColors ? colors.red('v') : 'v'; | ||
97 | var trimmed = lines.slice(0); | ||
98 | |||
99 | if (endsOnNewline) { | ||
100 | lines.splice(lines.length - 1, 1); | ||
101 | pos.endLine = pos.endLine - 1; | ||
102 | pos.endColumn = lines[lines.length - 1].length || 1; | ||
103 | } | ||
104 | |||
105 | // strip newlines at the end | ||
106 | if (endsOnNewline) { | ||
107 | trimmed = lines.reverse().reduce(function (trimmed, line, i) { | ||
108 | if (i === 0 && line === '') trimmed.trimming = true; | ||
109 | if (!trimmed.trimming) trimmed.push(line); | ||
110 | if (trimmed.trimming && line !== '') { | ||
111 | trimmed.trimming = false; | ||
112 | trimmed.push(line); | ||
113 | } | ||
114 | return trimmed; | ||
115 | }, []).reverse(); | ||
116 | pos.endLine = pos.endLine - (lines.length - trimmed.length); | ||
117 | pos.endColumn = trimmed[trimmed.length - 1].length || 1; | ||
118 | } | ||
119 | |||
120 | var spaces = ' '.repeat(String(pos.endLine).length); | ||
121 | var snippet = trimmed.map(function (line, i) { | ||
122 | return ' ' + (pos.startLine + i) + ' ' + line; | ||
123 | }).join('\n'); | ||
124 | |||
125 | if (trimmed.length === 1) { | ||
126 | snippet += '\n ' + spaces + ' ' + ' '.repeat(pos.startColumn - 1) + up.repeat(pos.endColumn - pos.startColumn + 1); | ||
127 | } else { | ||
128 | snippet = ' ' + spaces + ' ' + ' '.repeat(pos.startColumn - 1) + down + '\n' + snippet; | ||
129 | snippet += '\n ' + spaces + ' ' + ' '.repeat(pos.endColumn - 1) + up; | ||
130 | } | ||
131 | |||
132 | return Promise.resolve('\n' + numAndErr + ' ' + fileAndPos + '\n\n' + snippet + '\n\n' + result.message); | ||
133 | }).catch(function (error) { | ||
134 | debug('failed to format ide result: %o', error); | ||
135 | |||
136 | return Promise.resolve(''); | ||
137 | }); | ||
138 | } | ||
139 | |||
140 | return result.filename && result.position ? makeResultSnippet(result.filename, result.position) : makeResult(); | ||
141 | } | ||
142 | |||
143 | module.exports.connect = function connect(psModule) { | ||
144 | var options = psModule.options; | ||
145 | |||
146 | var serverCommand = options.pscIdeServer || 'purs'; | ||
147 | |||
148 | var serverArgs = (options.pscIdeServer ? [] : ['ide', 'server']).concat(dargs(Object.assign({ | ||
149 | outputDirectory: options.output, | ||
150 | '_': options.src | ||
151 | }, options.pscIdeServerArgs))); | ||
152 | |||
153 | debug('ide server: %s %o', serverCommand, serverArgs); | ||
154 | |||
155 | var ideServer = spawn(serverCommand, serverArgs); | ||
156 | |||
157 | ideServer.stdout.on('data', function (data) { | ||
158 | debugVerbose('ide server stdout: %s', data.toString()); | ||
159 | }); | ||
160 | |||
161 | ideServer.stderr.on('data', function (data) { | ||
162 | debugVerbose('ide server stderr: %s', data.toString()); | ||
163 | }); | ||
164 | |||
165 | ideServer.on('error', function (error) { | ||
166 | debugVerbose('ide server error: %o', error); | ||
167 | }); | ||
168 | |||
169 | ideServer.on('close', function (code, signal) { | ||
170 | debugVerbose('ide server close: %s %s', code, signal); | ||
171 | }); | ||
172 | |||
173 | return Promise.resolve(ideServer); | ||
174 | }; | ||
175 | |||
176 | module.exports.load = function load(psModule) { | ||
177 | var options = psModule.options; | ||
178 | |||
179 | var body = { command: 'load' }; | ||
180 | |||
181 | return spawnIdeClient(body, options); | ||
182 | }; | ||
183 | |||
184 | module.exports.loadWithRetry = function loadWithRetry(psModule) { | ||
185 | var retries = 9; | ||
186 | |||
187 | return retryPromise(function (retry, number) { | ||
188 | debugVerbose('attempting to load modules (%d out of %d attempts)', number, retries); | ||
189 | |||
190 | return module.exports.load(psModule).catch(retry); | ||
191 | }, { | ||
192 | retries: retries, | ||
193 | factor: 1, | ||
194 | minTimeout: 333, | ||
195 | maxTimeout: 333 | ||
196 | }).then(function () { | ||
197 | return psModule; | ||
198 | }); | ||
199 | }; | ||
200 | |||
201 | module.exports.rebuild = function rebuild(psModule) { | ||
202 | var options = psModule.options; | ||
203 | |||
204 | var body = { | ||
205 | command: 'rebuild', | ||
206 | params: { | ||
207 | file: psModule.srcPath | ||
208 | } | ||
209 | }; | ||
210 | |||
211 | var parseResponse = function parseResponse(response) { | ||
212 | try { | ||
213 | var parsed = JSON.parse(response); | ||
214 | |||
215 | debugVerbose('parsed JSON response: %O', parsed); | ||
216 | |||
217 | return Promise.resolve(parsed); | ||
218 | } catch (error) { | ||
219 | return Promise.reject(error); | ||
220 | } | ||
221 | }; | ||
222 | |||
223 | var formatResponse = function formatResponse(parsed) { | ||
224 | var result = Array.isArray(parsed.result) ? parsed.result : []; | ||
225 | |||
226 | return Promise.map(result, function (item, i) { | ||
227 | debugVerbose('formatting result %O', item); | ||
228 | |||
229 | return formatIdeResult(item, options, i, result.length); | ||
230 | }).then(function (formatted) { | ||
231 | return { | ||
232 | parsed: parsed, | ||
233 | formatted: formatted, | ||
234 | formattedMessage: formatted.join('\n') | ||
235 | }; | ||
236 | }); | ||
237 | }; | ||
238 | |||
239 | return spawnIdeClient(body, options).then(parseResponse).then(formatResponse).then(function (_ref) { | ||
240 | var parsed = _ref.parsed, | ||
241 | formatted = _ref.formatted, | ||
242 | formattedMessage = _ref.formattedMessage; | ||
243 | |||
244 | if (parsed.resultType === 'success') { | ||
245 | if (options.warnings && formattedMessage.length) { | ||
246 | psModule.emitWarning(formattedMessage); | ||
247 | } | ||
248 | |||
249 | return psModule; | ||
250 | } else if ((parsed.result || []).some(function (item) { | ||
251 | var isModuleNotFound = item.errorCode === 'ModuleNotFound'; | ||
252 | |||
253 | var isUnknownModule = item.errorCode === 'UnknownModule'; | ||
254 | |||
255 | var isUnknownModuleImport = item.errorCode === 'UnknownName' && /Unknown module/.test(item.message); | ||
256 | |||
257 | return isModuleNotFound || isUnknownModule || isUnknownModuleImport; | ||
258 | })) { | ||
259 | debug('module %s was not rebuilt because the module is unknown', psModule.name); | ||
260 | |||
261 | return Promise.reject(new UnknownModuleError()); | ||
262 | } else { | ||
263 | if (formattedMessage.length) { | ||
264 | psModule.emitError(formattedMessage); | ||
265 | } | ||
266 | |||
267 | return psModule; | ||
268 | } | ||
269 | }); | ||
270 | }; \ No newline at end of file | ||
diff --git a/lib/index.js b/lib/index.js new file mode 100644 index 0000000..e648869 --- /dev/null +++ b/lib/index.js | |||
@@ -0,0 +1,434 @@ | |||
1 | 'use strict'; | ||
2 | |||
3 | var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); | ||
4 | |||
5 | var debug_ = require('debug'); | ||
6 | |||
7 | var debug = debug_('purs-loader'); | ||
8 | |||
9 | var debugVerbose = debug_('purs-loader:verbose'); | ||
10 | |||
11 | var loaderUtils = require('loader-utils'); | ||
12 | |||
13 | var Promise = require('bluebird'); | ||
14 | |||
15 | var path = require('path'); | ||
16 | |||
17 | var PsModuleMap = require('./purs-module-map'); | ||
18 | |||
19 | var compile = require('./compile'); | ||
20 | |||
21 | var bundle = require('./bundle'); | ||
22 | |||
23 | var ide = require('./ide'); | ||
24 | |||
25 | var toJavaScript = require('./to-javascript'); | ||
26 | |||
27 | var sourceMaps = require('./source-maps'); | ||
28 | |||
29 | var dargs = require('./dargs'); | ||
30 | |||
31 | var utils = require('./utils'); | ||
32 | |||
33 | var spawn = require('cross-spawn').sync; | ||
34 | |||
35 | var eol = require('os').EOL; | ||
36 | |||
37 | var CACHE_VAR = { | ||
38 | rebuild: false, | ||
39 | deferred: [], | ||
40 | bundleModules: [], | ||
41 | ideServer: null, | ||
42 | psModuleMap: null, | ||
43 | warnings: [], | ||
44 | errors: [], | ||
45 | compilationStarted: false, | ||
46 | compilationFinished: false, | ||
47 | compilationFailed: false, | ||
48 | installed: false, | ||
49 | srcOption: [] | ||
50 | }; | ||
51 | |||
52 | module.exports = function purescriptLoader(source, map) { | ||
53 | var _this = this; | ||
54 | |||
55 | this.cacheable && this.cacheable(); | ||
56 | |||
57 | var webpackContext = this.options && this.options.context || this.rootContext; | ||
58 | |||
59 | var callback = this.async(); | ||
60 | |||
61 | var loaderOptions = loaderUtils.getOptions(this) || {}; | ||
62 | |||
63 | var srcOption = function (pscPackage) { | ||
64 | var srcPath = path.join('src', '**', '*.purs'); | ||
65 | |||
66 | var bowerPath = path.join('bower_components', 'purescript-*', 'src', '**', '*.purs'); | ||
67 | |||
68 | if (CACHE_VAR.srcOption.length > 0) { | ||
69 | return CACHE_VAR.srcOption; | ||
70 | } else if (pscPackage) { | ||
71 | var pscPackageCommand = 'psc-package'; | ||
72 | |||
73 | var pscPackageArgs = ['sources']; | ||
74 | |||
75 | var loaderSrc = loaderOptions.src || [srcPath]; | ||
76 | |||
77 | debug('psc-package %s %o', pscPackageCommand, pscPackageArgs); | ||
78 | |||
79 | var cmd = spawn(pscPackageCommand, pscPackageArgs); | ||
80 | |||
81 | if (cmd.error) { | ||
82 | throw new Error(cmd.error); | ||
83 | } else if (cmd.status !== 0) { | ||
84 | var error = cmd.stdout.toString(); | ||
85 | |||
86 | throw new Error(error); | ||
87 | } else { | ||
88 | var result = cmd.stdout.toString().split(eol).filter(function (v) { | ||
89 | return v != ''; | ||
90 | }).concat(loaderSrc); | ||
91 | |||
92 | debug('psc-package result: %o', result); | ||
93 | |||
94 | CACHE_VAR.srcOption = result; | ||
95 | |||
96 | return result; | ||
97 | } | ||
98 | } else { | ||
99 | var _result = loaderOptions.src || [bowerPath, srcPath]; | ||
100 | |||
101 | CACHE_VAR.srcOption = _result; | ||
102 | |||
103 | return _result; | ||
104 | } | ||
105 | }(loaderOptions.pscPackage); | ||
106 | |||
107 | var options = Object.assign({ | ||
108 | context: webpackContext, | ||
109 | psc: null, | ||
110 | pscArgs: {}, | ||
111 | pscBundle: null, | ||
112 | pscBundleArgs: {}, | ||
113 | pscIdeClient: null, | ||
114 | pscIdeClientArgs: {}, | ||
115 | pscIdeServer: null, | ||
116 | pscIdeServerArgs: {}, | ||
117 | pscIde: false, | ||
118 | pscIdeColors: loaderOptions.psc === 'psa', | ||
119 | pscPackage: false, | ||
120 | bundleOutput: 'output/bundle.js', | ||
121 | bundleNamespace: 'PS', | ||
122 | bundle: false, | ||
123 | warnings: true, | ||
124 | watch: false, | ||
125 | output: 'output', | ||
126 | src: [] | ||
127 | }, loaderOptions, { | ||
128 | src: srcOption | ||
129 | }); | ||
130 | |||
131 | if (!CACHE_VAR.installed) { | ||
132 | debugVerbose('installing purs-loader with options: %O', options); | ||
133 | |||
134 | CACHE_VAR.installed = true; | ||
135 | |||
136 | // invalidate loader CACHE_VAR when bundle is marked as invalid (in watch mode) | ||
137 | this._compiler.plugin('invalid', function () { | ||
138 | debugVerbose('invalidating loader CACHE_VAR'); | ||
139 | |||
140 | CACHE_VAR = { | ||
141 | rebuild: options.pscIde, | ||
142 | deferred: [], | ||
143 | bundleModules: [], | ||
144 | ideServer: CACHE_VAR.ideServer, | ||
145 | psModuleMap: CACHE_VAR.psModuleMap, | ||
146 | warnings: [], | ||
147 | errors: [], | ||
148 | compilationStarted: false, | ||
149 | compilationFinished: false, | ||
150 | compilationFailed: false, | ||
151 | installed: CACHE_VAR.installed, | ||
152 | srcOption: [] | ||
153 | }; | ||
154 | }); | ||
155 | |||
156 | // add psc warnings to webpack compilation warnings | ||
157 | this._compiler.plugin('after-compile', function (compilation, callback) { | ||
158 | CACHE_VAR.warnings.forEach(function (warning) { | ||
159 | compilation.warnings.push(warning); | ||
160 | }); | ||
161 | |||
162 | CACHE_VAR.errors.forEach(function (error) { | ||
163 | compilation.errors.push(error); | ||
164 | }); | ||
165 | |||
166 | callback(); | ||
167 | }); | ||
168 | } | ||
169 | |||
170 | var psModuleName = PsModuleMap.matchModule(source); | ||
171 | |||
172 | var psModule = { | ||
173 | name: psModuleName, | ||
174 | source: source, | ||
175 | load: function load(_ref) { | ||
176 | var js = _ref.js, | ||
177 | map = _ref.map; | ||
178 | return callback(null, js, map); | ||
179 | }, | ||
180 | reject: function reject(error) { | ||
181 | return callback(error); | ||
182 | }, | ||
183 | srcPath: this.resourcePath, | ||
184 | remainingRequest: loaderUtils.getRemainingRequest(this), | ||
185 | srcDir: path.dirname(this.resourcePath), | ||
186 | jsPath: path.resolve(path.join(options.output, psModuleName, 'index.js')), | ||
187 | options: options, | ||
188 | cache: CACHE_VAR, | ||
189 | emitWarning: function emitWarning(warning) { | ||
190 | if (options.warnings && warning.length) { | ||
191 | CACHE_VAR.warnings.push(warning); | ||
192 | } | ||
193 | }, | ||
194 | emitError: function emitError(pscMessage) { | ||
195 | if (pscMessage.length) { | ||
196 | var modules = []; | ||
197 | |||
198 | var matchErrorsSeparator = /\n(?=Error)/; | ||
199 | var errors = pscMessage.split(matchErrorsSeparator); | ||
200 | var _iteratorNormalCompletion = true; | ||
201 | var _didIteratorError = false; | ||
202 | var _iteratorError = undefined; | ||
203 | |||
204 | try { | ||
205 | for (var _iterator = errors[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { | ||
206 | var error = _step.value; | ||
207 | |||
208 | var matchErrLocation = /at (.+\.purs) line (\d+), column (\d+) - line (\d+), column (\d+)/; | ||
209 | |||
210 | var _ref2 = matchErrLocation.exec(error) || [], | ||
211 | _ref3 = _slicedToArray(_ref2, 2), | ||
212 | filename = _ref3[1]; | ||
213 | |||
214 | if (!filename) continue; | ||
215 | |||
216 | var baseModulePath = path.join(_this.rootContext, filename); | ||
217 | _this.addDependency(baseModulePath); | ||
218 | |||
219 | var matchErrModuleName = /in module ((?:\w+\.)*\w+)/; | ||
220 | |||
221 | var _ref4 = matchErrModuleName.exec(error) || [], | ||
222 | _ref5 = _slicedToArray(_ref4, 2), | ||
223 | baseModuleName = _ref5[1]; | ||
224 | |||
225 | if (!baseModuleName) continue; | ||
226 | |||
227 | var matchMissingModuleName = /Module ((?:\w+\.)*\w+) was not found/; | ||
228 | var matchMissingImportFromModuleName = /Cannot import value \w+ from module ((?:\w+\.)*\w+)/; | ||
229 | var _arr = [matchMissingModuleName, matchMissingImportFromModuleName]; | ||
230 | for (var _i = 0; _i < _arr.length; _i++) { | ||
231 | var re = _arr[_i]; | ||
232 | var _ref6 = re.exec(error) || [], | ||
233 | _ref7 = _slicedToArray(_ref6, 2), | ||
234 | targetModuleName = _ref7[1]; | ||
235 | |||
236 | if (targetModuleName) { | ||
237 | var resolved = utils.resolvePursModule({ | ||
238 | baseModulePath: baseModulePath, | ||
239 | baseModuleName: baseModuleName, | ||
240 | targetModuleName: targetModuleName | ||
241 | }); | ||
242 | _this.addDependency(resolved); | ||
243 | } | ||
244 | } | ||
245 | |||
246 | var desc = { | ||
247 | name: baseModuleName, | ||
248 | filename: baseModulePath | ||
249 | }; | ||
250 | |||
251 | if (typeof _this.describePscError === 'function') { | ||
252 | var _describePscError = _this.describePscError(error, desc), | ||
253 | _describePscError$dep = _describePscError.dependencies, | ||
254 | dependencies = _describePscError$dep === undefined ? [] : _describePscError$dep, | ||
255 | details = _describePscError.details; | ||
256 | |||
257 | var _iteratorNormalCompletion2 = true; | ||
258 | var _didIteratorError2 = false; | ||
259 | var _iteratorError2 = undefined; | ||
260 | |||
261 | try { | ||
262 | |||
263 | for (var _iterator2 = dependencies[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { | ||
264 | var dep = _step2.value; | ||
265 | |||
266 | _this.addDependency(dep); | ||
267 | } | ||
268 | } catch (err) { | ||
269 | _didIteratorError2 = true; | ||
270 | _iteratorError2 = err; | ||
271 | } finally { | ||
272 | try { | ||
273 | if (!_iteratorNormalCompletion2 && _iterator2.return) { | ||
274 | _iterator2.return(); | ||
275 | } | ||
276 | } finally { | ||
277 | if (_didIteratorError2) { | ||
278 | throw _iteratorError2; | ||
279 | } | ||
280 | } | ||
281 | } | ||
282 | |||
283 | Object.assign(desc, details); | ||
284 | } | ||
285 | |||
286 | modules.push(desc); | ||
287 | } | ||
288 | } catch (err) { | ||
289 | _didIteratorError = true; | ||
290 | _iteratorError = err; | ||
291 | } finally { | ||
292 | try { | ||
293 | if (!_iteratorNormalCompletion && _iterator.return) { | ||
294 | _iterator.return(); | ||
295 | } | ||
296 | } finally { | ||
297 | if (_didIteratorError) { | ||
298 | throw _iteratorError; | ||
299 | } | ||
300 | } | ||
301 | } | ||
302 | |||
303 | CACHE_VAR.errors.push(new utils.PscError(pscMessage, modules)); | ||
304 | } | ||
305 | } | ||
306 | }; | ||
307 | |||
308 | debug('loading %s', psModule.name); | ||
309 | |||
310 | if (options.bundle) { | ||
311 | CACHE_VAR.bundleModules.push(psModule.name); | ||
312 | } | ||
313 | |||
314 | if (CACHE_VAR.rebuild) { | ||
315 | var connect = function connect() { | ||
316 | if (!CACHE_VAR.ideServer) { | ||
317 | CACHE_VAR.ideServer = true; | ||
318 | |||
319 | return ide.connect(psModule).then(function (ideServer) { | ||
320 | CACHE_VAR.ideServer = ideServer; | ||
321 | return psModule; | ||
322 | }).then(ide.loadWithRetry).catch(function (error) { | ||
323 | if (CACHE_VAR.ideServer.kill) { | ||
324 | debug('ide failed to initially load modules, stopping the ide server process'); | ||
325 | |||
326 | CACHE_VAR.ideServer.kill(); | ||
327 | } | ||
328 | |||
329 | CACHE_VAR.ideServer = null; | ||
330 | |||
331 | return Promise.reject(error); | ||
332 | }); | ||
333 | } else { | ||
334 | return Promise.resolve(psModule); | ||
335 | } | ||
336 | }; | ||
337 | |||
338 | var rebuild = function rebuild() { | ||
339 | return ide.rebuild(psModule).then(function () { | ||
340 | return toJavaScript(psModule).then(function (js) { | ||
341 | return sourceMaps(psModule, js); | ||
342 | }).then(psModule.load).catch(psModule.reject); | ||
343 | }).catch(function (error) { | ||
344 | if (error instanceof ide.UnknownModuleError) { | ||
345 | // Store the modules that trigger a recompile due to an | ||
346 | // unknown module error. We need to wait until compilation is | ||
347 | // done before loading these files. | ||
348 | |||
349 | CACHE_VAR.deferred.push(psModule); | ||
350 | |||
351 | if (!CACHE_VAR.compilationStarted) { | ||
352 | CACHE_VAR.compilationStarted = true; | ||
353 | |||
354 | return compile(psModule).then(function () { | ||
355 | CACHE_VAR.compilationFinished = true; | ||
356 | }).then(function () { | ||
357 | return Promise.map(CACHE_VAR.deferred, function (psModule) { | ||
358 | return ide.load(psModule).then(function () { | ||
359 | return toJavaScript(psModule); | ||
360 | }).then(function (js) { | ||
361 | return sourceMaps(psModule, js); | ||
362 | }).then(psModule.load); | ||
363 | }); | ||
364 | }).catch(function (error) { | ||
365 | CACHE_VAR.compilationFailed = true; | ||
366 | |||
367 | CACHE_VAR.deferred[0].reject(error); | ||
368 | |||
369 | CACHE_VAR.deferred.slice(1).forEach(function (psModule) { | ||
370 | psModule.reject(new Error('purs-loader failed')); | ||
371 | }); | ||
372 | }); | ||
373 | } else if (CACHE_VAR.compilationFailed) { | ||
374 | CACHE_VAR.deferred.pop().reject(new Error('purs-loader failed')); | ||
375 | } else { | ||
376 | // The compilation has started. We must wait until it is | ||
377 | // done in order to ensure the module map contains all of | ||
378 | // the unknown modules. | ||
379 | } | ||
380 | } else { | ||
381 | debug('ide rebuild failed due to an unhandled error: %o', error); | ||
382 | |||
383 | psModule.reject(error); | ||
384 | } | ||
385 | }); | ||
386 | }; | ||
387 | |||
388 | connect().then(rebuild); | ||
389 | } else if (CACHE_VAR.compilationFinished) { | ||
390 | debugVerbose('compilation is already finished, loading module %s', psModule.name); | ||
391 | |||
392 | toJavaScript(psModule).then(function (js) { | ||
393 | return sourceMaps(psModule, js); | ||
394 | }).then(psModule.load).catch(psModule.reject); | ||
395 | } else { | ||
396 | // The compilation has not finished yet. We need to wait for | ||
397 | // compilation to finish before the loaders run so that references | ||
398 | // to compiled output are valid. Push the modules into the CACHE_VAR to | ||
399 | // be loaded once the complation is complete. | ||
400 | |||
401 | CACHE_VAR.deferred.push(psModule); | ||
402 | |||
403 | if (!CACHE_VAR.compilationStarted) { | ||
404 | CACHE_VAR.compilationStarted = true; | ||
405 | |||
406 | compile(psModule).then(function () { | ||
407 | CACHE_VAR.compilationFinished = true; | ||
408 | }).then(function () { | ||
409 | if (options.bundle) { | ||
410 | return bundle(options, CACHE_VAR.bundleModules); | ||
411 | } | ||
412 | }).then(function () { | ||
413 | return Promise.map(CACHE_VAR.deferred, function (psModule) { | ||
414 | return toJavaScript(psModule).then(function (js) { | ||
415 | return sourceMaps(psModule, js); | ||
416 | }).then(psModule.load); | ||
417 | }); | ||
418 | }).catch(function (error) { | ||
419 | CACHE_VAR.compilationFailed = true; | ||
420 | |||
421 | CACHE_VAR.deferred[0].reject(error); | ||
422 | |||
423 | CACHE_VAR.deferred.slice(1).forEach(function (psModule) { | ||
424 | psModule.reject(new Error('purs-loader failed')); | ||
425 | }); | ||
426 | }); | ||
427 | } else if (CACHE_VAR.compilationFailed) { | ||
428 | CACHE_VAR.deferred.pop().reject(new Error('purs-loader failed')); | ||
429 | } else { | ||
430 | // The complation has started. Nothing to do but wait until it is | ||
431 | // done before loading all of the modules. | ||
432 | } | ||
433 | } | ||
434 | }; \ No newline at end of file | ||
diff --git a/lib/purs-module-map.js b/lib/purs-module-map.js new file mode 100644 index 0000000..cb06322 --- /dev/null +++ b/lib/purs-module-map.js | |||
@@ -0,0 +1,78 @@ | |||
1 | 'use strict'; | ||
2 | |||
3 | var path = require('path'); | ||
4 | |||
5 | var Promise = require('bluebird'); | ||
6 | |||
7 | var fs = Promise.promisifyAll(require('fs')); | ||
8 | |||
9 | var globby = require('globby'); | ||
10 | |||
11 | var debug = require('debug')('purs-loader'); | ||
12 | |||
13 | var srcModuleRegex = /(?:^|\n)module\s+([\w\.]+)/i; | ||
14 | |||
15 | var importModuleRegex = /(?:^|\n)\s*import\s+([\w\.]+)/ig; | ||
16 | |||
17 | module.exports.matchModule = function matchModule(str) { | ||
18 | var matches = str.match(srcModuleRegex); | ||
19 | return matches && matches[1]; | ||
20 | }; | ||
21 | |||
22 | module.exports.matchImports = function matchImports(str) { | ||
23 | var matches = str.match(importModuleRegex); | ||
24 | return (matches || []).map(function (a) { | ||
25 | return a.replace(/\n?\s*import\s+/i, ''); | ||
26 | }); | ||
27 | }; | ||
28 | |||
29 | module.exports.makeMapEntry = function makeMapEntry(filePurs) { | ||
30 | var dirname = path.dirname(filePurs); | ||
31 | |||
32 | var basename = path.basename(filePurs, '.purs'); | ||
33 | |||
34 | var fileJs = path.join(dirname, basename + '.js'); | ||
35 | |||
36 | var result = Promise.props({ | ||
37 | filePurs: fs.readFileAsync(filePurs, 'utf8'), | ||
38 | fileJs: fs.readFileAsync(fileJs, 'utf8').catch(function () { | ||
39 | return undefined; | ||
40 | }) | ||
41 | }).then(function (fileMap) { | ||
42 | var sourcePurs = fileMap.filePurs; | ||
43 | |||
44 | var sourceJs = fileMap.fileJs; | ||
45 | |||
46 | var moduleName = module.exports.matchModule(sourcePurs); | ||
47 | |||
48 | var imports = module.exports.matchImports(sourcePurs); | ||
49 | |||
50 | var map = {}; | ||
51 | |||
52 | map[moduleName] = map[moduleName] || {}; | ||
53 | |||
54 | map[moduleName].src = path.resolve(filePurs); | ||
55 | |||
56 | map[moduleName].imports = imports; | ||
57 | |||
58 | if (sourceJs) { | ||
59 | map[moduleName].ffi = path.resolve(fileJs); | ||
60 | } | ||
61 | |||
62 | return map; | ||
63 | }); | ||
64 | |||
65 | return result; | ||
66 | }; | ||
67 | |||
68 | module.exports.makeMap = function makeMap(src) { | ||
69 | debug('loading PureScript source and FFI files from %o', src); | ||
70 | |||
71 | var globs = [].concat(src); | ||
72 | |||
73 | return globby(globs).then(function (paths) { | ||
74 | return Promise.all(paths.map(module.exports.makeMapEntry)).then(function (result) { | ||
75 | return result.reduce(Object.assign, {}); | ||
76 | }); | ||
77 | }); | ||
78 | }; \ No newline at end of file | ||
diff --git a/lib/source-maps.js b/lib/source-maps.js new file mode 100644 index 0000000..3ad70dd --- /dev/null +++ b/lib/source-maps.js | |||
@@ -0,0 +1,61 @@ | |||
1 | 'use strict'; | ||
2 | |||
3 | var Promise = require('bluebird'); | ||
4 | |||
5 | var fs = require('fs'); | ||
6 | |||
7 | var path = require('path'); | ||
8 | |||
9 | var debug_ = require('debug'); | ||
10 | |||
11 | var debugVerbose = debug_('purs-loader:verbose'); | ||
12 | |||
13 | module.exports = function sourceMap(psModule, js) { | ||
14 | var options = psModule.options; | ||
15 | |||
16 | var jsPath = psModule.jsPath; | ||
17 | |||
18 | var srcPath = psModule.srcPath; | ||
19 | |||
20 | var source = psModule.source; | ||
21 | |||
22 | var remainingRequest = psModule.remainingRequest; | ||
23 | |||
24 | var sourceMapPath = path.join(path.dirname(jsPath), 'index.js.map'); | ||
25 | |||
26 | var isSourceMapsEnabled = options.pscArgs && options.pscArgs.sourceMaps; | ||
27 | |||
28 | return new Promise(function (resolve, reject) { | ||
29 | if (!isSourceMapsEnabled) { | ||
30 | resolve({ | ||
31 | js: js, | ||
32 | map: undefined | ||
33 | }); | ||
34 | } else { | ||
35 | debugVerbose('loading source map %s', sourceMapPath); | ||
36 | |||
37 | fs.readFile(sourceMapPath, 'utf-8', function (error, result) { | ||
38 | if (error) { | ||
39 | reject(error); | ||
40 | } else { | ||
41 | try { | ||
42 | var map = Object.assign(JSON.parse(result), { | ||
43 | sources: [remainingRequest], | ||
44 | file: path.normalize(srcPath), | ||
45 | sourcesContent: [source] | ||
46 | }); | ||
47 | |||
48 | var jsRemovedMapUrl = js.replace(/^\/\/# sourceMappingURL=[^\r\n]*/gm, ''); | ||
49 | |||
50 | resolve({ | ||
51 | js: jsRemovedMapUrl, | ||
52 | map: map | ||
53 | }); | ||
54 | } catch (error) { | ||
55 | reject(error); | ||
56 | } | ||
57 | } | ||
58 | }); | ||
59 | } | ||
60 | }); | ||
61 | }; \ No newline at end of file | ||
diff --git a/lib/to-javascript.js b/lib/to-javascript.js new file mode 100644 index 0000000..ce49704 --- /dev/null +++ b/lib/to-javascript.js | |||
@@ -0,0 +1,152 @@ | |||
1 | 'use strict'; | ||
2 | |||
3 | var Promise = require('bluebird'); | ||
4 | |||
5 | var fs = Promise.promisifyAll(require('fs')); | ||
6 | |||
7 | var path = require('path'); | ||
8 | |||
9 | var jsStringEscape = require('js-string-escape'); | ||
10 | |||
11 | var difference = require('lodash.difference'); | ||
12 | |||
13 | var debug_ = require('debug'); | ||
14 | |||
15 | var debug = debug_('purs-loader'); | ||
16 | |||
17 | var debugVerbose = debug_('purs-loader:verbose'); | ||
18 | |||
19 | var PsModuleMap = require('./purs-module-map'); | ||
20 | |||
21 | function updatePsModuleMap(psModule) { | ||
22 | var options = psModule.options; | ||
23 | |||
24 | var cache = psModule.cache; | ||
25 | |||
26 | var filePurs = psModule.srcPath; | ||
27 | |||
28 | if (!cache.psModuleMap) { | ||
29 | debugVerbose('module mapping does not exist - making a new module map'); | ||
30 | |||
31 | cache.psModuleMap = PsModuleMap.makeMap(options.src); | ||
32 | |||
33 | return cache.psModuleMap; | ||
34 | } else { | ||
35 | debugVerbose('module mapping exists - updating module map for %s', filePurs); | ||
36 | |||
37 | cache.psModuleMap = cache.psModuleMap.then(function (psModuleMap) { | ||
38 | return PsModuleMap.makeMapEntry(filePurs).then(function (result) { | ||
39 | var map = Object.assign(psModuleMap, result); | ||
40 | |||
41 | return map; | ||
42 | }); | ||
43 | }); | ||
44 | |||
45 | return cache.psModuleMap; | ||
46 | } | ||
47 | } | ||
48 | |||
49 | // Reference the bundle. | ||
50 | function makeBundleJS(psModule) { | ||
51 | var bundleOutput = psModule.options.bundleOutput; | ||
52 | |||
53 | var name = psModule.name; | ||
54 | |||
55 | var srcDir = psModule.srcDir; | ||
56 | |||
57 | var escaped = jsStringEscape(path.relative(srcDir, bundleOutput)); | ||
58 | |||
59 | var result = 'module.exports = require("' + escaped + '")["' + name + '"]'; | ||
60 | |||
61 | return Promise.resolve(result); | ||
62 | } | ||
63 | |||
64 | // Replace require paths to output files generated by psc with paths | ||
65 | // to purescript sources, which are then also run through this loader. | ||
66 | // Additionally, the imports replaced are tracked so that in the event | ||
67 | // the compiler fails to compile the PureScript source, we can tack on | ||
68 | // any new imports in order to allow webpack to watch the new files | ||
69 | // before they have been successfully compiled. | ||
70 | function makeJS(psModule, psModuleMap, js) { | ||
71 | var requireRE = /require\(['"]\.\.\/([\w\.]+)(?:\/index\.js)?['"]\)/g; | ||
72 | |||
73 | var foreignRE = /require\(['"]\.\/foreign(?:\.js)?['"]\)/g; | ||
74 | |||
75 | var name = psModule.name; | ||
76 | |||
77 | var imports = psModuleMap[name].imports; | ||
78 | |||
79 | var replacedImports = []; | ||
80 | |||
81 | var result = js.replace(requireRE, function (m, p1) { | ||
82 | var moduleValue = psModuleMap[p1]; | ||
83 | |||
84 | if (!moduleValue) { | ||
85 | debug('module %s was not found in the map, replacing require with null', p1); | ||
86 | |||
87 | return 'null'; | ||
88 | } else { | ||
89 | var escapedPath = jsStringEscape(moduleValue.src); | ||
90 | |||
91 | replacedImports.push(p1); | ||
92 | |||
93 | return 'require("' + escapedPath + '")'; | ||
94 | } | ||
95 | }).replace(foreignRE, function () { | ||
96 | var escapedPath = jsStringEscape(psModuleMap[name].ffi); | ||
97 | |||
98 | return 'require("' + escapedPath + '")'; | ||
99 | }); | ||
100 | |||
101 | var additionalImports = difference(imports, replacedImports); | ||
102 | |||
103 | if (!additionalImports.length) { | ||
104 | return Promise.resolve(result); | ||
105 | } else { | ||
106 | debug('rebuilding module map due to additional imports for %s: %o', name, additionalImports); | ||
107 | |||
108 | psModule.cache.psModuleMap = null; | ||
109 | |||
110 | return updatePsModuleMap(psModule).then(function (updatedPsModuleMap) { | ||
111 | var additionalImportsResult = additionalImports.map(function (import_) { | ||
112 | var moduleValue = updatedPsModuleMap[import_]; | ||
113 | |||
114 | if (!moduleValue) { | ||
115 | debug('module %s was not found in the map, skipping require', import_); | ||
116 | |||
117 | return null; | ||
118 | } else { | ||
119 | var escapedPath = jsStringEscape(moduleValue.src); | ||
120 | |||
121 | return 'var ' + import_.replace(/\./g, '_') + ' = require("' + escapedPath + '")'; | ||
122 | } | ||
123 | }).filter(function (a) { | ||
124 | return a !== null; | ||
125 | }).join('\n'); | ||
126 | |||
127 | return result + '\n' + additionalImportsResult; | ||
128 | }); | ||
129 | } | ||
130 | } | ||
131 | |||
132 | module.exports = function toJavaScript(psModule) { | ||
133 | var options = psModule.options; | ||
134 | |||
135 | var cache = psModule.cache; | ||
136 | |||
137 | var bundlePath = path.resolve(options.bundleOutput); | ||
138 | |||
139 | var jsPath = options.bundle ? bundlePath : psModule.jsPath; | ||
140 | |||
141 | var js = fs.readFileAsync(jsPath, 'utf8').catch(function () { | ||
142 | return ''; | ||
143 | }); | ||
144 | |||
145 | var psModuleMap = updatePsModuleMap(psModule); | ||
146 | |||
147 | debugVerbose('loading JavaScript for %s', psModule.name); | ||
148 | |||
149 | return Promise.props({ js: js, psModuleMap: psModuleMap }).then(function (result) { | ||
150 | return options.bundle ? makeBundleJS(psModule) : makeJS(psModule, result.psModuleMap, result.js); | ||
151 | }); | ||
152 | }; \ No newline at end of file | ||
diff --git a/lib/utils.js b/lib/utils.js new file mode 100644 index 0000000..3b9ba19 --- /dev/null +++ b/lib/utils.js | |||
@@ -0,0 +1,64 @@ | |||
1 | 'use strict'; | ||
2 | |||
3 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); | ||
4 | |||
5 | function _toArray(arr) { return Array.isArray(arr) ? arr : Array.from(arr); } | ||
6 | |||
7 | function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } | ||
8 | |||
9 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
10 | |||
11 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } | ||
12 | |||
13 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
14 | |||
15 | var path = require('path'); | ||
16 | |||
17 | exports.PscError = function (_Error) { | ||
18 | _inherits(PscError, _Error); | ||
19 | |||
20 | function PscError(message, modules) { | ||
21 | _classCallCheck(this, PscError); | ||
22 | |||
23 | var _this = _possibleConstructorReturn(this, (PscError.__proto__ || Object.getPrototypeOf(PscError)).call(this, message)); | ||
24 | |||
25 | _this.modules = modules; | ||
26 | _this.isPscError = true; | ||
27 | return _this; | ||
28 | } | ||
29 | |||
30 | _createClass(PscError, null, [{ | ||
31 | key: 'name', | ||
32 | get: function get() { | ||
33 | return 'PscError'; | ||
34 | } | ||
35 | }]); | ||
36 | |||
37 | return PscError; | ||
38 | }(Error); | ||
39 | |||
40 | var repeat = function repeat(value, times) { | ||
41 | return times <= 0 ? [] : [value].concat(_toConsumableArray(repeat(value, times - 1))); | ||
42 | }; | ||
43 | var diffPursModuleNames = function diffPursModuleNames(from, target, parts) { | ||
44 | if (!from.length) return parts.concat(target); | ||
45 | if (!target.length) return parts.concat(repeat('..', from.length)); | ||
46 | |||
47 | var _from = _toArray(from), | ||
48 | head_from = _from[0], | ||
49 | tail_from = _from.slice(1); | ||
50 | |||
51 | var _target = _toArray(target), | ||
52 | head_target = _target[0], | ||
53 | tail_target = _target.slice(1); | ||
54 | |||
55 | return head_from === head_target ? diffPursModuleNames(tail_from, tail_target, parts) : parts.concat(repeat('..', from.length), target); | ||
56 | }; | ||
57 | exports.resolvePursModule = function (_ref) { | ||
58 | var baseModulePath = _ref.baseModulePath, | ||
59 | baseModuleName = _ref.baseModuleName, | ||
60 | targetModuleName = _ref.targetModuleName; | ||
61 | |||
62 | var parts = diffPursModuleNames(baseModuleName.split('.'), targetModuleName.split('.'), []); | ||
63 | return parts.length ? path.resolve(baseModulePath, path.join.apply(path, _toConsumableArray(parts)) + '.purs') : baseModulePath; | ||
64 | }; \ No newline at end of file | ||