Browse Source

Merge pull request #86 from rollup/reexports

Reexports
contingency-plan
Rich Harris 9 years ago
parent
commit
4ebd300abb
  1. 133
      src/Bundle.js
  2. 212
      src/Module.js
  3. 32
      src/Statement.js
  4. 17
      src/ast/Scope.js
  5. 30
      src/finalisers/es6.js
  6. 2
      src/finalisers/shared/getExportBlock.js
  7. 2
      src/utils/getExportMode.js
  8. 4
      test/form/exported-empty-vars/_expected/es6.js
  9. 3
      test/form/multiple-exports/_expected/es6.js
  10. 2
      test/function/deconflicts-globals/bar.js
  11. 2
      test/function/deconflicts-globals/foo.js
  12. 12
      test/function/export-from-with-definition-conflict/_config.js
  13. 3
      test/function/export-from-with-definition-conflict/a.js
  14. 9
      test/function/export-from-with-definition-conflict/main.js
  15. 12
      test/function/export-from-with-import-conflict/_config.js
  16. 3
      test/function/export-from-with-import-conflict/a.js
  17. 2
      test/function/export-from-with-import-conflict/b.js
  18. 8
      test/function/export-from-with-import-conflict/main.js
  19. 10
      test/function/export-two-ways/_config.js
  20. 2
      test/function/export-two-ways/foo.js
  21. 5
      test/function/export-two-ways/main.js

133
src/Bundle.js

