Socket
Socket
Sign inDemoInstall

rollup

Package Overview
Dependencies
21
Maintainers
1
Versions
800
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.3.1 to 0.4.0

src/Statement.js

9

CHANGELOG.md
# rollup changelog
## 0.4.0
* Self-hosting! `rollup.rollup` now rolls up rollup
* Fix bug with comments inside a statement later being appended to it
* Prevent shadowing of external modules
* Rewrite computed property identifiers where necessary
* Preserve original statement order where possible
* Internal refactoring
## 0.3.1

@@ -4,0 +13,0 @@

1370

dist/rollup.js
'use strict';
var _path = require('path');
var sander = require('sander');
var path = require('path');
var MagicString = require('magic-string');
MagicString = ('default' in MagicString ? MagicString['default'] : MagicString);
MagicString = 'default' in MagicString ? MagicString['default'] : MagicString;
var acorn = require('acorn');
var keys = Object.keys;
function badExports(option, keys) {
throw new Error('\'' + option + '\' was specified for options.exports, but entry module has following exports: ' + keys.join(', '));
}
var hasOwnProp = Object.prototype.hasOwnProperty;function has(obj, prop) {
var _keys = Object.keys;
var _hasOwnProp = Object.prototype.hasOwnProperty;
function _has(obj, prop) {
return _hasOwnProp.call(obj, prop);
}
function _getName(x) {
return x.name;
}
function req(x) {
return "require('" + x.id + "')";
}
function _quoteId(x) {
return "'" + x.id + "'";
}
function umd(bundle, magicString, exportMode, options) {
var indentStr = magicString.getIndentString();
var globalNames = options.globals || {};
var amdDeps = bundle.externalModules.map(_quoteId);
var cjsDeps = bundle.externalModules.map(req);
var globalDeps = bundle.externalModules.map(function (module) {
return _has(globalNames, module.id) ? globalNames[module.id] : module.name;
});
var args = bundle.externalModules.map(_getName);
if (exportMode === 'named') {
amdDeps.unshift('\'exports\'');
cjsDeps.unshift('\'exports\'');
globalDeps.unshift('(global.' + options.moduleName + ' = {})');
args.unshift('exports');
}
var amdParams = (_has(options, 'moduleId') ? '[\'' + options.moduleId + '\'], ' : '') + (amdDeps.length ? '[' + amdDeps.join(', ') + '], ' : '');
var intro = ('(function (global, factory) {\n\t\t\ttypeof exports === \'object\' && typeof module !== \'undefined\' ? factory(' + cjsDeps.join(', ') + ') :\n\t\t\ttypeof define === \'function\' && define.amd ? define(' + amdParams + 'factory) :\n\t\t\tfactory(' + globalDeps + ');\n\t\t}(this, function (' + args + ') { \'use strict\';\n\n\t\t').replace(/^\t\t/gm, '').replace(/^\t/gm, indentStr);
var exports = bundle.entryModule.exports;
var exportBlock = '\n\n' + Object.keys(exports).map(function (name) {
return 'exports.' + name + ' = ' + exports[name].localName + ';';
}).join('\n');
return magicString.append(exportBlock).trim().indent().append('\n\n}));').prepend(intro);
}
function iife(bundle, magicString, exportMode, options) {
var intro = "(function () { 'use strict';\n\n";
var outro = "\n\n})();";
return magicString.trim().indent().prepend(intro).append(outro);
}
function es6(bundle, magicString, exportMode, options) {
// TODO
var introBlock = '';
var exportBlock = '';
return magicString.trim();
}
var __keys = Object.keys;
function cjs(bundle, magicString, exportMode) {
var intro = '\'use strict\';\n\n';
// TODO handle empty imports, once they're supported
var importBlock = bundle.externalModules.map(function (module) {
var requireStatement = 'var ' + module.name + ' = require(\'' + module.id + '\');';
if (module.needsDefault) {
requireStatement += '\n' + (module.needsNamed ? 'var ' + module.name + '__default = ' : '' + module.name + ' = ') + ('\'default\' in ' + module.name + ' ? ' + module.name + '[\'default\'] : ' + module.name + ';');
}
return requireStatement;
}).join('\n');
if (importBlock) {
intro += importBlock + '\n\n';
}
magicString.prepend(intro);
var exportBlock = undefined;
if (exportMode === 'default' && bundle.entryModule.exports.default) {
exportBlock = 'module.exports = ' + bundle.entryModule.getCanonicalName('default') + ';';
} else if (exportMode === 'named') {
exportBlock = __keys(bundle.entryModule.exports).map(function (key) {
var specifier = bundle.entryModule.exports[key];
var name = bundle.entryModule.getCanonicalName(specifier.localName);
return 'exports.' + key + ' = ' + name + ';';
}).join('\n');
}
if (exportBlock) {
magicString.append('\n\n' + exportBlock);
}
return magicString;
}
var __hasOwnProp = Object.prototype.hasOwnProperty;
function __has(obj, prop) {
return __hasOwnProp.call(obj, prop);
}
function __getName(x) {
return x.name;
}
function quoteId(x) {
return "'" + x.id + "'";
}
function amd(bundle, magicString, exportMode, options) {
var deps = bundle.externalModules.map(quoteId);
var args = bundle.externalModules.map(__getName);
if (exportMode === 'named') {
args.unshift('exports');
deps.unshift('\'exports\'');
}
var params = (__has(options, 'moduleId') ? '[\'' + options.moduleId + '\'], ' : '') + (deps.length ? '[' + deps.join(', ') + '], ' : '');
var intro = 'define(' + params + 'function (' + args.join(', ') + ') { \'use strict\';\n\n';
var exports = bundle.entryModule.exports;
var exportBlock = undefined;
if (exportMode === 'default') {
exportBlock = 'return ' + bundle.entryModule.getCanonicalName('default') + ';';
} else {
exportBlock = '\n\n' + Object.keys(exports).map(function (name) {
return 'exports.' + name + ' = ' + exports[name].localName + ';';
}).join('\n');
}
return magicString.append(exportBlock).trim().indent().append('\n\n});').prepend(intro);
}
var finalisers = { amd: amd, cjs: cjs, es6: es6, iife: iife, umd: umd };
var ___hasOwnProp = Object.prototype.hasOwnProperty;
function ___has(obj, prop) {
return ___hasOwnProp.call(obj, prop);
}
var _blacklisted = {};
var _builtins = 'Infinity NaN undefined null true false eval uneval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Symbol Error EvalError InternalError RangeError ReferenceError SyntaxError TypeError URIError Number Math Date String RegExp Array Int8Array Uint8Array Uint8ClampedArray Int16Array Uint16Array Int32Array Uint32Array Float32Array Float64Array Map Set WeakMap WeakSet SIMD ArrayBuffer DataView JSON Promise Generator GeneratorFunction Reflect Proxy Intl'.split(' ');
var _reservedWords = 'break case class catch const continue debugger default delete do else export extends finally for function if import in instanceof let new return super switch this throw try typeof var void while with yield enum await implements package protected static interface private public'.split(' ');
_reservedWords.concat(_builtins).forEach(function (word) {
return _blacklisted[word] = true;
});
function _makeLegalIdentifier(str) {
str = str.replace(/[^$_a-zA-Z0-9]/g, '_');
if (/\d/.test(str[0]) || _blacklisted[str]) str = '_' + str;
return str;
}
var blacklisted = {};
var builtins = 'Infinity NaN undefined null true false eval uneval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Symbol Error EvalError InternalError RangeError ReferenceError SyntaxError TypeError URIError Number Math Date String RegExp Array Int8Array Uint8Array Uint8ClampedArray Int16Array Uint16Array Int32Array Uint32Array Float32Array Float64Array Map Set WeakMap WeakSet SIMD ArrayBuffer DataView JSON Promise Generator GeneratorFunction Reflect Proxy Intl'.split(' ');
var reservedWords = 'break case class catch const continue debugger default delete do else export extends finally for function if import in instanceof let new return super switch this throw try typeof var void while with yield enum await implements package protected static interface private public'.split(' ');
reservedWords.concat(builtins).forEach(function (word) {
return blacklisted[word] = true;
});
function makeLegalIdentifier(str) {
str = str.replace(/[^$_a-zA-Z0-9]/g, '_');
if (/\d/.test(str[0]) || blacklisted[str]) str = '_' + str;
return str;
}
function _sequence(arr, callback) {
var len = arr.length;
var results = new Array(len);
var promise = sander.Promise.resolve();
function next(i) {
return promise.then(function () {
return callback(arr[i], i);
}).then(function (result) {
return results[i] = result;
});
}
var i = undefined;
for (i = 0; i < len; i += 1) {
promise = next(i);
}
return promise.then(function () {
return results;
});
}
var _emptyArrayPromise = sander.Promise.resolve([]);
var ____hasOwnProp = Object.prototype.hasOwnProperty;
function ____has(obj, prop) {
return ____hasOwnProp.call(obj, prop);
}
function analyse(magicString, module) {
// first we need to generate comprehensive scope info
var previousStatement = null;
var commentIndex = 0;
module.statements.forEach(function (statement) {
var node = statement.node;
var trailing = !!previousStatement;
// TODO surely this can be neater
// attach leading comment
do {
var comment = module.comments[commentIndex];
// prevent comments inside the previous statement being
// appended to it
if (previousStatement) {
while (comment && comment.start < previousStatement.node.end) {
commentIndex += 1;
comment = module.comments[commentIndex];
}
}
if (!comment || comment.end > node.start) break;
// attach any trailing comment to the previous statement
if (trailing && !/\n/.test(module.source.slice(previousStatement.node.end, comment.start))) {
previousStatement.trailingComment = comment;
}
// then attach leading comments to this statement
else {
statement.leadingComments.push(comment);
}
commentIndex += 1;
trailing = false;
} while (module.comments[commentIndex]);
// determine margin
var previousEnd = previousStatement ? (previousStatement.trailingComment || previousStatement.node).end : 0;
var start = (statement.leadingComments[0] || node).start;
var gap = magicString.original.slice(previousEnd, start);
var margin = gap.split('\n').length;
if (previousStatement) previousStatement.margin[1] = margin;
statement.margin[0] = margin;
statement.analyse();
previousStatement = statement;
});
}var _analyse = analyse;
function _getLocation(source, charIndex) {
var lines = source.split('\n');
var len = lines.length;
var lineStart = 0;
var i = undefined;
for (i = 0; i < len; i += 1) {
var line = lines[i];
var lineEnd = lineStart + line.length + 1; // +1 for newline
if (lineEnd > charIndex) {
return { line: i + 1, column: charIndex - lineStart };
}
lineStart = lineEnd;
}
throw new Error('Could not determine location of character');
}
function isExportDeclaration(statement) {
return statement.isExportDeclaration;
}
function isImportDeclaration(statement) {
return statement.isImportDeclaration;
}
var hasOwnProp = Object.prototype.hasOwnProperty;
function has(obj, prop) {
return hasOwnProp.call(obj, prop);
}
var keys = Object.keys;
var shouldSkip = undefined;
var shouldAbort = undefined;
function walk(ast, _ref) {
var enter = _ref.enter;
var leave = _ref.leave;
shouldAbort = false;
visit(ast, null, enter, leave);
}
var shouldSkip = undefined;

@@ -34,6 +336,2 @@ var context = {

var childKeys = {};
var toString = Object.prototype.toString;
function isArray(thing) {

@@ -43,2 +341,4 @@ return toString.call(thing) === '[object Array]';

var childKeys = {};
function visit(node, parent, enter, leave) {

@@ -81,8 +381,61 @@ if (!node || shouldAbort) return;

}
function walk(ast, _ref) {
var enter = _ref.enter;
var leave = _ref.leave;
function Scope___classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
shouldAbort = false;
visit(ast, null, enter, leave);
}
function sequence(arr, callback) {
var len = arr.length;
var results = new Array(len);
var promise = sander.Promise.resolve();
function next(i) {
return promise.then(function () {
return callback(arr[i], i);
}).then(function (result) {
return results[i] = result;
});
}
var i = undefined;
for (i = 0; i < len; i += 1) {
promise = next(i);
}
return promise.then(function () {
return results;
});
}
var emptyArrayPromise = Promise.resolve([]);
function getLocation(source, charIndex) {
var lines = source.split('\n');
var len = lines.length;
var lineStart = 0;
var i = undefined;
for (i = 0; i < len; i += 1) {
var line = lines[i];
var lineEnd = lineStart + line.length + 1; // +1 for newline
if (lineEnd > charIndex) {
return { line: i + 1, column: charIndex - lineStart };
}
lineStart = lineEnd;
}
throw new Error('Could not determine location of character');
}function __classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var Scope = (function () {
function Scope(options) {
Scope___classCallCheck(this, Scope);
__classCallCheck(this, Scope);

@@ -130,105 +483,57 @@ options = options || {};

function quoteId(x) {
return "'" + x.id + "'";
}
function ___classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
function req(x) {
return "require('" + x.id + "')";
}
var Statement = (function () {
function Statement(node, magicString, module) {
___classCallCheck(this, Statement);
function getLocation(source, charIndex) {
var lines = source.split('\n');
var len = lines.length;
this.node = node;
this.module = module;
this.magicString = magicString;
var lineStart = 0;
var i = undefined;
this.scope = new Scope();
this.defines = {};
this.modifies = {};
this.dependsOn = {};
for (i = 0; i < len; i += 1) {
var line = lines[i];
var lineEnd = lineStart + line.length + 1; // +1 for newline
this.isIncluded = false;
if (lineEnd > charIndex) {
return { line: i + 1, column: charIndex - lineStart };
}
this.leadingComments = [];
this.trailingComment = null;
this.margin = [0, 0];
lineStart = lineEnd;
// some facts about this statement...
this.isImportDeclaration = node.type === 'ImportDeclaration';
this.isExportDeclaration = /^Export/.test(node.type);
}
throw new Error('Could not determine location of character');
}
Statement.prototype.analyse = function analyse() {
var _this = this;
var _analyse = analyse;
function analyse(ast, magicString, module) {
var scope = new Scope();
var currentTopLevelStatement = undefined;
if (this.isImportDeclaration) return; // nothing to analyse
function addToScope(declarator) {
var name = declarator.id.name;
scope.add(name, false);
var statement = this; // TODO use arrow functions instead
var magicString = this.magicString;
if (!scope.parent) {
currentTopLevelStatement._defines[name] = true;
}
}
var scope = this.scope;
function addToBlockScope(declarator) {
var name = declarator.id.name;
scope.add(name, true);
function addToScope(declarator) {
var name = declarator.id.name;
scope.add(name, false);
if (!scope.parent) {
currentTopLevelStatement._defines[name] = true;
if (!scope.parent) {
statement.defines[name] = true;
}
}
}
// first we need to generate comprehensive scope info
var previousStatement = null;
var commentIndex = 0;
function addToBlockScope(declarator) {
var name = declarator.id.name;
scope.add(name, true);
ast.body.forEach(function (statement) {
currentTopLevelStatement = statement; // so we can attach scoping info
Object.defineProperties(statement, {
_defines: { value: {} },
_modifies: { value: {} },
_dependsOn: { value: {} },
_included: { value: false, writable: true },
_module: { value: module },
_source: { value: magicString.snip(statement.start, statement.end) }, // TODO don't use snip, it's a waste of memory
_margin: { value: [0, 0] },
_leadingComments: { value: [] },
_trailingComment: { value: null, writable: true } });
var trailing = !!previousStatement;
// attach leading comment
do {
var comment = module.comments[commentIndex];
if (!comment || comment.end > statement.start) break;
// attach any trailing comment to the previous statement
if (trailing && !/\n/.test(magicString.slice(previousStatement.end, comment.start))) {
previousStatement._trailingComment = comment;
if (!scope.parent) {
statement.defines[name] = true;
}
}
// then attach leading comments to this statement
else {
statement._leadingComments.push(comment);
}
commentIndex += 1;
trailing = false;
} while (module.comments[commentIndex]);
// determine margin
var previousEnd = previousStatement ? (previousStatement._trailingComment || previousStatement).end : 0;
var start = (statement._leadingComments[0] || statement).start;
var gap = magicString.original.slice(previousEnd, start);
var margin = gap.split('\n').length;
if (previousStatement) previousStatement._margin[1] = margin;
statement._margin[0] = margin;
walk(statement, {
walk(this.node, {
enter: function (node) {

@@ -291,6 +596,2 @@ var newScope = undefined;

leave: function (node) {
if (node === currentTopLevelStatement) {
currentTopLevelStatement = null;
}
if (node._scope) {

@@ -302,126 +603,198 @@ scope = scope.parent;

previousStatement = statement;
});
if (!this.isImportDeclaration) {
walk(this.node, {
enter: function (node, parent) {
if (node._scope) scope = node._scope;
// then, we need to find which top-level dependencies this statement has,
// and which it potentially modifies
ast.body.forEach(function (statement) {
function checkForReads(node, parent) {
if (node.type === 'Identifier') {
// disregard the `bar` in `foo.bar` - these appear as Identifier nodes
if (parent.type === 'MemberExpression' && node !== parent.object) {
return;
_this.checkForReads(scope, node, parent);
_this.checkForWrites(scope, node);
},
leave: function (node) {
if (node._scope) scope = scope.parent;
}
});
}
};
// disregard the `bar` in { bar: foo }
if (parent.type === 'Property' && node !== parent.value) {
return;
}
Statement.prototype.checkForReads = function checkForReads(scope, node, parent) {
if (node.type === 'Identifier') {
// disregard the `bar` in `foo.bar` - these appear as Identifier nodes
if (parent.type === 'MemberExpression' && node !== parent.object) {
return;
}
var definingScope = scope.findDefiningScope(node.name);
// disregard the `bar` in { bar: foo }
if (parent.type === 'Property' && node !== parent.value) {
return;
}
if ((!definingScope || definingScope.depth === 0) && !statement._defines[node.name]) {
statement._dependsOn[node.name] = true;
}
var definingScope = scope.findDefiningScope(node.name);
if ((!definingScope || definingScope.depth === 0) && !this.defines[node.name]) {
this.dependsOn[node.name] = true;
}
}
};
function checkForWrites(node) {
function addNode(node, disallowImportReassignments) {
while (node.type === 'MemberExpression') {
node = node.object;
}
Statement.prototype.checkForWrites = function checkForWrites(scope, node) {
var _this2 = this;
// disallow assignments/updates to imported bindings and namespaces
if (disallowImportReassignments && has(module.imports, node.name) && !scope.contains(node.name)) {
var err = new Error('Illegal reassignment to import \'' + node.name + '\'');
err.file = module.path;
err.loc = getLocation(module.code.toString(), node.start);
throw err;
}
var addNode = function (node, disallowImportReassignments) {
while (node.type === 'MemberExpression') {
node = node.object;
}
if (node.type !== 'Identifier') {
return;
}
statement._modifies[node.name] = true;
// disallow assignments/updates to imported bindings and namespaces
if (disallowImportReassignments && has(_this2.module.imports, node.name) && !scope.contains(node.name)) {
var err = new Error('Illegal reassignment to import \'' + node.name + '\'');
err.file = _this2.module.path;
err.loc = getLocation(_this2.module.magicString.toString(), node.start);
throw err;
}
if (node.type === 'AssignmentExpression') {
addNode(node.left, true);
} else if (node.type === 'UpdateExpression') {
addNode(node.argument, true);
} else if (node.type === 'CallExpression') {
node.arguments.forEach(function (arg) {
return addNode(arg, false);
});
if (node.type !== 'Identifier') {
return;
}
// TODO UpdateExpressions, method calls?
_this2.modifies[node.name] = true;
};
if (node.type === 'AssignmentExpression') {
addNode(node.left, true);
} else if (node.type === 'UpdateExpression') {
addNode(node.argument, true);
} else if (node.type === 'CallExpression') {
node.arguments.forEach(function (arg) {
return addNode(arg, false);
});
}
};
walk(statement, {
enter: function (node, parent) {
// skip imports
if (/^Import/.test(node.type)) return this.skip();
Statement.prototype.expand = function expand() {
var _this3 = this;
if (node._scope) scope = node._scope;
if (this.isIncluded) return emptyArrayPromise;
this.isIncluded = true;
checkForReads(node, parent);
checkForWrites(node, parent);
var result = [];
//if ( node.type === 'ReturnStatement')
},
leave: function (node) {
if (node._scope) scope = scope.parent;
}
});
});
// We have a statement, and it hasn't been included yet. First, include
// the statements it depends on
var dependencies = Object.keys(this.dependsOn);
ast._scope = scope;
}
return sequence(dependencies, function (name) {
return _this3.module.define(name).then(function (definition) {
result.push.apply(result, definition);
});
})
function sequence(arr, callback) {
var len = arr.length;
var results = new Array(len);
// then include the statement itself
.then(function () {
result.push(_this3);
})
var promise = sander.Promise.resolve();
// then include any statements that could modify the
// thing(s) this statement defines
.then(function () {
return sequence(keys(_this3.defines), function (name) {
var modifications = has(_this3.module.modifications, name) && _this3.module.modifications[name];
function next(i) {
return promise.then(function () {
return callback(arr[i], i);
}).then(function (result) {
return results[i] = result;
if (modifications) {
return sequence(modifications, function (statement) {
if (!statement.isIncluded) {
return statement.expand().then(function (statements) {
result.push.apply(result, statements);
});
}
});
}
});
})
// the `result` is an array of statements needed to define `name`
.then(function () {
return result;
});
}
};
var i = undefined;
Statement.prototype.replaceIdentifiers = function replaceIdentifiers(names) {
var magicString = this.magicString.clone().trim();
var replacementStack = [names];
var nameList = keys(names);
for (i = 0; i < len; i += 1) {
promise = next(i);
}
var deshadowList = [];
nameList.forEach(function (name) {
var replacement = names[name];
deshadowList.push(replacement.split('.')[0]);
});
return promise.then(function () {
return results;
});
}
if (nameList.length > 0) {
walk(this.node, {
enter: function (node, parent) {
var _this4 = this;
var reservedWords = 'break case class catch const continue debugger default delete do else export extends finally for function if import in instanceof let new return super switch this throw try typeof var void while with yield enum await implements package protected static interface private public'.split(' ');
var builtins = 'Infinity NaN undefined null true false eval uneval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Symbol Error EvalError InternalError RangeError ReferenceError SyntaxError TypeError URIError Number Math Date String RegExp Array Int8Array Uint8Array Uint8ClampedArray Int16Array Uint16Array Int32Array Uint32Array Float32Array Float64Array Map Set WeakMap WeakSet SIMD ArrayBuffer DataView JSON Promise Generator GeneratorFunction Reflect Proxy Intl'.split(' ');
var scope = node._scope;
var blacklisted = {};
reservedWords.concat(builtins).forEach(function (word) {
return blacklisted[word] = true;
});
function makeLegalIdentifier(str) {
str = str.replace(/[^$_a-zA-Z0-9]/g, '_');
if (/\d/.test(str[0]) || blacklisted[str]) str = '_' + str;
if (scope) {
var _ret = (function () {
var newNames = {};
var hasReplacements = undefined;
return str;
}
keys(names).forEach(function (key) {
if (! ~scope.names.indexOf(key)) {
newNames[key] = names[key];
hasReplacements = true;
}
});
function Module___classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
deshadowList.forEach(function (name) {
if (~scope.names.indexOf(name)) {
newNames[name] = name + '$$'; // TODO better mechanism
hasReplacements = true;
}
});
var emptyArrayPromise = sander.Promise.resolve([]);
if (!hasReplacements) {
return {
v: _this4.skip()
};
}
names = newNames;
replacementStack.push(newNames);
})();
if (typeof _ret === 'object') return _ret.v;
}
// We want to rewrite identifiers (that aren't property names)
if (node.type !== 'Identifier') return;
if (parent.type === 'MemberExpression' && !parent.computed && node !== parent.object) return;
if (parent.type === 'Property' && node !== parent.value) return;
// TODO others...?
var name = has(names, node.name) && names[node.name];
if (name && name !== node.name) {
magicString.overwrite(node.start, node.end, name);
}
},
leave: function (node) {
if (node._scope) {
replacementStack.pop();
names = replacementStack[replacementStack.length - 1];
}
}
});
}
return magicString;
};
return Statement;
})();
function ____classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
var Module = (function () {

@@ -431,14 +804,16 @@ function Module(_ref) {

var path = _ref.path;
var code = _ref.code;
var path$$ = _ref.path;
var source = _ref.source;
var bundle = _ref.bundle;
Module___classCallCheck(this, Module);
____classCallCheck(this, Module);
this.source = source;
this.bundle = bundle;
this.path = path;
this.relativePath = _path.relative(bundle.base, path).slice(0, -3); // remove .js
this.path = path$$;
this.relativePath = path.relative(bundle.base, path$$).slice(0, -3); // remove .js
this.code = new MagicString(code, {
filename: path
this.magicString = new MagicString(source, {
filename: path$$
});

@@ -449,4 +824,6 @@

// Try to extract a list of top-level statements/declarations. If
// the parse fails, attach file info and abort
try {
this.ast = acorn.parse(code, {
var ast = acorn.parse(source, {
ecmaVersion: 6,

@@ -458,7 +835,15 @@ sourceType: 'module',

});
this.statements = ast.body.map(function (node) {
var magicString = _this.magicString.snip(node.start, node.end);
return new Statement(node, magicString, _this);
});
} catch (err) {
err.file = path;
err.file = path$$;
throw err;
}
this.importDeclarations = this.statements.filter(isImportDeclaration);
this.exportDeclarations = this.statements.filter(isExportDeclaration);
this.analyse();

@@ -474,90 +859,88 @@ }

this.ast.body.forEach(function (node) {
var source = undefined;
this.importDeclarations.forEach(function (statement) {
var node = statement.node;
var source = node.source.value;
// import foo from './foo';
// import { bar } from './bar';
if (node.type === 'ImportDeclaration') {
source = node.source.value;
node.specifiers.forEach(function (specifier) {
var isDefault = specifier.type === 'ImportDefaultSpecifier';
var isNamespace = specifier.type === 'ImportNamespaceSpecifier';
node.specifiers.forEach(function (specifier) {
var isDefault = specifier.type === 'ImportDefaultSpecifier';
var isNamespace = specifier.type === 'ImportNamespaceSpecifier';
var localName = specifier.local.name;
var name = isDefault ? 'default' : isNamespace ? '*' : specifier.imported.name;
var localName = specifier.local.name;
var name = isDefault ? 'default' : isNamespace ? '*' : specifier.imported.name;
if (____has(_this2.imports, localName)) {
var err = new Error('Duplicated import \'' + localName + '\'');
err.file = _this2.path;
err.loc = _getLocation(_this2.source, specifier.start);
throw err;
}
if (has(_this2.imports, localName)) {
var err = new Error('Duplicated import \'' + localName + '\'');
err.file = _this2.path;
err.loc = getLocation(_this2.code.original, specifier.start);
throw err;
}
_this2.imports[localName] = {
source: source,
name: name,
localName: localName
};
});
});
_this2.imports[localName] = {
source: source,
name: name,
localName: localName
};
});
} else if (/^Export/.test(node.type)) {
// export default function foo () {}
// export default foo;
// export default 42;
if (node.type === 'ExportDefaultDeclaration') {
var isDeclaration = /Declaration$/.test(node.declaration.type);
this.exportDeclarations.forEach(function (statement) {
var node = statement.node;
var source = node.source && node.source.value;
_this2.exports.default = {
node: node,
name: 'default',
localName: isDeclaration ? node.declaration.id.name : 'default',
isDeclaration: isDeclaration
};
}
// export default function foo () {}
// export default foo;
// export default 42;
if (node.type === 'ExportDefaultDeclaration') {
var isDeclaration = /Declaration$/.test(node.declaration.type);
// export { foo, bar, baz }
// export var foo = 42;
// export function foo () {}
else if (node.type === 'ExportNamedDeclaration') {
// export { foo } from './foo';
source = node.source && node.source.value;
_this2.exports.default = {
statement: statement,
name: 'default',
localName: isDeclaration ? node.declaration.id.name : 'default',
isDeclaration: isDeclaration
};
}
if (node.specifiers.length) {
// export { foo, bar, baz }
node.specifiers.forEach(function (specifier) {
var localName = specifier.local.name;
var exportedName = specifier.exported.name;
// export { foo, bar, baz }
// export var foo = 42;
// export function foo () {}
else if (node.type === 'ExportNamedDeclaration') {
if (node.specifiers.length) {
// export { foo, bar, baz }
node.specifiers.forEach(function (specifier) {
var localName = specifier.local.name;
var exportedName = specifier.exported.name;
_this2.exports[exportedName] = {
_this2.exports[exportedName] = {
localName: localName,
exportedName: exportedName
};
// export { foo } from './foo';
if (source) {
_this2.imports[localName] = {
source: source,
localName: localName,
exportedName: exportedName
name: exportedName
};
}
});
} else {
var declaration = node.declaration;
if (source) {
_this2.imports[localName] = {
source: source,
localName: localName,
name: exportedName
};
}
});
var _name = undefined;
if (declaration.type === 'VariableDeclaration') {
// export var foo = 42
_name = declaration.declarations[0].id.name;
} else {
var declaration = node.declaration;
// export function foo () {}
_name = declaration.id.name;
}
var _name = undefined;
if (declaration.type === 'VariableDeclaration') {
// export var foo = 42
_name = declaration.declarations[0].id.name;
} else {
// export function foo () {}
_name = declaration.id.name;
}
_this2.exports[_name] = {
node: node,
localName: _name,
expression: declaration
};
}
_this2.exports[_name] = {
statement: statement,
localName: _name,
expression: declaration
};
}

@@ -567,6 +950,4 @@ }

_analyse(this.ast, this.code, this);
_analyse(this.magicString, this);
this.definedNames = this.ast._scope.names.slice();
this.canonicalNames = {};

@@ -578,9 +959,9 @@

this.ast.body.forEach(function (statement) {
Object.keys(statement._defines).forEach(function (name) {
this.statements.forEach(function (statement) {
Object.keys(statement.defines).forEach(function (name) {
_this2.definitions[name] = statement;
});
Object.keys(statement._modifies).forEach(function (name) {
if (!has(_this2.modifications, name)) {
Object.keys(statement.modifies).forEach(function (name) {
if (!____has(_this2.modifications, name)) {
_this2.modifications[name] = [];

@@ -595,10 +976,10 @@ }

Module.prototype.getCanonicalName = function getCanonicalName(localName) {
if (has(this.suggestedNames, localName)) {
if (____has(this.suggestedNames, localName)) {
localName = this.suggestedNames[localName];
}
if (!has(this.canonicalNames, localName)) {
if (!____has(this.canonicalNames, localName)) {
var canonicalName = undefined;
if (has(this.imports, localName)) {
if (____has(this.imports, localName)) {
var importDeclaration = this.imports[localName];

@@ -635,4 +1016,4 @@ var _module = importDeclaration.module;

// shortcut cycles. TODO this won't work everywhere...
if (has(this.definitionPromises, name)) {
return emptyArrayPromise;
if (____has(this.definitionPromises, name)) {
return _emptyArrayPromise;
}

@@ -643,3 +1024,3 @@

// The definition for this name is in a different module
if (has(this.imports, name)) {
if (____has(this.imports, name)) {
(function () {

@@ -655,7 +1036,7 @@ var importDeclaration = _this3.imports[name];

var localName = importDeclaration.localName;
var suggestion = has(_this3.suggestedNames, localName) ? _this3.suggestedNames[localName] : localName;
var suggestion = ____has(_this3.suggestedNames, localName) ? _this3.suggestedNames[localName] : localName;
module.suggestName('default', suggestion);
} else if (importDeclaration.name === '*') {
var localName = importDeclaration.localName;
var suggestion = has(_this3.suggestedNames, localName) ? _this3.suggestedNames[localName] : localName;
var suggestion = ____has(_this3.suggestedNames, localName) ? _this3.suggestedNames[localName] : localName;
module.suggestName('*', suggestion);

@@ -673,3 +1054,3 @@ module.suggestName('default', '' + suggestion + '__default');

module.importedByBundle.push(importDeclaration);
return emptyArrayPromise;
return _emptyArrayPromise;
}

@@ -706,4 +1087,3 @@

if (name === 'default') {
// TODO can we use this.definitions[ name ], as below?
statement = this.exports.default.node;
statement = this.exports.default.statement;
} else {

@@ -713,74 +1093,37 @@ statement = this.definitions[name];

if (statement && !statement._included) {
promise = this.expandStatement(statement);
if (statement && !statement.isIncluded) {
promise = statement.expand();
}
}
this.definitionPromises[name] = promise || emptyArrayPromise;
this.definitionPromises[name] = promise || _emptyArrayPromise;
return this.definitionPromises[name];
};
Module.prototype.expandStatement = function expandStatement(statement) {
Module.prototype.expandAllStatements = function expandAllStatements(isEntryModule) {
var _this4 = this;
if (statement._included) return emptyArrayPromise;
statement._included = true;
var allStatements = [];
var result = [];
// We have a statement, and it hasn't been included yet. First, include
// the statements it depends on
var dependencies = Object.keys(statement._dependsOn);
return sequence(dependencies, function (name) {
return _this4.define(name).then(function (definition) {
result.push.apply(result, definition);
});
})
// then include the statement itself
.then(function () {
result.push(statement);
})
// then include any statements that could modify the
// thing(s) this statement defines
.then(function () {
return sequence(keys(statement._defines), function (name) {
var modifications = has(_this4.modifications, name) && _this4.modifications[name];
if (modifications) {
return sequence(modifications, function (statement) {
if (!statement._included) {
return _this4.expandStatement(statement).then(function (statements) {
result.push.apply(result, statements);
});
}
});
return _sequence(this.statements, function (statement) {
// A statement may have already been included, in which case we need to
// curb rollup's enthusiasm and move it down here. It remains to be seen
// if this approach is bulletproof
if (statement.isIncluded) {
var index = allStatements.indexOf(statement);
if (~index) {
allStatements.splice(index, 1);
allStatements.push(statement);
}
});
})
// the `result` is an array of statements needed to define `name`
.then(function () {
return result;
});
};
return;
}
Module.prototype.expandAllStatements = function expandAllStatements(isEntryModule) {
var _this5 = this;
var allStatements = [];
return sequence(this.ast.body, function (statement) {
// skip already-included statements
if (statement._included) return;
// skip import declarations
if (statement.type === 'ImportDeclaration') {
// unless they're empty, in which case assume we're importing them for the side-effects
// skip import declarations...
if (statement.isImportDeclaration) {
// ...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.specifiers.length) {
return _this5.bundle.fetchModule(statement.source.value, _this5.path).then(function (module) {
statement.module = module;
if (!statement.node.specifiers.length) {
return _this4.bundle.fetchModule(statement.node.source.value, _this4.path).then(function (module) {
statement.module = module; // TODO what is this for? what does it do? why not _module?
return module.expandAllStatements();

@@ -795,7 +1138,7 @@ }).then(function (statements) {

// skip `export { foo, bar, baz }`
if (statement.type === 'ExportNamedDeclaration' && statement.specifiers.length) {
// but ensure they are defined, if this is the entry module
// skip `export { foo, bar, baz }`...
if (statement.node.type === 'ExportNamedDeclaration' && statement.node.specifiers.length) {
// ...but ensure they are defined, if this is the entry module
if (isEntryModule) {
return _this5.expandStatement(statement).then(function (statements) {
return statement.expand().then(function (statements) {
allStatements.push.apply(allStatements, statements);

@@ -809,3 +1152,3 @@ });

// include everything else
return _this5.expandStatement(statement).then(function (statements) {
return statement.expand().then(function (statements) {
allStatements.push.apply(allStatements, statements);

@@ -831,7 +1174,7 @@ });

function ExternalModule___classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
function _____classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
var ExternalModule = (function () {
function ExternalModule(id) {
ExternalModule___classCallCheck(this, ExternalModule);
_____classCallCheck(this, ExternalModule);

@@ -877,190 +1220,5 @@ this.id = id;

function amd(bundle, magicString, exportMode, options) {
var deps = bundle.externalModules.map(quoteId);
var args = bundle.externalModules.map(getName);
if (exportMode === 'named') {
args.unshift('exports');
deps.unshift('\'exports\'');
}
var params = (has(options, 'moduleId') ? '[\'' + options.moduleId + '\'], ' : '') + (deps.length ? '[' + deps.join(', ') + '], ' : '');
var intro = 'define(' + params + 'function (' + args.join(', ') + ') { \'use strict\';\n\n';
var exports = bundle.entryModule.exports;
var exportBlock = undefined;
if (exportMode === 'default') {
exportBlock = 'return ' + bundle.entryModule.getCanonicalName('default') + ';';
} else {
exportBlock = '\n\n' + Object.keys(exports).map(function (name) {
return 'exports.' + name + ' = ' + exports[name].localName + ';';
}).join('\n');
}
return magicString.append(exportBlock).trim().indent().append('\n\n});').prepend(intro);
}
function cjs(bundle, magicString, exportMode) {
var intro = '\'use strict\';\n\n';
// TODO handle empty imports, once they're supported
var importBlock = bundle.externalModules.map(function (module) {
var requireStatement = 'var ' + module.name + ' = require(\'' + module.id + '\');';
if (module.needsDefault) {
requireStatement += '\n' + (module.needsNamed ? 'var ' + module.name + '__default = ' : '' + module.name + ' = ') + ('\'default\' in ' + module.name + ' ? ' + module.name + '[\'default\'] : ' + module.name + ';');
}
return requireStatement;
}).join('\n');
if (importBlock) {
intro += importBlock + '\n\n';
}
magicString.prepend(intro);
var exportBlock = undefined;
if (exportMode === 'default' && bundle.entryModule.exports.default) {
exportBlock = 'module.exports = ' + bundle.entryModule.getCanonicalName('default') + ';';
} else if (exportMode === 'named') {
exportBlock = keys(bundle.entryModule.exports).map(function (key) {
var specifier = bundle.entryModule.exports[key];
var name = bundle.entryModule.getCanonicalName(specifier.localName);
return 'exports.' + key + ' = ' + name + ';';
}).join('\n');
}
if (exportBlock) {
magicString.append('\n\n' + exportBlock);
}
return magicString;
}
var es6__default = es6__es6;
function es6__es6(bundle, magicString, exportMode, options) {
// TODO
var introBlock = '';
var exportBlock = '';
return magicString.trim();
}
var iife = iife__es6;
function iife__es6(bundle, magicString, exportMode, options) {
var intro = "(function () { 'use strict';\n\n";
var outro = "\n\n})();";
return magicString.trim().indent().prepend(intro).append(outro);
}
function umd(bundle, magicString, exportMode, options) {
var indentStr = magicString.getIndentString();
var globalNames = options.globals || {};
var amdDeps = bundle.externalModules.map(quoteId);
var cjsDeps = bundle.externalModules.map(req);
var globalDeps = bundle.externalModules.map(function (module) {
return has(globalNames, module.id) ? globalNames[module.id] : module.name;
});
var args = bundle.externalModules.map(getName);
if (exportMode === 'named') {
amdDeps.unshift('\'exports\'');
cjsDeps.unshift('\'exports\'');
globalDeps.unshift('(global.' + options.moduleName + ' = {})');
args.unshift('exports');
}
var amdParams = (has(options, 'moduleId') ? '[\'' + options.moduleId + '\'], ' : '') + (amdDeps.length ? '[' + amdDeps.join(', ') + '], ' : '');
var intro = ('(function (global, factory) {\n\t\t\ttypeof exports === \'object\' && typeof module !== \'undefined\' ? factory(' + cjsDeps.join(', ') + ') :\n\t\t\ttypeof define === \'function\' && define.amd ? define(' + amdParams + 'factory) :\n\t\t\tfactory(' + globalDeps + ');\n\t\t}(this, function (' + args + ') { \'use strict\';\n\n\t\t').replace(/^\t\t/gm, '').replace(/^\t/gm, indentStr);
var exports = bundle.entryModule.exports;
var exportBlock = '\n\n' + Object.keys(exports).map(function (name) {
return 'exports.' + name + ' = ' + exports[name].localName + ';';
}).join('\n');
return magicString.append(exportBlock).trim().indent().append('\n\n}));').prepend(intro);
}
var finalisers = { amd: amd, cjs: cjs, es6: es6__default, iife: iife, umd: umd };
function replaceIdentifiers(statement, snippet, names) {
var replacementStack = [names];
var keys = Object.keys(names);
if (keys.length === 0) {
return;
}
walk(statement, {
enter: function (node, parent) {
var _this = this;
var scope = node._scope;
if (scope) {
var _ret = (function () {
var newNames = {};
var hasReplacements = undefined;
keys.forEach(function (key) {
if (! ~scope.names.indexOf(key)) {
newNames[key] = names[key];
hasReplacements = true;
}
});
if (!hasReplacements) {
return {
v: _this.skip()
};
}
names = newNames;
replacementStack.push(newNames);
})();
if (typeof _ret === 'object') return _ret.v;
}
// We want to rewrite identifiers (that aren't property names)
if (node.type !== 'Identifier') return;
if (parent.type === 'MemberExpression' && node !== parent.object) return;
if (parent.type === 'Property' && node !== parent.value) return;
// TODO others...?
var name = has(names, node.name) && names[node.name];
if (name && name !== node.name) {
snippet.overwrite(node.start, node.end, name);
}
},
leave: function (node) {
if (node._scope) {
replacementStack.pop();
names = replacementStack[replacementStack.length - 1];
}
}
});
}
function defaultResolver(importee, importer) {
// absolute paths are left untouched
if (_path.isAbsolute(importee)) return importee;
if (path.isAbsolute(importee)) return importee;

@@ -1070,17 +1228,11 @@ // external modules stay external

return _path.resolve(_path.dirname(importer), importee).replace(/\.js$/, '') + '.js';
}
return path.resolve(path.dirname(importer), importee).replace(/\.js$/, '') + '.js';
}function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
function Bundle___classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
function badExports(option, keys) {
throw new Error('\'' + option + '\' was specified for options.exports, but entry module has following exports: ' + keys.join(', '));
}
var Bundle = (function () {
function Bundle(options) {
Bundle___classCallCheck(this, Bundle);
_classCallCheck(this, Bundle);
this.entryPath = _path.resolve(options.entry).replace(/\.js$/, '') + '.js';
this.base = _path.dirname(this.entryPath);
this.entryPath = path.resolve(options.entry).replace(/\.js$/, '') + '.js';
this.base = path.dirname(this.entryPath);

@@ -1100,6 +1252,6 @@ this.resolvePath = options.resolvePath || defaultResolver;

return sander.Promise.resolve(importer === null ? importee : this.resolvePath(importee, importer)).then(function (path) {
if (!path) {
return sander.Promise.resolve(importer === null ? importee : this.resolvePath(importee, importer)).then(function (path$$) {
if (!path$$) {
// external module
if (!has(_this.modulePromises, importee)) {
if (!___has(_this.modulePromises, importee)) {
var _module = new ExternalModule(importee);

@@ -1113,7 +1265,7 @@ _this.externalModules.push(_module);

if (!has(_this.modulePromises, path)) {
_this.modulePromises[path] = sander.readFile(path, { encoding: 'utf-8' }).then(function (code) {
if (!___has(_this.modulePromises, path$$)) {
_this.modulePromises[path$$] = sander.readFile(path$$, { encoding: 'utf-8' }).then(function (source) {
var module = new Module({
path: path,
code: code,
path: path$$,
source: source,
bundle: _this

@@ -1126,3 +1278,3 @@ });

return _this.modulePromises[path];
return _this.modulePromises[path$$];
});

@@ -1139,8 +1291,18 @@ };

if (entryModule.exports.default) {
var defaultExportName = makeLegalIdentifier(_path.basename(_this2.entryPath).slice(0, -_path.extname(_this2.entryPath).length));
while (entryModule.ast._scope.contains(defaultExportName)) {
defaultExportName = '_' + defaultExportName;
}
(function () {
var defaultExportName = _makeLegalIdentifier(path.basename(_this2.entryPath).slice(0, -path.extname(_this2.entryPath).length));
entryModule.suggestName('default', defaultExportName);
var topLevelNames = [];
entryModule.statements.forEach(function (statement) {
_keys(statement.defines).forEach(function (name) {
return topLevelNames.push(name);
});
});
while (~topLevelNames.indexOf(defaultExportName)) {
defaultExportName = '_' + defaultExportName;
}
entryModule.suggestName('default', defaultExportName);
})();
}

@@ -1161,4 +1323,4 @@

this.statements.forEach(function (statement) {
keys(statement._defines).forEach(function (name) {
if (has(definers, name)) {
_keys(statement.defines).forEach(function (name) {
if (___has(definers, name)) {
conflicts[name] = true;

@@ -1171,3 +1333,3 @@ } else {

// per module... but some people write bad js
definers[name].push(statement._module);
definers[name].push(statement.module);
});

@@ -1179,5 +1341,5 @@ });

// TODO is this right?
var name = makeLegalIdentifier(module.suggestedNames['*'] || module.suggestedNames.default || module.id);
var name = _makeLegalIdentifier(module.suggestedNames['*'] || module.suggestedNames.default || module.id);
if (has(definers, name)) {
if (___has(definers, name)) {
conflicts[name] = true;

@@ -1193,3 +1355,3 @@ } else {

// Rename conflicting identifiers so they can live in the same scope
keys(conflicts).forEach(function (name) {
_keys(conflicts).forEach(function (name) {
var modules = definers[name];

@@ -1206,3 +1368,3 @@

function getSafeName(name) {
while (has(conflicts, name)) {
while (___has(conflicts, name)) {
name = '_' + name;

@@ -1230,4 +1392,4 @@ }

keys(statement._dependsOn).concat(keys(statement._defines)).forEach(function (name) {
var canonicalName = statement._module.getCanonicalName(name);
_keys(statement.dependsOn).concat(_keys(statement.defines)).forEach(function (name) {
var canonicalName = statement.module.getCanonicalName(name);

@@ -1239,8 +1401,8 @@ if (name !== canonicalName) {

var source = statement._source.clone().trim();
var source = statement.replaceIdentifiers(replacements);
// modify exports as necessary
if (/^Export/.test(statement.type)) {
if (statement.isExportDeclaration) {
// skip `export { foo, bar, baz }`
if (statement.type === 'ExportNamedDeclaration' && statement.specifiers.length) {
if (statement.node.type === 'ExportNamedDeclaration' && statement.node.specifiers.length) {
return;

@@ -1250,4 +1412,4 @@ }

// remove `export` from `export var foo = 42`
if (statement.type === 'ExportNamedDeclaration' && statement.declaration.type === 'VariableDeclaration') {
source.remove(statement.start, statement.declaration.start);
if (statement.node.type === 'ExportNamedDeclaration' && statement.node.declaration.type === 'VariableDeclaration') {
source.remove(statement.node.start, statement.node.declaration.start);
}

@@ -1257,13 +1419,13 @@

// TODO default exports need different treatment
else if (statement.declaration.id) {
source.remove(statement.start, statement.declaration.start);
} else if (statement.type === 'ExportDefaultDeclaration') {
var _module2 = statement._module;
else if (statement.node.declaration.id) {
source.remove(statement.node.start, statement.node.declaration.start);
} else if (statement.node.type === 'ExportDefaultDeclaration') {
var _module2 = statement.module;
var canonicalName = _module2.getCanonicalName('default');
if (statement.declaration.type === 'Identifier' && canonicalName === _module2.getCanonicalName(statement.declaration.name)) {
if (statement.node.declaration.type === 'Identifier' && canonicalName === _module2.getCanonicalName(statement.node.declaration.name)) {
return;
}
source.overwrite(statement.start, statement.declaration.start, 'var ' + canonicalName + ' = ');
source.overwrite(statement.node.start, statement.node.declaration.start, 'var ' + canonicalName + ' = ');
} else {

@@ -1274,7 +1436,5 @@ throw new Error('Unhandled export');

replaceIdentifiers(statement, source, replacements);
// add leading comments
if (statement._leadingComments.length) {
var commentBlock = statement._leadingComments.map(function (comment) {
if (statement.leadingComments.length) {
var commentBlock = statement.leadingComments.map(function (comment) {
return comment.block ? '/*' + comment.text + '*/' : '//' + comment.text;

@@ -1287,3 +1447,3 @@ }).join('\n');

// add margin
var margin = Math.max(statement._margin[0], previousMargin);
var margin = Math.max(statement.margin[0], previousMargin);
var newLines = new Array(margin).join('\n');

@@ -1298,3 +1458,3 @@

// add trailing comments
var comment = statement._trailingComment;
var comment = statement.trailingComment;
if (comment) {

@@ -1306,3 +1466,3 @@ var commentBlock = comment.block ? ' /*' + comment.text + '*/' : ' //' + comment.text;

previousMargin = statement._margin[1];
previousMargin = statement.margin[1];
});

@@ -1313,3 +1473,3 @@

var namespaceBlock = this.internalNamespaceModules.map(function (module) {
var exportKeys = keys(module.exports);
var exportKeys = _keys(module.exports);

@@ -1326,3 +1486,3 @@ return 'var ' + module.getCanonicalName('*') + ' = {\n' + exportKeys.map(function (key) {

if (!finalise) {
throw new Error('You must specify an output type - valid options are ' + keys(finalisers).join(', '));
throw new Error('You must specify an output type - valid options are ' + _keys(finalisers).join(', '));
}

@@ -1343,3 +1503,3 @@

Bundle.prototype.getExportMode = function getExportMode(exportMode) {
var exportKeys = keys(this.entryModule.exports);
var exportKeys = _keys(this.entryModule.exports);

@@ -1401,3 +1561,3 @@ if (exportMode === 'default') {

code += '\n//# ' + SOURCEMAPPING_URL + '=' + _path.basename(dest) + '.map';
code += '\n//# ' + SOURCEMAPPING_URL + '=' + path.basename(dest) + '.map';

@@ -1404,0 +1564,0 @@ return Promise.all([sander.writeFile(dest, code), sander.writeFile(dest + '.map', map.toString())]);

{
"name": "rollup",
"version": "0.3.1",
"version": "0.4.0",
"description": "Next-generation ES6 module bundler",

@@ -37,2 +37,3 @@ "main": "dist/rollup.js",

"gobble-esperanto-bundle": "^0.2.0",
"gobble-rollup": "^0.1.1",
"mocha": "^2.2.4",

@@ -39,0 +40,0 @@ "source-map-support": "^0.2.10"

@@ -1,29 +0,2 @@

import walk from './walk';
import Scope from './Scope';
import { getName } from '../utils/map-helpers';
import { has } from '../utils/object';
import getLocation from '../utils/getLocation';
export default function analyse ( ast, magicString, module ) {
let scope = new Scope();
let currentTopLevelStatement;
function addToScope ( declarator ) {
var name = declarator.id.name;
scope.add( name, false );
if ( !scope.parent ) {
currentTopLevelStatement._defines[ name ] = true;
}
}
function addToBlockScope ( declarator ) {
var name = declarator.id.name;
scope.add( name, true );
if ( !scope.parent ) {
currentTopLevelStatement._defines[ name ] = true;
}
}
export default function analyse ( magicString, module ) {
// first we need to generate comprehensive scope info

@@ -33,28 +6,26 @@ let previousStatement = null;

ast.body.forEach( statement => {
currentTopLevelStatement = statement; // so we can attach scoping info
module.statements.forEach( statement => {
const node = statement.node;
Object.defineProperties( statement, {
_defines: { value: {} },
_modifies: { value: {} },
_dependsOn: { value: {} },
_included: { value: false, writable: true },
_module: { value: module },
_source: { value: magicString.snip( statement.start, statement.end ) }, // TODO don't use snip, it's a waste of memory
_margin: { value: [ 0, 0 ] },
_leadingComments: { value: [] },
_trailingComment: { value: null, writable: true },
});
let trailing = !!previousStatement;
// TODO surely this can be neater
// attach leading comment
do {
const comment = module.comments[ commentIndex ];
let comment = module.comments[ commentIndex ];
if ( !comment || ( comment.end > statement.start ) ) break;
// prevent comments inside the previous statement being
// appended to it
if ( previousStatement ) {
while ( comment && comment.start < previousStatement.node.end ) {
commentIndex += 1;
comment = module.comments[ commentIndex ];
}
}
if ( !comment || ( comment.end > node.start ) ) break;
// attach any trailing comment to the previous statement
if ( trailing && !/\n/.test( magicString.slice( previousStatement.end, comment.start ) ) ) {
previousStatement._trailingComment = comment;
if ( trailing && !/\n/.test( module.source.slice( previousStatement.node.end, comment.start ) ) ) {
previousStatement.trailingComment = comment;
}

@@ -64,3 +35,3 @@

else {
statement._leadingComments.push( comment );
statement.leadingComments.push( comment );
}

@@ -73,4 +44,4 @@

// determine margin
const previousEnd = previousStatement ? ( previousStatement._trailingComment || previousStatement ).end : 0;
const start = ( statement._leadingComments[0] || statement ).start;
const previousEnd = previousStatement ? ( previousStatement.trailingComment || previousStatement.node ).end : 0;
const start = ( statement.leadingComments[0] || node ).start;

@@ -80,156 +51,9 @@ const gap = magicString.original.slice( previousEnd, start );

if ( previousStatement ) previousStatement._margin[1] = margin;
statement._margin[0] = margin;
if ( previousStatement ) previousStatement.margin[1] = margin;
statement.margin[0] = margin;
walk( statement, {
enter ( node ) {
let newScope;
statement.analyse();
magicString.addSourcemapLocation( node.start );
switch ( node.type ) {
case 'FunctionExpression':
case 'FunctionDeclaration':
case 'ArrowFunctionExpression':
let names = node.params.map( getName );
if ( node.type === 'FunctionDeclaration' ) {
addToScope( node );
} else if ( node.type === 'FunctionExpression' && node.id ) {
names.push( node.id.name );
}
newScope = new Scope({
parent: scope,
params: names, // TODO rest params?
block: false
});
break;
case 'BlockStatement':
newScope = new Scope({
parent: scope,
block: true
});
break;
case 'CatchClause':
newScope = new Scope({
parent: scope,
params: [ node.param.name ],
block: true
});
break;
case 'VariableDeclaration':
node.declarations.forEach( node.kind === 'let' ? addToBlockScope : addToScope ); // TODO const?
break;
case 'ClassDeclaration':
addToScope( node );
break;
}
if ( newScope ) {
Object.defineProperty( node, '_scope', { value: newScope });
scope = newScope;
}
},
leave ( node ) {
if ( node === currentTopLevelStatement ) {
currentTopLevelStatement = null;
}
if ( node._scope ) {
scope = scope.parent;
}
}
});
previousStatement = statement;
});
// then, we need to find which top-level dependencies this statement has,
// and which it potentially modifies
ast.body.forEach( statement => {
function checkForReads ( node, parent ) {
if ( node.type === 'Identifier' ) {
// disregard the `bar` in `foo.bar` - these appear as Identifier nodes
if ( parent.type === 'MemberExpression' && node !== parent.object ) {
return;
}
// disregard the `bar` in { bar: foo }
if ( parent.type === 'Property' && node !== parent.value ) {
return;
}
const definingScope = scope.findDefiningScope( node.name );
if ( ( !definingScope || definingScope.depth === 0 ) && !statement._defines[ node.name ] ) {
statement._dependsOn[ node.name ] = true;
}
}
}
function checkForWrites ( node ) {
function addNode ( node, disallowImportReassignments ) {
while ( node.type === 'MemberExpression' ) {
node = node.object;
}
// disallow assignments/updates to imported bindings and namespaces
if ( disallowImportReassignments && has( module.imports, node.name ) && !scope.contains( node.name ) ) {
const err = new Error( `Illegal reassignment to import '${node.name}'` );
err.file = module.path;
err.loc = getLocation( module.code.toString(), node.start );
throw err;
}
if ( node.type !== 'Identifier' ) {
return;
}
statement._modifies[ node.name ] = true;
}
if ( node.type === 'AssignmentExpression' ) {
addNode( node.left, true );
}
else if ( node.type === 'UpdateExpression' ) {
addNode( node.argument, true );
}
else if ( node.type === 'CallExpression' ) {
node.arguments.forEach( arg => addNode( arg, false ) );
}
// TODO UpdateExpressions, method calls?
}
walk( statement, {
enter ( node, parent ) {
// skip imports
if ( /^Import/.test( node.type ) ) return this.skip();
if ( node._scope ) scope = node._scope;
checkForReads( node, parent );
checkForWrites( node, parent );
//if ( node.type === 'ReturnStatement')
},
leave ( node ) {
if ( node._scope ) scope = scope.parent;
}
});
});
ast._scope = scope;
}

@@ -8,3 +8,2 @@ import { basename, dirname, extname, resolve } from 'path';

import finalisers from './finalisers/index';
import replaceIdentifiers from './utils/replaceIdentifiers';
import makeLegalIdentifier from './utils/makeLegalIdentifier';

@@ -48,6 +47,6 @@ import { defaultResolver } from './utils/resolvePath';

this.modulePromises[ path ] = readFile( path, { encoding: 'utf-8' })
.then( code => {
.then( source => {
const module = new Module({
path,
code,
source,
bundle: this

@@ -72,3 +71,9 @@ });

let defaultExportName = makeLegalIdentifier( basename( this.entryPath ).slice( 0, -extname( this.entryPath ).length ) );
while ( entryModule.ast._scope.contains( defaultExportName ) ) {
let topLevelNames = [];
entryModule.statements.forEach( statement => {
keys( statement.defines ).forEach( name => topLevelNames.push( name ) );
});
while ( ~topLevelNames.indexOf( defaultExportName ) ) {
defaultExportName = `_${defaultExportName}`;

@@ -95,3 +100,3 @@ }

this.statements.forEach( statement => {
keys( statement._defines ).forEach( name => {
keys( statement.defines ).forEach( name => {
if ( has( definers, name ) ) {

@@ -105,3 +110,3 @@ conflicts[ name ] = true;

// per module... but some people write bad js
definers[ name ].push( statement._module );
definers[ name ].push( statement.module );
});

@@ -159,6 +164,6 @@ });

keys( statement._dependsOn )
.concat( keys( statement._defines ) )
keys( statement.dependsOn )
.concat( keys( statement.defines ) )
.forEach( name => {
const canonicalName = statement._module.getCanonicalName( name );
const canonicalName = statement.module.getCanonicalName( name );

@@ -170,8 +175,8 @@ if ( name !== canonicalName ) {

const source = statement._source.clone().trim();
const source = statement.replaceIdentifiers( replacements );
// modify exports as necessary
if ( /^Export/.test( statement.type ) ) {
if ( statement.isExportDeclaration ) {
// skip `export { foo, bar, baz }`
if ( statement.type === 'ExportNamedDeclaration' && statement.specifiers.length ) {
if ( statement.node.type === 'ExportNamedDeclaration' && statement.node.specifiers.length ) {
return;

@@ -181,4 +186,4 @@ }

// remove `export` from `export var foo = 42`
if ( statement.type === 'ExportNamedDeclaration' && statement.declaration.type === 'VariableDeclaration' ) {
source.remove( statement.start, statement.declaration.start );
if ( statement.node.type === 'ExportNamedDeclaration' && statement.node.declaration.type === 'VariableDeclaration' ) {
source.remove( statement.node.start, statement.node.declaration.start );
}

@@ -188,15 +193,15 @@

// TODO default exports need different treatment
else if ( statement.declaration.id ) {
source.remove( statement.start, statement.declaration.start );
else if ( statement.node.declaration.id ) {
source.remove( statement.node.start, statement.node.declaration.start );
}
else if ( statement.type === 'ExportDefaultDeclaration' ) {
const module = statement._module;
else if ( statement.node.type === 'ExportDefaultDeclaration' ) {
const module = statement.module;
const canonicalName = module.getCanonicalName( 'default' );
if ( statement.declaration.type === 'Identifier' && canonicalName === module.getCanonicalName( statement.declaration.name ) ) {
if ( statement.node.declaration.type === 'Identifier' && canonicalName === module.getCanonicalName( statement.node.declaration.name ) ) {
return;
}
source.overwrite( statement.start, statement.declaration.start, `var ${canonicalName} = ` );
source.overwrite( statement.node.start, statement.node.declaration.start, `var ${canonicalName} = ` );
}

@@ -209,7 +214,5 @@

replaceIdentifiers( statement, source, replacements );
// add leading comments
if ( statement._leadingComments.length ) {
const commentBlock = statement._leadingComments.map( comment => {
if ( statement.leadingComments.length ) {
const commentBlock = statement.leadingComments.map( comment => {
return comment.block ?

@@ -224,3 +227,3 @@ `/*${comment.text}*/` :

// add margin
const margin = Math.max( statement._margin[0], previousMargin );
const margin = Math.max( statement.margin[0], previousMargin );
const newLines = new Array( margin ).join( '\n' );

@@ -235,3 +238,3 @@

// add trailing comments
const comment = statement._trailingComment;
const comment = statement.trailingComment;
if ( comment ) {

@@ -245,3 +248,3 @@ const commentBlock = comment.block ?

previousMargin = statement._margin[1];
previousMargin = statement.margin[1];
});

@@ -248,0 +251,0 @@

@@ -1,2 +0,2 @@

export default function es6 ( bundle, magicString, exportMode, options ) {
export default function iife ( bundle, magicString, exportMode, options ) {

@@ -3,0 +3,0 @@ const intro = `(function () { 'use strict';\n\n`;

@@ -5,5 +5,7 @@ import { relative } from 'path';

import MagicString from 'magic-string';
import Statement from './Statement';
import analyse from './ast/analyse';
import { has, keys } from './utils/object';
import { sequence } from './utils/promise';
import { isImportDeclaration, isExportDeclaration } from './utils/map-helpers';
import getLocation from './utils/getLocation';

@@ -15,3 +17,5 @@ import makeLegalIdentifier from './utils/makeLegalIdentifier';

export default class Module {
constructor ({ path, code, bundle }) {
constructor ({ path, source, bundle }) {
this.source = source;
this.bundle = bundle;

@@ -21,3 +25,3 @@ this.path = path;

this.code = new MagicString( code, {
this.magicString = new MagicString( source, {
filename: path

@@ -29,4 +33,6 @@ });

// Try to extract a list of top-level statements/declarations. If
// the parse fails, attach file info and abort
try {
this.ast = parse( code, {
const ast = parse( source, {
ecmaVersion: 6,

@@ -36,2 +42,7 @@ sourceType: 'module',

});
this.statements = ast.body.map( node => {
const magicString = this.magicString.snip( node.start, node.end );
return new Statement( node, magicString, this );
});
} catch ( err ) {

@@ -42,2 +53,5 @@ err.file = path;

this.importDeclarations = this.statements.filter( isImportDeclaration );
this.exportDeclarations = this.statements.filter( isExportDeclaration );
this.analyse();

@@ -51,94 +65,90 @@ }

this.ast.body.forEach( node => {
let source;
this.importDeclarations.forEach( statement => {
const node = statement.node;
const source = node.source.value;
// import foo from './foo';
// import { bar } from './bar';
if ( node.type === 'ImportDeclaration' ) {
source = node.source.value;
node.specifiers.forEach( specifier => {
const isDefault = specifier.type === 'ImportDefaultSpecifier';
const isNamespace = specifier.type === 'ImportNamespaceSpecifier';
node.specifiers.forEach( specifier => {
const isDefault = specifier.type === 'ImportDefaultSpecifier';
const isNamespace = specifier.type === 'ImportNamespaceSpecifier';
const localName = specifier.local.name;
const name = isDefault ? 'default' : isNamespace ? '*' : specifier.imported.name;
const localName = specifier.local.name;
const name = isDefault ? 'default' : isNamespace ? '*' : specifier.imported.name;
if ( has( this.imports, localName ) ) {
const err = new Error( `Duplicated import '${localName}'` );
err.file = this.path;
err.loc = getLocation( this.source, specifier.start );
throw err;
}
if ( has( this.imports, localName ) ) {
const err = new Error( `Duplicated import '${localName}'` );
err.file = this.path;
err.loc = getLocation( this.code.original, specifier.start );
throw err;
}
this.imports[ localName ] = {
source,
name,
localName
};
});
});
this.imports[ localName ] = {
source,
name,
localName
};
});
}
this.exportDeclarations.forEach( statement => {
const node = statement.node;
const source = node.source && node.source.value;
else if ( /^Export/.test( node.type ) ) {
// export default function foo () {}
// export default foo;
// export default 42;
if ( node.type === 'ExportDefaultDeclaration' ) {
const isDeclaration = /Declaration$/.test( node.declaration.type );
// export default function foo () {}
// export default foo;
// export default 42;
if ( node.type === 'ExportDefaultDeclaration' ) {
const isDeclaration = /Declaration$/.test( node.declaration.type );
this.exports.default = {
node,
name: 'default',
localName: isDeclaration ? node.declaration.id.name : 'default',
isDeclaration
};
}
this.exports.default = {
statement,
name: 'default',
localName: isDeclaration ? node.declaration.id.name : 'default',
isDeclaration
};
}
// export { foo, bar, baz }
// export var foo = 42;
// export function foo () {}
else if ( node.type === 'ExportNamedDeclaration' ) {
// export { foo } from './foo';
source = node.source && node.source.value;
// export { foo, bar, baz }
// export var foo = 42;
// export function foo () {}
else if ( node.type === 'ExportNamedDeclaration' ) {
if ( node.specifiers.length ) {
// export { foo, bar, baz }
node.specifiers.forEach( specifier => {
const localName = specifier.local.name;
const exportedName = specifier.exported.name;
if ( node.specifiers.length ) {
// export { foo, bar, baz }
node.specifiers.forEach( specifier => {
const localName = specifier.local.name;
const exportedName = specifier.exported.name;
this.exports[ exportedName ] = {
localName,
exportedName
};
this.exports[ exportedName ] = {
// export { foo } from './foo';
if ( source ) {
this.imports[ localName ] = {
source,
localName,
exportedName
name: exportedName
};
}
});
}
if ( source ) {
this.imports[ localName ] = {
source,
localName,
name: exportedName
};
}
});
}
else {
let declaration = node.declaration;
else {
let declaration = node.declaration;
let name;
let name;
if ( declaration.type === 'VariableDeclaration' ) {
// export var foo = 42
name = declaration.declarations[0].id.name;
} else {
// export function foo () {}
name = declaration.id.name;
}
if ( declaration.type === 'VariableDeclaration' ) {
// export var foo = 42
name = declaration.declarations[0].id.name;
} else {
// export function foo () {}
name = declaration.id.name;
}
this.exports[ name ] = {
node,
localName: name,
expression: declaration
};
}
this.exports[ name ] = {
statement,
localName: name,
expression: declaration
};
}

@@ -148,8 +158,4 @@ }

analyse( this.magicString, this );
analyse( this.ast, this.code, this );
this.definedNames = this.ast._scope.names.slice();
this.canonicalNames = {};

@@ -161,8 +167,8 @@

this.ast.body.forEach( statement => {
Object.keys( statement._defines ).forEach( name => {
this.statements.forEach( statement => {
Object.keys( statement.defines ).forEach( name => {
this.definitions[ name ] = statement;
});
Object.keys( statement._modifies ).forEach( name => {
Object.keys( statement.modifies ).forEach( name => {
if ( !has( this.modifications, name ) ) {

@@ -285,12 +291,9 @@ this.modifications[ name ] = [];

if ( name === 'default' ) {
// TODO can we use this.definitions[ name ], as below?
statement = this.exports.default.node;
}
else {
statement = this.exports.default.statement;
} else {
statement = this.definitions[ name ];
}
if ( statement && !statement._included ) {
promise = this.expandStatement( statement );
if ( statement && !statement.isIncluded ) {
promise = statement.expand();
}

@@ -303,63 +306,27 @@ }

expandStatement ( statement ) {
if ( statement._included ) return emptyArrayPromise;
statement._included = true;
let result = [];
// We have a statement, and it hasn't been included yet. First, include
// the statements it depends on
const dependencies = Object.keys( statement._dependsOn );
return sequence( dependencies, name => {
return this.define( name ).then( definition => {
result.push.apply( result, definition );
});
})
// then include the statement itself
.then( () => {
result.push( statement );
})
// then include any statements that could modify the
// thing(s) this statement defines
.then( () => {
return sequence( keys( statement._defines ), name => {
const modifications = has( this.modifications, name ) && this.modifications[ name ];
if ( modifications ) {
return sequence( modifications, statement => {
if ( !statement._included ) {
return this.expandStatement( statement )
.then( statements => {
result.push.apply( result, statements );
});
}
});
}
});
})
// the `result` is an array of statements needed to define `name`
.then( () => {
return result;
});
}
expandAllStatements ( isEntryModule ) {
let allStatements = [];
return sequence( this.ast.body, statement => {
// skip already-included statements
if ( statement._included ) return;
return sequence( this.statements, statement => {
// A statement may have already been included, in which case we need to
// curb rollup's enthusiasm and move it down here. It remains to be seen
// if this approach is bulletproof
if ( statement.isIncluded ) {
const index = allStatements.indexOf( statement );
if ( ~index ) {
allStatements.splice( index, 1 );
allStatements.push( statement );
}
// skip import declarations
if ( statement.type === 'ImportDeclaration' ) {
// unless they're empty, in which case assume we're importing them for the side-effects
return;
}
// skip import declarations...
if ( statement.isImportDeclaration ) {
// ...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.specifiers.length ) {
return this.bundle.fetchModule( statement.source.value, this.path )
if ( !statement.node.specifiers.length ) {
return this.bundle.fetchModule( statement.node.source.value, this.path )
.then( module => {
statement.module = module;
statement.module = module; // TODO what is this for? what does it do? why not _module?
return module.expandAllStatements();

@@ -375,10 +342,9 @@ })

// skip `export { foo, bar, baz }`
if ( statement.type === 'ExportNamedDeclaration' && statement.specifiers.length ) {
// but ensure they are defined, if this is the entry module
// skip `export { foo, bar, baz }`...
if ( statement.node.type === 'ExportNamedDeclaration' && statement.node.specifiers.length ) {
// ...but ensure they are defined, if this is the entry module
if ( isEntryModule ) {
return this.expandStatement( statement )
.then( statements => {
allStatements.push.apply( allStatements, statements );
});
return statement.expand().then( statements => {
allStatements.push.apply( allStatements, statements );
});
}

@@ -390,6 +356,5 @@

// include everything else
return this.expandStatement( statement )
.then( statements => {
allStatements.push.apply( allStatements, statements );
});
return statement.expand().then( statements => {
allStatements.push.apply( allStatements, statements );
});
}).then( () => {

@@ -396,0 +361,0 @@ return allStatements;

@@ -12,1 +12,9 @@ export function getName ( x ) {

}
export function isImportDeclaration ( statement ) {
return statement.isImportDeclaration;
}
export function isExportDeclaration ( statement ) {
return statement.isExportDeclaration;
}

Sorry, the diff of this file is not supported yet

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