Browse Source

Integrating Scope into Module. Removed ~200 lines.

gh-109
Oskar Segersvärd 10 years ago
parent
commit
f8da4fdb65
  1. 114
      src/Bundle.js
  2. 19
      src/ExternalModule.js
  3. 307
      src/Module.js
  4. 20
      src/Scope.js
  5. 21
      src/Statement.js
  6. 2
      src/utils/getExportMode.js

114
src/Bundle.js

@ -12,6 +12,7 @@ import { defaultLoader } from './utils/load';
import getExportMode from './utils/getExportMode';
import getIndentString from './utils/getIndentString';
import { unixizePath } from './utils/normalizePlatform.js';
import Scope from './Scope';
export default class Bundle {
constructor ( options ) {
@ -30,6 +31,8 @@ export default class Bundle {
transform: ensureArray( options.transform )
};
this.scope = new Scope();
this.toExport = null;
this.pending = blank();
@ -48,8 +51,6 @@ export default class Bundle {
return Promise.resolve( this.resolveId( this.entry, undefined, this.resolveOptions ) )
.then( id => this.fetchModule( id ) )
.then( entryModule => {
entryModule.bindImportSpecifiers();
const defaultExport = entryModule.exports.default;
this.entryModule = entryModule;
@ -85,88 +86,10 @@ export default class Bundle {
entryModule.markAllStatements( true );
this.markAllModifierStatements();
this.orderedModules = this.sort();
});
}
// TODO would be better to deconflict once, rather than per-render
deconflict ( es6 ) {
let usedNames = blank();
// ensure no conflicts with globals
keys( this.assumedGlobals ).forEach( name => usedNames[ name ] = true );
let allReplacements = blank();
// Assign names to external modules
this.externalModules.forEach( module => {
// 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 );
module.name = getSafeName( name );
});
// Discover conflicts (i.e. two statements in separate modules both define `foo`)
let i = this.orderedModules.length;
while ( i-- ) {
const module = this.orderedModules[i];
// while we're here...
allReplacements[ module.id ] = blank();
keys( module.definitions ).forEach( name => {
const safeName = getSafeName( name );
if ( safeName !== name ) {
module.rename( name, safeName );
allReplacements[ module.id ][ name ] = safeName;
}
});
}
// Assign non-conflicting names to internal default/namespace export
this.orderedModules.forEach( module => {
if ( !module.needsDefault && !module.needsAll ) return;
if ( module.needsAll ) {
const namespaceName = getSafeName( module.suggestedNames[ '*' ] );
module.replacements[ '*' ] = namespaceName;
}
if ( module.needsDefault || module.needsAll && module.exports.default ) {
const defaultExport = module.exports.default;
// only create a new name if either
// a) it's an expression (`export default 42`) or
// b) it's a name that is reassigned to (`export var a = 1; a = 2`)
if ( defaultExport && defaultExport.identifier && !defaultExport.isModified ) return; // TODO encapsulate check for whether we need synthetic default name
const defaultName = getSafeName( module.suggestedNames.default );
module.replacements.default = defaultName;
}
// As a last step, deconflict all identifier names, once.
this.scope.deconflict();
});
this.orderedModules.forEach( module => {
keys( module.imports ).forEach( localName => {
if ( !module.imports[ localName ].isUsed ) return;
const bundleName = this.trace( module, localName, es6 );
if ( bundleName !== localName ) {
allReplacements[ module.id ][ localName ] = bundleName;
}
});
});
function getSafeName ( name ) {
while ( usedNames[ name ] ) {
name = `_${name}`;
}
usedNames[ name ] = true;
return name;
}
return allReplacements;
}
fetchModule ( id ) {
@ -193,7 +116,13 @@ export default class Bundle {
this.modules.push( module );
this.moduleById[ id ] = module;
return this.fetchAllDependencies( module ).then( () => module );
return this.fetchAllDependencies( module ).then( () => {
// Analyze the module once all its dependencies have been resolved.
// This means that any dependencies of a module has already been
// analysed when it's time for the module itself.
module.analyse();
return module;
});
});
}
@ -206,7 +135,7 @@ export default class Bundle {
// external module
if ( !resolvedId ) {
if ( !this.moduleById[ source ] ) {
const module = new ExternalModule( source );
const module = new ExternalModule( { id: source, bundle: this } );
this.externalModules.push( module );
this.moduleById[ source ] = module;
}
@ -269,7 +198,7 @@ export default class Bundle {
render ( options = {} ) {
const format = options.format || 'es6';
const allReplacements = this.deconflict( format === 'es6' );
const allReplacements = blank();
// Determine export mode - 'default', 'named', 'none'
const exportMode = getExportMode( this, options.exports );
@ -322,14 +251,12 @@ export default class Bundle {
// since we're rewriting variable exports, we want to
// ensure we don't try and export them again at the bottom
this.toExport = keys( this.entryModule.exports )
.concat( keys( this.entryModule.reexports ) )
.filter( key => !varExports[ key ] );
this.toExport = this.entryModule.exports.usedNames();
let magicString = new MagicString.Bundle({ separator: '\n\n' });
this.orderedModules.forEach( module => {
const source = module.render( allBundleExports, allReplacements[ module.id ], format );
const source = module.render( this.toExport, format );
if ( source.toString().length ) {
magicString.addSource( source );
}
@ -337,13 +264,10 @@ export default class Bundle {
// prepend bundle with internal namespaces
const indentString = getIndentString( magicString, options );
const namespaceBlock = this.internalNamespaceModules.map( module => {
const exports = keys( module.exports )
.concat( keys( module.reexports ) )
.map( name => {
const canonicalName = this.traceExport( module, name );
return `${indentString}get ${name} () { return ${canonicalName}; }`;
});
const exports = module.exports.localIds().map( ( [ name, id ] ) =>
`${indentString}get ${name} () { return ${id.name}; }`);
return `var ${module.replacements['*']} = {\n` +
exports.join( ',\n' ) +

19
src/ExternalModule.js

@ -1,15 +1,12 @@
import { blank } from './utils/object';
export default class ExternalModule {
constructor ( id ) {
constructor ( { id, bundle } ) {
this.id = id;
this.name = null;
this.name = id;
this.isExternal = true;
this.importedByBundle = [];
this.suggestedNames = blank();
this.needsDefault = false;
// Invariant: needsNamed and needsAll are never both true at once.
@ -19,19 +16,19 @@ export default class ExternalModule {
//
this.needsNamed = false;
this.needsAll = false;
this.exports = bundle.scope.virtual();
}
findDefiningStatement () {
return null;
}
rename () {
// noop
}
suggestName ( exportName, suggestion ) {
if ( !this.suggestedNames[ exportName ] ) {
this.suggestedNames[ exportName ] = suggestion;
const id = this.exports.lookup( exportName );
if ( id.name === id.originalName ) {
id.name = suggestion;
}
}
}

307
src/Module.js

@ -4,23 +4,15 @@ import Statement from './Statement';
import walk from './ast/walk';
import { blank, keys } from './utils/object';
import getLocation from './utils/getLocation';
import makeLegalIdentifier from './utils/makeLegalIdentifier';
function deconflict ( name, names ) {
while ( name in names ) {
name = `_${name}`;
}
return name;
}
function isEmptyExportedVarDeclaration ( node, allBundleExports, moduleReplacements ) {
function isEmptyExportedVarDeclaration ( node, exports, toExport ) {
if ( node.type !== 'VariableDeclaration' || node.declarations[0].init ) return false;
const name = node.declarations[0].id.name;
const canonicalName = moduleReplacements[ name ] || name;
return canonicalName in allBundleExports;
const id = exports.lookup( name );
return !~toExport.indexOf( id.name );
}
export default class Module {
@ -30,6 +22,9 @@ export default class Module {
this.bundle = bundle;
this.id = id;
// Implement Identifier interface.
this.name = id;
// By default, `id` is the filename. Custom resolvers and loaders
// can change that, but it makes sense to use it for the source filename
this.magicString = new MagicString( source, {
@ -49,15 +44,14 @@ export default class Module {
this.statements = this.parse( ast );
// all dependencies
this.dependencies = [];
this.resolvedIds = blank();
this.boundImportSpecifiers = false;
// imports and exports, indexed by local name
this.imports = blank();
this.exports = blank();
this.reexports = blank();
this.exportDelegates = blank();
this.locals = bundle.scope.virtual();
this.exports = bundle.scope.virtual();
this.exportAlls = [];
@ -70,7 +64,7 @@ export default class Module {
this.definitionPromises = blank();
this.modifications = blank();
this.analyse();
this.dependencies = this.collectDependencies();
}
addExport ( statement ) {
@ -79,24 +73,19 @@ export default class Module {
// export { name } from './other'
if ( source ) {
if ( !~this.dependencies.indexOf( source ) ) this.dependencies.push( source );
const module = this.getModule( source );
if ( node.type === 'ExportAllDeclaration' ) {
// Store `export * from '...'` statements in an array of delegates.
// When an unknown import is encountered, we see if one of them can satisfy it.
this.exportAlls.push({
statement,
source
});
this.exportAlls.push( module );
}
else {
node.specifiers.forEach( specifier => {
this.reexports[ specifier.exported.name ] = {
source,
localName: specifier.local.name,
module: null // filled in later
};
// Bind the export of this module, to the export of the other.
this.exports.bind( specifier.exported.name,
module.exports.reference( specifier.local.name ) );
});
}
}
@ -114,15 +103,23 @@ export default class Module {
node.declaration.name :
null;
this.exports.default = {
statement,
if ( identifier ) {
// If the default export has an identifier, bind to it.
this.exports.bind( 'default', this.locals.reference( identifier ) );
} else {
this.exports.define({
originalName: 'default',
name: 'default',
localName: identifier || 'default',
statement,
localName: 'default',
identifier,
isDeclaration,
isAnonymous,
isModified: false // in case of `export default foo; foo = somethingElse`
};
});
}
}
// export { foo, bar, baz }
@ -135,11 +132,7 @@ export default class Module {
const localName = specifier.local.name;
const exportedName = specifier.exported.name;
this.exports[ exportedName ] = {
statement,
localName,
exportedName
};
this.exports.bind( exportedName, this.locals.reference( localName ) );
});
}
@ -156,40 +149,44 @@ export default class Module {
name = declaration.id.name;
}
this.exports[ name ] = {
this.exports.bind({
originalName: name,
name,
statement,
localName: name,
expression: declaration
};
});
}
}
}
addImport ( statement ) {
const node = statement.node;
const source = node.source.value;
if ( !~this.dependencies.indexOf( source ) ) this.dependencies.push( source );
const module = this.getModule( node.source.value );
node.specifiers.forEach( specifier => {
const isDefault = specifier.type === 'ImportDefaultSpecifier';
const isNamespace = specifier.type === 'ImportNamespaceSpecifier';
const name = isDefault ? 'default' : specifier.imported.name;
const localName = specifier.local.name;
const name = isDefault ? 'default' : isNamespace ? '*' : specifier.imported.name;
if ( this.imports[ localName ] ) {
// console.log( `import ${localName} as ${name} ...`);
if ( this.locals.defines( localName ) ) {
const err = new Error( `Duplicated import '${localName}'` );
err.file = this.id;
err.loc = getLocation( this.source, specifier.start );
throw err;
}
this.imports[ localName ] = {
source,
name,
localName
};
if ( isNamespace ) {
// If it's a namespace import, we bind the localName to the module itself.
this.locals.bind( localName, module );
} else {
this.locals.bind( localName, module.exports.reference( name ) );
}
});
}
@ -203,6 +200,15 @@ export default class Module {
// consolidate names that are defined/modified in this module
keys( statement.defines ).forEach( name => {
this.locals.define({
originalName: name,
name,
statement,
module: this
});
// FIXME: remove?
this.definitions[ name ] = statement;
});
@ -243,32 +249,17 @@ export default class Module {
});
}
bindImportSpecifiers () {
if ( this.boundImportSpecifiers ) return;
this.boundImportSpecifiers = true;
[ this.imports, this.reexports ].forEach( specifiers => {
keys( specifiers ).forEach( name => {
const specifier = specifiers[ name ];
if ( specifier.module ) return;
const id = this.resolvedIds[ specifier.source ];
specifier.module = this.bundle.moduleById[ id ];
});
});
// Returns the set of imported module ids by going through all import/exports statements.
collectDependencies () {
const importedModules = blank();
this.exportAlls.forEach( delegate => {
const id = this.resolvedIds[ delegate.source ];
delegate.module = this.bundle.moduleById[ id ];
this.statements.forEach( statement => {
if ( statement.isImportDeclaration || ( statement.isExportDeclaration && statement.node.source ) ) {
importedModules[ statement.node.source.value ] = true;
}
});
this.dependencies.forEach( source => {
const id = this.resolvedIds[ source ];
const module = this.bundle.moduleById[ id ];
if ( !module.isExternal ) module.bindImportSpecifiers();
});
return keys( importedModules );
}
consolidateDependencies () {
@ -284,8 +275,7 @@ export default class Module {
this.statements.forEach( statement => {
if ( statement.isImportDeclaration && !statement.node.specifiers.length ) {
// include module for its side-effects
const id = this.resolvedIds[ statement.node.source.value ];
const module = this.bundle.moduleById[ id ];
const module = this.getModule( statement.node.source.value );
if ( !module.isExternal ) strongDependencies[ module.id ] = module;
}
@ -293,17 +283,11 @@ export default class Module {
else if ( statement.isReexportDeclaration ) {
if ( statement.node.specifiers ) {
statement.node.specifiers.forEach( specifier => {
let reexport;
let module = this;
let name = specifier.exported.name;
while ( !module.isExternal && module.reexports[ name ] && module.reexports[ name ].isUsed ) {
reexport = module.reexports[ name ];
module = reexport.module;
name = reexport.localName;
}
addDependency( strongDependencies, reexport );
let id = this.locals.lookup( name );
addDependency( strongDependencies, id );
});
}
}
@ -312,8 +296,7 @@ export default class Module {
keys( statement.stronglyDependsOn ).forEach( name => {
if ( statement.defines[ name ] ) return;
addDependency( strongDependencies, this.exportDelegates[ name ] ) ||
addDependency( strongDependencies, this.imports[ name ] );
addDependency( strongDependencies, this.locals.lookup( name ) );
});
}
});
@ -324,8 +307,7 @@ export default class Module {
keys( statement.dependsOn ).forEach( name => {
if ( statement.defines[ name ] ) return;
addDependency( weakDependencies, this.exportDelegates[ name ] ) ||
addDependency( weakDependencies, this.imports[ name ] );
addDependency( weakDependencies, this.locals.lookup( name ) );
});
});
@ -355,66 +337,19 @@ export default class Module {
return importDeclaration.module.findDefiningStatement( name );
}
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 );
getModule ( source ) {
return this.bundle.moduleById[ this.resolvedIds[ source ] ];
}
else if ( importDeclaration.name === '*' ) {
// we need to create an internal namespace
if ( !~this.bundle.internalNamespaceModules.indexOf( module ) ) {
this.bundle.internalNamespaceModules.push( module );
}
mark ( name ) {
const id = this.locals.lookup( name );
module.markAllExportStatements();
}
if ( id && !id.statement)
console.log(id)
else {
module.markExport( importDeclaration.name, name, this );
}
}
else {
const statement = name === 'default' ? this.exports.default.statement : this.definitions[ name ];
if ( statement ) statement.mark();
if ( id && id.statement ) {
// Assert that statement is defined. It isn't for external modules.
id.statement.mark();
}
}
@ -427,8 +362,7 @@ export default class Module {
// ...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 ];
const otherModule = this.getModule( statement.node.source.value );
if ( !otherModule.isExternal ) otherModule.markAllStatements();
}
@ -454,39 +388,21 @@ export default class Module {
}
markExport ( name, suggestedName, importer ) {
const reexport = this.reexports[ name ];
const exportDeclaration = this.exports[ name ];
const id = this.exports.lookup( 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();
}
if ( id ) {
// Assert that statement is defined. It isn't for external modules.
if ( id.statement ) id.statement.mark();
this.mark( exportDeclaration.localName );
return;
}
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 );
for ( const module of this.exportAlls ) {
const id = module.exports.lookup( name );
declaration.statement.dependsOn[ name ] =
declaration.statement.stronglyDependsOn[ name ] = true;
if ( id ) {
// Assert that statement is defined. It isn't for external modules.
if ( id.statement ) id.statement.mark();
return;
}
@ -494,7 +410,6 @@ export default class Module {
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)
@ -579,15 +494,12 @@ export default class Module {
return statements;
}
rename ( name, replacement ) {
this.replacements[ name ] = replacement;
}
render ( allBundleExports, moduleReplacements ) {
render ( toExport ) {
let magicString = this.magicString.clone();
this.statements.forEach( statement => {
if ( !statement.isIncluded ) {
console.log( 'removing definer of', keys( statement.defines ) );
magicString.remove( statement.start, statement.next );
return;
}
@ -601,7 +513,7 @@ export default class Module {
}
// skip `export var foo;` if foo is exported
if ( isEmptyExportedVarDeclaration( statement.node.declaration, allBundleExports, moduleReplacements ) ) {
if ( isEmptyExportedVarDeclaration( statement.node.declaration, this.exports, toExport ) ) {
magicString.remove( statement.start, statement.next );
return;
}
@ -609,7 +521,7 @@ export default class Module {
// skip empty var declarations for exported bindings
// (otherwise we're left with `exports.foo;`, which is useless)
if ( isEmptyExportedVarDeclaration( statement.node, allBundleExports, moduleReplacements ) ) {
if ( isEmptyExportedVarDeclaration( statement.node, this.exports, toExport ) ) {
magicString.remove( statement.start, statement.next );
return;
}
@ -617,9 +529,10 @@ export default class Module {
// split up/remove var declarations as necessary
if ( statement.node.isSynthetic ) {
// insert `var/let/const` if necessary
if ( !allBundleExports[ statement.node.declarations[0].id.name ] ) {
magicString.insert( statement.start, `${statement.node.kind} ` );
}
// FIXME: !!
// if ( !allBundleExports[ statement.node.declarations[0].id.name ] ) {
// magicString.insert( statement.start, `${statement.node.kind} ` );
// }
magicString.overwrite( statement.end, statement.next, ';\n' ); // TODO account for trailing newlines
}
@ -630,10 +543,12 @@ export default class Module {
keys( statement.dependsOn )
.concat( keys( statement.defines ) )
.forEach( name => {
const bundleName = moduleReplacements[ name ] || name;
// console.log ( name, statement.node );
// console.log( this.locals );
const bundleName = this.locals.lookup( name ).name;
if ( allBundleExports[ bundleName ] ) {
bundleExports[ name ] = replacements[ name ] = allBundleExports[ bundleName ];
if ( !~toExport.indexOf( bundleName ) ) {
bundleExports[ name ] = replacements[ name ] = bundleName;
} else if ( bundleName !== name ) { // TODO weird structure
replacements[ name ] = bundleName;
}
@ -657,10 +572,11 @@ export default class Module {
else if ( statement.node.type === 'ExportDefaultDeclaration' ) {
const canonicalName = this.defaultName();
if ( statement.node.declaration.type === 'Identifier' && canonicalName === ( moduleReplacements[ statement.node.declaration.name ] || statement.node.declaration.name ) ) {
magicString.remove( statement.start, statement.next );
return;
}
// FIXME: dunno what to do here yet.
// if ( statement.node.declaration.type === 'Identifier' && canonicalName === ( moduleReplacements[ statement.node.declaration.name ] || statement.node.declaration.name ) ) {
// magicString.remove( statement.start, statement.next );
// return;
// }
// prevent `var undefined = sideEffectyDefault(foo)`
if ( canonicalName === undefined ) {
@ -684,15 +600,4 @@ export default class Module {
return magicString.trim();
}
suggestName ( defaultOrBatch, suggestion ) {
// deconflict anonymous default exports with this module's definitions
const shouldDeconflict = this.exports.default && this.exports.default.isAnonymous;
if ( shouldDeconflict ) suggestion = deconflict( suggestion, this.definitions );
if ( !this.suggestedNames[ defaultOrBatch ] ) {
this.suggestedNames[ defaultOrBatch ] = makeLegalIdentifier( suggestion );
}
}
}

20
src/Scope.js

@ -37,10 +37,6 @@ export default class Scope {
// Binds the `name` to the given reference `ref`.
bind ( name, ref ) {
if ( isntReference( ref ) ) {
throw new TypeError( `` );
}
this.ids[ this.index( name ) ] = ref;
}
@ -71,6 +67,11 @@ export default class Scope {
}
}
// TODO: rename! Too similar to `define`.
defines ( name ) {
return name in this.names;
}
// !! private, don't use !!
//
// Lookup the `ids` index of `name`.
@ -84,6 +85,11 @@ export default class Scope {
return this.names[ name ];
}
// Returns a list of [ localName, identifier ] tuples.
localIds () {
return keys( this.names ).map( name => [ name, this.lookup( name ) ] );
}
// Lookup the identifier referred to by `name`.
lookup ( name ) {
let id = this.ids[ this.names[ name ] ];
@ -97,7 +103,11 @@ export default class Scope {
// Get a reference to the identifier `name` in this scope.
reference ( name ) {
return new Reference( this, this.names[ name ] );
if ( !this.defines( name ) ) {
this.define( name );
}
return new Reference( this, this.index( name ) );
}
// Return the names currently in use in the scope.

21
src/Statement.js

@ -189,6 +189,7 @@ export default class Statement {
// disallow assignments/updates to imported bindings and namespaces
if ( isAssignment ) {
// FIXME: imports is no longer used.
const importSpecifier = this.module.imports[ node.name ];
if ( importSpecifier && !scope.contains( node.name ) ) {
@ -207,11 +208,12 @@ export default class Statement {
// 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 && depth === 0 && this.module.exports.default.identifier === node.name ) {
const def = this.module.exports.lookup( 'default' );
if ( def && depth === 0 && def.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;
if ( !!scope.parent || node.start > def.statement.node.start ) {
def.isModified = true;
}
}
@ -260,18 +262,14 @@ export default class Statement {
if ( this.isIncluded ) return; // prevent infinite loops
this.isIncluded = true;
console.log( 'marking definer of', keys( this.defines ) );
// `export { name } from './other'` is a special case
if ( this.isReexportDeclaration ) {
const id = this.module.resolvedIds[ this.node.source.value ];
const otherModule = this.module.bundle.moduleById[ id ];
const otherModule = this.module.getModule( this.node.source.value );
this.node.specifiers.forEach( specifier => {
const reexport = this.module.reexports[ specifier.exported.name ];
reexport.isUsed = true;
reexport.module = otherModule; // TODO still necessary?
if ( !otherModule.isExternal ) otherModule.markExport( specifier.local.name, specifier.exported.name, this.module );
otherModule.exports.lookup( specifier.local.name ).statement.mark();
});
return;
@ -284,6 +282,7 @@ export default class Statement {
}
replaceIdentifiers ( magicString, names, bundleExports ) {
console.log( magicString.slice(this.start, this.end) );
const replacementStack = [ names ];
const nameList = keys( names );

2
src/utils/getExportMode.js

@ -5,7 +5,7 @@ function badExports ( option, keys ) {
}
export default function getExportMode ( bundle, exportMode ) {
const exportKeys = keys( bundle.entryModule.exports ).concat( keys( bundle.entryModule.reexports ) );
const exportKeys = bundle.entryModule.exports.usedNames();
if ( exportMode === 'default' ) {
if ( exportKeys.length !== 1 || exportKeys[0] !== 'default' ) {

Loading…
Cancel
Save