diff --git a/src/ExternalModule.js b/src/ExternalModule.js index e8749f8..757d56d 100644 --- a/src/ExternalModule.js +++ b/src/ExternalModule.js @@ -1,18 +1,19 @@ +import { blank } from './utils/object'; +import makeLegalIdentifier from './utils/makeLegalIdentifier'; export default class ExternalModule { constructor ( { id, bundle } ) { this.id = id; // Implement `Identifier` interface. - this.originalName = id; - this.name = id; + this.originalName = this.name = makeLegalIdentifier( id ); this.module = this; // Define the external module's name in the bundle scope. bundle.scope.define( id, this ); this.isExternal = true; - this.importedByBundle = []; + this.importedByBundle = blank(); // Invariant: needsNamed and needsAll are never both true at once. // Because an import with both a namespace and named import is invalid: diff --git a/src/Module.js b/src/Module.js index deef71b..d10eaa7 100644 --- a/src/Module.js +++ b/src/Module.js @@ -224,6 +224,7 @@ export default class Module { if ( isNamespace ) { // If it's a namespace import, we bind the localName to the module itself. module.needsAll = true; + module.name = localName; this.locals.bind( localName, module ); } else { const name = isDefault ? 'default' : specifier.imported.name; @@ -237,6 +238,7 @@ export default class Module { if ( module.isExternal && isDefault ) { const id = module.exports.lookup( name ); module.name = id.name = localName; + id.name += '__default'; } } }); @@ -393,10 +395,16 @@ export default class Module { mark ( name ) { const id = this.locals.lookup( name ); - if ( id && id.statement ) { - // Assert that statement is defined. It isn't for external modules. - id.isUsed = true; - id.statement.mark(); + if ( id && id.module ) { + if ( id.module.isExternal ) { + id.module.importedByBundle[ id.originalName ] = true; + } + + if ( id.statement ) { + // Assert that statement is defined. It isn't for external modules. + id.isUsed = true; + id.statement.mark(); + } } } @@ -601,7 +609,11 @@ export default class Module { .forEach( name => { const id = this.locals.lookup( name ); - if ( id.module && id.module.isExternal ) { + // We shouldn't create a replacement for `id` if + // 1. `id` is a Global, in which case it has no module property + // 2. `id.module` isn't external, which means we have direct access + // 3. `id` is its own module, in the case of namespace imports + if ( id.module && id.module.isExternal && id.module !== id ) { replacements[ name ] = id.originalName === 'default' ? // default names are always directly accessed id.name : diff --git a/src/utils/makeLegalIdentifier.js b/src/utils/makeLegalIdentifier.js index 7e0a846..1dd4454 100644 --- a/src/utils/makeLegalIdentifier.js +++ b/src/utils/makeLegalIdentifier.js @@ -8,7 +8,10 @@ reservedWords.concat( builtins ).forEach( word => blacklisted[ word ] = true ); export default function makeLegalIdentifier ( str ) { - str = str.replace( /[^$_a-zA-Z0-9]/g, '_' ); + str = str + .replace( /-(\w)/g, ( _, letter ) => letter.toUpperCase() ) + .replace( /[^$_a-zA-Z0-9]/g, '_' ); + if ( /\d/.test( str[0] ) || blacklisted[ str ] ) str = `_${str}`; return str; diff --git a/test/form/external-imports/_expected/cjs.js b/test/form/external-imports/_expected/cjs.js index ac9f79d..b6f5d31 100644 --- a/test/form/external-imports/_expected/cjs.js +++ b/test/form/external-imports/_expected/cjs.js @@ -1,10 +1,10 @@ 'use strict'; var factory = require('factory'); -factory = 'default' in factory ? factory['default'] : factory; var baz = require('baz'); var containers = require('shipping-port'); var alphabet = require('alphabet'); +factory = 'default' in factory ? factory['default'] : factory; var alphabet__default = 'default' in alphabet ? alphabet['default'] : alphabet; factory( null ); diff --git a/test/form/external-imports/_expected/es6.js b/test/form/external-imports/_expected/es6.js index cd41111..4d05b46 100644 --- a/test/form/external-imports/_expected/es6.js +++ b/test/form/external-imports/_expected/es6.js @@ -1,10 +1,10 @@ import factory from 'factory'; import { bar, foo } from 'baz'; import * as containers from 'shipping-port'; -import alphabet, { a } from 'alphabet'; +import alphabet__default, { a } from 'alphabet'; factory( null ); foo( bar ); containers.forEach( console.log, console ); console.log( a ); -console.log( alphabet.length ); +console.log( alphabet__default.length );