--- /dev/null
+'use strict';
+
+var path = require('path');
+
+var Promise = require('bluebird');
+
+var fs = Promise.promisifyAll(require('fs'));
+
+var spawn = require('cross-spawn');
+
+var debug = require('debug')('purs-loader');
+
+var dargs = require('./dargs');
+
+module.exports = function bundle(options, bundleModules) {
+ var stdout = [];
+
+ var stderr = [];
+
+ var bundleCommand = options.pscBundle || 'purs';
+
+ var bundleArgs = (options.pscBundle ? [] : ['bundle']).concat(dargs(Object.assign({
+ _: [path.join(options.output, '*', '*.js')],
+ output: options.bundleOutput,
+ namespace: options.bundleNamespace
+ }, options.pscBundleArgs)));
+
+ bundleModules.forEach(function (name) {
+ return bundleArgs.push('--module', name);
+ });
+
+ debug('bundle: %s %O', bundleCommand, bundleArgs);
+
+ return new Promise(function (resolve, reject) {
+ debug('bundling PureScript...');
+
+ var compilation = spawn(bundleCommand, bundleArgs);
+
+ compilation.stdout.on('data', function (data) {
+ return stdout.push(data.toString());
+ });
+
+ compilation.stderr.on('data', function (data) {
+ return stderr.push(data.toString());
+ });
+
+ compilation.on('close', function (code) {
+ debug('finished bundling PureScript.');
+
+ if (code !== 0) {
+ var errorMessage = stderr.join('');
+
+ if (errorMessage.length) {
+ psModule.emitError(errorMessage);
+ }
+
+ reject(new Error('bundling failed'));
+ } else {
+ resolve(fs.appendFileAsync(options.bundleOutput, 'module.exports = ' + options.bundleNamespace));
+ }
+ });
+ });
+};
\ No newline at end of file
--- /dev/null
+'use strict';
+
+var Promise = require('bluebird');
+
+var spawn = require('cross-spawn');
+
+var debug_ = require('debug');
+
+var debug = debug_('purs-loader');
+
+var debugVerbose = debug_('purs-loader:verbose');
+
+var dargs = require('./dargs');
+
+module.exports = function compile(psModule) {
+ var options = psModule.options;
+
+ var compileCommand = options.psc || 'purs';
+
+ var compileArgs = (options.psc ? [] : ['compile']).concat(dargs(Object.assign({
+ _: options.src,
+ output: options.output
+ }, options.pscArgs)));
+
+ var stderr = [];
+
+ debug('compile %s %O', compileCommand, compileArgs);
+
+ return new Promise(function (resolve, reject) {
+ debug('compiling PureScript...');
+
+ var compilation = spawn(compileCommand, compileArgs);
+
+ compilation.stderr.on('data', function (data) {
+ stderr.push(data.toString());
+ });
+
+ compilation.stdout.on('data', function (data) {
+ debugVerbose(data.toString());
+ });
+
+ compilation.on('close', function (code) {
+ debug('finished compiling PureScript.');
+
+ if (code !== 0) {
+ var errorMessage = stderr.join('');
+ if (errorMessage.length) {
+ psModule.emitError(errorMessage);
+ }
+ if (options.watch) {
+ resolve(psModule);
+ } else {
+ reject(new Error('compilation failed'));
+ }
+ } else {
+ var warningMessage = stderr.join('');
+ if (options.warnings && warningMessage.length) {
+ psModule.emitWarning(warningMessage);
+ }
+ resolve(psModule);
+ }
+ });
+ });
+};
\ No newline at end of file
--- /dev/null
+'use strict';
+
+var dargs = require('dargs');
+
+module.exports = function (obj) {
+ return dargs(obj, { ignoreFalse: true });
+};
\ No newline at end of file
--- /dev/null
+'use strict';
+
+var path = require('path');
+
+var Promise = require('bluebird');
+
+var fs = Promise.promisifyAll(require('fs'));
+
+var retryPromise = require('promise-retry');
+
+var spawn = require('cross-spawn');
+
+var colors = require('chalk');
+
+var debug_ = require('debug');
+
+var debug = debug_('purs-loader');
+
+var debugVerbose = debug_('purs-loader:verbose');
+
+var dargs = require('./dargs');
+
+var compile = require('./compile');
+
+var PsModuleMap = require('./purs-module-map');
+
+function UnknownModuleError() {
+ this.name = 'UnknownModuleError';
+ this.stack = new Error().stack;
+}
+
+UnknownModuleError.prototype = Object.create(Error.prototype);
+
+UnknownModuleError.prototype.constructor = UnknownModuleError;
+
+module.exports.UnknownModuleError = UnknownModuleError;
+
+function spawnIdeClient(body, options) {
+ var ideClientCommand = options.pscIdeClient || 'purs';
+
+ var ideClientArgs = (options.pscIdeClient ? [] : ['ide', 'client']).concat(dargs(options.pscIdeClientArgs));
+
+ var stderr = [];
+
+ var stdout = [];
+
+ debug('ide client %s %o %O', ideClientCommand, ideClientArgs, body);
+
+ return new Promise(function (resolve, reject) {
+ var ideClient = spawn(ideClientCommand, ideClientArgs);
+
+ ideClient.stderr.on('data', function (data) {
+ stderr.push(data.toString());
+ });
+
+ ideClient.stdout.on('data', function (data) {
+ stdout.push(data.toString());
+ });
+
+ ideClient.on('close', function (code) {
+ if (code !== 0) {
+ var errorMessage = stderr.join('');
+
+ reject(new Error('ide client failed: ' + errorMessage));
+ } else {
+ var result = stdout.join('');
+
+ resolve(result);
+ }
+ });
+
+ ideClient.stdin.resume();
+
+ ideClient.stdin.write(JSON.stringify(body));
+
+ ideClient.stdin.write('\n');
+ });
+}
+
+function formatIdeResult(result, options, index, length) {
+ var numAndErr = '[' + (index + 1) + '/' + length + ' ' + result.errorCode + ']';
+ numAndErr = options.pscIdeColors ? colors.yellow(numAndErr) : numAndErr;
+
+ function makeResult() {
+ return Promise.resolve('\n' + numAndErr + ' ' + result.message);
+ }
+
+ function makeResultSnippet(filename, pos) {
+ var srcPath = path.relative(options.context, filename);
+ var fileAndPos = srcPath + ':' + pos.startLine + ':' + pos.startColumn;
+
+ return fs.readFileAsync(filename, 'utf8').then(function (source) {
+ var lines = source.split('\n').slice(pos.startLine - 1, pos.endLine);
+ var endsOnNewline = pos.endColumn === 1 && pos.startLine !== pos.endLine;
+ var up = options.pscIdeColors ? colors.red('^') : '^';
+ var down = options.pscIdeColors ? colors.red('v') : 'v';
+ var trimmed = lines.slice(0);
+
+ if (endsOnNewline) {
+ lines.splice(lines.length - 1, 1);
+ pos.endLine = pos.endLine - 1;
+ pos.endColumn = lines[lines.length - 1].length || 1;
+ }
+
+ // strip newlines at the end
+ if (endsOnNewline) {
+ trimmed = lines.reverse().reduce(function (trimmed, line, i) {
+ if (i === 0 && line === '') trimmed.trimming = true;
+ if (!trimmed.trimming) trimmed.push(line);
+ if (trimmed.trimming && line !== '') {
+ trimmed.trimming = false;
+ trimmed.push(line);
+ }
+ return trimmed;
+ }, []).reverse();
+ pos.endLine = pos.endLine - (lines.length - trimmed.length);
+ pos.endColumn = trimmed[trimmed.length - 1].length || 1;
+ }
+
+ var spaces = ' '.repeat(String(pos.endLine).length);
+ var snippet = trimmed.map(function (line, i) {
+ return ' ' + (pos.startLine + i) + ' ' + line;
+ }).join('\n');
+
+ if (trimmed.length === 1) {
+ snippet += '\n ' + spaces + ' ' + ' '.repeat(pos.startColumn - 1) + up.repeat(pos.endColumn - pos.startColumn + 1);
+ } else {
+ snippet = ' ' + spaces + ' ' + ' '.repeat(pos.startColumn - 1) + down + '\n' + snippet;
+ snippet += '\n ' + spaces + ' ' + ' '.repeat(pos.endColumn - 1) + up;
+ }
+
+ return Promise.resolve('\n' + numAndErr + ' ' + fileAndPos + '\n\n' + snippet + '\n\n' + result.message);
+ }).catch(function (error) {
+ debug('failed to format ide result: %o', error);
+
+ return Promise.resolve('');
+ });
+ }
+
+ return result.filename && result.position ? makeResultSnippet(result.filename, result.position) : makeResult();
+}
+
+module.exports.connect = function connect(psModule) {
+ var options = psModule.options;
+
+ var serverCommand = options.pscIdeServer || 'purs';
+
+ var serverArgs = (options.pscIdeServer ? [] : ['ide', 'server']).concat(dargs(Object.assign({
+ outputDirectory: options.output,
+ '_': options.src
+ }, options.pscIdeServerArgs)));
+
+ debug('ide server: %s %o', serverCommand, serverArgs);
+
+ var ideServer = spawn(serverCommand, serverArgs);
+
+ ideServer.stdout.on('data', function (data) {
+ debugVerbose('ide server stdout: %s', data.toString());
+ });
+
+ ideServer.stderr.on('data', function (data) {
+ debugVerbose('ide server stderr: %s', data.toString());
+ });
+
+ ideServer.on('error', function (error) {
+ debugVerbose('ide server error: %o', error);
+ });
+
+ ideServer.on('close', function (code, signal) {
+ debugVerbose('ide server close: %s %s', code, signal);
+ });
+
+ return Promise.resolve(ideServer);
+};
+
+module.exports.load = function load(psModule) {
+ var options = psModule.options;
+
+ var body = { command: 'load' };
+
+ return spawnIdeClient(body, options);
+};
+
+module.exports.loadWithRetry = function loadWithRetry(psModule) {
+ var retries = 9;
+
+ return retryPromise(function (retry, number) {
+ debugVerbose('attempting to load modules (%d out of %d attempts)', number, retries);
+
+ return module.exports.load(psModule).catch(retry);
+ }, {
+ retries: retries,
+ factor: 1,
+ minTimeout: 333,
+ maxTimeout: 333
+ }).then(function () {
+ return psModule;
+ });
+};
+
+module.exports.rebuild = function rebuild(psModule) {
+ var options = psModule.options;
+
+ var body = {
+ command: 'rebuild',
+ params: {
+ file: psModule.srcPath
+ }
+ };
+
+ var parseResponse = function parseResponse(response) {
+ try {
+ var parsed = JSON.parse(response);
+
+ debugVerbose('parsed JSON response: %O', parsed);
+
+ return Promise.resolve(parsed);
+ } catch (error) {
+ return Promise.reject(error);
+ }
+ };
+
+ var formatResponse = function formatResponse(parsed) {
+ var result = Array.isArray(parsed.result) ? parsed.result : [];
+
+ return Promise.map(result, function (item, i) {
+ debugVerbose('formatting result %O', item);
+
+ return formatIdeResult(item, options, i, result.length);
+ }).then(function (formatted) {
+ return {
+ parsed: parsed,
+ formatted: formatted,
+ formattedMessage: formatted.join('\n')
+ };
+ });
+ };
+
+ return spawnIdeClient(body, options).then(parseResponse).then(formatResponse).then(function (_ref) {
+ var parsed = _ref.parsed,
+ formatted = _ref.formatted,
+ formattedMessage = _ref.formattedMessage;
+
+ if (parsed.resultType === 'success') {
+ if (options.warnings && formattedMessage.length) {
+ psModule.emitWarning(formattedMessage);
+ }
+
+ return psModule;
+ } else if ((parsed.result || []).some(function (item) {
+ var isModuleNotFound = item.errorCode === 'ModuleNotFound';
+
+ var isUnknownModule = item.errorCode === 'UnknownModule';
+
+ var isUnknownModuleImport = item.errorCode === 'UnknownName' && /Unknown module/.test(item.message);
+
+ return isModuleNotFound || isUnknownModule || isUnknownModuleImport;
+ })) {
+ debug('module %s was not rebuilt because the module is unknown', psModule.name);
+
+ return Promise.reject(new UnknownModuleError());
+ } else {
+ if (formattedMessage.length) {
+ psModule.emitError(formattedMessage);
+ }
+
+ return psModule;
+ }
+ });
+};
\ No newline at end of file
--- /dev/null
+'use strict';
+
+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"); } }; }();
+
+var debug_ = require('debug');
+
+var debug = debug_('purs-loader');
+
+var debugVerbose = debug_('purs-loader:verbose');
+
+var loaderUtils = require('loader-utils');
+
+var Promise = require('bluebird');
+
+var path = require('path');
+
+var PsModuleMap = require('./purs-module-map');
+
+var compile = require('./compile');
+
+var bundle = require('./bundle');
+
+var ide = require('./ide');
+
+var toJavaScript = require('./to-javascript');
+
+var sourceMaps = require('./source-maps');
+
+var dargs = require('./dargs');
+
+var utils = require('./utils');
+
+var spawn = require('cross-spawn').sync;
+
+var eol = require('os').EOL;
+
+var CACHE_VAR = {
+ rebuild: false,
+ deferred: [],
+ bundleModules: [],
+ ideServer: null,
+ psModuleMap: null,
+ warnings: [],
+ errors: [],
+ compilationStarted: false,
+ compilationFinished: false,
+ compilationFailed: false,
+ installed: false,
+ srcOption: []
+};
+
+module.exports = function purescriptLoader(source, map) {
+ var _this = this;
+
+ this.cacheable && this.cacheable();
+
+ var webpackContext = this.options && this.options.context || this.rootContext;
+
+ var callback = this.async();
+
+ var loaderOptions = loaderUtils.getOptions(this) || {};
+
+ var srcOption = function (pscPackage) {
+ var srcPath = path.join('src', '**', '*.purs');
+
+ var bowerPath = path.join('bower_components', 'purescript-*', 'src', '**', '*.purs');
+
+ if (CACHE_VAR.srcOption.length > 0) {
+ return CACHE_VAR.srcOption;
+ } else if (pscPackage) {
+ var pscPackageCommand = 'psc-package';
+
+ var pscPackageArgs = ['sources'];
+
+ var loaderSrc = loaderOptions.src || [srcPath];
+
+ debug('psc-package %s %o', pscPackageCommand, pscPackageArgs);
+
+ var cmd = spawn(pscPackageCommand, pscPackageArgs);
+
+ if (cmd.error) {
+ throw new Error(cmd.error);
+ } else if (cmd.status !== 0) {
+ var error = cmd.stdout.toString();
+
+ throw new Error(error);
+ } else {
+ var result = cmd.stdout.toString().split(eol).filter(function (v) {
+ return v != '';
+ }).concat(loaderSrc);
+
+ debug('psc-package result: %o', result);
+
+ CACHE_VAR.srcOption = result;
+
+ return result;
+ }
+ } else {
+ var _result = loaderOptions.src || [bowerPath, srcPath];
+
+ CACHE_VAR.srcOption = _result;
+
+ return _result;
+ }
+ }(loaderOptions.pscPackage);
+
+ var options = Object.assign({
+ context: webpackContext,
+ psc: null,
+ pscArgs: {},
+ pscBundle: null,
+ pscBundleArgs: {},
+ pscIdeClient: null,
+ pscIdeClientArgs: {},
+ pscIdeServer: null,
+ pscIdeServerArgs: {},
+ pscIde: false,
+ pscIdeColors: loaderOptions.psc === 'psa',
+ pscPackage: false,
+ bundleOutput: 'output/bundle.js',
+ bundleNamespace: 'PS',
+ bundle: false,
+ warnings: true,
+ watch: false,
+ output: 'output',
+ src: []
+ }, loaderOptions, {
+ src: srcOption
+ });
+
+ if (!CACHE_VAR.installed) {
+ debugVerbose('installing purs-loader with options: %O', options);
+
+ CACHE_VAR.installed = true;
+
+ // invalidate loader CACHE_VAR when bundle is marked as invalid (in watch mode)
+ this._compiler.plugin('invalid', function () {
+ debugVerbose('invalidating loader CACHE_VAR');
+
+ CACHE_VAR = {
+ rebuild: options.pscIde,
+ deferred: [],
+ bundleModules: [],
+ ideServer: CACHE_VAR.ideServer,
+ psModuleMap: CACHE_VAR.psModuleMap,
+ warnings: [],
+ errors: [],
+ compilationStarted: false,
+ compilationFinished: false,
+ compilationFailed: false,
+ installed: CACHE_VAR.installed,
+ srcOption: []
+ };
+ });
+
+ // add psc warnings to webpack compilation warnings
+ this._compiler.plugin('after-compile', function (compilation, callback) {
+ CACHE_VAR.warnings.forEach(function (warning) {
+ compilation.warnings.push(warning);
+ });
+
+ CACHE_VAR.errors.forEach(function (error) {
+ compilation.errors.push(error);
+ });
+
+ callback();
+ });
+ }
+
+ var psModuleName = PsModuleMap.matchModule(source);
+
+ var psModule = {
+ name: psModuleName,
+ source: source,
+ load: function load(_ref) {
+ var js = _ref.js,
+ map = _ref.map;
+ return callback(null, js, map);
+ },
+ reject: function reject(error) {
+ return callback(error);
+ },
+ srcPath: this.resourcePath,
+ remainingRequest: loaderUtils.getRemainingRequest(this),
+ srcDir: path.dirname(this.resourcePath),
+ jsPath: path.resolve(path.join(options.output, psModuleName, 'index.js')),
+ options: options,
+ cache: CACHE_VAR,
+ emitWarning: function emitWarning(warning) {
+ if (options.warnings && warning.length) {
+ CACHE_VAR.warnings.push(warning);
+ }
+ },
+ emitError: function emitError(pscMessage) {
+ if (pscMessage.length) {
+ var modules = [];
+
+ var matchErrorsSeparator = /\n(?=Error)/;
+ var errors = pscMessage.split(matchErrorsSeparator);
+ var _iteratorNormalCompletion = true;
+ var _didIteratorError = false;
+ var _iteratorError = undefined;
+
+ try {
+ for (var _iterator = errors[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
+ var error = _step.value;
+
+ var matchErrLocation = /at (.+\.purs) line (\d+), column (\d+) - line (\d+), column (\d+)/;
+
+ var _ref2 = matchErrLocation.exec(error) || [],
+ _ref3 = _slicedToArray(_ref2, 2),
+ filename = _ref3[1];
+
+ if (!filename) continue;
+
+ var baseModulePath = path.join(_this.rootContext, filename);
+ _this.addDependency(baseModulePath);
+
+ var matchErrModuleName = /in module ((?:\w+\.)*\w+)/;
+
+ var _ref4 = matchErrModuleName.exec(error) || [],
+ _ref5 = _slicedToArray(_ref4, 2),
+ baseModuleName = _ref5[1];
+
+ if (!baseModuleName) continue;
+
+ var matchMissingModuleName = /Module ((?:\w+\.)*\w+) was not found/;
+ var matchMissingImportFromModuleName = /Cannot import value \w+ from module ((?:\w+\.)*\w+)/;
+ var _arr = [matchMissingModuleName, matchMissingImportFromModuleName];
+ for (var _i = 0; _i < _arr.length; _i++) {
+ var re = _arr[_i];
+ var _ref6 = re.exec(error) || [],
+ _ref7 = _slicedToArray(_ref6, 2),
+ targetModuleName = _ref7[1];
+
+ if (targetModuleName) {
+ var resolved = utils.resolvePursModule({
+ baseModulePath: baseModulePath,
+ baseModuleName: baseModuleName,
+ targetModuleName: targetModuleName
+ });
+ _this.addDependency(resolved);
+ }
+ }
+
+ var desc = {
+ name: baseModuleName,
+ filename: baseModulePath
+ };
+
+ if (typeof _this.describePscError === 'function') {
+ var _describePscError = _this.describePscError(error, desc),
+ _describePscError$dep = _describePscError.dependencies,
+ dependencies = _describePscError$dep === undefined ? [] : _describePscError$dep,
+ details = _describePscError.details;
+
+ var _iteratorNormalCompletion2 = true;
+ var _didIteratorError2 = false;
+ var _iteratorError2 = undefined;
+
+ try {
+
+ for (var _iterator2 = dependencies[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
+ var dep = _step2.value;
+
+ _this.addDependency(dep);
+ }
+ } catch (err) {
+ _didIteratorError2 = true;
+ _iteratorError2 = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion2 && _iterator2.return) {
+ _iterator2.return();
+ }
+ } finally {
+ if (_didIteratorError2) {
+ throw _iteratorError2;
+ }
+ }
+ }
+
+ Object.assign(desc, details);
+ }
+
+ modules.push(desc);
+ }
+ } catch (err) {
+ _didIteratorError = true;
+ _iteratorError = err;
+ } finally {
+ try {
+ if (!_iteratorNormalCompletion && _iterator.return) {
+ _iterator.return();
+ }
+ } finally {
+ if (_didIteratorError) {
+ throw _iteratorError;
+ }
+ }
+ }
+
+ CACHE_VAR.errors.push(new utils.PscError(pscMessage, modules));
+ }
+ }
+ };
+
+ debug('loading %s', psModule.name);
+
+ if (options.bundle) {
+ CACHE_VAR.bundleModules.push(psModule.name);
+ }
+
+ if (CACHE_VAR.rebuild) {
+ var connect = function connect() {
+ if (!CACHE_VAR.ideServer) {
+ CACHE_VAR.ideServer = true;
+
+ return ide.connect(psModule).then(function (ideServer) {
+ CACHE_VAR.ideServer = ideServer;
+ return psModule;
+ }).then(ide.loadWithRetry).catch(function (error) {
+ if (CACHE_VAR.ideServer.kill) {
+ debug('ide failed to initially load modules, stopping the ide server process');
+
+ CACHE_VAR.ideServer.kill();
+ }
+
+ CACHE_VAR.ideServer = null;
+
+ return Promise.reject(error);
+ });
+ } else {
+ return Promise.resolve(psModule);
+ }
+ };
+
+ var rebuild = function rebuild() {
+ return ide.rebuild(psModule).then(function () {
+ return toJavaScript(psModule).then(function (js) {
+ return sourceMaps(psModule, js);
+ }).then(psModule.load).catch(psModule.reject);
+ }).catch(function (error) {
+ if (error instanceof ide.UnknownModuleError) {
+ // Store the modules that trigger a recompile due to an
+ // unknown module error. We need to wait until compilation is
+ // done before loading these files.
+
+ CACHE_VAR.deferred.push(psModule);
+
+ if (!CACHE_VAR.compilationStarted) {
+ CACHE_VAR.compilationStarted = true;
+
+ return compile(psModule).then(function () {
+ CACHE_VAR.compilationFinished = true;
+ }).then(function () {
+ return Promise.map(CACHE_VAR.deferred, function (psModule) {
+ return ide.load(psModule).then(function () {
+ return toJavaScript(psModule);
+ }).then(function (js) {
+ return sourceMaps(psModule, js);
+ }).then(psModule.load);
+ });
+ }).catch(function (error) {
+ CACHE_VAR.compilationFailed = true;
+
+ CACHE_VAR.deferred[0].reject(error);
+
+ CACHE_VAR.deferred.slice(1).forEach(function (psModule) {
+ psModule.reject(new Error('purs-loader failed'));
+ });
+ });
+ } else if (CACHE_VAR.compilationFailed) {
+ CACHE_VAR.deferred.pop().reject(new Error('purs-loader failed'));
+ } else {
+ // The compilation has started. We must wait until it is
+ // done in order to ensure the module map contains all of
+ // the unknown modules.
+ }
+ } else {
+ debug('ide rebuild failed due to an unhandled error: %o', error);
+
+ psModule.reject(error);
+ }
+ });
+ };
+
+ connect().then(rebuild);
+ } else if (CACHE_VAR.compilationFinished) {
+ debugVerbose('compilation is already finished, loading module %s', psModule.name);
+
+ toJavaScript(psModule).then(function (js) {
+ return sourceMaps(psModule, js);
+ }).then(psModule.load).catch(psModule.reject);
+ } else {
+ // The compilation has not finished yet. We need to wait for
+ // compilation to finish before the loaders run so that references
+ // to compiled output are valid. Push the modules into the CACHE_VAR to
+ // be loaded once the complation is complete.
+
+ CACHE_VAR.deferred.push(psModule);
+
+ if (!CACHE_VAR.compilationStarted) {
+ CACHE_VAR.compilationStarted = true;
+
+ compile(psModule).then(function () {
+ CACHE_VAR.compilationFinished = true;
+ }).then(function () {
+ if (options.bundle) {
+ return bundle(options, CACHE_VAR.bundleModules);
+ }
+ }).then(function () {
+ return Promise.map(CACHE_VAR.deferred, function (psModule) {
+ return toJavaScript(psModule).then(function (js) {
+ return sourceMaps(psModule, js);
+ }).then(psModule.load);
+ });
+ }).catch(function (error) {
+ CACHE_VAR.compilationFailed = true;
+
+ CACHE_VAR.deferred[0].reject(error);
+
+ CACHE_VAR.deferred.slice(1).forEach(function (psModule) {
+ psModule.reject(new Error('purs-loader failed'));
+ });
+ });
+ } else if (CACHE_VAR.compilationFailed) {
+ CACHE_VAR.deferred.pop().reject(new Error('purs-loader failed'));
+ } else {
+ // The complation has started. Nothing to do but wait until it is
+ // done before loading all of the modules.
+ }
+ }
+};
\ No newline at end of file
--- /dev/null
+'use strict';
+
+var path = require('path');
+
+var Promise = require('bluebird');
+
+var fs = Promise.promisifyAll(require('fs'));
+
+var globby = require('globby');
+
+var debug = require('debug')('purs-loader');
+
+var srcModuleRegex = /(?:^|\n)module\s+([\w\.]+)/i;
+
+var importModuleRegex = /(?:^|\n)\s*import\s+([\w\.]+)/ig;
+
+module.exports.matchModule = function matchModule(str) {
+ var matches = str.match(srcModuleRegex);
+ return matches && matches[1];
+};
+
+module.exports.matchImports = function matchImports(str) {
+ var matches = str.match(importModuleRegex);
+ return (matches || []).map(function (a) {
+ return a.replace(/\n?\s*import\s+/i, '');
+ });
+};
+
+module.exports.makeMapEntry = function makeMapEntry(filePurs) {
+ var dirname = path.dirname(filePurs);
+
+ var basename = path.basename(filePurs, '.purs');
+
+ var fileJs = path.join(dirname, basename + '.js');
+
+ var result = Promise.props({
+ filePurs: fs.readFileAsync(filePurs, 'utf8'),
+ fileJs: fs.readFileAsync(fileJs, 'utf8').catch(function () {
+ return undefined;
+ })
+ }).then(function (fileMap) {
+ var sourcePurs = fileMap.filePurs;
+
+ var sourceJs = fileMap.fileJs;
+
+ var moduleName = module.exports.matchModule(sourcePurs);
+
+ var imports = module.exports.matchImports(sourcePurs);
+
+ var map = {};
+
+ map[moduleName] = map[moduleName] || {};
+
+ map[moduleName].src = path.resolve(filePurs);
+
+ map[moduleName].imports = imports;
+
+ if (sourceJs) {
+ map[moduleName].ffi = path.resolve(fileJs);
+ }
+
+ return map;
+ });
+
+ return result;
+};
+
+module.exports.makeMap = function makeMap(src) {
+ debug('loading PureScript source and FFI files from %o', src);
+
+ var globs = [].concat(src);
+
+ return globby(globs).then(function (paths) {
+ return Promise.all(paths.map(module.exports.makeMapEntry)).then(function (result) {
+ return result.reduce(Object.assign, {});
+ });
+ });
+};
\ No newline at end of file
--- /dev/null
+'use strict';
+
+var Promise = require('bluebird');
+
+var fs = require('fs');
+
+var path = require('path');
+
+var debug_ = require('debug');
+
+var debugVerbose = debug_('purs-loader:verbose');
+
+module.exports = function sourceMap(psModule, js) {
+ var options = psModule.options;
+
+ var jsPath = psModule.jsPath;
+
+ var srcPath = psModule.srcPath;
+
+ var source = psModule.source;
+
+ var remainingRequest = psModule.remainingRequest;
+
+ var sourceMapPath = path.join(path.dirname(jsPath), 'index.js.map');
+
+ var isSourceMapsEnabled = options.pscArgs && options.pscArgs.sourceMaps;
+
+ return new Promise(function (resolve, reject) {
+ if (!isSourceMapsEnabled) {
+ resolve({
+ js: js,
+ map: undefined
+ });
+ } else {
+ debugVerbose('loading source map %s', sourceMapPath);
+
+ fs.readFile(sourceMapPath, 'utf-8', function (error, result) {
+ if (error) {
+ reject(error);
+ } else {
+ try {
+ var map = Object.assign(JSON.parse(result), {
+ sources: [remainingRequest],
+ file: path.normalize(srcPath),
+ sourcesContent: [source]
+ });
+
+ var jsRemovedMapUrl = js.replace(/^\/\/# sourceMappingURL=[^\r\n]*/gm, '');
+
+ resolve({
+ js: jsRemovedMapUrl,
+ map: map
+ });
+ } catch (error) {
+ reject(error);
+ }
+ }
+ });
+ }
+ });
+};
\ No newline at end of file
--- /dev/null
+'use strict';
+
+var Promise = require('bluebird');
+
+var fs = Promise.promisifyAll(require('fs'));
+
+var path = require('path');
+
+var jsStringEscape = require('js-string-escape');
+
+var difference = require('lodash.difference');
+
+var debug_ = require('debug');
+
+var debug = debug_('purs-loader');
+
+var debugVerbose = debug_('purs-loader:verbose');
+
+var PsModuleMap = require('./purs-module-map');
+
+function updatePsModuleMap(psModule) {
+ var options = psModule.options;
+
+ var cache = psModule.cache;
+
+ var filePurs = psModule.srcPath;
+
+ if (!cache.psModuleMap) {
+ debugVerbose('module mapping does not exist - making a new module map');
+
+ cache.psModuleMap = PsModuleMap.makeMap(options.src);
+
+ return cache.psModuleMap;
+ } else {
+ debugVerbose('module mapping exists - updating module map for %s', filePurs);
+
+ cache.psModuleMap = cache.psModuleMap.then(function (psModuleMap) {
+ return PsModuleMap.makeMapEntry(filePurs).then(function (result) {
+ var map = Object.assign(psModuleMap, result);
+
+ return map;
+ });
+ });
+
+ return cache.psModuleMap;
+ }
+}
+
+// Reference the bundle.
+function makeBundleJS(psModule) {
+ var bundleOutput = psModule.options.bundleOutput;
+
+ var name = psModule.name;
+
+ var srcDir = psModule.srcDir;
+
+ var escaped = jsStringEscape(path.relative(srcDir, bundleOutput));
+
+ var result = 'module.exports = require("' + escaped + '")["' + name + '"]';
+
+ return Promise.resolve(result);
+}
+
+// Replace require paths to output files generated by psc with paths
+// to purescript sources, which are then also run through this loader.
+// Additionally, the imports replaced are tracked so that in the event
+// the compiler fails to compile the PureScript source, we can tack on
+// any new imports in order to allow webpack to watch the new files
+// before they have been successfully compiled.
+function makeJS(psModule, psModuleMap, js) {
+ var requireRE = /require\(['"]\.\.\/([\w\.]+)(?:\/index\.js)?['"]\)/g;
+
+ var foreignRE = /require\(['"]\.\/foreign(?:\.js)?['"]\)/g;
+
+ var name = psModule.name;
+
+ var imports = psModuleMap[name].imports;
+
+ var replacedImports = [];
+
+ var result = js.replace(requireRE, function (m, p1) {
+ var moduleValue = psModuleMap[p1];
+
+ if (!moduleValue) {
+ debug('module %s was not found in the map, replacing require with null', p1);
+
+ return 'null';
+ } else {
+ var escapedPath = jsStringEscape(moduleValue.src);
+
+ replacedImports.push(p1);
+
+ return 'require("' + escapedPath + '")';
+ }
+ }).replace(foreignRE, function () {
+ var escapedPath = jsStringEscape(psModuleMap[name].ffi);
+
+ return 'require("' + escapedPath + '")';
+ });
+
+ var additionalImports = difference(imports, replacedImports);
+
+ if (!additionalImports.length) {
+ return Promise.resolve(result);
+ } else {
+ debug('rebuilding module map due to additional imports for %s: %o', name, additionalImports);
+
+ psModule.cache.psModuleMap = null;
+
+ return updatePsModuleMap(psModule).then(function (updatedPsModuleMap) {
+ var additionalImportsResult = additionalImports.map(function (import_) {
+ var moduleValue = updatedPsModuleMap[import_];
+
+ if (!moduleValue) {
+ debug('module %s was not found in the map, skipping require', import_);
+
+ return null;
+ } else {
+ var escapedPath = jsStringEscape(moduleValue.src);
+
+ return 'var ' + import_.replace(/\./g, '_') + ' = require("' + escapedPath + '")';
+ }
+ }).filter(function (a) {
+ return a !== null;
+ }).join('\n');
+
+ return result + '\n' + additionalImportsResult;
+ });
+ }
+}
+
+module.exports = function toJavaScript(psModule) {
+ var options = psModule.options;
+
+ var cache = psModule.cache;
+
+ var bundlePath = path.resolve(options.bundleOutput);
+
+ var jsPath = options.bundle ? bundlePath : psModule.jsPath;
+
+ var js = fs.readFileAsync(jsPath, 'utf8').catch(function () {
+ return '';
+ });
+
+ var psModuleMap = updatePsModuleMap(psModule);
+
+ debugVerbose('loading JavaScript for %s', psModule.name);
+
+ return Promise.props({ js: js, psModuleMap: psModuleMap }).then(function (result) {
+ return options.bundle ? makeBundleJS(psModule) : makeJS(psModule, result.psModuleMap, result.js);
+ });
+};
\ No newline at end of file
--- /dev/null
+'use strict';
+
+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; }; }();
+
+function _toArray(arr) { return Array.isArray(arr) ? arr : Array.from(arr); }
+
+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); } }
+
+function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
+
+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; }
+
+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; }
+
+var path = require('path');
+
+exports.PscError = function (_Error) {
+ _inherits(PscError, _Error);
+
+ function PscError(message, modules) {
+ _classCallCheck(this, PscError);
+
+ var _this = _possibleConstructorReturn(this, (PscError.__proto__ || Object.getPrototypeOf(PscError)).call(this, message));
+
+ _this.modules = modules;
+ return _this;
+ }
+
+ _createClass(PscError, null, [{
+ key: 'name',
+ get: function get() {
+ return 'PscError';
+ }
+ }]);
+
+ return PscError;
+}(Error);
+
+var repeat = function repeat(value, times) {
+ return times <= 0 ? [] : [value].concat(_toConsumableArray(repeat(value, times - 1)));
+};
+var diffPursModuleNames = function diffPursModuleNames(from, target, parts) {
+ if (!from.length) return parts.concat(target);
+ if (!target.length) return parts.concat(repeat('..', from.length));
+
+ var _from = _toArray(from),
+ head_from = _from[0],
+ tail_from = _from.slice(1);
+
+ var _target = _toArray(target),
+ head_target = _target[0],
+ tail_target = _target.slice(1);
+
+ return head_from === head_target ? diffPursModuleNames(tail_from, tail_target, parts) : parts.concat(repeat('..', from.length), target);
+};
+exports.resolvePursModule = function (_ref) {
+ var baseModulePath = _ref.baseModulePath,
+ baseModuleName = _ref.baseModuleName,
+ targetModuleName = _ref.targetModuleName;
+
+ var parts = diffPursModuleNames(baseModuleName.split('.'), targetModuleName.split('.'), []);
+ return parts.length ? path.resolve(baseModulePath, path.join.apply(path, _toConsumableArray(parts)) + '.purs') : baseModulePath;
+};
\ No newline at end of file