From 9d38968bbe4bbf54e2ca836d9a1550d74d4da703 Mon Sep 17 00:00:00 2001 From: eric thul Date: Thu, 2 Apr 2015 18:18:36 -0400 Subject: [PATCH 1/1] Adding purescript imports as dependencies 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 | 172 ++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 137 insertions(+), 35 deletions(-) diff --git a/index.js b/index.js index 4a74d15..449c841 100644 --- a/index.js +++ b/index.js @@ -1,62 +1,164 @@ -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; -- 2.41.0