UNPKG

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