Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
MR414N-ID
GitHub Repository: MR414N-ID/botku2
Path: blob/master/node_modules/@javascript-obfuscator/escodegen/escodegen.js
1126 views
1
/*
2
Copyright (C) 2012-2014 Yusuke Suzuki <[email protected]>
3
Copyright (C) 2015 Ingvar Stepanyan <[email protected]>
4
Copyright (C) 2014 Ivan Nikulin <[email protected]>
5
Copyright (C) 2012-2013 Michael Ficarra <[email protected]>
6
Copyright (C) 2012-2013 Mathias Bynens <[email protected]>
7
Copyright (C) 2013 Irakli Gozalishvili <[email protected]>
8
Copyright (C) 2012 Robert Gust-Bardon <[email protected]>
9
Copyright (C) 2012 John Freeman <[email protected]>
10
Copyright (C) 2011-2012 Ariya Hidayat <[email protected]>
11
Copyright (C) 2012 Joost-Wim Boekesteijn <[email protected]>
12
Copyright (C) 2012 Kris Kowal <[email protected]>
13
Copyright (C) 2012 Arpad Borsos <[email protected]>
14
15
Redistribution and use in source and binary forms, with or without
16
modification, are permitted provided that the following conditions are met:
17
18
* Redistributions of source code must retain the above copyright
19
notice, this list of conditions and the following disclaimer.
20
* Redistributions in binary form must reproduce the above copyright
21
notice, this list of conditions and the following disclaimer in the
22
documentation and/or other materials provided with the distribution.
23
24
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27
ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
28
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34
*/
35
36
/*global exports:true, require:true, global:true*/
37
(function () {
38
'use strict';
39
40
var Syntax,
41
Precedence,
42
BinaryPrecedence,
43
SourceNode,
44
estraverse,
45
esutils,
46
base,
47
indent,
48
json,
49
renumber,
50
hexadecimal,
51
quotes,
52
escapeless,
53
newline,
54
space,
55
parentheses,
56
semicolons,
57
safeConcatenation,
58
directive,
59
extra,
60
parse,
61
sourceMap,
62
sourceCode,
63
preserveBlankLines,
64
FORMAT_MINIFY,
65
FORMAT_DEFAULTS;
66
67
estraverse = require('@javascript-obfuscator/estraverse');
68
esutils = require('esutils');
69
70
Syntax = estraverse.Syntax;
71
72
// Generation is done by generateExpression.
73
function isExpression(node) {
74
return CodeGenerator.Expression.hasOwnProperty(node.type);
75
}
76
77
// Generation is done by generateStatement.
78
function isStatement(node) {
79
return CodeGenerator.Statement.hasOwnProperty(node.type);
80
}
81
82
Precedence = {
83
Sequence: 0,
84
Yield: 1,
85
Assignment: 1,
86
Conditional: 2,
87
ArrowFunction: 2,
88
NullishCoalescing: 3,
89
LogicalOR: 3,
90
LogicalAND: 4,
91
BitwiseOR: 5,
92
BitwiseXOR: 6,
93
BitwiseAND: 7,
94
Equality: 8,
95
Relational: 9,
96
BitwiseSHIFT: 10,
97
Additive: 11,
98
Multiplicative: 12,
99
Exponentiation: 13,
100
Await: 14,
101
Unary: 14,
102
Postfix: 15,
103
OptionalChaining: 16,
104
Call: 17,
105
New: 18,
106
TaggedTemplate: 19,
107
Member: 20,
108
Primary: 21
109
};
110
111
BinaryPrecedence = {
112
'??': Precedence.NullishCoalescing,
113
'||': Precedence.LogicalOR,
114
'&&': Precedence.LogicalAND,
115
'|': Precedence.BitwiseOR,
116
'^': Precedence.BitwiseXOR,
117
'&': Precedence.BitwiseAND,
118
'==': Precedence.Equality,
119
'!=': Precedence.Equality,
120
'===': Precedence.Equality,
121
'!==': Precedence.Equality,
122
'is': Precedence.Equality,
123
'isnt': Precedence.Equality,
124
'<': Precedence.Relational,
125
'>': Precedence.Relational,
126
'<=': Precedence.Relational,
127
'>=': Precedence.Relational,
128
'in': Precedence.Relational,
129
'instanceof': Precedence.Relational,
130
'<<': Precedence.BitwiseSHIFT,
131
'>>': Precedence.BitwiseSHIFT,
132
'>>>': Precedence.BitwiseSHIFT,
133
'+': Precedence.Additive,
134
'-': Precedence.Additive,
135
'*': Precedence.Multiplicative,
136
'%': Precedence.Multiplicative,
137
'/': Precedence.Multiplicative,
138
'**': Precedence.Exponentiation
139
};
140
141
//Flags
142
var F_ALLOW_IN = 1,
143
F_ALLOW_CALL = 1 << 1,
144
F_ALLOW_UNPARATH_NEW = 1 << 2,
145
F_FUNC_BODY = 1 << 3,
146
F_DIRECTIVE_CTX = 1 << 4,
147
F_SEMICOLON_OPT = 1 << 5;
148
149
//Expression flag sets
150
//NOTE: Flag order:
151
// F_ALLOW_IN
152
// F_ALLOW_CALL
153
// F_ALLOW_UNPARATH_NEW
154
var E_FTT = F_ALLOW_CALL | F_ALLOW_UNPARATH_NEW,
155
E_TTF = F_ALLOW_IN | F_ALLOW_CALL,
156
E_TTT = F_ALLOW_IN | F_ALLOW_CALL | F_ALLOW_UNPARATH_NEW,
157
E_TFF = F_ALLOW_IN,
158
E_FFT = F_ALLOW_UNPARATH_NEW,
159
E_TFT = F_ALLOW_IN | F_ALLOW_UNPARATH_NEW;
160
161
//Statement flag sets
162
//NOTE: Flag order:
163
// F_ALLOW_IN
164
// F_FUNC_BODY
165
// F_DIRECTIVE_CTX
166
// F_SEMICOLON_OPT
167
var S_TFFF = F_ALLOW_IN,
168
S_TFFT = F_ALLOW_IN | F_SEMICOLON_OPT,
169
S_FFFF = 0x00,
170
S_TFTF = F_ALLOW_IN | F_DIRECTIVE_CTX,
171
S_TTFF = F_ALLOW_IN | F_FUNC_BODY;
172
173
function getDefaultOptions() {
174
// default options
175
return {
176
indent: null,
177
base: null,
178
parse: null,
179
comment: false,
180
format: {
181
indent: {
182
style: ' ',
183
base: 0,
184
adjustMultilineComment: false
185
},
186
newline: '\n',
187
space: ' ',
188
json: false,
189
renumber: false,
190
hexadecimal: false,
191
quotes: 'single',
192
escapeless: false,
193
compact: false,
194
parentheses: true,
195
semicolons: true,
196
safeConcatenation: false,
197
preserveBlankLines: false
198
},
199
moz: {
200
comprehensionExpressionStartsWithAssignment: false,
201
starlessGenerator: false
202
},
203
sourceMap: null,
204
sourceMapRoot: null,
205
sourceMapWithCode: false,
206
directive: false,
207
raw: true,
208
verbatim: null,
209
sourceCode: null
210
};
211
}
212
213
function stringRepeat(str, num) {
214
var result = '';
215
216
for (num |= 0; num > 0; num >>>= 1, str += str) {
217
if (num & 1) {
218
result += str;
219
}
220
}
221
222
return result;
223
}
224
225
function hasLineTerminator(str) {
226
return (/[\r\n]/g).test(str);
227
}
228
229
function endsWithLineTerminator(str) {
230
var len = str.length;
231
return len && esutils.code.isLineTerminator(str.charCodeAt(len - 1));
232
}
233
234
function merge(target, override) {
235
var key;
236
for (key in override) {
237
if (override.hasOwnProperty(key)) {
238
target[key] = override[key];
239
}
240
}
241
return target;
242
}
243
244
function updateDeeply(target, override) {
245
var key, val;
246
247
function isHashObject(target) {
248
return typeof target === 'object' && target instanceof Object && !(target instanceof RegExp);
249
}
250
251
for (key in override) {
252
if (override.hasOwnProperty(key)) {
253
val = override[key];
254
if (isHashObject(val)) {
255
if (isHashObject(target[key])) {
256
updateDeeply(target[key], val);
257
} else {
258
target[key] = updateDeeply({}, val);
259
}
260
} else {
261
target[key] = val;
262
}
263
}
264
}
265
return target;
266
}
267
268
function generateNumber(value) {
269
var result, point, temp, exponent, pos;
270
271
if (value !== value) {
272
throw new Error('Numeric literal whose value is NaN');
273
}
274
if (value < 0 || (value === 0 && 1 / value < 0)) {
275
throw new Error('Numeric literal whose value is negative');
276
}
277
278
if (value === 1 / 0) {
279
return json ? 'null' : renumber ? '1e400' : '1e+400';
280
}
281
282
result = '' + value;
283
if (!renumber || result.length < 3) {
284
return result;
285
}
286
287
point = result.indexOf('.');
288
if (!json && result.charCodeAt(0) === 0x30 /* 0 */ && point === 1) {
289
point = 0;
290
result = result.slice(1);
291
}
292
temp = result;
293
result = result.replace('e+', 'e');
294
exponent = 0;
295
if ((pos = temp.indexOf('e')) > 0) {
296
exponent = +temp.slice(pos + 1);
297
temp = temp.slice(0, pos);
298
}
299
if (point >= 0) {
300
exponent -= temp.length - point - 1;
301
temp = +(temp.slice(0, point) + temp.slice(point + 1)) + '';
302
}
303
pos = 0;
304
while (temp.charCodeAt(temp.length + pos - 1) === 0x30 /* 0 */) {
305
--pos;
306
}
307
if (pos !== 0) {
308
exponent -= pos;
309
temp = temp.slice(0, pos);
310
}
311
if (exponent !== 0) {
312
temp += 'e' + exponent;
313
}
314
if ((temp.length < result.length ||
315
(hexadecimal && value > 1e12 && Math.floor(value) === value && (temp = '0x' + value.toString(16)).length < result.length)) &&
316
+temp === value) {
317
result = temp;
318
}
319
320
return result;
321
}
322
323
// Generate valid RegExp expression.
324
// This function is based on https://github.com/Constellation/iv Engine
325
326
function escapeRegExpCharacter(ch, previousIsBackslash) {
327
// not handling '\' and handling \u2028 or \u2029 to unicode escape sequence
328
if ((ch & ~1) === 0x2028) {
329
return (previousIsBackslash ? 'u' : '\\u') + ((ch === 0x2028) ? '2028' : '2029');
330
} else if (ch === 10 || ch === 13) { // \n, \r
331
return (previousIsBackslash ? '' : '\\') + ((ch === 10) ? 'n' : 'r');
332
}
333
return String.fromCharCode(ch);
334
}
335
336
function generateRegExp(reg) {
337
var match, result, flags, i, iz, ch, characterInBrack, previousIsBackslash;
338
339
result = reg.toString();
340
341
if (reg.source) {
342
// extract flag from toString result
343
match = result.match(/\/([^/]*)$/);
344
if (!match) {
345
return result;
346
}
347
348
flags = match[1];
349
result = '';
350
351
characterInBrack = false;
352
previousIsBackslash = false;
353
for (i = 0, iz = reg.source.length; i < iz; ++i) {
354
ch = reg.source.charCodeAt(i);
355
356
if (!previousIsBackslash) {
357
if (characterInBrack) {
358
if (ch === 93) { // ]
359
characterInBrack = false;
360
}
361
} else {
362
if (ch === 47) { // /
363
result += '\\';
364
} else if (ch === 91) { // [
365
characterInBrack = true;
366
}
367
}
368
result += escapeRegExpCharacter(ch, previousIsBackslash);
369
previousIsBackslash = ch === 92; // \
370
} else {
371
// if new RegExp("\\\n') is provided, create /\n/
372
result += escapeRegExpCharacter(ch, previousIsBackslash);
373
// prevent like /\\[/]/
374
previousIsBackslash = false;
375
}
376
}
377
378
return '/' + result + '/' + flags;
379
}
380
381
return result;
382
}
383
384
function escapeAllowedCharacter(code, next) {
385
var hex;
386
387
if (code === 0x08 /* \b */) {
388
return '\\b';
389
}
390
391
if (code === 0x0C /* \f */) {
392
return '\\f';
393
}
394
395
if (code === 0x09 /* \t */) {
396
return '\\t';
397
}
398
399
hex = code.toString(16).toUpperCase();
400
if (json || code > 0xFF) {
401
return '\\u' + '0000'.slice(hex.length) + hex;
402
} else if (code === 0x0000 && !esutils.code.isDecimalDigit(next)) {
403
return '\\0';
404
} else if (code === 0x000B /* \v */) { // '\v'
405
return '\\x0B';
406
} else {
407
return '\\x' + '00'.slice(hex.length) + hex;
408
}
409
}
410
411
function escapeDisallowedCharacter(code) {
412
if (code === 0x5C /* \ */) {
413
return '\\\\';
414
}
415
416
if (code === 0x0A /* \n */) {
417
return '\\n';
418
}
419
420
if (code === 0x0D /* \r */) {
421
return '\\r';
422
}
423
424
if (code === 0x2028) {
425
return '\\u2028';
426
}
427
428
if (code === 0x2029) {
429
return '\\u2029';
430
}
431
432
throw new Error('Incorrectly classified character');
433
}
434
435
function escapeDirective(str) {
436
var i, iz, code, quote;
437
438
quote = quotes === 'double' ? '"' : '\'';
439
for (i = 0, iz = str.length; i < iz; ++i) {
440
code = str.charCodeAt(i);
441
if (code === 0x27 /* ' */) {
442
quote = '"';
443
break;
444
} else if (code === 0x22 /* " */) {
445
quote = '\'';
446
break;
447
} else if (code === 0x5C /* \ */) {
448
++i;
449
}
450
}
451
452
return quote + str + quote;
453
}
454
455
function escapeString(str) {
456
var result = '', i, len, code, singleQuotes = 0, doubleQuotes = 0, single, quote;
457
458
for (i = 0, len = str.length; i < len; ++i) {
459
code = str.charCodeAt(i);
460
if (code === 0x27 /* ' */) {
461
++singleQuotes;
462
} else if (code === 0x22 /* " */) {
463
++doubleQuotes;
464
} else if (code === 0x2F /* / */ && json) {
465
result += '\\';
466
} else if (esutils.code.isLineTerminator(code) || code === 0x5C /* \ */) {
467
result += escapeDisallowedCharacter(code);
468
continue;
469
} else if (!esutils.code.isIdentifierPartES5(code) && (json && code < 0x20 /* SP */ || !json && !escapeless && (code < 0x20 /* SP */ || code > 0x7E /* ~ */))) {
470
result += escapeAllowedCharacter(code, str.charCodeAt(i + 1));
471
continue;
472
}
473
result += String.fromCharCode(code);
474
}
475
476
single = !(quotes === 'double' || (quotes === 'auto' && doubleQuotes < singleQuotes));
477
quote = single ? '\'' : '"';
478
479
if (!(single ? singleQuotes : doubleQuotes)) {
480
return quote + result + quote;
481
}
482
483
str = result;
484
result = quote;
485
486
for (i = 0, len = str.length; i < len; ++i) {
487
code = str.charCodeAt(i);
488
if ((code === 0x27 /* ' */ && single) || (code === 0x22 /* " */ && !single)) {
489
result += '\\';
490
}
491
result += String.fromCharCode(code);
492
}
493
494
return result + quote;
495
}
496
497
/**
498
* flatten an array to a string, where the array can contain
499
* either strings or nested arrays
500
*/
501
function flattenToString(arr) {
502
var i, iz, elem, result = '';
503
for (i = 0, iz = arr.length; i < iz; ++i) {
504
elem = arr[i];
505
result += Array.isArray(elem) ? flattenToString(elem) : elem;
506
}
507
return result;
508
}
509
510
/**
511
* convert generated to a SourceNode when source maps are enabled.
512
*/
513
function toSourceNodeWhenNeeded(generated, node) {
514
if (!sourceMap) {
515
// with no source maps, generated is either an
516
// array or a string. if an array, flatten it.
517
// if a string, just return it
518
if (Array.isArray(generated)) {
519
return flattenToString(generated);
520
} else {
521
return generated;
522
}
523
}
524
if (node == null) {
525
if (generated instanceof SourceNode) {
526
return generated;
527
} else {
528
node = {};
529
}
530
}
531
if (node.loc == null) {
532
return new SourceNode(null, null, sourceMap, generated, node.name || null);
533
}
534
return new SourceNode(node.loc.start.line, node.loc.start.column, (sourceMap === true ? node.loc.source || null : sourceMap), generated, node.name || null);
535
}
536
537
function noEmptySpace() {
538
return (space) ? space : ' ';
539
}
540
541
function join(left, right) {
542
var leftSource,
543
rightSource,
544
leftCharCode,
545
rightCharCode;
546
547
leftSource = toSourceNodeWhenNeeded(left).toString();
548
if (leftSource.length === 0) {
549
return [right];
550
}
551
552
rightSource = toSourceNodeWhenNeeded(right).toString();
553
if (rightSource.length === 0) {
554
return [left];
555
}
556
557
leftCharCode = leftSource.charCodeAt(leftSource.length - 1);
558
rightCharCode = rightSource.charCodeAt(0);
559
560
if ((leftCharCode === 0x2B /* + */ || leftCharCode === 0x2D /* - */) && leftCharCode === rightCharCode ||
561
esutils.code.isIdentifierPartES5(leftCharCode) && esutils.code.isIdentifierPartES5(rightCharCode) ||
562
leftCharCode === 0x2F /* / */ && rightCharCode === 0x69 /* i */) { // infix word operators all start with `i`
563
return [left, noEmptySpace(), right];
564
} else if (esutils.code.isWhiteSpace(leftCharCode) || esutils.code.isLineTerminator(leftCharCode) ||
565
esutils.code.isWhiteSpace(rightCharCode) || esutils.code.isLineTerminator(rightCharCode)) {
566
return [left, right];
567
}
568
return [left, space, right];
569
}
570
571
function addIndent(stmt) {
572
return [base, stmt];
573
}
574
575
function withIndent(fn) {
576
var previousBase;
577
previousBase = base;
578
base += indent;
579
fn(base);
580
base = previousBase;
581
}
582
583
function calculateSpaces(str) {
584
var i;
585
for (i = str.length - 1; i >= 0; --i) {
586
if (esutils.code.isLineTerminator(str.charCodeAt(i))) {
587
break;
588
}
589
}
590
return (str.length - 1) - i;
591
}
592
593
function adjustMultilineComment(value, specialBase) {
594
var array, i, len, line, j, spaces, previousBase, sn;
595
596
array = value.split(/\r\n|[\r\n]/);
597
spaces = Number.MAX_VALUE;
598
599
// first line doesn't have indentation
600
for (i = 1, len = array.length; i < len; ++i) {
601
line = array[i];
602
j = 0;
603
while (j < line.length && esutils.code.isWhiteSpace(line.charCodeAt(j))) {
604
++j;
605
}
606
if (spaces > j) {
607
spaces = j;
608
}
609
}
610
611
if (typeof specialBase !== 'undefined') {
612
// pattern like
613
// {
614
// var t = 20; /*
615
// * this is comment
616
// */
617
// }
618
previousBase = base;
619
if (array[1][spaces] === '*') {
620
specialBase += ' ';
621
}
622
base = specialBase;
623
} else {
624
if (spaces & 1) {
625
// /*
626
// *
627
// */
628
// If spaces are odd number, above pattern is considered.
629
// We waste 1 space.
630
--spaces;
631
}
632
previousBase = base;
633
}
634
635
for (i = 1, len = array.length; i < len; ++i) {
636
sn = toSourceNodeWhenNeeded(addIndent(array[i].slice(spaces)));
637
array[i] = sourceMap ? sn.join('') : sn;
638
}
639
640
base = previousBase;
641
642
return array.join('\n');
643
}
644
645
function generateComment(comment, specialBase) {
646
if (comment.type === 'Line') {
647
if (endsWithLineTerminator(comment.value)) {
648
return '//' + comment.value;
649
} else {
650
// Always use LineTerminator
651
var result = '//' + comment.value;
652
if (!preserveBlankLines) {
653
result += '\n';
654
}
655
return result;
656
}
657
}
658
if (extra.format.indent.adjustMultilineComment && /[\n\r]/.test(comment.value)) {
659
return adjustMultilineComment('/*' + comment.value + '*/', specialBase);
660
}
661
return '/*' + comment.value + '*/';
662
}
663
664
function addComments(stmt, result) {
665
var i, len, comment, save, tailingToStatement, specialBase, fragment,
666
extRange, range, prevRange, prefix, infix, suffix, count;
667
668
if (stmt.leadingComments && stmt.leadingComments.length > 0) {
669
save = result;
670
671
if (preserveBlankLines) {
672
comment = stmt.leadingComments[0];
673
result = [];
674
675
extRange = comment.extendedRange;
676
range = comment.range;
677
678
prefix = sourceCode.substring(extRange[0], range[0]);
679
count = (prefix.match(/\n/g) || []).length;
680
if (count > 0) {
681
result.push(stringRepeat('\n', count));
682
result.push(addIndent(generateComment(comment)));
683
} else {
684
result.push(prefix);
685
result.push(generateComment(comment));
686
}
687
688
prevRange = range;
689
690
for (i = 1, len = stmt.leadingComments.length; i < len; i++) {
691
comment = stmt.leadingComments[i];
692
range = comment.range;
693
694
infix = sourceCode.substring(prevRange[1], range[0]);
695
count = (infix.match(/\n/g) || []).length;
696
result.push(stringRepeat('\n', count));
697
result.push(addIndent(generateComment(comment)));
698
699
prevRange = range;
700
}
701
702
suffix = sourceCode.substring(range[1], extRange[1]);
703
count = (suffix.match(/\n/g) || []).length;
704
result.push(stringRepeat('\n', count));
705
} else {
706
comment = stmt.leadingComments[0];
707
result = [];
708
if (safeConcatenation && stmt.type === Syntax.Program && stmt.body.length === 0) {
709
result.push('\n');
710
}
711
result.push(generateComment(comment));
712
if (!endsWithLineTerminator(toSourceNodeWhenNeeded(result).toString())) {
713
result.push('\n');
714
}
715
716
for (i = 1, len = stmt.leadingComments.length; i < len; ++i) {
717
comment = stmt.leadingComments[i];
718
fragment = [generateComment(comment)];
719
if (!endsWithLineTerminator(toSourceNodeWhenNeeded(fragment).toString())) {
720
fragment.push('\n');
721
}
722
result.push(addIndent(fragment));
723
}
724
}
725
726
result.push(addIndent(save));
727
}
728
729
if (stmt.trailingComments) {
730
731
if (preserveBlankLines) {
732
comment = stmt.trailingComments[0];
733
extRange = comment.extendedRange;
734
range = comment.range;
735
736
prefix = sourceCode.substring(extRange[0], range[0]);
737
count = (prefix.match(/\n/g) || []).length;
738
739
if (count > 0) {
740
result.push(stringRepeat('\n', count));
741
result.push(addIndent(generateComment(comment)));
742
} else {
743
result.push(prefix);
744
result.push(generateComment(comment));
745
}
746
} else {
747
tailingToStatement = !endsWithLineTerminator(toSourceNodeWhenNeeded(result).toString());
748
specialBase = stringRepeat(' ', calculateSpaces(toSourceNodeWhenNeeded([base, result, indent]).toString()));
749
for (i = 0, len = stmt.trailingComments.length; i < len; ++i) {
750
comment = stmt.trailingComments[i];
751
if (tailingToStatement) {
752
// We assume target like following script
753
//
754
// var t = 20; /**
755
// * This is comment of t
756
// */
757
if (i === 0) {
758
// first case
759
result = [result, indent];
760
} else {
761
result = [result, specialBase];
762
}
763
result.push(generateComment(comment, specialBase));
764
} else {
765
result = [result, addIndent(generateComment(comment))];
766
}
767
if (i !== len - 1 && !endsWithLineTerminator(toSourceNodeWhenNeeded(result).toString())) {
768
result = [result, '\n'];
769
}
770
}
771
}
772
}
773
774
return result;
775
}
776
777
function generateBlankLines(start, end, result) {
778
var j, newlineCount = 0;
779
780
for (j = start; j < end; j++) {
781
if (sourceCode[j] === '\n') {
782
newlineCount++;
783
}
784
}
785
786
for (j = 1; j < newlineCount; j++) {
787
result.push(newline);
788
}
789
}
790
791
function parenthesize(text, current, should) {
792
if (current < should) {
793
return ['(', text, ')'];
794
}
795
return text;
796
}
797
798
function generateVerbatimString(string) {
799
var i, iz, result;
800
result = string.split(/\r\n|\n/);
801
for (i = 1, iz = result.length; i < iz; i++) {
802
result[i] = newline + base + result[i];
803
}
804
return result;
805
}
806
807
function generateVerbatim(expr, precedence) {
808
var verbatim, result, prec;
809
verbatim = expr[extra.verbatim];
810
811
if (typeof verbatim === 'string') {
812
result = parenthesize(generateVerbatimString(verbatim), Precedence.Sequence, precedence);
813
} else {
814
// verbatim is object
815
result = generateVerbatimString(verbatim.content);
816
prec = (verbatim.precedence != null) ? verbatim.precedence : Precedence.Sequence;
817
result = parenthesize(result, prec, precedence);
818
}
819
820
return toSourceNodeWhenNeeded(result, expr);
821
}
822
823
function CodeGenerator() {
824
}
825
826
// Helpers.
827
828
CodeGenerator.prototype.maybeBlock = function(stmt, flags) {
829
var result, noLeadingComment, that = this;
830
831
noLeadingComment = !extra.comment || !stmt.leadingComments;
832
833
if (stmt.type === Syntax.BlockStatement && noLeadingComment) {
834
return [space, this.generateStatement(stmt, flags)];
835
}
836
837
if (stmt.type === Syntax.EmptyStatement && noLeadingComment) {
838
return ';';
839
}
840
841
withIndent(function () {
842
result = [
843
newline,
844
addIndent(that.generateStatement(stmt, flags))
845
];
846
});
847
848
return result;
849
};
850
851
CodeGenerator.prototype.maybeBlockSuffix = function (stmt, result) {
852
var ends = endsWithLineTerminator(toSourceNodeWhenNeeded(result).toString());
853
if (stmt.type === Syntax.BlockStatement && (!extra.comment || !stmt.leadingComments) && !ends) {
854
return [result, space];
855
}
856
if (ends) {
857
return [result, base];
858
}
859
return [result, newline, base];
860
};
861
862
function generateIdentifier(node) {
863
var identifierName = node.name;
864
865
if (node.type === Syntax.PrivateIdentifier) {
866
identifierName = '#' + identifierName;
867
}
868
869
return toSourceNodeWhenNeeded(identifierName, node);
870
}
871
872
function generateAsyncPrefix(node, spaceRequired) {
873
return node.async ? 'async' + (spaceRequired ? noEmptySpace() : space) : '';
874
}
875
876
function generateStarSuffix(node) {
877
var isGenerator = node.generator && !extra.moz.starlessGenerator;
878
return isGenerator ? '*' + space : '';
879
}
880
881
function generateMethodPrefix(prop) {
882
var func = prop.value, prefix = '';
883
if (func.async) {
884
prefix += generateAsyncPrefix(func, !prop.computed);
885
}
886
if (func.generator) {
887
// avoid space before method name
888
prefix += generateStarSuffix(func) ? '*' : '';
889
}
890
return prefix;
891
}
892
893
CodeGenerator.prototype.generatePattern = function (node, precedence, flags) {
894
if (node.type === Syntax.Identifier) {
895
return generateIdentifier(node);
896
}
897
return this.generateExpression(node, precedence, flags);
898
};
899
900
CodeGenerator.prototype.generateFunctionParams = function (node) {
901
var i, iz, result, hasDefault;
902
903
hasDefault = false;
904
905
if (node.type === Syntax.ArrowFunctionExpression &&
906
!node.rest && (!node.defaults || node.defaults.length === 0) &&
907
node.params.length === 1 && node.params[0].type === Syntax.Identifier) {
908
// arg => { } case
909
result = [generateAsyncPrefix(node, true), generateIdentifier(node.params[0])];
910
} else {
911
result = node.type === Syntax.ArrowFunctionExpression ? [generateAsyncPrefix(node, false)] : [];
912
result.push('(');
913
if (node.defaults) {
914
hasDefault = true;
915
}
916
for (i = 0, iz = node.params.length; i < iz; ++i) {
917
if (hasDefault && node.defaults[i]) {
918
// Handle default values.
919
result.push(this.generateAssignment(node.params[i], node.defaults[i], '=', Precedence.Assignment, E_TTT));
920
} else {
921
result.push(this.generatePattern(node.params[i], Precedence.Assignment, E_TTT));
922
}
923
if (i + 1 < iz) {
924
result.push(',' + space);
925
}
926
}
927
928
if (node.rest) {
929
if (node.params.length) {
930
result.push(',' + space);
931
}
932
result.push('...');
933
result.push(generateIdentifier(node.rest));
934
}
935
936
result.push(')');
937
}
938
939
return result;
940
};
941
942
CodeGenerator.prototype.generateFunctionBody = function (node) {
943
var result, expr;
944
945
result = this.generateFunctionParams(node);
946
947
if (node.type === Syntax.ArrowFunctionExpression) {
948
result.push(space);
949
result.push('=>');
950
}
951
952
if (node.expression) {
953
result.push(space);
954
expr = this.generateExpression(node.body, Precedence.Assignment, E_TTT);
955
if (expr.toString().charAt(0) === '{') {
956
expr = ['(', expr, ')'];
957
}
958
result.push(expr);
959
} else {
960
result.push(this.maybeBlock(node.body, S_TTFF));
961
}
962
963
return result;
964
};
965
966
CodeGenerator.prototype.generateIterationForStatement = function (operator, stmt, flags) {
967
var result = ['for' + (stmt.await ? noEmptySpace() + 'await' : '') + space + '('], that = this;
968
withIndent(function () {
969
if (stmt.left.type === Syntax.VariableDeclaration) {
970
withIndent(function () {
971
result.push(stmt.left.kind + noEmptySpace());
972
result.push(that.generateStatement(stmt.left.declarations[0], S_FFFF));
973
});
974
} else {
975
result.push(that.generateExpression(stmt.left, Precedence.Call, E_TTT));
976
}
977
978
result = join(result, operator);
979
result = [join(
980
result,
981
that.generateExpression(stmt.right, Precedence.Assignment, E_TTT)
982
), ')'];
983
});
984
result.push(this.maybeBlock(stmt.body, flags));
985
return result;
986
};
987
988
CodeGenerator.prototype.generatePropertyKey = function (expr, computed) {
989
var result = [];
990
991
if (computed) {
992
result.push('[');
993
}
994
995
result.push(this.generateExpression(expr, Precedence.Assignment, E_TTT));
996
997
if (computed) {
998
result.push(']');
999
}
1000
1001
return result;
1002
};
1003
1004
CodeGenerator.prototype.generateAssignment = function (left, right, operator, precedence, flags) {
1005
if (Precedence.Assignment < precedence) {
1006
flags |= F_ALLOW_IN;
1007
}
1008
1009
return parenthesize(
1010
[
1011
this.generateExpression(left, Precedence.Call, flags),
1012
space + operator + space,
1013
this.generateExpression(right, Precedence.Assignment, flags)
1014
],
1015
Precedence.Assignment,
1016
precedence
1017
);
1018
};
1019
1020
CodeGenerator.prototype.semicolon = function (flags) {
1021
if (!semicolons && flags & F_SEMICOLON_OPT) {
1022
return '';
1023
}
1024
return ';';
1025
};
1026
1027
// Statements.
1028
1029
CodeGenerator.Statement = {
1030
1031
BlockStatement: function (stmt, flags) {
1032
var range, content, result = ['{', newline], that = this;
1033
1034
withIndent(function () {
1035
// handle functions without any code
1036
if (stmt.body.length === 0 && preserveBlankLines) {
1037
range = stmt.range;
1038
if (range[1] - range[0] > 2) {
1039
content = sourceCode.substring(range[0] + 1, range[1] - 1);
1040
if (content[0] === '\n') {
1041
result = ['{'];
1042
}
1043
result.push(content);
1044
}
1045
}
1046
1047
var i, iz, fragment, bodyFlags;
1048
bodyFlags = S_TFFF;
1049
if (flags & F_FUNC_BODY) {
1050
bodyFlags |= F_DIRECTIVE_CTX;
1051
}
1052
1053
for (i = 0, iz = stmt.body.length; i < iz; ++i) {
1054
if (preserveBlankLines) {
1055
// handle spaces before the first line
1056
if (i === 0) {
1057
if (stmt.body[0].leadingComments) {
1058
range = stmt.body[0].leadingComments[0].extendedRange;
1059
content = sourceCode.substring(range[0], range[1]);
1060
if (content[0] === '\n') {
1061
result = ['{'];
1062
}
1063
}
1064
if (!stmt.body[0].leadingComments) {
1065
generateBlankLines(stmt.range[0], stmt.body[0].range[0], result);
1066
}
1067
}
1068
1069
// handle spaces between lines
1070
if (i > 0) {
1071
if (!stmt.body[i - 1].trailingComments && !stmt.body[i].leadingComments) {
1072
generateBlankLines(stmt.body[i - 1].range[1], stmt.body[i].range[0], result);
1073
}
1074
}
1075
}
1076
1077
if (i === iz - 1) {
1078
bodyFlags |= F_SEMICOLON_OPT;
1079
}
1080
1081
if (stmt.body[i].leadingComments && preserveBlankLines) {
1082
fragment = that.generateStatement(stmt.body[i], bodyFlags);
1083
} else {
1084
fragment = addIndent(that.generateStatement(stmt.body[i], bodyFlags));
1085
}
1086
1087
result.push(fragment);
1088
if (!endsWithLineTerminator(toSourceNodeWhenNeeded(fragment).toString())) {
1089
if (preserveBlankLines && i < iz - 1) {
1090
// don't add a new line if there are leading coments
1091
// in the next statement
1092
if (!stmt.body[i + 1].leadingComments) {
1093
result.push(newline);
1094
}
1095
} else {
1096
result.push(newline);
1097
}
1098
}
1099
1100
if (preserveBlankLines) {
1101
// handle spaces after the last line
1102
if (i === iz - 1) {
1103
if (!stmt.body[i].trailingComments) {
1104
generateBlankLines(stmt.body[i].range[1], stmt.range[1], result);
1105
}
1106
}
1107
}
1108
}
1109
});
1110
1111
result.push(addIndent('}'));
1112
return result;
1113
},
1114
1115
BreakStatement: function (stmt, flags) {
1116
if (stmt.label) {
1117
return 'break ' + stmt.label.name + this.semicolon(flags);
1118
}
1119
return 'break' + this.semicolon(flags);
1120
},
1121
1122
ContinueStatement: function (stmt, flags) {
1123
if (stmt.label) {
1124
return 'continue ' + stmt.label.name + this.semicolon(flags);
1125
}
1126
return 'continue' + this.semicolon(flags);
1127
},
1128
1129
ClassBody: function (stmt, flags) {
1130
var result = [ '{', newline], that = this;
1131
1132
withIndent(function (indent) {
1133
var i, iz;
1134
1135
for (i = 0, iz = stmt.body.length; i < iz; ++i) {
1136
result.push(indent);
1137
result.push(that.generateExpression(stmt.body[i], Precedence.Sequence, E_TTT));
1138
if (i + 1 < iz) {
1139
result.push(newline);
1140
}
1141
}
1142
});
1143
1144
if (!endsWithLineTerminator(toSourceNodeWhenNeeded(result).toString())) {
1145
result.push(newline);
1146
}
1147
result.push(base);
1148
result.push('}');
1149
return result;
1150
},
1151
1152
ClassDeclaration: function (stmt, flags) {
1153
var result, fragment;
1154
result = ['class'];
1155
if (stmt.id) {
1156
result = join(result, this.generateExpression(stmt.id, Precedence.Sequence, E_TTT));
1157
}
1158
if (stmt.superClass) {
1159
fragment = join('extends', this.generateExpression(stmt.superClass, Precedence.Unary, E_TTT));
1160
result = join(result, fragment);
1161
}
1162
result.push(space);
1163
result.push(this.generateStatement(stmt.body, S_TFFT));
1164
return result;
1165
},
1166
1167
DirectiveStatement: function (stmt, flags) {
1168
if (extra.raw && stmt.raw) {
1169
return stmt.raw + this.semicolon(flags);
1170
}
1171
return escapeDirective(stmt.directive) + this.semicolon(flags);
1172
},
1173
1174
DoWhileStatement: function (stmt, flags) {
1175
// Because `do 42 while (cond)` is Syntax Error. We need semicolon.
1176
var result = join('do', this.maybeBlock(stmt.body, S_TFFF));
1177
result = this.maybeBlockSuffix(stmt.body, result);
1178
return join(result, [
1179
'while' + space + '(',
1180
this.generateExpression(stmt.test, Precedence.Sequence, E_TTT),
1181
')' + this.semicolon(flags)
1182
]);
1183
},
1184
1185
CatchClause: function (stmt, flags) {
1186
var result, that = this;
1187
withIndent(function () {
1188
var guard;
1189
1190
if (stmt.param) {
1191
result = [
1192
'catch' + space + '(',
1193
that.generateExpression(stmt.param, Precedence.Sequence, E_TTT),
1194
')'
1195
];
1196
1197
if (stmt.guard) {
1198
guard = that.generateExpression(stmt.guard, Precedence.Sequence, E_TTT);
1199
result.splice(2, 0, ' if ', guard);
1200
}
1201
} else {
1202
result = ['catch'];
1203
}
1204
});
1205
result.push(this.maybeBlock(stmt.body, S_TFFF));
1206
return result;
1207
},
1208
1209
DebuggerStatement: function (stmt, flags) {
1210
return 'debugger' + this.semicolon(flags);
1211
},
1212
1213
EmptyStatement: function (stmt, flags) {
1214
return ';';
1215
},
1216
1217
ExportDefaultDeclaration: function (stmt, flags) {
1218
var result = [ 'export' ], bodyFlags;
1219
1220
bodyFlags = (flags & F_SEMICOLON_OPT) ? S_TFFT : S_TFFF;
1221
1222
// export default HoistableDeclaration[Default]
1223
// export default AssignmentExpression[In] ;
1224
result = join(result, 'default');
1225
if (isStatement(stmt.declaration)) {
1226
result = join(result, this.generateStatement(stmt.declaration, bodyFlags));
1227
} else {
1228
result = join(result, this.generateExpression(stmt.declaration, Precedence.Assignment, E_TTT) + this.semicolon(flags));
1229
}
1230
return result;
1231
},
1232
1233
ExportNamedDeclaration: function (stmt, flags) {
1234
var result = [ 'export' ], bodyFlags, that = this;
1235
1236
bodyFlags = (flags & F_SEMICOLON_OPT) ? S_TFFT : S_TFFF;
1237
1238
// export VariableStatement
1239
// export Declaration[Default]
1240
if (stmt.declaration) {
1241
return join(result, this.generateStatement(stmt.declaration, bodyFlags));
1242
}
1243
1244
// export ExportClause[NoReference] FromClause ;
1245
// export ExportClause ;
1246
if (stmt.specifiers) {
1247
if (stmt.specifiers.length === 0) {
1248
result = join(result, '{' + space + '}');
1249
} else if (stmt.specifiers[0].type === Syntax.ExportBatchSpecifier) {
1250
result = join(result, this.generateExpression(stmt.specifiers[0], Precedence.Sequence, E_TTT));
1251
} else {
1252
result = join(result, '{');
1253
withIndent(function (indent) {
1254
var i, iz;
1255
result.push(newline);
1256
for (i = 0, iz = stmt.specifiers.length; i < iz; ++i) {
1257
result.push(indent);
1258
result.push(that.generateExpression(stmt.specifiers[i], Precedence.Sequence, E_TTT));
1259
if (i + 1 < iz) {
1260
result.push(',' + newline);
1261
}
1262
}
1263
});
1264
if (!endsWithLineTerminator(toSourceNodeWhenNeeded(result).toString())) {
1265
result.push(newline);
1266
}
1267
result.push(base + '}');
1268
}
1269
1270
if (stmt.source) {
1271
result = join(result, [
1272
'from' + space,
1273
// ModuleSpecifier
1274
this.generateExpression(stmt.source, Precedence.Sequence, E_TTT),
1275
this.semicolon(flags)
1276
]);
1277
} else {
1278
result.push(this.semicolon(flags));
1279
}
1280
}
1281
return result;
1282
},
1283
1284
ExportAllDeclaration: function (stmt, flags) {
1285
// export * FromClause ;
1286
var result = [
1287
'export' + space,
1288
'*' + space
1289
];
1290
1291
if (stmt.exported) {
1292
result.push('as ' + stmt.exported.name + ' ');
1293
}
1294
1295
result = join(result, [
1296
'from' + space,
1297
// ModuleSpecifier
1298
this.generateExpression(stmt.source, Precedence.Sequence, E_TTT),
1299
this.semicolon(flags)
1300
]);
1301
1302
return result;
1303
},
1304
1305
ExpressionStatement: function (stmt, flags) {
1306
var result, fragment;
1307
1308
function isClassPrefixed(fragment) {
1309
var code;
1310
if (fragment.slice(0, 5) !== 'class') {
1311
return false;
1312
}
1313
code = fragment.charCodeAt(5);
1314
return code === 0x7B /* '{' */ || esutils.code.isWhiteSpace(code) || esutils.code.isLineTerminator(code);
1315
}
1316
1317
function isFunctionPrefixed(fragment) {
1318
var code;
1319
if (fragment.slice(0, 8) !== 'function') {
1320
return false;
1321
}
1322
code = fragment.charCodeAt(8);
1323
return code === 0x28 /* '(' */ || esutils.code.isWhiteSpace(code) || code === 0x2A /* '*' */ || esutils.code.isLineTerminator(code);
1324
}
1325
1326
function isAsyncPrefixed(fragment) {
1327
var code, i, iz;
1328
if (fragment.slice(0, 5) !== 'async') {
1329
return false;
1330
}
1331
if (!esutils.code.isWhiteSpace(fragment.charCodeAt(5))) {
1332
return false;
1333
}
1334
for (i = 6, iz = fragment.length; i < iz; ++i) {
1335
if (!esutils.code.isWhiteSpace(fragment.charCodeAt(i))) {
1336
break;
1337
}
1338
}
1339
if (i === iz) {
1340
return false;
1341
}
1342
if (fragment.slice(i, i + 8) !== 'function') {
1343
return false;
1344
}
1345
code = fragment.charCodeAt(i + 8);
1346
return code === 0x28 /* '(' */ || esutils.code.isWhiteSpace(code) || code === 0x2A /* '*' */ || esutils.code.isLineTerminator(code);
1347
}
1348
1349
result = [this.generateExpression(stmt.expression, Precedence.Sequence, E_TTT)];
1350
// 12.4 '{', 'function', 'class' is not allowed in this position.
1351
// wrap expression with parentheses
1352
fragment = toSourceNodeWhenNeeded(result).toString();
1353
if (fragment.charCodeAt(0) === 0x7B /* '{' */ || // ObjectExpression
1354
isClassPrefixed(fragment) ||
1355
isFunctionPrefixed(fragment) ||
1356
isAsyncPrefixed(fragment) ||
1357
(directive && (flags & F_DIRECTIVE_CTX) && stmt.expression.type === Syntax.Literal && typeof stmt.expression.value === 'string')) {
1358
result = ['(', result, ')' + this.semicolon(flags)];
1359
} else {
1360
result.push(this.semicolon(flags));
1361
}
1362
return result;
1363
},
1364
1365
ImportDeclaration: function (stmt, flags) {
1366
// ES6: 15.2.1 valid import declarations:
1367
// - import ImportClause FromClause ;
1368
// - import ModuleSpecifier ;
1369
var result, cursor, that = this;
1370
1371
// If no ImportClause is present,
1372
// this should be `import ModuleSpecifier` so skip `from`
1373
// ModuleSpecifier is StringLiteral.
1374
if (stmt.specifiers.length === 0) {
1375
// import ModuleSpecifier ;
1376
return [
1377
'import',
1378
space,
1379
// ModuleSpecifier
1380
this.generateExpression(stmt.source, Precedence.Sequence, E_TTT),
1381
this.semicolon(flags)
1382
];
1383
}
1384
1385
// import ImportClause FromClause ;
1386
result = [
1387
'import'
1388
];
1389
cursor = 0;
1390
1391
// ImportedBinding
1392
if (stmt.specifiers[cursor].type === Syntax.ImportDefaultSpecifier) {
1393
result = join(result, [
1394
this.generateExpression(stmt.specifiers[cursor], Precedence.Sequence, E_TTT)
1395
]);
1396
++cursor;
1397
}
1398
1399
if (stmt.specifiers[cursor]) {
1400
if (cursor !== 0) {
1401
result.push(',');
1402
}
1403
1404
if (stmt.specifiers[cursor].type === Syntax.ImportNamespaceSpecifier) {
1405
// NameSpaceImport
1406
result = join(result, [
1407
space,
1408
this.generateExpression(stmt.specifiers[cursor], Precedence.Sequence, E_TTT)
1409
]);
1410
} else {
1411
// NamedImports
1412
result.push(space + '{');
1413
1414
if ((stmt.specifiers.length - cursor) === 1) {
1415
// import { ... } from "...";
1416
result.push(space);
1417
result.push(this.generateExpression(stmt.specifiers[cursor], Precedence.Sequence, E_TTT));
1418
result.push(space + '}' + space);
1419
} else {
1420
// import {
1421
// ...,
1422
// ...,
1423
// } from "...";
1424
withIndent(function (indent) {
1425
var i, iz;
1426
result.push(newline);
1427
for (i = cursor, iz = stmt.specifiers.length; i < iz; ++i) {
1428
result.push(indent);
1429
result.push(that.generateExpression(stmt.specifiers[i], Precedence.Sequence, E_TTT));
1430
if (i + 1 < iz) {
1431
result.push(',' + newline);
1432
}
1433
}
1434
});
1435
if (!endsWithLineTerminator(toSourceNodeWhenNeeded(result).toString())) {
1436
result.push(newline);
1437
}
1438
result.push(base + '}' + space);
1439
}
1440
}
1441
}
1442
1443
result = join(result, [
1444
'from' + space,
1445
// ModuleSpecifier
1446
this.generateExpression(stmt.source, Precedence.Sequence, E_TTT),
1447
this.semicolon(flags)
1448
]);
1449
return result;
1450
},
1451
1452
VariableDeclarator: function (stmt, flags) {
1453
var itemFlags = (flags & F_ALLOW_IN) ? E_TTT : E_FTT;
1454
if (stmt.init) {
1455
return [
1456
this.generateExpression(stmt.id, Precedence.Assignment, itemFlags),
1457
space,
1458
'=',
1459
space,
1460
this.generateExpression(stmt.init, Precedence.Assignment, itemFlags)
1461
];
1462
}
1463
return this.generatePattern(stmt.id, Precedence.Assignment, itemFlags);
1464
},
1465
1466
VariableDeclaration: function (stmt, flags) {
1467
// VariableDeclarator is typed as Statement,
1468
// but joined with comma (not LineTerminator).
1469
// So if comment is attached to target node, we should specialize.
1470
var result, i, iz, node, bodyFlags, that = this;
1471
1472
result = [ stmt.kind ];
1473
1474
bodyFlags = (flags & F_ALLOW_IN) ? S_TFFF : S_FFFF;
1475
1476
function block() {
1477
node = stmt.declarations[0];
1478
if (extra.comment && node.leadingComments) {
1479
result.push('\n');
1480
result.push(addIndent(that.generateStatement(node, bodyFlags)));
1481
} else {
1482
result.push(noEmptySpace());
1483
result.push(that.generateStatement(node, bodyFlags));
1484
}
1485
1486
for (i = 1, iz = stmt.declarations.length; i < iz; ++i) {
1487
node = stmt.declarations[i];
1488
if (extra.comment && node.leadingComments) {
1489
result.push(',' + newline);
1490
result.push(addIndent(that.generateStatement(node, bodyFlags)));
1491
} else {
1492
result.push(',' + space);
1493
result.push(that.generateStatement(node, bodyFlags));
1494
}
1495
}
1496
}
1497
1498
if (stmt.declarations.length > 1) {
1499
withIndent(block);
1500
} else {
1501
block();
1502
}
1503
1504
result.push(this.semicolon(flags));
1505
1506
return result;
1507
},
1508
1509
StaticBlock: function (stmt, flags) {
1510
return [
1511
'static' + space,
1512
this.BlockStatement(stmt, flags)
1513
];
1514
},
1515
1516
ThrowStatement: function (stmt, flags) {
1517
return [join(
1518
'throw',
1519
this.generateExpression(stmt.argument, Precedence.Sequence, E_TTT)
1520
), this.semicolon(flags)];
1521
},
1522
1523
TryStatement: function (stmt, flags) {
1524
var result, i, iz, guardedHandlers;
1525
1526
result = ['try', this.maybeBlock(stmt.block, S_TFFF)];
1527
result = this.maybeBlockSuffix(stmt.block, result);
1528
1529
if (stmt.handlers) {
1530
// old interface
1531
for (i = 0, iz = stmt.handlers.length; i < iz; ++i) {
1532
result = join(result, this.generateStatement(stmt.handlers[i], S_TFFF));
1533
if (stmt.finalizer || i + 1 !== iz) {
1534
result = this.maybeBlockSuffix(stmt.handlers[i].body, result);
1535
}
1536
}
1537
} else {
1538
guardedHandlers = stmt.guardedHandlers || [];
1539
1540
for (i = 0, iz = guardedHandlers.length; i < iz; ++i) {
1541
result = join(result, this.generateStatement(guardedHandlers[i], S_TFFF));
1542
if (stmt.finalizer || i + 1 !== iz) {
1543
result = this.maybeBlockSuffix(guardedHandlers[i].body, result);
1544
}
1545
}
1546
1547
// new interface
1548
if (stmt.handler) {
1549
if (Array.isArray(stmt.handler)) {
1550
for (i = 0, iz = stmt.handler.length; i < iz; ++i) {
1551
result = join(result, this.generateStatement(stmt.handler[i], S_TFFF));
1552
if (stmt.finalizer || i + 1 !== iz) {
1553
result = this.maybeBlockSuffix(stmt.handler[i].body, result);
1554
}
1555
}
1556
} else {
1557
result = join(result, this.generateStatement(stmt.handler, S_TFFF));
1558
if (stmt.finalizer) {
1559
result = this.maybeBlockSuffix(stmt.handler.body, result);
1560
}
1561
}
1562
}
1563
}
1564
if (stmt.finalizer) {
1565
result = join(result, ['finally', this.maybeBlock(stmt.finalizer, S_TFFF)]);
1566
}
1567
return result;
1568
},
1569
1570
SwitchStatement: function (stmt, flags) {
1571
var result, fragment, i, iz, bodyFlags, that = this;
1572
withIndent(function () {
1573
result = [
1574
'switch' + space + '(',
1575
that.generateExpression(stmt.discriminant, Precedence.Sequence, E_TTT),
1576
')' + space + '{' + newline
1577
];
1578
});
1579
if (stmt.cases) {
1580
bodyFlags = S_TFFF;
1581
for (i = 0, iz = stmt.cases.length; i < iz; ++i) {
1582
if (i === iz - 1) {
1583
bodyFlags |= F_SEMICOLON_OPT;
1584
}
1585
fragment = addIndent(this.generateStatement(stmt.cases[i], bodyFlags));
1586
result.push(fragment);
1587
if (!endsWithLineTerminator(toSourceNodeWhenNeeded(fragment).toString())) {
1588
result.push(newline);
1589
}
1590
}
1591
}
1592
result.push(addIndent('}'));
1593
return result;
1594
},
1595
1596
SwitchCase: function (stmt, flags) {
1597
var result, fragment, i, iz, bodyFlags, that = this;
1598
withIndent(function () {
1599
if (stmt.test) {
1600
result = [
1601
join('case', that.generateExpression(stmt.test, Precedence.Sequence, E_TTT)),
1602
':'
1603
];
1604
} else {
1605
result = ['default:'];
1606
}
1607
1608
i = 0;
1609
iz = stmt.consequent.length;
1610
if (iz && stmt.consequent[0].type === Syntax.BlockStatement) {
1611
fragment = that.maybeBlock(stmt.consequent[0], S_TFFF);
1612
result.push(fragment);
1613
i = 1;
1614
}
1615
1616
if (i !== iz && !endsWithLineTerminator(toSourceNodeWhenNeeded(result).toString())) {
1617
result.push(newline);
1618
}
1619
1620
bodyFlags = S_TFFF;
1621
for (; i < iz; ++i) {
1622
if (i === iz - 1 && flags & F_SEMICOLON_OPT) {
1623
bodyFlags |= F_SEMICOLON_OPT;
1624
}
1625
fragment = addIndent(that.generateStatement(stmt.consequent[i], bodyFlags));
1626
result.push(fragment);
1627
if (i + 1 !== iz && !endsWithLineTerminator(toSourceNodeWhenNeeded(fragment).toString())) {
1628
result.push(newline);
1629
}
1630
}
1631
});
1632
return result;
1633
},
1634
1635
IfStatement: function (stmt, flags) {
1636
var result, bodyFlags, semicolonOptional, that = this;
1637
withIndent(function () {
1638
result = [
1639
'if' + space + '(',
1640
that.generateExpression(stmt.test, Precedence.Sequence, E_TTT),
1641
')'
1642
];
1643
});
1644
semicolonOptional = flags & F_SEMICOLON_OPT;
1645
bodyFlags = S_TFFF;
1646
if (semicolonOptional) {
1647
bodyFlags |= F_SEMICOLON_OPT;
1648
}
1649
if (stmt.alternate) {
1650
result.push(this.maybeBlock(stmt.consequent, S_TFFF));
1651
result = this.maybeBlockSuffix(stmt.consequent, result);
1652
if (stmt.alternate.type === Syntax.IfStatement) {
1653
result = join(result, ['else ', this.generateStatement(stmt.alternate, bodyFlags)]);
1654
} else {
1655
result = join(result, join('else', this.maybeBlock(stmt.alternate, bodyFlags)));
1656
}
1657
} else {
1658
result.push(this.maybeBlock(stmt.consequent, bodyFlags));
1659
}
1660
return result;
1661
},
1662
1663
ForStatement: function (stmt, flags) {
1664
var result, that = this;
1665
withIndent(function () {
1666
result = ['for' + space + '('];
1667
if (stmt.init) {
1668
if (stmt.init.type === Syntax.VariableDeclaration) {
1669
result.push(that.generateStatement(stmt.init, S_FFFF));
1670
} else {
1671
// F_ALLOW_IN becomes false.
1672
result.push(that.generateExpression(stmt.init, Precedence.Sequence, E_FTT));
1673
result.push(';');
1674
}
1675
} else {
1676
result.push(';');
1677
}
1678
1679
if (stmt.test) {
1680
result.push(space);
1681
result.push(that.generateExpression(stmt.test, Precedence.Sequence, E_TTT));
1682
result.push(';');
1683
} else {
1684
result.push(';');
1685
}
1686
1687
if (stmt.update) {
1688
result.push(space);
1689
result.push(that.generateExpression(stmt.update, Precedence.Sequence, E_TTT));
1690
result.push(')');
1691
} else {
1692
result.push(')');
1693
}
1694
});
1695
1696
result.push(this.maybeBlock(stmt.body, flags & F_SEMICOLON_OPT ? S_TFFT : S_TFFF));
1697
return result;
1698
},
1699
1700
ForInStatement: function (stmt, flags) {
1701
return this.generateIterationForStatement('in', stmt, flags & F_SEMICOLON_OPT ? S_TFFT : S_TFFF);
1702
},
1703
1704
ForOfStatement: function (stmt, flags) {
1705
return this.generateIterationForStatement('of', stmt, flags & F_SEMICOLON_OPT ? S_TFFT : S_TFFF);
1706
},
1707
1708
LabeledStatement: function (stmt, flags) {
1709
return [stmt.label.name + ':', this.maybeBlock(stmt.body, flags & F_SEMICOLON_OPT ? S_TFFT : S_TFFF)];
1710
},
1711
1712
Program: function (stmt, flags) {
1713
var result, fragment, i, iz, bodyFlags;
1714
iz = stmt.body.length;
1715
result = [safeConcatenation && iz > 0 ? '\n' : ''];
1716
bodyFlags = S_TFTF;
1717
for (i = 0; i < iz; ++i) {
1718
if (!safeConcatenation && i === iz - 1) {
1719
bodyFlags |= F_SEMICOLON_OPT;
1720
}
1721
1722
if (preserveBlankLines) {
1723
// handle spaces before the first line
1724
if (i === 0) {
1725
if (!stmt.body[0].leadingComments) {
1726
generateBlankLines(stmt.range[0], stmt.body[i].range[0], result);
1727
}
1728
}
1729
1730
// handle spaces between lines
1731
if (i > 0) {
1732
if (!stmt.body[i - 1].trailingComments && !stmt.body[i].leadingComments) {
1733
generateBlankLines(stmt.body[i - 1].range[1], stmt.body[i].range[0], result);
1734
}
1735
}
1736
}
1737
1738
fragment = addIndent(this.generateStatement(stmt.body[i], bodyFlags));
1739
result.push(fragment);
1740
if (i + 1 < iz && !endsWithLineTerminator(toSourceNodeWhenNeeded(fragment).toString())) {
1741
if (preserveBlankLines) {
1742
if (!stmt.body[i + 1].leadingComments) {
1743
result.push(newline);
1744
}
1745
} else {
1746
result.push(newline);
1747
}
1748
}
1749
1750
if (preserveBlankLines) {
1751
// handle spaces after the last line
1752
if (i === iz - 1) {
1753
if (!stmt.body[i].trailingComments) {
1754
generateBlankLines(stmt.body[i].range[1], stmt.range[1], result);
1755
}
1756
}
1757
}
1758
}
1759
return result;
1760
},
1761
1762
FunctionDeclaration: function (stmt, flags) {
1763
return [
1764
generateAsyncPrefix(stmt, true),
1765
'function',
1766
generateStarSuffix(stmt) || noEmptySpace(),
1767
stmt.id ? generateIdentifier(stmt.id) : '',
1768
this.generateFunctionBody(stmt)
1769
];
1770
},
1771
1772
ReturnStatement: function (stmt, flags) {
1773
if (stmt.argument) {
1774
return [join(
1775
'return',
1776
this.generateExpression(stmt.argument, Precedence.Sequence, E_TTT)
1777
), this.semicolon(flags)];
1778
}
1779
return ['return' + this.semicolon(flags)];
1780
},
1781
1782
WhileStatement: function (stmt, flags) {
1783
var result, that = this;
1784
withIndent(function () {
1785
result = [
1786
'while' + space + '(',
1787
that.generateExpression(stmt.test, Precedence.Sequence, E_TTT),
1788
')'
1789
];
1790
});
1791
result.push(this.maybeBlock(stmt.body, flags & F_SEMICOLON_OPT ? S_TFFT : S_TFFF));
1792
return result;
1793
},
1794
1795
WithStatement: function (stmt, flags) {
1796
var result, that = this;
1797
withIndent(function () {
1798
result = [
1799
'with' + space + '(',
1800
that.generateExpression(stmt.object, Precedence.Sequence, E_TTT),
1801
')'
1802
];
1803
});
1804
result.push(this.maybeBlock(stmt.body, flags & F_SEMICOLON_OPT ? S_TFFT : S_TFFF));
1805
return result;
1806
}
1807
1808
};
1809
1810
merge(CodeGenerator.prototype, CodeGenerator.Statement);
1811
1812
// Expressions.
1813
1814
CodeGenerator.Expression = {
1815
1816
SequenceExpression: function (expr, precedence, flags) {
1817
var result, i, iz;
1818
if (Precedence.Sequence < precedence) {
1819
flags |= F_ALLOW_IN;
1820
}
1821
result = [];
1822
for (i = 0, iz = expr.expressions.length; i < iz; ++i) {
1823
result.push(this.generateExpression(expr.expressions[i], Precedence.Assignment, flags));
1824
if (i + 1 < iz) {
1825
result.push(',' + space);
1826
}
1827
}
1828
return parenthesize(result, Precedence.Sequence, precedence);
1829
},
1830
1831
AssignmentExpression: function (expr, precedence, flags) {
1832
return this.generateAssignment(expr.left, expr.right, expr.operator, precedence, flags);
1833
},
1834
1835
ArrowFunctionExpression: function (expr, precedence, flags) {
1836
return parenthesize(this.generateFunctionBody(expr), Precedence.ArrowFunction, precedence);
1837
},
1838
1839
ConditionalExpression: function (expr, precedence, flags) {
1840
if (Precedence.Conditional < precedence) {
1841
flags |= F_ALLOW_IN;
1842
}
1843
return parenthesize(
1844
[
1845
this.generateExpression(expr.test, Precedence.LogicalOR, flags),
1846
space + '?' + space,
1847
this.generateExpression(expr.consequent, Precedence.Assignment, flags),
1848
space + ':' + space,
1849
this.generateExpression(expr.alternate, Precedence.Assignment, flags)
1850
],
1851
Precedence.Conditional,
1852
precedence
1853
);
1854
},
1855
1856
LogicalExpression: function (expr, precedence, flags) {
1857
return this.BinaryExpression(expr, precedence, flags);
1858
},
1859
1860
BinaryExpression: function (expr, precedence, flags) {
1861
var result, leftPrecedence, rightPrecedence, currentPrecedence, fragment, leftSource;
1862
currentPrecedence = BinaryPrecedence[expr.operator];
1863
1864
leftPrecedence = currentPrecedence;
1865
rightPrecedence = currentPrecedence + 1;
1866
1867
switch (expr.operator) {
1868
case '**':
1869
leftPrecedence = Precedence.Postfix;
1870
rightPrecedence = currentPrecedence;
1871
break;
1872
1873
case '??':
1874
if (expr.left.type === Syntax.LogicalExpression && (expr.left.operator === '||' || expr.left.operator === '&&')) {
1875
leftPrecedence = BinaryPrecedence[expr.left.operator] + 1;
1876
}
1877
1878
if (expr.right.type === Syntax.LogicalExpression && expr.right.operator === '&&') {
1879
rightPrecedence = BinaryPrecedence[expr.right.operator] + 1;
1880
}
1881
1882
break;
1883
1884
case '||':
1885
if (expr.left.type === Syntax.LogicalExpression && expr.left.operator === '??') {
1886
leftPrecedence = BinaryPrecedence[expr.left.operator] + 1;
1887
}
1888
1889
break;
1890
}
1891
1892
if (currentPrecedence < precedence) {
1893
flags |= F_ALLOW_IN;
1894
}
1895
1896
fragment = this.generateExpression(expr.left, leftPrecedence, flags);
1897
1898
leftSource = fragment.toString();
1899
1900
if (leftSource.charCodeAt(leftSource.length - 1) === 0x2F /* / */ && esutils.code.isIdentifierPartES5(expr.operator.charCodeAt(0))) {
1901
result = [fragment, noEmptySpace(), expr.operator];
1902
} else {
1903
result = join(fragment, expr.operator);
1904
}
1905
1906
fragment = this.generateExpression(expr.right, rightPrecedence, flags);
1907
1908
if (expr.operator === '/' && fragment.toString().charAt(0) === '/' ||
1909
expr.operator.slice(-1) === '<' && fragment.toString().slice(0, 3) === '!--') {
1910
// If '/' concats with '/' or `<` concats with `!--`, it is interpreted as comment start
1911
result.push(noEmptySpace());
1912
result.push(fragment);
1913
} else {
1914
result = join(result, fragment);
1915
}
1916
1917
if (expr.operator === 'in' && !(flags & F_ALLOW_IN)) {
1918
return ['(', result, ')'];
1919
}
1920
return parenthesize(result, currentPrecedence, precedence);
1921
},
1922
1923
CallExpression: function (expr, precedence, flags) {
1924
var result, i, iz, isIIFE;
1925
1926
// F_ALLOW_UNPARATH_NEW becomes false.
1927
result = [this.generateExpression(expr.callee, Precedence.Call, E_TTF)];
1928
1929
if (expr.optional) {
1930
result.push('?.');
1931
}
1932
1933
result.push('(');
1934
for (i = 0, iz = expr['arguments'].length; i < iz; ++i) {
1935
result.push(this.generateExpression(expr['arguments'][i], Precedence.Assignment, E_TTT));
1936
if (i + 1 < iz) {
1937
result.push(',' + space);
1938
}
1939
}
1940
result.push(')');
1941
1942
if (!(flags & F_ALLOW_CALL)) {
1943
return ['(', result, ')'];
1944
}
1945
1946
isIIFE = expr.callee.id === null && expr.callee.params.length === 0;
1947
1948
return isIIFE
1949
? parenthesize(result, precedence, Precedence.Call)
1950
: parenthesize(result, Precedence.Call, precedence);
1951
},
1952
1953
ChainExpression: function (expr, precedence, flags) {
1954
if (Precedence.OptionalChaining < precedence) {
1955
flags |= F_ALLOW_CALL;
1956
}
1957
1958
var result = this.generateExpression(expr.expression, Precedence.OptionalChaining, flags);
1959
1960
return parenthesize(result, Precedence.OptionalChaining, precedence);
1961
},
1962
1963
NewExpression: function (expr, precedence, flags) {
1964
var result, length, i, iz, itemFlags;
1965
length = expr['arguments'].length;
1966
1967
// F_ALLOW_CALL becomes false.
1968
// F_ALLOW_UNPARATH_NEW may become false.
1969
itemFlags = (flags & F_ALLOW_UNPARATH_NEW && !parentheses && length === 0) ? E_TFT : E_TFF;
1970
1971
result = join(
1972
'new',
1973
this.generateExpression(expr.callee, Precedence.New, itemFlags)
1974
);
1975
1976
if (!(flags & F_ALLOW_UNPARATH_NEW) || parentheses || length > 0) {
1977
result.push('(');
1978
for (i = 0, iz = length; i < iz; ++i) {
1979
result.push(this.generateExpression(expr['arguments'][i], Precedence.Assignment, E_TTT));
1980
if (i + 1 < iz) {
1981
result.push(',' + space);
1982
}
1983
}
1984
result.push(')');
1985
}
1986
1987
return parenthesize(result, Precedence.New, precedence);
1988
},
1989
1990
MemberExpression: function (expr, precedence, flags) {
1991
var result, fragment;
1992
1993
// F_ALLOW_UNPARATH_NEW becomes false.
1994
result = [this.generateExpression(expr.object, Precedence.Call, (flags & F_ALLOW_CALL) ? E_TTF : E_TFF)];
1995
1996
if (expr.computed) {
1997
if (expr.optional) {
1998
result.push('?.');
1999
}
2000
2001
result.push('[');
2002
result.push(this.generateExpression(expr.property, Precedence.Sequence, flags & F_ALLOW_CALL ? E_TTT : E_TFT));
2003
result.push(']');
2004
} else {
2005
if (!expr.optional && expr.object.type === Syntax.Literal && typeof expr.object.value === 'number') {
2006
fragment = toSourceNodeWhenNeeded(result).toString();
2007
// When the following conditions are all true,
2008
// 1. No floating point
2009
// 2. Don't have exponents
2010
// 3. The last character is a decimal digit
2011
// 4. Not hexadecimal OR octal number literal
2012
// we should add a floating point.
2013
if (
2014
fragment.indexOf('.') < 0 &&
2015
!/[eExX]/.test(fragment) &&
2016
esutils.code.isDecimalDigit(fragment.charCodeAt(fragment.length - 1)) &&
2017
!(fragment.length >= 2 && fragment.charCodeAt(0) === 48) // '0'
2018
) {
2019
result.push(' ');
2020
}
2021
}
2022
result.push(expr.optional ? '?.' : '.');
2023
result.push(generateIdentifier(expr.property));
2024
}
2025
2026
return parenthesize(result, Precedence.Member, precedence);
2027
},
2028
2029
MetaProperty: function (expr, precedence, flags) {
2030
var result;
2031
result = [];
2032
result.push(typeof expr.meta === "string" ? expr.meta : generateIdentifier(expr.meta));
2033
result.push('.');
2034
result.push(typeof expr.property === "string" ? expr.property : generateIdentifier(expr.property));
2035
return parenthesize(result, Precedence.Member, precedence);
2036
},
2037
2038
UnaryExpression: function (expr, precedence, flags) {
2039
var result, fragment, rightCharCode, leftSource, leftCharCode;
2040
fragment = this.generateExpression(expr.argument, Precedence.Unary, E_TTT);
2041
2042
if (space === '') {
2043
result = join(expr.operator, fragment);
2044
} else {
2045
result = [expr.operator];
2046
if (expr.operator.length > 2) {
2047
// delete, void, typeof
2048
// get `typeof []`, not `typeof[]`
2049
result = join(result, fragment);
2050
} else {
2051
// Prevent inserting spaces between operator and argument if it is unnecessary
2052
// like, `!cond`
2053
leftSource = toSourceNodeWhenNeeded(result).toString();
2054
leftCharCode = leftSource.charCodeAt(leftSource.length - 1);
2055
rightCharCode = fragment.toString().charCodeAt(0);
2056
2057
if (((leftCharCode === 0x2B /* + */ || leftCharCode === 0x2D /* - */) && leftCharCode === rightCharCode) ||
2058
(esutils.code.isIdentifierPartES5(leftCharCode) && esutils.code.isIdentifierPartES5(rightCharCode))) {
2059
result.push(noEmptySpace());
2060
result.push(fragment);
2061
} else {
2062
result.push(fragment);
2063
}
2064
}
2065
}
2066
return parenthesize(result, Precedence.Unary, precedence);
2067
},
2068
2069
YieldExpression: function (expr, precedence, flags) {
2070
var result;
2071
if (expr.delegate) {
2072
result = 'yield*';
2073
} else {
2074
result = 'yield';
2075
}
2076
if (expr.argument) {
2077
result = join(
2078
result,
2079
this.generateExpression(expr.argument, Precedence.Yield, E_TTT)
2080
);
2081
}
2082
return parenthesize(result, Precedence.Yield, precedence);
2083
},
2084
2085
AwaitExpression: function (expr, precedence, flags) {
2086
var result = join(
2087
expr.all ? 'await*' : 'await',
2088
this.generateExpression(expr.argument, Precedence.Await, E_TTT)
2089
);
2090
return parenthesize(result, Precedence.Await, precedence);
2091
},
2092
2093
UpdateExpression: function (expr, precedence, flags) {
2094
if (expr.prefix) {
2095
return parenthesize(
2096
[
2097
expr.operator,
2098
this.generateExpression(expr.argument, Precedence.Unary, E_TTT)
2099
],
2100
Precedence.Unary,
2101
precedence
2102
);
2103
}
2104
return parenthesize(
2105
[
2106
this.generateExpression(expr.argument, Precedence.Postfix, E_TTT),
2107
expr.operator
2108
],
2109
Precedence.Postfix,
2110
precedence
2111
);
2112
},
2113
2114
FunctionExpression: function (expr, precedence, flags) {
2115
var result = [
2116
generateAsyncPrefix(expr, true),
2117
'function'
2118
];
2119
if (expr.id) {
2120
result.push(generateStarSuffix(expr) || noEmptySpace());
2121
result.push(generateIdentifier(expr.id));
2122
} else {
2123
result.push(generateStarSuffix(expr) || space);
2124
}
2125
result.push(this.generateFunctionBody(expr));
2126
return result;
2127
},
2128
2129
ArrayPattern: function (expr, precedence, flags) {
2130
return this.ArrayExpression(expr, precedence, flags, true);
2131
},
2132
2133
ArrayExpression: function (expr, precedence, flags, isPattern) {
2134
var result, multiline, that = this;
2135
if (!expr.elements.length) {
2136
return '[]';
2137
}
2138
multiline = isPattern ? false : expr.elements.length > 1;
2139
result = ['[', multiline ? newline : ''];
2140
withIndent(function (indent) {
2141
var i, iz;
2142
for (i = 0, iz = expr.elements.length; i < iz; ++i) {
2143
if (!expr.elements[i]) {
2144
if (multiline) {
2145
result.push(indent);
2146
}
2147
if (i + 1 === iz) {
2148
result.push(',');
2149
}
2150
} else {
2151
result.push(multiline ? indent : '');
2152
result.push(that.generateExpression(expr.elements[i], Precedence.Assignment, E_TTT));
2153
}
2154
if (i + 1 < iz) {
2155
result.push(',' + (multiline ? newline : space));
2156
}
2157
}
2158
});
2159
if (multiline && !endsWithLineTerminator(toSourceNodeWhenNeeded(result).toString())) {
2160
result.push(newline);
2161
}
2162
result.push(multiline ? base : '');
2163
result.push(']');
2164
return result;
2165
},
2166
2167
RestElement: function(expr, precedence, flags) {
2168
return '...' + this.generatePattern(expr.argument);
2169
},
2170
2171
ClassExpression: function (expr, precedence, flags) {
2172
var result, fragment;
2173
result = ['class'];
2174
if (expr.id) {
2175
result = join(result, this.generateExpression(expr.id, Precedence.Sequence, E_TTT));
2176
}
2177
if (expr.superClass) {
2178
fragment = join('extends', this.generateExpression(expr.superClass, Precedence.Unary, E_TTT));
2179
result = join(result, fragment);
2180
}
2181
result.push(space);
2182
result.push(this.generateStatement(expr.body, S_TFFT));
2183
return result;
2184
},
2185
2186
MethodDefinition: function (expr, precedence, flags) {
2187
var result, fragment;
2188
if (expr['static']) {
2189
result = ['static' + space];
2190
} else {
2191
result = [];
2192
}
2193
if (expr.kind === 'get' || expr.kind === 'set') {
2194
fragment = [
2195
join(expr.kind, this.generatePropertyKey(expr.key, expr.computed)),
2196
this.generateFunctionBody(expr.value)
2197
];
2198
} else {
2199
fragment = [
2200
generateMethodPrefix(expr),
2201
this.generatePropertyKey(expr.key, expr.computed),
2202
this.generateFunctionBody(expr.value)
2203
];
2204
}
2205
return join(result, fragment);
2206
},
2207
2208
PrivateIdentifier: function (expr, precedence, flags) {
2209
return generateIdentifier(expr);
2210
},
2211
2212
Property: function (expr, precedence, flags) {
2213
if (expr.kind === 'get' || expr.kind === 'set') {
2214
return [
2215
expr.kind, noEmptySpace(),
2216
this.generatePropertyKey(expr.key, expr.computed),
2217
this.generateFunctionBody(expr.value)
2218
];
2219
}
2220
2221
if (expr.shorthand) {
2222
if (expr.value.type === "AssignmentPattern") {
2223
return this.AssignmentPattern(expr.value, Precedence.Sequence, E_TTT);
2224
}
2225
return this.generatePropertyKey(expr.key, expr.computed);
2226
}
2227
2228
if (expr.method) {
2229
return [
2230
generateMethodPrefix(expr),
2231
this.generatePropertyKey(expr.key, expr.computed),
2232
this.generateFunctionBody(expr.value)
2233
];
2234
}
2235
2236
return [
2237
this.generatePropertyKey(expr.key, expr.computed),
2238
':' + space,
2239
this.generateExpression(expr.value, Precedence.Assignment, E_TTT)
2240
];
2241
},
2242
2243
PropertyDefinition: function (expr, precedence, flags) {
2244
var result;
2245
2246
if (expr.static) {
2247
result = ['static '];
2248
} else {
2249
result = [];
2250
}
2251
2252
result.push(this.generatePropertyKey(expr.key, expr.computed));
2253
2254
if (expr.value) {
2255
result.push( space + '=' + space);
2256
result.push(this.generateExpression(expr.value, Precedence.Assignment, E_TTT));
2257
}
2258
2259
result.push(this.semicolon(flags));
2260
2261
return result;
2262
},
2263
2264
ObjectExpression: function (expr, precedence, flags) {
2265
var multiline, result, fragment, that = this;
2266
2267
if (!expr.properties.length) {
2268
return '{}';
2269
}
2270
multiline = expr.properties.length > 1;
2271
2272
withIndent(function () {
2273
fragment = that.generateExpression(expr.properties[0], Precedence.Sequence, E_TTT);
2274
});
2275
2276
if (!multiline) {
2277
// issues 4
2278
// Do not transform from
2279
// dejavu.Class.declare({
2280
// method2: function () {}
2281
// });
2282
// to
2283
// dejavu.Class.declare({method2: function () {
2284
// }});
2285
if (!hasLineTerminator(toSourceNodeWhenNeeded(fragment).toString())) {
2286
return [ '{', space, fragment, space, '}' ];
2287
}
2288
}
2289
2290
withIndent(function (indent) {
2291
var i, iz;
2292
result = [ '{', newline, indent, fragment ];
2293
2294
if (multiline) {
2295
result.push(',' + newline);
2296
for (i = 1, iz = expr.properties.length; i < iz; ++i) {
2297
result.push(indent);
2298
result.push(that.generateExpression(expr.properties[i], Precedence.Sequence, E_TTT));
2299
if (i + 1 < iz) {
2300
result.push(',' + newline);
2301
}
2302
}
2303
}
2304
});
2305
2306
if (!endsWithLineTerminator(toSourceNodeWhenNeeded(result).toString())) {
2307
result.push(newline);
2308
}
2309
result.push(base);
2310
result.push('}');
2311
return result;
2312
},
2313
2314
AssignmentPattern: function(expr, precedence, flags) {
2315
return this.generateAssignment(expr.left, expr.right, '=', precedence, flags);
2316
},
2317
2318
ObjectPattern: function (expr, precedence, flags) {
2319
var result, i, iz, multiline, property, that = this;
2320
if (!expr.properties.length) {
2321
return '{}';
2322
}
2323
2324
multiline = false;
2325
if (expr.properties.length === 1) {
2326
property = expr.properties[0];
2327
if (
2328
property.type === Syntax.Property
2329
&& property.value.type !== Syntax.Identifier
2330
) {
2331
multiline = true;
2332
}
2333
} else {
2334
for (i = 0, iz = expr.properties.length; i < iz; ++i) {
2335
property = expr.properties[i];
2336
if (
2337
property.type === Syntax.Property
2338
&& !property.shorthand
2339
) {
2340
multiline = true;
2341
break;
2342
}
2343
}
2344
}
2345
result = ['{', multiline ? newline : '' ];
2346
2347
withIndent(function (indent) {
2348
var i, iz;
2349
for (i = 0, iz = expr.properties.length; i < iz; ++i) {
2350
result.push(multiline ? indent : '');
2351
result.push(that.generateExpression(expr.properties[i], Precedence.Sequence, E_TTT));
2352
if (i + 1 < iz) {
2353
result.push(',' + (multiline ? newline : space));
2354
}
2355
}
2356
});
2357
2358
if (multiline && !endsWithLineTerminator(toSourceNodeWhenNeeded(result).toString())) {
2359
result.push(newline);
2360
}
2361
result.push(multiline ? base : '');
2362
result.push('}');
2363
return result;
2364
},
2365
2366
ThisExpression: function (expr, precedence, flags) {
2367
return 'this';
2368
},
2369
2370
Super: function (expr, precedence, flags) {
2371
return 'super';
2372
},
2373
2374
Identifier: function (expr, precedence, flags) {
2375
return generateIdentifier(expr);
2376
},
2377
2378
ImportDefaultSpecifier: function (expr, precedence, flags) {
2379
return generateIdentifier(expr.id || expr.local);
2380
},
2381
2382
ImportNamespaceSpecifier: function (expr, precedence, flags) {
2383
var result = ['*'];
2384
var id = expr.id || expr.local;
2385
if (id) {
2386
result.push(space + 'as' + noEmptySpace() + generateIdentifier(id));
2387
}
2388
return result;
2389
},
2390
2391
ImportSpecifier: function (expr, precedence, flags) {
2392
var imported = expr.imported;
2393
var result = [ imported.name ];
2394
var local = expr.local;
2395
if (local && local.name !== imported.name) {
2396
result.push(noEmptySpace() + 'as' + noEmptySpace() + generateIdentifier(local));
2397
}
2398
return result;
2399
},
2400
2401
ExportSpecifier: function (expr, precedence, flags) {
2402
var local = expr.local;
2403
var result = [ local.name ];
2404
var exported = expr.exported;
2405
if (exported && exported.name !== local.name) {
2406
result.push(noEmptySpace() + 'as' + noEmptySpace() + generateIdentifier(exported));
2407
}
2408
return result;
2409
},
2410
2411
Literal: function (expr, precedence, flags) {
2412
var raw;
2413
if (expr.hasOwnProperty('raw') && parse && extra.raw) {
2414
try {
2415
raw = parse(expr.raw).body[0].expression;
2416
if (raw.type === Syntax.Literal) {
2417
if (raw.value === expr.value) {
2418
return expr.raw;
2419
}
2420
}
2421
} catch (e) {
2422
// not use raw property
2423
}
2424
}
2425
2426
if (expr.regex) {
2427
return '/' + expr.regex.pattern + '/' + expr.regex.flags;
2428
}
2429
2430
// BigInt, eg: 1n
2431
if (typeof expr.bigint === 'string' && expr.raw) {
2432
return expr.raw;
2433
}
2434
2435
if (expr.value === null) {
2436
return 'null';
2437
}
2438
2439
if (typeof expr.value === 'string') {
2440
return escapeString(expr.value);
2441
}
2442
2443
if (typeof expr.value === 'number') {
2444
// Has Numeric Separator
2445
if (expr.raw && expr.raw.indexOf('_') !== -1) {
2446
return expr.raw;
2447
}
2448
2449
return generateNumber(expr.value);
2450
}
2451
2452
if (typeof expr.value === 'boolean') {
2453
return expr.value ? 'true' : 'false';
2454
}
2455
2456
return generateRegExp(expr.value);
2457
},
2458
2459
GeneratorExpression: function (expr, precedence, flags) {
2460
return this.ComprehensionExpression(expr, precedence, flags);
2461
},
2462
2463
ComprehensionExpression: function (expr, precedence, flags) {
2464
// GeneratorExpression should be parenthesized with (...), ComprehensionExpression with [...]
2465
// Due to https://bugzilla.mozilla.org/show_bug.cgi?id=883468 position of expr.body can differ in Spidermonkey and ES6
2466
2467
var result, i, iz, fragment, that = this;
2468
result = (expr.type === Syntax.GeneratorExpression) ? ['('] : ['['];
2469
2470
if (extra.moz.comprehensionExpressionStartsWithAssignment) {
2471
fragment = this.generateExpression(expr.body, Precedence.Assignment, E_TTT);
2472
result.push(fragment);
2473
}
2474
2475
if (expr.blocks) {
2476
withIndent(function () {
2477
for (i = 0, iz = expr.blocks.length; i < iz; ++i) {
2478
fragment = that.generateExpression(expr.blocks[i], Precedence.Sequence, E_TTT);
2479
if (i > 0 || extra.moz.comprehensionExpressionStartsWithAssignment) {
2480
result = join(result, fragment);
2481
} else {
2482
result.push(fragment);
2483
}
2484
}
2485
});
2486
}
2487
2488
if (expr.filter) {
2489
result = join(result, 'if' + space);
2490
fragment = this.generateExpression(expr.filter, Precedence.Sequence, E_TTT);
2491
result = join(result, [ '(', fragment, ')' ]);
2492
}
2493
2494
if (!extra.moz.comprehensionExpressionStartsWithAssignment) {
2495
fragment = this.generateExpression(expr.body, Precedence.Assignment, E_TTT);
2496
2497
result = join(result, fragment);
2498
}
2499
2500
result.push((expr.type === Syntax.GeneratorExpression) ? ')' : ']');
2501
return result;
2502
},
2503
2504
ComprehensionBlock: function (expr, precedence, flags) {
2505
var fragment;
2506
if (expr.left.type === Syntax.VariableDeclaration) {
2507
fragment = [
2508
expr.left.kind, noEmptySpace(),
2509
this.generateStatement(expr.left.declarations[0], S_FFFF)
2510
];
2511
} else {
2512
fragment = this.generateExpression(expr.left, Precedence.Call, E_TTT);
2513
}
2514
2515
fragment = join(fragment, expr.of ? 'of' : 'in');
2516
fragment = join(fragment, this.generateExpression(expr.right, Precedence.Sequence, E_TTT));
2517
2518
return [ 'for' + space + '(', fragment, ')' ];
2519
},
2520
2521
SpreadElement: function (expr, precedence, flags) {
2522
return [
2523
'...',
2524
this.generateExpression(expr.argument, Precedence.Assignment, E_TTT)
2525
];
2526
},
2527
2528
TaggedTemplateExpression: function (expr, precedence, flags) {
2529
var itemFlags = E_TTF;
2530
if (!(flags & F_ALLOW_CALL)) {
2531
itemFlags = E_TFF;
2532
}
2533
var result = [
2534
this.generateExpression(expr.tag, Precedence.Call, itemFlags),
2535
this.generateExpression(expr.quasi, Precedence.Primary, E_FFT)
2536
];
2537
return parenthesize(result, Precedence.TaggedTemplate, precedence);
2538
},
2539
2540
TemplateElement: function (expr, precedence, flags) {
2541
// Don't use "cooked". Since tagged template can use raw template
2542
// representation. So if we do so, it breaks the script semantics.
2543
return expr.value.raw;
2544
},
2545
2546
TemplateLiteral: function (expr, precedence, flags) {
2547
var result, i, iz;
2548
result = [ '`' ];
2549
for (i = 0, iz = expr.quasis.length; i < iz; ++i) {
2550
result.push(this.generateExpression(expr.quasis[i], Precedence.Primary, E_TTT));
2551
if (i + 1 < iz) {
2552
result.push('${' + space);
2553
result.push(this.generateExpression(expr.expressions[i], Precedence.Sequence, E_TTT));
2554
result.push(space + '}');
2555
}
2556
}
2557
result.push('`');
2558
return result;
2559
},
2560
2561
ModuleSpecifier: function (expr, precedence, flags) {
2562
return this.Literal(expr, precedence, flags);
2563
},
2564
2565
ImportExpression: function(expr, precedence, flag) {
2566
return parenthesize([
2567
'import(',
2568
this.generateExpression(expr.source, Precedence.Assignment, E_TTT),
2569
')'
2570
], Precedence.Call, precedence);
2571
}
2572
};
2573
2574
merge(CodeGenerator.prototype, CodeGenerator.Expression);
2575
2576
CodeGenerator.prototype.generateExpression = function (expr, precedence, flags) {
2577
var result, type;
2578
2579
type = expr.type || Syntax.Property;
2580
2581
if (extra.verbatim && expr.hasOwnProperty(extra.verbatim)) {
2582
return generateVerbatim(expr, precedence);
2583
}
2584
2585
result = this[type](expr, precedence, flags);
2586
2587
2588
if (extra.comment) {
2589
result = addComments(expr, result);
2590
}
2591
return toSourceNodeWhenNeeded(result, expr);
2592
};
2593
2594
CodeGenerator.prototype.generateStatement = function (stmt, flags) {
2595
var result,
2596
fragment;
2597
2598
result = this[stmt.type](stmt, flags);
2599
2600
// Attach comments
2601
2602
if (extra.comment) {
2603
result = addComments(stmt, result);
2604
}
2605
2606
fragment = toSourceNodeWhenNeeded(result).toString();
2607
if (stmt.type === Syntax.Program && !safeConcatenation && newline === '' && fragment.charAt(fragment.length - 1) === '\n') {
2608
result = sourceMap ? toSourceNodeWhenNeeded(result).replaceRight(/\s+$/, '') : fragment.replace(/\s+$/, '');
2609
}
2610
2611
return toSourceNodeWhenNeeded(result, stmt);
2612
};
2613
2614
function generateInternal(node) {
2615
var codegen;
2616
2617
codegen = new CodeGenerator();
2618
if (isStatement(node)) {
2619
return codegen.generateStatement(node, S_TFFF);
2620
}
2621
2622
if (isExpression(node)) {
2623
return codegen.generateExpression(node, Precedence.Sequence, E_TTT);
2624
}
2625
2626
throw new Error('Unknown node type: ' + node.type);
2627
}
2628
2629
function generate(node, options) {
2630
var defaultOptions = getDefaultOptions(), result, pair;
2631
2632
if (options != null) {
2633
// Obsolete options
2634
//
2635
// `options.indent`
2636
// `options.base`
2637
//
2638
// Instead of them, we can use `option.format.indent`.
2639
if (typeof options.indent === 'string') {
2640
defaultOptions.format.indent.style = options.indent;
2641
}
2642
if (typeof options.base === 'number') {
2643
defaultOptions.format.indent.base = options.base;
2644
}
2645
options = updateDeeply(defaultOptions, options);
2646
indent = options.format.indent.style;
2647
if (typeof options.base === 'string') {
2648
base = options.base;
2649
} else {
2650
base = stringRepeat(indent, options.format.indent.base);
2651
}
2652
} else {
2653
options = defaultOptions;
2654
indent = options.format.indent.style;
2655
base = stringRepeat(indent, options.format.indent.base);
2656
}
2657
json = options.format.json;
2658
renumber = options.format.renumber;
2659
hexadecimal = json ? false : options.format.hexadecimal;
2660
quotes = json ? 'double' : options.format.quotes;
2661
escapeless = options.format.escapeless;
2662
newline = options.format.newline;
2663
space = options.format.space;
2664
if (options.format.compact) {
2665
newline = space = indent = base = '';
2666
}
2667
parentheses = options.format.parentheses;
2668
semicolons = options.format.semicolons;
2669
safeConcatenation = options.format.safeConcatenation;
2670
directive = options.directive;
2671
parse = json ? null : options.parse;
2672
sourceMap = options.sourceMap;
2673
sourceCode = options.sourceCode;
2674
preserveBlankLines = options.format.preserveBlankLines && sourceCode !== null;
2675
extra = options;
2676
2677
if (sourceMap) {
2678
if (!exports.browser) {
2679
// We assume environment is node.js
2680
// And prevent from including source-map by browserify
2681
SourceNode = require('source-map').SourceNode;
2682
} else {
2683
SourceNode = global.sourceMap.SourceNode;
2684
}
2685
}
2686
2687
result = generateInternal(node);
2688
2689
if (!sourceMap) {
2690
pair = {code: result.toString(), map: null};
2691
return options.sourceMapWithCode ? pair : pair.code;
2692
}
2693
2694
2695
pair = result.toStringWithSourceMap({
2696
file: options.file,
2697
sourceRoot: options.sourceMapRoot
2698
});
2699
2700
if (options.sourceContent) {
2701
pair.map.setSourceContent(options.sourceMap,
2702
options.sourceContent);
2703
}
2704
2705
if (options.sourceMapWithCode) {
2706
return pair;
2707
}
2708
2709
return pair.map.toString();
2710
}
2711
2712
FORMAT_MINIFY = {
2713
indent: {
2714
style: '',
2715
base: 0
2716
},
2717
renumber: true,
2718
hexadecimal: true,
2719
quotes: 'auto',
2720
escapeless: true,
2721
compact: true,
2722
parentheses: false,
2723
semicolons: false
2724
};
2725
2726
FORMAT_DEFAULTS = getDefaultOptions().format;
2727
2728
exports.version = require('./package.json').version;
2729
exports.generate = generate;
2730
exports.attachComments = estraverse.attachComments;
2731
exports.Precedence = updateDeeply({}, Precedence);
2732
exports.browser = false;
2733
exports.FORMAT_MINIFY = FORMAT_MINIFY;
2734
exports.FORMAT_DEFAULTS = FORMAT_DEFAULTS;
2735
}());
2736
/* vim: set sw=4 ts=4 et tw=80 : */
2737
2738