aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--index.js172
1 files 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 @@
1var cp = require('child_process') 1'use strict';
2 , path = require('path') 2
3 , fs = require('fs') 3var os = require('os');
4 , glob = require('glob') 4
5 , lodash = require('lodash') 5var cp = require('child_process');
6 , chalk = require('chalk') 6
7 , lu = require('loader-utils') 7var path = require('path')
8 , cwd = process.cwd() 8
9 , MODULE_RE = /^module\s+([\w\.]+)\s+/i 9var fs = require('fs');
10 , BOWER_PATTERN = path.join('bower_components', 'purescript-*', 'src') 10
11 , PSC_MAKE = 'psc-make' 11var glob = require('glob');
12 , OUTPUT = 'output' 12
13 , OPTIONS = { 13var lodash = require('lodash');
14 'no-prelude': '--no-prelude', 14
15 'no-opts': '--no-opts', 15var chalk = require('chalk');
16 'no-magic-do': '--no-magic-do', 16
17 'no-tco': '--no-tco', 17var lu = require('loader-utils');
18 'verbose-errors': '--verbose-errors', 18
19 'output': '--output' 19var cwd = process.cwd();
20 } 20
21; 21var MODULE_RE = /(?:^|\n)module\s+([\w\.]+)/i;
22
23var IMPORT_RE = /^\s*import\s+(?:qualified\s+)?([\w\.]+)/i;
24
25var BOWER_PATTERN = path.join('bower_components', 'purescript-*', 'src');
26
27var PSC_MAKE = 'psc-make';
28
29var OUTPUT = 'output';
30
31var OPTIONS = {
32 'no-prelude': '--no-prelude',
33 'no-opts': '--no-opts',
34 'no-magic-do': '--no-magic-do',
35 'no-tco': '--no-tco',
36 'verbose-errors': '--verbose-errors',
37 'output': '--output'
38};
22 39
23function pattern(root) { 40function pattern(root) {
24 var as = [ BOWER_PATTERN, root ]; 41 var as = [ BOWER_PATTERN, root ];
25 return path.join('{' + as.join(',') + '}', '**', '*.purs'); 42 return path.join('{' + as.join(',') + '}', '**', '*.purs');
26} 43}
27 44
28module.exports = function(source){ 45function mkOptions(query) {
29 var callback = this.async() 46 return lodash.foldl(lodash.keys(query), function(acc, k){
30 , request = lu.getRemainingRequest(this) 47 var h = function(v){return acc.concat(query[k] && OPTIONS[k] ? [v] : []);}
31 , root = path.dirname(path.relative(cwd, request)) 48 if (k === OUTPUT) return h(OPTIONS[k] + '=' + query[k]);
32 , query = lu.parseQuery(this.query) 49 else return h(OPTIONS[k]);
33 , opts = lodash.foldl(lodash.keys(query), function(acc, k){ 50 }, []);
34 var h = function(v){return acc.concat(query[k] && OPTIONS[k] ? [v] : []);} 51}
35 if (k === OUTPUT) return h(OPTIONS[k] + '=' + query[k]); 52
36 else return h(OPTIONS[k]); 53function mkGraph(files) {
54 var graph = {};
55
56 files.forEach(function(file){
57 var source = fs.readFileSync(file, {encoding: 'utf-8'});
58
59 var result = MODULE_RE.exec(source);
60
61 var module = result ? result[1] : null;
62
63 var imports =
64 lodash.foldl(source.split(os.EOL), function(b, a){
65 var result = IMPORT_RE.exec(a);
66 if (result) b.push(result[1]);
67 return b;
37 }, []) 68 }, [])
38 ; 69 ;
70
71 if (module) {
72 graph[module] = {
73 file: file,
74 imports: imports || []
75 };
76 }
77 });
78
79 return graph;
80}
81
82function findDeps(graph, module) {
83 function go(acc, module){
84 var node = graph[module];
85
86 var imports = node && node.imports;
87
88 if (lodash.isEmpty(imports)) return acc;
89 else {
90 var deps =
91 lodash.map(imports, function(i){
92 return go(acc.concat(imports), i);
93 })
94 ;
95 return lodash.flatten(deps);
96 }
97 }
98
99 return lodash.unique(go([], module));
100}
101
102function loader(source) {
103 this.cacheable && this.cacheable();
104
105 this.clearDependencies();
106
107 this.addDependency(this.resourcePath);
108
109 var callback = this.async();
110
111 var request = lu.getRemainingRequest(this)
112
113 var root = path.dirname(path.relative(cwd, request));
114
115 var query = lu.parseQuery(this.query);
116
117 var opts = mkOptions(query);
118
119 var that = this;
120
39 glob(pattern(root), function(e, files){ 121 glob(pattern(root), function(e, files){
40 if (e !== null) callback(e); 122 if (e !== null) callback(e);
41 else { 123 else {
42 var cmd = cp.spawn(PSC_MAKE, opts.concat(files)); 124 var cmd = cp.spawn(PSC_MAKE, opts.concat(files));
125
126 var graph = mkGraph(files);
127
43 cmd.on('close', function(e){ 128 cmd.on('close', function(e){
44 if (e) callback(e); 129 if (e) callback(e);
45 else { 130 else {
46 var result = MODULE_RE.exec(source); 131 var result = MODULE_RE.exec(source);
47 var module = result.length > 1 ? result[1] : ''; 132
48 fs.readFile(path.join(query[OUTPUT] || OUTPUT, module, 'index.js'), 'utf-8', function(e, output){ 133 var module = result ? result[1] : '';
134
135 var dependencies = findDeps(graph, module);
136
137 var indexPath = path.join(query[OUTPUT] || OUTPUT, module, 'index.js');
138
139 fs.readFile(indexPath, 'utf-8', function(e, output){
49 if (e) callback(e); 140 if (e) callback(e);
50 else callback(e, output); 141 else {
142 dependencies.forEach(function(dep){
143 var module = graph[dep];
144 if (module) that.addDependency(path.resolve(module.file));
145 });
146
147 callback(null, output);
148 }
51 }); 149 });
52 } 150 }
53 }); 151 });
152
54 cmd.stdout.on('data', function(stdout){ 153 cmd.stdout.on('data', function(stdout){
55 console.log('Stdout from \'' + chalk.cyan(PSC_MAKE) + '\'\n' + chalk.magenta(stdout)); 154 console.log('Stdout from \'' + chalk.cyan(PSC_MAKE) + '\'\n' + chalk.magenta(stdout));
56 }); 155 });
156
57 cmd.stderr.on('data', function(stderr){ 157 cmd.stderr.on('data', function(stderr){
58 console.log('Stderr from \'' + chalk.cyan(PSC_MAKE) + '\'\n' + chalk.magenta(stderr)); 158 console.log('Stderr from \'' + chalk.cyan(PSC_MAKE) + '\'\n' + chalk.magenta(stderr));
59 }); 159 });
60 } 160 }
61 }); 161 });
62}; 162}
163
164module.exports = loader;