]>
git.immae.eu Git - github/fretlink/purs-loader.git/blob - src/to-javascript.js
3 const Promise
= require('bluebird');
5 const fs
= Promise
.promisifyAll(require('fs'));
7 const path
= require('path');
9 const jsStringEscape
= require('js-string-escape');
11 const difference
= require('lodash.difference');
13 const debug_
= require('debug');
15 const debug
= debug_('purs-loader');
17 const debugVerbose
= debug_('purs-loader:verbose');
19 const PsModuleMap
= require('./PsModuleMap');
21 function updatePsModuleMap(psModule
) {
22 const options
= psModule
.options
;
24 const cache
= psModule
.cache
;
26 const filePurs
= psModule
.srcPath
;
28 if (!cache
.psModuleMap
) {
29 debug('module mapping does not exist');
31 return PsModuleMap
.makeMap(options
.src
).then(map
=> {
32 cache
.psModuleMap
= map
;
33 return cache
.psModuleMap
;
37 return PsModuleMap
.makeMapEntry(filePurs
).then(result
=> {
38 const map
= Object
.assign(cache
.psModuleMap
, result
);
40 cache
.psModuleMap
= map
;
42 return cache
.psModuleMap
;
47 // Reference the bundle.
48 function makeBundleJS(psModule
) {
49 const bundleOutput
= psModule
.options
.bundleOutput
;
51 const name
= psModule
.name
;
53 const srcDir
= psModule
.srcDir
;
55 const escaped
= jsStringEscape(path
.relative(srcDir
, bundleOutput
));
57 const result
= `module.exports = require("${escaped}")["${name}"]`;
62 // Replace require paths to output files generated by psc with paths
63 // to purescript sources, which are then also run through this loader.
64 // Additionally, the imports replaced are tracked so that in the event
65 // the compiler fails to compile the PureScript source, we can tack on
66 // any new imports in order to allow webpack to watch the new files
67 // before they have been successfully compiled.
68 function makeJS(psModule
, psModuleMap
, js
) {
69 const requireRE
= /require\(['"]\.\.\/([\w\.]+)['"]\)/g;
71 const foreignRE
= /require\(['"]\.\/foreign['"]\)/g;
73 const name
= psModule
.name
;
75 const imports
= psModuleMap
[name
].imports
;
77 var replacedImports
= [];
80 .replace(requireRE
, (m
, p1
) => {
81 const moduleValue
= psModuleMap
[p1
];
84 debug('module %s was not found in the map, replacing require with null', p1
);
89 const escapedPath
= jsStringEscape(moduleValue
.src
);
91 replacedImports
.push(p1
);
93 return `require("${escapedPath}")`;
96 .replace(foreignRE
, () => {
97 const escapedPath
= jsStringEscape(psModuleMap
[name
].ffi
);
99 return `require("${escapedPath}")`;
103 const additionalImports
= difference(imports
, replacedImports
);
105 if (additionalImports
.length
) {
106 debugVerbose('additional imports for %s: %o', name
, additionalImports
);
109 const additionalImportsResult
= additionalImports
.map(import_
=> {
110 const moduleValue
= psModuleMap
[import_
];
113 debug('module %s was not found in the map, skipping require', import_
);
118 const escapedPath
= jsStringEscape(moduleValue
.src
);
120 return `var ${import_.replace(/\./g, '_')} = require("${escapedPath}")`;
122 }).filter(a
=> a
!== null).join('\n');
124 const result_
= result
+ (additionalImports
.length
? '\n' + additionalImportsResult : '');
129 module
.exports
= function toJavaScript(psModule
) {
130 const options
= psModule
.options
;
132 const cache
= psModule
.cache
;
134 const bundlePath
= path
.resolve(options
.bundleOutput
);
136 const jsPath
= options
.bundle
? bundlePath : psModule
.jsPath
;
138 const js
= fs
.readFileAsync(jsPath
, 'utf8').catch(() => '');
140 const psModuleMap
= updatePsModuleMap(psModule
);
142 debugVerbose('loading JavaScript for %s', psModule
.name
);
144 return Promise
.props({js: js
, psModuleMap: psModuleMap
}).then(result
=>
146 makeBundleJS(psModule
) :
147 makeJS(psModule
, result
.psModuleMap
, result
.js
)