diff --git a/src/Bundle.js b/src/Bundle.js index e1f5754..d234cef 100644 --- a/src/Bundle.js +++ b/src/Bundle.js @@ -238,6 +238,13 @@ export default class Bundle { let previousIndex = -1; let previousMargin = 0; + // within a module, statements should preserve their original order + // TODO is this foolproof? + this.statements.sort( ( a, b ) => { + if ( a.module !== b.module ) return -1; // no change + return a.index - b.index; + }); + this.statements.forEach( statement => { // skip `export { foo, bar, baz }` if ( statement.node.type === 'ExportNamedDeclaration' && statement.node.specifiers.length ) { diff --git a/src/Module.js b/src/Module.js index f7731b2..965660b 100644 --- a/src/Module.js +++ b/src/Module.js @@ -99,13 +99,16 @@ export default class Module { if ( node.type === 'ExportDefaultDeclaration' ) { const isDeclaration = /Declaration$/.test( node.declaration.type ); const declaredName = isDeclaration && node.declaration.id.name; + const identifier = node.declaration.type === 'Identifier' && node.declaration.name; this.exports.default = { statement, name: 'default', localName: declaredName || 'default', declaredName, - isDeclaration + identifier, + isDeclaration, + isModified: false // in case of `export default foo; foo = somethingElse` }; } @@ -207,6 +210,16 @@ export default class Module { } getCanonicalName ( localName ) { + // Special case + if ( localName === 'default' && this.exports.default && this.exports.default.isModified ) { + let canonicalName = makeLegalIdentifier( this.path.replace( this.bundle.base + '/', '' ).replace( /\.js$/, '' ) ); + while ( this.definitions[ canonicalName ] ) { + canonicalName = `_${canonicalName}`; + } + + return canonicalName; + } + if ( this.suggestedNames[ localName ] ) { localName = this.suggestedNames[ localName ]; } @@ -358,7 +371,7 @@ export default class Module { if ( !statement.node.specifiers.length ) { return this.bundle.fetchModule( statement.node.source.value, this.path ) .then( module => { - statement.module = module; // TODO what is this for? what does it do? why not _module? + statement.module = module; return module.expandAllStatements(); }) .then( statements => { diff --git a/src/Statement.js b/src/Statement.js index b96d8e7..f2031f1 100644 --- a/src/Statement.js +++ b/src/Statement.js @@ -176,6 +176,17 @@ export default class Statement { return; } + // special case = `export default foo; foo += 1;` - we'll + // need to assign a new variable so that the exported + // value is not updated by the second statement + if ( this.module.exports.default && this.module.exports.default.identifier === node.name ) { + // but only if this is a) inside a function body or + // b) after the export declaration + if ( !!scope.parent || node.start > this.module.exports.default.statement.node.start ) { + this.module.exports.default.isModified = true; + } + } + this.modifies[ node.name ] = true; }; diff --git a/test/function/default-export-is-not-bound/_config.js b/test/function/default-export-is-not-bound/_config.js index 4f9f6d6..ca09856 100644 --- a/test/function/default-export-is-not-bound/_config.js +++ b/test/function/default-export-is-not-bound/_config.js @@ -1,6 +1,5 @@ module.exports = { - description: 'does not bind default exports', - skip: true + description: 'does not bind default exports' }; // test copied from https://github.com/esnext/es6-module-transpiler/tree/master/test/examples/export-default diff --git a/test/function/default-export-is-not-bound/main.js b/test/function/default-export-is-not-bound/main.js index d3f5321..e706c04 100644 --- a/test/function/default-export-is-not-bound/main.js +++ b/test/function/default-export-is-not-bound/main.js @@ -1,6 +1,6 @@ import value from './foo'; import { change } from './foo'; -assert.equal(value, 42); +assert.equal( value, 42 ); change(); assert.equal( value, 42, 'default export should not be bound' );