diff options
-rw-r--r-- | index.js | 172 |
1 files changed, 137 insertions, 35 deletions
@@ -1,62 +1,164 @@ | |||
1 | var cp = require('child_process') | 1 | 'use strict'; |
2 | , path = require('path') | 2 | |
3 | , fs = require('fs') | 3 | var os = require('os'); |
4 | , glob = require('glob') | 4 | |
5 | , lodash = require('lodash') | 5 | var cp = require('child_process'); |
6 | , chalk = require('chalk') | 6 | |
7 | , lu = require('loader-utils') | 7 | var path = require('path') |
8 | , cwd = process.cwd() | 8 | |
9 | , MODULE_RE = /^module\s+([\w\.]+)\s+/i | 9 | var fs = require('fs'); |
10 | , BOWER_PATTERN = path.join('bower_components', 'purescript-*', 'src') | 10 | |
11 | , PSC_MAKE = 'psc-make' | 11 | var glob = require('glob'); |
12 | , OUTPUT = 'output' | 12 | |
13 | , OPTIONS = { | 13 | var lodash = require('lodash'); |
14 | 'no-prelude': '--no-prelude', | 14 | |
15 | 'no-opts': '--no-opts', | 15 | var chalk = require('chalk'); |
16 | 'no-magic-do': '--no-magic-do', | 16 | |
17 | 'no-tco': '--no-tco', | 17 | var lu = require('loader-utils'); |
18 | 'verbose-errors': '--verbose-errors', | 18 | |
19 | 'output': '--output' | 19 | var cwd = process.cwd(); |
20 | } | 20 | |
21 | ; | 21 | var MODULE_RE = /(?:^|\n)module\s+([\w\.]+)/i; |
22 | |||
23 | var IMPORT_RE = /^\s*import\s+(?:qualified\s+)?([\w\.]+)/i; | ||
24 | |||
25 | var BOWER_PATTERN = path.join('bower_components', 'purescript-*', 'src'); | ||
26 | |||
27 | var PSC_MAKE = 'psc-make'; | ||
28 | |||
29 | var OUTPUT = 'output'; | ||
30 | |||
31 | var 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 | ||
23 | function pattern(root) { | 40 | function 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 | ||
28 | module.exports = function(source){ | 45 | function 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]); | 53 | function 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 | |||
82 | function 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 | |||
102 | function 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 | |||
164 | module.exports = loader; | ||