]>
Commit | Line | Data |
---|---|---|
9d38968b | 1 | 'use strict'; |
2 | ||
3 | var os = require('os'); | |
4 | ||
5 | var cp = require('child_process'); | |
6 | ||
7 | var path = require('path') | |
8 | ||
9 | var fs = require('fs'); | |
10 | ||
11 | var glob = require('glob'); | |
12 | ||
13 | var lodash = require('lodash'); | |
14 | ||
15 | var chalk = require('chalk'); | |
16 | ||
17 | var lu = require('loader-utils'); | |
18 | ||
19 | var cwd = process.cwd(); | |
20 | ||
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 | }; | |
a42f24b8 | 39 | |
a6986505 | 40 | function pattern(root) { |
41 | var as = [ BOWER_PATTERN, root ]; | |
42 | return path.join('{' + as.join(',') + '}', '**', '*.purs'); | |
43 | } | |
44 | ||
9d38968b | 45 | function mkOptions(query) { |
46 | return lodash.foldl(lodash.keys(query), function(acc, k){ | |
47 | var h = function(v){return acc.concat(query[k] && OPTIONS[k] ? [v] : []);} | |
48 | if (k === OUTPUT) return h(OPTIONS[k] + '=' + query[k]); | |
49 | else return h(OPTIONS[k]); | |
50 | }, []); | |
51 | } | |
52 | ||
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; | |
a42f24b8 | 68 | }, []) |
9d38968b | 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 | ||
a6986505 | 121 | glob(pattern(root), function(e, files){ |
a42f24b8 | 122 | if (e !== null) callback(e); |
123 | else { | |
124 | var cmd = cp.spawn(PSC_MAKE, opts.concat(files)); | |
9d38968b | 125 | |
126 | var graph = mkGraph(files); | |
127 | ||
a42f24b8 | 128 | cmd.on('close', function(e){ |
129 | if (e) callback(e); | |
130 | else { | |
a92aa714 | 131 | var result = MODULE_RE.exec(source); |
9d38968b | 132 | |
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){ | |
a42f24b8 | 140 | if (e) callback(e); |
9d38968b | 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 | } | |
a42f24b8 | 149 | }); |
150 | } | |
151 | }); | |
9d38968b | 152 | |
a42f24b8 | 153 | cmd.stdout.on('data', function(stdout){ |
154 | console.log('Stdout from \'' + chalk.cyan(PSC_MAKE) + '\'\n' + chalk.magenta(stdout)); | |
155 | }); | |
9d38968b | 156 | |
a42f24b8 | 157 | cmd.stderr.on('data', function(stderr){ |
158 | console.log('Stderr from \'' + chalk.cyan(PSC_MAKE) + '\'\n' + chalk.magenta(stderr)); | |
159 | }); | |
160 | } | |
161 | }); | |
9d38968b | 162 | } |
163 | ||
164 | module.exports = loader; |