]> git.immae.eu Git - github/fretlink/purs-loader.git/blame - lib/index.js
Build v4.0.0
[github/fretlink/purs-loader.git] / lib / index.js
CommitLineData
d3f40b6f
CS
1'use strict';
2
3var _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
5var debug_ = require('debug');
6
7var debug = debug_('purs-loader');
8
9var debugVerbose = debug_('purs-loader:verbose');
10
11var loaderUtils = require('loader-utils');
12
13var Promise = require('bluebird');
14
15var path = require('path');
16
17var PsModuleMap = require('./purs-module-map');
18
19var compile = require('./compile');
20
21var bundle = require('./bundle');
22
23var ide = require('./ide');
24
25var toJavaScript = require('./to-javascript');
26
27var sourceMaps = require('./source-maps');
28
29var dargs = require('./dargs');
30
31var utils = require('./utils');
32
33var spawn = require('cross-spawn').sync;
34
35var eol = require('os').EOL;
36
37var 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
52module.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
9dad774b 208 var matchErrLocation = /at (.+\.purs):(\d+):(\d+) - (\d+):(\d+) \(line \2, column \3 - line \4, column \5\)/;
d3f40b6f
CS
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};