Browse Source

more fixes

declarations-and-references
Rich-Harris 9 years ago
parent
commit
e44d83df4d
  1. 75
      src/Bundle.js
  2. 38
      src/Module.js
  3. 8
      src/Statement.js
  4. 8
      src/finalisers/es6.js
  5. 11
      src/finalisers/shared/getExportBlock.js
  6. 3
      test/form/exports-at-end-if-possible/_config.js

75
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}` );
}
}

38
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 *

8
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();
}
}
});

8
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 ) {

11
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' );
}

3
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
}
};

Loading…
Cancel
Save