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.9.1 to 0.10.0

6

CHANGELOG.md
# rollup changelog
## 0.10.0
* Better sorting algorithm – sorting happens at the module level, rather than the statement level. This avoids certain edge cases
* IIFEs are ignored for the purposes of distinguishing between 'strong' and 'weak' dependencies
* Empty `var` declarations for exported bindings are omitted
## 0.9.1

@@ -4,0 +10,0 @@

272

dist/rollup.js

@@ -263,2 +263,11 @@ 'use strict';

function isEmptyExportedVarDeclaration(node, module, allBundleExports) {
if (node.type !== 'VariableDeclaration' || node.declarations[0].init) return false;
var name = node.declarations[0].id.name;
var canonicalName = module.getCanonicalName(name);
return canonicalName in allBundleExports;
}
var blacklisted = blank();

@@ -476,2 +485,6 @@

function isIife(node, parent) {
return parent && parent.type === 'CallExpression' && node === parent.callee;
}
var blockDeclarations = {

@@ -589,3 +602,3 @@ 'const': true,

walk(this.node, {
enter: function (node) {
enter: function (node, parent) {
var newScope = undefined;

@@ -618,6 +631,8 @@

case 'BlockStatement':
newScope = new Scope({
parent: scope,
block: true
});
if (!/Function/.test(parent.type)) {
newScope = new Scope({
parent: scope,
block: true
});
}

@@ -658,12 +673,31 @@ break;

// This allows us to track whether we're looking at code that will
// be executed immediately (either outside a function, or immediately
// inside an IIFE), for the purposes of determining whether dependencies
// are strong or weak. It's not bulletproof, since it wouldn't catch...
//
// var calledImmediately = function () {
// doSomethingWith( strongDependency );
// }
// calledImmediately();
//
// ...but it's better than nothing
var depth = 0;
if (!this.isImportDeclaration) {
walk(this.node, {
enter: function (node, parent) {
if (node._scope) scope = node._scope;
if (node._scope) {
if (!scope.isBlockScope && !isIife(node, parent)) depth += 1;
scope = node._scope;
}
_this.checkForReads(scope, node, parent);
_this.checkForReads(scope, node, parent, !depth);
_this.checkForWrites(scope, node);
},
leave: function (node) {
if (node._scope) scope = scope.parent;
leave: function (node, parent) {
if (node._scope) {
if (!scope.isBlockScope && !isIife(node, parent)) depth -= 1;
scope = scope.parent;
}
}

@@ -678,3 +712,3 @@ });

Statement.prototype.checkForReads = function checkForReads(scope, node, parent) {
Statement.prototype.checkForReads = function checkForReads(scope, node, parent, strong) {
if (node.type === 'Identifier') {

@@ -698,4 +732,3 @@ // disregard the `bar` in `foo.bar` - these appear as Identifier nodes

this.dependsOn[node.name] = true;
if (!scope.parent) this.stronglyDependsOn[node.name] = true;
if (strong) this.stronglyDependsOn[node.name] = true;
}

@@ -1167,2 +1200,41 @@ }

Module.prototype.consolidateDependencies = function consolidateDependencies() {
var _this3 = this;
var strongDependencies = blank();
this.statements.forEach(function (statement) {
if (statement.isImportDeclaration && !statement.node.specifiers.length) {
// 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(function (name) {
if (statement.defines[name]) return;
var importDeclaration = _this3.imports[name];
if (importDeclaration && importDeclaration.module && !importDeclaration.module.isExternal) {
strongDependencies[importDeclaration.module.id] = importDeclaration.module;
}
});
});
var weakDependencies = blank();
this.statements.forEach(function (statement) {
keys(statement.dependsOn).forEach(function (name) {
if (statement.defines[name]) return;
var importDeclaration = _this3.imports[name];
if (importDeclaration && importDeclaration.module && !importDeclaration.module.isExternal) {
weakDependencies[importDeclaration.module.id] = importDeclaration.module;
}
});
});
return { strongDependencies: strongDependencies, weakDependencies: weakDependencies };
};
Module.prototype.findDeclaration = function findDeclaration(localName) {

@@ -1236,3 +1308,3 @@ var importDeclaration = this.imports[localName];

Module.prototype.define = function define(name) {
var _this3 = this;
var _this4 = this;

@@ -1249,5 +1321,5 @@ // shortcut cycles. TODO this won't work everywhere...

(function () {
var importDeclaration = _this3.imports[name];
var importDeclaration = _this4.imports[name];
promise = _this3.bundle.fetchModule(importDeclaration.source, _this3.id).then(function (module) {
promise = _this4.bundle.fetchModule(importDeclaration.source, _this4.id).then(function (module) {
importDeclaration.module = module;

@@ -1259,3 +1331,3 @@

var localName = importDeclaration.localName;
var suggestion = _this3.suggestedNames[localName] || localName;
var suggestion = _this4.suggestedNames[localName] || localName;

@@ -1270,3 +1342,3 @@ // special case - the module has its own import by this name

var localName = importDeclaration.localName;
var suggestion = _this3.suggestedNames[localName] || localName;
var suggestion = _this4.suggestedNames[localName] || localName;
module.suggestName('*', suggestion);

@@ -1289,4 +1361,4 @@ module.suggestName('default', '' + suggestion + '__default');

// we need to create an internal namespace
if (! ~_this3.bundle.internalNamespaceModules.indexOf(module)) {
_this3.bundle.internalNamespaceModules.push(module);
if (! ~_this4.bundle.internalNamespaceModules.indexOf(module)) {
_this4.bundle.internalNamespaceModules.push(module);
}

@@ -1300,3 +1372,3 @@

if (!exportDeclaration) {
throw new Error('Module ' + module.id + ' does not export ' + importDeclaration.name + ' (imported by ' + _this3.id + ')');
throw new Error('Module ' + module.id + ' does not export ' + importDeclaration.name + ' (imported by ' + _this4.id + ')');
}

@@ -1318,3 +1390,3 @@

statement = name === 'default' ? _this3.exports.default.statement : _this3.definitions[name];
statement = name === 'default' ? _this4.exports.default.statement : _this4.definitions[name];
promise = statement && !statement.isIncluded ? statement.expand() : emptyArrayPromise;

@@ -1327,5 +1399,5 @@

// `foo` will include statements *after* the declaration
if (name === 'default' && _this3.exports.default.identifier && _this3.exports.default.isModified) {
if (name === 'default' && _this4.exports.default.identifier && _this4.exports.default.isModified) {
(function () {
var defaultExportStatement = _this3.exports.default.statement;
var defaultExportStatement = _this4.exports.default.statement;
promise = promise.then(function (statements) {

@@ -1340,3 +1412,3 @@ // remove the default export statement...

while (i--) {
if (statements[i].module === _this3 && statements[i].index < defaultExportStatement.index) {
if (statements[i].module === _this4 && statements[i].index < defaultExportStatement.index) {
statements.splice(i + 1, 0, defaultExportStatement);

@@ -1361,3 +1433,3 @@ inserted = true;

Module.prototype.expandAllStatements = function expandAllStatements(isEntryModule) {
var _this4 = this;
var _this5 = this;

@@ -1385,3 +1457,3 @@ var allStatements = [];

if (!statement.node.specifiers.length) {
return _this4.bundle.fetchModule(statement.node.source.value, _this4.id).then(function (module) {
return _this5.bundle.fetchModule(statement.node.source.value, _this5.id).then(function (module) {
statement.module = module;

@@ -1581,2 +1653,4 @@ return module.expandAllStatements();

this.modulePromises = blank();
this.modules = [];
this.statements = [];

@@ -1611,2 +1685,4 @@ this.externalModules = [];

_this.modules.push(module);
return module;

@@ -1663,3 +1739,4 @@ });

_this2.deconflict();
_this2.sort();
_this2.orderedStatements = _this2.sort();
});

@@ -1756,93 +1833,94 @@ };

Bundle.prototype.sort = function sort() {
// TODO avoid this work whenever possible...
var seen = {};
var ordered = [];
var hasCycles = undefined;
var definitions = blank();
var strongDeps = {};
var stronglyDependsOn = {};
// gather definitions
this.statements.forEach(function (statement) {
keys(statement.defines).forEach(function (name) {
var canonicalName = statement.module.getCanonicalName(name);
definitions[canonicalName] = statement;
});
});
function visit(module) {
seen[module.id] = true;
var strongDeps = blank();
var stronglyDependsOn = blank();
var _module$consolidateDependencies = module.consolidateDependencies();
this.statements.forEach(function (statement) {
var id = statement.id;
strongDeps[id] = [];
stronglyDependsOn[id] = {};
var strongDependencies = _module$consolidateDependencies.strongDependencies;
var weakDependencies = _module$consolidateDependencies.weakDependencies;
keys(statement.stronglyDependsOn).forEach(function (name) {
if (statement.defines[name]) return; // TODO seriously... need to fix this
var canonicalName = statement.module.getCanonicalName(name);
var definition = definitions[canonicalName];
strongDeps[module.id] = [];
stronglyDependsOn[module.id] = {};
if (definition) strongDeps[statement.id].push(definition);
keys(strongDependencies).forEach(function (id) {
var imported = strongDependencies[id];
strongDeps[module.id].push(imported);
if (seen[id]) {
// we need to prevent an infinite loop, and note that
// we need to check for strong/weak dependency relationships
hasCycles = true;
return;
}
visit(imported);
});
});
// add second (and third...) order strong dependencies
this.statements.forEach(function (statement) {
var id = statement.id;
keys(weakDependencies).forEach(function (id) {
var imported = weakDependencies[id];
if (seen[id]) {
// we need to prevent an infinite loop, and note that
// we need to check for strong/weak dependency relationships
hasCycles = true;
return;
}
visit(imported);
});
// add second (and third...) order dependencies
function addStrongDependencies(dependency) {
if (stronglyDependsOn[id][dependency.id]) return;
if (stronglyDependsOn[module.id][dependency.id]) return;
stronglyDependsOn[id][dependency.id] = true;
stronglyDependsOn[module.id][dependency.id] = true;
strongDeps[dependency.id].forEach(addStrongDependencies);
}
strongDeps[id].forEach(addStrongDependencies);
});
strongDeps[module.id].forEach(addStrongDependencies);
// reinsert each statement, ensuring its strong dependencies appear first
var sorted = [];
var included = blank();
var highestIndex = blank();
ordered.push(module);
}
function include(statement) {
if (included[statement.id]) return;
included[statement.id] = true;
visit(this.entryModule);
var alreadyIncluded = false;
if (hasCycles) {
var unordered = ordered;
ordered = [];
var unordered = statement.index < highestIndex[statement.module.id];
highestIndex[statement.module.id] = Math.max(statement.index, highestIndex[statement.module.id] || 0);
// unordered is actually semi-ordered, as [ fewer dependencies ... more dependencies ]
unordered.forEach(function (module) {
// ensure strong dependencies of `module` that don't strongly depend on `module` go first
strongDeps[module.id].forEach(place);
if (unordered) {
var len = sorted.length;
var i = 0;
for (i = 0; i < len; i += 1) {
// ensure that this statement appears above later statements
// from the same module - in rare situations (#34) they can
// become jumbled
var existing = sorted[i];
if (existing.module === statement.module && existing.index > statement.index) {
sorted.splice(i, 0, statement);
return;
function place(dep) {
if (!stronglyDependsOn[dep.id][module.id] && ! ~ordered.indexOf(dep)) {
strongDeps[dep.id].forEach(place);
ordered.push(dep);
}
}
}
sorted.push(statement);
if (! ~ordered.indexOf(module)) {
ordered.push(module);
}
});
}
this.statements.forEach(function (statement) {
strongDeps[statement.id].forEach(includeStrongDependency);
var statements = [];
function includeStrongDependency(dependency) {
if (!stronglyDependsOn[dependency.id][statement.id] && !included[dependency.id]) {
strongDeps[dependency.id].forEach(includeStrongDependency);
include(dependency);
}
}
include(statement);
ordered.forEach(function (module) {
module.statements.forEach(function (statement) {
if (statement.isIncluded) statements.push(statement);
});
});
this.statements = sorted;
return statements;
};

@@ -1902,8 +1980,16 @@

this.statements.forEach(function (statement) {
this.orderedStatements.forEach(function (statement) {
// skip `export { foo, bar, baz }`
if (statement.node.type === 'ExportNamedDeclaration' && statement.node.specifiers.length) {
return;
if (statement.node.type === 'ExportNamedDeclaration') {
// skip `export { foo, bar, baz }`
if (statement.node.specifiers.length) return;
// skip `export var foo;` if foo is exported
if (isEmptyExportedVarDeclaration(statement.node.declaration, statement.module, allBundleExports)) return;
}
// skip empty var declarations for exported bindings
// (otherwise we're left with `exports.foo;`, which is useless)
if (isEmptyExportedVarDeclaration(statement.node, statement.module, allBundleExports)) return;
var replacements = blank();

@@ -1910,0 +1996,0 @@ var bundleExports = blank();

{
"name": "rollup",
"version": "0.9.1",
"version": "0.10.0",
"description": "Next-generation ES6 module bundler",

@@ -5,0 +5,0 @@ "main": "dist/rollup.js",

@@ -16,2 +16,11 @@ import { basename, dirname, extname, relative } from 'path';

function isEmptyExportedVarDeclaration ( node, module, allBundleExports ) {
if ( node.type !== 'VariableDeclaration' || node.declarations[0].init ) return false;
const name = node.declarations[0].id.name;
const canonicalName = module.getCanonicalName( name );
return canonicalName in allBundleExports;
}
export default class Bundle {

@@ -38,2 +47,4 @@ constructor ( options ) {

this.modulePromises = blank();
this.modules = [];
this.statements = [];

@@ -68,2 +79,4 @@ this.externalModules = [];

this.modules.push( module );
return module;

@@ -116,3 +129,4 @@ });

this.deconflict();
this.sort();
this.orderedStatements = this.sort();
});

@@ -207,96 +221,91 @@ }

sort () {
// TODO avoid this work whenever possible...
let seen = {};
let ordered = [];
let hasCycles;
let definitions = blank();
let strongDeps = {};
let stronglyDependsOn = {};
// gather definitions
this.statements.forEach( statement => {
keys( statement.defines ).forEach( name => {
const canonicalName = statement.module.getCanonicalName( name );
definitions[ canonicalName ] = statement;
});
});
function visit ( module ) {
seen[ module.id ] = true;
let strongDeps = blank();
let stronglyDependsOn = blank();
const { strongDependencies, weakDependencies } = module.consolidateDependencies();
this.statements.forEach( statement => {
const id = statement.id;
strongDeps[ id ] = [];
stronglyDependsOn[ id ] = {};
strongDeps[ module.id ] = [];
stronglyDependsOn[ module.id ] = {};
keys( statement.stronglyDependsOn ).forEach( name => {
if ( statement.defines[ name ] ) return; // TODO seriously... need to fix this
const canonicalName = statement.module.getCanonicalName( name );
const definition = definitions[ canonicalName ];
keys( strongDependencies ).forEach( id => {
const imported = strongDependencies[ id ];
if ( definition ) strongDeps[ statement.id ].push( definition );
strongDeps[ module.id ].push( imported );
if ( seen[ id ] ) {
// we need to prevent an infinite loop, and note that
// we need to check for strong/weak dependency relationships
hasCycles = true;
return;
}
visit( imported );
});
});
// add second (and third...) order strong dependencies
this.statements.forEach( statement => {
const id = statement.id;
keys( weakDependencies ).forEach( id => {
const imported = weakDependencies[ id ];
if ( seen[ id ] ) {
// we need to prevent an infinite loop, and note that
// we need to check for strong/weak dependency relationships
hasCycles = true;
return;
}
visit( imported );
});
// add second (and third...) order dependencies
function addStrongDependencies ( dependency ) {
if ( stronglyDependsOn[ id ][ dependency.id ] ) return;
if ( stronglyDependsOn[ module.id ][ dependency.id ] ) return;
stronglyDependsOn[ id ][ dependency.id ] = true;
stronglyDependsOn[ module.id ][ dependency.id ] = true;
strongDeps[ dependency.id ].forEach( addStrongDependencies );
}
strongDeps[ id ].forEach( addStrongDependencies );
});
strongDeps[ module.id ].forEach( addStrongDependencies );
// reinsert each statement, ensuring its strong dependencies appear first
let sorted = [];
let included = blank();
let highestIndex = blank();
ordered.push( module );
}
function include ( statement ) {
if ( included[ statement.id ] ) return;
included[ statement.id ] = true;
visit( this.entryModule );
let alreadyIncluded = false;
if ( hasCycles ) {
let unordered = ordered;
ordered = [];
const unordered = statement.index < highestIndex[ statement.module.id ];
highestIndex[ statement.module.id ] = Math.max(
statement.index,
highestIndex[ statement.module.id ] || 0
);
// unordered is actually semi-ordered, as [ fewer dependencies ... more dependencies ]
unordered.forEach( module => {
// ensure strong dependencies of `module` that don't strongly depend on `module` go first
strongDeps[ module.id ].forEach( place );
if ( unordered ) {
const len = sorted.length;
let i = 0;
for ( i = 0; i < len; i += 1 ) {
// ensure that this statement appears above later statements
// from the same module - in rare situations (#34) they can
// become jumbled
const existing = sorted[i];
if ( existing.module === statement.module && existing.index > statement.index ) {
sorted.splice( i, 0, statement );
return
function place ( dep ) {
if ( !stronglyDependsOn[ dep.id ][ module.id ] && !~ordered.indexOf( dep ) ) {
strongDeps[ dep.id ].forEach( place );
ordered.push( dep );
}
}
}
sorted.push( statement );
if ( !~ordered.indexOf( module ) ) {
ordered.push( module );
}
});
}
this.statements.forEach( statement => {
strongDeps[ statement.id ].forEach( includeStrongDependency );
let statements = [];
function includeStrongDependency ( dependency ) {
if ( !stronglyDependsOn[ dependency.id ][ statement.id ] && !included[ dependency.id ] ) {
strongDeps[ dependency.id ].forEach( includeStrongDependency );
include( dependency );
}
}
include( statement );
ordered.forEach( module => {
module.statements.forEach( statement => {
if ( statement.isIncluded ) statements.push( statement );
});
});
this.statements = sorted;
return statements;
}

@@ -351,8 +360,16 @@

this.statements.forEach( statement => {
this.orderedStatements.forEach( statement => {
// skip `export { foo, bar, baz }`
if ( statement.node.type === 'ExportNamedDeclaration' && statement.node.specifiers.length ) {
return;
if ( statement.node.type === 'ExportNamedDeclaration' ) {
// skip `export { foo, bar, baz }`
if ( statement.node.specifiers.length ) return;
// skip `export var foo;` if foo is exported
if ( isEmptyExportedVarDeclaration( statement.node.declaration, statement.module, allBundleExports ) ) return;
}
// skip empty var declarations for exported bindings
// (otherwise we're left with `exports.foo;`, which is useless)
if ( isEmptyExportedVarDeclaration( statement.node, statement.module, allBundleExports ) ) return;
let replacements = blank();

@@ -359,0 +376,0 @@ let bundleExports = blank();

@@ -237,2 +237,39 @@ import { dirname } from 'path';

consolidateDependencies () {
let strongDependencies = blank();
this.statements.forEach( statement => {
if ( statement.isImportDeclaration && !statement.node.specifiers.length ) {
// 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 importDeclaration = this.imports[ name ];
if ( importDeclaration && importDeclaration.module && !importDeclaration.module.isExternal ) {
strongDependencies[ importDeclaration.module.id ] = importDeclaration.module;
}
});
});
let weakDependencies = blank();
this.statements.forEach( statement => {
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;
}
});
});
return { strongDependencies, weakDependencies };
}
findDeclaration ( localName ) {

@@ -239,0 +276,0 @@ const importDeclaration = this.imports[ localName ];

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

function isIife ( node, parent ) {
return parent && parent.type === 'CallExpression' && node === parent.callee;
}
export default class Statement {

@@ -42,3 +46,3 @@ constructor ( node, magicString, module, index ) {

walk( this.node, {
enter ( node ) {
enter ( node, parent ) {
let newScope;

@@ -71,6 +75,8 @@

case 'BlockStatement':
newScope = new Scope({
parent: scope,
block: true
});
if ( !/Function/.test( parent.type ) ) {
newScope = new Scope({
parent: scope,
block: true
});
}

@@ -111,12 +117,31 @@ break;

// This allows us to track whether we're looking at code that will
// be executed immediately (either outside a function, or immediately
// inside an IIFE), for the purposes of determining whether dependencies
// are strong or weak. It's not bulletproof, since it wouldn't catch...
//
// var calledImmediately = function () {
// doSomethingWith( strongDependency );
// }
// calledImmediately();
//
// ...but it's better than nothing
let depth = 0;
if ( !this.isImportDeclaration ) {
walk( this.node, {
enter: ( node, parent ) => {
if ( node._scope ) scope = node._scope;
if ( node._scope ) {
if ( !scope.isBlockScope && !isIife( node, parent ) ) depth += 1;
scope = node._scope;
}
this.checkForReads( scope, node, parent );
this.checkForReads( scope, node, parent, !depth );
this.checkForWrites( scope, node );
},
leave: ( node ) => {
if ( node._scope ) scope = scope.parent;
leave: ( node, parent ) => {
if ( node._scope ) {
if ( !scope.isBlockScope && !isIife( node, parent ) ) depth -= 1;
scope = scope.parent;
}
}

@@ -131,3 +156,3 @@ });

checkForReads ( scope, node, parent ) {
checkForReads ( scope, node, parent, strong ) {
if ( node.type === 'Identifier' ) {

@@ -151,4 +176,3 @@ // disregard the `bar` in `foo.bar` - these appear as Identifier nodes

this.dependsOn[ node.name ] = true;
if ( !scope.parent ) this.stronglyDependsOn[ node.name ] = true;
if ( strong ) this.stronglyDependsOn[ node.name ] = true;
}

@@ -155,0 +179,0 @@ }

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