-var cp = require('child_process')
- , path = require('path')
- , fs = require('fs')
- , glob = require('glob')
- , lodash = require('lodash')
- , chalk = require('chalk')
- , lu = require('loader-utils')
- , cwd = process.cwd()
- , MODULE_RE = /^module\s+([\w\.]+)\s+/i
- , BOWER_PATTERN = path.join('bower_components', 'purescript-*', 'src')
- , PSC_MAKE = 'psc-make'
- , OUTPUT = 'output'
- , OPTIONS = {
- 'no-prelude': '--no-prelude',
- 'no-opts': '--no-opts',
- 'no-magic-do': '--no-magic-do',
- 'no-tco': '--no-tco',
- 'verbose-errors': '--verbose-errors',
- 'output': '--output'
- }
-;
+'use strict';
+
+var os = require('os');
+
+var cp = require('child_process');
+
+var path = require('path')
+
+var fs = require('fs');
+
+var glob = require('glob');
+
+var lodash = require('lodash');
+
+var chalk = require('chalk');
+
+var lu = require('loader-utils');
+
+var cwd = process.cwd();
+
+var MODULE_RE = /(?:^|\n)module\s+([\w\.]+)/i;
+
+var IMPORT_RE = /^\s*import\s+(?:qualified\s+)?([\w\.]+)/i;
+
+var BOWER_PATTERN = path.join('bower_components', 'purescript-*', 'src');
+
+var PSC_MAKE = 'psc-make';
+
+var OUTPUT = 'output';
+
+var OPTIONS = {
+ 'no-prelude': '--no-prelude',
+ 'no-opts': '--no-opts',
+ 'no-magic-do': '--no-magic-do',
+ 'no-tco': '--no-tco',
+ 'verbose-errors': '--verbose-errors',
+ 'output': '--output'
+};
function pattern(root) {
var as = [ BOWER_PATTERN, root ];
return path.join('{' + as.join(',') + '}', '**', '*.purs');
}
-module.exports = function(source){
- var callback = this.async()
- , request = lu.getRemainingRequest(this)
- , root = path.dirname(path.relative(cwd, request))
- , query = lu.parseQuery(this.query)
- , opts = lodash.foldl(lodash.keys(query), function(acc, k){
- var h = function(v){return acc.concat(query[k] && OPTIONS[k] ? [v] : []);}
- if (k === OUTPUT) return h(OPTIONS[k] + '=' + query[k]);
- else return h(OPTIONS[k]);
+function mkOptions(query) {
+ return lodash.foldl(lodash.keys(query), function(acc, k){
+ var h = function(v){return acc.concat(query[k] && OPTIONS[k] ? [v] : []);}
+ if (k === OUTPUT) return h(OPTIONS[k] + '=' + query[k]);
+ else return h(OPTIONS[k]);
+ }, []);
+}
+
+function mkGraph(files) {
+ var graph = {};
+
+ files.forEach(function(file){
+ var source = fs.readFileSync(file, {encoding: 'utf-8'});
+
+ var result = MODULE_RE.exec(source);
+
+ var module = result ? result[1] : null;
+
+ var imports =
+ lodash.foldl(source.split(os.EOL), function(b, a){
+ var result = IMPORT_RE.exec(a);
+ if (result) b.push(result[1]);
+ return b;
}, [])
- ;
+ ;
+
+ if (module) {
+ graph[module] = {
+ file: file,
+ imports: imports || []
+ };
+ }
+ });
+
+ return graph;
+}
+
+function findDeps(graph, module) {
+ function go(acc, module){
+ var node = graph[module];
+
+ var imports = node && node.imports;
+
+ if (lodash.isEmpty(imports)) return acc;
+ else {
+ var deps =
+ lodash.map(imports, function(i){
+ return go(acc.concat(imports), i);
+ })
+ ;
+ return lodash.flatten(deps);
+ }
+ }
+
+ return lodash.unique(go([], module));
+}
+
+function loader(source) {
+ this.cacheable && this.cacheable();
+
+ this.clearDependencies();
+
+ this.addDependency(this.resourcePath);
+
+ var callback = this.async();
+
+ var request = lu.getRemainingRequest(this)
+
+ var root = path.dirname(path.relative(cwd, request));
+
+ var query = lu.parseQuery(this.query);
+
+ var opts = mkOptions(query);
+
+ var that = this;
+
glob(pattern(root), function(e, files){
if (e !== null) callback(e);
else {
var cmd = cp.spawn(PSC_MAKE, opts.concat(files));
+
+ var graph = mkGraph(files);
+
cmd.on('close', function(e){
if (e) callback(e);
else {
var result = MODULE_RE.exec(source);
- var module = result.length > 1 ? result[1] : '';
- fs.readFile(path.join(query[OUTPUT] || OUTPUT, module, 'index.js'), 'utf-8', function(e, output){
+
+ var module = result ? result[1] : '';
+
+ var dependencies = findDeps(graph, module);
+
+ var indexPath = path.join(query[OUTPUT] || OUTPUT, module, 'index.js');
+
+ fs.readFile(indexPath, 'utf-8', function(e, output){
if (e) callback(e);
- else callback(e, output);
+ else {
+ dependencies.forEach(function(dep){
+ var module = graph[dep];
+ if (module) that.addDependency(path.resolve(module.file));
+ });
+
+ callback(null, output);
+ }
});
}
});
+
cmd.stdout.on('data', function(stdout){
console.log('Stdout from \'' + chalk.cyan(PSC_MAKE) + '\'\n' + chalk.magenta(stdout));
});
+
cmd.stderr.on('data', function(stderr){
console.log('Stderr from \'' + chalk.cyan(PSC_MAKE) + '\'\n' + chalk.magenta(stderr));
});
}
});
-};
+}
+
+module.exports = loader;