@ -224,7 +224,7 @@ export default class Bundle {
keys( statement.modifies ).forEach( name => {
const definingStatement = module.definitions[ name ];
const exportDeclaration = module.exports[ name ] || (
const exportDeclaration = module.exports[ name ] || module.reexports[ name ] || (
module.exports.default && module.exports.default.identifier === name && module.exports.default
);
@ -290,29 +290,42 @@ export default class Bundle {
//
// This doesn't apply if the bundle is exported as ES6!
let allBundleExports = blank();
let isVarDeclaration = blank();
let varExports = blank();
let getterExports = [];
if ( format !== 'es6' && exportMode === 'named' ) {
keys( this.entryModule.exports ).forEach( key => {
const exportDeclaration = this.entryModule.exports[ key ];
const originalDeclaration = this.entryModule.findDeclaration( exportDeclaration.localName );
if ( originalDeclaration && originalDeclaration.type === 'VariableDeclaration' ) {
const canonicalName = this.trace( this.entryModule, exportDeclaration.localName, false );
allBundleExports[ canonicalName ] = `exports.${key}`;
varExports[ key ] = true;
}
this.orderedModules.forEach( module => {
module.varDeclarations.forEach( name => {
isVarDeclaration[ module.replacements[ name ] || name ] = true;
});
});
if ( format !== 'es6' && exportMode === 'named' ) {
keys( this.entryModule.exports )
.concat( keys( this.entryModule.reexports ) )
.forEach( name => {
const canonicalName = this.traceExport( this.entryModule, name );
if ( isVarDeclaration[ canonicalName ] ) {
varExports[ name ] = true;
// if the same binding is exported multiple ways, we need to
// use getters to keep all exports in sync
if ( allBundleExports[ canonicalName ] ) {
getterExports.push({ key: name, value: allBundleExports[ canonicalName ] });
} else {
allBundleExports[ canonicalName ] = `exports.${name}`;
}
}
});
}
// 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 ] );
let magicString = new MagicString.Bundle({ separator: '\n\n' });
this.orderedModules.forEach( module => {
@ -323,43 +336,38 @@ export default class Bundle {
});
// prepend bundle with internal namespaces
const indentString = magicString.getIndentString();
const indentString = getIndentString( magicString, options );
const namespaceBlock = this.internalNamespaceModules.map( module => {
const exportKeys = keys( module.exports );
const exports = keys( module.exports )
.concat( keys( module.reexports ) )
.map( name => {
const canonicalName = this.traceExport( module, name );
return `${indentString}get ${name} () { return ${canonicalName}; }`;
});
return `var ${module.replacements['*']} = {\n` +
exportKeys.map( key => {
let actualModule = module;
let exportDeclaration = module.exports[ key ];
// special case - `export { default as foo } from './foo'`
while ( exportDeclaration.linkedImport ) {
actualModule = exportDeclaration.linkedImport.module;
exportDeclaration = actualModule.exports[ exportDeclaration.linkedImport.name ];
}
let localName = exportDeclaration.localName;
localName = actualModule.replacements[ localName ] || localName;
return `${indentString}get ${key} () { return ${localName}; }`; // TODO...
}).join( ',\n' ) +
exports.join( ',\n' ) +
`\n};\n\n`;
}).join( '' );
magicString.prepend( namespaceBlock );
if ( getterExports.length ) {
// TODO offer ES3-safe (but not spec-compliant) alternative?
const getterExportsBlock = `Object.defineProperties(exports, {\n` +
getterExports.map( ({ key, value }) => indentString + `${key}: { get: function () { return ${value}; } }` ).join( ',\n' ) +
`\n});`;
magicString.append( '\n\n' + getterExportsBlock );
}
const finalise = finalisers[ format ];
if ( !finalise ) {
throw new Error( `You must specify an output type - valid options are ${keys( finalisers ).join( ', ' )}` );
}
magicString = finalise( this, magicString.trim(), {
// Determine export mode - 'default', 'named', 'none'
exportMode,
// Determine indentation
indentString: getIndentString( magicString, options )
}, options );
magicString = finalise( this, magicString.trim(), { exportMode, indentString }, options );
if ( options.banner ) magicString.prepend( options.banner + '\n' );
if ( options.footer ) magicString.append( '\n' + options.footer );
@ -469,50 +477,39 @@ export default class Bundle {
const importDeclaration = module.imports[ localName ];
// defined in this module
if ( !importDeclaration ) {
if ( localName === 'default' ) return module.defaultName();
return module.replacements[ localName ] || localName;
}
if ( !importDeclaration ) return module.replacements[ localName ] || localName;
// defined elsewhere
const otherModule = importDeclaration.module;
if ( otherModule.isExternal ) {
if ( importDeclaration.name === 'default' ) {
return otherModule.needsNamed && !es6 ?
`${otherModule.name}__default` :
otherModule.name;
}
if ( importDeclaration.name === '*' ) {
return otherModule.name;
}
return this.traceExport( importDeclaration.module, importDeclaration.name, es6 );
}
return es6 ?
importDeclaration.name :
`${otherModule.name}.${importDeclaration.name}`;
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}`;
}
if ( importDeclaration.name === '*' ) {
return otherModule.replacements[ '*' ];
const reexportDeclaration = module.reexports[ name ];
if ( reexportDeclaration ) {
return this.traceExport( reexportDeclaration.module, reexportDeclaration.localName );
}
if ( importDeclaration.name === 'default' ) {
return otherModule.defaultName();
}
if ( name === '*' ) return module.replacements[ '*' ];
if ( name === 'default' ) return module.defaultName();
const exportDeclaration = otherModule.exports[ importDeclaration.name ];
if ( exportDeclaration ) return this.trace( otherModule, exportDeclaration.localName );
const exportDeclaration = module.exports[ name ];
if ( exportDeclaration ) return this.trace( module, exportDeclaration.localName );
for ( let i = 0; i < otherModule.exportDelegates.length; i += 1 ) {
const delegate = otherModule.exportDelegates[i];
const delegateExportDeclaration = delegate.module.exports[ importDeclaration.name ];
for ( let i = 0; i < module.exportDelegates.length; i += 1 ) {
const delegate = module.exportDelegates[i];
const delegateExportDeclaration = delegate.module.exports[ name ];
if ( delegateExportDeclaration ) {
return this.trace( delegate.module, delegateExportDeclaration.localName );
return this.trace( delegate.module, delegateExportDeclaration.localName, es6 );
}
}
throw new Error( 'Could not trace binding' );
throw new Error( `Could not trace binding '${name}' from ${module.id}` );
}
}

212
src/Module.js

@ -55,6 +55,7 @@ export default class Module {
// imports and exports, indexed by ID
this.imports = blank();
this.exports = blank();
this.reexports = blank();
this.exportAlls = blank();
@ -63,6 +64,8 @@ export default class Module {
this.replacements = blank();
this.varDeclarations = [];
this.definitions = blank();
this.definitionPromises = blank();
this.modifications = blank();
@ -74,10 +77,32 @@ export default class Module {
const node = statement.node;
const source = node.source && node.source.value;
// export { name } from './other'
if ( 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.exportDelegates.push({
statement,
source
});
}
else {
node.specifiers.forEach( specifier => {
this.reexports[ specifier.exported.name ] = {
source,
localName: specifier.local.name,
module: null // filled in later
};
});
}
}
// export default function foo () {}
// export default foo;
// export default 42;
if ( node.type === 'ExportDefaultDeclaration' ) {
else if ( node.type === 'ExportDefaultDeclaration' ) {
const isDeclaration = /Declaration$/.test( node.declaration.type );
const isAnonymous = /(?:Class|Function)Expression$/.test( node.declaration.type );
@ -108,20 +133,10 @@ export default class Module {
const localName = specifier.local.name;
const exportedName = specifier.exported.name;
// export { foo } from './foo';
if ( source ) {
this.imports[ localName ] = {
source,
localName: exportedName,
name: localName
};
}
this.exports[ exportedName ] = {
statement,
localName,
exportedName,
linkedImport: source ? this.imports[ localName ] : null
exportedName
};
});
}
@ -146,15 +161,6 @@ export default class Module {
};
}
}
// Store `export * from '...'` statements in an array of delegates.
// When an unknown import is encountered, we see if one of them can satisfy it.
else {
this.exportDelegates.push({
statement,
source
});
}
}
addImport ( statement ) {
@ -196,6 +202,10 @@ export default class Module {
this.definitions[ name ] = statement;
});
statement.scope.varDeclarations.forEach( name => {
this.varDeclarations.push( name );
});
keys( statement.modifies ).forEach( name => {
( this.modifications[ name ] || ( this.modifications[ name ] = [] ) ).push( statement );
});
@ -204,6 +214,8 @@ export default class Module {
// if names are referenced that are neither defined nor imported
// in this module, we assume that they're globals
this.statements.forEach( statement => {
if ( statement.isReexportDeclaration ) return;
keys( statement.dependsOn ).forEach( name => {
if ( !this.definitions[ name ] && !this.imports[ name ] ) {
this.bundle.assumedGlobals[ name ] = true;
@ -215,28 +227,45 @@ export default class Module {
consolidateDependencies () {
let strongDependencies = blank();
function addDependency ( dependencies, declaration ) {
if ( declaration && declaration.module && !declaration.module.isExternal ) {
dependencies[ declaration.module.id ] = declaration.module;
return true;
}
}
this.statements.forEach( statement => {
if ( statement.isImportDeclaration && !statement.node.specifiers.length && !statement.module.isExternal ) {
// include module for its side-effects
strongDependencies[ statement.module.id ] = statement.module; // TODO is this right? `statement.module` should be `this`, surely?
}
keys( statement.stronglyDependsOn ).forEach( name => {
if ( statement.defines[ name ] ) return;
const exportAllDeclaration = this.exportAlls[ name ];
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;
}
if ( exportAllDeclaration && exportAllDeclaration.module && !exportAllDeclaration.module.isExternal ) {
strongDependencies[ exportAllDeclaration.module.id ] = exportAllDeclaration.module;
return;
addDependency( strongDependencies, reexport );
});
}
}
const importDeclaration = this.imports[ name ];
else {
keys( statement.stronglyDependsOn ).forEach( name => {
if ( statement.defines[ name ] ) return;
if ( importDeclaration && importDeclaration.module && !importDeclaration.module.isExternal ) {
strongDependencies[ importDeclaration.module.id ] = importDeclaration.module;
}
});
addDependency( strongDependencies, this.exportAlls[ name ] ) ||
addDependency( strongDependencies, this.imports[ name ] );
});
}
});
let weakDependencies = blank();
@ -245,11 +274,8 @@ export default class Module {
keys( statement.dependsOn ).forEach( name => {
if ( statement.defines[ name ] ) return;
const importDeclaration = this.imports[ name ];
if ( importDeclaration && importDeclaration.module && !importDeclaration.module.isExternal ) {
weakDependencies[ importDeclaration.module.id ] = importDeclaration.module;
}
addDependency( weakDependencies, this.exportAlls[ name ] ) ||
addDependency( weakDependencies, this.imports[ name ] );
});
});
@ -283,33 +309,6 @@ export default class Module {
});
}
findDeclaration ( localName ) {
const importDeclaration = this.imports[ localName ];
// name was defined by another module
if ( importDeclaration ) {
const module = importDeclaration.module;
if ( module.isExternal ) return null;
if ( importDeclaration.name === '*' ) return null;
if ( importDeclaration.name === 'default' ) return null;
const exportDeclaration = module.exports[ importDeclaration.name ];
return module.findDeclaration( exportDeclaration.localName );
}
// name was defined by this module, if any
let i = this.statements.length;
while ( i-- ) {
const declaration = this.statements[i].scope.declarations[ localName ];
if ( declaration ) {
return declaration;
}
}
return null;
}
mark ( name ) {
// shortcut cycles
if ( this.definitionPromises[ name ] ) {
@ -346,7 +345,7 @@ export default class Module {
module.suggestName( 'default', `${suggestion}__default` );
}
if ( importDeclaration.name === 'default' && ( module.isExternal || !module.exports.default.linkedImport ) ) { // special case - exclude `export { default } from ...`
if ( importDeclaration.name === 'default' ) {
module.needsDefault = true;
} else if ( importDeclaration.name === '*' ) {
module.needsAll = true;
@ -368,39 +367,7 @@ export default class Module {
return module.markAllExportStatements();
}
const exportDeclaration = module.exports[ importDeclaration.name ];
if ( !exportDeclaration ) {
const noExport = new Error( `Module ${module.id} does not export ${importDeclaration.name} (imported by ${this.id})` );
// See if there exists an export delegate that defines `name`.
return first( module.exportDelegates, noExport, declaration => {
return module.bundle.fetchModule( declaration.source, module.id ).then( submodule => {
declaration.module = submodule;
return submodule.mark( name ).then( result => {
if ( !result.length ) throw noExport;
// It's found! This module exports `name` through declaration.
// It is however not imported into this scope.
module.exportAlls[ name ] = declaration;
declaration.statement.dependsOn[ name ] =
declaration.statement.stronglyDependsOn[ name ] = result;
return result;
});
});
});
}
exportDeclaration.isUsed = true;
if ( importDeclaration.name === 'default' ) {
return exportDeclaration.statement.mark();
}
return module.mark( exportDeclaration.localName );
return module.markExport( importDeclaration.name, name, this );
});
}
@ -458,6 +425,53 @@ export default class Module {
});
}
markExport ( name, suggestedName, importer ) {
const reexportDeclaration = this.reexports[ name ];
if ( reexportDeclaration ) {
reexportDeclaration.isUsed = true;
return this.bundle.fetchModule( reexportDeclaration.source, this.id )
.then( otherModule => {
reexportDeclaration.module = otherModule;
return otherModule.markExport( reexportDeclaration.localName, suggestedName, this );
});
}
const exportDeclaration = this.exports[ name ];
if ( exportDeclaration ) {
exportDeclaration.isUsed = true;
if ( name === 'default' ) {
this.needsDefault = true;
this.suggestName( 'default', suggestedName );
return exportDeclaration.statement.mark();
}
return this.mark( exportDeclaration.localName );
}
const noExport = new Error( `Module ${this.id} does not export ${name} (imported by ${importer.id})` );
// See if there exists an export delegate that defines `name`.
return first( this.exportDelegates, noExport, declaration => {
return this.bundle.fetchModule( declaration.source, this.id ).then( submodule => {
declaration.module = submodule;
return submodule.mark( name ).then( result => {
if ( !result.length ) throw noExport;
// It's found! This module exports `name` through declaration.
// It is however not imported into this scope.
this.exportAlls[ name ] = declaration;
declaration.statement.dependsOn[ name ] =
declaration.statement.stronglyDependsOn[ name ] = result;
return result;
});
});
});
}
parse ( ast ) {
// The ast can be supplied programmatically (but usually won't be)
if ( !ast ) {

32
src/Statement.js

@ -26,6 +26,7 @@ export default class Statement {
this.isImportDeclaration = node.type === 'ImportDeclaration';
this.isExportDeclaration = /^Export/.test( node.type );
this.isReexportDeclaration = this.isExportDeclaration && !!node.source;
}
analyse () {
@ -42,7 +43,7 @@ export default class Statement {
case 'FunctionDeclaration':
case 'ArrowFunctionExpression':
if ( node.type === 'FunctionDeclaration' ) {
scope.addDeclaration( node.id.name, node );
scope.addDeclaration( node.id.name, node, false );
}
newScope = new Scope({
@ -54,7 +55,7 @@ export default class Statement {
// named function expressions - the name is considered
// part of the function's scope
if ( node.type === 'FunctionExpression' && node.id ) {
newScope.addDeclaration( node.id.name, node );
newScope.addDeclaration( node.id.name, node, false );
}
break;
@ -80,12 +81,12 @@ export default class Statement {
case 'VariableDeclaration':
node.declarations.forEach( declarator => {
scope.addDeclaration( declarator.id.name, node );
scope.addDeclaration( declarator.id.name, node, true );
});
break;
case 'ClassDeclaration':
scope.addDeclaration( node.id.name, node );
scope.addDeclaration( node.id.name, node, false );
break;
}
@ -163,7 +164,7 @@ export default class Statement {
const definingScope = scope.findDefiningScope( node.name );
if ( ( !definingScope || definingScope.depth === 0 ) && !this.defines[ node.name ] ) {
if ( !definingScope || definingScope.depth === 0 ) {
this.dependsOn[ node.name ] = true;
if ( strong ) this.stronglyDependsOn[ node.name ] = true;
}
@ -235,6 +236,23 @@ export default class Statement {
if ( this.isIncluded ) return; // prevent infinite loops
this.isIncluded = true;
// `export { name } from './other'` is a special case
if ( this.isReexportDeclaration ) {
return this.module.bundle.fetchModule( this.node.source.value, this.module.id )
.then( otherModule => {
return sequence( this.node.specifiers, specifier => {
const reexport = this.module.reexports[ specifier.exported.name ];
reexport.isUsed = true;
reexport.module = otherModule;
return otherModule.isExternal ?
null :
otherModule.markExport( specifier.local.name, specifier.exported.name, this.module );
});
});
}
const dependencies = Object.keys( this.dependsOn );
return sequence( dependencies, name => {
@ -371,6 +389,10 @@ export default class Statement {
return magicString;
}
source () {
return this.module.source.slice( this.start, this.end );
}
toString () {
return this.module.magicString.slice( this.start, this.end );
}

17
src/ast/Scope.js

@ -14,6 +14,8 @@ export default class Scope {
this.declarations = blank();
this.isBlockScope = !!options.block;
this.varDeclarations = [];
if ( options.params ) {
options.params.forEach( param => {
this.declarations[ param.name ] = param;
@ -21,25 +23,16 @@ export default class Scope {
}
}
// add ( name, isBlockDeclaration ) {
// if ( !isBlockDeclaration && this.isBlockScope ) {
// // it's a `var` or function declaration, and this
// // is a block scope, so we need to go up
// this.parent.add( name, isBlockDeclaration );
// } else {
// this.names.push( name );
// }
// }
addDeclaration ( name, declaration ) {
addDeclaration ( name, declaration, isVar ) {
const isBlockDeclaration = declaration.type === 'VariableDeclaration' && blockDeclarations[ declaration.kind ];
if ( !isBlockDeclaration && this.isBlockScope ) {
// it's a `var` or function declaration, and this
// is a block scope, so we need to go up
this.parent.addDeclaration( name, declaration );
this.parent.addDeclaration( name, declaration, isVar );
} else {
this.declarations[ name ] = declaration;
if ( isVar ) this.varDeclarations.push( name )
}
}

30
src/finalisers/es6.js

@ -10,6 +10,10 @@ function uniqueNames ( declarations ) {
return keys( uniques );
}
function notDefault ( name ) {
return name !== 'default';
}
export default function es6 ( bundle, magicString ) {
const importBlock = bundle.externalModules
.map( module => {
@ -40,23 +44,25 @@ export default function es6 ( bundle, magicString ) {
magicString.prepend( importBlock + '\n\n' );
}
const exports = bundle.entryModule.exports;
const exportBlock = keys( exports ).map( exportedName => {
const specifier = exports[ exportedName ];
const module = bundle.entryModule;
const canonicalName = bundle.entryModule.replacements[ specifier.localName ] || specifier.localName;
const specifiers = bundle.toExport.filter( notDefault ).map( name => {
const canonicalName = bundle.traceExport( module, name );
if ( exportedName === 'default' ) {
return `export default ${canonicalName};`;
}
return canonicalName === name ?
name :
`${canonicalName} as ${name}`;
});
return exportedName === canonicalName ?
`export { ${exportedName} };` :
`export { ${canonicalName} as ${exportedName} };`;
}).join( '\n' );
let exportBlock = specifiers.length ? `export { ${specifiers.join(', ')} };` : '';
const defaultExport = module.exports.default || module.reexports.default;
if ( defaultExport ) {
exportBlock += `export default ${bundle.traceExport(module,'default')};`;
}
if ( exportBlock ) {
magicString.append( '\n\n' + exportBlock );
magicString.append( '\n\n' + exportBlock.trim() );
}
return magicString.trim();

2
src/finalisers/shared/getExportBlock.js

@ -11,7 +11,7 @@ export default function getExportBlock ( bundle, exportMode, mechanism = 'return
return bundle.toExport
.map( name => {
const prop = name === 'default' ? `['default']` : `.${name}`;
name = bundle.trace( bundle.entryModule, name );
name = bundle.traceExport( bundle.entryModule, name );
return `exports${prop} = ${name};`;
})
.join( '\n' );

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 );
const exportKeys = keys( bundle.entryModule.exports ).concat( keys( bundle.entryModule.reexports ) );
if ( exportMode === 'default' ) {
if ( exportKeys.length !== 1 || exportKeys[0] !== 'default' ) {

4
test/form/exported-empty-vars/_expected/es6.js

@ -6,6 +6,4 @@ var baz;
bar = 43;
baz = 44;
export { foo };
export { bar };
export { baz };
export { foo, bar, baz };

3
test/form/multiple-exports/_expected/es6.js

@ -1,5 +1,4 @@
var foo = 1;
var bar = 2;
export { foo };
export { bar };
export { foo, bar };

2
test/function/deconflicts-globals/bar.js

@ -3,4 +3,4 @@ import foo from './foo';
export default function() {
assert.equal( foo(), 'foo' );
return Number;
};
}

2
test/function/deconflicts-globals/foo.js

@ -2,4 +2,4 @@ export var Number = 42;
export default function() {
return 'foo';
};
}

12
test/function/export-from-with-definition-conflict/_config.js

@ -0,0 +1,12 @@
var assert = require( 'assert' );
module.exports = {
description: 'ignores conflict between local definitions and export from declaration',
exports: function ( exports ) {
assert.equal( exports.foo, 'a-bar' );
assert.equal( exports.bar, 'a-foo' );
assert.equal( exports.baz, 'a-baz' );
}
};
// https://github.com/rollup/rollup/issues/16

3
test/function/export-from-with-definition-conflict/a.js

@ -0,0 +1,3 @@
export var foo = 'a-foo';
export var bar = 'a-bar';
export var baz = 'a-baz';

9
test/function/export-from-with-definition-conflict/main.js

@ -0,0 +1,9 @@
var foo = 'local-foo';
var baz = 'local-baz';
export { foo as bar } from './a';
export { bar as foo } from './a';
export { baz } from './a';
assert.equal( foo, 'local-foo' );
assert.equal( baz, 'local-baz' );

12
test/function/export-from-with-import-conflict/_config.js

@ -0,0 +1,12 @@
var assert = require( 'assert' );
module.exports = {
description: 'ignores conflict between import declaration and export from declaration',
exports: function ( exports ) {
assert.equal( exports.foo, 'a-bar' );
assert.equal( exports.bar, 'a-foo' );
assert.equal( exports.baz, 'a-baz' );
}
};
// https://github.com/rollup/rollup/issues/16

3
test/function/export-from-with-import-conflict/a.js

@ -0,0 +1,3 @@
export var foo = 'a-foo';
export var bar = 'a-bar';
export var baz = 'a-baz';

2
test/function/export-from-with-import-conflict/b.js

@ -0,0 +1,2 @@
export var foo = 'b-foo';
export var baz = 'b-baz';

8
test/function/export-from-with-import-conflict/main.js

@ -0,0 +1,8 @@
import { foo, baz } from './b';
export { foo as bar } from './a';
export { bar as foo } from './a';
export { baz } from './a';
assert.equal( foo, 'b-foo' );
assert.equal( baz, 'b-baz' );

10
test/function/export-two-ways/_config.js

@ -0,0 +1,10 @@
var assert = require( 'assert' );
module.exports = {
description: 'exports the same binding more than one way',
exports: function ( exports ) {
assert.equal( exports.a, 2 );
assert.equal( exports.b, 2 );
assert.equal( exports.c, 2 );
}
};

2
test/function/export-two-ways/foo.js

@ -0,0 +1,2 @@
export var foo = 1;
foo = 2;

5
test/function/export-two-ways/main.js

@ -0,0 +1,5 @@
import { foo } from './foo';
export { foo as a };
export { foo as b };
export { foo as c };
Loading…
Cancel
Save