UNPKG

66.6 kBJavaScriptView Raw
1'use strict';
2
3function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
4
5var sander = require('sander');
6var MagicString = require('magic-string');
7MagicString = 'default' in MagicString ? MagicString['default'] : MagicString;
8var acorn = require('acorn');
9
10// TODO does this all work on windows?
11
12var absolutePath = /^(?:\/|(?:[A-Za-z]:)?\\)/;
13
14function isAbsolute(path) {
15 return absolutePath.test(path);
16}
17
18function basename(path) {
19 return path.split(/(\/|\\)/).pop();
20}
21
22function dirname(path) {
23 var match = /(\/|\\)[^\/\\]*$/.exec(path);
24 if (!match) return '.';
25
26 var dir = path.slice(0, -match[0].length);
27
28 // If `dir` is the empty string, we're at root.
29 return dir ? dir : '/';
30}
31
32function extname(path) {
33 var match = /\.[^\.]+$/.exec(path);
34 if (!match) return '';
35 return match[0];
36}
37
38function resolve() {
39 for (var _len = arguments.length, paths = Array(_len), _key = 0; _key < _len; _key++) {
40 paths[_key] = arguments[_key];
41 }
42
43 var resolvedParts = paths.shift().split(/[\/\\]/);
44
45 paths.forEach(function (path) {
46 if (isAbsolute(path)) {
47 resolvedParts = path.split(/[\/\\]/);
48 } else {
49 var parts = path.split(/[\/\\]/);
50
51 while (parts[0] && parts[0][0] === '.') {
52 var part = parts.shift();
53 if (part === '..') {
54 resolvedParts.pop();
55 } else if (part !== '.') {
56 throw new Error('Unexpected path part (' + part + ')');
57 }
58 }
59
60 resolvedParts.push.apply(resolvedParts, parts);
61 }
62 });
63
64 return resolvedParts.join('/'); // TODO windows...
65}
66
67var keys = Object.keys;
68
69function blank() {
70 return Object.create(null);
71}
72
73function unixizePath(path) {
74 return path.split(/[\/\\]/).join('/');
75}
76
77function getIndentString(magicString, options) {
78 if (!('indent' in options) || options.indent === true) {
79 return magicString.getIndentString();
80 }
81
82 return options.indent || '';
83}
84
85function badExports(option, keys) {
86 throw new Error('\'' + option + '\' was specified for options.exports, but entry module has following exports: ' + keys.join(', '));
87}
88
89function getExportMode(bundle, exportMode) {
90 var exportKeys = keys(bundle.entryModule.exports);
91
92 if (exportMode === 'default') {
93 if (exportKeys.length !== 1 || exportKeys[0] !== 'default') {
94 badExports('default', exportKeys);
95 }
96 } else if (exportMode === 'none' && exportKeys.length) {
97 badExports('none', exportKeys);
98 }
99
100 if (!exportMode || exportMode === 'auto') {
101 if (exportKeys.length === 0) {
102 exportMode = 'none';
103 } else if (exportKeys.length === 1 && exportKeys[0] === 'default') {
104 exportMode = 'default';
105 } else {
106 exportMode = 'named';
107 }
108 }
109
110 if (!/(?:default|named|none)/.test(exportMode)) {
111 throw new Error('options.exports must be \'default\', \'named\', \'none\', \'auto\', or left unspecified (defaults to \'auto\')');
112 }
113
114 return exportMode;
115}
116
117function getInteropBlock(bundle) {
118 return bundle.externalModules.filter(function (module) {
119 return module.needsDefault && module.needsNamed;
120 }).map(function (module) {
121 return 'var ' + module.name + '__default = \'default\' in ' + module.name + ' ? ' + module.name + '[\'default\'] : ' + module.name + ';';
122 }).join('\n');
123}
124
125function getName(x) {
126 return x.name;
127}
128
129function quoteId(x) {
130 return '\'' + x.id + '\'';
131}
132
133function req(x) {
134 return 'require(\'' + x.id + '\')';
135}
136
137function umd(bundle, magicString, _ref, options) {
138 var exportMode = _ref.exportMode;
139 var indentString = _ref.indentString;
140
141 if (exportMode !== 'none' && !options.moduleName) {
142 throw new Error('You must supply options.moduleName for UMD bundles');
143 }
144
145 var globalNames = options.globals || blank();
146
147 var amdDeps = bundle.externalModules.map(quoteId);
148 var cjsDeps = bundle.externalModules.map(req);
149 var globalDeps = bundle.externalModules.map(function (module) {
150 return 'global.' + (globalNames[module.id] || module.name);
151 });
152
153 var args = bundle.externalModules.map(getName);
154
155 if (exportMode === 'named') {
156 amdDeps.unshift('\'exports\'');
157 cjsDeps.unshift('exports');
158 globalDeps.unshift('(global.' + options.moduleName + ' = {})');
159
160 args.unshift('exports');
161 }
162
163 var amdParams = (options.moduleId ? '[\'' + options.moduleId + '\'], ' : '') + (amdDeps.length ? '[' + amdDeps.join(', ') + '], ' : '');
164
165 var cjsExport = exportMode === 'default' ? 'module.exports = ' : '';
166 var defaultExport = exportMode === 'default' ? 'global.' + options.moduleName + ' = ' : '';
167
168 var intro = ('(function (global, factory) {\n\t\t\ttypeof exports === \'object\' && typeof module !== \'undefined\' ? ' + cjsExport + 'factory(' + cjsDeps.join(', ') + ') :\n\t\t\ttypeof define === \'function\' && define.amd ? define(' + amdParams + 'factory) :\n\t\t\t' + defaultExport + 'factory(' + globalDeps + ');\n\t\t}(this, function (' + args + ') { \'use strict\';\n\n\t\t').replace(/^\t\t/gm, '').replace(/^\t/gm, magicString.getIndentString());
169
170 // var foo__default = 'default' in foo ? foo['default'] : foo;
171 var interopBlock = getInteropBlock(bundle);
172 if (interopBlock) magicString.prepend(interopBlock + '\n\n');
173
174 var exports = bundle.entryModule.exports;
175
176 var exportBlock = undefined;
177
178 if (exportMode === 'default') {
179 var canonicalName = bundle.entryModule.getCanonicalName('default');
180 exportBlock = 'return ' + canonicalName + ';';
181 } else {
182 exportBlock = bundle.toExport.map(function (name) {
183 var canonicalName = bundle.entryModule.getCanonicalName(exports[name].localName);
184 return 'exports.' + name + ' = ' + canonicalName + ';';
185 }).join('\n');
186 }
187
188 if (exportBlock) {
189 magicString.append('\n\n' + exportBlock);
190 }
191
192 return magicString.trim().indent(indentString).append('\n\n}));').prepend(intro);
193}
194
195function iife(bundle, magicString, _ref2, options) {
196 var exportMode = _ref2.exportMode;
197 var indentString = _ref2.indentString;
198
199 var globalNames = options.globals || blank();
200
201 var dependencies = bundle.externalModules.map(function (module) {
202 return globalNames[module.id] || module.name;
203 });
204
205 var args = bundle.externalModules.map(getName);
206
207 if (exportMode !== 'none' && !options.moduleName) {
208 throw new Error('You must supply options.moduleName for IIFE bundles');
209 }
210
211 if (exportMode === 'named') {
212 dependencies.unshift('(this.' + options.moduleName + ' = {})');
213 args.unshift('exports');
214 }
215
216 var intro = '(function (' + args + ') { \'use strict\';\n\n';
217 var outro = '\n\n})(' + dependencies + ');';
218
219 // var foo__default = 'default' in foo ? foo['default'] : foo;
220 var interopBlock = getInteropBlock(bundle);
221 if (interopBlock) magicString.prepend(interopBlock + '\n\n');
222
223 if (exportMode === 'default') {
224 intro = 'var ' + options.moduleName + ' = ' + intro;
225 magicString.append('\n\nreturn ' + bundle.entryModule.getCanonicalName('default') + ';');
226 }
227
228 // TODO named exports
229
230 return magicString.indent(indentString).prepend(intro).append(outro);
231}
232
233function es6(bundle, magicString, _ref3, options) {
234 var exportMode = _ref3.exportMode;
235
236 var importBlock = bundle.externalModules.map(function (module) {
237 var specifiers = [];
238
239 if (module.needsDefault) {
240 specifiers.push(module.importedByBundle.filter(function (declaration) {
241 return declaration.name === 'default';
242 })[0].localName);
243 }
244
245 if (module.needsAll) {
246 specifiers.push('* as ' + module.importedByBundle.filter(function (declaration) {
247 return declaration.name === '*';
248 })[0].localName);
249 }
250
251 if (module.needsNamed) {
252 specifiers.push('{ ' + module.importedByBundle.filter(function (declaration) {
253 return !/^(default|\*)$/.test(declaration.name);
254 }).map(function (_ref4) {
255 var name = _ref4.name;
256 var localName = _ref4.localName;
257 return name === localName ? name : name + ' as ' + localName;
258 }).join(', ') + ' }');
259 }
260
261 return specifiers.length ? 'import ' + specifiers.join(', ') + ' from \'' + module.id + '\';' : 'import \'' + module.id + '\';';
262 }).join('\n');
263
264 if (importBlock) {
265 magicString.prepend(importBlock + '\n\n');
266 }
267
268 var exports = bundle.entryModule.exports;
269 var exportBlock = keys(exports).map(function (exportedName) {
270 var specifier = exports[exportedName];
271
272 var canonicalName = bundle.entryModule.getCanonicalName(specifier.localName);
273
274 if (exportedName === 'default') {
275 return 'export default ' + canonicalName + ';';
276 }
277
278 return exportedName === canonicalName ? 'export { ' + exportedName + ' };' : 'export { ' + canonicalName + ' as ' + exportedName + ' };';
279 }).join('\n');
280
281 if (exportBlock) {
282 magicString.append('\n\n' + exportBlock);
283 }
284
285 return magicString.trim();
286}
287
288function cjs(bundle, magicString, _ref5) {
289 var exportMode = _ref5.exportMode;
290
291 var intro = '\'use strict\';\n\n';
292
293 // TODO handle empty imports, once they're supported
294 var importBlock = bundle.externalModules.map(function (module) {
295 var requireStatement = 'var ' + module.name + ' = require(\'' + module.id + '\');';
296
297 if (module.needsDefault) {
298 requireStatement += '\n' + (module.needsNamed ? 'var ' + module.name + '__default = ' : module.name + ' = ') + ('\'default\' in ' + module.name + ' ? ' + module.name + '[\'default\'] : ' + module.name + ';');
299 }
300
301 return requireStatement;
302 }).join('\n');
303
304 if (importBlock) {
305 intro += importBlock + '\n\n';
306 }
307
308 magicString.prepend(intro);
309
310 var exportBlock = undefined;
311 if (exportMode === 'default' && bundle.entryModule.exports.default) {
312 exportBlock = 'module.exports = ' + bundle.entryModule.getCanonicalName('default') + ';';
313 } else if (exportMode === 'named') {
314 exportBlock = bundle.toExport.map(function (key) {
315 var specifier = bundle.entryModule.exports[key];
316 var name = bundle.entryModule.getCanonicalName(specifier.localName);
317
318 return 'exports.' + key + ' = ' + name + ';';
319 }).join('\n');
320 }
321
322 if (exportBlock) {
323 magicString.append('\n\n' + exportBlock);
324 }
325
326 return magicString;
327}
328
329function amd(bundle, magicString, _ref6, options) {
330 var exportMode = _ref6.exportMode;
331 var indentString = _ref6.indentString;
332
333 var deps = bundle.externalModules.map(quoteId);
334 var args = bundle.externalModules.map(getName);
335
336 if (exportMode === 'named') {
337 args.unshift('exports');
338 deps.unshift('\'exports\'');
339 }
340
341 var params = (options.moduleId ? '[\'' + options.moduleId + '\'], ' : '') + (deps.length ? '[' + deps.join(', ') + '], ' : '');
342
343 var intro = 'define(' + params + 'function (' + args.join(', ') + ') { \'use strict\';\n\n';
344
345 // var foo__default = 'default' in foo ? foo['default'] : foo;
346 var interopBlock = getInteropBlock(bundle);
347 if (interopBlock) magicString.prepend(interopBlock + '\n\n');
348
349 var exports = bundle.entryModule.exports;
350
351 var exportBlock = undefined;
352
353 if (exportMode === 'default') {
354 exportBlock = 'return ' + bundle.entryModule.getCanonicalName('default') + ';';
355 } else {
356 exportBlock = bundle.toExport.map(function (name) {
357 return 'exports.' + name + ' = ' + exports[name].localName + ';';
358 }).join('\n');
359 }
360
361 if (exportBlock) magicString.append('\n\n' + exportBlock);
362
363 return magicString.indent(indentString).append('\n\n});').prepend(intro);
364}
365
366var finalisers = { amd: amd, cjs: cjs, es6: es6, iife: iife, umd: umd };
367
368var 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(' ');
369var 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(' ');
370
371var blacklisted = blank();
372reservedWords.concat(builtins).forEach(function (word) {
373 return blacklisted[word] = true;
374});
375
376function makeLegalIdentifier(str) {
377 str = str.replace(/[^$_a-zA-Z0-9]/g, '_');
378 if (/\d/.test(str[0]) || blacklisted[str]) str = '_' + str;
379
380 return str;
381}
382
383var shouldSkip = undefined;
384var shouldAbort = undefined;
385
386function walk(ast, _ref7) {
387 var enter = _ref7.enter;
388 var leave = _ref7.leave;
389
390 shouldAbort = false;
391 visit(ast, null, enter, leave);
392}
393
394var context = {
395 skip: function () {
396 return shouldSkip = true;
397 },
398 abort: function () {
399 return shouldAbort = true;
400 }
401};
402
403var childKeys = blank();
404
405var toString = Object.prototype.toString;
406
407function isArray(thing) {
408 return toString.call(thing) === '[object Array]';
409}
410
411function visit(node, parent, enter, leave) {
412 if (!node || shouldAbort) return;
413
414 if (enter) {
415 shouldSkip = false;
416 enter.call(context, node, parent);
417 if (shouldSkip || shouldAbort) return;
418 }
419
420 var keys = childKeys[node.type] || (childKeys[node.type] = Object.keys(node).filter(function (key) {
421 return typeof node[key] === 'object';
422 }));
423
424 var key = undefined,
425 value = undefined,
426 i = undefined,
427 j = undefined;
428
429 i = keys.length;
430 while (i--) {
431 key = keys[i];
432 value = node[key];
433
434 if (isArray(value)) {
435 j = value.length;
436 while (j--) {
437 visit(value[j], node, enter, leave);
438 }
439 } else if (value && value.type) {
440 visit(value, node, enter, leave);
441 }
442 }
443
444 if (leave && !shouldAbort) {
445 leave(node, parent);
446 }
447}
448
449function sequence(arr, callback) {
450 var len = arr.length;
451 var results = new Array(len);
452
453 var promise = sander.Promise.resolve();
454
455 function next(i) {
456 return promise.then(function () {
457 return callback(arr[i], i);
458 }).then(function (result) {
459 return results[i] = result;
460 });
461 }
462
463 var i = undefined;
464
465 for (i = 0; i < len; i += 1) {
466 promise = next(i);
467 }
468
469 return promise.then(function () {
470 return results;
471 });
472}
473
474function first(arr, fail, callback) {
475 var len = arr.length;
476
477 var promise = sander.Promise.reject(fail);
478
479 function next(i) {
480 return promise.catch(function () {
481 return callback(arr[i], i);
482 });
483 }
484
485 var i = undefined;
486
487 for (i = 0; i < len; i += 1) {
488 promise = next(i);
489 }
490
491 return promise;
492}
493
494function getLocation(source, charIndex) {
495 var lines = source.split('\n');
496 var len = lines.length;
497
498 var lineStart = 0;
499 var i = undefined;
500
501 for (i = 0; i < len; i += 1) {
502 var line = lines[i];
503 var lineEnd = lineStart + line.length + 1; // +1 for newline
504
505 if (lineEnd > charIndex) {
506 return { line: i + 1, column: charIndex - lineStart };
507 }
508
509 lineStart = lineEnd;
510 }
511
512 throw new Error('Could not determine location of character');
513}
514
515var blockDeclarations = {
516 'const': true,
517 'let': true
518};
519
520var Scope = (function () {
521 function Scope(options) {
522 var _this = this;
523
524 _classCallCheck(this, Scope);
525
526 options = options || {};
527
528 this.parent = options.parent;
529 this.depth = this.parent ? this.parent.depth + 1 : 0;
530 this.declarations = blank();
531 this.isBlockScope = !!options.block;
532
533 if (options.params) {
534 options.params.forEach(function (param) {
535 _this.declarations[param.name] = param;
536 });
537 }
538 }
539
540 // add ( name, isBlockDeclaration ) {
541 // if ( !isBlockDeclaration && this.isBlockScope ) {
542 // // it's a `var` or function declaration, and this
543 // // is a block scope, so we need to go up
544 // this.parent.add( name, isBlockDeclaration );
545 // } else {
546 // this.names.push( name );
547 // }
548 // }
549
550 Scope.prototype.addDeclaration = function addDeclaration(name, declaration) {
551 var isBlockDeclaration = declaration.type === 'VariableDeclaration' && blockDeclarations[declaration.kind];
552
553 if (!isBlockDeclaration && this.isBlockScope) {
554 // it's a `var` or function declaration, and this
555 // is a block scope, so we need to go up
556 this.parent.addDeclaration(name, declaration);
557 } else {
558 this.declarations[name] = declaration;
559 }
560 };
561
562 Scope.prototype.contains = function contains(name) {
563 return !!this.getDeclaration(name);
564 };
565
566 Scope.prototype.findDefiningScope = function findDefiningScope(name) {
567 if (!!this.declarations[name]) {
568 return this;
569 }
570
571 if (this.parent) {
572 return this.parent.findDefiningScope(name);
573 }
574
575 return null;
576 };
577
578 Scope.prototype.getDeclaration = function getDeclaration(name) {
579 return this.declarations[name] || this.parent && this.parent.getDeclaration(name);
580 };
581
582 return Scope;
583})();
584
585function isIife(node, parent) {
586 return parent && parent.type === 'CallExpression' && node === parent.callee;
587}
588
589var Statement = (function () {
590 function Statement(node, module, start, end) {
591 _classCallCheck(this, Statement);
592
593 this.node = node;
594 this.module = module;
595 this.start = start;
596 this.end = end;
597 this.next = null; // filled in later
598
599 this.scope = new Scope();
600 this.defines = blank();
601 this.modifies = blank();
602 this.dependsOn = blank();
603 this.stronglyDependsOn = blank();
604
605 this.isIncluded = false;
606
607 this.isImportDeclaration = node.type === 'ImportDeclaration';
608 this.isExportDeclaration = /^Export/.test(node.type);
609 }
610
611 Statement.prototype.analyse = function analyse() {
612 var _this2 = this;
613
614 if (this.isImportDeclaration) return; // nothing to analyse
615
616 var scope = this.scope;
617
618 walk(this.node, {
619 enter: function (node, parent) {
620 var newScope = undefined;
621
622 switch (node.type) {
623 case 'FunctionExpression':
624 case 'FunctionDeclaration':
625 case 'ArrowFunctionExpression':
626 if (node.type === 'FunctionDeclaration') {
627 scope.addDeclaration(node.id.name, node);
628 }
629
630 newScope = new Scope({
631 parent: scope,
632 params: node.params, // TODO rest params?
633 block: false
634 });
635
636 // named function expressions - the name is considered
637 // part of the function's scope
638 if (node.type === 'FunctionExpression' && node.id) {
639 newScope.addDeclaration(node.id.name, node);
640 }
641
642 break;
643
644 case 'BlockStatement':
645 if (!/Function/.test(parent.type)) {
646 newScope = new Scope({
647 parent: scope,
648 block: true
649 });
650 }
651
652 break;
653
654 case 'CatchClause':
655 newScope = new Scope({
656 parent: scope,
657 params: [node.param],
658 block: true
659 });
660
661 break;
662
663 case 'VariableDeclaration':
664 node.declarations.forEach(function (declarator) {
665 scope.addDeclaration(declarator.id.name, node);
666 });
667 break;
668
669 case 'ClassDeclaration':
670 scope.addDeclaration(node.id.name, node);
671 break;
672 }
673
674 if (newScope) {
675 Object.defineProperty(node, '_scope', { value: newScope });
676 scope = newScope;
677 }
678 },
679 leave: function (node) {
680 if (node._scope) {
681 scope = scope.parent;
682 }
683 }
684 });
685
686 // This allows us to track whether we're looking at code that will
687 // be executed immediately (either outside a function, or immediately
688 // inside an IIFE), for the purposes of determining whether dependencies
689 // are strong or weak. It's not bulletproof, since it wouldn't catch...
690 //
691 // var calledImmediately = function () {
692 // doSomethingWith( strongDependency );
693 // }
694 // calledImmediately();
695 //
696 // ...but it's better than nothing
697 var depth = 0;
698
699 if (!this.isImportDeclaration) {
700 walk(this.node, {
701 enter: function (node, parent) {
702 if (node._scope) {
703 if (!scope.isBlockScope && !isIife(node, parent)) depth += 1;
704 scope = node._scope;
705 }
706
707 _this2.checkForReads(scope, node, parent, !depth);
708 _this2.checkForWrites(scope, node);
709 },
710 leave: function (node, parent) {
711 if (node._scope) {
712 if (!scope.isBlockScope && !isIife(node, parent)) depth -= 1;
713 scope = scope.parent;
714 }
715 }
716 });
717 }
718
719 keys(scope.declarations).forEach(function (name) {
720 _this2.defines[name] = true;
721 });
722 };
723
724 Statement.prototype.checkForReads = function checkForReads(scope, node, parent, strong) {
725 if (node.type === 'Identifier') {
726 // disregard the `bar` in `foo.bar` - these appear as Identifier nodes
727 if (parent.type === 'MemberExpression' && !parent.computed && node !== parent.object) {
728 return;
729 }
730
731 // disregard the `bar` in { bar: foo }
732 if (parent.type === 'Property' && node !== parent.value) {
733 return;
734 }
735
736 // disregard the `bar` in `class Foo { bar () {...} }`
737 if (parent.type === 'MethodDefinition') return;
738
739 var definingScope = scope.findDefiningScope(node.name);
740
741 if ((!definingScope || definingScope.depth === 0) && !this.defines[node.name]) {
742 this.dependsOn[node.name] = true;
743 if (strong) this.stronglyDependsOn[node.name] = true;
744 }
745 }
746 };
747
748 Statement.prototype.checkForWrites = function checkForWrites(scope, node) {
749 var _this3 = this;
750
751 var addNode = function (node, isAssignment) {
752 var depth = 0; // determine whether we're illegally modifying a binding or namespace
753
754 while (node.type === 'MemberExpression') {
755 node = node.object;
756 depth += 1;
757 }
758
759 // disallow assignments/updates to imported bindings and namespaces
760 if (isAssignment) {
761 var importSpecifier = _this3.module.imports[node.name];
762
763 if (importSpecifier && !scope.contains(node.name)) {
764 var minDepth = importSpecifier.name === '*' ? 2 : // cannot do e.g. `namespace.foo = bar`
765 1; // cannot do e.g. `foo = bar`, but `foo.bar = bar` is fine
766
767 if (depth < minDepth) {
768 var err = new Error('Illegal reassignment to import \'' + node.name + '\'');
769 err.file = _this3.module.id;
770 err.loc = getLocation(_this3.module.magicString.toString(), node.start);
771 throw err;
772 }
773 }
774
775 // special case = `export default foo; foo += 1;` - we'll
776 // need to assign a new variable so that the exported
777 // value is not updated by the second statement
778 if (_this3.module.exports.default && depth === 0 && _this3.module.exports.default.identifier === node.name) {
779 // but only if this is a) inside a function body or
780 // b) after the export declaration
781 if (!!scope.parent || node.start > _this3.module.exports.default.statement.node.start) {
782 _this3.module.exports.default.isModified = true;
783 }
784 }
785 }
786
787 if (node.type === 'Identifier') {
788 _this3.modifies[node.name] = true;
789 }
790 };
791
792 if (node.type === 'AssignmentExpression') {
793 addNode(node.left, true);
794 } else if (node.type === 'UpdateExpression') {
795 addNode(node.argument, true);
796 } else if (node.type === 'CallExpression') {
797 node.arguments.forEach(function (arg) {
798 return addNode(arg, false);
799 });
800
801 // `foo.bar()` is assumed to mutate foo
802 if (node.callee.type === 'MemberExpression') {
803 addNode(node.callee);
804 }
805 }
806 };
807
808 Statement.prototype.mark = function mark() {
809 var _this4 = this;
810
811 if (this.isIncluded) return; // prevent infinite loops
812 this.isIncluded = true;
813
814 var dependencies = Object.keys(this.dependsOn);
815
816 return sequence(dependencies, function (name) {
817 if (_this4.defines[name]) return; // TODO maybe exclude from `this.dependsOn` in the first place?
818 return _this4.module.mark(name);
819 });
820 };
821
822 Statement.prototype.replaceIdentifiers = function replaceIdentifiers(magicString, names, bundleExports) {
823 var replacementStack = [names];
824 var nameList = keys(names);
825
826 var deshadowList = [];
827 nameList.forEach(function (name) {
828 var replacement = names[name];
829 deshadowList.push(replacement.split('.')[0]);
830 });
831
832 var topLevel = true;
833 var depth = 0;
834
835 walk(this.node, {
836 enter: function (node, parent) {
837 var _this5 = this;
838
839 if (node._skip) return this.skip();
840
841 if (/^Function/.test(node.type)) depth += 1;
842
843 // `this` is undefined at the top level of ES6 modules
844 if (node.type === 'ThisExpression' && depth === 0) {
845 magicString.overwrite(node.start, node.end, 'undefined');
846 }
847
848 // special case - variable declarations that need to be rewritten
849 // as bundle exports
850 if (topLevel) {
851 if (node.type === 'VariableDeclaration') {
852 // if this contains a single declarator, and it's one that
853 // needs to be rewritten, we replace the whole lot
854 var _name = node.declarations[0].id.name;
855 if (node.declarations.length === 1 && bundleExports[_name]) {
856 magicString.overwrite(node.start, node.declarations[0].id.end, bundleExports[_name]);
857 node.declarations[0].id._skip = true;
858 }
859
860 // otherwise, we insert the `exports.foo = foo` after the declaration
861 else {
862 var exportInitialisers = node.declarations.map(function (declarator) {
863 return declarator.id.name;
864 }).filter(function (name) {
865 return !!bundleExports[name];
866 }).map(function (name) {
867 return '\n' + bundleExports[name] + ' = ' + name + ';';
868 }).join('');
869
870 if (exportInitialisers) {
871 // TODO clean this up
872 try {
873 magicString.insert(node.end, exportInitialisers);
874 } catch (err) {
875 magicString.append(exportInitialisers);
876 }
877 }
878 }
879 }
880 }
881
882 var scope = node._scope;
883
884 if (scope) {
885 var _ret = (function () {
886 topLevel = false;
887
888 var newNames = blank();
889 var hasReplacements = undefined;
890
891 // special case = function foo ( foo ) {...}
892 if (node.id && names[node.id.name] && scope.declarations[node.id.name]) {
893 magicString.overwrite(node.id.start, node.id.end, names[node.id.name]);
894 }
895
896 keys(names).forEach(function (name) {
897 if (!scope.declarations[name]) {
898 newNames[name] = names[name];
899 hasReplacements = true;
900 }
901 });
902
903 deshadowList.forEach(function (name) {
904 if (~scope.declarations[name]) {
905 // TODO is this right? no indexOf?
906 newNames[name] = name + '$$'; // TODO better mechanism
907 hasReplacements = true;
908 }
909 });
910
911 if (!hasReplacements && depth > 0) {
912 return {
913 v: _this5.skip()
914 };
915 }
916
917 names = newNames;
918 replacementStack.push(newNames);
919 })();
920
921 if (typeof _ret === 'object') return _ret.v;
922 }
923
924 if (node.type !== 'Identifier') return;
925
926 // if there's no replacement, or it's the same, there's nothing more to do
927 var name = names[node.name];
928 if (!name || name === node.name) return;
929
930 // shorthand properties (`obj = { foo }`) need to be expanded
931 if (parent.type === 'Property' && parent.shorthand) {
932 magicString.insert(node.end, ': ' + name);
933 parent.key._skip = true;
934 parent.value._skip = true; // redundant, but defensive
935 return;
936 }
937
938 // property names etc can be disregarded
939 if (parent.type === 'MemberExpression' && !parent.computed && node !== parent.object) return;
940 if (parent.type === 'Property' && node !== parent.value) return;
941 if (parent.type === 'MethodDefinition' && node === parent.key) return;
942 // TODO others...?
943
944 // all other identifiers should be overwritten
945 magicString.overwrite(node.start, node.end, name);
946 },
947
948 leave: function (node) {
949 if (/^Function/.test(node.type)) depth -= 1;
950
951 if (node._scope) {
952 replacementStack.pop();
953 names = replacementStack[replacementStack.length - 1];
954 }
955 }
956 });
957
958 return magicString;
959 };
960
961 return Statement;
962})();
963
964var emptyArrayPromise = sander.Promise.resolve([]);
965
966function deconflict(name, names) {
967 while (name in names) {
968 name = '_' + name;
969 }
970
971 return name;
972}
973
974function isEmptyExportedVarDeclaration(node, module, allBundleExports, es6) {
975 if (node.type !== 'VariableDeclaration' || node.declarations[0].init) return false;
976
977 var name = node.declarations[0].id.name;
978 var canonicalName = module.getCanonicalName(name, es6);
979
980 return canonicalName in allBundleExports;
981}
982
983var Module = (function () {
984 function Module(_ref8) {
985 var id = _ref8.id;
986 var source = _ref8.source;
987 var bundle = _ref8.bundle;
988
989 _classCallCheck(this, Module);
990
991 this.source = source;
992
993 this.bundle = bundle;
994 this.id = id;
995
996 // By default, `id` is the filename. Custom resolvers and loaders
997 // can change that, but it makes sense to use it for the source filename
998 this.magicString = new MagicString(source, {
999 filename: id
1000 });
1001
1002 this.suggestedNames = blank();
1003 this.comments = [];
1004
1005 this.statements = this._parse();
1006
1007 // imports and exports, indexed by ID
1008 this.imports = blank();
1009 this.exports = blank();
1010
1011 this.exportAlls = blank();
1012
1013 // array of all-export sources
1014 this.exportDelegates = [];
1015
1016 this.canonicalNames = blank();
1017
1018 this.definitions = blank();
1019 this.definitionPromises = blank();
1020 this.modifications = blank();
1021
1022 this.analyse();
1023 }
1024
1025 Module.prototype.addExport = function addExport(statement) {
1026 var _this6 = this;
1027
1028 var node = statement.node;
1029 var source = node.source && node.source.value;
1030
1031 // export default function foo () {}
1032 // export default foo;
1033 // export default 42;
1034 if (node.type === 'ExportDefaultDeclaration') {
1035 var isDeclaration = /Declaration$/.test(node.declaration.type);
1036 var isAnonymous = /(?:Class|Function)Expression$/.test(node.declaration.type);
1037
1038 var declaredName = isDeclaration && node.declaration.id.name;
1039 var identifier = node.declaration.type === 'Identifier' && node.declaration.name;
1040
1041 this.exports.default = {
1042 statement: statement,
1043 name: 'default',
1044 localName: declaredName || 'default',
1045 declaredName: declaredName,
1046 identifier: identifier,
1047 isDeclaration: isDeclaration,
1048 isAnonymous: isAnonymous,
1049 isModified: false // in case of `export default foo; foo = somethingElse`
1050 };
1051 }
1052
1053 // export { foo, bar, baz }
1054 // export var foo = 42;
1055 // export function foo () {}
1056 else if (node.type === 'ExportNamedDeclaration') {
1057 if (node.specifiers.length) {
1058 // export { foo, bar, baz }
1059 node.specifiers.forEach(function (specifier) {
1060 var localName = specifier.local.name;
1061 var exportedName = specifier.exported.name;
1062
1063 _this6.exports[exportedName] = {
1064 localName: localName,
1065 exportedName: exportedName
1066 };
1067
1068 // export { foo } from './foo';
1069 if (source) {
1070 _this6.imports[localName] = {
1071 source: source,
1072 localName: localName,
1073 name: localName
1074 };
1075 }
1076 });
1077 } else {
1078 var declaration = node.declaration;
1079
1080 var _name2 = undefined;
1081
1082 if (declaration.type === 'VariableDeclaration') {
1083 // export var foo = 42
1084 _name2 = declaration.declarations[0].id.name;
1085 } else {
1086 // export function foo () {}
1087 _name2 = declaration.id.name;
1088 }
1089
1090 this.exports[_name2] = {
1091 statement: statement,
1092 localName: _name2,
1093 expression: declaration
1094 };
1095 }
1096 }
1097
1098 // Store `export * from '...'` statements in an array of delegates.
1099 // When an unknown import is encountered, we see if one of them can satisfy it.
1100 else {
1101 this.exportDelegates.push({
1102 statement: statement,
1103 source: source
1104 });
1105 }
1106 };
1107
1108 Module.prototype.addImport = function addImport(statement) {
1109 var _this7 = this;
1110
1111 var node = statement.node;
1112 var source = node.source.value;
1113
1114 node.specifiers.forEach(function (specifier) {
1115 var isDefault = specifier.type === 'ImportDefaultSpecifier';
1116 var isNamespace = specifier.type === 'ImportNamespaceSpecifier';
1117
1118 var localName = specifier.local.name;
1119 var name = isDefault ? 'default' : isNamespace ? '*' : specifier.imported.name;
1120
1121 if (_this7.imports[localName]) {
1122 var err = new Error('Duplicated import \'' + localName + '\'');
1123 err.file = _this7.id;
1124 err.loc = getLocation(_this7.source, specifier.start);
1125 throw err;
1126 }
1127
1128 _this7.imports[localName] = {
1129 source: source,
1130 name: name,
1131 localName: localName
1132 };
1133 });
1134 };
1135
1136 Module.prototype.analyse = function analyse() {
1137 var _this8 = this;
1138
1139 // discover this module's imports and exports
1140 this.statements.forEach(function (statement) {
1141 if (statement.isImportDeclaration) _this8.addImport(statement);else if (statement.isExportDeclaration) _this8.addExport(statement);
1142
1143 statement.analyse();
1144
1145 // consolidate names that are defined/modified in this module
1146 keys(statement.defines).forEach(function (name) {
1147 _this8.definitions[name] = statement;
1148 });
1149
1150 keys(statement.modifies).forEach(function (name) {
1151 (_this8.modifications[name] || (_this8.modifications[name] = [])).push(statement);
1152 });
1153 });
1154
1155 // if names are referenced that are neither defined nor imported
1156 // in this module, we assume that they're globals
1157 this.statements.forEach(function (statement) {
1158 keys(statement.dependsOn).forEach(function (name) {
1159 if (!_this8.definitions[name] && !_this8.imports[name]) {
1160 _this8.bundle.assumedGlobals[name] = true;
1161 }
1162 });
1163 });
1164 };
1165
1166 Module.prototype.consolidateDependencies = function consolidateDependencies() {
1167 var _this9 = this;
1168
1169 var strongDependencies = blank();
1170
1171 this.statements.forEach(function (statement) {
1172 if (statement.isImportDeclaration && !statement.node.specifiers.length && !statement.module.isExternal) {
1173 // include module for its side-effects
1174 strongDependencies[statement.module.id] = statement.module; // TODO is this right? `statement.module` should be `this`, surely?
1175 }
1176
1177 keys(statement.stronglyDependsOn).forEach(function (name) {
1178 if (statement.defines[name]) return;
1179
1180 var exportAllDeclaration = _this9.exportAlls[name];
1181
1182 if (exportAllDeclaration && exportAllDeclaration.module && !exportAllDeclaration.module.isExternal) {
1183 strongDependencies[exportAllDeclaration.module.id] = exportAllDeclaration.module;
1184 return;
1185 }
1186
1187 var importDeclaration = _this9.imports[name];
1188
1189 if (importDeclaration && importDeclaration.module && !importDeclaration.module.isExternal) {
1190 strongDependencies[importDeclaration.module.id] = importDeclaration.module;
1191 }
1192 });
1193 });
1194
1195 var weakDependencies = blank();
1196
1197 this.statements.forEach(function (statement) {
1198 keys(statement.dependsOn).forEach(function (name) {
1199 if (statement.defines[name]) return;
1200
1201 var importDeclaration = _this9.imports[name];
1202
1203 if (importDeclaration && importDeclaration.module && !importDeclaration.module.isExternal) {
1204 weakDependencies[importDeclaration.module.id] = importDeclaration.module;
1205 }
1206 });
1207 });
1208
1209 return { strongDependencies: strongDependencies, weakDependencies: weakDependencies };
1210 };
1211
1212 Module.prototype.findDefiningStatement = function findDefiningStatement(name) {
1213 if (this.definitions[name]) return this.definitions[name];
1214
1215 // TODO what about `default`/`*`?
1216
1217 var importDeclaration = this.imports[name];
1218 if (!importDeclaration) return null;
1219
1220 return sander.Promise.resolve(importDeclaration.module || this.bundle.fetchModule(importDeclaration.source, this.id)).then(function (module) {
1221 importDeclaration.module = module;
1222 return module.findDefiningStatement(name);
1223 });
1224 };
1225
1226 Module.prototype.findDeclaration = function findDeclaration(localName) {
1227 var importDeclaration = this.imports[localName];
1228
1229 // name was defined by another module
1230 if (importDeclaration) {
1231 var _module = importDeclaration.module;
1232
1233 if (_module.isExternal) return null;
1234
1235 var exportDeclaration = _module.exports[importDeclaration.name];
1236 return _module.findDeclaration(exportDeclaration.localName);
1237 }
1238
1239 // name was defined by this module, if any
1240 var i = this.statements.length;
1241 while (i--) {
1242 var declaration = this.statements[i].scope.declarations[localName];
1243 if (declaration) {
1244 return declaration;
1245 }
1246 }
1247
1248 return null;
1249 };
1250
1251 Module.prototype.getCanonicalName = function getCanonicalName(localName, es6) {
1252 // Special case
1253 if (localName === 'default' && (this.exports.default.isModified || !this.suggestedNames.default)) {
1254 var canonicalName = makeLegalIdentifier(this.id.replace(dirname(this.bundle.entryModule.id) + '/', '').replace(/\.js$/, ''));
1255 return deconflict(canonicalName, this.definitions);
1256 }
1257
1258 if (this.suggestedNames[localName]) {
1259 localName = this.suggestedNames[localName];
1260 }
1261
1262 var id = localName + (es6 ? '-es6' : ''); // TODO ugh this seems like a terrible hack
1263
1264 if (!this.canonicalNames[id]) {
1265 var canonicalName = undefined;
1266
1267 if (this.imports[localName]) {
1268 var importDeclaration = this.imports[localName];
1269 var _module2 = importDeclaration.module;
1270
1271 if (importDeclaration.name === '*') {
1272 canonicalName = _module2.suggestedNames['*'];
1273 } else {
1274 var exporterLocalName = undefined;
1275
1276 if (_module2.isExternal) {
1277 exporterLocalName = importDeclaration.name;
1278 } else {
1279 var exportDeclaration = _module2.exports[importDeclaration.name];
1280
1281 // The export declaration of the particular name is known.
1282 if (exportDeclaration) {
1283 exporterLocalName = exportDeclaration.localName;
1284 } else {
1285 // export * from '...'
1286 exporterLocalName = importDeclaration.name;
1287 }
1288 }
1289
1290 canonicalName = _module2.getCanonicalName(exporterLocalName, es6);
1291 }
1292 } else {
1293 canonicalName = localName;
1294 }
1295
1296 this.canonicalNames[id] = canonicalName;
1297 }
1298
1299 return this.canonicalNames[id];
1300 };
1301
1302 Module.prototype.mark = function mark(name) {
1303 var _this10 = this;
1304
1305 // shortcut cycles. TODO this won't work everywhere...
1306 if (this.definitionPromises[name]) {
1307 return emptyArrayPromise;
1308 }
1309
1310 var promise = undefined;
1311
1312 // The definition for this name is in a different module
1313 if (this.imports[name]) {
1314 (function () {
1315 var importDeclaration = _this10.imports[name];
1316
1317 promise = _this10.bundle.fetchModule(importDeclaration.source, _this10.id).then(function (module) {
1318 importDeclaration.module = module;
1319
1320 // suggest names. TODO should this apply to non default/* imports?
1321 if (importDeclaration.name === 'default') {
1322 // TODO this seems ropey
1323 var localName = importDeclaration.localName;
1324 var suggestion = _this10.suggestedNames[localName] || localName;
1325
1326 // special case - the module has its own import by this name
1327 while (!module.isExternal && module.imports[suggestion]) {
1328 suggestion = '_' + suggestion;
1329 }
1330
1331 module.suggestName('default', suggestion);
1332 } else if (importDeclaration.name === '*') {
1333 var localName = importDeclaration.localName;
1334 var suggestion = _this10.suggestedNames[localName] || localName;
1335 module.suggestName('*', suggestion);
1336 module.suggestName('default', suggestion + '__default');
1337 }
1338
1339 if (module.isExternal) {
1340 if (importDeclaration.name === 'default') {
1341 module.needsDefault = true;
1342 } else if (importDeclaration.name === '*') {
1343 module.needsAll = true;
1344 } else {
1345 module.needsNamed = true;
1346 }
1347
1348 module.importedByBundle.push(importDeclaration);
1349 return emptyArrayPromise;
1350 }
1351
1352 if (importDeclaration.name === '*') {
1353 // we need to create an internal namespace
1354 if (! ~_this10.bundle.internalNamespaceModules.indexOf(module)) {
1355 _this10.bundle.internalNamespaceModules.push(module);
1356 }
1357
1358 return module.markAllStatements();
1359 }
1360
1361 var exportDeclaration = module.exports[importDeclaration.name];
1362
1363 if (!exportDeclaration) {
1364 var _ret3 = (function () {
1365 var noExport = new Error('Module ' + module.id + ' does not export ' + importDeclaration.name + ' (imported by ' + _this10.id + ')');
1366
1367 // See if there exists an export delegate that defines `name`.
1368 return {
1369 v: first(module.exportDelegates, noExport, function (declaration) {
1370 return module.bundle.fetchModule(declaration.source, module.id).then(function (submodule) {
1371 declaration.module = submodule;
1372
1373 return submodule.mark(name).then(function (result) {
1374 if (!result.length) throw noExport;
1375
1376 // It's found! This module exports `name` through declaration.
1377 // It is however not imported into this scope.
1378 module.exportAlls[name] = declaration;
1379
1380 declaration.statement.dependsOn[name] = declaration.statement.stronglyDependsOn[name] = result;
1381
1382 return result;
1383 });
1384 });
1385 })
1386 };
1387 })();
1388
1389 if (typeof _ret3 === 'object') return _ret3.v;
1390 }
1391
1392 exportDeclaration.isUsed = true;
1393 return module.mark(exportDeclaration.localName);
1394 });
1395 })();
1396 }
1397
1398 // The definition is in this module
1399 else if (name === 'default' && this.exports.default.isDeclaration) {
1400 // We have something like `export default foo` - so we just start again,
1401 // searching for `foo` instead of default
1402 promise = this.mark(this.exports.default.name);
1403 } else {
1404 (function () {
1405 var statement = undefined;
1406
1407 statement = name === 'default' ? _this10.exports.default.statement : _this10.definitions[name];
1408 promise = statement && !statement.isIncluded ? statement.mark() : emptyArrayPromise;
1409
1410 // Special case - `export default foo; foo += 1` - need to be
1411 // vigilant about maintaining the correct order of the export
1412 // declaration. Otherwise, the export declaration will always
1413 // go at the end of the expansion, because the expansion of
1414 // `foo` will include statements *after* the declaration
1415 if (name === 'default' && _this10.exports.default.identifier && _this10.exports.default.isModified) {
1416 (function () {
1417 var defaultExportStatement = _this10.exports.default.statement;
1418 promise = promise.then(function (statements) {
1419 // remove the default export statement...
1420 // TODO could this be statements.pop()?
1421 statements.splice(statements.indexOf(defaultExportStatement), 1);
1422
1423 var i = statements.length;
1424 var inserted = false;
1425
1426 while (i--) {
1427 if (statements[i].module === _this10 && statements[i].index < defaultExportStatement.index) {
1428 statements.splice(i + 1, 0, defaultExportStatement);
1429 inserted = true;
1430 break;
1431 }
1432 }
1433
1434 if (!inserted) statements.push(statement);
1435 return statements;
1436 });
1437 })();
1438 }
1439 })();
1440 }
1441
1442 this.definitionPromises[name] = promise || emptyArrayPromise;
1443 return this.definitionPromises[name];
1444 };
1445
1446 Module.prototype.markAllStatements = function markAllStatements(isEntryModule) {
1447 var _this11 = this;
1448
1449 return sequence(this.statements, function (statement) {
1450 if (statement.isIncluded) return; // TODO can this happen? probably not...
1451
1452 // skip import declarations...
1453 if (statement.isImportDeclaration) {
1454 // ...unless they're empty, in which case assume we're importing them for the side-effects
1455 // THIS IS NOT FOOLPROOF. Probably need /*rollup: include */ or similar
1456 if (!statement.node.specifiers.length) {
1457 return _this11.bundle.fetchModule(statement.node.source.value, _this11.id).then(function (module) {
1458 statement.module = module;
1459 if (module.isExternal) {
1460 return;
1461 }
1462 return module.markAllStatements();
1463 });
1464 }
1465
1466 return;
1467 }
1468
1469 // skip `export { foo, bar, baz }`...
1470 if (statement.node.type === 'ExportNamedDeclaration' && statement.node.specifiers.length) {
1471 // ...but ensure they are defined, if this is the entry module
1472 if (isEntryModule) {
1473 return statement.mark();
1474 }
1475
1476 return;
1477 }
1478
1479 // include everything else
1480 return statement.mark();
1481 });
1482 };
1483
1484 // TODO rename this to parse, once https://github.com/rollup/rollup/issues/42 is fixed
1485
1486 Module.prototype._parse = function _parse() {
1487 var _this12 = this;
1488
1489 // Try to extract a list of top-level statements/declarations. If
1490 // the parse fails, attach file info and abort
1491 var ast = undefined;
1492
1493 try {
1494 ast = acorn.parse(this.source, {
1495 ecmaVersion: 6,
1496 sourceType: 'module',
1497 onComment: function (block, text, start, end) {
1498 return _this12.comments.push({ block: block, text: text, start: start, end: end });
1499 }
1500 });
1501 } catch (err) {
1502 err.code = 'PARSE_ERROR';
1503 err.file = this.id; // see above - not necessarily true, but true enough
1504 throw err;
1505 }
1506
1507 walk(ast, {
1508 enter: function (node) {
1509 _this12.magicString.addSourcemapLocation(node.start);
1510 _this12.magicString.addSourcemapLocation(node.end);
1511 }
1512 });
1513
1514 var statements = [];
1515 var lastChar = 0;
1516 var commentIndex = 0;
1517
1518 ast.body.forEach(function (node) {
1519 // special case - top-level var declarations with multiple declarators
1520 // should be split up. Otherwise, we may end up including code we
1521 // don't need, just because an unwanted declarator is included
1522 if (node.type === 'VariableDeclaration' && node.declarations.length > 1) {
1523 // remove the leading var/let/const
1524 _this12.magicString.remove(node.start, node.declarations[0].start);
1525
1526 node.declarations.forEach(function (declarator, i) {
1527 var start = declarator.start;
1528 var end = declarator.end;
1529
1530 var syntheticNode = {
1531 type: 'VariableDeclaration',
1532 kind: node.kind,
1533 start: start,
1534 end: end,
1535 declarations: [declarator],
1536 isSynthetic: true
1537 };
1538
1539 var statement = new Statement(syntheticNode, _this12, start, end);
1540 statements.push(statement);
1541 });
1542
1543 lastChar = node.end; // TODO account for trailing line comment
1544 } else {
1545 var comment = undefined;
1546 do {
1547 comment = _this12.comments[commentIndex];
1548 if (!comment) break;
1549 if (comment.start > node.start) break;
1550 commentIndex += 1;
1551 } while (comment.end < lastChar);
1552
1553 var start = comment ? Math.min(comment.start, node.start) : node.start;
1554 var end = node.end; // TODO account for trailing line comment
1555
1556 var statement = new Statement(node, _this12, start, end);
1557 statements.push(statement);
1558
1559 lastChar = end;
1560 }
1561 });
1562
1563 statements.forEach(function (statement, i) {
1564 var nextStatement = statements[i + 1];
1565 statement.next = nextStatement ? nextStatement.start : statement.end;
1566 });
1567
1568 return statements;
1569 };
1570
1571 Module.prototype.rename = function rename(name, replacement) {
1572 // TODO again, hacky...
1573 this.canonicalNames[name] = this.canonicalNames[name + '-es6'] = replacement;
1574 };
1575
1576 Module.prototype.render = function render(allBundleExports, format) {
1577 var magicString = this.magicString.clone();
1578
1579 var previousIndex = -1;
1580 var previousMargin = 0;
1581
1582 this.statements.forEach(function (statement, i) {
1583 if (!statement.isIncluded) {
1584 magicString.remove(statement.start, statement.next);
1585 return;
1586 }
1587
1588 // skip `export { foo, bar, baz }`
1589 if (statement.node.type === 'ExportNamedDeclaration') {
1590 // skip `export { foo, bar, baz }`
1591 if (statement.node.specifiers.length) {
1592 magicString.remove(statement.start, statement.next);
1593 return;
1594 };
1595
1596 // skip `export var foo;` if foo is exported
1597 if (isEmptyExportedVarDeclaration(statement.node.declaration, statement.module, allBundleExports, format === 'es6')) {
1598 magicString.remove(statement.start, statement.next);
1599 return;
1600 }
1601 }
1602
1603 // skip empty var declarations for exported bindings
1604 // (otherwise we're left with `exports.foo;`, which is useless)
1605 if (isEmptyExportedVarDeclaration(statement.node, statement.module, allBundleExports, format === 'es6')) {
1606 magicString.remove(statement.start, statement.next);
1607 return;
1608 }
1609
1610 // split up/remove var declarations as necessary
1611 if (statement.node.isSynthetic) {
1612 magicString.insert(statement.start, statement.node.kind + ' ');
1613 magicString.overwrite(statement.end, statement.next, ';\n'); // TODO account for trailing newlines
1614 }
1615
1616 var replacements = blank();
1617 var bundleExports = blank();
1618
1619 keys(statement.dependsOn).concat(keys(statement.defines)).forEach(function (name) {
1620 var canonicalName = statement.module.getCanonicalName(name, format === 'es6');
1621
1622 if (allBundleExports[canonicalName]) {
1623 bundleExports[name] = replacements[name] = allBundleExports[canonicalName];
1624 } else if (name !== canonicalName) {
1625 replacements[name] = canonicalName;
1626 }
1627 });
1628
1629 statement.replaceIdentifiers(magicString, replacements, bundleExports);
1630
1631 // modify exports as necessary
1632 if (statement.isExportDeclaration) {
1633 // remove `export` from `export var foo = 42`
1634 if (statement.node.type === 'ExportNamedDeclaration' && statement.node.declaration.type === 'VariableDeclaration') {
1635 magicString.remove(statement.node.start, statement.node.declaration.start);
1636 }
1637
1638 // remove `export` from `export class Foo {...}` or `export default Foo`
1639 // TODO default exports need different treatment
1640 else if (statement.node.declaration.id) {
1641 magicString.remove(statement.node.start, statement.node.declaration.start);
1642 } else if (statement.node.type === 'ExportDefaultDeclaration') {
1643 var _module3 = statement.module;
1644 var canonicalName = _module3.getCanonicalName('default', format === 'es6');
1645
1646 if (statement.node.declaration.type === 'Identifier' && canonicalName === _module3.getCanonicalName(statement.node.declaration.name, format === 'es6')) {
1647 magicString.remove(statement.start, statement.next);
1648 return;
1649 }
1650
1651 // anonymous functions should be converted into declarations
1652 if (statement.node.declaration.type === 'FunctionExpression') {
1653 magicString.overwrite(statement.node.start, statement.node.declaration.start + 8, 'function ' + canonicalName);
1654 } else {
1655 magicString.overwrite(statement.node.start, statement.node.declaration.start, 'var ' + canonicalName + ' = ');
1656 }
1657 } else {
1658 throw new Error('Unhandled export');
1659 }
1660 }
1661 });
1662
1663 return magicString.trim();
1664 };
1665
1666 Module.prototype.suggestName = function suggestName(defaultOrBatch, suggestion) {
1667 // deconflict anonymous default exports with this module's definitions
1668 var shouldDeconflict = this.exports.default && this.exports.default.isAnonymous;
1669
1670 if (shouldDeconflict) suggestion = deconflict(suggestion, this.definitions);
1671
1672 if (!this.suggestedNames[defaultOrBatch]) {
1673 this.suggestedNames[defaultOrBatch] = makeLegalIdentifier(suggestion);
1674 }
1675 };
1676
1677 return Module;
1678})();
1679
1680var ExternalModule = (function () {
1681 function ExternalModule(id) {
1682 _classCallCheck(this, ExternalModule);
1683
1684 this.id = id;
1685 this.name = null;
1686
1687 this.isExternal = true;
1688 this.importedByBundle = [];
1689
1690 this.canonicalNames = blank();
1691 this.suggestedNames = blank();
1692
1693 this.needsDefault = false;
1694
1695 // Invariant: needsNamed and needsAll are never both true at once.
1696 // Because an import with both a namespace and named import is invalid:
1697 //
1698 // import * as ns, { a } from '...'
1699 //
1700 this.needsNamed = false;
1701 this.needsAll = false;
1702 }
1703
1704 ExternalModule.prototype.findDefiningStatement = function findDefiningStatement() {
1705 return null;
1706 };
1707
1708 ExternalModule.prototype.getCanonicalName = function getCanonicalName(name, es6) {
1709 if (name === 'default') {
1710 return this.needsNamed && !es6 ? this.name + '__default' : this.name;
1711 }
1712
1713 if (name === '*') {
1714 return this.name; // TODO is this correct in ES6?
1715 }
1716
1717 return es6 ? this.canonicalNames[name] || name : this.name + '.' + name;
1718 };
1719
1720 ExternalModule.prototype.rename = function rename(name, replacement) {
1721 this.canonicalNames[name] = replacement;
1722 };
1723
1724 ExternalModule.prototype.suggestName = function suggestName(exportName, suggestion) {
1725 if (!this.suggestedNames[exportName]) {
1726 this.suggestedNames[exportName] = suggestion;
1727 }
1728 };
1729
1730 return ExternalModule;
1731})();
1732
1733function ensureArray(thing) {
1734 if (Array.isArray(thing)) return thing;
1735 if (thing == undefined) return [];
1736 return [thing];
1737}
1738
1739function defaultResolver(importee, importer, options) {
1740 // absolute paths are left untouched
1741 if (isAbsolute(importee)) return importee;
1742
1743 // if this is the entry point, resolve against cwd
1744 if (importer === undefined) return resolve(process.cwd(), importee);
1745
1746 // we try to resolve external modules
1747 if (importee[0] !== '.') {
1748 // unless we want to keep it external, that is
1749 if (~options.external.indexOf(importee)) return null;
1750
1751 return options.resolveExternal(importee, importer, options);
1752 }
1753
1754 return resolve(dirname(importer), importee).replace(/\.js$/, '') + '.js';
1755}
1756
1757function defaultExternalResolver(id, importer) {
1758 // for now, only node_modules is supported, and only jsnext:main
1759 var root = absolutePath.exec(importer)[0];
1760 var dir = dirname(importer);
1761
1762 while (dir !== root) {
1763 var pkgPath = resolve(dir, 'node_modules', id, 'package.json');
1764 var pkgJson = undefined;
1765
1766 try {
1767 pkgJson = sander.readFileSync(pkgPath).toString();
1768 } catch (err) {}
1769
1770 if (pkgJson) {
1771 var pkg = undefined;
1772
1773 try {
1774 pkg = JSON.parse(pkgJson);
1775 } catch (err) {
1776 throw new Error('Malformed JSON: ' + pkgPath);
1777 }
1778
1779 var main = pkg['jsnext:main'];
1780
1781 if (!main) {
1782 throw new Error('Package ' + id + ' does not have a jsnext:main field, and so cannot be included in your rollup. Try adding it as an external module instead (e.g. options.external = [\'' + id + '\']). See https://github.com/rollup/rollup/wiki/jsnext:main for more info');
1783 }
1784
1785 return resolve(dirname(pkgPath), main).replace(/\.js$/, '') + '.js';
1786 }
1787
1788 dir = dirname(dir);
1789 }
1790
1791 throw new Error('Could not find package ' + id + ' (required by ' + importer + ')');
1792}
1793
1794function defaultLoader(id, options) {
1795 // TODO support plugins e.g. !css and !json?
1796 var source = sander.readFileSync(id, { encoding: 'utf-8' });
1797
1798 return options.transform.reduce(function (source, transformer) {
1799 return transformer(source, id);
1800 }, source);
1801}
1802
1803var Bundle = (function () {
1804 function Bundle(options) {
1805 _classCallCheck(this, Bundle);
1806
1807 this.entry = options.entry;
1808 this.entryModule = null;
1809
1810 this.resolveId = options.resolveId || defaultResolver;
1811 this.load = options.load || defaultLoader;
1812
1813 this.resolveOptions = {
1814 external: ensureArray(options.external),
1815 resolveExternal: options.resolveExternal || defaultExternalResolver
1816 };
1817
1818 this.loadOptions = {
1819 transform: ensureArray(options.transform)
1820 };
1821
1822 this.varExports = blank();
1823 this.toExport = null;
1824
1825 this.modulePromises = blank();
1826 this.modules = [];
1827
1828 this.statements = null;
1829 this.externalModules = [];
1830 this.internalNamespaceModules = [];
1831 this.assumedGlobals = blank();
1832 }
1833
1834 Bundle.prototype.build = function build() {
1835 var _this13 = this;
1836
1837 return this.fetchModule(this.entry, undefined).then(function (entryModule) {
1838 var defaultExport = entryModule.exports.default;
1839
1840 _this13.entryModule = entryModule;
1841
1842 if (defaultExport) {
1843 // `export default function foo () {...}` -
1844 // use the declared name for the export
1845 if (defaultExport.declaredName) {
1846 entryModule.suggestName('default', defaultExport.declaredName);
1847 }
1848
1849 // `export default a + b` - generate an export name
1850 // based on the id of the entry module
1851 else {
1852 (function () {
1853 var defaultExportName = makeLegalIdentifier(basename(_this13.entryModule.id).slice(0, -extname(_this13.entryModule.id).length));
1854
1855 // deconflict
1856 var topLevelNames = [];
1857 entryModule.statements.forEach(function (statement) {
1858 keys(statement.defines).forEach(function (name) {
1859 return topLevelNames.push(name);
1860 });
1861 });
1862
1863 while (~topLevelNames.indexOf(defaultExportName)) {
1864 defaultExportName = '_' + defaultExportName;
1865 }
1866
1867 entryModule.suggestName('default', defaultExportName);
1868 })();
1869 }
1870 }
1871
1872 return entryModule.markAllStatements(true);
1873 }).then(function () {
1874 return _this13.markAllModifierStatements();
1875 }).then(function () {
1876 _this13.orderedModules = _this13.sort();
1877 });
1878 };
1879
1880 Bundle.prototype.deconflict = function deconflict(es6) {
1881 var _this14 = this;
1882
1883 var definers = blank();
1884 var conflicts = blank();
1885
1886 // Assign names to external modules
1887 this.externalModules.forEach(function (module) {
1888 // TODO is this right?
1889 var name = makeLegalIdentifier(module.suggestedNames['*'] || module.suggestedNames.default || module.id);
1890
1891 if (definers[name]) {
1892 conflicts[name] = true;
1893 } else {
1894 definers[name] = [];
1895 }
1896
1897 definers[name].push(module);
1898 module.name = name;
1899 _this14.assumedGlobals[name] = true;
1900 });
1901
1902 // Discover conflicts (i.e. two statements in separate modules both define `foo`)
1903 this.orderedModules.forEach(function (module) {
1904 module.statements.forEach(function (statement) {
1905 var names = keys(statement.defines);
1906
1907 // with default exports that are expressions (`export default 42`),
1908 // we need to ensure that the name chosen for the expression does
1909 // not conflict
1910 if (statement.node.type === 'ExportDefaultDeclaration') {
1911 var _name3 = module.getCanonicalName('default', es6);
1912
1913 var isProxy = statement.node.declaration && statement.node.declaration.type === 'Identifier';
1914 var shouldDeconflict = !isProxy || module.getCanonicalName(statement.node.declaration.name, es6) !== _name3;
1915
1916 if (shouldDeconflict && ! ~names.indexOf(_name3)) {
1917 names.push(_name3);
1918 }
1919 }
1920
1921 names.forEach(function (name) {
1922 if (definers[name]) {
1923 conflicts[name] = true;
1924 } else {
1925 definers[name] = [];
1926 }
1927
1928 // TODO in good js, there shouldn't be duplicate definitions
1929 // per module... but some people write bad js
1930 definers[name].push(module);
1931 });
1932 });
1933 });
1934
1935 // Ensure we don't conflict with globals
1936 keys(this.assumedGlobals).forEach(function (name) {
1937 if (definers[name]) {
1938 conflicts[name] = true;
1939 }
1940 });
1941
1942 // Rename conflicting identifiers so they can live in the same scope
1943 keys(conflicts).forEach(function (name) {
1944 var modules = definers[name];
1945
1946 if (!_this14.assumedGlobals[name]) {
1947 // the module closest to the entryModule gets away with
1948 // keeping things as they are, unless we have a conflict
1949 // with a global name
1950 modules.pop();
1951 }
1952
1953 modules.forEach(function (module) {
1954 var replacement = getSafeName(name);
1955 module.rename(name, replacement);
1956 });
1957 });
1958
1959 function getSafeName(name) {
1960 while (conflicts[name]) {
1961 name = '_' + name;
1962 }
1963
1964 conflicts[name] = true;
1965 return name;
1966 }
1967 };
1968
1969 Bundle.prototype.fetchModule = function fetchModule(importee, importer) {
1970 var _this15 = this;
1971
1972 return sander.Promise.resolve(this.resolveId(importee, importer, this.resolveOptions)).then(function (id) {
1973 if (!id) {
1974 // external module
1975 if (!_this15.modulePromises[importee]) {
1976 var _module4 = new ExternalModule(importee);
1977 _this15.externalModules.push(_module4);
1978 _this15.modulePromises[importee] = sander.Promise.resolve(_module4);
1979 }
1980
1981 return _this15.modulePromises[importee];
1982 }
1983
1984 if (!_this15.modulePromises[id]) {
1985 _this15.modulePromises[id] = sander.Promise.resolve(_this15.load(id, _this15.loadOptions)).then(function (source) {
1986 var module = new Module({
1987 id: id,
1988 source: source,
1989 bundle: _this15
1990 });
1991
1992 _this15.modules.push(module);
1993
1994 return module;
1995 });
1996 }
1997
1998 return _this15.modulePromises[id];
1999 });
2000 };
2001
2002 Bundle.prototype.markAllModifierStatements = function markAllModifierStatements() {
2003 var _this16 = this;
2004
2005 var settled = true;
2006 var promises = [];
2007
2008 this.modules.forEach(function (module) {
2009 module.statements.forEach(function (statement) {
2010 if (statement.isIncluded) return;
2011
2012 keys(statement.modifies).forEach(function (name) {
2013 var definingStatement = module.definitions[name];
2014 var exportDeclaration = module.exports[name] || module.exports.default && module.exports.default.identifier === name && module.exports.default;
2015
2016 var shouldMark = definingStatement && definingStatement.isIncluded || exportDeclaration && exportDeclaration.isUsed;
2017
2018 if (shouldMark) {
2019 settled = false;
2020 promises.push(statement.mark());
2021 return;
2022 }
2023
2024 // special case - https://github.com/rollup/rollup/pull/40
2025 var importDeclaration = module.imports[name];
2026 if (!importDeclaration) return;
2027
2028 var promise = sander.Promise.resolve(importDeclaration.module || _this16.fetchModule(importDeclaration.source, module.id)).then(function (module) {
2029 importDeclaration.module = module;
2030 var exportDeclaration = module.exports[importDeclaration.name];
2031 // TODO things like `export default a + b` don't apply here... right?
2032 return module.findDefiningStatement(exportDeclaration.localName);
2033 }).then(function (definingStatement) {
2034 if (!definingStatement) return;
2035
2036 settled = false;
2037 return statement.mark();
2038 });
2039
2040 promises.push(promise);
2041 });
2042 });
2043 });
2044
2045 return sander.Promise.all(promises).then(function () {
2046 if (!settled) return _this16.markAllModifierStatements();
2047 });
2048 };
2049
2050 Bundle.prototype.render = function render() {
2051 var _this17 = this;
2052
2053 var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
2054
2055 var format = options.format || 'es6';
2056 this.deconflict(format === 'es6');
2057
2058 // If we have named exports from the bundle, and those exports
2059 // are assigned to *within* the bundle, we may need to rewrite e.g.
2060 //
2061 // export let count = 0;
2062 // export function incr () { count++ }
2063 //
2064 // might become...
2065 //
2066 // exports.count = 0;
2067 // function incr () {
2068 // exports.count += 1;
2069 // }
2070 // exports.incr = incr;
2071 //
2072 // This doesn't apply if the bundle is exported as ES6!
2073 var allBundleExports = blank();
2074
2075 if (format !== 'es6') {
2076 keys(this.entryModule.exports).forEach(function (key) {
2077 var exportDeclaration = _this17.entryModule.exports[key];
2078
2079 var originalDeclaration = _this17.entryModule.findDeclaration(exportDeclaration.localName);
2080
2081 if (originalDeclaration && originalDeclaration.type === 'VariableDeclaration') {
2082 var canonicalName = _this17.entryModule.getCanonicalName(exportDeclaration.localName, false);
2083
2084 allBundleExports[canonicalName] = 'exports.' + key;
2085 _this17.varExports[key] = true;
2086 }
2087 });
2088 }
2089
2090 // since we're rewriting variable exports, we want to
2091 // ensure we don't try and export them again at the bottom
2092 this.toExport = keys(this.entryModule.exports).filter(function (key) {
2093 return !_this17.varExports[key];
2094 });
2095
2096 var magicString = new MagicString.Bundle({ separator: '\n\n' });
2097
2098 this.orderedModules.forEach(function (module) {
2099 var source = module.render(allBundleExports, format);
2100 if (source.toString().length) {
2101 magicString.addSource(source);
2102 }
2103 });
2104
2105 // prepend bundle with internal namespaces
2106 var indentString = magicString.getIndentString();
2107 var namespaceBlock = this.internalNamespaceModules.map(function (module) {
2108 var exportKeys = keys(module.exports);
2109
2110 return 'var ' + module.getCanonicalName('*', format === 'es6') + ' = {\n' + exportKeys.map(function (key) {
2111 return indentString + 'get ' + key + ' () { return ' + module.getCanonicalName(key, format === 'es6') + '; }';
2112 }).join(',\n') + '\n};\n\n';
2113 }).join('');
2114
2115 magicString.prepend(namespaceBlock);
2116
2117 var finalise = finalisers[format];
2118
2119 if (!finalise) {
2120 throw new Error('You must specify an output type - valid options are ' + keys(finalisers).join(', '));
2121 }
2122
2123 magicString = finalise(this, magicString.trim(), {
2124 // Determine export mode - 'default', 'named', 'none'
2125 exportMode: getExportMode(this, options.exports),
2126
2127 // Determine indentation
2128 indentString: getIndentString(magicString, options)
2129 }, options);
2130
2131 var code = magicString.toString();
2132 var map = null;
2133
2134 if (options.sourceMap) {
2135 var file = options.sourceMapFile || options.dest;
2136 map = magicString.generateMap({
2137 includeContent: true,
2138 file
2139 // TODO
2140 : file });
2141
2142 map.sources = map.sources.map(unixizePath);
2143 }
2144
2145 return { code: code, map: map };
2146 };
2147
2148 Bundle.prototype.sort = function sort() {
2149 var seen = {};
2150 var ordered = [];
2151 var hasCycles = undefined;
2152
2153 var strongDeps = {};
2154 var stronglyDependsOn = {};
2155
2156 function visit(module) {
2157 seen[module.id] = true;
2158
2159 var _module$consolidateDependencies = module.consolidateDependencies();
2160
2161 var strongDependencies = _module$consolidateDependencies.strongDependencies;
2162 var weakDependencies = _module$consolidateDependencies.weakDependencies;
2163
2164 strongDeps[module.id] = [];
2165 stronglyDependsOn[module.id] = {};
2166
2167 keys(strongDependencies).forEach(function (id) {
2168 var imported = strongDependencies[id];
2169
2170 strongDeps[module.id].push(imported);
2171
2172 if (seen[id]) {
2173 // we need to prevent an infinite loop, and note that
2174 // we need to check for strong/weak dependency relationships
2175 hasCycles = true;
2176 return;
2177 }
2178
2179 visit(imported);
2180 });
2181
2182 keys(weakDependencies).forEach(function (id) {
2183 var imported = weakDependencies[id];
2184
2185 if (seen[id]) {
2186 // we need to prevent an infinite loop, and note that
2187 // we need to check for strong/weak dependency relationships
2188 hasCycles = true;
2189 return;
2190 }
2191
2192 visit(imported);
2193 });
2194
2195 // add second (and third...) order dependencies
2196 function addStrongDependencies(dependency) {
2197 if (stronglyDependsOn[module.id][dependency.id]) return;
2198
2199 stronglyDependsOn[module.id][dependency.id] = true;
2200 strongDeps[dependency.id].forEach(addStrongDependencies);
2201 }
2202
2203 strongDeps[module.id].forEach(addStrongDependencies);
2204
2205 ordered.push(module);
2206 }
2207
2208 visit(this.entryModule);
2209
2210 if (hasCycles) {
2211 var unordered = ordered;
2212 ordered = [];
2213
2214 // unordered is actually semi-ordered, as [ fewer dependencies ... more dependencies ]
2215 unordered.forEach(function (module) {
2216 // ensure strong dependencies of `module` that don't strongly depend on `module` go first
2217 strongDeps[module.id].forEach(place);
2218
2219 function place(dep) {
2220 if (!stronglyDependsOn[dep.id][module.id] && ! ~ordered.indexOf(dep)) {
2221 strongDeps[dep.id].forEach(place);
2222 ordered.push(dep);
2223 }
2224 }
2225
2226 if (! ~ordered.indexOf(module)) {
2227 ordered.push(module);
2228 }
2229 });
2230 }
2231
2232 return ordered;
2233 };
2234
2235 return Bundle;
2236})();
2237
2238var SOURCEMAPPING_URL = 'sourceMa';
2239SOURCEMAPPING_URL += 'ppingURL';
2240
2241function rollup(options) {
2242 if (!options || !options.entry) {
2243 throw new Error('You must supply options.entry to rollup');
2244 }
2245
2246 var bundle = new Bundle(options);
2247
2248 return bundle.build().then(function () {
2249 return {
2250 generate: function (options) {
2251 return bundle.render(options);
2252 },
2253 write: function (options) {
2254 if (!options || !options.dest) {
2255 throw new Error('You must supply options.dest to bundle.write');
2256 }
2257
2258 var dest = options.dest;
2259
2260 var _bundle$render = bundle.render(options);
2261
2262 var code = _bundle$render.code;
2263 var map = _bundle$render.map;
2264
2265 var promises = [];
2266
2267 if (options.sourceMap) {
2268 var url = undefined;
2269
2270 if (options.sourceMap === 'inline') {
2271 url = map.toUrl();
2272 } else {
2273 url = basename(dest) + '.map';
2274 promises.push(sander.writeFile(dest + '.map', map.toString()));
2275 }
2276
2277 code += '\n//# ' + SOURCEMAPPING_URL + '=' + url;
2278 }
2279
2280 promises.push(sander.writeFile(dest, code));
2281 return Promise.all(promises);
2282 }
2283 };
2284 });
2285}
2286
2287exports.rollup = rollup;
2288
2289// noop
2290//# sourceMappingURL=rollup.js.map