]> git.immae.eu Git - github/fretlink/purs-loader.git/blob - lib/index.js
Build v4.2.0
[github/fretlink/purs-loader.git] / lib / index.js
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 rewriteRules: {}
128 }, loaderOptions, {
129 src: srcOption
130 });
131
132 if (!CACHE_VAR.installed) {
133 debugVerbose('installing purs-loader with options: %O', options);
134
135 CACHE_VAR.installed = true;
136
137 // invalidate loader CACHE_VAR when bundle is marked as invalid (in watch mode)
138 this._compiler.plugin('invalid', function () {
139 debugVerbose('invalidating loader CACHE_VAR');
140
141 CACHE_VAR = {
142 rebuild: options.pscIde,
143 deferred: [],
144 bundleModules: [],
145 ideServer: CACHE_VAR.ideServer,
146 psModuleMap: CACHE_VAR.psModuleMap,
147 warnings: [],
148 errors: [],
149 compilationStarted: false,
150 compilationFinished: false,
151 compilationFailed: false,
152 installed: CACHE_VAR.installed,
153 srcOption: []
154 };
155 });
156
157 // add psc warnings to webpack compilation warnings
158 this._compiler.plugin('after-compile', function (compilation, callback) {
159 CACHE_VAR.warnings.forEach(function (warning) {
160 compilation.warnings.push(warning);
161 });
162
163 CACHE_VAR.errors.forEach(function (error) {
164 compilation.errors.push(error);
165 });
166
167 callback();
168 });
169 }
170
171 var psModuleName = PsModuleMap.matchModule(source);
172
173 var psModule = {
174 name: psModuleName,
175 source: source,
176 load: function load(_ref) {
177 var js = _ref.js,
178 map = _ref.map;
179 return callback(null, js, map);
180 },
181 reject: function reject(error) {
182 return callback(error);
183 },
184 srcPath: this.resourcePath,
185 remainingRequest: loaderUtils.getRemainingRequest(this),
186 srcDir: path.dirname(this.resourcePath),
187 jsPath: path.resolve(path.join(options.output, psModuleName, 'index.js')),
188 options: options,
189 cache: CACHE_VAR,
190 emitWarning: function emitWarning(warning) {
191 if (options.warnings && warning.length) {
192 CACHE_VAR.warnings.push(warning);
193 }
194 },
195 emitError: function emitError(pscMessage) {
196 if (pscMessage.length) {
197 var modules = [];
198
199 var matchErrorsSeparator = /\n(?=Error)/;
200 var errors = pscMessage.split(matchErrorsSeparator);
201 var _iteratorNormalCompletion = true;
202 var _didIteratorError = false;
203 var _iteratorError = undefined;
204
205 try {
206 for (var _iterator = errors[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
207 var error = _step.value;
208
209 var matchErrLocation = /at (.+\.purs):(\d+):(\d+) - (\d+):(\d+) \(line \2, column \3 - line \4, column \5\)/;
210
211 var _ref2 = matchErrLocation.exec(error) || [],
212 _ref3 = _slicedToArray(_ref2, 2),
213 filename = _ref3[1];
214
215 if (!filename) continue;
216
217 var baseModulePath = path.join(_this.rootContext, filename);
218 _this.addDependency(baseModulePath);
219
220 var foreignModulesErrorCodes = ['ErrorParsingFFIModule', 'MissingFFIImplementations', 'UnusedFFIImplementations', 'MissingFFIModule'];
221 var _iteratorNormalCompletion2 = true;
222 var _didIteratorError2 = false;
223 var _iteratorError2 = undefined;
224
225 try {
226 for (var _iterator2 = foreignModulesErrorCodes[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
227 var code = _step2.value;
228
229 if (error.includes(code)) {
230 var resolved = utils.resolveForeignModule(baseModulePath);
231 _this.addDependency(resolved);
232 }
233 }
234 } catch (err) {
235 _didIteratorError2 = true;
236 _iteratorError2 = err;
237 } finally {
238 try {
239 if (!_iteratorNormalCompletion2 && _iterator2.return) {
240 _iterator2.return();
241 }
242 } finally {
243 if (_didIteratorError2) {
244 throw _iteratorError2;
245 }
246 }
247 }
248
249 var matchErrModuleName = /in module ((?:\w+\.)*\w+)/;
250
251 var _ref4 = matchErrModuleName.exec(error) || [],
252 _ref5 = _slicedToArray(_ref4, 2),
253 baseModuleName = _ref5[1];
254
255 if (!baseModuleName) continue;
256
257 var matchMissingModuleName = /Module ((?:\w+\.)*\w+) was not found/;
258 var matchMissingImportFromModuleName = /Cannot import value \w+ from module ((?:\w+\.)*\w+)/;
259 var _arr = [matchMissingModuleName, matchMissingImportFromModuleName];
260 for (var _i = 0; _i < _arr.length; _i++) {
261 var re = _arr[_i];
262 var _ref6 = re.exec(error) || [],
263 _ref7 = _slicedToArray(_ref6, 2),
264 targetModuleName = _ref7[1];
265
266 if (targetModuleName) {
267 var _resolved = utils.resolvePursModule({
268 baseModulePath: baseModulePath,
269 baseModuleName: baseModuleName,
270 rewriteRules: options.rewriteRules,
271 targetModuleName: targetModuleName
272 });
273 _this.addDependency(_resolved);
274 }
275 }
276
277 var desc = {
278 name: baseModuleName,
279 filename: baseModulePath
280 };
281
282 if (typeof _this.describePscError === 'function') {
283 var _describePscError = _this.describePscError(error, desc),
284 _describePscError$dep = _describePscError.dependencies,
285 dependencies = _describePscError$dep === undefined ? [] : _describePscError$dep,
286 details = _describePscError.details;
287
288 var _iteratorNormalCompletion3 = true;
289 var _didIteratorError3 = false;
290 var _iteratorError3 = undefined;
291
292 try {
293
294 for (var _iterator3 = dependencies[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
295 var dep = _step3.value;
296
297 _this.addDependency(dep);
298 }
299 } catch (err) {
300 _didIteratorError3 = true;
301 _iteratorError3 = err;
302 } finally {
303 try {
304 if (!_iteratorNormalCompletion3 && _iterator3.return) {
305 _iterator3.return();
306 }
307 } finally {
308 if (_didIteratorError3) {
309 throw _iteratorError3;
310 }
311 }
312 }
313
314 Object.assign(desc, details);
315 }
316
317 modules.push(desc);
318 }
319 } catch (err) {
320 _didIteratorError = true;
321 _iteratorError = err;
322 } finally {
323 try {
324 if (!_iteratorNormalCompletion && _iterator.return) {
325 _iterator.return();
326 }
327 } finally {
328 if (_didIteratorError) {
329 throw _iteratorError;
330 }
331 }
332 }
333
334 CACHE_VAR.errors.push(new utils.PscError(pscMessage, modules));
335 }
336 }
337 };
338
339 debug('loading %s', psModule.name);
340
341 if (options.bundle) {
342 CACHE_VAR.bundleModules.push(psModule.name);
343 }
344
345 if (CACHE_VAR.rebuild) {
346 var connect = function connect() {
347 if (!CACHE_VAR.ideServer) {
348 CACHE_VAR.ideServer = true;
349
350 return ide.connect(psModule).then(function (ideServer) {
351 CACHE_VAR.ideServer = ideServer;
352 return psModule;
353 }).then(ide.loadWithRetry).catch(function (error) {
354 if (CACHE_VAR.ideServer.kill) {
355 debug('ide failed to initially load modules, stopping the ide server process');
356
357 CACHE_VAR.ideServer.kill();
358 }
359
360 CACHE_VAR.ideServer = null;
361
362 return Promise.reject(error);
363 });
364 } else {
365 return Promise.resolve(psModule);
366 }
367 };
368
369 var rebuild = function rebuild() {
370 return ide.rebuild(psModule).then(function () {
371 return toJavaScript(psModule).then(function (js) {
372 return sourceMaps(psModule, js);
373 }).then(psModule.load).catch(psModule.reject);
374 }).catch(function (error) {
375 if (error instanceof ide.UnknownModuleError) {
376 // Store the modules that trigger a recompile due to an
377 // unknown module error. We need to wait until compilation is
378 // done before loading these files.
379
380 CACHE_VAR.deferred.push(psModule);
381
382 if (!CACHE_VAR.compilationStarted) {
383 CACHE_VAR.compilationStarted = true;
384
385 return compile(psModule).then(function () {
386 CACHE_VAR.compilationFinished = true;
387 }).then(function () {
388 return Promise.map(CACHE_VAR.deferred, function (psModule) {
389 return ide.load(psModule).then(function () {
390 return toJavaScript(psModule);
391 }).then(function (js) {
392 return sourceMaps(psModule, js);
393 }).then(psModule.load);
394 });
395 }).catch(function (error) {
396 CACHE_VAR.compilationFailed = true;
397
398 CACHE_VAR.deferred[0].reject(error);
399
400 CACHE_VAR.deferred.slice(1).forEach(function (psModule) {
401 psModule.reject(new Error('purs-loader failed'));
402 });
403 });
404 } else if (CACHE_VAR.compilationFailed) {
405 CACHE_VAR.deferred.pop().reject(new Error('purs-loader failed'));
406 } else {
407 // The compilation has started. We must wait until it is
408 // done in order to ensure the module map contains all of
409 // the unknown modules.
410 }
411 } else {
412 debug('ide rebuild failed due to an unhandled error: %o', error);
413
414 psModule.reject(error);
415 }
416 });
417 };
418
419 connect().then(rebuild);
420 } else if (CACHE_VAR.compilationFinished) {
421 debugVerbose('compilation is already finished, loading module %s', psModule.name);
422
423 toJavaScript(psModule).then(function (js) {
424 return sourceMaps(psModule, js);
425 }).then(psModule.load).catch(psModule.reject);
426 } else {
427 // The compilation has not finished yet. We need to wait for
428 // compilation to finish before the loaders run so that references
429 // to compiled output are valid. Push the modules into the CACHE_VAR to
430 // be loaded once the complation is complete.
431
432 CACHE_VAR.deferred.push(psModule);
433
434 if (!CACHE_VAR.compilationStarted) {
435 CACHE_VAR.compilationStarted = true;
436
437 compile(psModule).then(function () {
438 CACHE_VAR.compilationFinished = true;
439 }).then(function () {
440 if (options.bundle) {
441 return bundle(options, CACHE_VAR.bundleModules);
442 }
443 }).then(function () {
444 return Promise.map(CACHE_VAR.deferred, function (psModule) {
445 return toJavaScript(psModule).then(function (js) {
446 return sourceMaps(psModule, js);
447 }).then(psModule.load);
448 });
449 }).catch(function (error) {
450 CACHE_VAR.compilationFailed = true;
451
452 CACHE_VAR.deferred[0].reject(error);
453
454 CACHE_VAR.deferred.slice(1).forEach(function (psModule) {
455 psModule.reject(new Error('purs-loader failed'));
456 });
457 });
458 } else if (CACHE_VAR.compilationFailed) {
459 CACHE_VAR.deferred.pop().reject(new Error('purs-loader failed'));
460 } else {
461 // The complation has started. Nothing to do but wait until it is
462 // done before loading all of the modules.
463 }
464 }
465 };