Socket
Socket
Sign inDemoInstall

rollup

Package Overview
Dependencies
31
Maintainers
1
Versions
800
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.13.0 to 0.14.0

7

CHANGELOG.md
# rollup changelog
## 0.14.0
* Internal refactoring
* Correctly deconflict generated default export names ([#72](https://github.com/rollup/rollup/issues/72))
* Handle `export { x } from 'y'` declarations ([#74](https://github.com/rollup/rollup/issues/74))
* Dedupe named imports from external modules in ES6 bundles ([#77](https://github.com/rollup/rollup/issues/77))
## 0.13.0

@@ -4,0 +11,0 @@

8

package.json
{
"name": "rollup",
"version": "0.13.0",
"version": "0.14.0",
"description": "Next-generation ES6 module bundler",

@@ -14,3 +14,4 @@ "main": "dist/rollup.js",

"build": "gobble build -f dist",
"prepublish": "npm test"
"prepublish": "npm test",
"lint": "eslint src"
},

@@ -37,2 +38,3 @@ "repository": {

"console-group": "^0.1.2",
"eslint": "^1.1.0",
"gobble": "^0.10.1",

@@ -43,3 +45,3 @@ "gobble-babel": "^5.5.8",

"gobble-esperanto-bundle": "^0.2.0",
"gobble-rollup": "^0.5.0",
"gobble-rollup": "^0.6.0",
"gobble-rollup-babel": "^0.1.0",

@@ -46,0 +48,0 @@ "mocha": "^2.2.4",

@@ -51,3 +51,3 @@ import { blank } from '../utils/object';

findDefiningScope ( name ) {
if ( !!this.declarations[ name ] ) {
if ( this.declarations[ name ] ) {
return this;

@@ -54,0 +54,0 @@ }

@@ -33,3 +33,2 @@ import { basename, extname } from './utils/path';

this.varExports = blank();
this.toExport = null;

@@ -56,6 +55,8 @@

if ( defaultExport ) {
entryModule.needsDefault = true;
// `export default function foo () {...}` -
// use the declared name for the export
if ( defaultExport.declaredName ) {
entryModule.suggestName( 'default', defaultExport.declaredName );
if ( defaultExport.identifier ) {
entryModule.suggestName( 'default', defaultExport.identifier );
}

@@ -92,74 +93,68 @@

// TODO would be better to deconflict once, rather than per-render
deconflict ( es6 ) {
let definers = blank();
let conflicts = blank();
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 );
while ( definers[ name ] ) {
conflicts[ name ] = true;
name = `_${name}`;
}
definers[ name ] = [ module ];
module.name = name;
this.assumedGlobals[ name ] = true;
module.name = getSafeName( name );
});
// Discover conflicts (i.e. two statements in separate modules both define `foo`)
this.orderedModules.forEach( module => {
module.statements.forEach( statement => {
const names = keys( statement.defines );
let i = this.orderedModules.length;
while ( i-- ) {
const module = this.orderedModules[i];
// with default exports that are expressions (`export default 42`),
// we need to ensure that the name chosen for the expression does
// not conflict
if ( statement.node.type === 'ExportDefaultDeclaration' ) {
const name = module.getCanonicalName( 'default', es6 );
// while we're here...
allReplacements[ module.id ] = blank();
const isProxy = statement.node.declaration && statement.node.declaration.type === 'Identifier';
const shouldDeconflict = !isProxy || ( module.getCanonicalName( statement.node.declaration.name, es6 ) !== name );
if ( shouldDeconflict && !~names.indexOf( name ) ) {
names.push( name );
}
keys( module.definitions ).forEach( name => {
const safeName = getSafeName( name );
if ( safeName !== name ) {
module.rename( name, safeName );
allReplacements[ module.id ][ name ] = safeName;
}
});
}
names.forEach( name => {
if ( definers[ name ] ) {
conflicts[ name ] = true;
} else {
definers[ name ] = [];
}
// Assign non-conflicting names to internal default/namespace export
this.orderedModules.forEach( module => {
if ( !module.needsDefault && !module.needsAll ) return;
// TODO in good js, there shouldn't be duplicate definitions
// per module... but some people write bad js
definers[ name ].push( module );
});
});
});
if ( module.needsAll ) {
const namespaceName = getSafeName( module.suggestedNames[ '*' ] );
module.replacements[ '*' ] = namespaceName;
}
// Ensure we don't conflict with globals
keys( this.assumedGlobals ).forEach( name => {
if ( definers[ name ] ) {
conflicts[ name ] = true;
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;
}
});
// Rename conflicting identifiers so they can live in the same scope
keys( conflicts ).forEach( name => {
const modules = definers[ name ];
this.orderedModules.forEach( module => {
keys( module.imports ).forEach( localName => {
if ( !module.imports[ localName ].isUsed ) return;
if ( !this.assumedGlobals[ name ] ) {
// the module closest to the entryModule gets away with
// keeping things as they are, unless we have a conflict
// with a global name
modules.pop();
}
modules.forEach( module => {
const replacement = getSafeName( name );
module.rename( name, replacement );
const bundleName = this.trace( module, localName, es6 );
if ( bundleName !== localName ) {
allReplacements[ module.id ][ localName ] = bundleName;
}
});

@@ -169,9 +164,11 @@ });

function getSafeName ( name ) {
while ( conflicts[ name ] ) {
while ( usedNames[ name ] ) {
name = `_${name}`;
}
conflicts[ name ] = true;
usedNames[ name ] = true;
return name;
}
return allReplacements;
}

@@ -279,4 +276,7 @@

const format = options.format || 'es6';
this.deconflict( format === 'es6' );
const allReplacements = this.deconflict( format === 'es6' );
// Determine export mode - 'default', 'named', 'none'
const exportMode = getExportMode( this, options.exports );
// If we have named exports from the bundle, and those exports

@@ -298,4 +298,5 @@ // are assigned to *within* the bundle, we may need to rewrite e.g.

let allBundleExports = blank();
let varExports = blank();
if ( format !== 'es6' ) {
if ( format !== 'es6' && exportMode === 'named' ) {
keys( this.entryModule.exports ).forEach( key => {

@@ -307,6 +308,6 @@ const exportDeclaration = this.entryModule.exports[ key ];

if ( originalDeclaration && originalDeclaration.type === 'VariableDeclaration' ) {
const canonicalName = this.entryModule.getCanonicalName( exportDeclaration.localName, false );
const canonicalName = this.trace( this.entryModule, exportDeclaration.localName, false );
allBundleExports[ canonicalName ] = `exports.${key}`;
this.varExports[ key ] = true;
varExports[ key ] = true;
}

@@ -319,3 +320,3 @@ });

this.toExport = keys( this.entryModule.exports )
.filter( key => !this.varExports[ key ] );
.filter( key => !varExports[ key ] );

@@ -326,3 +327,3 @@

this.orderedModules.forEach( module => {
const source = module.render( allBundleExports, format );
const source = module.render( allBundleExports, allReplacements[ module.id ], format );
if ( source.toString().length ) {

@@ -338,6 +339,16 @@ magicString.addSource( source );

return `var ${module.getCanonicalName('*', format === 'es6')} = {\n` +
return `var ${module.replacements['*']} = {\n` +
exportKeys.map( key => {
const localName = module.exports[ key ].localName;
return `${indentString}get ${key} () { return ${module.getCanonicalName(localName, format === 'es6')}; }`;
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' ) +

@@ -357,3 +368,3 @@ `\n};\n\n`;

// Determine export mode - 'default', 'named', 'none'
exportMode: getExportMode( this, options.exports ),
exportMode,

@@ -467,2 +478,53 @@ // Determine indentation

}
trace ( module, localName, es6 ) {
const importDeclaration = module.imports[ localName ];
// defined in this module
if ( !importDeclaration ) {
if ( localName === 'default' ) return module.defaultName();
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 es6 ?
importDeclaration.name :
`${otherModule.name}.${importDeclaration.name}`;
}
if ( importDeclaration.name === '*' ) {
return otherModule.replacements[ '*' ];
}
if ( importDeclaration.name === 'default' ) {
return otherModule.defaultName();
}
const exportDeclaration = otherModule.exports[ importDeclaration.name ];
if ( exportDeclaration ) return this.trace( otherModule, exportDeclaration.localName );
for ( let i = 0; i < otherModule.exportDelegates.length; i += 1 ) {
const delegate = otherModule.exportDelegates[i];
const delegateExportDeclaration = delegate.module.exports[ importDeclaration.name ];
if ( delegateExportDeclaration ) {
return this.trace( delegate.module, delegateExportDeclaration.localName );
}
}
throw new Error( 'Could not trace binding' );
}
}

@@ -11,3 +11,2 @@ import { blank } from './utils/object';

this.canonicalNames = blank();
this.suggestedNames = blank();

@@ -30,16 +29,4 @@

getCanonicalName ( name, es6 ) {
if ( name === 'default' ) {
return this.needsNamed && !es6 ? `${this.name}__default` : this.name;
}
if ( name === '*' ) {
return this.name; // TODO is this correct in ES6?
}
return es6 ? ( this.canonicalNames[ name ] || name ) : `${this.name}.${name}`;
}
rename ( name, replacement ) {
this.canonicalNames[ name ] = replacement;
// noop
}

@@ -46,0 +33,0 @@

@@ -1,4 +0,14 @@

import { keys } from '../utils/object';
import { blank, keys } from '../utils/object';
export default function es6 ( bundle, magicString, { exportMode }, options ) {
function uniqueNames ( declarations ) {
let uniques = blank();
declarations
.filter( declaration => !/^(default|\*)$/.test( declaration.name ) )
.forEach( declaration => uniques[ declaration.name ] = true );
return keys( uniques );
}
export default function es6 ( bundle, magicString ) {
const importBlock = bundle.externalModules

@@ -19,6 +29,3 @@ .map( module => {

if ( module.needsNamed ) {
specifiers.push( '{ ' + module.importedByBundle
.filter( declaration => !/^(default|\*)$/.test( declaration.name ) )
.map( ({ name, localName }) =>
name === localName ? name : `${name} as ${localName}` )
specifiers.push( '{ ' + uniqueNames( module.importedByBundle )
.join( ', ' ) + ' }' );

@@ -41,3 +48,3 @@ }

const canonicalName = bundle.entryModule.getCanonicalName( specifier.localName );
const canonicalName = bundle.entryModule.replacements[ specifier.localName ] || specifier.localName;

@@ -44,0 +51,0 @@ if ( exportedName === 'default' ) {

export default function getExportBlock ( bundle, exportMode, mechanism = 'return' ) {
if ( exportMode === 'default' ) {
return `${mechanism} ${bundle.entryModule.getCanonicalName('default')};`;
const defaultExport = bundle.entryModule.exports.default;
const defaultExportName = bundle.entryModule.replacements.default ||
defaultExport.identifier;
return `${mechanism} ${defaultExportName};`;
}

@@ -9,5 +14,6 @@

const prop = name === 'default' ? `['default']` : `.${name}`;
return `exports${prop} = ${bundle.entryModule.getCanonicalName(name)};`;
name = bundle.trace( bundle.entryModule, name );
return `exports${prop} = ${name};`;
})
.join( '\n' );
}

@@ -12,3 +12,3 @@ import { dirname } from './utils/path';

const emptyArrayPromise = Promise.resolve([]);
const emptyPromise = Promise.resolve();

@@ -23,7 +23,7 @@ function deconflict ( name, names ) {

function isEmptyExportedVarDeclaration ( node, module, allBundleExports, es6 ) {
function isEmptyExportedVarDeclaration ( node, module, allBundleExports, moduleReplacements, es6 ) {
if ( node.type !== 'VariableDeclaration' || node.declarations[0].init ) return false;
const name = node.declarations[0].id.name;
const canonicalName = module.getCanonicalName( name, es6 );
const canonicalName = moduleReplacements[ name ] || name;

@@ -56,3 +56,3 @@ return canonicalName in allBundleExports;

this.statements = this._parse( ast );
this.statements = this.parse( ast );

@@ -68,3 +68,3 @@ // imports and exports, indexed by ID

this.canonicalNames = blank();
this.replacements = blank();

@@ -89,4 +89,7 @@ this.definitions = blank();

const declaredName = isDeclaration && node.declaration.id.name;
const identifier = node.declaration.type === 'Identifier' && node.declaration.name;
const identifier = isDeclaration ?
node.declaration.id.name :
node.declaration.type === 'Identifier' ?
node.declaration.name :
null;

@@ -96,4 +99,3 @@ this.exports.default = {

name: 'default',
localName: declaredName || 'default',
declaredName,
localName: identifier || 'default',
identifier,

@@ -116,7 +118,2 @@ isDeclaration,

this.exports[ exportedName ] = {
localName,
exportedName
};
// export { foo } from './foo';

@@ -126,6 +123,13 @@ if ( source ) {

source,
localName,
localName: exportedName,
name: localName
};
}
this.exports[ exportedName ] = {
statement,
localName,
exportedName,
linkedImport: source ? this.imports[ localName ] : null
};
});

@@ -264,2 +268,14 @@ }

defaultName () {
const defaultExport = this.exports.default;
if ( !defaultExport ) return null;
const name = defaultExport.identifier && !defaultExport.isModified ?
defaultExport.identifier :
this.replacements.default;
return this.replacements[ name ] || name;
}
findDefiningStatement ( name ) {

@@ -288,2 +304,4 @@ if ( this.definitions[ name ] ) return this.definitions[ name ];

if ( module.isExternal ) return null;
if ( importDeclaration.name === '*' ) return null;
if ( importDeclaration.name === 'default' ) return null;

@@ -306,58 +324,6 @@ const exportDeclaration = module.exports[ importDeclaration.name ];

getCanonicalName ( localName, es6 ) {
// Special case
if ( localName === 'default' && ( this.exports.default.isModified || !this.suggestedNames.default ) ) {
let canonicalName = makeLegalIdentifier( this.id.replace( dirname( this.bundle.entryModule.id ) + '/', '' ).replace( /\.js$/, '' ) );
return deconflict( canonicalName, this.definitions );
}
if ( this.suggestedNames[ localName ] ) {
localName = this.suggestedNames[ localName ];
}
const id = localName + ( es6 ? '-es6' : '' ); // TODO ugh this seems like a terrible hack
if ( !this.canonicalNames[ id ] ) {
let canonicalName;
if ( this.imports[ localName ] ) {
const importDeclaration = this.imports[ localName ];
const module = importDeclaration.module;
if ( importDeclaration.name === '*' ) {
canonicalName = module.suggestedNames[ '*' ];
} else {
let exporterLocalName;
if ( module.isExternal ) {
exporterLocalName = importDeclaration.name;
} else {
const exportDeclaration = module.exports[ importDeclaration.name ];
// The export declaration of the particular name is known.
if (exportDeclaration) {
exporterLocalName = exportDeclaration.localName;
} else { // export * from '...'
exporterLocalName = importDeclaration.name;
}
}
canonicalName = module.getCanonicalName( exporterLocalName, es6 );
}
}
else {
canonicalName = localName;
}
this.canonicalNames[ id ] = canonicalName;
}
return this.canonicalNames[ id ];
}
mark ( name ) {
// shortcut cycles. TODO this won't work everywhere...
// shortcut cycles
if ( this.definitionPromises[ name ] ) {
return emptyArrayPromise;
return emptyPromise;
}

@@ -370,2 +336,3 @@

const importDeclaration = this.imports[ name ];
importDeclaration.isUsed = true;

@@ -395,13 +362,13 @@ promise = this.bundle.fetchModule( importDeclaration.source, this.id )

if ( importDeclaration.name === 'default' && ( module.isExternal || !module.exports.default.linkedImport ) ) { // special case - exclude `export { default } from ...`
module.needsDefault = true;
} else if ( importDeclaration.name === '*' ) {
module.needsAll = true;
} else {
module.needsNamed = true;
}
if ( module.isExternal ) {
if ( importDeclaration.name === 'default' ) {
module.needsDefault = true;
} else if ( importDeclaration.name === '*' ) {
module.needsAll = true;
} else {
module.needsNamed = true;
}
module.importedByBundle.push( importDeclaration );
return emptyArrayPromise;
return emptyPromise;
}

@@ -415,3 +382,3 @@

return module.markAllStatements();
return module.markAllExportStatements();
}

@@ -446,2 +413,7 @@

exportDeclaration.isUsed = true;
if ( importDeclaration.name === 'default' ) {
return exportDeclaration.statement.mark();
}
return module.mark( exportDeclaration.localName );

@@ -451,45 +423,8 @@ });

// The definition is in this module
else if ( name === 'default' && this.exports.default.isDeclaration ) {
// We have something like `export default foo` - so we just start again,
// searching for `foo` instead of default
promise = this.mark( this.exports.default.name );
}
else {
let statement;
statement = name === 'default' ? this.exports.default.statement : this.definitions[ name ];
promise = statement && !statement.isIncluded ? statement.mark() : emptyArrayPromise;
// Special case - `export default foo; foo += 1` - need to be
// vigilant about maintaining the correct order of the export
// declaration. Otherwise, the export declaration will always
// go at the end of the expansion, because the expansion of
// `foo` will include statements *after* the declaration
if ( name === 'default' && this.exports.default.identifier && this.exports.default.isModified ) {
const defaultExportStatement = this.exports.default.statement;
promise = promise.then( statements => {
// remove the default export statement...
// TODO could this be statements.pop()?
statements.splice( statements.indexOf( defaultExportStatement ), 1 );
let i = statements.length;
let inserted = false;
while ( i-- ) {
if ( statements[i].module === this && statements[i].index < defaultExportStatement.index ) {
statements.splice( i + 1, 0, defaultExportStatement );
inserted = true;
break;
}
}
if ( !inserted ) statements.push( statement );
return statements;
});
}
const statement = name === 'default' ? this.exports.default.statement : this.definitions[ name ];
promise = statement && statement.mark();
}
this.definitionPromises[ name ] = promise || emptyArrayPromise;
this.definitionPromises[ name ] = promise || emptyPromise;
return this.definitionPromises[ name ];

@@ -535,4 +470,11 @@ }

// TODO rename this to parse, once https://github.com/rollup/rollup/issues/42 is fixed
_parse ( ast ) {
markAllExportStatements () {
return sequence( this.statements, statement => {
return statement.isExportDeclaration ?
statement.mark() :
null;
});
}
parse ( ast ) {
// The ast can be supplied programmatically (but usually won't be)

@@ -574,3 +516,3 @@ if ( !ast ) {

node.declarations.forEach( ( declarator, i ) => {
node.declarations.forEach( declarator => {
const { start, end } = declarator;

@@ -622,13 +564,9 @@

rename ( name, replacement ) {
// TODO again, hacky...
this.canonicalNames[ name ] = this.canonicalNames[ name + '-es6' ] = replacement;
this.replacements[ name ] = replacement;
}
render ( allBundleExports, format ) {
render ( allBundleExports, moduleReplacements, format ) {
let magicString = this.magicString.clone();
let previousIndex = -1;
let previousMargin = 0;
this.statements.forEach( ( statement, i ) => {
this.statements.forEach( statement => {
if ( !statement.isIncluded ) {

@@ -645,6 +583,6 @@ magicString.remove( statement.start, statement.next );

return;
};
}
// skip `export var foo;` if foo is exported
if ( isEmptyExportedVarDeclaration( statement.node.declaration, statement.module, allBundleExports, format === 'es6' ) ) {
if ( isEmptyExportedVarDeclaration( statement.node.declaration, this, allBundleExports, moduleReplacements, format === 'es6' ) ) {
magicString.remove( statement.start, statement.next );

@@ -657,3 +595,3 @@ return;

// (otherwise we're left with `exports.foo;`, which is useless)
if ( isEmptyExportedVarDeclaration( statement.node, statement.module, allBundleExports, format === 'es6' ) ) {
if ( isEmptyExportedVarDeclaration( statement.node, this, allBundleExports, moduleReplacements, format === 'es6' ) ) {
magicString.remove( statement.start, statement.next );

@@ -679,8 +617,8 @@ return;

.forEach( name => {
const canonicalName = statement.module.getCanonicalName( name, format === 'es6' );
const bundleName = moduleReplacements[ name ] || name;
if ( allBundleExports[ canonicalName ] ) {
bundleExports[ name ] = replacements[ name ] = allBundleExports[ canonicalName ];
} else if ( name !== canonicalName ) {
replacements[ name ] = canonicalName;
if ( allBundleExports[ bundleName ] ) {
bundleExports[ name ] = replacements[ name ] = allBundleExports[ bundleName ];
} else if ( bundleName !== name ) { // TODO weird structure
replacements[ name ] = bundleName;
}

@@ -705,6 +643,5 @@ });

else if ( statement.node.type === 'ExportDefaultDeclaration' ) {
const module = statement.module;
const canonicalName = module.getCanonicalName( 'default', format === 'es6' );
const canonicalName = this.defaultName();
if ( statement.node.declaration.type === 'Identifier' && canonicalName === module.getCanonicalName( statement.node.declaration.name, format === 'es6' ) ) {
if ( statement.node.declaration.type === 'Identifier' && canonicalName === ( moduleReplacements[ statement.node.declaration.name ] || statement.node.declaration.name ) ) {
magicString.remove( statement.start, statement.next );

@@ -714,2 +651,8 @@ return;

// prevent `var undefined = sideEffectyDefault(foo)`
if ( canonicalName === undefined ) {
magicString.remove( statement.start, statement.node.declaration.start );
return;
}
// anonymous functions should be converted into declarations

@@ -716,0 +659,0 @@ if ( statement.node.declaration.type === 'FunctionExpression' ) {

@@ -161,2 +161,5 @@ import { blank, keys } from './utils/object';

// disregard the `bar` in `export { foo as bar }`
if ( parent.type === 'ExportSpecifier' && node !== parent.local ) return;
const definingScope = scope.findDefiningScope( node.name );

@@ -371,2 +374,6 @@

}
toString () {
return this.module.magicString.slice( this.start, this.end );
}
}

@@ -1,3 +0,3 @@

export function unixizePath( path ) {
return path.split( /[\/\\]/ ).join( '/' );
export function unixizePath ( path ) {
return path.split( /[\/\\]/ ).join( '/' );
}

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc