From e44d83df4d6c22acf98ef29d95b4956042384c25 Mon Sep 17 00:00:00 2001 From: Rich-Harris Date: Sat, 3 Oct 2015 14:26:49 -0400 Subject: [PATCH] more fixes --- src/Bundle.js | 75 +------------------ src/Module.js | 38 ++++++---- src/Statement.js | 8 +- src/finalisers/es6.js | 8 +- src/finalisers/shared/getExportBlock.js | 11 +-- .../exports-at-end-if-possible/_config.js | 3 +- 6 files changed, 38 insertions(+), 105 deletions(-) diff --git a/src/Bundle.js b/src/Bundle.js index 9ee74c9..3ab7977 100644 --- a/src/Bundle.js +++ b/src/Bundle.js @@ -49,6 +49,8 @@ export default class Bundle { return Promise.resolve( this.resolveId( this.entry, undefined, this.resolveOptions ) ) .then( id => this.fetchModule( id ) ) .then( entryModule => { + this.entryModule = entryModule; + this.modules.forEach( module => { module.bindImportSpecifiers(); module.bindReferences(); @@ -58,39 +60,8 @@ export default class Bundle { module.markAllSideEffects(); }); - const defaultExport = entryModule.exports.default; - - this.entryModule = entryModule; - - if ( defaultExport ) { - entryModule.needsDefault = true; - - // `export default function foo () {...}` - - // use the declared name for the export - if ( defaultExport.identifier ) { - entryModule.suggestName( 'default', defaultExport.identifier ); - } - - // `export default a + b` - generate an export name - // based on the id of the entry module - else { - let defaultExportName = this.entryModule.basename(); - - // deconflict - let topLevelNames = []; - entryModule.statements.forEach( statement => { - keys( statement.defines ).forEach( name => topLevelNames.push( name ) ); - }); - - while ( ~topLevelNames.indexOf( defaultExportName ) ) { - defaultExportName = `_${defaultExportName}`; - } - - entryModule.suggestName( 'default', defaultExportName ); - } - } + this.entryModule.markAllExportStatements(); - entryModule.markAllStatements( true ); this.markAllModifierStatements(); this.orderedModules = this.sort(); @@ -216,7 +187,7 @@ export default class Bundle { throw new Error( `You must specify an output type - valid options are ${keys( finalisers ).join( ', ' )}` ); } - this.toExport = []; // TODO + this.toExport = this.entryModule.getExports(); // TODO magicString = finalise( this, magicString.trim(), { exportMode, indentString }, options ); if ( options.banner ) magicString.prepend( options.banner + '\n' ); @@ -322,42 +293,4 @@ export default class Bundle { return ordered; } - - trace ( module, localName, es6 ) { - const importDeclaration = module.imports[ localName ]; - - // defined in this module - if ( !importDeclaration ) return module.replacements[ localName ] || localName; - - // defined elsewhere - return this.traceExport( importDeclaration.module, importDeclaration.name, es6 ); - } - - traceExport ( module, name, es6 ) { - if ( module.isExternal ) { - if ( name === 'default' ) return module.needsNamed && !es6 ? `${module.name}__default` : module.name; - if ( name === '*' ) return module.name; - return es6 ? name : `${module.name}.${name}`; - } - - const reexportDeclaration = module.reexports[ name ]; - if ( reexportDeclaration ) { - return this.traceExport( reexportDeclaration.module, reexportDeclaration.localName ); - } - - if ( name === '*' ) return module.replacements[ '*' ]; - if ( name === 'default' ) return module.defaultName(); - - const exportDeclaration = module.exports[ name ]; - if ( exportDeclaration ) return this.trace( module, exportDeclaration.localName ); - - for ( let i = 0; i < module.exportAlls.length; i += 1 ) { - const declaration = module.exportAlls[i]; - if ( declaration.module.exports[ name ] ) { - return this.traceExport( declaration.module, name, es6 ); - } - } - - throw new Error( `Could not trace binding '${name}' from ${module.id}` ); - } } diff --git a/src/Module.js b/src/Module.js index 45e2592..372029d 100644 --- a/src/Module.js +++ b/src/Module.js @@ -247,9 +247,9 @@ export default class Module { const name = defaultExport.identifier && !defaultExport.isModified ? defaultExport.identifier : - this.replacements.default; + this.basename(); // TODO should be deconflictable - return this.replacements[ name ] || name; + return name; } getExports () { @@ -514,39 +514,45 @@ export default class Module { this.statements.forEach( statement => { if ( !statement.isIncluded ) { magicString.remove( statement.start, statement.next ); + return; } statement.references.forEach( reference => { const declaration = reference.declaration; if ( reference.declaration ) { - const { start, end } = reference.node; + const { start } = reference.node; const name = ( !es6 && declaration.isExternal ) ? `${declaration.module.name}.${declaration.name}` : declaration.name; - magicString.overwrite( start, end, name ); + magicString.overwrite( start, start + reference.name.length, name ); } }); // modify exports as necessary if ( statement.isExportDeclaration ) { + // remove `export` from `export var foo = 42` + if ( statement.node.type === 'ExportNamedDeclaration' && statement.node.declaration.type === 'VariableDeclaration' ) { + magicString.remove( statement.node.start, statement.node.declaration.start ); + } + // remove `export` from `export class Foo {...}` or `export default Foo` // TODO default exports need different treatment - if ( statement.node.declaration.id ) { + else if ( statement.node.declaration.id ) { magicString.remove( statement.node.start, statement.node.declaration.start ); } - // else if ( statement.node.type === 'ExportDefaultDeclaration' ) { - // const defaultExport = this.exports.default; - // - // // anonymous functions should be converted into declarations - // if ( statement.node.declaration.type === 'FunctionExpression' ) { - // magicString.overwrite( statement.node.start, statement.node.declaration.start + 8, `function ${defaultExport.name}` ); - // } else { - // magicString.overwrite( statement.node.start, statement.node.declaration.start, `var ${defaultExport.name} = ` ); - // } - // } + else if ( statement.node.type === 'ExportDefaultDeclaration' ) { + const defaultExport = this.exports.default; + + // anonymous functions should be converted into declarations + if ( statement.node.declaration.type === 'FunctionExpression' ) { + magicString.overwrite( statement.node.start, statement.node.declaration.start + 8, `function ${this.defaultName()}` ); + } else { + magicString.overwrite( statement.node.start, statement.node.declaration.start, `var ${this.defaultName()} = ` ); + } + } else { throw new Error( 'Unhandled export' ); @@ -586,7 +592,7 @@ export default class Module { throw new Error( 'TODO default expression exports' ); } - return this.trace( exportDeclaration.name ); + return this.trace( exportDeclaration.localName ); } // TODO export * diff --git a/src/Statement.js b/src/Statement.js index 3c95ad6..9047067 100644 --- a/src/Statement.js +++ b/src/Statement.js @@ -123,7 +123,7 @@ export default class Statement { // If this is a top-level call expression, or an assignment to a global, // this statement will need to be marked - if ( node.type === 'CallExpression' ) { + if ( node.type === 'CallExpression' || node.type === 'NewExpression' ) { statement.mark(); } @@ -131,10 +131,10 @@ export default class Statement { let subject = node[ modifierNodes[ node.type ] ]; while ( subject.type === 'MemberExpression' ) subject = subject.object; - const bundle = statement.module.bundle; - const canonicalName = bundle.trace( statement.module, subject.name ); + const declaration = statement.module.trace( subject.name ); - if ( bundle.assumedGlobals[ canonicalName ] ) statement.mark(); + // global + if ( !declaration ) statement.mark(); } } }); diff --git a/src/finalisers/es6.js b/src/finalisers/es6.js index a005e91..e21e066 100644 --- a/src/finalisers/es6.js +++ b/src/finalisers/es6.js @@ -47,18 +47,18 @@ export default function es6 ( bundle, magicString ) { const module = bundle.entryModule; const specifiers = bundle.toExport.filter( notDefault ).map( name => { - const canonicalName = bundle.traceExport( module, name ); + const declaration = module.traceExport( name ); - return canonicalName === name ? + return declaration.name === name ? name : - `${canonicalName} as ${name}`; + `${declaration.name} as ${name}`; }); let exportBlock = specifiers.length ? `export { ${specifiers.join(', ')} };` : ''; const defaultExport = module.exports.default || module.reexports.default; if ( defaultExport ) { - exportBlock += `export default ${bundle.traceExport(module,'default')};`; + exportBlock += `export default ${module.traceExport( 'default' ).name};`; } if ( exportBlock ) { diff --git a/src/finalisers/shared/getExportBlock.js b/src/finalisers/shared/getExportBlock.js index 24eeb61..3480074 100644 --- a/src/finalisers/shared/getExportBlock.js +++ b/src/finalisers/shared/getExportBlock.js @@ -1,18 +1,13 @@ export default function getExportBlock ( bundle, exportMode, mechanism = 'return' ) { if ( exportMode === 'default' ) { - const defaultExport = bundle.entryModule.exports.default; - - const defaultExportName = bundle.entryModule.replacements.default || - defaultExport.identifier; - - return `${mechanism} ${defaultExportName};`; + return `${mechanism} ${bundle.entryModule.defaultName()};`; } return bundle.toExport .map( name => { const prop = name === 'default' ? `['default']` : `.${name}`; - name = bundle.traceExport( bundle.entryModule, name ); - return `exports${prop} = ${name};`; + const declaration = bundle.entryModule.traceExport( name ); + return `exports${prop} = ${declaration.name};`; }) .join( '\n' ); } diff --git a/test/form/exports-at-end-if-possible/_config.js b/test/form/exports-at-end-if-possible/_config.js index a898bc7..30d375e 100644 --- a/test/form/exports-at-end-if-possible/_config.js +++ b/test/form/exports-at-end-if-possible/_config.js @@ -2,6 +2,5 @@ module.exports = { description: 'exports variables at end, if possible', options: { moduleName: 'myBundle' - }, - // solo: true + } };