|
|
@ -1,4 +1,4 @@ |
|
|
|
import { resolve } from 'path'; |
|
|
|
import { basename, extname, resolve } from 'path'; |
|
|
|
import { readFile } from 'sander'; |
|
|
|
import MagicString from 'magic-string'; |
|
|
|
import { keys, has } from './utils/object'; |
|
|
@ -10,9 +10,13 @@ import replaceIdentifiers from './utils/replaceIdentifiers'; |
|
|
|
import makeLegalIdentifier from './utils/makeLegalIdentifier'; |
|
|
|
import { defaultResolver } from './utils/resolvePath'; |
|
|
|
|
|
|
|
function badExports ( option, keys ) { |
|
|
|
throw new Error( `'${option}' was specified for options.exports, but entry module has following exports: ${keys.join(', ')}` ); |
|
|
|
} |
|
|
|
|
|
|
|
export default class Bundle { |
|
|
|
constructor ( options ) { |
|
|
|
this.base = options.base || process.cwd(); |
|
|
|
this.base = resolve( options.base || process.cwd() ); |
|
|
|
this.entryPath = resolve( this.base, options.entry ).replace( /\.js$/, '' ) + '.js'; |
|
|
|
this.resolvePath = options.resolvePath || defaultResolver; |
|
|
|
|
|
|
@ -20,6 +24,7 @@ export default class Bundle { |
|
|
|
this.modulePromises = {}; |
|
|
|
this.statements = []; |
|
|
|
this.externalModules = []; |
|
|
|
this.defaultExportName = null; |
|
|
|
} |
|
|
|
|
|
|
|
fetchModule ( importee, importer ) { |
|
|
@ -72,11 +77,29 @@ export default class Bundle { |
|
|
|
// Exclude imports
|
|
|
|
if ( /^Import/.test( node.type ) ) return; |
|
|
|
|
|
|
|
if ( node.type === 'ExportNamedDeclaration' ) { |
|
|
|
// Exclude default exports that proxy a name
|
|
|
|
// e.g. `export default foo`
|
|
|
|
if ( node.type === 'ExportDefaultDeclaration' && /Declaration$/.test( node.declaration.type ) ) return; |
|
|
|
|
|
|
|
// Exclude specifier exports
|
|
|
|
if ( node.specifiers.length ) return; |
|
|
|
// e.g. `export { foo }`
|
|
|
|
if ( node.type === 'ExportNamedDeclaration' && node.specifiers.length ) return; |
|
|
|
|
|
|
|
// Include everything else...
|
|
|
|
|
|
|
|
if ( node.type === 'ExportDefaultDeclaration' ) { |
|
|
|
// TODO generic 'get deconflicted name' mechanism
|
|
|
|
let defaultExportName = makeLegalIdentifier( basename( this.entryPath ).slice( 0, -extname( this.entryPath ).length ) ); |
|
|
|
while ( this.entryModule.ast._scope.contains( defaultExportName ) ) { |
|
|
|
defaultExportName = `_${defaultExportName}`; |
|
|
|
} |
|
|
|
|
|
|
|
this.defaultExportName = defaultExportName; |
|
|
|
node._source.overwrite( node.start, node.declaration.start, `var ${defaultExportName} = ` ); |
|
|
|
} |
|
|
|
|
|
|
|
// Remove the `export` from everything else
|
|
|
|
if ( node.type === 'ExportNamedDeclaration' ) { |
|
|
|
// Remove the `export`
|
|
|
|
node._source.remove( node.start, node.declaration.start ); |
|
|
|
} |
|
|
|
|
|
|
@ -136,6 +159,9 @@ export default class Bundle { |
|
|
|
generate ( options = {} ) { |
|
|
|
let magicString = new MagicString.Bundle({ separator: '' }); |
|
|
|
|
|
|
|
// Determine export mode - 'default', 'named', 'none'
|
|
|
|
let exportMode = this.getExportMode( options.exports ); |
|
|
|
|
|
|
|
// Apply new names and add to the output bundle
|
|
|
|
this.statements.forEach( statement => { |
|
|
|
let replacements = {}; |
|
|
@ -162,7 +188,7 @@ export default class Bundle { |
|
|
|
throw new Error( `You must specify an output type - valid options are ${keys( finalisers ).join( ', ' )}` ); |
|
|
|
} |
|
|
|
|
|
|
|
magicString = finalise( this, magicString, options ); |
|
|
|
magicString = finalise( this, magicString, exportMode, options ); |
|
|
|
|
|
|
|
return { |
|
|
|
code: magicString.toString(), |
|
|
@ -173,4 +199,32 @@ export default class Bundle { |
|
|
|
}) |
|
|
|
}; |
|
|
|
} |
|
|
|
|
|
|
|
getExportMode ( exportMode ) { |
|
|
|
const exportKeys = keys( this.entryModule.exports ); |
|
|
|
|
|
|
|
if ( exportMode === 'default' ) { |
|
|
|
if ( exportKeys.length !== 1 || exportKeys[0] !== 'default' ) { |
|
|
|
badExports( 'default', exportKeys ); |
|
|
|
} |
|
|
|
} else if ( exportMode === 'none' && exportKeys.length ) { |
|
|
|
badExports( 'none', exportKeys ); |
|
|
|
} |
|
|
|
|
|
|
|
if ( !exportMode || exportMode === 'auto' ) { |
|
|
|
if ( exportKeys.length === 0 ) { |
|
|
|
exportMode = 'none'; |
|
|
|
} else if ( exportKeys.length === 1 && exportKeys[0] === 'default' ) { |
|
|
|
exportMode = 'default'; |
|
|
|
} else { |
|
|
|
exportMode = 'named'; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if ( !/(?:default|named|none)/.test( exportMode ) ) { |
|
|
|
throw new Error( `options.exports must be 'default', 'named', 'none', 'auto', or left unspecified (defaults to 'auto')` ); |
|
|
|
} |
|
|
|
|
|
|
|
return exportMode; |
|
|
|
} |
|
|
|
} |