Browse Source

more fixes

declarations-and-references
Rich-Harris 9 years ago
parent
commit
67986e1945
  1. 1
      src/Bundle.js
  2. 2
      src/ExternalModule.js
  3. 89
      src/Module.js
  4. 12
      src/Statement.js
  5. 11
      src/ast/Scope.js
  6. 5
      src/finalisers/shared/getExportBlock.js
  7. 3
      test/function/assignment-to-exports/_config.js

1
src/Bundle.js

@ -62,6 +62,7 @@ export default class Bundle {
// mark all export statements
entryModule.getExports().forEach( name => {
const declaration = entryModule.traceExport( name );
declaration.isExported = true;
declaration.statement.mark();
});

2
src/ExternalModule.js

@ -18,7 +18,7 @@ class ExternalDeclaration {
}
}
getName ( es6 ) {
render ( es6 ) {
if ( this.name === '*' ) {
return this.module.name;
}

89
src/Module.js

@ -21,6 +21,10 @@ class SyntheticDefaultDeclaration {
reference.declaration = this;
this.name = reference.name;
}
render () {
return this.name;
}
}
export default class Module {
@ -298,78 +302,6 @@ export default class Module {
});
}
markAllStatements ( isEntryModule ) {
this.statements.forEach( statement => {
if ( statement.isIncluded ) return; // TODO can this happen? probably not...
// skip import declarations...
if ( statement.isImportDeclaration ) {
// ...unless they're empty, in which case assume we're importing them for the side-effects
// THIS IS NOT FOOLPROOF. Probably need /*rollup: include */ or similar
if ( !statement.node.specifiers.length ) {
const id = this.resolvedIds[ statement.node.source.value ];
const otherModule = this.bundle.moduleById[ id ];
if ( !otherModule.isExternal ) otherModule.markAllStatements();
}
}
// skip `export { foo, bar, baz }`...
else if ( statement.node.type === 'ExportNamedDeclaration' && statement.node.specifiers.length ) {
// ...but ensure they are defined, if this is the entry module
if ( isEntryModule ) statement.mark();
}
// include everything else
else {
statement.mark();
}
});
}
markExport ( name, suggestedName, importer ) {
const reexport = this.reexports[ name ];
const exportDeclaration = this.exports[ name ];
if ( reexport ) {
reexport.isUsed = true;
reexport.module.markExport( reexport.localName, suggestedName, this );
}
else if ( exportDeclaration ) {
exportDeclaration.isUsed = true;
if ( name === 'default' ) {
this.needsDefault = true;
this.suggestName( 'default', suggestedName );
return exportDeclaration.statement.mark();
}
this.mark( exportDeclaration.localName );
}
else {
// See if there exists an export delegate that defines `name`.
let i;
for ( i = 0; i < this.exportAlls.length; i += 1 ) {
const declaration = this.exportAlls[i];
if ( declaration.module.exports[ name ] ) {
// It's found! This module exports `name` through declaration.
// It is however not imported into this scope.
this.exportDelegates[ name ] = declaration;
declaration.module.markExport( name );
declaration.statement.dependsOn[ name ] =
declaration.statement.stronglyDependsOn[ name ] = true;
return;
}
}
throw new Error( `Module ${this.id} does not export ${name} (imported by ${importer.id})` );
}
}
parse ( ast ) {
// The ast can be supplied programmatically (but usually won't be)
if ( !ast ) {
@ -482,9 +414,7 @@ export default class Module {
if ( reference.declaration ) {
const { start } = reference.node;
const name = declaration.isExternal ?
declaration.getName( es6 ) :
declaration.name;
const name = declaration.render( es6 );
if ( reference.name !== name ) {
magicString.overwrite( start, start + reference.name.length, name );
@ -496,7 +426,14 @@ export default class Module {
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 );
const name = statement.node.declaration.declarations[0].id.name;
const declaration = this.declarations[ name ];
const end = declaration.isExported && declaration.isReassigned ?
statement.node.declaration.declarations[0].start :
statement.node.declaration.start;
magicString.remove( statement.node.start, end );
}
else if ( statement.node.type === 'ExportAllDeclaration' ) {

12
src/Statement.js

@ -92,6 +92,18 @@ export default class Statement {
const reference = new Reference( node, scope );
references.push( reference );
if ( node.type === 'Identifier' ) {
// `foo = bar`
if ( parent.type === 'AssignmentExpression' && node === parent.left ) {
reference.isReassignment = true;
}
// `foo++`
if ( parent.type === 'UpdateExpression' && node === parent.argument ) {
reference.isReassignment = true;
}
}
this.skip(); // don't descend from `foo.bar.baz` into `foo.bar`
}
},

11
src/ast/Scope.js

@ -38,11 +38,22 @@ class Declaration {
this.references = [];
this.statement = null;
this.name = null;
this.isReassigned = false;
}
addReference ( reference ) {
reference.declaration = this;
this.name = reference.name; // TODO handle differences of opinion
if ( reference.isReassignment ) this.isReassigned = true;
}
render ( es6 ) {
if ( es6 ) return this.name;
if ( !this.isReassigned || !this.isExported ) return this.name;
return `exports.${this.name}`;
}
}

5
src/finalisers/shared/getExportBlock.js

@ -7,7 +7,10 @@ export default function getExportBlock ( bundle, exportMode, mechanism = 'return
.map( name => {
const prop = name === 'default' ? `['default']` : `.${name}`;
const declaration = bundle.entryModule.traceExport( name );
return `exports${prop} = ${declaration.name};`;
if ( declaration.isReassigned ) return null;
return `exports${prop} = ${declaration.render( false )};`;
})
.filter( Boolean )
.join( '\n' );
}

3
test/function/assignment-to-exports/_config.js

@ -6,6 +6,5 @@ module.exports = {
assert.equal( exports.count, 0 );
exports.incr();
assert.equal( exports.count, 1 );
},
// solo: true
}
};

Loading…
Cancel
Save