]>
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('./purs-module-map');
21 function updatePsModuleMap(psModule
) {
22 const options
= psModule
.options
;
24 const cache
= psModule
.cache
;
26 const filePurs
= psModule
.srcPath
;
28 if (!cache
.psModuleMap
) {
29 debugVerbose('module mapping does not exist - making a new module map');
31 cache
.psModuleMap
= PsModuleMap
.makeMap(options
.src
);
33 return cache
.psModuleMap
;
36 debugVerbose('module mapping exists - updating module map for %s', filePurs
);
38 cache
.psModuleMap
= cache
.psModuleMap
.then(psModuleMap
=>
39 PsModuleMap
.makeMapEntry(filePurs
).then(result
=> {
40 const map
= Object
.assign(psModuleMap
, result
);
46 return cache
.psModuleMap
;
50 // Reference the bundle.
51 function makeBundleJS(psModule
) {
52 const bundleOutput
= psModule
.options
.bundleOutput
;
54 const name
= psModule
.name
;
56 const srcDir
= psModule
.srcDir
;
58 const escaped
= jsStringEscape(path
.relative(srcDir
, bundleOutput
));
60 const result
= `module.exports = require("${escaped}")["${name}"]`;
62 return Promise
.resolve(result
);
65 // Replace require paths to output files generated by psc with paths
66 // to purescript sources, which are then also run through this loader.
67 // Additionally, the imports replaced are tracked so that in the event
68 // the compiler fails to compile the PureScript source, we can tack on
69 // any new imports in order to allow webpack to watch the new files
70 // before they have been successfully compiled.
71 function makeJS(psModule
, psModuleMap
, js
) {
72 const requireRE
= /require\(['"]\.\.\/([\w\.]+)(?:\/index\.js)?['"]\)/g;
74 const foreignRE
= /require\(['"]\.\/foreign(?:\.js)?['"]\)/g;
76 const name
= psModule
.name
;
78 const imports
= psModuleMap
[name
].imports
;
80 var replacedImports
= [];
83 .replace(requireRE
, (m
, p1
) => {
84 const moduleValue
= psModuleMap
[p1
];
87 debug('module %s was not found in the map, replacing require with null', p1
);
92 const escapedPath
= jsStringEscape(moduleValue
.src
);
94 replacedImports
.push(p1
);
96 return `require("${escapedPath}")`;
99 .replace(foreignRE
, () => {
100 const escapedPath
= jsStringEscape(psModuleMap
[name
].ffi
);
102 return `require("${escapedPath}")`;
106 const additionalImports
= difference(imports
, replacedImports
);
108 if (!additionalImports
.length
) {
109 return Promise
.resolve(result
);
112 const missingImports
= additionalImports
.filter(moduleName
=>
113 !psModuleMap
[moduleName
] && moduleName
.split('.')[0] !== 'Prim'
116 let updatingPsModuleMap
;
117 if (missingImports
.length
> 0) {
118 debug('rebuilding module map due to missing imports for %s: %o', name
, missingImports
);
119 psModule
.cache
.psModuleMap
= null;
120 updatingPsModuleMap
= updatePsModuleMap(psModule
);
122 updatingPsModuleMap
= Promise
.resolve(psModuleMap
);
125 return updatingPsModuleMap
.then(updatedPsModuleMap
=> {
126 const missingImportsResult
= missingImports
.map(import_
=> {
127 const moduleValue
= updatedPsModuleMap
[import_
];
130 debug('module %s was not found in the map, skipping require', import_
);
135 const escapedPath
= jsStringEscape(moduleValue
.src
);
137 return `var ${import_.replace(/\./g, '_')} = require("${escapedPath}")`;
139 }).filter(a
=> a
!== null).join('\n');
141 return result
+ '\n' + missingImportsResult
;
146 module
.exports
= function toJavaScript(psModule
) {
147 const options
= psModule
.options
;
149 const cache
= psModule
.cache
;
151 const bundlePath
= path
.resolve(options
.bundleOutput
);
153 const jsPath
= options
.bundle
? bundlePath : psModule
.jsPath
;
155 const js
= fs
.readFileAsync(jsPath
, 'utf8').catch(() => '');
157 const psModuleMap
= updatePsModuleMap(psModule
);
159 debugVerbose('loading JavaScript for %s', psModule
.name
);
161 return Promise
.props({js: js
, psModuleMap: psModuleMap
}).then(result
=>
163 makeBundleJS(psModule
) :
164 makeJS(psModule
, result
.psModuleMap
, result
.js
)