]> git.immae.eu Git - github/fretlink/purs-loader.git/commitdiff
Adding purescript imports as dependencies
authoreric thul <thul.eric@gmail.com>
Thu, 2 Apr 2015 22:18:36 +0000 (18:18 -0400)
committereric thul <thul.eric@gmail.com>
Sun, 12 Apr 2015 15:12:08 +0000 (11:12 -0400)
The purescript imports are added as webpack dependencies in order to
rebuild in watch mode when one of the files has changed.

Resolves #4 regarding watching purescript files.

index.js

index 4a74d154ad45a16ac73237279bb06284d3f8817c..449c841ac558d0aa0e4f2b8d4087499a191fa3d6 100644 (file)
--- a/index.js
+++ b/index.js
-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;