UNPKG

118 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, '__esModule', { value: true });
4
5function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
6
7var acorn = require('acorn');
8var acornJsx = _interopDefault(require('acorn-jsx'));
9var acornDynamicImport = _interopDefault(require('acorn-dynamic-import'));
10var MagicString = _interopDefault(require('magic-string'));
11var rewritePattern = _interopDefault(require('regexpu-core'));
12
13// used for debugging, without the noise created by
14// circular references
15function toJSON(node) {
16 var obj = {};
17
18 Object.keys(node).forEach(key => {
19 if (
20 key === 'parent' ||
21 key === 'program' ||
22 key === 'keys' ||
23 key === '__wrapped'
24 )
25 { return; }
26
27 if (Array.isArray(node[key])) {
28 obj[key] = node[key].map(toJSON);
29 } else if (node[key] && node[key].toJSON) {
30 obj[key] = node[key].toJSON();
31 } else {
32 obj[key] = node[key];
33 }
34 });
35
36 return obj;
37}
38
39class Node {
40 ancestor(level) {
41 var node = this;
42 while (level--) {
43 node = node.parent;
44 if (!node) { return null; }
45 }
46
47 return node;
48 }
49
50 contains(node) {
51 while (node) {
52 if (node === this) { return true; }
53 node = node.parent;
54 }
55
56 return false;
57 }
58
59 findLexicalBoundary() {
60 return this.parent.findLexicalBoundary();
61 }
62
63 findNearest(type) {
64 if (typeof type === 'string') { type = new RegExp(`^${type}$`); }
65 if (type.test(this.type)) { return this; }
66 return this.parent.findNearest(type);
67 }
68
69 unparenthesizedParent() {
70 var node = this.parent;
71 while (node && node.type === 'ParenthesizedExpression') {
72 node = node.parent;
73 }
74 return node;
75 }
76
77 unparenthesize() {
78 var node = this;
79 while (node.type === 'ParenthesizedExpression') {
80 node = node.expression;
81 }
82 return node;
83 }
84
85 findScope(functionScope) {
86 return this.parent.findScope(functionScope);
87 }
88
89 getIndentation() {
90 return this.parent.getIndentation();
91 }
92
93 initialise(transforms) {
94 for (var i = 0, list = this.keys; i < list.length; i += 1) {
95 var key = list[i];
96
97 var value = this[key];
98
99 if (Array.isArray(value)) {
100 value.forEach(node => node && node.initialise(transforms));
101 } else if (value && typeof value === 'object') {
102 value.initialise(transforms);
103 }
104 }
105 }
106
107 toJSON() {
108 return toJSON(this);
109 }
110
111 toString() {
112 return this.program.magicString.original.slice(this.start, this.end);
113 }
114
115 transpile(code, transforms) {
116 for (var i = 0, list = this.keys; i < list.length; i += 1) {
117 var key = list[i];
118
119 var value = this[key];
120
121 if (Array.isArray(value)) {
122 value.forEach(node => node && node.transpile(code, transforms));
123 } else if (value && typeof value === 'object') {
124 value.transpile(code, transforms);
125 }
126 }
127 }
128}
129
130function extractNames(node) {
131 var names = [];
132 extractors[node.type](names, node);
133 return names;
134}
135
136var extractors = {
137 Identifier(names, node) {
138 names.push(node);
139 },
140
141 ObjectPattern(names, node) {
142 for (var i = 0, list = node.properties; i < list.length; i += 1) {
143 var prop = list[i];
144
145 extractors[prop.type](names, prop);
146 }
147 },
148
149 Property(names, node) {
150 extractors[node.value.type](names, node.value);
151 },
152
153 ArrayPattern(names, node) {
154 for (var i = 0, list = node.elements; i < list.length; i += 1) {
155 var element = list[i];
156
157 if (element) { extractors[element.type](names, element); }
158 }
159 },
160
161 RestElement(names, node) {
162 extractors[node.argument.type](names, node.argument);
163 },
164
165 AssignmentPattern(names, node) {
166 extractors[node.left.type](names, node.left);
167 }
168};
169
170var reserved = Object.create(null);
171'do if in for let new try var case else enum eval null this true void with await break catch class const false super throw while yield delete export import public return static switch typeof default extends finally package private continue debugger function arguments interface protected implements instanceof'
172 .split(' ')
173 .forEach(word => (reserved[word] = true));
174
175function Scope(options) {
176 options = options || {};
177
178 this.parent = options.parent;
179 this.isBlockScope = !!options.block;
180 this.createDeclarationCallback = options.declare;
181
182 var scope = this;
183 while (scope.isBlockScope) { scope = scope.parent; }
184 this.functionScope = scope;
185
186 this.identifiers = [];
187 this.declarations = Object.create(null);
188 this.references = Object.create(null);
189 this.blockScopedDeclarations = this.isBlockScope ? null : Object.create(null);
190 this.aliases = Object.create(null);
191}
192
193Scope.prototype = {
194 addDeclaration(node, kind) {
195 for (var i = 0, list = extractNames(node); i < list.length; i += 1) {
196 var identifier = list[i];
197
198 var name = identifier.name;
199
200 var declaration = { name, node: identifier, kind, instances: [] };
201 this.declarations[name] = declaration;
202
203 if (this.isBlockScope) {
204 if (!this.functionScope.blockScopedDeclarations[name])
205 { this.functionScope.blockScopedDeclarations[name] = []; }
206 this.functionScope.blockScopedDeclarations[name].push(declaration);
207 }
208 }
209 },
210
211 addReference(identifier) {
212 if (this.consolidated) {
213 this.consolidateReference(identifier);
214 } else {
215 this.identifiers.push(identifier);
216 }
217 },
218
219 consolidate() {
220 for (var i = 0; i < this.identifiers.length; i += 1) {
221 // we might push to the array during consolidation, so don't cache length
222 var identifier = this.identifiers[i];
223 this.consolidateReference(identifier);
224 }
225
226 this.consolidated = true; // TODO understand why this is necessary... seems bad
227 },
228
229 consolidateReference(identifier) {
230 var declaration = this.declarations[identifier.name];
231 if (declaration) {
232 declaration.instances.push(identifier);
233 } else {
234 this.references[identifier.name] = true;
235 if (this.parent) { this.parent.addReference(identifier); }
236 }
237 },
238
239 contains(name) {
240 return (
241 this.declarations[name] ||
242 (this.parent ? this.parent.contains(name) : false)
243 );
244 },
245
246 createIdentifier(base) {
247 if (typeof base === 'number') { base = base.toString(); }
248
249 base = base
250 .replace(/\s/g, '')
251 .replace(/\[([^\]]+)\]/g, '_$1')
252 .replace(/[^a-zA-Z0-9_$]/g, '_')
253 .replace(/_{2,}/, '_');
254
255 var name = base;
256 var counter = 1;
257
258 while (
259 this.declarations[name] ||
260 this.references[name] ||
261 this.aliases[name] ||
262 name in reserved
263 ) {
264 name = `${base}$${counter++}`;
265 }
266
267 this.aliases[name] = true;
268 return name;
269 },
270
271 createDeclaration(base) {
272 var id = this.createIdentifier(base);
273 this.createDeclarationCallback(id);
274 return id;
275 },
276
277 findDeclaration(name) {
278 return (
279 this.declarations[name] ||
280 (this.parent && this.parent.findDeclaration(name))
281 );
282 },
283
284 // Sometimes, block scope declarations change name during transpilation
285 resolveName(name) {
286 var declaration = this.findDeclaration(name);
287 return declaration ? declaration.name : name;
288 }
289};
290
291function locate(source, index) {
292 var lines = source.split('\n');
293 var len = lines.length;
294
295 var lineStart = 0;
296 var i;
297
298 for (i = 0; i < len; i += 1) {
299 var line = lines[i];
300 var lineEnd = lineStart + line.length + 1; // +1 for newline
301
302 if (lineEnd > index) {
303 return { line: i + 1, column: index - lineStart, char: i };
304 }
305
306 lineStart = lineEnd;
307 }
308
309 throw new Error('Could not determine location of character');
310}
311
312function pad(num, len) {
313 var result = String(num);
314 return result + repeat(' ', len - result.length);
315}
316
317function repeat(str, times) {
318 var result = '';
319 while (times--) { result += str; }
320 return result;
321}
322
323function getSnippet(source, loc, length) {
324 if ( length === void 0 ) length = 1;
325
326 var first = Math.max(loc.line - 5, 0);
327 var last = loc.line;
328
329 var numDigits = String(last).length;
330
331 var lines = source.split('\n').slice(first, last);
332
333 var lastLine = lines[lines.length - 1];
334 var offset = lastLine.slice(0, loc.column).replace(/\t/g, ' ').length;
335
336 var snippet = lines
337 .map((line, i) => `${pad(i + first + 1, numDigits)} : ${line.replace(/\t/g, ' ')}`)
338 .join('\n');
339
340 snippet += '\n' + repeat(' ', numDigits + 3 + offset) + repeat('^', length);
341
342 return snippet;
343}
344
345class CompileError extends Error {
346 constructor(message, node) {
347 super(message);
348
349 this.name = 'CompileError';
350 if (!node) {
351 return;
352 }
353
354 var source = node.program.magicString.original;
355 var loc = locate(source, node.start);
356
357 this.message = message + ` (${loc.line}:${loc.column})`;
358
359 this.stack = new Error().stack.replace(
360 new RegExp(`.+new ${this.name}.+\\n`, 'm'),
361 ''
362 );
363
364 this.loc = loc;
365 this.snippet = getSnippet(source, loc, node.end - node.start);
366 }
367
368 toString() {
369 return `${this.name}: ${this.message}\n${this.snippet}`;
370 }
371
372 static missingTransform(feature, transformKey, node, dangerousKey) {
373 if ( dangerousKey === void 0 ) dangerousKey = null;
374
375 var maybeDangerous = dangerousKey ? `, or \`transforms: { ${dangerousKey}: true }\` if you know what you're doing` : '';
376 throw new CompileError(`Transforming ${feature} is not ${dangerousKey ? "fully supported" : "implemented"}. Use \`transforms: { ${transformKey}: false }\` to skip transformation and disable this error${maybeDangerous}.`, node);
377 }
378}
379
380function findIndex(array, fn) {
381 for (var i = 0; i < array.length; i += 1) {
382 if (fn(array[i], i)) { return i; }
383 }
384
385 return -1;
386}
387
388var handlers = {
389 Identifier: destructureIdentifier,
390 AssignmentPattern: destructureAssignmentPattern,
391 ArrayPattern: destructureArrayPattern,
392 ObjectPattern: destructureObjectPattern
393};
394
395function destructure(
396 code,
397 createIdentifier,
398 resolveName,
399 node,
400 ref,
401 inline,
402 statementGenerators
403) {
404 handlers[node.type](code, createIdentifier, resolveName, node, ref, inline, statementGenerators);
405}
406
407function destructureIdentifier(
408 code,
409 createIdentifier,
410 resolveName,
411 node,
412 ref,
413 inline,
414 statementGenerators
415) {
416 statementGenerators.push((start, prefix, suffix) => {
417 code.overwrite(node.start, node.end, (inline ? prefix : `${prefix}var `) + resolveName(node) + ` = ${ref}${suffix}`);
418 code.move(node.start, node.end, start);
419 });
420}
421
422function destructureMemberExpression(
423 code,
424 createIdentifier,
425 resolveName,
426 node,
427 ref,
428 inline,
429 statementGenerators
430) {
431 statementGenerators.push((start, prefix, suffix) => {
432 code.prependRight(node.start, inline ? prefix : `${prefix}var `);
433 code.appendLeft(node.end, ` = ${ref}${suffix}`);
434 code.move(node.start, node.end, start);
435 });
436}
437
438function destructureAssignmentPattern(
439 code,
440 createIdentifier,
441 resolveName,
442 node,
443 ref,
444 inline,
445 statementGenerators
446) {
447 var isIdentifier = node.left.type === 'Identifier';
448 var name = isIdentifier ? node.left.name : ref;
449
450 if (!inline) {
451 statementGenerators.push((start, prefix, suffix) => {
452 code.prependRight(
453 node.left.end,
454 `${prefix}if ( ${name} === void 0 ) ${name}`
455 );
456 code.move(node.left.end, node.right.end, start);
457 code.appendLeft(node.right.end, suffix);
458 });
459 }
460
461 if (!isIdentifier) {
462 destructure(code, createIdentifier, resolveName, node.left, ref, inline, statementGenerators);
463 }
464}
465
466function destructureArrayPattern(
467 code,
468 createIdentifier,
469 resolveName,
470 node,
471 ref,
472 inline,
473 statementGenerators
474) {
475 var c = node.start;
476
477 node.elements.forEach((element, i) => {
478 if (!element) { return; }
479
480 if (element.type === 'RestElement') {
481 handleProperty(
482 code,
483 createIdentifier,
484 resolveName,
485 c,
486 element.argument,
487 `${ref}.slice(${i})`,
488 inline,
489 statementGenerators
490 );
491 } else {
492 handleProperty(
493 code,
494 createIdentifier,
495 resolveName,
496 c,
497 element,
498 `${ref}[${i}]`,
499 inline,
500 statementGenerators
501 );
502 }
503 c = element.end;
504 });
505
506 code.remove(c, node.end);
507}
508
509function destructureObjectPattern(
510 code,
511 createIdentifier,
512 resolveName,
513 node,
514 ref,
515 inline,
516 statementGenerators
517) {
518 var c = node.start;
519
520 var nonRestKeys = [];
521 node.properties.forEach(prop => {
522 var value;
523 var content;
524 if (prop.type === 'Property') {
525 content = prop.value;
526 if (!prop.computed && prop.key.type === 'Identifier') {
527 value = `${ref}.${prop.key.name}`;
528 nonRestKeys.push(`"${prop.key.name}"`);
529 } else if (!prop.computed && prop.key.type === 'Literal') {
530 value = `${ref}[${prop.key.raw}]`;
531 nonRestKeys.push(JSON.stringify(String(prop.key.value)));
532 } else {
533 var expr = code.slice(prop.key.start, prop.key.end);
534 value = `${ref}[${expr}]`;
535 nonRestKeys.push(`String(${expr})`);
536 }
537 } else if (prop.type === 'RestElement') {
538 content = prop.argument;
539 value = createIdentifier('rest');
540 statementGenerators.push((start, prefix, suffix) => {
541 var helper = prop.program.getObjectWithoutPropertiesHelper(code);
542 code.overwrite(
543 prop.start,
544 (c = prop.argument.start),
545 (inline ? prefix : `${prefix}var `) + `${value} = ${helper}( ${ref}, [${nonRestKeys.join(', ')}] )${suffix}`
546 );
547 code.move(prop.start, c, start);
548 });
549 } else {
550 throw new CompileError(
551 this,
552 `Unexpected node of type ${prop.type} in object pattern`
553 );
554 }
555 handleProperty(code, createIdentifier, resolveName, c, content, value, inline, statementGenerators);
556 c = prop.end;
557 });
558
559 code.remove(c, node.end);
560}
561
562function handleProperty(
563 code,
564 createIdentifier,
565 resolveName,
566 c,
567 node,
568 value,
569 inline,
570 statementGenerators
571) {
572 switch (node.type) {
573 case 'Identifier': {
574 code.remove(c, node.start);
575 destructureIdentifier(
576 code,
577 createIdentifier,
578 resolveName,
579 node,
580 value,
581 inline,
582 statementGenerators
583 );
584 break;
585 }
586
587 case 'MemberExpression':
588 code.remove(c, node.start);
589 destructureMemberExpression(
590 code,
591 createIdentifier,
592 resolveName,
593 node,
594 value,
595 true,
596 statementGenerators
597 );
598 break;
599
600 case 'AssignmentPattern': {
601 var name;
602
603 var isIdentifier = node.left.type === 'Identifier';
604
605 if (isIdentifier) {
606 name = resolveName(node.left);
607 } else {
608 name = createIdentifier(value);
609 }
610
611 statementGenerators.push((start, prefix, suffix) => {
612 if (inline) {
613 code.prependRight(
614 node.right.start,
615 `${name} = ${value}, ${name} = ${name} === void 0 ? `
616 );
617 code.appendLeft(node.right.end, ` : ${name}${suffix}`);
618 } else {
619 code.prependRight(
620 node.right.start,
621 `${prefix}var ${name} = ${value}; if ( ${name} === void 0 ) ${name} = `
622 );
623 code.appendLeft(node.right.end, suffix);
624 }
625
626 code.move(node.right.start, node.right.end, start);
627 });
628
629 if (isIdentifier) {
630 code.remove(c, node.right.start);
631 } else {
632 code.remove(c, node.left.start);
633 code.remove(node.left.end, node.right.start);
634 handleProperty(
635 code,
636 createIdentifier,
637 resolveName,
638 c,
639 node.left,
640 name,
641 inline,
642 statementGenerators
643 );
644 }
645
646 break;
647 }
648
649 case 'ObjectPattern': {
650 code.remove(c, (c = node.start));
651
652 var ref = value;
653 if (node.properties.length > 1) {
654 ref = createIdentifier(value);
655
656 statementGenerators.push((start, prefix, suffix) => {
657 // this feels a tiny bit hacky, but we can't do a
658 // straightforward appendLeft and keep correct order...
659 code.prependRight(node.start, (inline ? '' : `${prefix}var `) + `${ref} = `);
660 code.overwrite(node.start, (c = node.start + 1), value);
661 code.appendLeft(c, suffix);
662
663 code.overwrite(
664 node.start,
665 (c = node.start + 1),
666 (inline ? '' : `${prefix}var `) + `${ref} = ${value}${suffix}`
667 );
668 code.move(node.start, c, start);
669 });
670 }
671
672 destructureObjectPattern(
673 code,
674 createIdentifier,
675 resolveName,
676 node,
677 ref,
678 inline,
679 statementGenerators
680 );
681
682 break;
683 }
684
685 case 'ArrayPattern': {
686 code.remove(c, (c = node.start));
687
688 if (node.elements.filter(Boolean).length > 1) {
689 var ref$1 = createIdentifier(value);
690
691 statementGenerators.push((start, prefix, suffix) => {
692 code.prependRight(node.start, (inline ? '' : `${prefix}var `) + `${ref$1} = `);
693 code.overwrite(node.start, (c = node.start + 1), value, {
694 contentOnly: true
695 });
696 code.appendLeft(c, suffix);
697
698 code.move(node.start, c, start);
699 });
700
701 node.elements.forEach((element, i) => {
702 if (!element) { return; }
703
704 if (element.type === 'RestElement') {
705 handleProperty(
706 code,
707 createIdentifier,
708 resolveName,
709 c,
710 element.argument,
711 `${ref$1}.slice(${i})`,
712 inline,
713 statementGenerators
714 );
715 } else {
716 handleProperty(
717 code,
718 createIdentifier,
719 resolveName,
720 c,
721 element,
722 `${ref$1}[${i}]`,
723 inline,
724 statementGenerators
725 );
726 }
727 c = element.end;
728 });
729 } else {
730 var index = findIndex(node.elements, Boolean);
731 var element = node.elements[index];
732 if (element.type === 'RestElement') {
733 handleProperty(
734 code,
735 createIdentifier,
736 resolveName,
737 c,
738 element.argument,
739 `${value}.slice(${index})`,
740 inline,
741 statementGenerators
742 );
743 } else {
744 handleProperty(
745 code,
746 createIdentifier,
747 resolveName,
748 c,
749 element,
750 `${value}[${index}]`,
751 inline,
752 statementGenerators
753 );
754 }
755 c = element.end;
756 }
757
758 code.remove(c, node.end);
759 break;
760 }
761
762 default: {
763 throw new Error(`Unexpected node type in destructuring (${node.type})`);
764 }
765 }
766}
767
768function isUseStrict(node) {
769 if (!node) { return false; }
770 if (node.type !== 'ExpressionStatement') { return false; }
771 if (node.expression.type !== 'Literal') { return false; }
772 return node.expression.value === 'use strict';
773}
774
775class BlockStatement extends Node {
776 createScope() {
777 this.parentIsFunction = /Function/.test(this.parent.type);
778 this.isFunctionBlock = this.parentIsFunction || this.parent.type === 'Root';
779 this.scope = new Scope({
780 block: !this.isFunctionBlock,
781 parent: this.parent.findScope(false),
782 declare: id => this.createdDeclarations.push(id)
783 });
784
785 if (this.parentIsFunction) {
786 this.parent.params.forEach(node => {
787 this.scope.addDeclaration(node, 'param');
788 });
789 }
790 }
791
792 initialise(transforms) {
793 this.thisAlias = null;
794 this.argumentsAlias = null;
795 this.defaultParameters = [];
796 this.createdDeclarations = [];
797
798 // normally the scope gets created here, during initialisation,
799 // but in some cases (e.g. `for` statements), we need to create
800 // the scope early, as it pertains to both the init block and
801 // the body of the statement
802 if (!this.scope) { this.createScope(); }
803
804 this.body.forEach(node => node.initialise(transforms));
805
806 this.scope.consolidate();
807 }
808
809 findLexicalBoundary() {
810 if (this.type === 'Program') { return this; }
811 if (/^Function/.test(this.parent.type)) { return this; }
812
813 return this.parent.findLexicalBoundary();
814 }
815
816 findScope(functionScope) {
817 if (functionScope && !this.isFunctionBlock)
818 { return this.parent.findScope(functionScope); }
819 return this.scope;
820 }
821
822 getArgumentsAlias() {
823 if (!this.argumentsAlias) {
824 this.argumentsAlias = this.scope.createIdentifier('arguments');
825 }
826
827 return this.argumentsAlias;
828 }
829
830 getArgumentsArrayAlias() {
831 if (!this.argumentsArrayAlias) {
832 this.argumentsArrayAlias = this.scope.createIdentifier('argsArray');
833 }
834
835 return this.argumentsArrayAlias;
836 }
837
838 getThisAlias() {
839 if (!this.thisAlias) {
840 this.thisAlias = this.scope.createIdentifier('this');
841 }
842
843 return this.thisAlias;
844 }
845
846 getIndentation() {
847 if (this.indentation === undefined) {
848 var source = this.program.magicString.original;
849
850 var useOuter = this.synthetic || !this.body.length;
851 var c = useOuter ? this.start : this.body[0].start;
852
853 while (c && source[c] !== '\n') { c -= 1; }
854
855 this.indentation = '';
856
857 // eslint-disable-next-line no-constant-condition
858 while (true) {
859 c += 1;
860 var char = source[c];
861
862 if (char !== ' ' && char !== '\t') { break; }
863
864 this.indentation += char;
865 }
866
867 var indentString = this.program.magicString.getIndentString();
868
869 // account for dedented class constructors
870 var parent = this.parent;
871 while (parent) {
872 if (parent.kind === 'constructor' && !parent.parent.parent.superClass) {
873 this.indentation = this.indentation.replace(indentString, '');
874 }
875
876 parent = parent.parent;
877 }
878
879 if (useOuter) { this.indentation += indentString; }
880 }
881
882 return this.indentation;
883 }
884
885 transpile(code, transforms) {
886 var indentation = this.getIndentation();
887
888 var introStatementGenerators = [];
889
890 if (this.argumentsAlias) {
891 introStatementGenerators.push((start, prefix, suffix) => {
892 var assignment = `${prefix}var ${this.argumentsAlias} = arguments${
893 suffix
894 }`;
895 code.appendLeft(start, assignment);
896 });
897 }
898
899 if (this.thisAlias) {
900 introStatementGenerators.push((start, prefix, suffix) => {
901 var assignment = `${prefix}var ${this.thisAlias} = this${suffix}`;
902 code.appendLeft(start, assignment);
903 });
904 }
905
906 if (this.argumentsArrayAlias) {
907 introStatementGenerators.push((start, prefix, suffix) => {
908 var i = this.scope.createIdentifier('i');
909 var assignment = `${prefix}var ${i} = arguments.length, ${
910 this.argumentsArrayAlias
911 } = Array(${i});\n${indentation}while ( ${i}-- ) ${
912 this.argumentsArrayAlias
913 }[${i}] = arguments[${i}]${suffix}`;
914 code.appendLeft(start, assignment);
915 });
916 }
917
918 if (/Function/.test(this.parent.type)) {
919 this.transpileParameters(
920 this.parent.params,
921 code,
922 transforms,
923 indentation,
924 introStatementGenerators
925 );
926 } else if ('CatchClause' === this.parent.type) {
927 this.transpileParameters(
928 [this.parent.param],
929 code,
930 transforms,
931 indentation,
932 introStatementGenerators
933 );
934 }
935
936 if (transforms.letConst && this.isFunctionBlock) {
937 this.transpileBlockScopedIdentifiers(code);
938 }
939
940 super.transpile(code, transforms);
941
942 if (this.createdDeclarations.length) {
943 introStatementGenerators.push((start, prefix, suffix) => {
944 var assignment = `${prefix}var ${this.createdDeclarations.join(', ')}${suffix}`;
945 code.appendLeft(start, assignment);
946 });
947 }
948
949 if (this.synthetic) {
950 if (this.parent.type === 'ArrowFunctionExpression') {
951 var expr = this.body[0];
952
953 if (introStatementGenerators.length) {
954 code
955 .appendLeft(this.start, `{`)
956 .prependRight(this.end, `${this.parent.getIndentation()}}`);
957
958 code.prependRight(expr.start, `\n${indentation}return `);
959 code.appendLeft(expr.end, `;\n`);
960 } else if (transforms.arrow) {
961 code.prependRight(expr.start, `{ return `);
962 code.appendLeft(expr.end, `; }`);
963 }
964 } else if (introStatementGenerators.length) {
965 code.prependRight(this.start, `{`).appendLeft(this.end, `}`);
966 }
967 }
968
969 var start;
970 if (isUseStrict(this.body[0])) {
971 start = this.body[0].end;
972 } else if (this.synthetic || this.parent.type === 'Root') {
973 start = this.start;
974 } else {
975 start = this.start + 1;
976 }
977
978 var prefix = `\n${indentation}`;
979 var suffix = ';';
980 introStatementGenerators.forEach((fn, i) => {
981 if (i === introStatementGenerators.length - 1) { suffix = `;\n`; }
982 fn(start, prefix, suffix);
983 });
984 }
985
986 transpileParameters(params, code, transforms, indentation, introStatementGenerators) {
987 params.forEach(param => {
988 if (
989 param.type === 'AssignmentPattern' &&
990 param.left.type === 'Identifier'
991 ) {
992 if (transforms.defaultParameter) {
993 introStatementGenerators.push((start, prefix, suffix) => {
994 var lhs = `${prefix}if ( ${param.left.name} === void 0 ) ${
995 param.left.name
996 }`;
997
998 code
999 .prependRight(param.left.end, lhs)
1000 .move(param.left.end, param.right.end, start)
1001 .appendLeft(param.right.end, suffix);
1002 });
1003 }
1004 } else if (param.type === 'RestElement') {
1005 if (transforms.spreadRest) {
1006 introStatementGenerators.push((start, prefix, suffix) => {
1007 var penultimateParam = params[params.length - 2];
1008
1009 if (penultimateParam) {
1010 code.remove(
1011 penultimateParam ? penultimateParam.end : param.start,
1012 param.end
1013 );
1014 } else {
1015 var start$1 = param.start,
1016 end = param.end; // TODO https://gitlab.com/Rich-Harris/buble/issues/8
1017
1018 while (/\s/.test(code.original[start$1 - 1])) { start$1 -= 1; }
1019 while (/\s/.test(code.original[end])) { end += 1; }
1020
1021 code.remove(start$1, end);
1022 }
1023
1024 var name = param.argument.name;
1025 var len = this.scope.createIdentifier('len');
1026 var count = params.length - 1;
1027
1028 if (count) {
1029 code.prependRight(
1030 start,
1031 `${prefix}var ${name} = [], ${len} = arguments.length - ${
1032 count
1033 };\n${indentation}while ( ${len}-- > 0 ) ${name}[ ${
1034 len
1035 } ] = arguments[ ${len} + ${count} ]${suffix}`
1036 );
1037 } else {
1038 code.prependRight(
1039 start,
1040 `${prefix}var ${name} = [], ${len} = arguments.length;\n${
1041 indentation
1042 }while ( ${len}-- ) ${name}[ ${len} ] = arguments[ ${len} ]${
1043 suffix
1044 }`
1045 );
1046 }
1047 });
1048 }
1049 } else if (param.type !== 'Identifier') {
1050 if (transforms.parameterDestructuring) {
1051 var ref = this.scope.createIdentifier('ref');
1052 destructure(
1053 code,
1054 id => this.scope.createIdentifier(id),
1055 (ref) => {
1056 var name = ref.name;
1057
1058 return this.scope.resolveName(name);
1059 },
1060 param,
1061 ref,
1062 false,
1063 introStatementGenerators
1064 );
1065 code.prependRight(param.start, ref);
1066 }
1067 }
1068 });
1069 }
1070
1071 transpileBlockScopedIdentifiers(code) {
1072 Object.keys(this.scope.blockScopedDeclarations).forEach(name => {
1073 var declarations = this.scope.blockScopedDeclarations[name];
1074
1075 for (var i$2 = 0, list$2 = declarations; i$2 < list$2.length; i$2 += 1) {
1076 var declaration = list$2[i$2];
1077
1078 var cont = false; // TODO implement proper continue...
1079
1080 if (declaration.kind === 'for.let') {
1081 // special case
1082 var forStatement = declaration.node.findNearest('ForStatement');
1083
1084 if (forStatement.shouldRewriteAsFunction) {
1085 var outerAlias = this.scope.createIdentifier(name);
1086 var innerAlias = forStatement.reassigned[name]
1087 ? this.scope.createIdentifier(name)
1088 : name;
1089
1090 declaration.name = outerAlias;
1091 code.overwrite(
1092 declaration.node.start,
1093 declaration.node.end,
1094 outerAlias,
1095 { storeName: true }
1096 );
1097
1098 forStatement.aliases[name] = {
1099 outer: outerAlias,
1100 inner: innerAlias
1101 };
1102
1103 for (var i = 0, list = declaration.instances; i < list.length; i += 1) {
1104 var identifier = list[i];
1105
1106 var alias = forStatement.body.contains(identifier)
1107 ? innerAlias
1108 : outerAlias;
1109
1110 if (name !== alias) {
1111 code.overwrite(identifier.start, identifier.end, alias, {
1112 storeName: true
1113 });
1114 }
1115 }
1116
1117 cont = true;
1118 }
1119 }
1120
1121 if (!cont) {
1122 var alias$1 = this.scope.createIdentifier(name);
1123
1124 if (name !== alias$1) {
1125 var declarationParent = declaration.node.parent;
1126 declaration.name = alias$1;
1127 code.overwrite(
1128 declaration.node.start,
1129 declaration.node.end,
1130 alias$1,
1131 { storeName: true }
1132 );
1133 if (declarationParent.type === 'Property' && declarationParent.shorthand) {
1134 declarationParent.shorthand = false;
1135 code.prependLeft(declaration.node.start, `${name}: `);
1136 }
1137
1138 for (var i$1 = 0, list$1 = declaration.instances; i$1 < list$1.length; i$1 += 1) {
1139 var identifier$1 = list$1[i$1];
1140
1141 identifier$1.rewritten = true;
1142 var identifierParent = identifier$1.parent;
1143 code.overwrite(identifier$1.start, identifier$1.end, alias$1, {
1144 storeName: true
1145 });
1146 if (identifierParent.type === 'Property' && identifierParent.shorthand) {
1147 identifierParent.shorthand = false;
1148 code.prependLeft(identifier$1.start, `${name}: `);
1149 }
1150 }
1151 }
1152 }
1153 }
1154 });
1155 }
1156}
1157
1158function isArguments(node) {
1159 return node.type === 'Identifier' && node.name === 'arguments';
1160}
1161
1162function inlineSpreads(
1163 code,
1164 node,
1165 elements
1166) {
1167 var i = elements.length;
1168
1169 while (i--) {
1170 var element = elements[i];
1171 if (!element || element.type !== 'SpreadElement') {
1172 continue;
1173 }
1174 var argument = element.argument;
1175 if (argument.type !== 'ArrayExpression') {
1176 continue;
1177 }
1178 var subelements = argument.elements;
1179 if (subelements.some(subelement => subelement === null)) {
1180 // Not even going to try inlining spread arrays with holes.
1181 // It's a lot of work (got to be VERY careful in comma counting for
1182 // ArrayExpression, and turn blanks into undefined for
1183 // CallExpression and NewExpression), and probably literally no one
1184 // would ever benefit from it.
1185 continue;
1186 }
1187 // We can inline it: drop the `...[` and `]` and sort out any commas.
1188 var isLast = i === elements.length - 1;
1189 if (subelements.length === 0) {
1190 code.remove(
1191 isLast && i !== 0
1192 ? elements[i - 1].end // Take the previous comma too
1193 : element.start,
1194 isLast
1195 ? node.end - 1 // Must remove trailing comma; element.end wouldn’t
1196 : elements[i + 1].start);
1197 } else {
1198 // Strip the `...[` and the `]` with a possible trailing comma before it,
1199 // leaving just the possible trailing comma after it.
1200 code.remove(element.start, subelements[0].start);
1201 code.remove(
1202 // Strip a possible trailing comma after the last element
1203 subelements[subelements.length - 1].end,
1204 // And also a possible trailing comma after the spread
1205 isLast
1206 ? node.end - 1
1207 : element.end
1208 );
1209 }
1210 elements.splice.apply(elements, [ i, 1 ].concat( subelements ));
1211 i += subelements.length;
1212 }
1213}
1214
1215// Returns false if it’s safe to simply append a method call to the node,
1216// e.g. `a` → `a.concat()`.
1217//
1218// Returns true if it may not be and so parentheses should be employed,
1219// e.g. `a ? b : c` → `a ? b : c.concat()` would be wrong.
1220//
1221// This test may be overcautious; if desired it can be refined over time.
1222function needsParentheses(node) {
1223 switch (node.type) {
1224 // Currently whitelisted are all relevant ES5 node types ('Literal' and
1225 // 'ObjectExpression' are skipped as irrelevant for array/call spread.)
1226 case 'ArrayExpression':
1227 case 'CallExpression':
1228 case 'Identifier':
1229 case 'ParenthesizedExpression':
1230 case 'ThisExpression':
1231 return false;
1232 default:
1233 return true;
1234 }
1235}
1236
1237function spread(
1238 code,
1239 elements,
1240 start,
1241 argumentsArrayAlias,
1242 isNew
1243) {
1244 var i = elements.length;
1245 var firstSpreadIndex = -1;
1246
1247 while (i--) {
1248 var element$1 = elements[i];
1249 if (element$1 && element$1.type === 'SpreadElement') {
1250 if (isArguments(element$1.argument)) {
1251 code.overwrite(
1252 element$1.argument.start,
1253 element$1.argument.end,
1254 argumentsArrayAlias
1255 );
1256 }
1257
1258 firstSpreadIndex = i;
1259 }
1260 }
1261
1262 if (firstSpreadIndex === -1) { return false; } // false indicates no spread elements
1263
1264 if (isNew) {
1265 for (i = 0; i < elements.length; i += 1) {
1266 var element$2 = elements[i];
1267 if (element$2.type === 'SpreadElement') {
1268 code.remove(element$2.start, element$2.argument.start);
1269 } else {
1270 code.prependRight(element$2.start, '[');
1271 code.prependRight(element$2.end, ']');
1272 }
1273 }
1274
1275 return true; // true indicates some spread elements
1276 }
1277
1278 var element = elements[firstSpreadIndex];
1279 var previousElement = elements[firstSpreadIndex - 1];
1280
1281 if (!previousElement) {
1282 // We may need to parenthesize it to handle ternaries like [...a ? b : c].
1283 var addClosingParen;
1284 if (start !== element.start) {
1285 if ((addClosingParen = needsParentheses(element.argument))) {
1286 code.overwrite(start, element.start, '( ');
1287 } else {
1288 code.remove(start, element.start);
1289 }
1290 } else if (element.parent.type === 'CallExpression') {
1291 // CallExpression inserts `( ` itself, we add the ).
1292 // (Yeah, CallExpression did the needsParentheses call already,
1293 // but we don’t have its result handy, so do it again. It’s cheap.)
1294 addClosingParen = needsParentheses(element.argument);
1295 } else {
1296 // Should be unreachable, but doing this is more robust.
1297 throw new CompileError(
1298 'Unsupported spread construct, please raise an issue at https://github.com/bublejs/buble/issues',
1299 element
1300 );
1301 }
1302 code.overwrite(element.end, elements[1].start,
1303 addClosingParen ? ' ).concat( ' : '.concat( ');
1304 } else {
1305 code.overwrite(previousElement.end, element.start, ' ].concat( ');
1306 }
1307
1308 for (i = firstSpreadIndex; i < elements.length; i += 1) {
1309 element = elements[i];
1310
1311 if (element) {
1312 if (element.type === 'SpreadElement') {
1313 code.remove(element.start, element.argument.start);
1314 } else {
1315 code.appendLeft(element.start, '[');
1316 code.appendLeft(element.end, ']');
1317 }
1318 }
1319 }
1320
1321 return true; // true indicates some spread elements
1322}
1323
1324class ArrayExpression extends Node {
1325 initialise(transforms) {
1326 if (transforms.spreadRest && this.elements.length) {
1327 var lexicalBoundary = this.findLexicalBoundary();
1328
1329 var i = this.elements.length;
1330 while (i--) {
1331 var element = this.elements[i];
1332 if (
1333 element &&
1334 element.type === 'SpreadElement' &&
1335 isArguments(element.argument)
1336 ) {
1337 this.argumentsArrayAlias = lexicalBoundary.getArgumentsArrayAlias();
1338 }
1339 }
1340 }
1341
1342 super.initialise(transforms);
1343 }
1344
1345 transpile(code, transforms) {
1346 super.transpile(code, transforms);
1347
1348 if (transforms.spreadRest) {
1349 inlineSpreads(code, this, this.elements);
1350 // erase trailing comma after last array element if not an array hole
1351 if (this.elements.length) {
1352 var lastElement = this.elements[this.elements.length - 1];
1353 if (
1354 lastElement &&
1355 /\s*,/.test(code.original.slice(lastElement.end, this.end))
1356 ) {
1357 code.overwrite(lastElement.end, this.end - 1, ' ');
1358 }
1359 }
1360
1361 if (this.elements.length === 1) {
1362 var element = this.elements[0];
1363
1364 if (element && element.type === 'SpreadElement') {
1365 // special case – [ ...arguments ]
1366 if (isArguments(element.argument)) {
1367 code.overwrite(
1368 this.start,
1369 this.end,
1370 `[].concat( ${this.argumentsArrayAlias} )`
1371 ); // TODO if this is the only use of argsArray, don't bother concating
1372 } else {
1373 code.overwrite(this.start, element.argument.start, '[].concat( ');
1374 code.overwrite(element.end, this.end, ' )');
1375 }
1376 }
1377 } else {
1378 var hasSpreadElements = spread(
1379 code,
1380 this.elements,
1381 this.start,
1382 this.argumentsArrayAlias
1383 );
1384
1385 if (hasSpreadElements) {
1386 code.overwrite(this.end - 1, this.end, ')');
1387 }
1388 }
1389 }
1390 }
1391}
1392
1393function removeTrailingComma(code, c) {
1394 while (code.original[c] !== ')') {
1395 if (code.original[c] === ',') {
1396 code.remove(c, c + 1);
1397 return;
1398 }
1399
1400 if (code.original[c] === '/') {
1401 if (code.original[c + 1] === '/') {
1402 c = code.original.indexOf('\n', c);
1403 } else {
1404 c = code.original.indexOf('*/', c) + 1;
1405 }
1406 }
1407 c += 1;
1408 }
1409}
1410
1411class ArrowFunctionExpression extends Node {
1412 initialise(transforms) {
1413 if (this.async && transforms.asyncAwait) {
1414 CompileError.missingTransform("async arrow functions", "asyncAwait", this);
1415 }
1416 this.body.createScope();
1417 super.initialise(transforms);
1418 }
1419
1420 transpile(code, transforms) {
1421 var openParensPos = this.start;
1422 for (var end = (this.body || this.params[0]).start - 1; code.original[openParensPos] !== '(' && openParensPos < end;) {
1423 ++openParensPos;
1424 }
1425 if (code.original[openParensPos] !== '(') { openParensPos = -1; }
1426 var naked = openParensPos === -1;
1427
1428 if (transforms.arrow || this.needsArguments(transforms)) {
1429 // remove arrow
1430 var charIndex = this.body.start;
1431 while (code.original[charIndex] !== '=') {
1432 charIndex -= 1;
1433 }
1434 code.remove(charIndex, this.body.start);
1435
1436 super.transpile(code, transforms);
1437
1438 // wrap naked parameter
1439 if (naked) {
1440 code.prependRight(this.params[0].start, '(');
1441 code.appendLeft(this.params[0].end, ')');
1442 }
1443
1444 // standalone expression statement
1445 var standalone = this.parent && this.parent.type === 'ExpressionStatement';
1446 var start, text = standalone ? '!' : '';
1447 if (this.async) { text += 'async '; }
1448 text += 'function';
1449 if (!standalone) { text += ' '; }
1450 if (naked) {
1451 start = this.params[0].start;
1452 } else {
1453 start = openParensPos;
1454 }
1455 // add function
1456 if (start > this.start) {
1457 code.overwrite(this.start, start, text);
1458 } else {
1459 code.prependRight(this.start, text);
1460 }
1461 } else {
1462 super.transpile(code, transforms);
1463 }
1464
1465 if (transforms.trailingFunctionCommas && this.params.length && !naked) {
1466 removeTrailingComma(code, this.params[this.params.length - 1].end);
1467 }
1468 }
1469
1470 // Returns whether any transforms that will happen use `arguments`
1471 needsArguments(transforms) {
1472 return (
1473 transforms.spreadRest &&
1474 this.params.filter(param => param.type === 'RestElement').length > 0
1475 );
1476 }
1477}
1478
1479function checkConst(identifier, scope) {
1480 var declaration = scope.findDeclaration(identifier.name);
1481 if (declaration && declaration.kind === 'const') {
1482 throw new CompileError(`${identifier.name} is read-only`, identifier);
1483 }
1484}
1485
1486class AssignmentExpression extends Node {
1487 initialise(transforms) {
1488 if (this.left.type === 'Identifier') {
1489 var declaration = this.findScope(false).findDeclaration(this.left.name);
1490 // special case – https://gitlab.com/Rich-Harris/buble/issues/11
1491 var statement = declaration && declaration.node.ancestor(3);
1492 if (
1493 statement &&
1494 statement.type === 'ForStatement' &&
1495 statement.body.contains(this)
1496 ) {
1497 statement.reassigned[this.left.name] = true;
1498 }
1499 }
1500
1501 super.initialise(transforms);
1502 }
1503
1504 transpile(code, transforms) {
1505 if (this.left.type === 'Identifier') {
1506 // Do this check after everything has been initialized to find
1507 // shadowing declarations after this expression
1508 checkConst(this.left, this.findScope(false));
1509 }
1510
1511 if (this.operator === '**=' && transforms.exponentiation) {
1512 this.transpileExponentiation(code, transforms);
1513 } else if (/Pattern/.test(this.left.type) && transforms.destructuring) {
1514 this.transpileDestructuring(code);
1515 }
1516
1517 super.transpile(code, transforms);
1518 }
1519
1520 transpileDestructuring(code) {
1521 var writeScope = this.findScope(true);
1522 var lookupScope = this.findScope(false);
1523 var assign = writeScope.createDeclaration('assign');
1524 code.appendRight(this.left.end, `(${assign}`);
1525
1526 code.appendLeft(this.right.end, ', ');
1527 var statementGenerators = [];
1528 destructure(
1529 code,
1530 id => writeScope.createDeclaration(id),
1531 node => {
1532 var name = lookupScope.resolveName(node.name);
1533 checkConst(node, lookupScope);
1534 return name;
1535 },
1536 this.left,
1537 assign,
1538 true,
1539 statementGenerators
1540 );
1541
1542 var suffix = ', ';
1543 statementGenerators.forEach((fn, j) => {
1544 if (j === statementGenerators.length - 1) {
1545 suffix = '';
1546 }
1547
1548 fn(this.end, '', suffix);
1549 });
1550
1551 if (this.unparenthesizedParent().type === 'ExpressionStatement') {
1552 // no rvalue needed for expression statement
1553 code.prependRight(this.end, `)`);
1554 } else {
1555 // destructuring is part of an expression - need an rvalue
1556 code.appendRight(this.end, `, ${assign})`);
1557 }
1558 }
1559
1560 transpileExponentiation(code) {
1561 var scope = this.findScope(false);
1562
1563 // first, the easy part – `**=` -> `=`
1564 var charIndex = this.left.end;
1565 while (code.original[charIndex] !== '*') { charIndex += 1; }
1566 code.remove(charIndex, charIndex + 2);
1567
1568 // how we do the next part depends on a number of factors – whether
1569 // this is a top-level statement, and whether we're updating a
1570 // simple or complex reference
1571 var base;
1572
1573 var left = this.left.unparenthesize();
1574
1575 if (left.type === 'Identifier') {
1576 base = scope.resolveName(left.name);
1577 } else if (left.type === 'MemberExpression') {
1578 var object;
1579 var needsObjectVar = false;
1580 var property;
1581 var needsPropertyVar = false;
1582
1583 var statement = this.findNearest(/(?:Statement|Declaration)$/);
1584 var i0 = statement.getIndentation();
1585
1586 if (left.property.type === 'Identifier') {
1587 property = left.computed
1588 ? scope.resolveName(left.property.name)
1589 : left.property.name;
1590 } else {
1591 property = scope.createDeclaration('property');
1592 needsPropertyVar = true;
1593 }
1594
1595 if (left.object.type === 'Identifier') {
1596 object = scope.resolveName(left.object.name);
1597 } else {
1598 object = scope.createDeclaration('object');
1599 needsObjectVar = true;
1600 }
1601
1602 if (left.start === statement.start) {
1603 if (needsObjectVar && needsPropertyVar) {
1604 code.prependRight(statement.start, `${object} = `);
1605 code.overwrite(
1606 left.object.end,
1607 left.property.start,
1608 `;\n${i0}${property} = `
1609 );
1610 code.overwrite(
1611 left.property.end,
1612 left.end,
1613 `;\n${i0}${object}[${property}]`
1614 );
1615 } else if (needsObjectVar) {
1616 code.prependRight(statement.start, `${object} = `);
1617 code.appendLeft(left.object.end, `;\n${i0}`);
1618 code.appendLeft(left.object.end, object);
1619 } else if (needsPropertyVar) {
1620 code.prependRight(left.property.start, `${property} = `);
1621 code.appendLeft(left.property.end, `;\n${i0}`);
1622 code.move(left.property.start, left.property.end, this.start);
1623
1624 code.appendLeft(left.object.end, `[${property}]`);
1625 code.remove(left.object.end, left.property.start);
1626 code.remove(left.property.end, left.end);
1627 }
1628 } else {
1629 if (needsObjectVar && needsPropertyVar) {
1630 code.prependRight(left.start, `( ${object} = `);
1631 code.overwrite(
1632 left.object.end,
1633 left.property.start,
1634 `, ${property} = `
1635 );
1636 code.overwrite(
1637 left.property.end,
1638 left.end,
1639 `, ${object}[${property}]`
1640 );
1641 } else if (needsObjectVar) {
1642 code.prependRight(left.start, `( ${object} = `);
1643 code.appendLeft(left.object.end, `, ${object}`);
1644 } else if (needsPropertyVar) {
1645 code.prependRight(left.property.start, `( ${property} = `);
1646 code.appendLeft(left.property.end, `, `);
1647 code.move(left.property.start, left.property.end, left.start);
1648
1649 code.overwrite(left.object.end, left.property.start, `[${property}]`);
1650 code.remove(left.property.end, left.end);
1651 }
1652
1653 if (needsPropertyVar) {
1654 code.appendLeft(this.end, ` )`);
1655 }
1656 }
1657
1658 base =
1659 object +
1660 (left.computed || needsPropertyVar ? `[${property}]` : `.${property}`);
1661 }
1662
1663 code.prependRight(this.right.start, `Math.pow( ${base}, `);
1664 code.appendLeft(this.right.end, ` )`);
1665 }
1666}
1667
1668class AwaitExpression extends Node {
1669 initialise(transforms) {
1670 if (transforms.asyncAwait) {
1671 CompileError.missingTransform("await", "asyncAwait", this);
1672 }
1673 super.initialise(transforms);
1674 }
1675}
1676
1677class BinaryExpression extends Node {
1678 transpile(code, transforms) {
1679 if (this.operator === '**' && transforms.exponentiation) {
1680 code.prependRight(this.start, `Math.pow( `);
1681 code.overwrite(this.left.end, this.right.start, `, `);
1682 code.appendLeft(this.end, ` )`);
1683 }
1684 super.transpile(code, transforms);
1685 }
1686}
1687
1688var loopStatement = /(?:For(?:In|Of)?|While)Statement/;
1689
1690class BreakStatement extends Node {
1691 initialise() {
1692 var loop = this.findNearest(loopStatement);
1693 var switchCase = this.findNearest('SwitchCase');
1694
1695 if (loop && (!switchCase || loop.depth > switchCase.depth)) {
1696 loop.canBreak = true;
1697 this.loop = loop;
1698 }
1699 }
1700
1701 transpile(code) {
1702 if (this.loop && this.loop.shouldRewriteAsFunction) {
1703 if (this.label)
1704 { throw new CompileError(
1705 'Labels are not currently supported in a loop with locally-scoped variables',
1706 this
1707 ); }
1708 code.overwrite(this.start, this.start + 5, `return 'break'`);
1709 }
1710 }
1711}
1712
1713class CallExpression extends Node {
1714 initialise(transforms) {
1715 if (transforms.spreadRest && this.arguments.length > 1) {
1716 var lexicalBoundary = this.findLexicalBoundary();
1717
1718 var i = this.arguments.length;
1719 while (i--) {
1720 var arg = this.arguments[i];
1721 if (arg.type === 'SpreadElement' && isArguments(arg.argument)) {
1722 this.argumentsArrayAlias = lexicalBoundary.getArgumentsArrayAlias();
1723 }
1724 }
1725 }
1726
1727 super.initialise(transforms);
1728 }
1729
1730 transpile(code, transforms) {
1731 if (transforms.spreadRest && this.arguments.length) {
1732 inlineSpreads(code, this, this.arguments);
1733 // this.arguments.length may have changed, must retest.
1734 }
1735
1736 if (transforms.spreadRest && this.arguments.length) {
1737 var hasSpreadElements = false;
1738 var context;
1739
1740 var firstArgument = this.arguments[0];
1741
1742 if (this.arguments.length === 1) {
1743 if (firstArgument.type === 'SpreadElement') {
1744 code.remove(firstArgument.start, firstArgument.argument.start);
1745 hasSpreadElements = true;
1746 }
1747 } else {
1748 hasSpreadElements = spread(
1749 code,
1750 this.arguments,
1751 firstArgument.start,
1752 this.argumentsArrayAlias
1753 );
1754 }
1755
1756 if (hasSpreadElements) {
1757 // we need to handle super() and super.method() differently
1758 // due to its instance
1759 var _super = null;
1760 if (this.callee.type === 'Super') {
1761 _super = this.callee;
1762 } else if (
1763 this.callee.type === 'MemberExpression' &&
1764 this.callee.object.type === 'Super'
1765 ) {
1766 _super = this.callee.object;
1767 }
1768
1769 if (!_super && this.callee.type === 'MemberExpression') {
1770 if (this.callee.object.type === 'Identifier') {
1771 context = this.callee.object.name;
1772 } else {
1773 context = this.findScope(true).createDeclaration('ref');
1774 var callExpression = this.callee.object;
1775 code.prependRight(callExpression.start, `(${context} = `);
1776 code.appendLeft(callExpression.end, `)`);
1777 }
1778 } else {
1779 context = 'void 0';
1780 }
1781
1782 code.appendLeft(this.callee.end, '.apply');
1783
1784 if (_super) {
1785 _super.noCall = true; // bit hacky...
1786
1787 if (this.arguments.length > 1) {
1788 if (firstArgument.type === 'SpreadElement') {
1789 if (needsParentheses(firstArgument.argument)) {
1790 code.prependRight(firstArgument.start, `( `);
1791 }
1792 } else {
1793 code.prependRight(firstArgument.start, `[ `);
1794 }
1795
1796 code.appendLeft(
1797 this.arguments[this.arguments.length - 1].end,
1798 ' )'
1799 );
1800 }
1801 } else if (this.arguments.length === 1) {
1802 code.prependRight(firstArgument.start, `${context}, `);
1803 } else {
1804 if (firstArgument.type === 'SpreadElement') {
1805 if (needsParentheses(firstArgument.argument)) {
1806 code.appendLeft(firstArgument.start, `${context}, ( `);
1807 } else {
1808 code.appendLeft(firstArgument.start, `${context}, `);
1809 }
1810 } else {
1811 code.appendLeft(firstArgument.start, `${context}, [ `);
1812 }
1813
1814 code.appendLeft(this.arguments[this.arguments.length - 1].end, ' )');
1815 }
1816 }
1817 }
1818
1819 if (transforms.trailingFunctionCommas && this.arguments.length) {
1820 removeTrailingComma(code, this.arguments[this.arguments.length - 1].end);
1821 }
1822
1823 super.transpile(code, transforms);
1824 }
1825}
1826
1827class CatchClause extends Node {
1828 initialise(transforms) {
1829 this.createdDeclarations = [];
1830 this.scope = new Scope({
1831 block: true,
1832 parent: this.parent.findScope(false),
1833 declare: id => this.createdDeclarations.push(id)
1834 });
1835
1836 this.scope.addDeclaration(this.param, 'catch');
1837
1838 super.initialise(transforms);
1839 this.scope.consolidate();
1840 }
1841
1842 findScope(functionScope) {
1843 return functionScope
1844 ? this.parent.findScope(functionScope)
1845 : this.scope;
1846 }
1847}
1848
1849// TODO this code is pretty wild, tidy it up
1850class ClassBody extends Node {
1851 transpile(code, transforms, inFunctionExpression, superName) {
1852 if (transforms.classes) {
1853 var name = this.parent.name;
1854
1855 var indentStr = code.getIndentString();
1856 var i0 =
1857 this.getIndentation() + (inFunctionExpression ? indentStr : '');
1858 var i1 = i0 + indentStr;
1859
1860 var constructorIndex = findIndex(
1861 this.body,
1862 node => node.kind === 'constructor'
1863 );
1864 var constructor = this.body[constructorIndex];
1865
1866 var introBlock = '';
1867 var outroBlock = '';
1868
1869 if (this.body.length) {
1870 code.remove(this.start, this.body[0].start);
1871 code.remove(this.body[this.body.length - 1].end, this.end);
1872 } else {
1873 code.remove(this.start, this.end);
1874 }
1875
1876 if (constructor) {
1877 constructor.value.body.isConstructorBody = true;
1878
1879 var previousMethod = this.body[constructorIndex - 1];
1880 var nextMethod = this.body[constructorIndex + 1];
1881
1882 // ensure constructor is first
1883 if (constructorIndex > 0) {
1884 code.remove(previousMethod.end, constructor.start);
1885 code.move(
1886 constructor.start,
1887 nextMethod ? nextMethod.start : this.end - 1,
1888 this.body[0].start
1889 );
1890 }
1891
1892 if (!inFunctionExpression) { code.appendLeft(constructor.end, ';'); }
1893 }
1894
1895 var namedFunctions =
1896 this.program.options.namedFunctionExpressions !== false;
1897 var namedConstructor =
1898 namedFunctions ||
1899 this.parent.superClass ||
1900 this.parent.type !== 'ClassDeclaration';
1901 if (this.parent.superClass) {
1902 var inheritanceBlock = `if ( ${superName} ) ${name}.__proto__ = ${
1903 superName
1904 };\n${i0}${name}.prototype = Object.create( ${superName} && ${
1905 superName
1906 }.prototype );\n${i0}${name}.prototype.constructor = ${name};`;
1907
1908 if (constructor) {
1909 introBlock += `\n\n${i0}` + inheritanceBlock;
1910 } else {
1911 var fn =
1912 `function ${name} () {` +
1913 (superName
1914 ? `\n${i1}${superName}.apply(this, arguments);\n${i0}}`
1915 : `}`) +
1916 (inFunctionExpression ? '' : ';') +
1917 (this.body.length ? `\n\n${i0}` : '');
1918
1919 inheritanceBlock = fn + inheritanceBlock;
1920 introBlock += inheritanceBlock + `\n\n${i0}`;
1921 }
1922 } else if (!constructor) {
1923 var fn$1 = 'function ' + (namedConstructor ? name + ' ' : '') + '() {}';
1924 if (this.parent.type === 'ClassDeclaration') { fn$1 += ';'; }
1925 if (this.body.length) { fn$1 += `\n\n${i0}`; }
1926
1927 introBlock += fn$1;
1928 }
1929
1930 var scope = this.findScope(false);
1931
1932 var prototypeGettersAndSetters = [];
1933 var staticGettersAndSetters = [];
1934 var prototypeAccessors;
1935 var staticAccessors;
1936
1937 this.body.forEach((method, i) => {
1938 if ((method.kind === 'get' || method.kind === 'set') && transforms.getterSetter) {
1939 CompileError.missingTransform("getters and setters", "getterSetter", method);
1940 }
1941
1942 if (method.kind === 'constructor') {
1943 var constructorName = namedConstructor ? ' ' + name : '';
1944 code.overwrite(
1945 method.key.start,
1946 method.key.end,
1947 `function${constructorName}`
1948 );
1949 return;
1950 }
1951
1952 if (method.static) {
1953 var len = code.original[method.start + 6] == ' ' ? 7 : 6;
1954 code.remove(method.start, method.start + len);
1955 }
1956
1957 var isAccessor = method.kind !== 'method';
1958 var lhs;
1959
1960 var methodName = method.key.name;
1961 if (
1962 reserved[methodName] ||
1963 method.value.body.scope.references[methodName]
1964 ) {
1965 methodName = scope.createIdentifier(methodName);
1966 }
1967
1968 // when method name is a string or a number let's pretend it's a computed method
1969
1970 var fake_computed = false;
1971 if (!method.computed && method.key.type === 'Literal') {
1972 fake_computed = true;
1973 method.computed = true;
1974 }
1975
1976 if (isAccessor) {
1977 if (method.computed) {
1978 throw new Error(
1979 'Computed accessor properties are not currently supported'
1980 );
1981 }
1982
1983 code.remove(method.start, method.key.start);
1984
1985 if (method.static) {
1986 if (!~staticGettersAndSetters.indexOf(method.key.name))
1987 { staticGettersAndSetters.push(method.key.name); }
1988 if (!staticAccessors)
1989 { staticAccessors = scope.createIdentifier('staticAccessors'); }
1990
1991 lhs = `${staticAccessors}`;
1992 } else {
1993 if (!~prototypeGettersAndSetters.indexOf(method.key.name))
1994 { prototypeGettersAndSetters.push(method.key.name); }
1995 if (!prototypeAccessors)
1996 { prototypeAccessors = scope.createIdentifier('prototypeAccessors'); }
1997
1998 lhs = `${prototypeAccessors}`;
1999 }
2000 } else {
2001 lhs = method.static ? `${name}` : `${name}.prototype`;
2002 }
2003
2004 if (!method.computed) { lhs += '.'; }
2005
2006 var insertNewlines =
2007 (constructorIndex > 0 && i === constructorIndex + 1) ||
2008 (i === 0 && constructorIndex === this.body.length - 1);
2009
2010 if (insertNewlines) { lhs = `\n\n${i0}${lhs}`; }
2011
2012 var c = method.key.end;
2013 if (method.computed) {
2014 if (fake_computed) {
2015 code.prependRight(method.key.start, '[');
2016 code.appendLeft(method.key.end, ']');
2017 } else {
2018 while (code.original[c] !== ']') { c += 1; }
2019 c += 1;
2020 }
2021 }
2022
2023 var funcName =
2024 method.computed || isAccessor || !namedFunctions
2025 ? ''
2026 : `${methodName} `;
2027 var rhs =
2028 (isAccessor ? `.${method.kind}` : '') +
2029 ` = ${method.value.async ? 'async ' : ''}function` +
2030 (method.value.generator ? '* ' : ' ') +
2031 funcName;
2032 code.remove(c, method.value.start);
2033 code.prependRight(method.value.start, rhs);
2034 code.appendLeft(method.end, ';');
2035
2036 if (method.value.generator) { code.remove(method.start, method.key.start); }
2037
2038 var start = method.key.start;
2039 if (method.computed && !fake_computed) {
2040 while (code.original[start] != '[') {
2041 --start;
2042 }
2043 }
2044 if (method.start < start) {
2045 code.overwrite(method.start, start, lhs);
2046 } else {
2047 code.prependRight(method.start, lhs);
2048 }
2049 });
2050
2051 if (prototypeGettersAndSetters.length || staticGettersAndSetters.length) {
2052 var intro = [];
2053 var outro = [];
2054
2055 if (prototypeGettersAndSetters.length) {
2056 intro.push(
2057 `var ${prototypeAccessors} = { ${prototypeGettersAndSetters
2058 .map(name => `${name}: { configurable: true }`)
2059 .join(',')} };`
2060 );
2061 outro.push(
2062 `Object.defineProperties( ${name}.prototype, ${
2063 prototypeAccessors
2064 } );`
2065 );
2066 }
2067
2068 if (staticGettersAndSetters.length) {
2069 intro.push(
2070 `var ${staticAccessors} = { ${staticGettersAndSetters
2071 .map(name => `${name}: { configurable: true }`)
2072 .join(',')} };`
2073 );
2074 outro.push(`Object.defineProperties( ${name}, ${staticAccessors} );`);
2075 }
2076
2077 if (constructor) { introBlock += `\n\n${i0}`; }
2078 introBlock += intro.join(`\n${i0}`);
2079 if (!constructor) { introBlock += `\n\n${i0}`; }
2080
2081 outroBlock += `\n\n${i0}` + outro.join(`\n${i0}`);
2082 }
2083
2084 if (constructor) {
2085 code.appendLeft(constructor.end, introBlock);
2086 } else {
2087 code.prependRight(this.start, introBlock);
2088 }
2089
2090 code.appendLeft(this.end, outroBlock);
2091 }
2092
2093 super.transpile(code, transforms);
2094 }
2095}
2096
2097// TODO this function is slightly flawed – it works on the original string,
2098// not its current edited state.
2099// That's not a problem for the way that it's currently used, but it could
2100// be in future...
2101function deindent(node, code) {
2102 var start = node.start;
2103 var end = node.end;
2104
2105 var indentStr = code.getIndentString();
2106 var indentStrLen = indentStr.length;
2107 var indentStart = start - indentStrLen;
2108
2109 if (
2110 !node.program.indentExclusions[indentStart] &&
2111 code.original.slice(indentStart, start) === indentStr
2112 ) {
2113 code.remove(indentStart, start);
2114 }
2115
2116 var pattern = new RegExp(indentStr + '\\S', 'g');
2117 var slice = code.original.slice(start, end);
2118 var match;
2119
2120 while ((match = pattern.exec(slice))) {
2121 var removeStart = start + match.index;
2122 if (!node.program.indentExclusions[removeStart]) {
2123 code.remove(removeStart, removeStart + indentStrLen);
2124 }
2125 }
2126}
2127
2128class ClassDeclaration extends Node {
2129 initialise(transforms) {
2130 if (this.id) {
2131 this.name = this.id.name;
2132 this.findScope(true).addDeclaration(this.id, 'class');
2133 } else {
2134 this.name = this.findScope(true).createIdentifier("defaultExport");
2135 }
2136
2137 super.initialise(transforms);
2138 }
2139
2140 transpile(code, transforms) {
2141 if (transforms.classes) {
2142 if (!this.superClass) { deindent(this.body, code); }
2143
2144 var superName =
2145 this.superClass && (this.superClass.name || 'superclass');
2146
2147 var i0 = this.getIndentation();
2148 var i1 = i0 + code.getIndentString();
2149
2150 // if this is an export default statement, we have to move the export to
2151 // after the declaration, because `export default var Foo = ...` is illegal
2152 var isExportDefaultDeclaration = this.parent.type === 'ExportDefaultDeclaration';
2153
2154 if (isExportDefaultDeclaration) {
2155 code.remove(this.parent.start, this.start);
2156 }
2157
2158 var c = this.start;
2159 if (this.id) {
2160 code.overwrite(c, this.id.start, 'var ');
2161 c = this.id.end;
2162 } else {
2163 code.prependLeft(c, `var ${this.name}`);
2164 }
2165
2166 if (this.superClass) {
2167 if (this.superClass.end === this.body.start) {
2168 code.remove(c, this.superClass.start);
2169 code.appendLeft(c, ` = /*@__PURE__*/(function (${superName}) {\n${i1}`);
2170 } else {
2171 code.overwrite(c, this.superClass.start, ' = ');
2172 code.overwrite(
2173 this.superClass.end,
2174 this.body.start,
2175 `/*@__PURE__*/(function (${superName}) {\n${i1}`
2176 );
2177 }
2178 } else {
2179 if (c === this.body.start) {
2180 code.appendLeft(c, ' = ');
2181 } else {
2182 code.overwrite(c, this.body.start, ' = ');
2183 }
2184 }
2185
2186 this.body.transpile(code, transforms, !!this.superClass, superName);
2187
2188 var syntheticDefaultExport =
2189 isExportDefaultDeclaration
2190 ? `\n\n${i0}export default ${this.name};`
2191 : '';
2192 if (this.superClass) {
2193 code.appendLeft(this.end, `\n\n${i1}return ${this.name};\n${i0}}(`);
2194 code.move(this.superClass.start, this.superClass.end, this.end);
2195 code.prependRight(this.end, `));${syntheticDefaultExport}`);
2196 } else if (syntheticDefaultExport) {
2197 code.prependRight(this.end, syntheticDefaultExport);
2198 }
2199 } else {
2200 this.body.transpile(code, transforms, false, null);
2201 }
2202 }
2203}
2204
2205class ClassExpression extends Node {
2206 initialise(transforms) {
2207 this.name = (this.id
2208 ? this.id.name
2209 : this.parent.type === 'VariableDeclarator'
2210 ? this.parent.id.name
2211 : this.parent.type !== 'AssignmentExpression'
2212 ? null
2213 : this.parent.left.type === 'Identifier'
2214 ? this.parent.left.name
2215 : this.parent.left.type === 'MemberExpression'
2216 ? this.parent.left.property.name
2217 : null) || this.findScope(true).createIdentifier('anonymous');
2218
2219 super.initialise(transforms);
2220 }
2221
2222 transpile(code, transforms) {
2223 if (transforms.classes) {
2224 var superName = this.superClass && (this.superClass.name || 'superclass');
2225 if (superName === this.name) {
2226 superName = this.findScope(true).createIdentifier(this.name);
2227 }
2228
2229 var i0 = this.getIndentation();
2230 var i1 = i0 + code.getIndentString();
2231
2232 if (this.superClass) {
2233 code.remove(this.start, this.superClass.start);
2234 code.remove(this.superClass.end, this.body.start);
2235 code.appendRight(this.start, `/*@__PURE__*/(function (${superName}) {\n${i1}`);
2236 } else {
2237 code.overwrite(this.start, this.body.start, `/*@__PURE__*/(function () {\n${i1}`);
2238 }
2239
2240 this.body.transpile(code, transforms, true, superName);
2241
2242 var superClass = '';
2243 if (this.superClass) {
2244 superClass = code.slice(this.superClass.start, this.superClass.end);
2245 code.remove(this.superClass.start, this.superClass.end);
2246 }
2247 code.appendLeft(this.end, `\n\n${i1}return ${this.name};\n${i0}}(${superClass}))`);
2248 } else {
2249 this.body.transpile(code, transforms, false);
2250 }
2251 }
2252}
2253
2254class ContinueStatement extends Node {
2255 transpile(code) {
2256 var loop = this.findNearest(loopStatement);
2257 if (loop.shouldRewriteAsFunction) {
2258 if (this.label)
2259 { throw new CompileError(
2260 'Labels are not currently supported in a loop with locally-scoped variables',
2261 this
2262 ); }
2263 code.overwrite(this.start, this.start + 8, 'return');
2264 }
2265 }
2266}
2267
2268class ExportDefaultDeclaration extends Node {
2269 initialise(transforms) {
2270 if (transforms.moduleExport)
2271 { CompileError.missingTransform("export", "moduleExport", this); }
2272 super.initialise(transforms);
2273 }
2274}
2275
2276class ExportNamedDeclaration extends Node {
2277 initialise(transforms) {
2278 if (transforms.moduleExport)
2279 { CompileError.missingTransform("export", "moduleExport", this); }
2280 super.initialise(transforms);
2281 }
2282}
2283
2284class LoopStatement extends Node {
2285 findScope(functionScope) {
2286 return functionScope || !this.createdScope
2287 ? this.parent.findScope(functionScope)
2288 : this.body.scope;
2289 }
2290
2291 initialise(transforms) {
2292 this.body.createScope();
2293 this.createdScope = true;
2294
2295 // this is populated as and when reassignments occur
2296 this.reassigned = Object.create(null);
2297 this.aliases = Object.create(null);
2298
2299 this.thisRefs = [];
2300
2301 super.initialise(transforms);
2302 if (this.scope) {
2303 this.scope.consolidate();
2304 }
2305
2306 var declarations = Object.assign({}, this.body.scope.declarations);
2307 if (this.scope) {
2308 Object.assign(declarations, this.scope.declarations);
2309 }
2310
2311 if (transforms.letConst) {
2312 // see if any block-scoped declarations are referenced
2313 // inside function expressions
2314 var names = Object.keys(declarations);
2315
2316 var i = names.length;
2317 while (i--) {
2318 var name = names[i];
2319 var declaration = declarations[name];
2320
2321 var j = declaration.instances.length;
2322 while (j--) {
2323 var instance = declaration.instances[j];
2324 var nearestFunctionExpression = instance.findNearest(/Function/);
2325
2326 if (
2327 nearestFunctionExpression &&
2328 nearestFunctionExpression.depth > this.depth
2329 ) {
2330 this.shouldRewriteAsFunction = true;
2331 for (var i$1 = 0, list = this.thisRefs; i$1 < list.length; i$1 += 1) {
2332 var node = list[i$1];
2333
2334 node.alias = node.alias || node.findLexicalBoundary().getThisAlias();
2335 }
2336 break;
2337 }
2338 }
2339
2340 if (this.shouldRewriteAsFunction) { break; }
2341 }
2342 }
2343 }
2344
2345 transpile(code, transforms) {
2346 var needsBlock =
2347 this.type != 'ForOfStatement' &&
2348 (this.body.type !== 'BlockStatement' ||
2349 (this.body.type === 'BlockStatement' && this.body.synthetic));
2350
2351 if (this.shouldRewriteAsFunction) {
2352 var i0 = this.getIndentation();
2353 var i1 = i0 + code.getIndentString();
2354
2355 var argString = this.args ? ` ${this.args.join(', ')} ` : '';
2356 var paramString = this.params ? ` ${this.params.join(', ')} ` : '';
2357
2358 var functionScope = this.findScope(true);
2359 var loop = functionScope.createIdentifier('loop');
2360
2361 var before =
2362 `var ${loop} = function (${paramString}) ` +
2363 (this.body.synthetic ? `{\n${i0}${code.getIndentString()}` : '');
2364 var after = (this.body.synthetic ? `\n${i0}}` : '') + `;\n\n${i0}`;
2365
2366 code.prependRight(this.body.start, before);
2367 code.appendLeft(this.body.end, after);
2368 code.move(this.start, this.body.start, this.body.end);
2369
2370 if (this.canBreak || this.canReturn) {
2371 var returned = functionScope.createIdentifier('returned');
2372
2373 var insert = `{\n${i1}var ${returned} = ${loop}(${argString});\n`;
2374 if (this.canBreak)
2375 { insert += `\n${i1}if ( ${returned} === 'break' ) break;`; }
2376 if (this.canReturn)
2377 { insert += `\n${i1}if ( ${returned} ) return ${returned}.v;`; }
2378 insert += `\n${i0}}`;
2379
2380 code.prependRight(this.body.end, insert);
2381 } else {
2382 var callExpression = `${loop}(${argString});`;
2383
2384 if (this.type === 'DoWhileStatement') {
2385 code.overwrite(
2386 this.start,
2387 this.body.start,
2388 `do {\n${i1}${callExpression}\n${i0}}`
2389 );
2390 } else {
2391 code.prependRight(this.body.end, callExpression);
2392 }
2393 }
2394 } else if (needsBlock) {
2395 code.appendLeft(this.body.start, '{ ');
2396 code.prependRight(this.body.end, ' }');
2397 }
2398
2399 super.transpile(code, transforms);
2400 }
2401}
2402
2403class ForStatement extends LoopStatement {
2404 initialise(transforms) {
2405 this.createdDeclarations = [];
2406
2407 this.scope = new Scope({
2408 block: true,
2409 parent: this.parent.findScope(false),
2410 declare: id => this.createdDeclarations.push(id)
2411 });
2412
2413 super.initialise(transforms);
2414 }
2415
2416 findScope(functionScope) {
2417 return functionScope
2418 ? this.parent.findScope(functionScope)
2419 : this.scope;
2420 }
2421
2422 transpile(code, transforms) {
2423 var i1 = this.getIndentation() + code.getIndentString();
2424
2425 if (this.shouldRewriteAsFunction) {
2426 // which variables are declared in the init statement?
2427 var names = this.init && this.init.type === 'VariableDeclaration'
2428 ? this.init.declarations.map(declarator => extractNames(declarator.id))
2429 : [];
2430
2431 var aliases = this.aliases;
2432
2433 this.args = names.map(
2434 name => (name in this.aliases ? this.aliases[name].outer : name)
2435 );
2436 this.params = names.map(
2437 name => (name in this.aliases ? this.aliases[name].inner : name)
2438 );
2439
2440 var updates = Object.keys(this.reassigned).map(
2441 name => `${aliases[name].outer} = ${aliases[name].inner};`
2442 );
2443
2444 if (updates.length) {
2445 if (this.body.synthetic) {
2446 code.appendLeft(this.body.body[0].end, `; ${updates.join(` `)}`);
2447 } else {
2448 var lastStatement = this.body.body[this.body.body.length - 1];
2449 code.appendLeft(
2450 lastStatement.end,
2451 `\n\n${i1}${updates.join(`\n${i1}`)}`
2452 );
2453 }
2454 }
2455 }
2456
2457 super.transpile(code, transforms);
2458 }
2459}
2460
2461class ForInStatement extends LoopStatement {
2462 initialise(transforms) {
2463 this.createdDeclarations = [];
2464
2465 this.scope = new Scope({
2466 block: true,
2467 parent: this.parent.findScope(false),
2468 declare: id => this.createdDeclarations.push(id)
2469 });
2470
2471 super.initialise(transforms);
2472 }
2473
2474 findScope(functionScope) {
2475 return functionScope
2476 ? this.parent.findScope(functionScope)
2477 : this.scope;
2478 }
2479
2480 transpile(code, transforms) {
2481 var hasDeclaration = this.left.type === 'VariableDeclaration';
2482
2483 if (this.shouldRewriteAsFunction) {
2484 // which variables are declared in the init statement?
2485 var names = hasDeclaration
2486 ? this.left.declarations.map(declarator => extractNames(declarator.id))
2487 : [];
2488
2489 this.args = names.map(
2490 name => (name in this.aliases ? this.aliases[name].outer : name)
2491 );
2492 this.params = names.map(
2493 name => (name in this.aliases ? this.aliases[name].inner : name)
2494 );
2495 }
2496
2497 super.transpile(code, transforms);
2498
2499 var maybePattern = hasDeclaration ? this.left.declarations[0].id : this.left;
2500 if (maybePattern.type !== 'Identifier' && maybePattern.type !== 'MemberExpression') {
2501 this.destructurePattern(code, maybePattern, hasDeclaration);
2502 }
2503 }
2504
2505 destructurePattern(code, pattern, isDeclaration) {
2506 var scope = this.findScope(true);
2507 var i0 = this.getIndentation();
2508 var i1 = i0 + code.getIndentString();
2509
2510 var ref = scope.createIdentifier('ref');
2511
2512 var bodyStart = this.body.body.length ? this.body.body[0].start : this.body.start + 1;
2513
2514 code.move(pattern.start, pattern.end, bodyStart);
2515
2516 code.prependRight(pattern.end, isDeclaration ? ref : `var ${ref}`);
2517
2518 var statementGenerators = [];
2519 destructure(
2520 code,
2521 id => scope.createIdentifier(id),
2522 (ref) => {
2523 var name = ref.name;
2524
2525 return scope.resolveName(name);
2526 },
2527 pattern,
2528 ref,
2529 false,
2530 statementGenerators
2531 );
2532
2533 var suffix = `;\n${i1}`;
2534 statementGenerators.forEach((fn, i) => {
2535 if (i === statementGenerators.length - 1) {
2536 suffix = `;\n\n${i1}`;
2537 }
2538
2539 fn(bodyStart, '', suffix);
2540 });
2541 }
2542}
2543
2544class ForOfStatement extends LoopStatement {
2545 initialise(transforms) {
2546 if (transforms.forOf && !transforms.dangerousForOf)
2547 { CompileError.missingTransform("for-of statements", "forOf", this, "dangerousForOf"); }
2548 if (this.await && transforms.asyncAwait)
2549 { CompileError.missingTransform("for-await-of statements", "asyncAwait", this); }
2550
2551 this.createdDeclarations = [];
2552
2553 this.scope = new Scope({
2554 block: true,
2555 parent: this.parent.findScope(false),
2556 declare: id => this.createdDeclarations.push(id)
2557 });
2558
2559 super.initialise(transforms);
2560 }
2561
2562 findScope(functionScope) {
2563 return functionScope
2564 ? this.parent.findScope(functionScope)
2565 : this.scope;
2566 }
2567
2568 transpile(code, transforms) {
2569 super.transpile(code, transforms);
2570 if (!transforms.dangerousForOf) { return; }
2571
2572 // edge case (#80)
2573 if (!this.body.body[0]) {
2574 if (
2575 this.left.type === 'VariableDeclaration' &&
2576 this.left.kind === 'var'
2577 ) {
2578 code.remove(this.start, this.left.start);
2579 code.appendLeft(this.left.end, ';');
2580 code.remove(this.left.end, this.end);
2581 } else {
2582 code.remove(this.start, this.end);
2583 }
2584
2585 return;
2586 }
2587
2588 var scope = this.findScope(true);
2589 var i0 = this.getIndentation();
2590 var i1 = i0 + code.getIndentString();
2591
2592 var key = scope.createIdentifier('i');
2593 var list = scope.createIdentifier('list');
2594
2595 if (this.body.synthetic) {
2596 code.prependRight(this.left.start, `{\n${i1}`);
2597 code.appendLeft(this.body.body[0].end, `\n${i0}}`);
2598 }
2599
2600 var bodyStart = this.body.body[0].start;
2601
2602 code.remove(this.left.end, this.right.start);
2603 code.move(this.left.start, this.left.end, bodyStart);
2604
2605 code.prependRight(this.right.start, `var ${key} = 0, ${list} = `);
2606 code.appendLeft(this.right.end, `; ${key} < ${list}.length; ${key} += 1`);
2607
2608 var isDeclaration = this.left.type === 'VariableDeclaration';
2609 var maybeDestructuring = isDeclaration ? this.left.declarations[0].id : this.left;
2610 if (maybeDestructuring.type !== 'Identifier') {
2611 var statementGenerators = [];
2612 var ref = scope.createIdentifier('ref');
2613 destructure(
2614 code,
2615 id => scope.createIdentifier(id),
2616 (ref) => {
2617 var name = ref.name;
2618
2619 return scope.resolveName(name);
2620 },
2621 maybeDestructuring,
2622 ref,
2623 !isDeclaration,
2624 statementGenerators
2625 );
2626
2627 var suffix = `;\n${i1}`;
2628 statementGenerators.forEach((fn, i) => {
2629 if (i === statementGenerators.length - 1) {
2630 suffix = `;\n\n${i1}`;
2631 }
2632
2633 fn(bodyStart, '', suffix);
2634 });
2635
2636 if (isDeclaration) {
2637 code.appendLeft(this.left.start + this.left.kind.length + 1, ref);
2638 code.appendLeft(this.left.end, ` = ${list}[${key}];\n${i1}`);
2639 } else {
2640 code.appendLeft(this.left.end, `var ${ref} = ${list}[${key}];\n${i1}`);
2641 }
2642 } else {
2643 code.appendLeft(this.left.end, ` = ${list}[${key}];\n\n${i1}`);
2644 }
2645 }
2646}
2647
2648class FunctionDeclaration extends Node {
2649 initialise(transforms) {
2650 if (this.generator && transforms.generator) {
2651 CompileError.missingTransform("generators", "generator", this);
2652 }
2653 if (this.async && transforms.asyncAwait) {
2654 CompileError.missingTransform("async functions", "asyncAwait", this);
2655 }
2656
2657 this.body.createScope();
2658
2659 if (this.id) {
2660 this.findScope(true).addDeclaration(this.id, 'function');
2661 }
2662 super.initialise(transforms);
2663 }
2664
2665 transpile(code, transforms) {
2666 super.transpile(code, transforms);
2667 if (transforms.trailingFunctionCommas && this.params.length) {
2668 removeTrailingComma(code, this.params[this.params.length - 1].end);
2669 }
2670 }
2671}
2672
2673class FunctionExpression extends Node {
2674 initialise(transforms) {
2675 if (this.generator && transforms.generator) {
2676 CompileError.missingTransform("generators", "generator", this);
2677 }
2678 if (this.async && transforms.asyncAwait) {
2679 CompileError.missingTransform("async functions", "asyncAwait", this);
2680 }
2681
2682 this.body.createScope();
2683
2684 if (this.id) {
2685 // function expression IDs belong to the child scope...
2686 this.body.scope.addDeclaration(this.id, 'function');
2687 }
2688
2689 super.initialise(transforms);
2690
2691 var parent = this.parent;
2692 var methodName;
2693
2694 if (
2695 transforms.conciseMethodProperty &&
2696 parent.type === 'Property' &&
2697 parent.kind === 'init' &&
2698 parent.method &&
2699 parent.key.type === 'Identifier'
2700 ) {
2701 // object literal concise method
2702 methodName = parent.key.name;
2703 } else if (
2704 transforms.classes &&
2705 parent.type === 'MethodDefinition' &&
2706 parent.kind === 'method' &&
2707 parent.key.type === 'Identifier'
2708 ) {
2709 // method definition in a class
2710 methodName = parent.key.name;
2711 } else if (this.id && this.id.type === 'Identifier') {
2712 // naked function expression
2713 methodName = this.id.alias || this.id.name;
2714 }
2715
2716 if (methodName) {
2717 for (var i$1 = 0, list$1 = this.params; i$1 < list$1.length; i$1 += 1) {
2718 var param = list$1[i$1];
2719
2720 if (param.type === 'Identifier' && methodName === param.name) {
2721 // workaround for Safari 9/WebKit bug:
2722 // https://gitlab.com/Rich-Harris/buble/issues/154
2723 // change parameter name when same as method name
2724
2725 var scope = this.body.scope;
2726 var declaration = scope.declarations[methodName];
2727
2728 var alias = scope.createIdentifier(methodName);
2729 param.alias = alias;
2730
2731 for (var i = 0, list = declaration.instances; i < list.length; i += 1) {
2732 var identifier = list[i];
2733
2734 identifier.alias = alias;
2735 }
2736
2737 break;
2738 }
2739 }
2740 }
2741 }
2742
2743 transpile(code, transforms) {
2744 super.transpile(code, transforms);
2745 if (transforms.trailingFunctionCommas && this.params.length) {
2746 removeTrailingComma(code, this.params[this.params.length - 1].end);
2747 }
2748 }
2749}
2750
2751function isReference(node, parent) {
2752 if (node.type === 'MemberExpression') {
2753 return !node.computed && isReference(node.object, node);
2754 }
2755
2756 if (node.type === 'Identifier') {
2757 // the only time we could have an identifier node without a parent is
2758 // if it's the entire body of a function without a block statement –
2759 // i.e. an arrow function expression like `a => a`
2760 if (!parent) { return true; }
2761
2762 if (/(Function|Class)Expression/.test(parent.type)) { return false; }
2763
2764 if (parent.type === 'VariableDeclarator') { return node === parent.init; }
2765
2766 // TODO is this right?
2767 if (
2768 parent.type === 'MemberExpression' ||
2769 parent.type === 'MethodDefinition'
2770 ) {
2771 return parent.computed || node === parent.object;
2772 }
2773
2774 if (parent.type === 'ArrayPattern') { return false; }
2775
2776 // disregard the `bar` in `{ bar: foo }`, but keep it in `{ [bar]: foo }`
2777 if (parent.type === 'Property') {
2778 if (parent.parent.type === 'ObjectPattern') { return false; }
2779 return parent.computed || node === parent.value;
2780 }
2781
2782 // disregard the `bar` in `class Foo { bar () {...} }`
2783 if (parent.type === 'MethodDefinition') { return false; }
2784
2785 // disregard the `bar` in `export { foo as bar }`
2786 if (parent.type === 'ExportSpecifier' && node !== parent.local)
2787 { return false; }
2788
2789 return true;
2790 }
2791}
2792
2793class Identifier extends Node {
2794 findScope(functionScope) {
2795 if (this.parent.params && ~this.parent.params.indexOf(this)) {
2796 return this.parent.body.scope;
2797 }
2798
2799 if (this.parent.type === 'FunctionExpression' && this === this.parent.id) {
2800 return this.parent.body.scope;
2801 }
2802
2803 return this.parent.findScope(functionScope);
2804 }
2805
2806 initialise(transforms) {
2807 if (this.isLabel()) {
2808 return;
2809 }
2810
2811 if (isReference(this, this.parent)) {
2812 if (
2813 transforms.arrow &&
2814 this.name === 'arguments' &&
2815 !this.findScope(false).contains(this.name)
2816 ) {
2817 var lexicalBoundary = this.findLexicalBoundary();
2818 var arrowFunction = this.findNearest('ArrowFunctionExpression');
2819 var loop = this.findNearest(loopStatement);
2820
2821 if (arrowFunction && arrowFunction.depth > lexicalBoundary.depth) {
2822 this.alias = lexicalBoundary.getArgumentsAlias();
2823 }
2824
2825 if (
2826 loop &&
2827 loop.body.contains(this) &&
2828 loop.depth > lexicalBoundary.depth
2829 ) {
2830 this.alias = lexicalBoundary.getArgumentsAlias();
2831 }
2832 }
2833
2834 this.findScope(false).addReference(this);
2835 }
2836 }
2837
2838 isLabel() {
2839 switch (this.parent.type) {
2840 case 'BreakStatement': return true;
2841 case 'ContinueStatement': return true;
2842 case 'LabeledStatement': return true;
2843 default: return false;
2844 }
2845 }
2846
2847 transpile(code) {
2848 if (this.alias) {
2849 code.overwrite(this.start, this.end, this.alias, {
2850 storeName: true,
2851 contentOnly: true
2852 });
2853 }
2854 }
2855}
2856
2857class IfStatement extends Node {
2858 initialise(transforms) {
2859 super.initialise(transforms);
2860 }
2861
2862 transpile(code, transforms) {
2863 if (
2864 this.consequent.type !== 'BlockStatement' ||
2865 (this.consequent.type === 'BlockStatement' && this.consequent.synthetic)
2866 ) {
2867 code.appendLeft(this.consequent.start, '{ ');
2868 code.prependRight(this.consequent.end, ' }');
2869 }
2870
2871 if (
2872 this.alternate &&
2873 this.alternate.type !== 'IfStatement' &&
2874 (this.alternate.type !== 'BlockStatement' ||
2875 (this.alternate.type === 'BlockStatement' && this.alternate.synthetic))
2876 ) {
2877 code.appendLeft(this.alternate.start, '{ ');
2878 code.prependRight(this.alternate.end, ' }');
2879 }
2880
2881 super.transpile(code, transforms);
2882 }
2883}
2884
2885class Import extends Node {
2886 initialise(transforms) {
2887 if (transforms.moduleImport) {
2888 CompileError.missingTransform("dynamic import expressions", "moduleImport", this);
2889 }
2890 super.initialise(transforms);
2891 }
2892}
2893
2894class ImportDeclaration extends Node {
2895 initialise(transforms) {
2896 if (transforms.moduleImport)
2897 { CompileError.missingTransform("import", "moduleImport", this); }
2898 super.initialise(transforms);
2899 }
2900}
2901
2902class ImportDefaultSpecifier extends Node {
2903 initialise(transforms) {
2904 this.findScope(true).addDeclaration(this.local, 'import');
2905 super.initialise(transforms);
2906 }
2907}
2908
2909class ImportSpecifier extends Node {
2910 initialise(transforms) {
2911 this.findScope(true).addDeclaration(this.local, 'import');
2912 super.initialise(transforms);
2913 }
2914}
2915
2916var hasDashes = val => /-/.test(val);
2917
2918var formatKey = key => (hasDashes(key) ? `'${key}'` : key);
2919
2920var formatVal = val => (val ? '' : 'true');
2921
2922class JSXAttribute extends Node {
2923 transpile(code, transforms) {
2924 var ref = this.name;
2925 var start = ref.start;
2926 var name = ref.name;
2927
2928 // Overwrite equals sign if value is present.
2929 var end = this.value ? this.value.start : this.name.end;
2930
2931 code.overwrite(start, end, `${formatKey(name)}: ${formatVal(this.value)}`);
2932
2933 super.transpile(code, transforms);
2934 }
2935}
2936
2937function containsNewLine(node) {
2938 return (
2939 node.type === 'JSXText' && !/\S/.test(node.value) && /\n/.test(node.value)
2940 );
2941}
2942
2943class JSXClosingElement extends Node {
2944 transpile(code) {
2945 var spaceBeforeParen = true;
2946
2947 var lastChild = this.parent.children[this.parent.children.length - 1];
2948
2949 // omit space before closing paren if
2950 // a) this is on a separate line, or
2951 // b) there are no children but there are attributes
2952 if (
2953 (lastChild && containsNewLine(lastChild)) ||
2954 this.parent.openingElement.attributes.length
2955 ) {
2956 spaceBeforeParen = false;
2957 }
2958
2959 code.overwrite(this.start, this.end, spaceBeforeParen ? ' )' : ')');
2960 }
2961}
2962
2963function containsNewLine$1(node) {
2964 return (
2965 node.type === 'JSXText' && !/\S/.test(node.value) && /\n/.test(node.value)
2966 );
2967}
2968
2969class JSXClosingFragment extends Node {
2970 transpile(code) {
2971 var spaceBeforeParen = true;
2972
2973 var lastChild = this.parent.children[this.parent.children.length - 1];
2974
2975 // omit space before closing paren if this is on a separate line
2976 if (lastChild && containsNewLine$1(lastChild)) {
2977 spaceBeforeParen = false;
2978 }
2979
2980 code.overwrite(this.start, this.end, spaceBeforeParen ? ' )' : ')');
2981 }
2982}
2983
2984function normalise(str, removeTrailingWhitespace) {
2985
2986 if (removeTrailingWhitespace && /\n/.test(str)) {
2987 str = str.replace(/[ \f\n\r\t\v]+$/, '');
2988 }
2989
2990 str = str
2991 .replace(/^\n\r?[ \f\n\r\t\v]+/, '') // remove leading newline + space
2992 .replace(/[ \f\n\r\t\v]*\n\r?[ \f\n\r\t\v]*/gm, ' '); // replace newlines with spaces
2993
2994 // TODO prefer single quotes?
2995 return JSON.stringify(str);
2996}
2997
2998class JSXElement extends Node {
2999 transpile(code, transforms) {
3000 super.transpile(code, transforms);
3001
3002 var children = this.children.filter(child => {
3003 if (child.type !== 'JSXText') { return true; }
3004
3005 // remove whitespace-only literals, unless on a single line
3006 return /[^ \f\n\r\t\v]/.test(child.raw) || !/\n/.test(child.raw);
3007 });
3008
3009 if (children.length) {
3010 var c = (this.openingElement || this.openingFragment).end;
3011
3012 var i;
3013 for (i = 0; i < children.length; i += 1) {
3014 var child = children[i];
3015
3016 if (
3017 child.type === 'JSXExpressionContainer' &&
3018 child.expression.type === 'JSXEmptyExpression'
3019 ) ; else {
3020 var tail =
3021 code.original[c] === '\n' && child.type !== 'JSXText' ? '' : ' ';
3022 code.appendLeft(c, `,${tail}`);
3023 }
3024
3025 if (child.type === 'JSXText') {
3026 var str = normalise(child.value, i === children.length - 1);
3027 code.overwrite(child.start, child.end, str);
3028 }
3029
3030 c = child.end;
3031 }
3032 }
3033 }
3034}
3035
3036class JSXExpressionContainer extends Node {
3037 transpile(code, transforms) {
3038 code.remove(this.start, this.expression.start);
3039 code.remove(this.expression.end, this.end);
3040
3041 super.transpile(code, transforms);
3042 }
3043}
3044
3045class JSXFragment extends JSXElement {
3046}
3047
3048class JSXOpeningElement extends Node {
3049 transpile(code, transforms) {
3050 super.transpile(code, transforms);
3051
3052 code.overwrite(this.start, this.name.start, `${this.program.jsx}( `);
3053
3054 var html =
3055 this.name.type === 'JSXIdentifier' &&
3056 this.name.name[0] === this.name.name[0].toLowerCase();
3057 if (html) { code.prependRight(this.name.start, `'`); }
3058
3059 var len = this.attributes.length;
3060 var c = this.name.end;
3061
3062 if (len) {
3063 var i;
3064
3065 var hasSpread = false;
3066 for (i = 0; i < len; i += 1) {
3067 if (this.attributes[i].type === 'JSXSpreadAttribute') {
3068 hasSpread = true;
3069 break;
3070 }
3071 }
3072
3073 c = this.attributes[0].end;
3074
3075 for (i = 0; i < len; i += 1) {
3076 var attr = this.attributes[i];
3077
3078 if (i > 0) {
3079 if (attr.start === c) { code.prependRight(c, ', '); }
3080 else { code.overwrite(c, attr.start, ', '); }
3081 }
3082
3083 if (hasSpread && attr.type !== 'JSXSpreadAttribute') {
3084 var lastAttr = this.attributes[i - 1];
3085 var nextAttr = this.attributes[i + 1];
3086
3087 if (!lastAttr || lastAttr.type === 'JSXSpreadAttribute') {
3088 code.prependRight(attr.start, '{ ');
3089 }
3090
3091 if (!nextAttr || nextAttr.type === 'JSXSpreadAttribute') {
3092 code.appendLeft(attr.end, ' }');
3093 }
3094 }
3095
3096 c = attr.end;
3097 }
3098
3099 var after;
3100 var before;
3101 if (hasSpread) {
3102 if (len === 1) {
3103 before = html ? `',` : ',';
3104 } else {
3105 if (!this.program.options.objectAssign) {
3106 throw new CompileError(
3107 "Mixed JSX attributes ending in spread requires specified objectAssign option with 'Object.assign' or polyfill helper.",
3108 this
3109 );
3110 }
3111 before = html
3112 ? `', ${this.program.options.objectAssign}({},`
3113 : `, ${this.program.options.objectAssign}({},`;
3114 after = ')';
3115 }
3116 } else {
3117 before = html ? `', {` : ', {';
3118 after = ' }';
3119 }
3120
3121 code.prependRight(this.name.end, before);
3122
3123 if (after) {
3124 code.appendLeft(this.attributes[len - 1].end, after);
3125 }
3126 } else {
3127 code.appendLeft(this.name.end, html ? `', null` : `, null`);
3128 c = this.name.end;
3129 }
3130
3131 if (this.selfClosing) {
3132 code.overwrite(c, this.end, this.attributes.length ? `)` : ` )`);
3133 } else {
3134 code.remove(c, this.end);
3135 }
3136 }
3137}
3138
3139class JSXOpeningFragment extends Node {
3140 transpile(code) {
3141 code.overwrite(this.start, this.end, `${this.program.jsx}( ${this.program.jsxFragment}, null`);
3142 }
3143}
3144
3145class JSXSpreadAttribute extends Node {
3146 transpile(code, transforms) {
3147 code.remove(this.start, this.argument.start);
3148 code.remove(this.argument.end, this.end);
3149
3150 super.transpile(code, transforms);
3151 }
3152}
3153
3154var nonAsciiLsOrPs = /[\u2028-\u2029]/g;
3155
3156class Literal extends Node {
3157 initialise() {
3158 if (typeof this.value === 'string') {
3159 this.program.indentExclusionElements.push(this);
3160 }
3161 }
3162
3163 transpile(code, transforms) {
3164 if (transforms.numericLiteral) {
3165 if (this.raw.match(/^0[bo]/i)) {
3166 code.overwrite(this.start, this.end, String(this.value), {
3167 storeName: true,
3168 contentOnly: true
3169 });
3170 }
3171 }
3172
3173 if (this.regex) {
3174 var ref = this.regex;
3175 var pattern = ref.pattern;
3176 var flags = ref.flags;
3177
3178 if (transforms.stickyRegExp && /y/.test(flags))
3179 { CompileError.missingTransform('the regular expression sticky flag', 'stickyRegExp', this); }
3180 if (transforms.unicodeRegExp && /u/.test(flags)) {
3181 code.overwrite(
3182 this.start,
3183 this.end,
3184 `/${rewritePattern(pattern, flags)}/${flags.replace('u', '')}`,
3185 {
3186 contentOnly: true
3187 }
3188 );
3189 }
3190 } else if (typeof this.value === "string" && this.value.match(nonAsciiLsOrPs)) {
3191 code.overwrite(
3192 this.start,
3193 this.end,
3194 this.raw.replace(nonAsciiLsOrPs, m => m == '\u2028' ? '\\u2028' : '\\u2029'),
3195 {
3196 contentOnly: true
3197 }
3198 );
3199 }
3200 }
3201}
3202
3203class MemberExpression extends Node {
3204 transpile(code, transforms) {
3205 if (transforms.reservedProperties && reserved[this.property.name]) {
3206 code.overwrite(this.object.end, this.property.start, `['`);
3207 code.appendLeft(this.property.end, `']`);
3208 }
3209
3210 super.transpile(code, transforms);
3211 }
3212}
3213
3214class NewExpression extends Node {
3215 initialise(transforms) {
3216 if (transforms.spreadRest && this.arguments.length) {
3217 var lexicalBoundary = this.findLexicalBoundary();
3218
3219 var i = this.arguments.length;
3220 while (i--) {
3221 var arg = this.arguments[i];
3222 if (arg.type === 'SpreadElement' && isArguments(arg.argument)) {
3223 this.argumentsArrayAlias = lexicalBoundary.getArgumentsArrayAlias();
3224 break;
3225 }
3226 }
3227 }
3228
3229 super.initialise(transforms);
3230 }
3231
3232 transpile(code, transforms) {
3233 super.transpile(code, transforms);
3234
3235 if (transforms.spreadRest && this.arguments.length) {
3236 inlineSpreads(code, this, this.arguments);
3237 // this.arguments.length may have changed, must retest.
3238 }
3239
3240 if (transforms.spreadRest && this.arguments.length) {
3241 var firstArgument = this.arguments[0];
3242 var isNew = true;
3243 var hasSpreadElements = spread(
3244 code,
3245 this.arguments,
3246 firstArgument.start,
3247 this.argumentsArrayAlias,
3248 isNew
3249 );
3250
3251 if (hasSpreadElements) {
3252 code.prependRight(
3253 this.start + 'new'.length,
3254 ' (Function.prototype.bind.apply('
3255 );
3256 code.overwrite(
3257 this.callee.end,
3258 firstArgument.start,
3259 ', [ null ].concat( '
3260 );
3261 code.appendLeft(this.end, ' ))');
3262 }
3263 }
3264
3265 if (this.arguments.length) {
3266 removeTrailingComma(code, this.arguments[this.arguments.length - 1].end);
3267 }
3268 }
3269}
3270
3271class ObjectExpression extends Node {
3272 transpile(code, transforms) {
3273 var ref;
3274
3275 super.transpile(code, transforms);
3276
3277 var firstPropertyStart = this.start + 1;
3278 var spreadPropertyCount = 0;
3279 var computedPropertyCount = 0;
3280 var firstSpreadProperty = null;
3281 var firstComputedProperty = null;
3282
3283 for (var i = 0; i < this.properties.length; ++i) {
3284 var prop = this.properties[i];
3285 if (prop.type === 'SpreadElement') {
3286 // First see if we can inline the spread, to save needing objectAssign.
3287 var argument = prop.argument;
3288 if (
3289 argument.type === 'ObjectExpression' || (
3290 argument.type === 'Literal' &&
3291 typeof argument.value !== 'string'
3292 )
3293 ) {
3294 if (argument.type === 'ObjectExpression' && argument.properties.length > 0) {
3295 // Strip the `...{` and the `}` with a possible trailing comma before it,
3296 // leaving just the possible trailing comma after it.
3297 code.remove(prop.start, argument.properties[0].start);
3298 code.remove(argument.properties[argument.properties.length - 1].end, prop.end);
3299 (ref = this.properties).splice.apply(ref, [ i, 1 ].concat( argument.properties ));
3300 i--;
3301 } else {
3302 // An empty object, boolean, null, undefined, number or regexp (but NOT
3303 // string) will spread to nothing, so just remove the element altogether,
3304 // including a possible trailing comma.
3305 code.remove(prop.start, i === this.properties.length - 1
3306 ? prop.end
3307 : this.properties[i + 1].start);
3308 this.properties.splice(i, 1);
3309 i--;
3310 }
3311 } else {
3312 spreadPropertyCount += 1;
3313 if (firstSpreadProperty === null) { firstSpreadProperty = i; }
3314 }
3315 } else if (prop.computed && transforms.computedProperty) {
3316 computedPropertyCount += 1;
3317 if (firstComputedProperty === null) { firstComputedProperty = i; }
3318 }
3319 }
3320
3321 if (spreadPropertyCount && !transforms.objectRestSpread && !(computedPropertyCount && transforms.computedProperty)) {
3322 spreadPropertyCount = 0;
3323 firstSpreadProperty = null;
3324 } else if (spreadPropertyCount) {
3325 if (!this.program.options.objectAssign) {
3326 throw new CompileError(
3327 "Object spread operator requires specified objectAssign option with 'Object.assign' or polyfill helper.",
3328 this
3329 );
3330 }
3331 var i$1 = this.properties.length;
3332 while (i$1--) {
3333 var prop$1 = this.properties[i$1];
3334
3335 // enclose run of non-spread properties in curlies
3336 if (prop$1.type === 'Property' && !computedPropertyCount) {
3337 var lastProp = this.properties[i$1 - 1];
3338 var nextProp = this.properties[i$1 + 1];
3339
3340 if (!lastProp || lastProp.type !== 'Property') {
3341 code.prependRight(prop$1.start, '{');
3342 }
3343
3344 if (!nextProp || nextProp.type !== 'Property') {
3345 code.appendLeft(prop$1.end, '}');
3346 }
3347 }
3348
3349 // Remove ellipsis on spread property
3350 if (prop$1.type === 'SpreadElement') {
3351 code.remove(prop$1.start, prop$1.argument.start);
3352 code.remove(prop$1.argument.end, prop$1.end);
3353 }
3354 }
3355
3356 // wrap the whole thing in Object.assign
3357 firstPropertyStart = this.properties[0].start;
3358 if (!computedPropertyCount) {
3359 code.overwrite(
3360 this.start,
3361 firstPropertyStart,
3362 `${this.program.options.objectAssign}({}, `
3363 );
3364 code.overwrite(
3365 this.properties[this.properties.length - 1].end,
3366 this.end,
3367 ')'
3368 );
3369 } else if (this.properties[0].type === 'SpreadElement') {
3370 code.overwrite(
3371 this.start,
3372 firstPropertyStart,
3373 `${this.program.options.objectAssign}({}, `
3374 );
3375 code.remove(this.end - 1, this.end);
3376 code.appendRight(this.end, ')');
3377 } else {
3378 code.prependLeft(this.start, `${this.program.options.objectAssign}(`);
3379 code.appendRight(this.end, ')');
3380 }
3381 }
3382
3383 if (computedPropertyCount && transforms.computedProperty) {
3384 var i0 = this.getIndentation();
3385
3386 var isSimpleAssignment;
3387 var name;
3388
3389 if (
3390 this.parent.type === 'VariableDeclarator' &&
3391 this.parent.parent.declarations.length === 1 &&
3392 this.parent.id.type === 'Identifier'
3393 ) {
3394 isSimpleAssignment = true;
3395 name = this.parent.id.alias || this.parent.id.name; // TODO is this right?
3396 } else if (
3397 this.parent.type === 'AssignmentExpression' &&
3398 this.parent.parent.type === 'ExpressionStatement' &&
3399 this.parent.left.type === 'Identifier'
3400 ) {
3401 isSimpleAssignment = true;
3402 name = this.parent.left.alias || this.parent.left.name; // TODO is this right?
3403 } else if (
3404 this.parent.type === 'AssignmentPattern' &&
3405 this.parent.left.type === 'Identifier'
3406 ) {
3407 isSimpleAssignment = true;
3408 name = this.parent.left.alias || this.parent.left.name; // TODO is this right?
3409 }
3410
3411 if (spreadPropertyCount) { isSimpleAssignment = false; }
3412
3413 // handle block scoping
3414 name = this.findScope(false).resolveName(name);
3415
3416 var start = firstPropertyStart;
3417 var end = this.end;
3418
3419 if (isSimpleAssignment) ; else {
3420 if (
3421 firstSpreadProperty === null ||
3422 firstComputedProperty < firstSpreadProperty
3423 ) {
3424 name = this.findScope(true).createDeclaration('obj');
3425
3426 code.prependRight(this.start, `( ${name} = `);
3427 } else { name = null; } // We don't actually need this variable
3428 }
3429
3430 var len = this.properties.length;
3431 var lastComputedProp;
3432 var sawNonComputedProperty = false;
3433 var isFirst = true;
3434
3435 for (var i$2 = 0; i$2 < len; i$2 += 1) {
3436 var prop$2 = this.properties[i$2];
3437 var moveStart = i$2 > 0 ? this.properties[i$2 - 1].end : start;
3438
3439 if (
3440 prop$2.type === 'Property' &&
3441 (prop$2.computed || (lastComputedProp && !spreadPropertyCount))
3442 ) {
3443 if (i$2 === 0) { moveStart = this.start + 1; } // Trim leading whitespace
3444 lastComputedProp = prop$2;
3445
3446 if (!name) {
3447 name = this.findScope(true).createDeclaration('obj');
3448
3449 var propId = name + (prop$2.computed ? '' : '.');
3450 code.appendRight(prop$2.start, `( ${name} = {}, ${propId}`);
3451 } else {
3452 var propId$1 =
3453 (isSimpleAssignment ? `;\n${i0}${name}` : `, ${name}`) +
3454 (prop$2.key.type === 'Literal' || prop$2.computed ? '' : '.');
3455
3456 if (moveStart < prop$2.start) {
3457 code.overwrite(moveStart, prop$2.start, propId$1);
3458 } else {
3459 code.prependRight(prop$2.start, propId$1);
3460 }
3461 }
3462
3463 var c = prop$2.key.end;
3464 if (prop$2.computed) {
3465 while (code.original[c] !== ']') { c += 1; }
3466 c += 1;
3467 }
3468 if (prop$2.key.type === 'Literal' && !prop$2.computed) {
3469 code.overwrite(
3470 prop$2.start,
3471 prop$2.value.start,
3472 '[' + code.slice(prop$2.start, prop$2.key.end) + '] = '
3473 );
3474 } else if (prop$2.shorthand || (prop$2.method && !prop$2.computed && transforms.conciseMethodProperty)) {
3475 // Replace : with = if Property::transpile inserted the :
3476 code.overwrite(
3477 prop$2.key.start,
3478 prop$2.key.end,
3479 code.slice(prop$2.key.start, prop$2.key.end).replace(/:/, ' =')
3480 );
3481 } else {
3482 if (prop$2.value.start > c) { code.remove(c, prop$2.value.start); }
3483 code.prependLeft(c, ' = ');
3484 }
3485
3486 // This duplicates behavior from Property::transpile which is disabled
3487 // for computed properties or if conciseMethodProperty is false
3488 if (prop$2.method && (prop$2.computed || !transforms.conciseMethodProperty)) {
3489 if (prop$2.value.generator) { code.remove(prop$2.start, prop$2.key.start); }
3490 code.prependRight(prop$2.value.start, `function${prop$2.value.generator ? '*' : ''} `);
3491 }
3492 } else if (prop$2.type === 'SpreadElement') {
3493 if (name && i$2 > 0) {
3494 if (!lastComputedProp) {
3495 lastComputedProp = this.properties[i$2 - 1];
3496 }
3497 code.appendLeft(lastComputedProp.end, `, ${name} )`);
3498
3499 lastComputedProp = null;
3500 name = null;
3501 }
3502 } else {
3503 if (!isFirst && spreadPropertyCount) {
3504 // We are in an Object.assign context, so we need to wrap regular properties
3505 code.prependRight(prop$2.start, '{');
3506 code.appendLeft(prop$2.end, '}');
3507 }
3508 sawNonComputedProperty = true;
3509 }
3510 if (isFirst && (prop$2.type === 'SpreadElement' || prop$2.computed)) {
3511 var beginEnd = sawNonComputedProperty
3512 ? this.properties[this.properties.length - 1].end
3513 : this.end - 1;
3514 // Trim trailing comma because it can easily become a leading comma which is illegal
3515 if (code.original[beginEnd] == ',') { ++beginEnd; }
3516 var closing = code.slice(beginEnd, end);
3517 code.prependLeft(moveStart, closing);
3518 code.remove(beginEnd, end);
3519 isFirst = false;
3520 }
3521
3522 // Clean up some extranous whitespace
3523 var c$1 = prop$2.end;
3524 if (i$2 < len - 1 && !sawNonComputedProperty) {
3525 while (code.original[c$1] !== ',') { c$1 += 1; }
3526 } else if (i$2 == len - 1) { c$1 = this.end; }
3527 if (prop$2.end != c$1) { code.overwrite(prop$2.end, c$1, '', {contentOnly: true}); }
3528 }
3529
3530 if (!isSimpleAssignment && name) {
3531 code.appendLeft(lastComputedProp.end, `, ${name} )`);
3532 }
3533 }
3534 }
3535}
3536
3537class Property extends Node {
3538 initialise(transforms) {
3539 if ((this.kind === 'get' || this.kind === 'set') && transforms.getterSetter) {
3540 CompileError.missingTransform("getters and setters", "getterSetter", this);
3541 }
3542 super.initialise(transforms);
3543 }
3544
3545 transpile(code, transforms) {
3546 super.transpile(code, transforms);
3547
3548 if (
3549 transforms.conciseMethodProperty &&
3550 !this.computed &&
3551 this.parent.type !== 'ObjectPattern'
3552 ) {
3553 if (this.shorthand) {
3554 code.prependRight(this.start, `${this.key.name}: `);
3555 } else if (this.method) {
3556 var name = '';
3557 if (this.program.options.namedFunctionExpressions !== false) {
3558 if (
3559 this.key.type === 'Literal' &&
3560 typeof this.key.value === 'number'
3561 ) {
3562 name = '';
3563 } else if (this.key.type === 'Identifier') {
3564 if (
3565 reserved[this.key.name] ||
3566 !/^[a-z_$][a-z0-9_$]*$/i.test(this.key.name) ||
3567 this.value.body.scope.references[this.key.name]
3568 ) {
3569 name = this.findScope(true).createIdentifier(this.key.name);
3570 } else {
3571 name = this.key.name;
3572 }
3573 } else {
3574 name = this.findScope(true).createIdentifier(this.key.value);
3575 }
3576 name = ' ' + name;
3577 }
3578
3579 if (this.start < this.key.start) { code.remove(this.start, this.key.start); }
3580 code.appendLeft(
3581 this.key.end,
3582 `: ${this.value.async ? 'async ' : ''}function${this.value.generator ? '*' : ''}${name}`
3583 );
3584 }
3585 }
3586
3587 if (transforms.reservedProperties && reserved[this.key.name]) {
3588 code.prependRight(this.key.start, `'`);
3589 code.appendLeft(this.key.end, `'`);
3590 }
3591 }
3592}
3593
3594class ReturnStatement extends Node {
3595 initialise(transforms) {
3596 this.loop = this.findNearest(loopStatement);
3597 this.nearestFunction = this.findNearest(/Function/);
3598
3599 if (
3600 this.loop &&
3601 (!this.nearestFunction || this.loop.depth > this.nearestFunction.depth)
3602 ) {
3603 this.loop.canReturn = true;
3604 this.shouldWrap = true;
3605 }
3606
3607 if (this.argument) { this.argument.initialise(transforms); }
3608 }
3609
3610 transpile(code, transforms) {
3611 var shouldWrap =
3612 this.shouldWrap && this.loop && this.loop.shouldRewriteAsFunction;
3613
3614 if (this.argument) {
3615 if (shouldWrap) { code.prependRight(this.argument.start, `{ v: `); }
3616 this.argument.transpile(code, transforms);
3617 if (shouldWrap) { code.appendLeft(this.argument.end, ` }`); }
3618 } else if (shouldWrap) {
3619 code.appendLeft(this.start + 6, ' {}');
3620 }
3621 }
3622}
3623
3624class Super extends Node {
3625 initialise(transforms) {
3626 if (transforms.classes) {
3627 this.method = this.findNearest('MethodDefinition');
3628 if (!this.method)
3629 { throw new CompileError('use of super outside class method', this); }
3630
3631 var parentClass = this.findNearest('ClassBody').parent;
3632 this.superClassName =
3633 parentClass.superClass && (parentClass.superClass.name || 'superclass');
3634
3635 if (!this.superClassName)
3636 { throw new CompileError('super used in base class', this); }
3637
3638 this.isCalled =
3639 this.parent.type === 'CallExpression' && this === this.parent.callee;
3640
3641 if (this.method.kind !== 'constructor' && this.isCalled) {
3642 throw new CompileError(
3643 'super() not allowed outside class constructor',
3644 this
3645 );
3646 }
3647
3648 this.isMember = this.parent.type === 'MemberExpression';
3649
3650 if (!this.isCalled && !this.isMember) {
3651 throw new CompileError(
3652 'Unexpected use of `super` (expected `super(...)` or `super.*`)',
3653 this
3654 );
3655 }
3656 }
3657
3658 if (transforms.arrow) {
3659 var lexicalBoundary = this.findLexicalBoundary();
3660 var arrowFunction = this.findNearest('ArrowFunctionExpression');
3661 var loop = this.findNearest(loopStatement);
3662
3663 if (arrowFunction && arrowFunction.depth > lexicalBoundary.depth) {
3664 this.thisAlias = lexicalBoundary.getThisAlias();
3665 }
3666
3667 if (
3668 loop &&
3669 loop.body.contains(this) &&
3670 loop.depth > lexicalBoundary.depth
3671 ) {
3672 this.thisAlias = lexicalBoundary.getThisAlias();
3673 }
3674 }
3675 }
3676
3677 transpile(code, transforms) {
3678 if (transforms.classes) {
3679 var expression =
3680 this.isCalled || this.method.static
3681 ? this.superClassName
3682 : `${this.superClassName}.prototype`;
3683
3684 code.overwrite(this.start, this.end, expression, {
3685 storeName: true,
3686 contentOnly: true
3687 });
3688
3689 var callExpression = this.isCalled ? this.parent : this.parent.parent;
3690
3691 if (callExpression && callExpression.type === 'CallExpression') {
3692 if (!this.noCall) {
3693 // special case – `super( ...args )`
3694 code.appendLeft(callExpression.callee.end, '.call');
3695 }
3696
3697 var thisAlias = this.thisAlias || 'this';
3698
3699 if (callExpression.arguments.length) {
3700 code.appendLeft(callExpression.arguments[0].start, `${thisAlias}, `);
3701 } else {
3702 code.appendLeft(callExpression.end - 1, `${thisAlias}`);
3703 }
3704 }
3705 }
3706 }
3707}
3708
3709class TaggedTemplateExpression extends Node {
3710 initialise(transforms) {
3711 if (
3712 transforms.templateString &&
3713 !transforms.dangerousTaggedTemplateString
3714 ) {
3715 CompileError.missingTransform(
3716 "tagged template strings", "templateString", this, "dangerousTaggedTemplateString"
3717 );
3718 }
3719
3720 super.initialise(transforms);
3721 }
3722
3723 transpile(code, transforms) {
3724 if (transforms.templateString && transforms.dangerousTaggedTemplateString) {
3725 var ordered = this.quasi.expressions
3726 .concat(this.quasi.quasis)
3727 .sort((a, b) => a.start - b.start);
3728
3729 var program = this.program;
3730 var rootScope = program.body.scope;
3731
3732 // insert strings at start
3733 var templateStrings = this.quasi.quasis.map(quasi =>
3734 JSON.stringify(quasi.value.cooked)
3735 ).join(', ');
3736
3737 var templateObject = this.program.templateLiteralQuasis[templateStrings];
3738 if (!templateObject) {
3739 templateObject = rootScope.createIdentifier('templateObject');
3740 code.prependLeft(this.program.prependAt, `var ${templateObject} = Object.freeze([${templateStrings}]);\n`);
3741
3742 this.program.templateLiteralQuasis[templateStrings] = templateObject;
3743 }
3744
3745 code.overwrite(
3746 this.tag.end,
3747 ordered[0].start,
3748 `(${templateObject}`
3749 );
3750
3751 var lastIndex = ordered[0].start;
3752 ordered.forEach(node => {
3753 if (node.type === 'TemplateElement') {
3754 code.remove(lastIndex, node.end);
3755 } else {
3756 code.overwrite(lastIndex, node.start, ', ');
3757 }
3758
3759 lastIndex = node.end;
3760 });
3761
3762 code.overwrite(lastIndex, this.end, ')');
3763 }
3764
3765 super.transpile(code, transforms);
3766 }
3767}
3768
3769class TemplateElement extends Node {
3770 initialise() {
3771 this.program.indentExclusionElements.push(this);
3772 }
3773}
3774
3775class TemplateLiteral extends Node {
3776 transpile(code, transforms) {
3777 super.transpile(code, transforms);
3778
3779 if (
3780 transforms.templateString &&
3781 this.parent.type !== 'TaggedTemplateExpression'
3782 ) {
3783 var ordered = this.expressions
3784 .concat(this.quasis)
3785 .sort((a, b) => a.start - b.start || a.end - b.end)
3786 .filter((node, i) => {
3787 // include all expressions
3788 if (node.type !== 'TemplateElement') { return true; }
3789
3790 // include all non-empty strings
3791 if (node.value.raw) { return true; }
3792
3793 // exclude all empty strings not at the head
3794 return !i;
3795 });
3796
3797 // special case – we may be able to skip the first element,
3798 // if it's the empty string, but only if the second and
3799 // third elements aren't both expressions (since they maybe
3800 // be numeric, and `1 + 2 + '3' === '33'`)
3801 if (ordered.length >= 3) {
3802 var first = ordered[0];
3803 var third = ordered[2];
3804 if (
3805 first.type === 'TemplateElement' &&
3806 first.value.raw === '' &&
3807 third.type === 'TemplateElement'
3808 ) {
3809 ordered.shift();
3810 }
3811 }
3812
3813 var parenthesise =
3814 (this.quasis.length !== 1 || this.expressions.length !== 0) &&
3815 this.parent.type !== 'TemplateLiteral' &&
3816 this.parent.type !== 'AssignmentExpression' &&
3817 this.parent.type !== 'AssignmentPattern' &&
3818 this.parent.type !== 'VariableDeclarator' &&
3819 (this.parent.type !== 'BinaryExpression' ||
3820 this.parent.operator !== '+');
3821
3822 if (parenthesise) { code.appendRight(this.start, '('); }
3823
3824 var lastIndex = this.start;
3825
3826 ordered.forEach((node, i) => {
3827 var prefix = i === 0 ? (parenthesise ? '(' : '') : ' + ';
3828
3829 if (node.type === 'TemplateElement') {
3830 code.overwrite(
3831 lastIndex,
3832 node.end,
3833 prefix + JSON.stringify(node.value.cooked)
3834 );
3835 } else {
3836 var parenthesise$1 = node.type !== 'Identifier'; // TODO other cases where it's safe
3837
3838 if (parenthesise$1) { prefix += '('; }
3839
3840 code.remove(lastIndex, node.start);
3841
3842 if (prefix) { code.prependRight(node.start, prefix); }
3843 if (parenthesise$1) { code.appendLeft(node.end, ')'); }
3844 }
3845
3846 lastIndex = node.end;
3847 });
3848
3849 if (parenthesise) { code.appendLeft(lastIndex, ')'); }
3850 code.overwrite(lastIndex, this.end, "", { contentOnly: true });
3851 }
3852 }
3853}
3854
3855class ThisExpression extends Node {
3856 initialise(transforms) {
3857 var lexicalBoundary = this.findLexicalBoundary();
3858
3859 if (transforms.letConst) {
3860 // save all loops up to the lexical boundary in case we need
3861 // to alias them later for block-scoped declarations
3862 var node = this.findNearest(loopStatement);
3863 while (node && node.depth > lexicalBoundary.depth) {
3864 node.thisRefs.push(this);
3865 node = node.parent.findNearest(loopStatement);
3866 }
3867 }
3868
3869 if (transforms.arrow) {
3870 var arrowFunction = this.findNearest('ArrowFunctionExpression');
3871
3872 if (arrowFunction && arrowFunction.depth > lexicalBoundary.depth) {
3873 this.alias = lexicalBoundary.getThisAlias();
3874 }
3875 }
3876 }
3877
3878 transpile(code) {
3879 if (this.alias) {
3880 code.overwrite(this.start, this.end, this.alias, {
3881 storeName: true,
3882 contentOnly: true
3883 });
3884 }
3885 }
3886}
3887
3888class UpdateExpression extends Node {
3889 initialise(transforms) {
3890 if (this.argument.type === 'Identifier') {
3891 var declaration = this.findScope(false).findDeclaration(
3892 this.argument.name
3893 );
3894 // special case – https://gitlab.com/Rich-Harris/buble/issues/150
3895 var statement = declaration && declaration.node.ancestor(3);
3896 if (
3897 statement &&
3898 statement.type === 'ForStatement' &&
3899 statement.body.contains(this)
3900 ) {
3901 statement.reassigned[this.argument.name] = true;
3902 }
3903 }
3904
3905 super.initialise(transforms);
3906 }
3907
3908 transpile(code, transforms) {
3909 if (this.argument.type === 'Identifier') {
3910 // Do this check after everything has been initialized to find
3911 // shadowing declarations after this expression
3912 checkConst(this.argument, this.findScope(false));
3913 }
3914 super.transpile(code, transforms);
3915 }
3916}
3917
3918class VariableDeclaration extends Node {
3919 initialise(transforms) {
3920 this.scope = this.findScope(this.kind === 'var');
3921 this.declarations.forEach(declarator => declarator.initialise(transforms));
3922 }
3923
3924 transpile(code, transforms) {
3925 var i0 = this.getIndentation();
3926 var kind = this.kind;
3927
3928 if (transforms.letConst && kind !== 'var') {
3929 kind = 'var';
3930 code.overwrite(this.start, this.start + this.kind.length, kind, {
3931 contentOnly: true,
3932 storeName: true
3933 });
3934 }
3935
3936 if (transforms.destructuring && this.parent.type !== 'ForOfStatement' && this.parent.type !== 'ForInStatement') {
3937 var c = this.start;
3938 var lastDeclaratorIsPattern;
3939
3940 this.declarations.forEach((declarator, i) => {
3941 declarator.transpile(code, transforms);
3942
3943 if (declarator.id.type === 'Identifier') {
3944 if (i > 0 && this.declarations[i - 1].id.type !== 'Identifier') {
3945 code.overwrite(c, declarator.id.start, `var `);
3946 }
3947 } else {
3948 var inline = loopStatement.test(this.parent.type);
3949
3950 if (i === 0) {
3951 code.remove(c, declarator.id.start);
3952 } else {
3953 code.overwrite(c, declarator.id.start, `;\n${i0}`);
3954 }
3955
3956 var simple =
3957 declarator.init.type === 'Identifier' && !declarator.init.rewritten;
3958
3959 var name = simple
3960 ? (declarator.init.alias || declarator.init.name)
3961 : declarator.findScope(true).createIdentifier('ref');
3962
3963 c = declarator.start;
3964
3965 var statementGenerators = [];
3966
3967 if (simple) {
3968 code.remove(declarator.id.end, declarator.end);
3969 } else {
3970 statementGenerators.push((start, prefix, suffix) => {
3971 code.prependRight(declarator.id.end, `var ${name}`);
3972 code.appendLeft(declarator.init.end, `${suffix}`);
3973 code.move(declarator.id.end, declarator.end, start);
3974 });
3975 }
3976
3977 var scope = declarator.findScope(false);
3978 destructure(
3979 code,
3980 id => scope.createIdentifier(id),
3981 (ref) => {
3982 var name = ref.name;
3983
3984 return scope.resolveName(name);
3985 },
3986 declarator.id,
3987 name,
3988 inline,
3989 statementGenerators
3990 );
3991
3992 var prefix = inline ? 'var ' : '';
3993 var suffix = inline ? `, ` : `;\n${i0}`;
3994 statementGenerators.forEach((fn, j) => {
3995 if (
3996 i === this.declarations.length - 1 &&
3997 j === statementGenerators.length - 1
3998 ) {
3999 suffix = inline ? '' : ';';
4000 }
4001
4002 fn(declarator.start, j === 0 ? prefix : '', suffix);
4003 });
4004 }
4005
4006 c = declarator.end;
4007 lastDeclaratorIsPattern = declarator.id.type !== 'Identifier';
4008 });
4009
4010 if (lastDeclaratorIsPattern && this.end > c) {
4011 code.overwrite(c, this.end, '', { contentOnly: true });
4012 }
4013 } else {
4014 this.declarations.forEach(declarator => {
4015 declarator.transpile(code, transforms);
4016 });
4017 }
4018 }
4019}
4020
4021class VariableDeclarator extends Node {
4022 initialise(transforms) {
4023 var kind = this.parent.kind;
4024 if (kind === 'let' && this.parent.parent.type === 'ForStatement') {
4025 kind = 'for.let'; // special case...
4026 }
4027
4028 this.parent.scope.addDeclaration(this.id, kind);
4029 super.initialise(transforms);
4030 }
4031
4032 transpile(code, transforms) {
4033 if (!this.init && transforms.letConst && this.parent.kind !== 'var') {
4034 var inLoop = this.findNearest(
4035 /Function|^For(In|Of)?Statement|^(?:Do)?WhileStatement/
4036 );
4037 if (
4038 inLoop &&
4039 !/Function/.test(inLoop.type) &&
4040 !this.isLeftDeclaratorOfLoop()
4041 ) {
4042 code.appendLeft(this.id.end, ' = (void 0)');
4043 }
4044 }
4045
4046 if (this.id) { this.id.transpile(code, transforms); }
4047 if (this.init) { this.init.transpile(code, transforms); }
4048 }
4049
4050 isLeftDeclaratorOfLoop() {
4051 return (
4052 this.parent &&
4053 this.parent.type === 'VariableDeclaration' &&
4054 this.parent.parent &&
4055 (this.parent.parent.type === 'ForInStatement' ||
4056 this.parent.parent.type === 'ForOfStatement') &&
4057 this.parent.parent.left &&
4058 this.parent.parent.left.declarations[0] === this
4059 );
4060 }
4061}
4062
4063var types = {
4064 ArrayExpression,
4065 ArrowFunctionExpression,
4066 AssignmentExpression,
4067 AwaitExpression,
4068 BinaryExpression,
4069 BreakStatement,
4070 CallExpression,
4071 CatchClause,
4072 ClassBody,
4073 ClassDeclaration,
4074 ClassExpression,
4075 ContinueStatement,
4076 DoWhileStatement: LoopStatement,
4077 ExportNamedDeclaration,
4078 ExportDefaultDeclaration,
4079 ForStatement,
4080 ForInStatement,
4081 ForOfStatement,
4082 FunctionDeclaration,
4083 FunctionExpression,
4084 Identifier,
4085 IfStatement,
4086 Import,
4087 ImportDeclaration,
4088 ImportDefaultSpecifier,
4089 ImportSpecifier,
4090 JSXAttribute,
4091 JSXClosingElement,
4092 JSXClosingFragment,
4093 JSXElement,
4094 JSXExpressionContainer,
4095 JSXFragment,
4096 JSXOpeningElement,
4097 JSXOpeningFragment,
4098 JSXSpreadAttribute,
4099 Literal,
4100 MemberExpression,
4101 NewExpression,
4102 ObjectExpression,
4103 Property,
4104 ReturnStatement,
4105 Super,
4106 TaggedTemplateExpression,
4107 TemplateElement,
4108 TemplateLiteral,
4109 ThisExpression,
4110 UpdateExpression,
4111 VariableDeclaration,
4112 VariableDeclarator,
4113 WhileStatement: LoopStatement
4114};
4115
4116var keys = {
4117 Program: ['body'],
4118 Literal: []
4119};
4120
4121var statementsWithBlocks = {
4122 IfStatement: 'consequent',
4123 ForStatement: 'body',
4124 ForInStatement: 'body',
4125 ForOfStatement: 'body',
4126 WhileStatement: 'body',
4127 DoWhileStatement: 'body',
4128 ArrowFunctionExpression: 'body'
4129};
4130
4131function wrap(raw, parent) {
4132 if (!raw) { return; }
4133
4134 if ('length' in raw) {
4135 var i = raw.length;
4136 while (i--) { wrap(raw[i], parent); }
4137 return;
4138 }
4139
4140 // with e.g. shorthand properties, key and value are
4141 // the same node. We don't want to wrap an object twice
4142 if (raw.__wrapped) { return; }
4143 raw.__wrapped = true;
4144
4145 if (!keys[raw.type]) {
4146 keys[raw.type] = Object.keys(raw).filter(
4147 key => typeof raw[key] === 'object'
4148 );
4149 }
4150
4151 // special case – body-less if/for/while statements. TODO others?
4152 var bodyType = statementsWithBlocks[raw.type];
4153 if (bodyType && raw[bodyType].type !== 'BlockStatement') {
4154 var expression = raw[bodyType];
4155
4156 // create a synthetic block statement, otherwise all hell
4157 // breaks loose when it comes to block scoping
4158 raw[bodyType] = {
4159 start: expression.start,
4160 end: expression.end,
4161 type: 'BlockStatement',
4162 body: [expression],
4163 synthetic: true
4164 };
4165 }
4166
4167 raw.parent = parent;
4168 raw.program = parent.program || parent;
4169 raw.depth = parent.depth + 1;
4170 raw.keys = keys[raw.type];
4171 raw.indentation = undefined;
4172
4173 for (var i$1 = 0, list = keys[raw.type]; i$1 < list.length; i$1 += 1) {
4174 var key = list[i$1];
4175
4176 wrap(raw[key], raw);
4177 }
4178
4179 raw.program.magicString.addSourcemapLocation(raw.start);
4180 raw.program.magicString.addSourcemapLocation(raw.end);
4181
4182 var type =
4183 (raw.type === 'BlockStatement' ? BlockStatement : types[raw.type]) || Node;
4184 raw.__proto__ = type.prototype;
4185}
4186
4187function Program(source, ast, transforms, options) {
4188 this.type = 'Root';
4189
4190 // options
4191 this.jsx = options.jsx || 'React.createElement';
4192 this.jsxFragment = options.jsxFragment || 'React.Fragment';
4193 this.options = options;
4194
4195 this.source = source;
4196 this.magicString = new MagicString(source);
4197
4198 this.ast = ast;
4199 this.depth = 0;
4200
4201 wrap((this.body = ast), this);
4202 this.body.__proto__ = BlockStatement.prototype;
4203
4204 this.templateLiteralQuasis = Object.create(null);
4205 for (var i = 0; i < this.body.body.length; ++i) {
4206 if (!this.body.body[i].directive) {
4207 this.prependAt = this.body.body[i].start;
4208 break;
4209 }
4210 }
4211 this.objectWithoutPropertiesHelper = null;
4212
4213 this.indentExclusionElements = [];
4214 this.body.initialise(transforms);
4215
4216 this.indentExclusions = Object.create(null);
4217 for (var i$2 = 0, list = this.indentExclusionElements; i$2 < list.length; i$2 += 1) {
4218 var node = list[i$2];
4219
4220 for (var i$1 = node.start; i$1 < node.end; i$1 += 1) {
4221 this.indentExclusions[i$1] = true;
4222 }
4223 }
4224
4225 this.body.transpile(this.magicString, transforms);
4226}
4227
4228Program.prototype = {
4229 export(options) {
4230 if ( options === void 0 ) options = {};
4231
4232 return {
4233 code: this.magicString.toString(),
4234 map: this.magicString.generateMap({
4235 file: options.file,
4236 source: options.source,
4237 includeContent: options.includeContent !== false
4238 })
4239 };
4240 },
4241
4242 findNearest() {
4243 return null;
4244 },
4245
4246 findScope() {
4247 return null;
4248 },
4249
4250 getObjectWithoutPropertiesHelper(code) {
4251 if (!this.objectWithoutPropertiesHelper) {
4252 this.objectWithoutPropertiesHelper = this.body.scope.createIdentifier('objectWithoutProperties');
4253 code.prependLeft(this.prependAt, `function ${this.objectWithoutPropertiesHelper} (obj, exclude) { ` +
4254 `var target = {}; for (var k in obj) ` +
4255 `if (Object.prototype.hasOwnProperty.call(obj, k) && exclude.indexOf(k) === -1) ` +
4256 `target[k] = obj[k]; return target; }\n`
4257 );
4258 }
4259 return this.objectWithoutPropertiesHelper;
4260 }
4261};
4262
4263var matrix = {
4264 chrome: {
4265 48: 0b00010010101000110011111,
4266 49: 0b00010011111001111111111,
4267 50: 0b00010111111001111111111,
4268 51: 0b00010111111001111111111,
4269 52: 0b00011111111001111111111,
4270 53: 0b00011111111001111111111,
4271 54: 0b00011111111001111111111,
4272 55: 0b01011111111001111111111,
4273 56: 0b01011111111001111111111,
4274 57: 0b01011111111001111111111,
4275 58: 0b01111111111001111111111,
4276 59: 0b01111111111001111111111,
4277 60: 0b11111111111001111111111,
4278 61: 0b11111111111001111111111,
4279 62: 0b11111111111001111111111,
4280 63: 0b11111111111001111111111,
4281 64: 0b11111111111001111111111,
4282 65: 0b11111111111001111111111,
4283 66: 0b11111111111001111111111,
4284 67: 0b11111111111001111111111,
4285 68: 0b11111111111001111111111,
4286 69: 0b11111111111001111111111,
4287 70: 0b11111111111001111111111,
4288 71: 0b11111111111001111111111
4289 },
4290 firefox: {
4291 43: 0b00010011101000110111011,
4292 44: 0b00010011101000110111011,
4293 45: 0b00010011101000110111111,
4294 46: 0b00010111101000110111111,
4295 47: 0b00010111101000111111111,
4296 48: 0b00010111101000111111111,
4297 49: 0b00010111101000111111111,
4298 50: 0b00010111101000111111111,
4299 51: 0b00010111101001111111111,
4300 52: 0b01111111111001111111111,
4301 53: 0b01111111111001111111111,
4302 54: 0b01111111111001111111111,
4303 55: 0b11111111111001111111111,
4304 56: 0b11111111111001111111111,
4305 57: 0b11111111111001111111111,
4306 58: 0b11111111111001111111111,
4307 59: 0b11111111111001111111111,
4308 60: 0b11111111111001111111111,
4309 61: 0b11111111111001111111111,
4310 62: 0b11111111111001111111111,
4311 63: 0b11111111111001111111111,
4312 64: 0b11111111111001111111111
4313 },
4314 safari: {
4315 8: 0b00010000000000000001001,
4316 9: 0b00010010001000011011101,
4317 10: 0b00110111111001111111111,
4318 '10.1': 0b01111111111001111111111,
4319 11: 0b01111111111001111111111,
4320 '11.1': 0b11111111111001111111111,
4321 12: 0b11111111111001111111111
4322 },
4323 ie: {
4324 8: 0b00000000000000000000000,
4325 9: 0b00010000000000000000001,
4326 10: 0b00010000000000000000001,
4327 11: 0b00010000000000000000001 // no let/const in for loops
4328 },
4329 edge: {
4330 12: 0b00010010101000010011011,
4331 13: 0b00010111101000110011111,
4332 14: 0b00111111101001111111111,
4333 15: 0b01111111101001111111111,
4334 16: 0b01111111101001111111111,
4335 17: 0b01111111101001111111111,
4336 18: 0b01111111101001111111111,
4337 19: 0b01111111101001111111111
4338 },
4339 node: {
4340 '0.10': 0b00010000000000000000001,
4341 '0.12': 0b00010000000000010000001,
4342 4: 0b00010010001000110011111,
4343 5: 0b00010010001000110011111,
4344 6: 0b00010111111001111111111,
4345 8: 0b01111111111001111111111,
4346 '8.3': 0b11111111111001111111111,
4347 '8.7': 0b11111111111001111111111,
4348 '8.10': 0b11111111111001111111111
4349 }
4350};
4351
4352var features = [
4353 'getterSetter',
4354 'arrow',
4355 'classes',
4356 'computedProperty',
4357 'conciseMethodProperty',
4358 'defaultParameter',
4359 'destructuring',
4360 'forOf',
4361 'generator',
4362 'letConst',
4363 'moduleExport',
4364 'moduleImport',
4365 'numericLiteral',
4366 'parameterDestructuring',
4367 'spreadRest',
4368 'stickyRegExp',
4369 'templateString',
4370 'unicodeRegExp',
4371
4372 // ES2016
4373 'exponentiation',
4374
4375 // additional transforms, not from
4376 // https://featuretests.io
4377 'reservedProperties',
4378
4379 'trailingFunctionCommas',
4380 'asyncAwait',
4381 'objectRestSpread'
4382];
4383
4384var version = "0.20.0";
4385
4386var parser = acorn.Parser.extend(acornDynamicImport, acornJsx());
4387
4388var dangerousTransforms = ['dangerousTaggedTemplateString', 'dangerousForOf'];
4389
4390function target(target) {
4391 var targets = Object.keys(target);
4392 var bitmask = targets.length
4393 ? 0b11111111111111111111111
4394 : 0b00010000000000000000001;
4395
4396 Object.keys(target).forEach(environment => {
4397 var versions = matrix[environment];
4398 if (!versions)
4399 { throw new Error(
4400 `Unknown environment '${environment}'. Please raise an issue at https://github.com/bublejs/buble/issues`
4401 ); }
4402
4403 var targetVersion = target[environment];
4404 if (!(targetVersion in versions))
4405 { throw new Error(
4406 `Support data exists for the following versions of ${environment}: ${Object.keys(
4407 versions
4408 ).join(
4409 ', '
4410 )}. Please raise an issue at https://github.com/bublejs/buble/issues`
4411 ); }
4412 var support = versions[targetVersion];
4413
4414 bitmask &= support;
4415 });
4416
4417 var transforms = Object.create(null);
4418 features.forEach((name, i) => {
4419 transforms[name] = !(bitmask & (1 << i));
4420 });
4421
4422 dangerousTransforms.forEach(name => {
4423 transforms[name] = false;
4424 });
4425
4426 return transforms;
4427}
4428
4429function transform(source, options) {
4430 if ( options === void 0 ) options = {};
4431
4432 var ast;
4433 var jsx = null;
4434
4435 try {
4436 ast = parser.parse(source, {
4437 ecmaVersion: 10,
4438 preserveParens: true,
4439 sourceType: 'module',
4440 allowAwaitOutsideFunction: true,
4441 allowReturnOutsideFunction: true,
4442 allowHashBang: true,
4443 onComment: (block, text) => {
4444 if (!jsx) {
4445 var match = /@jsx\s+([^\s]+)/.exec(text);
4446 if (match) { jsx = match[1]; }
4447 }
4448 }
4449 });
4450 options.jsx = jsx || options.jsx;
4451 } catch (err) {
4452 err.snippet = getSnippet(source, err.loc);
4453 err.toString = () => `${err.name}: ${err.message}\n${err.snippet}`;
4454 throw err;
4455 }
4456
4457 var transforms = target(options.target || {});
4458 Object.keys(options.transforms || {}).forEach(name => {
4459 if (name === 'modules') {
4460 if (!('moduleImport' in options.transforms))
4461 { transforms.moduleImport = options.transforms.modules; }
4462 if (!('moduleExport' in options.transforms))
4463 { transforms.moduleExport = options.transforms.modules; }
4464 return;
4465 }
4466
4467 if (!(name in transforms)) { throw new Error(`Unknown transform '${name}'`); }
4468 transforms[name] = options.transforms[name];
4469 });
4470 if (options.objectAssign === true) { options.objectAssign = 'Object.assign'; }
4471 return new Program(source, ast, transforms, options).export(options);
4472}
4473
4474exports.VERSION = version;
4475exports.target = target;
4476exports.transform = transform;
4477//# sourceMappingURL=buble.cjs.js.map