diff --git a/src/Bundle.js b/src/Bundle.js index a21c1db..f126049 100644 --- a/src/Bundle.js +++ b/src/Bundle.js @@ -4,7 +4,6 @@ import { blank, keys } from './utils/object'; import Module from './Module'; import ExternalModule from './ExternalModule'; import finalisers from './finalisers/index'; -import makeLegalIdentifier from './utils/makeLegalIdentifier'; import ensureArray from './utils/ensureArray'; import { defaultResolver, defaultExternalResolver } from './utils/resolveId'; import { defaultLoader } from './utils/load'; @@ -60,7 +59,11 @@ export default class Bundle { module.markAllSideEffects(); }); - this.entryModule.markAllExportStatements(); + // mark all export statements + entryModule.getExports().forEach( name => { + const declaration = entryModule.traceExport( name ); + declaration.statement.mark(); + }); this.markAllModifierStatements(); @@ -69,7 +72,7 @@ export default class Bundle { } // TODO would be better to deconflict once, rather than per-render - deconflict ( es6 ) { + deconflict () { let nameCount = blank(); // ensure no conflicts with globals @@ -225,6 +228,7 @@ export default class Bundle { let stronglyDependsOn = {}; function visit ( module ) { + if ( seen[ module.id ] ) return; seen[ module.id ] = true; const { strongDependencies, weakDependencies } = module.consolidateDependencies(); diff --git a/src/ExternalModule.js b/src/ExternalModule.js index ee1df17..396dcc9 100644 --- a/src/ExternalModule.js +++ b/src/ExternalModule.js @@ -24,7 +24,7 @@ class ExternalDeclaration { } if ( this.name === 'default' ) { - return this.module.needsNamed ? + return !es6 && this.module.needsNamed ? `${this.module.name}__default` : this.module.name; } diff --git a/src/Module.js b/src/Module.js index 4844b31..4ae634d 100644 --- a/src/Module.js +++ b/src/Module.js @@ -8,6 +8,21 @@ import getLocation from './utils/getLocation'; import makeLegalIdentifier from './utils/makeLegalIdentifier'; import SOURCEMAPPING_URL from './utils/sourceMappingURL'; +class SyntheticDefaultDeclaration { + constructor ( node, statement, name ) { + this.node = node; + this.statement = statement; + this.name = name; + + this.references = []; + } + + addReference ( reference ) { + reference.declaration = this; + this.name = reference.name; + } +} + export default class Module { constructor ({ id, source, ast, bundle }) { this.source = source; @@ -98,6 +113,11 @@ export default class Module { isAnonymous, isModified: false // in case of `export default foo; foo = somethingElse` }; + + if ( !identifier ) { + // create a synthetic declaration + this.declarations.default = new SyntheticDefaultDeclaration( node, statement, this.defaultName() ); + } } // export { foo, bar, baz } @@ -272,69 +292,6 @@ export default class Module { return keys( exports ); } - mark ( name ) { - // shortcut cycles - if ( this.marked[ name ] ) return; - this.marked[ name ] = true; - - // The definition for this name is in a different module - if ( this.imports[ name ] ) { - const importDeclaration = this.imports[ name ]; - importDeclaration.isUsed = true; - - const module = importDeclaration.module; - - // suggest names. TODO should this apply to non default/* imports? - if ( importDeclaration.name === 'default' ) { - // TODO this seems ropey - const localName = importDeclaration.localName; - let suggestion = this.suggestedNames[ localName ] || localName; - - // special case - the module has its own import by this name - while ( !module.isExternal && module.imports[ suggestion ] ) { - suggestion = `_${suggestion}`; - } - - module.suggestName( 'default', suggestion ); - } else if ( importDeclaration.name === '*' ) { - const localName = importDeclaration.localName; - const suggestion = this.suggestedNames[ localName ] || localName; - module.suggestName( '*', suggestion ); - module.suggestName( 'default', `${suggestion}__default` ); - } - - if ( importDeclaration.name === 'default' ) { - module.needsDefault = true; - } else if ( importDeclaration.name === '*' ) { - module.needsAll = true; - } else { - module.needsNamed = true; - } - - if ( module.isExternal ) { - module.importedByBundle.push( importDeclaration ); - } - - else if ( importDeclaration.name === '*' ) { - // we need to create an internal namespace - if ( !~this.bundle.internalNamespaceModules.indexOf( module ) ) { - this.bundle.internalNamespaceModules.push( module ); - } - - module.markAllExportStatements(); - } - - else { - module.markExport( importDeclaration.name, name, this ); - } - } - - else { - const statement = name === 'default' ? this.exports.default.statement : this.definitions[ name ]; - if ( statement ) statement.mark(); - } - } - markAllSideEffects () { this.statements.forEach( statement => { statement.markSideEffect(); @@ -370,12 +327,6 @@ export default class Module { }); } - markAllExportStatements () { - this.statements.forEach( statement => { - if ( statement.isExportDeclaration ) statement.mark(); - }); - } - markExport ( name, suggestedName, importer ) { const reexport = this.reexports[ name ]; const exportDeclaration = this.exports[ name ]; @@ -517,6 +468,15 @@ export default class Module { return; } + // skip `export { foo, bar, baz }` + if ( statement.node.type === 'ExportNamedDeclaration' ) { + // skip `export { foo, bar, baz }` + if ( statement.node.specifiers.length ) { + magicString.remove( statement.start, statement.next ); + return; + } + } + statement.references.forEach( reference => { const declaration = reference.declaration; @@ -526,7 +486,9 @@ export default class Module { declaration.getName( es6 ) : declaration.name; - magicString.overwrite( start, start + reference.name.length, name ); + if ( reference.name !== name ) { + magicString.overwrite( start, start + reference.name.length, name ); + } } }); @@ -549,8 +511,6 @@ export default class Module { } 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()}` ); @@ -594,13 +554,19 @@ export default class Module { return this.trace( exportDeclaration.identifier ); } - throw new Error( 'TODO default expression exports' ); + return this.declarations.default; } return this.trace( exportDeclaration.localName ); } - // TODO export * + for ( let i = 0; i < this.exportAlls.length; i += 1 ) { + const exportAll = this.exportAlls[i]; + const declaration = exportAll.module.traceExport( name ); + + if ( declaration ) return declaration; + } + return null; } } diff --git a/src/Statement.js b/src/Statement.js index 9047067..8ff6c77 100644 --- a/src/Statement.js +++ b/src/Statement.js @@ -81,10 +81,8 @@ export default class Statement { declaration.statement = this; }); - let references = this.references; - // find references - let scope = this.scope; + let { references, scope } = this; walk( this.node, { enter ( node, parent ) { @@ -140,10 +138,6 @@ export default class Statement { }); } - replaceIdentifiers ( magicString ) { - return magicString; - } - source () { return this.module.source.slice( this.start, this.end ); }