3 const debug
= require('debug')('purs-loader')
5 const loaderUtils
= require('loader-utils')
7 const Promise
= require('bluebird')
9 const path
= require('path')
11 const PsModuleMap
= require('./purs-module-map');
13 const compile
= require('./compile');
15 const bundle
= require('./bundle');
17 const ide
= require('./ide');
19 const toJavaScript
= require('./to-javascript');
21 const dargs
= require('./dargs');
23 const spawn
= require('cross-spawn').sync
25 const eol
= require('os').EOL
27 module
.exports
= function purescriptLoader(source
, map
) {
28 const callback
= this.async()
29 const config
= this.options
30 const query
= loaderUtils
.getOptions(this) || {}
31 const webpackOptions
= this.options
.purescriptLoader
|| {}
33 const depsPaths
= (pscPackage
=> {
35 debug('calling psc-package...')
37 return spawn('psc-package', ['sources']).stdout
.toString().split(eol
).filter(v
=> v
!= '')
40 return [ path
.join('bower_components', 'purescript-*', 'src', '**', '*.purs') ]
44 let options
= Object
.assign(webpackOptions
, query
)
46 const defaultDeps
= depsPaths(options
.pscPackage
)
47 const defaultOptions
= {
48 context: config
.context
,
54 pscIdeColors: options
.psc
=== 'psa',
57 bundleOutput: 'output/bundle.js',
58 bundleNamespace: 'PS',
64 path
.join('src', '**', '*.purs'),
69 this.cacheable
&& this.cacheable()
71 let cache
= config
.purescriptLoaderCache
= config
.purescriptLoaderCache
|| {
79 if (options
.pscPackage
&& options
.src
) {
80 options
.src
= options
.src
.concat(defaultDeps
) // append psc-package-provided source paths with users'
83 options
= Object
.assign(defaultOptions
, options
)
85 if (!config
.purescriptLoaderInstalled
) {
86 config
.purescriptLoaderInstalled
= true
88 // invalidate loader cache when bundle is marked as invalid (in watch mode)
89 this._compiler
.plugin('invalid', () => {
90 debug('invalidating loader cache');
92 cache
= config
.purescriptLoaderCache
= {
93 rebuild: options
.pscIde
,
96 ideServer: cache
.ideServer
,
97 psModuleMap: cache
.psModuleMap
,
103 // add psc warnings to webpack compilation warnings
104 this._compiler
.plugin('after-compile', (compilation
, callback
) => {
105 cache
.warnings
.forEach(warning
=> {
106 compilation
.warnings
.push(warning
);
109 cache
.errors
.forEach(error
=> {
110 compilation
.errors
.push(error
);
117 const psModuleName
= PsModuleMap
.matchModule(source
)
120 load: js
=> callback(null, js
),
121 reject: error
=> callback(error
),
122 srcPath: this.resourcePath
,
123 srcDir: path
.dirname(this.resourcePath
),
124 jsPath: path
.resolve(path
.join(options
.output
, psModuleName
, 'index.js')),
127 emitWarning: warning
=> {
128 if (options
.warnings
&& warning
.length
) {
129 cache
.warnings
.push(warning
);
132 emitError: error
=> {
134 cache
.errors
.push(error
);
139 debug('loader called', psModule
.name
)
141 if (options
.bundle
) {
142 cache
.bundleModules
.push(psModule
.name
)
146 return ide
.connect(psModule
)
150 .catch(psModule
.reject
)
153 if (cache
.compilationFinished
) {
154 return toJavaScript(psModule
).then(psModule
.load
).catch(psModule
.reject
)
157 // We need to wait for compilation to finish before the loaders run so that
158 // references to compiled output are valid.
159 cache
.deferred
.push(psModule
)
161 if (!cache
.compilationStarted
) {
162 cache
.compilationStarted
= true;
164 return compile(psModule
)
166 cache
.compilationFinished
= true;
168 const bundlePromise
= options
.bundle
? bundle(options
, cache
) : Promise
.resolve();
170 return bundlePromise
.then(() =>
171 PsModuleMap
.makeMap(options
.src
).then(map
=> {
172 debug('rebuilt module map after compile');
173 cache
.psModuleMap
= map
;
177 .then(() => Promise
.map(cache
.deferred
, psModule
=> {
178 if (typeof cache
.ideServer
=== 'object') cache
.ideServer
.kill()
179 return toJavaScript(psModule
).then(psModule
.load
)
182 cache
.deferred
[0].reject(error
)
183 cache
.deferred
.slice(1).forEach(psModule
=> psModule
.reject(new Error('purs-loader failed')))