aboutsummaryrefslogtreecommitdiffhomepage
path: root/lib/to-javascript.js
diff options
context:
space:
mode:
Diffstat (limited to 'lib/to-javascript.js')
-rw-r--r--lib/to-javascript.js152
1 files changed, 152 insertions, 0 deletions
diff --git a/lib/to-javascript.js b/lib/to-javascript.js
new file mode 100644
index 0000000..ce49704
--- /dev/null
+++ b/lib/to-javascript.js
@@ -0,0 +1,152 @@
1'use strict';
2
3var Promise = require('bluebird');
4
5var fs = Promise.promisifyAll(require('fs'));
6
7var path = require('path');
8
9var jsStringEscape = require('js-string-escape');
10
11var difference = require('lodash.difference');
12
13var debug_ = require('debug');
14
15var debug = debug_('purs-loader');
16
17var debugVerbose = debug_('purs-loader:verbose');
18
19var PsModuleMap = require('./purs-module-map');
20
21function updatePsModuleMap(psModule) {
22 var options = psModule.options;
23
24 var cache = psModule.cache;
25
26 var filePurs = psModule.srcPath;
27
28 if (!cache.psModuleMap) {
29 debugVerbose('module mapping does not exist - making a new module map');
30
31 cache.psModuleMap = PsModuleMap.makeMap(options.src);
32
33 return cache.psModuleMap;
34 } else {
35 debugVerbose('module mapping exists - updating module map for %s', filePurs);
36
37 cache.psModuleMap = cache.psModuleMap.then(function (psModuleMap) {
38 return PsModuleMap.makeMapEntry(filePurs).then(function (result) {
39 var map = Object.assign(psModuleMap, result);
40
41 return map;
42 });
43 });
44
45 return cache.psModuleMap;
46 }
47}
48
49// Reference the bundle.
50function makeBundleJS(psModule) {
51 var bundleOutput = psModule.options.bundleOutput;
52
53 var name = psModule.name;
54
55 var srcDir = psModule.srcDir;
56
57 var escaped = jsStringEscape(path.relative(srcDir, bundleOutput));
58
59 var result = 'module.exports = require("' + escaped + '")["' + name + '"]';
60
61 return Promise.resolve(result);
62}
63
64// Replace require paths to output files generated by psc with paths
65// to purescript sources, which are then also run through this loader.
66// Additionally, the imports replaced are tracked so that in the event
67// the compiler fails to compile the PureScript source, we can tack on
68// any new imports in order to allow webpack to watch the new files
69// before they have been successfully compiled.
70function makeJS(psModule, psModuleMap, js) {
71 var requireRE = /require\(['"]\.\.\/([\w\.]+)(?:\/index\.js)?['"]\)/g;
72
73 var foreignRE = /require\(['"]\.\/foreign(?:\.js)?['"]\)/g;
74
75 var name = psModule.name;
76
77 var imports = psModuleMap[name].imports;
78
79 var replacedImports = [];
80
81 var result = js.replace(requireRE, function (m, p1) {
82 var moduleValue = psModuleMap[p1];
83
84 if (!moduleValue) {
85 debug('module %s was not found in the map, replacing require with null', p1);
86
87 return 'null';
88 } else {
89 var escapedPath = jsStringEscape(moduleValue.src);
90
91 replacedImports.push(p1);
92
93 return 'require("' + escapedPath + '")';
94 }
95 }).replace(foreignRE, function () {
96 var escapedPath = jsStringEscape(psModuleMap[name].ffi);
97
98 return 'require("' + escapedPath + '")';
99 });
100
101 var additionalImports = difference(imports, replacedImports);
102
103 if (!additionalImports.length) {
104 return Promise.resolve(result);
105 } else {
106 debug('rebuilding module map due to additional imports for %s: %o', name, additionalImports);
107
108 psModule.cache.psModuleMap = null;
109
110 return updatePsModuleMap(psModule).then(function (updatedPsModuleMap) {
111 var additionalImportsResult = additionalImports.map(function (import_) {
112 var moduleValue = updatedPsModuleMap[import_];
113
114 if (!moduleValue) {
115 debug('module %s was not found in the map, skipping require', import_);
116
117 return null;
118 } else {
119 var escapedPath = jsStringEscape(moduleValue.src);
120
121 return 'var ' + import_.replace(/\./g, '_') + ' = require("' + escapedPath + '")';
122 }
123 }).filter(function (a) {
124 return a !== null;
125 }).join('\n');
126
127 return result + '\n' + additionalImportsResult;
128 });
129 }
130}
131
132module.exports = function toJavaScript(psModule) {
133 var options = psModule.options;
134
135 var cache = psModule.cache;
136
137 var bundlePath = path.resolve(options.bundleOutput);
138
139 var jsPath = options.bundle ? bundlePath : psModule.jsPath;
140
141 var js = fs.readFileAsync(jsPath, 'utf8').catch(function () {
142 return '';
143 });
144
145 var psModuleMap = updatePsModuleMap(psModule);
146
147 debugVerbose('loading JavaScript for %s', psModule.name);
148
149 return Promise.props({ js: js, psModuleMap: psModuleMap }).then(function (result) {
150 return options.bundle ? makeBundleJS(psModule) : makeJS(psModule, result.psModuleMap, result.js);
151 });
152}; \ No newline at end of file