Browse Source

simplify deconflicting logic

contingency-plan
Rich-Harris 9 years ago
parent
commit
962431075a
  1. 69
      src/Bundle.js
  2. 3
      src/Statement.js
  3. 3
      test/form/unused-default-exports/_config.js

69
src/Bundle.js

@ -90,8 +90,10 @@ export default class Bundle {
// TODO would be better to deconflict once, rather than per-render
deconflict ( es6 ) {
let definers = blank();
let conflicts = blank();
let usedNames = blank();
// ensure no conflicts with globals
keys( this.assumedGlobals ).forEach( name => usedNames[ name ] = true );
let allReplacements = blank();
@ -100,65 +102,28 @@ export default class Bundle {
// while we're here...
allReplacements[ module.id ] = blank();
// TODO is this necessary in the ES6 case?
let name = makeLegalIdentifier( module.suggestedNames['*'] || module.suggestedNames.default || module.id );
while ( definers[ name ] ) {
conflicts[ name ] = true;
name = `_${name}`;
}
definers[ name ] = [ module ];
module.name = name;
this.assumedGlobals[ name ] = true;
module.name = getSafeName( name );
});
// Discover conflicts (i.e. two statements in separate modules both define `foo`)
this.orderedModules.forEach( module => {
let i = this.orderedModules.length;
while ( i-- ) {
const module = this.orderedModules[i];
// while we're here...
allReplacements[ module.id ] = blank();
module.statements.forEach( statement => {
if ( !statement.isIncluded ) return;
keys( statement.defines ).forEach( name => {
if ( definers[ name ] ) {
conflicts[ name ] = true;
} else {
definers[ name ] = [];
}
// TODO in good js, there shouldn't be duplicate definitions
// per module... but some people write bad js
definers[ name ].push( module );
});
});
});
// Ensure we don't conflict with globals
keys( this.assumedGlobals ).forEach( name => {
if ( definers[ name ] ) {
conflicts[ name ] = true;
keys( module.definitions ).forEach( name => {
const safeName = getSafeName( name );
if ( safeName !== name ) {
module.rename( name, safeName );
allReplacements[ module.id ][ name ] = safeName;
}
});
// Rename conflicting identifiers so they can live in the same scope
keys( conflicts ).forEach( name => {
const modules = definers[ name ];
if ( !this.assumedGlobals[ name ] ) {
// the module closest to the entryModule gets away with
// keeping things as they are, unless we have a conflict
// with a global name
modules.pop();
}
modules.forEach( module => {
const replacement = getSafeName( name );
module.rename( name, replacement );
allReplacements[ module.id ][ name ] = replacement;
});
});
// Assign non-conflicting names to internal default/namespace export
this.orderedModules.forEach( module => {
if ( !module.needsDefault && !module.needsAll ) return;
@ -193,11 +158,11 @@ export default class Bundle {
});
function getSafeName ( name ) {
while ( definers[ name ] || conflicts[ name ] ) { // TODO this seems wonky
while ( usedNames[ name ] ) {
name = `_${name}`;
}
conflicts[ name ] = true;
usedNames[ name ] = true;
return name;
}

3
src/Statement.js

@ -158,6 +158,9 @@ export default class Statement {
// disregard the `bar` in `class Foo { bar () {...} }`
if ( parent.type === 'MethodDefinition' ) return;
// disregard the `bar` in `export { foo as bar }`
if ( parent.type === 'ExportSpecifier' && node !== parent.local ) return;
const definingScope = scope.findDefiningScope( node.name );
if ( ( !definingScope || definingScope.depth === 0 ) && !this.defines[ node.name ] ) {

3
test/form/unused-default-exports/_config.js

@ -1,4 +1,3 @@
module.exports = {
description: 'does not name unused-but-included default export',
// solo: true
description: 'does not name unused-but-included default export'
};

Loading…
Cancel
Save