js-shrink 1.0.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/JsShrink.js ADDED
@@ -0,0 +1,4086 @@
1
+
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+ const DEBUG = 0
13
+ const CONST_DECLARATION_QUOTE_CHARACTER = "`"
14
+ const TO_SHRINK_ALL_STRING_LITERALS = 1
15
+ const TO_SHRINK_ALL_PROPERTY_NAMES = 1
16
+ const TO_SHRINK_ALL_UNDECLARED_GLOBALS = 1
17
+ const TO_SHRINK_ALL_VARIABLES_WHEN_POSSIBLE = 1
18
+ const TO_SHRINK_BUILTIN_VALUES = 1
19
+ const TO_SHRINK_ALL_THIS = 1
20
+ const MIN_PROPERTY_NAME_LENGTH = 3
21
+ const TO_REPLACE_ON_0_GAIN = 0
22
+ // class objects
23
+ const TO_INLINE_CLASS_OBJECT_PROPERTIES_AND_REMOVE_UNUSED = 0
24
+ // comment markers
25
+ const CLASS_OBJECT_MARKER = "CLASS_OBJECT"
26
+ const CLASS_OBJECT_MARKER_PENDING = "CLASS_OBJECT_PENDING"
27
+ const CLASS_OBJECT_MARKER__KEEP_PROPERTY = "JSSHRINK_KEEP_PROPERTY"
28
+ const CLASS_OBJECT_MARKER__DONT_INLINE_HERE = "JSSHRINK_DONT_INLINE_HERE"
29
+ const EXCLUDE_FUNCTION_FROM_SHRINK_MARKER = "!EXCLUDE!"
30
+ const DECLARATIONS_HERE_MARKER = "__JSSHRINK_DECLARATIONS_HERE__"
31
+ const DECLARATIONS_HERE_MARKER_CONST = "__JSSHRINK_CONSTANT_DECLARATIONS_HERE__"
32
+ const DECLARATIONS_HERE_MARKER_VAR = "__JSSHRINK_VARIABLE_DECLARATIONS_HERE__"
33
+
34
+
35
+
36
+
37
+ const acorn = require("acorn");
38
+ const scan = require('./scope-analyzer')
39
+ const {astTransformMS, bsGetIndexOfNearest} = require("./transform-ast");
40
+ const convertSourceMap = require('convert-source-map')
41
+ /** @import { SourceMap } from 'magic-string' */
42
+ /** @import { Node } from 'acorn' */
43
+ /** @import { Binding } from './scope-analyzer' */
44
+
45
+ const keywords = new Set(
46
+ ["abstract", "arguments", "await", "boolean", "break", "byte", "case", "catch", "char", "class", "const", "continue", "debugger", "default",
47
+ "delete", "do", "double", "else", "enum", "eval", "export", "extends", "false", "final", "finally", "float", "for", "function", "goto", "if",
48
+ "implements", "import", "in", "instanceof", "int", "interface", "let", "long", "native", "new", "null", "package", "private", "protected",
49
+ "public", "return", "short", "static", "super", "switch", "synchronized", "this", "throw", "throws", "transient", "true", "try", "typeof",
50
+ "var", "void", "volatile", "while", "with", "yield", "const",
51
+ "NaN", "undefined", "Infinity"]
52
+ )
53
+
54
+
55
+ const base54 = (() => {
56
+ const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_0123456789"
57
+ function base54(num) {
58
+ var ret = "", base = 54;
59
+ num++;
60
+ do {
61
+ num--;
62
+ ret += chars[num % base];
63
+ num = Math.floor(num / base);
64
+ base = 64;
65
+ } while (num > 0);
66
+ return ret;
67
+ }
68
+ return base54;
69
+ })();
70
+ Map.prototype.some = function(cb) { // callback([key, value])
71
+ for (const pair of this) {
72
+ if(cb(pair)) return true
73
+ }
74
+ }
75
+ Set.prototype.some = function(cb) { // callback(value)
76
+ for (const val of this) {
77
+ if(cb(val)) return true
78
+ }
79
+ }
80
+ const gimmeSomethingUnique = (() => {
81
+ var counter = 0
82
+ var prefix = "___$$_y0"+base54(Math.floor(Math.random()*100000000)) // let's not bother searching for collisions, just hope this is unique enough
83
+ return function gimme() {
84
+ return prefix+(++counter);
85
+ }
86
+ })();
87
+ function isJsAlphanum(char){
88
+ if(!char) return false;
89
+ char = char.charCodeAt(0);
90
+ return char > 47 && char < 58 || char > 96 && char < 123 || char > 64 && char < 91 || char === 95 || char === 36;
91
+ }
92
+ function getAllTakenNamesFor(ast_nodes) {
93
+ var scopes = new Set
94
+ for (const node of ast_nodes) {
95
+ var scope = scan.scope(node) || scan.nearestScope(node, true) || scan.nearestScope(node)
96
+ scopes.add(scope)
97
+ var p = scope
98
+ while (p = p.parent) {
99
+ scopes.add(p)
100
+ }
101
+ }
102
+ var names = new Set
103
+ for (const scope of scopes) {
104
+ for (const [n] of scope.bindings) {
105
+ names.add(n)
106
+ }
107
+ }
108
+ return names
109
+ }
110
+ function getIIFEBodyBlockNode(ast_node) {
111
+ // if ast_node is a script wrapped in a IIFE without arguments, then returns the block node of that IIFE
112
+ if(ast_node.type != "Program") return
113
+ var n = ast_node.body
114
+ if(n.length != 1) return
115
+ n = n[0]
116
+ if(n.type != "ExpressionStatement") return
117
+ n = n.expression
118
+ if(n.type == "UnaryExpression"){ // if: !function(){...}()
119
+ if (n.operator != "!") return
120
+ n = n.argument
121
+ }
122
+ if (n.type != "CallExpression") return
123
+ if(n.arguments.length != 0) return
124
+ n = n.callee
125
+ if(n.type != "FunctionExpression" && n.type != "ArrowFunctionExpression") return
126
+ n = n.body
127
+ if(n.type != "BlockStatement") return
128
+ // n = n.body
129
+ return n
130
+ }
131
+ function obtainNewVariableIdentifiers(ast_node, otherIdentifiersInThisScope, customGlobalReservedNames) {
132
+ function areRefsInScope(referencedNodesSet, scopeNode) {
133
+ var i=0
134
+ for (const refNode of referencedNodesSet) {
135
+ // The first entry is the declaration. The declaration can be below the block, and below the first ref. Check for that case.
136
+ if(i === 0) {
137
+ ++i
138
+ if (scopeNode.start <= refNode.start && scopeNode.end >= refNode.end) {
139
+ return true
140
+ }
141
+ continue
142
+ }
143
+ // ordered from here
144
+ if (scopeNode.start > refNode.end) {
145
+ continue
146
+ }
147
+ else if(refNode.start > scopeNode.end){
148
+ return false
149
+ }
150
+ else if (refNode.start >= scopeNode.start) {
151
+ return true
152
+ }
153
+ }
154
+ return false
155
+ }
156
+ function canTake(id, scope, node) {
157
+ if (keywords.has(id)
158
+ || undeclaredBindings.has(id)
159
+ || customGlobalReservedNames && customGlobalReservedNames.has(id)) {
160
+ return false
161
+ }
162
+ var isInBlockScope = scope.isBlock
163
+ var aParentScope = scope
164
+
165
+ while (aParentScope = aParentScope.parent){
166
+ if (aParentScope.newVars) {
167
+ var referencedNodesSet = aParentScope.newVars.get(id)
168
+ if (referencedNodesSet) {
169
+ if (isInBlockScope) {
170
+ return false
171
+ }
172
+ if(areRefsInScope(referencedNodesSet, node)){
173
+ return false
174
+ }
175
+ }
176
+ }
177
+ if (isInBlockScope && !aParentScope.isBlock) {
178
+ isInBlockScope = false
179
+ }
180
+ }
181
+ return true
182
+ }
183
+ function assignNewNames(scope, node, otherIdentifiersInThisScope) {
184
+ var unsafeNames
185
+ var variableItems = [...scope.bindings]
186
+ .filter(x => {
187
+ if (x[1].hasRefsInWith) {
188
+ unsafeNames ??= new Set
189
+ unsafeNames.add(x[0])
190
+ return false
191
+ }
192
+ return true
193
+ })
194
+ .map(x=>[null, x[1].references.size, x[1].references, 100, x[1].name, "_v"])
195
+ var allItems = variableItems
196
+ if(otherIdentifiersInThisScope){
197
+ allItems = allItems.concat(otherIdentifiersInThisScope)
198
+ }
199
+ allItems.sort(([, aLength], [, bLength]) => bLength - aLength)
200
+ var nameCounter = -1
201
+ varsLoop:
202
+ for (const t of allItems) {
203
+ while (true) {
204
+ let aname = base54(++nameCounter)
205
+ if (canTake(aname, scope, node) && !unsafeNames?.has(aname)) {
206
+ var maxIdLength = t[3]
207
+ if(aname.length > maxIdLength){
208
+ t[0] = null
209
+ --nameCounter
210
+ continue varsLoop
211
+ }
212
+ t[0] = aname
213
+ var nodes = t[2]
214
+ if (nodes) {
215
+ nodes = nodes.references || nodes
216
+ for (const n of nodes) {
217
+ if(t[5]) n[t[5]] = aname
218
+ if(n.type != "Identifier" && n.type != "Literal" && n.type != "TemplateLiteral" && !(n.type === "UnaryExpression" && n.operator === "void")) {
219
+ throw "node must be a Identifier|Literal|TemplateLiteral"
220
+ }
221
+
222
+ }
223
+ }
224
+ continue varsLoop
225
+ }
226
+ }
227
+ }
228
+ if(allItems.length){
229
+ scope.newVars = new Map(allItems.map(t => [t[0], t[2]]))
230
+ }
231
+ variableItems.forEach(t => gain += (t[4].length - t[0].length) * t[1])
232
+ }
233
+ function assignNewLabelNames(labels) {
234
+ var nameCounter = -1
235
+ for (var labelName in labels) {
236
+ var nodes = labels[labelName];
237
+ var aname = base54(++nameCounter)
238
+ for (const node of nodes) {
239
+ node._v = aname
240
+ gain += node.name.length - aname.length
241
+ }
242
+ }
243
+ }
244
+ var n = ast_node
245
+ while (n.parent) n = n.parent
246
+ var undeclaredBindings = scan.scope(n).undeclaredBindings
247
+
248
+ var gain = 0
249
+ walk(ast_node, node=>{
250
+ var scope = scan.scope(node)
251
+ if (scope) {
252
+ assignNewNames(scope, node, otherIdentifiersInThisScope)
253
+ if(scope.labels) assignNewLabelNames(scope.labels)
254
+ }
255
+ otherIdentifiersInThisScope = null
256
+ })
257
+ return gain
258
+ }
259
+ function findAllLiterals(ast_node, comments, toIncludePropertyKeys=true, minPropertyKeyLength=1, excludeNodes, src, toIncludeNumbers_minLength) {
260
+ function getNumber(node) {
261
+ let n = node.value
262
+ let origLen = node.end - node.start
263
+ let seen = numbersSeen.get(n)
264
+ var newStr
265
+ if (seen) {
266
+ newStr = seen
267
+ var tuple = numbers.get(n)
268
+ }
269
+ else {
270
+ let len
271
+ if (typeof n === "number") {
272
+ let hasFraction = n%1, str2
273
+ newStr = n.toString()
274
+ len = newStr.length
275
+ str2 = n.toExponential().replace("+","")
276
+ if (str2.length < len && Number(str2) === n) {
277
+ len = str2.length
278
+ newStr = str2
279
+ }
280
+ if (newStr.startsWith("0.")) {
281
+ newStr = newStr.slice(1)
282
+ --len
283
+ }
284
+ if (!hasFraction) {
285
+ str2 = n.toString(16)
286
+ if (str2.length+2 < len) {
287
+ len = str2.length
288
+ newStr = "0x"+str2
289
+ }
290
+ }
291
+ }
292
+ else if(typeof n === "bigint"){
293
+ newStr = n.toString()+"n"
294
+ }
295
+ var maxIdentifierLength = Math.max(1, newStr.length-1)
296
+ if (maxIdentifierLength > 1 && newStr.length >= toIncludeNumbers_minLength) {
297
+ tuple = [[], newStr, 0, n, maxIdentifierLength, "", 0]
298
+ numbers.set(n, tuple)
299
+ }
300
+ numbersSeen.set(n, newStr)
301
+ }
302
+ let gain = origLen - newStr.length
303
+ if (DEBUG && gain < 0) {
304
+ throw "gain < 0"
305
+ }
306
+ if (gain > 0) {
307
+ node._shrunkNumber = newStr
308
+ }
309
+ if (tuple) {
310
+ tuple[0].push(node)
311
+ tuple[2] += gain
312
+ tuple[6] += origLen
313
+ }
314
+ }
315
+
316
+ var names = new Map
317
+ /** @type {Map<number, [Node[], str:string, sumGain:number, numValue:number, maxIdentifierLength:number, varName:string, sumLengthOrig]} */
318
+ var numbers = new Map
319
+ var numbersSeen = new Map
320
+ walk(ast_node, node=>{
321
+ if (excludeNodes?.size && excludeNodes.has(node)) {
322
+ return "jump"
323
+ }
324
+
325
+ var name = null
326
+ var isIdentifier = node.type == "Identifier"
327
+ var isLiteral = node.type == "Literal"
328
+ var isTemplateLiteral = node.type == "TemplateLiteral" && node.expressions.length == 0
329
+ var templateLiteralValue = isTemplateLiteral && node.quasis[0].value.cooked
330
+ if(isLiteral || isTemplateLiteral || isIdentifier) {
331
+ var isObjectKey = node.parent.type == "Property" && node.parent.key == node
332
+ var isClassKey = (node.parent.type == "PropertyDefinition" || node.parent.type == "MethodDefinition") && node.parent.key == node
333
+ var isPropertyMemberKey = node.parent.type == "MemberExpression" && node.parent.property == node
334
+ var isPropertyKey = isObjectKey || isClassKey || isPropertyMemberKey
335
+
336
+ if (isClassKey) {
337
+ let propertyDefinition = node.parent
338
+ let classBody = propertyDefinition.parent
339
+ if (classBody.type !== "ClassBody") throw "ClassBody expected"
340
+ let isFirst = classBody.body[0] === propertyDefinition
341
+ var classKey_needsSemicol = !isFirst && !propertyDefinition.static && !propertyDefinition.computed
342
+ if (classKey_needsSemicol) {
343
+ let indexInBody = classBody.body.indexOf(propertyDefinition)
344
+ let prev = classBody.body[indexInBody-1]
345
+ if (prev.type === "MethodDefinition" || !prev.value) {
346
+ classKey_needsSemicol = false
347
+ }
348
+ else {
349
+ let hasSemicol = findNextIndexInJs(";", src, comments, prev.end, propertyDefinition.start) >= 0
350
+ if (hasSemicol) classKey_needsSemicol = false
351
+ }
352
+ }
353
+ }
354
+ var caseDelta = -2
355
+ if (isPropertyKey) {
356
+
357
+ var isComputed = node.parent.computed
358
+ var isOptional = node.parent.optional
359
+ if (isLiteral) {
360
+ if(typeof node.value === "string"){
361
+ name = node.value
362
+ }
363
+ else if (toIncludeNumbers_minLength && (typeof node.value === "number" || typeof node.value === "bigint")) {
364
+ getNumber(node)
365
+ return
366
+ }
367
+ else return
368
+ }
369
+ else if(isTemplateLiteral){
370
+ name = templateLiteralValue
371
+ }
372
+ else if(isIdentifier && !isComputed){
373
+ name = node.name
374
+ }
375
+ else{
376
+ return
377
+ }
378
+ let isActuallyALiteral = isComputed // treat x["literal"] like a literal
379
+ if (isActuallyALiteral) {
380
+
381
+ }
382
+ else{
383
+ if(!toIncludePropertyKeys){
384
+ return
385
+ }
386
+
387
+ if(name.length < minPropertyKeyLength){
388
+ return
389
+ }
390
+
391
+ if (isIdentifier) { // {a: | x?.a | x.a
392
+ if (classKey_needsSemicol) {
393
+ caseDelta = 3
394
+ }
395
+ else {
396
+ caseDelta = isObjectKey || isOptional? 2 : 1
397
+ }
398
+ }
399
+ else{ // {"a":
400
+ caseDelta = 0
401
+ }
402
+ }
403
+
404
+ }
405
+ else if(isLiteral && typeof node.value == "string"){
406
+ if (node.parent.type === "ExpressionStatement") {
407
+ return
408
+ }
409
+ name = node.value
410
+ }
411
+ else if (toIncludeNumbers_minLength && (typeof node.value === "number" || typeof node.value === "bigint")) {
412
+ getNumber(node)
413
+ return
414
+ }
415
+ else if(isTemplateLiteral){
416
+ name = templateLiteralValue
417
+ }
418
+ else{
419
+ return
420
+ }
421
+
422
+ if(isPropertyKey) node._caseDelta = caseDelta
423
+ if(classKey_needsSemicol) node._needsSemicol = true
424
+
425
+ var tuple = names.get(name)
426
+ if(!tuple){
427
+ tuple = [[], 0, 0, 0, 0, 0]
428
+ names.set(name, tuple)
429
+ }
430
+ var nodes = tuple[0]
431
+ nodes.push(node)
432
+ if(caseDelta == -2) tuple[1] += 1
433
+ else if(caseDelta == 0) tuple[2] += 1
434
+ else if(caseDelta == 1) tuple[3] += 1
435
+ else if(caseDelta == 2) tuple[4] += 1
436
+ else if(caseDelta == 3) tuple[5] += 1
437
+ return
438
+ }
439
+ })
440
+ let numbers2 = [...numbers.values()]
441
+ /** @type {[names, numbers2]} */
442
+ let ret = [names, numbers2]
443
+ return ret
444
+ }
445
+ function findBuiltinValues(ast_node, excludeNodes) {
446
+ var names = new Map
447
+ walk(ast_node, node=>{
448
+ if (excludeNodes?.size && excludeNodes.has(node)) {
449
+ return "jump"
450
+ }
451
+
452
+ var isLiteral = node.type === "Literal"
453
+ var isIdentifier = node.type === "Identifier"
454
+ if(isLiteral || isIdentifier) {
455
+ if(isLiteral && node.value === null) {
456
+ var name = "null"
457
+ }
458
+ else if(isIdentifier){
459
+ if (node.name === "undefined" && !scan.getBinding(node)) {
460
+ let b = scan.getBinding(node)
461
+ if (b) {
462
+
463
+ }
464
+ else {
465
+ var name = "void 0"
466
+ }
467
+ }
468
+ else if (node.name === "Infinity" && !scan.getBinding(node)){
469
+ var name = "Infinity"
470
+ }
471
+ }
472
+ }
473
+ else if(node.type === "UnaryExpression" && node.operator === "void"
474
+ && (node.argument.type === "Literal" || node.type == "TemplateLiteral" && node.expressions.length == 0 || node.argument.type === "Identifier")
475
+ ){
476
+ var name = "void 0"
477
+ }
478
+ if (name) {
479
+ var refNodes = names.get(name)
480
+ if(!refNodes){
481
+ refNodes = []
482
+ names.set(name, refNodes)
483
+ }
484
+ refNodes.push(node)
485
+ }
486
+ })
487
+ return names
488
+ }
489
+ function getCharacterGain(origLiteralLength, newIdentifierLength, n_m2, n_p0, n_p1, n_p2, n_p3) {
490
+ var diff = origLiteralLength - newIdentifierLength
491
+ var gain = (diff+2)*n_m2 + (diff)*n_p0
492
+ if (diff > 1) {
493
+ gain += (diff-1)*n_p1
494
+ }
495
+ if (diff > 2) {
496
+ gain += (diff-2)*n_p2
497
+ }
498
+ if (diff > 3) {
499
+ gain += (diff-3)*n_p3
500
+ }
501
+ var declarationCost = origLiteralLength + newIdentifierLength + 2 + 2
502
+ gain -= declarationCost
503
+ return gain
504
+ }
505
+ function maxIdentifierLengthFor(num, origLength, allow0Gain, extraCost=0) {
506
+ var cost = origLength+2+extraCost
507
+ var maxLength = origLength-cost/(num+1)
508
+ if(maxLength%1 == 0 && !allow0Gain) maxLength -= 1
509
+ return maxLength
510
+ }
511
+ function getMaxIdentifierLengthForPropsLiterals(originalLiteral, toAllow_0_Gain, n_m2, n_p0, n_p1, n_p2, n_p3) {
512
+ var newIdentifierLength = 1
513
+ while (true) {
514
+ var gain = getCharacterGain(originalLiteral.length, newIdentifierLength, n_m2, n_p0, n_p1, n_p2, n_p3)
515
+ var hasGain = toAllow_0_Gain? gain >= 0 : gain > 0
516
+ if(!hasGain) break
517
+ ++newIdentifierLength
518
+ if (newIdentifierLength > 10) {
519
+ break;
520
+ }
521
+ }
522
+ return newIdentifierLength -1
523
+ }
524
+ function getAllScopeVariableNames(scope) {
525
+ var names = new Set
526
+ getAllBlockNames(scope)
527
+ function getAllBlockNames(scope) {
528
+ scope.bindings.forEach(b => names.add(b.name))
529
+ if (scope.children) {
530
+ for (const child of scope.children) {
531
+ if(child.isBlock) getAllBlockNames(child)
532
+ }
533
+ }
534
+ }
535
+ return names
536
+ }
537
+ function walk(ast_node, cb, cbLeave, inExecutionOrder) {
538
+ // cb(node, parent, previousSibling, index) : "end" | "stop" | "jump"
539
+ // "end" = stop walking, and don't call the "leave" callbacks
540
+ // "stop" = stop walking, do call the "leave" callbacks
541
+ // "jump" = jump over this node
542
+ if(!ast_node || !cb && !cbLeave) return
543
+ function _walk(node, parent, previousSibling, index) {
544
+ var ret = cb && cb(node, parent, previousSibling, index)
545
+ var walked = false
546
+ if(ret === "end") return "end"
547
+ if(ret !== "jump" && ret !== "stop") {
548
+ if (inExecutionOrder) {
549
+ walked = true
550
+ if (node.type == "BinaryExpression" || node.type == "LogicalExpression" || node.type == "AssignmentExpression") {
551
+ ret = _walk(node.left, node)
552
+ if(ret === "end") return "end"
553
+ ret = _walk(node.right, node)
554
+ if(ret === "end") return "end"
555
+ }
556
+ else if (node.type == "ConditionalExpression" || node.type == "IfStatement") {
557
+ ret = _walk(node.test, node)
558
+ if(ret === "end") return "end"
559
+ ret = _walk(node.consequent, node)
560
+ if(ret === "end") return "end"
561
+ if (node.alternate) {
562
+ ret = _walk(node.alternate, node)
563
+ if(ret === "end") return "end"
564
+ }
565
+ }
566
+ else if (node.type == "MemberExpression") {
567
+ ret = _walk(node.object, node);
568
+ if (ret === "end") return "end";
569
+ ret = _walk(node.property, node);
570
+ if (ret === "end") return "end";
571
+ }
572
+ else if (node.type == "CallExpression") {
573
+ ret = _walk(node.callee, node)
574
+ if(ret === "end") return "end"
575
+ ret = walkArray(node.arguments, node)
576
+ if(ret === "end") return "end"
577
+ }
578
+ else if (node.type == "ForOfStatement" || node.type == "ForInStatement") {
579
+ ret = _walk(node.right, node)
580
+ if(ret === "end") return "end"
581
+ ret = _walk(node.left, node)
582
+ if(ret === "end") return "end"
583
+ ret = _walk(node.body, node)
584
+ if(ret === "end") return "end"
585
+ }
586
+ else if (node.type == "ForStatement") {
587
+ if (node.init) {
588
+ ret = _walk(node.init, node)
589
+ if(ret === "end") return "end"
590
+ }
591
+ if (node.test) {
592
+ ret = _walk(node.test, node)
593
+ if(ret === "end") return "end"
594
+ }
595
+ if (node.update) {
596
+ ret = _walk(node.update, node)
597
+ if(ret === "end") return "end"
598
+ }
599
+ ret = _walk(node.body, node)
600
+ if(ret === "end") return "end"
601
+ }
602
+ else if (node.type == "WhileStatement") {
603
+ ret = _walk(node.test, node)
604
+ if(ret === "end") return "end"
605
+ ret = _walk(node.body, node)
606
+ if(ret === "end") return "end"
607
+ }
608
+ else if (node.type == "DoWhileStatement") {
609
+ ret = _walk(node.body, node)
610
+ if(ret === "end") return "end"
611
+ ret = _walk(node.test, node)
612
+ if(ret === "end") return "end"
613
+ }
614
+ else if (node.type == "SwitchStatement") {
615
+ ret = _walk(node.discriminant, node)
616
+ if(ret === "end") return "end"
617
+ ret = walkArray(node.cases, node)
618
+ if(ret === "end") return "end"
619
+ }
620
+ else if (node.type == "SwitchCase") {
621
+ if (node.test) {
622
+ ret = _walk(node.test, node)
623
+ if(ret === "end") return "end"
624
+ }
625
+ ret = _walk(node.consequent, node)
626
+ if(ret === "end") return "end"
627
+ }
628
+ else walked = false
629
+ }
630
+ if(!walked){
631
+ for (var k in node) {
632
+ if (has(node, k)) {
633
+ if (k[0] === '_') continue
634
+ if (k === 'parent') continue
635
+ let something = node[k]
636
+ if (isNode(something)) {
637
+ ret = _walk(something, node)
638
+ if(ret === "end") return "end"
639
+ } else if (Array.isArray(something)) {
640
+ ret = walkArray(something, node)
641
+ if(ret === "end") return "end"
642
+ }
643
+ }
644
+ }
645
+ }
646
+ }
647
+ if (cbLeave) {
648
+ let _ret = cbLeave(node, parent, previousSibling, index)
649
+ if(typeof _ret == "string") ret = _ret
650
+ }
651
+ return ret
652
+ }
653
+ function walkArray(array, parent) {
654
+ let prev = null
655
+ for (let i = 0; i < array.length; i++) {
656
+ let n = array[i]
657
+ if (isNode(n)){
658
+ var ret = _walk(n, parent, prev, i)
659
+ if(ret === "end") return "end"
660
+ if(ret === "stop") return "stop"
661
+ prev = n
662
+ }
663
+ }
664
+ }
665
+ function has (obj, prop) {
666
+ return Object.prototype.hasOwnProperty.call(obj, prop)
667
+ }
668
+ function isNode (node) {
669
+ return typeof node === 'object' && node && typeof node.type === 'string'
670
+ }
671
+ _walk(ast_node)
672
+ }
673
+ function isNodeContainedIn(node, parent, canBeSame) {
674
+ let parent_ = canBeSame? node : node.parent
675
+ while (parent_) {
676
+ if (parent_ === parent) return true
677
+ parent_ = parent_.parent
678
+ }
679
+ }
680
+ function getRefsInScope(referencedNodesSet, scopeNode) {
681
+ var refs
682
+ var i=0
683
+ for (const refNode of referencedNodesSet) {
684
+ // The first entry is the declaration.
685
+ if(i === 0) {
686
+ ++i
687
+ continue
688
+ }
689
+ if (scopeNode.start > refNode.end) {
690
+ continue
691
+ }
692
+ else if(refNode.start > scopeNode.end){
693
+ break
694
+ }
695
+ else if (refNode.start >= scopeNode.start) {
696
+ if(!refs) refs = []
697
+ refs.push(refNode)
698
+ continue
699
+ }
700
+ }
701
+ return refs
702
+ }
703
+ function getDirectParentScope(node) {
704
+ return scan.nearestScope(node, true) || scan.nearestScope(node)
705
+ }
706
+ function getNodeDepth(node) {
707
+ var depth = 1
708
+ while (node = node.parent) ++depth
709
+ return depth
710
+ }
711
+ function isAssignmentTarget(node, includingDeclaration, includingUninitializedDeclaration, includingFunctionparam) {
712
+ let parent = node.parent
713
+ if (parent.type == "UpdateExpression"
714
+ || parent.type == "AssignmentExpression" && parent.left == node
715
+ || includingDeclaration && (
716
+ parent.type == "VariableDeclarator" && parent.id == node && (includingUninitializedDeclaration? true : parent.init)
717
+ || includingFunctionparam && isFunctionNode(parent) && parent.params.includes(node)
718
+ )
719
+ ) {
720
+ return parent
721
+ }
722
+ else if (parent.type == "Property" && parent.value == node && parent.kind == 'init'
723
+ ) {
724
+ let parent2 = parent.parent
725
+ if (parent2.type == "ObjectPattern") {
726
+ return isAssignmentTarget(parent2)
727
+ }
728
+ }
729
+ else if (parent.type == "ArrayPattern"
730
+ ) {
731
+ return isAssignmentTarget(parent)
732
+ }
733
+ else if (parent.type === 'RestElement' && parent.argument == node) {
734
+ return isAssignmentTarget(parent)
735
+ }
736
+ else if (parent.type == "AssignmentPattern" && parent.left == node
737
+ ) {
738
+ return isAssignmentTarget(parent)
739
+ }
740
+ }
741
+ function isVariableAssignedTo(binding, except) {
742
+ for (const refNode of binding.references) {
743
+ if(refNode === binding.definition) continue
744
+ if(isAssignmentTarget(refNode, 1, 1) && !(except && except.includes(refNode))
745
+ ) return true
746
+ }
747
+ }
748
+ function isPreceededBy(node, pred, checkAll) {
749
+ var block = node
750
+ while (!(block.type == "Program" || block.type == "BlockStatement")) {
751
+ block = block.parent
752
+ }
753
+ var ni = block.body.indexOf(node)
754
+ while (--ni >= 0) {
755
+ var n = block.body[ni]
756
+ if(pred(n, ni)) return true
757
+ if(!checkAll) return
758
+ }
759
+ }
760
+ function transform_addSemicolIfNeeded(node, ctx) {
761
+ var block
762
+ var statement = node
763
+ while (block = statement.parent) {
764
+ if (block.type == "Program" || block.type == "BlockStatement") {
765
+ break
766
+ }
767
+ if(isFunctionNode(block)) return
768
+ statement = statement.parent
769
+ }
770
+ if (!block) {
771
+ return
772
+ }
773
+ var ni = block.body.indexOf(statement)
774
+ if(ni > 0){
775
+ let char
776
+ let iu = ni, io = ni-1
777
+ let nu, no
778
+ while (!char) {
779
+ nu = block.body[iu++]
780
+ char = ctx? ctx.srcOrig[nu.start] : nu.source()[0]
781
+ if(iu >= block.body.length) return
782
+ }
783
+
784
+ if (char == "(" || nu.type == "AssignmentExpression" && (char == "[" || char == "{")) {
785
+ let char2, src2
786
+ do {
787
+ no = block.body[io]
788
+ src2 = ctx? ctx.source(no) : no.source()
789
+ } while (--io >= 0 && !src2.length);
790
+ if(io < 0) return
791
+ char2 = src2[src2.length-1]
792
+ if(char2 != ";"){
793
+ if (ctx) {
794
+ ctx.append(";", no)
795
+ }
796
+ else {
797
+ no.edit.append(";")
798
+ }
799
+ }
800
+ }
801
+ }
802
+ }
803
+ function ToNotWrapExpressionInRoundParantheses(inlinedNode, replacedNode) {
804
+ return inlinedNode.type == "CallExpression"
805
+ || inlinedNode.type == "Literal"
806
+ && !(replacedNode && replacedNode.parent && replacedNode.parent.type == "MemberExpression" && typeof inlinedNode.value == "number")
807
+ || inlinedNode.type == "Identifier"
808
+ || inlinedNode.type == "MemberExpression"
809
+ }
810
+ function isBindingExistenceChecked(binding) {
811
+ for (const ref of binding.references) {
812
+ if(ref.parent.type == "UnaryExpression" && ref.parent.operator == "typeof") return true
813
+ }
814
+ }
815
+ function isCallNode(node) {
816
+ return node.type === "CallExpression"
817
+ || node.type === "MemberExpression"
818
+ }
819
+ function hasExpressionCalls(node, OrThis) {
820
+ var has = false
821
+ walk(node, n=>{
822
+ if (isCallNode(n)){
823
+ has = true
824
+ return "end"
825
+ }
826
+ if (OrThis && n.type === "ThisExpression"){
827
+ has = true
828
+ return "end"
829
+ }
830
+ if (isFunctionNode(n)) {
831
+ return "jump"
832
+ }
833
+ })
834
+ return has
835
+ }
836
+ function isFunctionNode(n) {
837
+ return n.type === 'FunctionDeclaration' || n.type === 'FunctionExpression' || n.type === 'ArrowFunctionExpression'
838
+ }
839
+ function isSafeAssignment(AssignmentExpression) {
840
+ var safe = true
841
+ walk(AssignmentExpression.left, n=>{
842
+ if (isCallNode(n)){
843
+ safe = false
844
+ return "end"
845
+ }
846
+ })
847
+ return safe
848
+ }
849
+ function getFunctionInfo(functionNode, refCallExpressionNode, variableNamesChangeable, src) {
850
+ function checkStatements(functionNode) {
851
+ var hasStatements = false
852
+ var lastReturnNode = null
853
+ var conditionalReturn = false
854
+ if (functionNode.expression) {
855
+ return {hasStatements:false, lastReturnNode:false}
856
+ }
857
+ var BlockStatement = functionNode.body
858
+ if(BlockStatement.type != "BlockStatement")
859
+ throw "BlockStatement expected"
860
+ var statements = BlockStatement.body
861
+ let firstUnconditionalReturnStatement
862
+ walk(functionNode.body, n=>{
863
+ if (n.type === 'ReturnStatement') {
864
+ if (n.parent === BlockStatement) {
865
+ if (!firstUnconditionalReturnStatement) {
866
+ firstUnconditionalReturnStatement = n
867
+ if (!conditionalReturn) return "stop"
868
+ }
869
+ return "jump"
870
+ }
871
+ else {
872
+ conditionalReturn = true
873
+ return "stop"
874
+ }
875
+ }
876
+ else if(isFunctionNode(n)){
877
+ return "jump"
878
+ }
879
+ })
880
+ lastReturnNode = firstUnconditionalReturnStatement
881
+
882
+ var unreachable = false
883
+ for (var i = 0; i < statements.length; i++) {
884
+ var statement = statements[i];
885
+ if (unreachable) {
886
+ functionNode._unreachableNodes ??= []
887
+ functionNode._unreachableNodes.push(statement)
888
+ continue
889
+ }
890
+ if (statement.type != "ExpressionStatement" && statement.type != "EmptyStatement") {
891
+ hasStatements = true
892
+ }
893
+ if (statement === firstUnconditionalReturnStatement) {
894
+ unreachable = true
895
+ }
896
+ }
897
+
898
+ return {hasStatements, lastReturnNode, conditionalReturn}
899
+ }
900
+ function hasFunctionDeclarations(functionNode) {
901
+ var has = false
902
+ var names = [[], new Set, []] // names, nodes, bindings
903
+ walk(functionNode, n=>{
904
+ if (n == functionNode) return
905
+ if (n.type === 'FunctionDeclaration') {
906
+ has = true
907
+ names[0].push(n.id.name)
908
+ names[1].add(n)
909
+ names[2].push(scan.getBinding(n.id))
910
+ return "jump"
911
+ }
912
+ if (n.type === 'FunctionExpression' || n.type === 'ArrowFunctionExpression') {
913
+ return "jump"
914
+ }
915
+ })
916
+ return has && names
917
+ }
918
+ if(refCallExpressionNode.type != "CallExpression") throw "CallExpression expected"
919
+ if(functionNode.generator || functionNode.async) return
920
+ var isCallSiteAStatement = refCallExpressionNode.parent.type == "ExpressionStatement"
921
+ var isCallSiteAVariableDeclarator = refCallExpressionNode.parent.type == "VariableDeclarator"
922
+ && refCallExpressionNode.parent.id.type == "Identifier"
923
+ && refCallExpressionNode.parent.id
924
+ var isCallSiteAnAssignmentExpression = refCallExpressionNode.parent.type == "AssignmentExpression"
925
+ && refCallExpressionNode.parent.parent.type == "ExpressionStatement"
926
+ && isSafeAssignment(refCallExpressionNode.parent)
927
+ && refCallExpressionNode.parent.left
928
+ var funcScope = scan.scope(functionNode)
929
+ var {hasStatements, lastReturnNode, conditionalReturn} = checkStatements(functionNode)
930
+ if(conditionalReturn) return
931
+ var isExpression = functionNode.expression || !hasStatements
932
+ var params = functionNode.params
933
+ var isOriginallyABlock = false
934
+ var toCreateBlock = !isExpression
935
+ var toInlineArg = new Set
936
+
937
+ if(!functionNode.expression){
938
+ if(functionNode.body.type == "BlockStatement"){
939
+ let fbScope = scan.scope(functionNode.body)
940
+ var hasFunctionBlockLets = fbScope && fbScope.bindings.size
941
+ isOriginallyABlock = true
942
+ }
943
+ }
944
+ var funcDeclarations = hasFunctionDeclarations(functionNode)
945
+ if(funcDeclarations){
946
+ if(funcDeclarations[2].some((b, i, arr) => isVariableAssignedTo(b))) return
947
+ if(!variableNamesChangeable) return
948
+ functionNode._funDeclarations = funcDeclarations[1]
949
+ }
950
+
951
+
952
+ for (var i = 0; i < params.length; i++) {
953
+ var paramNode = params[i]
954
+ var arg = refCallExpressionNode.arguments[i]
955
+ let identifier
956
+ let defaultValueNode
957
+ if(paramNode.type == "Identifier") identifier = paramNode
958
+ else if(paramNode.type == "AssignmentPattern" && paramNode.left.type === "Identifier"){
959
+ identifier = paramNode.left
960
+ defaultValueNode = paramNode.right
961
+ }
962
+ else return
963
+ var paramBinding = funcScope.bindings.get(identifier.name)
964
+ if(isExpression) {
965
+ var numReferences = paramBinding.references.size - 1
966
+ var isSimpleArg = arg && (arg.type === 'Literal' || arg.type === 'Identifier' || arg.type === "TemplateLiteral" && arg.expressions.length == 0)
967
+ var isArgString = isSimpleArg && (arg.type === 'Literal' && typeof arg.value === "string" || arg.type === "TemplateLiteral")
968
+ var isArgIdentifier = isSimpleArg && arg.type === 'Identifier'
969
+ var canInlineParam = !isVariableAssignedTo(paramBinding)
970
+ if(!canInlineParam){
971
+ if (isCallSiteAStatement) {
972
+ toCreateBlock = true
973
+ }
974
+ else return
975
+ }
976
+ if(numReferences > 1){
977
+ if(canInlineParam && !defaultValueNode && (!arg || numReferences <= 3 && isSimpleArg && !isArgString || isArgIdentifier)){
978
+ toInlineArg.add(paramBinding.name)
979
+ }
980
+ else if (isCallSiteAStatement) {
981
+ toCreateBlock = true
982
+ }
983
+ else return
984
+ }
985
+ }
986
+ }
987
+ var toPrependForAssignment = false
988
+ if(toCreateBlock && variableNamesChangeable && isCallSiteAVariableDeclarator){
989
+ let varDeclaratorNode = refCallExpressionNode.parent
990
+ let varDeclarationNode = varDeclaratorNode.parent
991
+ toPrependForAssignment = {
992
+ returnVarName: gimmeSomethingUnique(),
993
+ varDeclaratorNode,
994
+ varDeclarationNode,
995
+ }
996
+ }
997
+ if (!toPrependForAssignment && toCreateBlock && !isCallSiteAStatement) {
998
+ let anode = refCallExpressionNode
999
+ let isunsafe
1000
+ let targetStatement
1001
+ while ((anode = anode.parent) && anode.parent) {
1002
+ if(isFunctionNode(anode) || anode.type === 'ForStatement' || anode.type === 'ForInStatement' || anode.type === 'ForOfStatement'){
1003
+ isunsafe = true
1004
+ break
1005
+ }
1006
+ if (anode.parent.type == "BlockStatement") {
1007
+ targetStatement = anode
1008
+ anode = anode.parent
1009
+ break
1010
+ }
1011
+ }
1012
+ if(!isunsafe && anode && targetStatement){
1013
+ if(!hasCallsBetween(anode, targetStatement, refCallExpressionNode, 1, 0, src)){
1014
+ var toPrependForExpression = {
1015
+ targetStatement,
1016
+ returnVarName: gimmeSomethingUnique()
1017
+ }
1018
+ }
1019
+ }
1020
+ if (!toPrependForExpression) {
1021
+ return
1022
+ }
1023
+ }
1024
+
1025
+ var type = {
1026
+ isExpression,
1027
+ hasStatements,
1028
+ lastReturnNode,
1029
+ hasFunctionBlockLets,
1030
+ isOriginallyABlock,
1031
+ toCreateBlock,
1032
+ toInlineArg,
1033
+ toPrependForAssignment,
1034
+ toPrependForExpression,
1035
+ isCallSiteAVariableDeclarator,
1036
+ isCallSiteAnAssignmentExpression,
1037
+ isCallSiteAStatement,
1038
+ refCallExpressionNode,
1039
+ }
1040
+ return type
1041
+ }
1042
+ function editInlinedFunctionBody(functionNode, functionInfo, refCallExpressionNode, ctx) {
1043
+ if (functionInfo.toCreateBlock) {
1044
+ walk(functionNode, n =>{
1045
+ if (n != functionNode && isFunctionNode(n)) {
1046
+ return "jump"
1047
+ }
1048
+ if (n.type == "VariableDeclaration" && n.kind == 'var') {
1049
+ let numAssignmentDeclarators = 0
1050
+ let hasComplicated
1051
+ let firstDeclarator
1052
+ n.declarations.forEach((d, i) => {
1053
+ if(d.id.type !== "Identifier") hasComplicated = 1
1054
+ if (d.init) {
1055
+ ++numAssignmentDeclarators
1056
+ if (!firstDeclarator) firstDeclarator = d
1057
+ }
1058
+ else {
1059
+ let hasNext = i < n.declarations.length-1
1060
+ let end = hasNext? n.declarations[i+1].start : d.end
1061
+ ctx.edit.remove(d.start, end)
1062
+ }
1063
+ })
1064
+ if (firstDeclarator) {
1065
+ ctx.edit.remove(n.start, firstDeclarator.start)
1066
+ if(hasComplicated && numAssignmentDeclarators.length == 1){
1067
+ ctx.prepend("0,", n)
1068
+ }
1069
+ if (n.parent.type !== "ForStatement") {
1070
+ ctx.append(";", n)
1071
+ }
1072
+ }
1073
+ else {
1074
+ ctx.edit.remove(n.start, n.end)
1075
+ }
1076
+ }
1077
+ })
1078
+ }
1079
+ if(!functionInfo.toCreateBlock){
1080
+ for (var i = 0; i < functionNode.params.length; i++) {
1081
+ var param = functionNode.params[i];
1082
+ var arg = refCallExpressionNode.arguments[i];
1083
+ if (arg === undefined) {
1084
+ arg = "undefined"
1085
+ }
1086
+ var binding = scan.binding(param)
1087
+ if (functionInfo.toInlineArg.has(param.name)) {
1088
+ var paramRefNodes = [...binding.references].slice(1)
1089
+ }
1090
+ else{
1091
+ var paramRefNodes = [[...binding.references][1]]
1092
+ }
1093
+ for (const paramRefNode of paramRefNodes) {
1094
+ if (paramRefNode) {
1095
+ let replacementArgSrc
1096
+ if (typeof arg == "string") {
1097
+ replacementArgSrc = arg
1098
+ }
1099
+ else{
1100
+ replacementArgSrc = ctx.source(arg)
1101
+ if (!ToNotWrapExpressionInRoundParantheses(arg, paramRefNode)) {
1102
+ replacementArgSrc = "("+replacementArgSrc+")"
1103
+ }
1104
+ }
1105
+ ctx.update(replacementArgSrc, paramRefNode)
1106
+ }
1107
+ }
1108
+ }
1109
+ }
1110
+
1111
+ var node = functionNode
1112
+ var fBody = node.body
1113
+ var isCallSiteAStatement = refCallExpressionNode.parent.type == "ExpressionStatement"
1114
+ if(fBody.type == "BlockStatement"){
1115
+ let bodyBlockNodes = fBody.body
1116
+ let assignmentLeftNode = functionInfo.isCallSiteAVariableDeclarator || functionInfo.isCallSiteAnAssignmentExpression
1117
+ let lastReturnNode = functionInfo.lastReturnNode
1118
+ if (lastReturnNode) {
1119
+ let returnArgNode
1120
+ if(isCallSiteAStatement && lastReturnNode.argument.type == "Literal") returnArgNode = null
1121
+ else returnArgNode = lastReturnNode.argument
1122
+ if (functionInfo.toPrependForAssignment) {
1123
+ ctx.prepend(functionInfo.toPrependForAssignment.returnVarName + "=", returnArgNode)
1124
+ }
1125
+ else if (functionInfo.toPrependForExpression) {
1126
+ ctx.prepend(functionInfo.toPrependForExpression.returnVarName + "=", returnArgNode)
1127
+ }
1128
+ ctx.edit.remove(lastReturnNode.start, returnArgNode.start)
1129
+ }
1130
+ else{
1131
+ if(functionInfo.toPrependForAssignment){
1132
+ let lastBodyNode = bodyBlockNodes[bodyBlockNodes.length-1]
1133
+ ctx.append(";"+ctx.source(assignmentLeftNode) + "=void 0", lastBodyNode)
1134
+ }
1135
+ }
1136
+ let toConvertBlockIntoExpression = !functionInfo.toCreateBlock && functionInfo.isOriginallyABlock
1137
+ if(toConvertBlockIntoExpression){
1138
+ let lastExpression, numExpressions = 0, bodyBlockNodes_lastIndex = bodyBlockNodes.length - 1
1139
+ for (let i = 0; i < bodyBlockNodes.length; i++) {
1140
+ let bn = bodyBlockNodes[i];
1141
+ if (bn.type === "EmptyStatement") {
1142
+ ctx.edit.remove(bn.start, bn.end)
1143
+ }
1144
+ else {
1145
+ ++numExpressions
1146
+ if(ctx.srcOrig[bn.end-1] == ";") ctx.edit.remove(bn.end-1, bn.end)
1147
+ if (lastExpression) ctx.append(",", lastExpression)
1148
+ lastExpression = bn.expression
1149
+ }
1150
+ }
1151
+ if(!lastReturnNode && !isCallSiteAStatement && lastExpression) ctx.append("void 0", lastExpression)
1152
+
1153
+ let toNotWrapInRoundParantheses = isCallSiteAStatement || (
1154
+ bodyBlockNodes.length == 1 && ToNotWrapExpressionInRoundParantheses(bodyBlockNodes[0])
1155
+ )
1156
+ ctx.edit.remove(fBody.start, fBody.start+1)
1157
+ ctx.edit.remove(fBody.end-1, fBody.end)
1158
+
1159
+ if(!toNotWrapInRoundParantheses){
1160
+ ctx.prepend("(", fBody)
1161
+ ctx.append(")", fBody)
1162
+ }
1163
+ if (isCallSiteAStatement) {
1164
+ ctx.append(";", fBody)
1165
+ }
1166
+ }
1167
+ else{
1168
+ if (node._funDeclarations && node._funDeclarations.size) {
1169
+ let scopeFDs = new Map
1170
+ for (const d of node._funDeclarations) {
1171
+ let fscope = scan.nearestScope(d, true) || scan.nearestScope(d)
1172
+ let block
1173
+ if (fscope.n.type == "BlockStatement") {
1174
+ block = fscope.n
1175
+ }
1176
+ else if (fscope.n.body && fscope.n.body.type == "BlockStatement") {
1177
+ block = fscope.n.body
1178
+ }
1179
+ else throw "BlockStatement expected"
1180
+
1181
+ let name = d.id._rn || d.id.name
1182
+ ctx.update("", d.id)
1183
+ ctx.prepend(name + "=", d)
1184
+ let assignments = scopeFDs.get(fscope)
1185
+ if (!assignments) {
1186
+ assignments = [block, []]
1187
+ scopeFDs.set(fscope, assignments)
1188
+ }
1189
+ assignments = assignments[1]
1190
+ assignments.push(d)
1191
+ }
1192
+ for (const [scope, [block, assignments]] of scopeFDs) {
1193
+ if (ctx.srcOrig[block.start] !== "{") {
1194
+ throw "expecting {"
1195
+ }
1196
+ for (let i = 0, endIndex = assignments.length-1; i < assignments.length; i++) {
1197
+ let assignment = assignments[i];
1198
+ if (i === 0) {
1199
+ ctx.prepend("let ", assignment)
1200
+ }
1201
+ let commaOrSemicol = i === endIndex? ";" : ","
1202
+ ctx.append(commaOrSemicol, assignment)
1203
+ ctx.move2(assignment.start, assignment.end, block.start+1)
1204
+ assignment._moved_ = true
1205
+ }
1206
+ }
1207
+ }
1208
+
1209
+ }
1210
+
1211
+ if (functionNode._unreachableNodes) {
1212
+ for (const unreachableNode of functionNode._unreachableNodes) {
1213
+ if (!unreachableNode._moved_) {
1214
+ ctx.remove2(unreachableNode.start, unreachableNode.end)
1215
+ }
1216
+ }
1217
+ }
1218
+ }
1219
+ else if(!ToNotWrapExpressionInRoundParantheses(fBody)){
1220
+ ctx.prepend("(", fBody)
1221
+ ctx.append(")", fBody)
1222
+ }
1223
+ }
1224
+ function inlineFunctionBody(functionNode, functionInfo, refCallExpressionNode, ctx) {
1225
+ var fBody = functionNode.body
1226
+ var toCreateBlock = functionInfo.toCreateBlock
1227
+ var editNode
1228
+ if (toCreateBlock) {
1229
+ var funcScopeBindings = scan.scope(functionNode).bindings
1230
+ var lets = []
1231
+ var paramsMap = new Map
1232
+ functionNode.params.forEach((p, i)=>{
1233
+ let callArg = refCallExpressionNode.arguments[i]
1234
+ let name, defaultValueNode
1235
+ if(p.type == "Identifier") name = p.name
1236
+ else if(p.type == "AssignmentPattern" && p.left.type === "Identifier"){
1237
+ name = p.left.name
1238
+ defaultValueNode = p.right
1239
+ if (callArg) {
1240
+ ctx.prepend("??", defaultValueNode)
1241
+ }
1242
+ }
1243
+ else throw "pattern parameter support not implemented"
1244
+ paramsMap.set(name, [callArg, defaultValueNode])
1245
+ })
1246
+ for (const [, b] of funcScopeBindings) {
1247
+ let name = b.definition._rn || b.name
1248
+ let callArg = paramsMap.get(b.name)
1249
+ if(callArg){
1250
+ let firstArgPart = callArg[0] || callArg[1]
1251
+ ctx.prepend(name + "=", firstArgPart)
1252
+ lets.push(callArg)
1253
+ }
1254
+ else{
1255
+ lets.push(name)
1256
+ }
1257
+ }
1258
+ if (lets.length) {
1259
+ if (typeof lets[0] === "string") {
1260
+ lets[0] = "{let "+lets[0]
1261
+ }
1262
+ else {
1263
+ let firstArgPart = lets[0][0] || lets[0][1]
1264
+ ctx.prepend("{let ", firstArgPart)
1265
+ }
1266
+ let firstNode
1267
+ for (let i = 0, endIndex = lets.length-1; i < lets.length; i++) {
1268
+ let _let = lets[i];
1269
+ let commaOrSemicol = i === endIndex? ";" : ","
1270
+ if (typeof _let === "string") {
1271
+ _let += commaOrSemicol
1272
+ lets[i] = _let
1273
+ }
1274
+ else {
1275
+ if (!firstNode) firstNode = _let
1276
+ let secondArgPart = _let[1] || _let[0]
1277
+ ctx.append(commaOrSemicol, secondArgPart)
1278
+ }
1279
+ }
1280
+ if (firstNode) {
1281
+ if (typeof lets[0] === "string") throw "node expected"
1282
+ let lastNode
1283
+ let combinedStringArgs = ""
1284
+ for (const _let of lets) {
1285
+ if (typeof _let === "string") {
1286
+ combinedStringArgs += _let
1287
+ }
1288
+ else {
1289
+ let firstArgPart = _let[0] || _let[1]
1290
+ let secondArgPart = _let[1] || _let[0]
1291
+ lastNode = secondArgPart
1292
+ if (combinedStringArgs) {
1293
+ ctx.prepend(combinedStringArgs, firstArgPart)
1294
+ }
1295
+ fBody._prependNodes ??= []
1296
+ fBody._prependNodes.push(firstArgPart)
1297
+ ctx.secureRange(firstArgPart.start, firstArgPart.end)
1298
+ if (firstArgPart !== secondArgPart) {
1299
+ fBody._prependNodes.push(secondArgPart)
1300
+ ctx.secureRange(secondArgPart.start, secondArgPart.end)
1301
+ }
1302
+ }
1303
+ }
1304
+ if (combinedStringArgs) {
1305
+ ctx.append(combinedStringArgs, lastNode)
1306
+ }
1307
+ }
1308
+ else {
1309
+ var toPrependLets = lets.join("")
1310
+ }
1311
+ }
1312
+ if (!functionInfo.hasFunctionBlockLets && functionInfo.isOriginallyABlock) {
1313
+ if (ctx.srcOrig[fBody.start] !== "{") {
1314
+ throw "expecting {"
1315
+ }
1316
+ if (ctx.edit.slice(fBody.start, fBody.start+1)[0] !== "{") {
1317
+ throw "expecting { 2"
1318
+ }
1319
+ ctx.edit.remove(fBody.start, fBody.start+1)
1320
+ ctx.edit.remove(fBody.end-1, fBody.end)
1321
+ }
1322
+ if (lets.length) {
1323
+ ctx.append("}", fBody)
1324
+ if (toPrependLets) {
1325
+ ctx.prepend(toPrependLets, fBody)
1326
+ }
1327
+ }
1328
+
1329
+ if (functionInfo.toPrependForAssignment) {
1330
+ if (functionInfo.isCallSiteAnAssignmentExpression) {
1331
+ editNode = fBody
1332
+ }
1333
+ else if(functionInfo.isCallSiteAVariableDeclarator){
1334
+ let varDeclaratorNode = refCallExpressionNode.parent
1335
+ varDeclaratorNode._inlinedFunc = fBody
1336
+ if (DEBUG) {
1337
+ varDeclaratorNode._name = functionNode._name
1338
+ }
1339
+ var toPrependForAssignment = functionInfo.toPrependForAssignment
1340
+ }
1341
+ else throw "toPrependForAssignment error"
1342
+ }
1343
+ else if(functionInfo.toPrependForExpression){
1344
+ functionInfo.toPrependForExpression.targetStatement._inlinedFunc = fBody
1345
+ var toPrependForExpression = functionInfo.toPrependForExpression
1346
+ }
1347
+ else{
1348
+ editNode = fBody
1349
+ }
1350
+
1351
+ }
1352
+ else{
1353
+ if (!functionInfo.hasFunctionBlockLets && functionInfo.isOriginallyABlock
1354
+ && !scan.scope(functionNode).bindings.size
1355
+ && ctx.edit.slice(fBody.start, fBody.start+1) === "{"
1356
+ ) {
1357
+ ctx.edit.remove(fBody.start, fBody.start+1)
1358
+ ctx.edit.remove(fBody.end-1, fBody.end)
1359
+ }
1360
+ editNode = fBody
1361
+ }
1362
+
1363
+ if (editNode) {
1364
+ ctx.remove2(refCallExpressionNode.start, refCallExpressionNode.end)
1365
+ if (fBody._prependNodes) {
1366
+ for (const node of fBody._prependNodes) {
1367
+ ctx.move2(node.start, node.end, refCallExpressionNode.start)
1368
+ }
1369
+ }
1370
+ ctx.move2(fBody.start, fBody.end, refCallExpressionNode.start)
1371
+ transform_addSemicolIfNeeded(refCallExpressionNode, ctx)
1372
+ if (DEBUG) {
1373
+ ctx.edit.prependLeft(refCallExpressionNode.start, "/* "+functionNode._name+" INLINED SATRT: *\/")
1374
+ ctx.edit.appendRight(refCallExpressionNode.start, " /* "+functionNode._name+" INLINED END *\/")
1375
+ }
1376
+ }
1377
+
1378
+ return {
1379
+ toPrependForAssignment,
1380
+ toPrependForExpression,
1381
+ }
1382
+ }
1383
+ function hasCallsBetween(rootNode, startNode, endNode, toCheckStartNodeToo, toCheckEndNodeToo) {
1384
+ var has = false
1385
+ var begin = false
1386
+ var end = false
1387
+ function check(node) {
1388
+ walk(node, n=>{
1389
+ if (!begin) {
1390
+ if (n.start < startNode.start) {
1391
+ if (n.end < startNode.start) {
1392
+ return "jump"
1393
+ }
1394
+ return
1395
+ }
1396
+ else if(n == startNode){
1397
+ begin = true
1398
+ if (!toCheckStartNodeToo) {
1399
+ return "jump"
1400
+ }
1401
+ }
1402
+ else if(n.start >= startNode.end){
1403
+ return "end"
1404
+ }
1405
+ }
1406
+ if (!toCheckEndNodeToo && n === endNode) {
1407
+ end = true
1408
+ return "end"
1409
+ }
1410
+ if (n.type == "ConditionalExpression" || n.type == "IfStatement") {
1411
+ check(n.test)
1412
+ if(end) return "end"
1413
+ check(n.consequent)
1414
+ if (end) {
1415
+ if(endNode && endNode.start >= n.consequent.start && endNode.start < n.consequent.end || !endNode) return "end"
1416
+ has = false
1417
+ end = false
1418
+ }
1419
+ if (n.alternate) {
1420
+ check(n.alternate)
1421
+ if(end) return "end"
1422
+ }
1423
+ return "jump"
1424
+ }
1425
+ if (n.type == "MemberExpression") {
1426
+ check(n.object)
1427
+ if(end) return "end"
1428
+ check(n.property)
1429
+ if(end) return "end"
1430
+ if (n.parent && !(
1431
+ n.parent.type === "CallExpression" && n === n.parent.callee
1432
+ )
1433
+ ) {
1434
+ has = true
1435
+ end = true
1436
+ return "end"
1437
+ }
1438
+ return "jump"
1439
+ }
1440
+ if (n.type == "CallExpression") {
1441
+ check(n.callee)
1442
+ if(end) return "end"
1443
+ for (const arg of n.arguments) {
1444
+ check(arg)
1445
+ if(end) return "end"
1446
+ }
1447
+ has = true
1448
+ end = true
1449
+ return "end"
1450
+ }
1451
+ if (isCallNode(n)){
1452
+ has = true
1453
+ end = true
1454
+ return "end"
1455
+ }
1456
+ if (isFunctionNode(n)) {
1457
+ return "jump"
1458
+ }
1459
+ if (n === endNode) {
1460
+ end = true
1461
+ return "end"
1462
+ }
1463
+ }, null, 1)
1464
+ }
1465
+ check(rootNode)
1466
+ return has
1467
+ }
1468
+ function isBindingInScope(binding, targetNode) {
1469
+ let scopeNode = binding.scope?.scopeNode
1470
+ return !scopeNode || isNodeContainedIn(targetNode, scopeNode)
1471
+ }
1472
+ function sortScopeBindingsByPositionInCode(scope) {
1473
+ // The declaration node is at the top of binding.references, regardless of source position.
1474
+ // The rest is sorted by source position
1475
+ for (const [id, binding] of scope.bindings) {
1476
+ if (binding.references.size >= 3) {
1477
+ var [declaration, ...refs] = [...binding.references]
1478
+ refs.sort((a, b) => a.start - b.start)
1479
+ binding.references = new Set([declaration, ...refs])
1480
+ }
1481
+ }
1482
+ var children = scope.children
1483
+ if (children) {
1484
+ for (const child of children) {
1485
+ sortScopeBindingsByPositionInCode(child)
1486
+ }
1487
+ }
1488
+ }
1489
+ function JsEscapeString(string, quoteChar) {
1490
+ return ('' + string).replace(/["'`\\\n\r\u2028\u2029\u2003]/g, function (character) {
1491
+ switch (character) {
1492
+ case '"':
1493
+ case '`':
1494
+ case "'":
1495
+ if(quoteChar !== character) return character
1496
+ case '\\':
1497
+ return '\\' + character
1498
+ case '\n':
1499
+ return '\\n'
1500
+ case '\r':
1501
+ return '\\r'
1502
+ case '\u2028':
1503
+ return '\\u2028'
1504
+ case '\u2029':
1505
+ return '\\u2029'
1506
+ case '\u2003':
1507
+ return '\\u2003'
1508
+ case '\0':
1509
+ return '\\0'
1510
+ }
1511
+ })
1512
+ }
1513
+ function indexOfSeparator(separator, strAboveOrBelow, below=true) {
1514
+ const comments = '(?:\\s*(?:\\/\\/.*\\r?\\n|\\/\\*(?:[\\s\\S](?!\\*\\/))*?(?:.|[\\s])?\\*\\/)*)*'
1515
+ let regStr = below? "^"+comments+"\\s*"+separator : separator+comments+"\\s*$"
1516
+ if (!separator && below) regStr = "^"+comments+"."
1517
+ let regs = indexOfSeparator.regs ??= new Map
1518
+ let reg = regs.get(regStr)
1519
+ if (!reg) {
1520
+ reg = new RegExp(regStr)
1521
+ regs.set(regStr, reg)
1522
+ }
1523
+ let match = strAboveOrBelow.match(reg)?.[0]
1524
+ if (!match) return -1
1525
+ return below? match.length-1 : strAboveOrBelow.length-match.length
1526
+ }
1527
+ function findNextIndexInJs(str, src, comments, start=0, end=src.length, backward) {
1528
+ if (!backward) {
1529
+ let commentIndex = bsGetIndexOfNearest(comments, start, true, "start")
1530
+ let nextComment
1531
+ if (commentIndex >= 0) {
1532
+ if (start < comments[commentIndex].end) start = comments[commentIndex].end
1533
+ }
1534
+ nextComment = comments[++commentIndex]
1535
+ var iStr = 0
1536
+ var strLen = str.length
1537
+ for (let i = start; i < end; i++) {
1538
+ if (nextComment && i === nextComment.start) {
1539
+ i = nextComment.end
1540
+ nextComment = comments[++commentIndex]
1541
+ }
1542
+ while (src[i+iStr] === str[iStr] && iStr < strLen) ++iStr
1543
+ if (iStr >= strLen) return i
1544
+ iStr = 0
1545
+ }
1546
+ return -1
1547
+ }
1548
+ else {
1549
+ let commentIndex = bsGetIndexOfNearest(comments, end, true, "start")
1550
+ let nextComment
1551
+ if (commentIndex >= 0) {
1552
+ if (end < comments[commentIndex].end) end = comments[commentIndex].start-1
1553
+ }
1554
+ nextComment = comments[--commentIndex]
1555
+ var strLen = str.length
1556
+ var iStr = 0
1557
+ for (let i = end; i >= start; i--) {
1558
+ if (nextComment && i === nextComment.end-1) {
1559
+ i = nextComment.start-1
1560
+ nextComment = comments[--commentIndex]
1561
+ }
1562
+ while (src[i-iStr] === str[strLen-1-iStr] && iStr < strLen) ++iStr
1563
+ if (iStr >= strLen) return i
1564
+ iStr = 0
1565
+ }
1566
+ return -1
1567
+ }
1568
+ }
1569
+ function getExcludeRanges(src, ast) {
1570
+ var ranges = []
1571
+ var funcNodes = new Set
1572
+ walk(ast, node=>{
1573
+ if (node.type === "FunctionDeclaration" || node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression") {
1574
+ var hasMarker = src.slice(node.start - (EXCLUDE_FUNCTION_FROM_SHRINK_MARKER.length+13), node.start).includes(EXCLUDE_FUNCTION_FROM_SHRINK_MARKER)
1575
+ if (hasMarker) {
1576
+ ranges.push([node.start, node.end])
1577
+ funcNodes.add(node)
1578
+ return "jump"
1579
+ }
1580
+ }
1581
+ })
1582
+ return [ranges, funcNodes]
1583
+ }
1584
+ function hasCommentAnnotationInFront(src, node, comments, annotation, maxDistance=Infinity, toReturnCommentNode) {
1585
+ let commentIndex = bsGetIndexOfNearest(comments, node.start, true, "end")
1586
+ if (commentIndex < 0) return
1587
+ if(src.slice(comments[commentIndex].end, node.start).trim() !== "") return
1588
+ var i = commentIndex, c = 0
1589
+ while (i >= 0) {
1590
+ var comment = comments[i]
1591
+ var result = typeof annotation === "string"? comment.value.trimLeft().startsWith(annotation) : comment.value.match(annotation)
1592
+ if (result) {
1593
+ return toReturnCommentNode? comment : result
1594
+ }
1595
+ if (++c >= maxDistance) return
1596
+ var prevComment = comments[i-1]
1597
+ if (!prevComment) return
1598
+ let prevEnd = prevComment.end
1599
+ if(prevComment.type === "Block") prevEnd += 2
1600
+ let start = comment.start -2
1601
+ if (src.slice(prevEnd, start).trim() !== "") return
1602
+ --i
1603
+ }
1604
+ }
1605
+ function getUseStrictExpressionStatement(functionOrProgramNode) {
1606
+ if (functionOrProgramNode.body.length) {
1607
+ let first = functionOrProgramNode.body[0]
1608
+ if (first.type === 'ExpressionStatement' && first.expression.type === 'Literal' && first.expression.value === 'use strict') {
1609
+ return first
1610
+ }
1611
+ }
1612
+ }
1613
+ function forceArrowFunctions(ast, src, ms, comments) {
1614
+ function usesPrivateFunctionName(n) {
1615
+ if (n.id) {
1616
+ let b = scan.getBinding(n.id)
1617
+ return b && b.references.size > 1
1618
+ }
1619
+ }
1620
+ var numConvertedFunctions = 0
1621
+ var hoistingPointsVar = new Map
1622
+ var hoistingPointsLet = new Map
1623
+ walk(ast, n=>{
1624
+ let isFunctionDeclaration = n.type === 'FunctionDeclaration'
1625
+ let isFunctionExpression = n.type === 'FunctionExpression'
1626
+ if (!isFunctionDeclaration && !isFunctionExpression) return
1627
+ if (n.uses_arguments || n.uses_this) return
1628
+ if (n.generator) return
1629
+ if (n.parent.type == "Property" && (n.parent.kind != "init" || n.parent.method) || n.parent.type == "MethodDefinition") return
1630
+ if (isFunctionExpression) {
1631
+ if (usesPrivateFunctionName(n)) return
1632
+ }
1633
+ var hasParams = n.params.length
1634
+ var init_start = n.start
1635
+ var async = n.async?"async":""
1636
+ if (hasParams) {
1637
+ var bracketIndex = findNextIndexInJs("(", src, comments, n.id?.start ?? n.start, n.end)
1638
+ if (DEBUG && bracketIndex < 0) throw "!bracketIndex"
1639
+ var init_end = bracketIndex
1640
+ ms.update(init_start, init_end, async)
1641
+ var bracketIndex2 = findNextIndexInJs(")", src, comments, n.start, n.body.start, 1)
1642
+ if (DEBUG && bracketIndex2 < 0) throw "!bracketIndex2"
1643
+ if (bracketIndex2+1 < n.body.start) {
1644
+ ms.update(bracketIndex2+1, n.body.start, "=>")
1645
+ }
1646
+ else {
1647
+ ms.prependRight(n.body.start, "=>")
1648
+ }
1649
+
1650
+ }
1651
+ else {
1652
+ var init_end = n.body.start
1653
+ ms.update(init_start, init_end, async+"()=>")
1654
+ }
1655
+ if(isFunctionDeclaration) {
1656
+ if (n.id?.type !== "Identifier") {
1657
+ throw "n.id: Identifier expected"
1658
+ }
1659
+ var parentFunc = scan.getNearestScopeNode(n)
1660
+ var isStrict = parentFunc.isStrictMode
1661
+ var isLet = isStrict
1662
+ var points = isLet? hoistingPointsLet : hoistingPointsVar
1663
+ var pointDef = scan.getNearestScopeNode(n, 1)
1664
+ let arr = points.get(pointDef)
1665
+ if (!arr) {
1666
+ arr = []
1667
+ points.set(pointDef, arr)
1668
+ }
1669
+ arr.push(n)
1670
+ }
1671
+ ++numConvertedFunctions
1672
+ })
1673
+ for (const points of [hoistingPointsVar, hoistingPointsLet]) {
1674
+ for (const [scopeNode, funcs] of points) {
1675
+ if (DEBUG && (scopeNode.type !== "BlockStatement" && scopeNode.type !== "Program")) {
1676
+ throw "scopeNode BlockStatement|Program expected"
1677
+ }
1678
+ let use_strict = getUseStrictExpressionStatement(scopeNode)
1679
+ var isLet = points === hoistingPointsLet
1680
+ var decl = isLet? "let " : "var "
1681
+ if (use_strict && src[use_strict.end-1] != ";") decl = ";"+decl
1682
+ var first = funcs[0]
1683
+ for (const func of funcs) {
1684
+ let name = func.id._v || func.id.name
1685
+ let prependStr = name+"="
1686
+ if (func !== first) prependStr = ","+prependStr
1687
+ ms.prependRight(func.start, prependStr)
1688
+ }
1689
+ ms.prependRight(first.start, decl)
1690
+ let last = funcs[funcs.length-1]
1691
+ ms.appendLeft(last.end, ";")
1692
+ if (use_strict) {
1693
+ var targetIndex = scopeNode.body[1]?.start ?? use_strict.end
1694
+ }
1695
+ else {
1696
+ if (scopeNode.type === "Program") {
1697
+ let firstStatement = scopeNode.body.length && scopeNode.body[use_strict? 1 : 0]
1698
+ if (firstStatement) {
1699
+ var targetIndex = firstStatement.start
1700
+ }
1701
+ else {
1702
+ let i = indexOfSeparator("", src, 1)
1703
+ var targetIndex = i < 0? 0 : i
1704
+ }
1705
+ }
1706
+ else {
1707
+ var targetIndex = scopeNode.start
1708
+ if (src[targetIndex] == "{") ++targetIndex
1709
+ }
1710
+ }
1711
+ for (const func of funcs) {
1712
+ ms.move(func.start, func.end, targetIndex)
1713
+ }
1714
+ }
1715
+ }
1716
+ return numConvertedFunctions
1717
+ }
1718
+
1719
+
1720
+
1721
+
1722
+ /**
1723
+ * @typedef {Object} InlineClassObjectPropertiesOptions
1724
+ * @property {any} [variableNamesChangeable=false]
1725
+ * @property {any} [classesNeedCommentMarker=false]
1726
+ * @property {any} [inlineConstantsMaxNumberOfTimes=3]
1727
+ * @property {any} [toAllowInliningOutsideOfTheClass=true]
1728
+ * @property {any} [withSourceMap=false]
1729
+ * @property {any} [rootIsStrictMode=false]
1730
+ * @property {{inlinedProps:Set<string>, removedUnusedProps:Set<string>}} [infoObject]
1731
+ * @property {SourceMap?} [map] - a prior source map object; this key will hold the new source map object if withSourceMap is truthy
1732
+ */
1733
+ /**
1734
+ * @param {string} src - source code
1735
+ * @param {InlineClassObjectPropertiesOptions} options
1736
+ * @returns {string}
1737
+ */
1738
+ function inlineClassObjectProperties(src, options) {
1739
+ const variableNamesChangeable = options && "variableNamesChangeable" in options? options.variableNamesChangeable : false
1740
+ const classesNeedCommentMarker = options && "classesNeedCommentMarker" in options? options.classesNeedCommentMarker : false
1741
+ const toAllowInliningOutsideOfTheClass = options && "allowInliningOutsideOfTheClass" in options? options.allowInliningOutsideOfTheClass : true
1742
+ const inlineLiteralValues_maxNumberOfTimes = Math.max(1, Number(options?.["inlineConstantsMaxNumberOfTimes"]) || 3)
1743
+ const infoObject = options && "infoObject" in options? options.infoObject : null
1744
+ const withSourceMap = options && "withSourceMap" in options? options.withSourceMap : false
1745
+ const rootIsStrictMode = options && "rootIsStrictMode" in options? options.rootIsStrictMode : false
1746
+ let inputMap = options?.map
1747
+
1748
+ function _inline() {
1749
+
1750
+
1751
+ /** @type {acorn.Comment[]} */
1752
+ var comments = []
1753
+ var ast = acorn.parse(src, {
1754
+ ecmaVersion: "latest",
1755
+ onComment: comments,
1756
+ // sourceType: "module",
1757
+ })
1758
+ scan.crawl(ast, {rootIsStrictMode})
1759
+
1760
+
1761
+ function findClassObject() {
1762
+ function hasMarker(node) {
1763
+ return hasCommentAnnotationInFront(src, node, comments, firstIteration? CLASS_OBJECT_MARKER : CLASS_OBJECT_MARKER_PENDING, 10, 1)
1764
+ }
1765
+ walk(ast, n=>{
1766
+ let comment
1767
+ if (n.type == "ObjectExpression" && _offset <= n.start && (comment = hasMarker(n))) {
1768
+ _offset = n.start
1769
+ cObj = n
1770
+ if (!firstIteration && comment) {
1771
+ cObj._comment_pending = comment
1772
+ }
1773
+ return "end"
1774
+ }
1775
+ if ((n.type == "ClassDeclaration" || n.type == "ClassExpression") && _offset <= n.start && n.body && n.body.body
1776
+ && (!classesNeedCommentMarker && firstIteration || (comment = hasMarker(n)))
1777
+ ) {
1778
+ _offset = n.start
1779
+ cObj = n
1780
+ cObj._isClass = 1
1781
+ if (!firstIteration && comment) {
1782
+ cObj._comment_pending = comment
1783
+ }
1784
+ return "end"
1785
+ }
1786
+ })
1787
+ }
1788
+ function findAllObjectProperties() {
1789
+ var properties = cObj._isClass? cObj.body.body : cObj.properties
1790
+ var i = -1
1791
+ for (let propertyNode of properties) {
1792
+ ++i
1793
+ if(cObj._isClass){
1794
+ }
1795
+ else{
1796
+ if (propertyNode.kind !== "init") continue
1797
+
1798
+ }
1799
+ if (propertyNode.key.type == "Identifier" || propertyNode.key.type == 'PrivateIdentifier') {
1800
+ var name = propertyNode.key.name
1801
+ }
1802
+ else if(propertyNode.key.type == "Literal" && typeof propertyNode.key.value == "string"){
1803
+ var name = propertyNode.key.value
1804
+ }
1805
+ else continue
1806
+ let valueNode = propertyNode.value
1807
+ if(hasExpressionCalls(valueNode, true)) continue
1808
+ _allProps.set(name, propertyNode)
1809
+ propertyNode._i = i
1810
+ propertyNode._isInClass = cObj._isClass
1811
+ propertyNode._cObj = cObj
1812
+ propertyNode._name = name
1813
+ if (valueNode) {
1814
+ valueNode._name = name
1815
+ if (isPropertyValueAlwaysInlinableLiteral(valueNode) || valueNode.type == "Identifier") {
1816
+ propertyNode._isPropertyValueAlwaysInlinable = true
1817
+ }
1818
+ }
1819
+ }
1820
+ }
1821
+ function isValidAssignment(node, safe=true) {
1822
+ var left, right, isDeclaration
1823
+ if(node.type === "AssignmentExpression"){
1824
+ let operator = node.operator
1825
+ if (operator === "=") {
1826
+ if (safe && isResultAccessible(node.parent)) {
1827
+ return false
1828
+ }
1829
+
1830
+ left = node.left
1831
+ right = node.right
1832
+ }
1833
+ else return
1834
+ }
1835
+ else if (node.type === 'VariableDeclarator' && node.init) {
1836
+ left = node.id
1837
+ right = node.init
1838
+ isDeclaration = true
1839
+ }
1840
+ else return
1841
+ return [left, right, isDeclaration]
1842
+
1843
+
1844
+
1845
+
1846
+ function isResultAccessible(node, canBeVariableDeclarator=true) {
1847
+ if (canBeVariableDeclarator && node.type == "VariableDeclarator") return false
1848
+ if (node.type == "LogicalExpression" || node.type == "BinaryExpression") {
1849
+ return isResultAccessible(node.parent, false)
1850
+ }
1851
+ var isVoided = node.type == "ExpressionStatement"
1852
+ || node.type == "SequenceExpression" && (
1853
+ node.expression[node.expression.length-1] !== node || node.parent.type == "ExpressionStatement"
1854
+ )
1855
+ return !isVoided
1856
+ }
1857
+ }
1858
+ function IsBindingConstant(/** @type {Binding} */ binding, forProperties, addRefsiteChecker) {
1859
+ var _isConstant = true
1860
+ try {
1861
+ if (binding.isConst) return true
1862
+ if (binding._isConst2 !== undefined){
1863
+ if (binding._isConst2) return true
1864
+ if (forProperties){
1865
+ if(binding._isConst2_forProperties !== undefined) return binding._isConst2_forProperties
1866
+ }
1867
+ else return false
1868
+ }
1869
+ if (!binding.definition){
1870
+ return _isConstant = false
1871
+ }
1872
+ if (binding.references.size === 1) return true
1873
+ var _hasCheckedAssignment
1874
+ var assignmentNode, assignmentRef
1875
+ var initializerNode
1876
+ var assignmentFunction
1877
+ var bindingScopeFunction
1878
+ if (!getAssignmentContext()) {
1879
+ return _isConstant = false
1880
+ }
1881
+ binding._assignmentNode = assignmentNode
1882
+ binding._assignmentRef = assignmentRef
1883
+ if (binding.isHoisted && (binding.definition.parent.type === "FunctionDeclaration" && binding.definition.parent.id == binding.definition) && !assignmentRef) return true
1884
+ if (!assignmentRef) return true
1885
+ var isInitializedAtDeclaration = binding.definition === assignmentRef
1886
+ var assignmentLoop
1887
+ var assignmentBranch
1888
+ var hasUndef = false
1889
+ if (binding.references.size <= (isInitializedAtDeclaration?1:2)) return true
1890
+ getLocationContext()
1891
+ if (!check_refs()){
1892
+ return _isConstant = false
1893
+ }
1894
+ return true
1895
+
1896
+ } finally {
1897
+ binding._isConst2 = _isConstant && !hasUndef
1898
+ if (forProperties) {
1899
+ binding._isConst2_forProperties = _isConstant
1900
+ }
1901
+ if (addRefsiteChecker && _isConstant) {
1902
+ binding._isConstantAtNode = isConstantAtNode
1903
+ }
1904
+ }
1905
+
1906
+ function check_refs() {
1907
+ if (assignmentLoop){
1908
+ if (forProperties) {
1909
+ return true
1910
+ }
1911
+ else return false
1912
+ }
1913
+ return verify_functions_validRange()
1914
+ }
1915
+ function verify_functions_validRange(otherRefNode) {
1916
+ var defNode = binding.definition
1917
+ var bindingScopes = getScopes()
1918
+ if (otherRefNode) {
1919
+ if (otherRefNode === defNode || otherRefNode === assignmentRef) return false
1920
+ return isRefValid(otherRefNode)
1921
+ }
1922
+ for (const ref of binding.references) {
1923
+ if (ref === defNode || ref === assignmentRef) continue
1924
+ if (!isRefValid(ref)) {
1925
+ if (forProperties) ref._mightBeUndef = hasUndef = true
1926
+ else return false
1927
+ }
1928
+ }
1929
+ return true
1930
+
1931
+ function isRefValid(ref) {
1932
+ let scopeNode = scan.getNearestScopeNode(ref, 0)
1933
+ let refLocationValid = isLocationValid(ref)
1934
+ if (refLocationValid === "inFuncOrMethod") return true
1935
+ let isRootRef = bindingScopes.has(scopeNode)
1936
+ if (isRootRef) {
1937
+ return refLocationValid
1938
+ }
1939
+ while (scopeNode) {
1940
+ let parentScopeNode = scan.getNearestScopeNode(scopeNode, 0)
1941
+ let isRootFunc = bindingScopes.has(parentScopeNode)
1942
+ if (isRootFunc) {
1943
+ if (scopeNode.type === "FunctionDeclaration") {
1944
+ let funcBinding = scan.getBinding(scopeNode.id)
1945
+ return isValidRootFuncBinding(funcBinding)
1946
+ }
1947
+ else {
1948
+ if (isLocationValid(scopeNode)) {
1949
+ return true
1950
+ }
1951
+ var [left] = isValidAssignment(scopeNode.parent, 1)||""
1952
+ if (!left)
1953
+ return false
1954
+ let funcBinding = scan.getBinding(left)
1955
+ return isValidRootFuncBinding(funcBinding, left)
1956
+ }
1957
+ }
1958
+ scopeNode = parentScopeNode
1959
+ }
1960
+ }
1961
+ function getScopes() {
1962
+ let scopes = new Set
1963
+ let scope = scan.getNearestScopeNode(assignmentBranch, 0, 1)
1964
+ let root = bindingScopeFunction
1965
+ scopes.add(root)
1966
+ while(scope){
1967
+ scopes.add(scope)
1968
+ scope = scan.getNearestScopeNode(scope, 0)
1969
+ if (scope === root) break
1970
+ }
1971
+ return scopes
1972
+ }
1973
+ function isValidRootFuncBinding(funcBinding, assignmentRef) {
1974
+ let isConst = IsBindingConstant(funcBinding, 1)
1975
+ if (!isConst)
1976
+ return false
1977
+ for (const ref of funcBinding.references) {
1978
+ if (ref === funcBinding.definition || ref === assignmentRef) continue
1979
+ if (!isLocationValid(ref))
1980
+ return false
1981
+ }
1982
+ return true
1983
+ }
1984
+ function isLocationValid(ref) {
1985
+ let afterAssignment = isAfterAssignment(ref)
1986
+ if (afterAssignment
1987
+ && (assignmentBranch? (ref.start >= assignmentBranch.start && ref.end <= assignmentBranch.end): true)
1988
+ ) {
1989
+ return afterAssignment
1990
+ }
1991
+ }
1992
+ function isAfterAssignment(referenceNode) {
1993
+ if (referenceNode !== assignmentRef && referenceNode.end <= assignmentNode.end){
1994
+ if (referenceNode.end <= initializerNode.start) {
1995
+ return false
1996
+ }
1997
+ let lastFunc
1998
+ let parent = referenceNode.parent
1999
+ while (parent) {
2000
+ if (initializerNode === parent) break
2001
+ if (isFunctionNode(parent)) {
2002
+ lastFunc = parent
2003
+ }
2004
+ parent = parent.parent
2005
+ }
2006
+ if (!lastFunc){
2007
+ return false
2008
+ }
2009
+ if (lastFunc === initializerNode){
2010
+ }
2011
+ else {
2012
+ parent = lastFunc
2013
+ while (parent) {
2014
+ if (parent === initializerNode) break
2015
+ if (parent.parent.parent.type === 'ClassBody') {
2016
+ parent = parent.parent.parent.parent
2017
+ }
2018
+ else if(parent.parent.type === 'Property'){
2019
+ parent = parent.parent.parent
2020
+ }
2021
+ else if(parent.parent.type === 'ArrayExpression'){
2022
+ parent = parent.parent
2023
+ }
2024
+ else {
2025
+ return false
2026
+ }
2027
+ }
2028
+ if (DEBUG && !parent) throw "!parent"
2029
+ }
2030
+ return "inFuncOrMethod"
2031
+ }
2032
+ return true
2033
+ }
2034
+ }
2035
+ function getLocationContext() {
2036
+ let child = assignmentNode
2037
+ let parent = child.parent
2038
+ let scopeNode = binding.scope.scopeNode
2039
+ while (parent) {
2040
+ if (scopeNode === parent || assignmentFunction === parent){
2041
+ break
2042
+ }
2043
+ if (parent.type === 'IfStatement' && child !== parent.test
2044
+ || parent.type === 'ConditionalExpression' && parent.test !== child
2045
+ || parent.type === 'LogicalExpression' && child === parent.right
2046
+ || parent.type === 'MemberExpression' && parent.optional && child === parent.property
2047
+ || parent.type === 'SwitchStatement' && child !== parent.discriminant
2048
+ ) {
2049
+ assignmentBranch = child
2050
+ }
2051
+ else if (parent.type === 'DoWhileStatement' && child !== parent.test
2052
+ || parent.type === 'WhileStatement' && child !== parent.test
2053
+ || parent.type === 'ForStatement' && child !== parent.test && child !== parent.init
2054
+ ) {
2055
+ assignmentBranch = child
2056
+ assignmentLoop = parent
2057
+ }
2058
+ if (assignmentBranch) break
2059
+ child = parent
2060
+ parent = child.parent
2061
+ }
2062
+ assignmentBranch ||= assignmentFunction
2063
+
2064
+ if (assignmentLoop){
2065
+ if (forProperties) {
2066
+ for (const ref of binding.references) {
2067
+ ref._mightBeUndef = true
2068
+ }
2069
+ hasUndef = true
2070
+ }
2071
+ }
2072
+ }
2073
+ function getAssignmentContext() {
2074
+ _hasCheckedAssignment = true
2075
+ for (const ref of binding.references) {
2076
+ let parent = ref.parent
2077
+ if (parent.type === "UpdateExpression") {
2078
+ return false
2079
+ }
2080
+ let _assignmentNode
2081
+ if (_assignmentNode = isAssignmentTarget(ref, 1)) {
2082
+ if (assignmentNode) return false
2083
+
2084
+ assignmentNode = _assignmentNode
2085
+ assignmentRef = ref
2086
+ if (assignmentNode.type == "AssignmentExpression") {
2087
+ initializerNode = assignmentNode.right
2088
+ }
2089
+ else if (assignmentNode.type == "VariableDeclarator") {
2090
+ initializerNode = assignmentNode.init
2091
+ }
2092
+ }
2093
+ }
2094
+ bindingScopeFunction = scan.getNearestScopeNode(binding.scope.scopeNode, 0, 1)
2095
+ if (assignmentNode) {
2096
+ assignmentFunction = scan.getNearestScopeNode(assignmentNode, 0) || bindingScopeFunction
2097
+ }
2098
+ return true
2099
+ }
2100
+ function isConstantAtNode(node) {
2101
+ let nodeScopeNode = scan.getNearestScopeNode(node, 1, 0)
2102
+ let bindingScopeNode = binding.scope.scopeNode
2103
+ if (!nodeScopeNode || !isNodeContainedIn(nodeScopeNode, bindingScopeNode, 1)) return false
2104
+ if (!_hasCheckedAssignment) getAssignmentContext()
2105
+ if (!assignmentNode) return true
2106
+ if (!assignmentFunction) getLocationContext()
2107
+ if (assignmentLoop) return false
2108
+ return verify_functions_validRange(node)
2109
+ }
2110
+ }
2111
+ function findSafeClassBindings() {
2112
+ function isReassigned(binding, validRight, infoObject) {
2113
+ let assignment1
2114
+ for (const ref of binding.references) {
2115
+ let parent = ref.parent
2116
+ if (parent.type === "UpdateExpression") {
2117
+ return true
2118
+ }
2119
+ var leftRight = isValidAssignment(parent)
2120
+ if (leftRight) {
2121
+ if (validRight !== leftRight[1] || assignment1) return true
2122
+ assignment1 = leftRight[1]
2123
+ }
2124
+ else if(parent.type === "AssignmentExpression"){
2125
+ return true
2126
+ }
2127
+ }
2128
+ return false
2129
+ }
2130
+ function getOtherAssignedBindings(binding1, arr=[]) {
2131
+ if (binding1) {
2132
+ var _assignmentRef = binding1._assignmentRef
2133
+ var definition = binding1.definition
2134
+ for (const ref of binding1.references) {
2135
+ if (ref === _assignmentRef || ref === definition || ref._mightBeUndef) continue
2136
+ let leftright = isValidAssignment(ref.parent)
2137
+ if (leftright && leftright[1] === ref && leftright[0].type === "Identifier") {
2138
+ let binding2 = scan.getBinding(leftright[0])
2139
+ if (binding2 && binding2 !== binding1 && !arr.includes(binding2) && IsBindingConstant(binding2, 1)) {
2140
+ arr.push(binding2)
2141
+ getOtherAssignedBindings(binding2, arr)
2142
+ }
2143
+ }
2144
+ }
2145
+ }
2146
+ return arr
2147
+ }
2148
+ function getAllSafeThisBindings(functionNode) {
2149
+ var result = []
2150
+ walk(functionNode.body, n=>{
2151
+ if(n.type == "ThisExpression"){
2152
+ var leftRight = isValidAssignment(n.parent)
2153
+ if (leftRight) {
2154
+ let [left, right, isDeclaration] = leftRight
2155
+ if (leftRight && right === n && left.type === "Identifier" && isDeclaration) {
2156
+ let binding = scan.getBinding(left)
2157
+ if (IsBindingConstant(binding, 1)) {
2158
+ result.push(binding, ...getOtherAssignedBindings(binding))
2159
+ }
2160
+ }
2161
+ }
2162
+ n._isValidThis = cObj
2163
+ }
2164
+ if (n !== functionNode && (n.type === 'FunctionDeclaration' || n.type === 'FunctionExpression')) {
2165
+ return "jump"
2166
+ }
2167
+ })
2168
+ return result
2169
+ }
2170
+
2171
+ var classIsExpression
2172
+ var binding1, binding2
2173
+ if (isClass) {
2174
+ binding1 = cObj.id && scan.getBinding(cObj.id)
2175
+ if (binding1 && isReassigned(binding1, cObj)) {
2176
+ binding1 = null
2177
+ }
2178
+ if (cObj.type == "ClassExpression") {
2179
+ classIsExpression = true
2180
+ }
2181
+ }
2182
+ else {
2183
+ classIsExpression = true
2184
+ }
2185
+ if (classIsExpression) {
2186
+ let parent = cObj.parent
2187
+ var leftRight = isValidAssignment(parent)
2188
+ if (leftRight && leftRight[1] === cObj && leftRight[0].type === "Identifier") {
2189
+ binding2 = scan.getBinding(leftRight[0])
2190
+ if (binding2 && !IsBindingConstant(binding2, 1)) {
2191
+ binding2 = null
2192
+ }
2193
+ }
2194
+ }
2195
+ if (binding1 || binding2) {
2196
+ for (const binding of [binding1, binding2, ...getOtherAssignedBindings(binding2)]) {
2197
+ if (binding) {
2198
+ if (!cObj._name) cObj._name = binding.name
2199
+ for (const ref of binding.references) {
2200
+ let isRefOutsideOfTheClass = ref.start < cObj.start || ref.start >= cObj.end
2201
+ if (toAllowInliningOutsideOfTheClass || !isRefOutsideOfTheClass) {
2202
+ if (isClass) {
2203
+ ref._isSafeClassRef = cObj
2204
+ }
2205
+ else {
2206
+ ref._isSafeThis = cObj
2207
+ }
2208
+ }
2209
+ }
2210
+ }
2211
+ }
2212
+ }
2213
+ else {
2214
+ cObj._name = isClass? "?class" : "?object"
2215
+ }
2216
+
2217
+ for (const [n, property] of _allProps) {
2218
+ let toNotInlineHereComment = hasCommentAnnotationInFront(src, property, comments, CLASS_OBJECT_MARKER__DONT_INLINE_HERE, 10, 1)
2219
+ let propNode = property.value
2220
+ if (propNode && propNode.type == "FunctionExpression" && propNode.uses_this) {
2221
+ for (const binding of getAllSafeThisBindings(propNode)) {
2222
+ for (const ref of binding.references) {
2223
+ ref._isSafeThis = cObj
2224
+ }
2225
+ }
2226
+ }
2227
+ if (toNotInlineHereComment) {
2228
+ property._comment_toNotInlineHere = toNotInlineHereComment
2229
+ }
2230
+
2231
+ let toNotInlineComment = hasCommentAnnotationInFront(src, property, comments, CLASS_OBJECT_MARKER__KEEP_PROPERTY, 10)
2232
+ if (toNotInlineComment) {
2233
+ _allProps.delete(n)
2234
+ }
2235
+ }
2236
+
2237
+
2238
+ }
2239
+ function filterIfAccessedOnUnknownObjectsAndGetRefs() {
2240
+ function isAssignedTo(node) {
2241
+ return node.parent.type == "UpdateExpression"
2242
+ || node.parent.type == "AssignmentExpression" && node.parent.left == node
2243
+ }
2244
+ function removeCandidateProperty(name, _allProps) {
2245
+ _allProps.delete(name)
2246
+ if (!_allProps.size) {
2247
+ let allEmpty = classObjects.every(({_allProps})=>!_allProps.size)
2248
+ if (allEmpty) return true
2249
+ }
2250
+ }
2251
+ const toInlineSafeLiteralsWherePossible = true
2252
+ var classObjects_currentIndex = 0
2253
+ var cObj_ofCurrentLocation = null
2254
+ var cObjNext = classObjects[0]
2255
+
2256
+ walk(ast, node=>{
2257
+ var name = null
2258
+ var isIdentifier = node.type == "Identifier" || node.type == 'PrivateIdentifier'
2259
+ var isLiteral = node.type == "Literal"
2260
+ var isTemplateLiteral = node.type == "TemplateLiteral" && node.expressions.length == 0
2261
+ var templateLiteralValue = isTemplateLiteral && node.quasis[0].value.cooked
2262
+ if(!(isLiteral || isTemplateLiteral || isIdentifier)) return
2263
+ var isPropertyMemberKey = node.parent.type == "MemberExpression" && node.parent.property == node
2264
+ if (isPropertyMemberKey) {
2265
+
2266
+ var isComputed = node.parent.computed
2267
+ if (isLiteral) {
2268
+ if(typeof node.value !== "string") return
2269
+ name = node.value
2270
+ }
2271
+ else if(isTemplateLiteral){
2272
+ name = templateLiteralValue
2273
+ }
2274
+ else if(isIdentifier && !isComputed){
2275
+ name = node.name
2276
+ }
2277
+ else{
2278
+ return
2279
+ }
2280
+ }
2281
+ else{
2282
+ return
2283
+ }
2284
+ node = node.parent
2285
+ var object = node.object
2286
+ var isUsage = true
2287
+ try {
2288
+ if (cObjNext && cObjNext.start <= node.start && cObjNext.end >= node.end) {
2289
+ cObj_ofCurrentLocation = cObjNext
2290
+ cObjNext = classObjects[++classObjects_currentIndex]
2291
+ }
2292
+ else if(cObj_ofCurrentLocation && !(cObj_ofCurrentLocation.start <= node.start && cObj_ofCurrentLocation.end >= node.end)){
2293
+ cObj_ofCurrentLocation = null
2294
+ }
2295
+
2296
+ for (let i = classObjects.length-1; i >= 0; --i) {
2297
+ let _cObj = classObjects[i];
2298
+ let _allProps = _cObj._allProps
2299
+ let knownObject = object._isValidThis || object._isSafeThis || object._isSafeClassRef
2300
+ if (!knownObject || knownObject === _cObj) {
2301
+ let property = _allProps.get(name)
2302
+ if (property) {
2303
+ let isRefOutsideOfTheClass = node.start < _cObj.start || node.start >= _cObj.end
2304
+ let isValidRef = !isRefOutsideOfTheClass || toAllowInliningOutsideOfTheClass && object._isSafeClassRef === _cObj
2305
+ if (!isValidRef && toInlineSafeLiteralsWherePossible && property._isPropertyValueAlwaysInlinable) {
2306
+ property._mustKeep = 1
2307
+ isValidRef = 1
2308
+ }
2309
+ if ( !isValidRef
2310
+ ) {
2311
+ if (removeCandidateProperty(name, _allProps)) return "end"
2312
+ continue
2313
+ }
2314
+ }
2315
+ }
2316
+
2317
+ }
2318
+
2319
+ if (!toAllowInliningOutsideOfTheClass && !cObj_ofCurrentLocation) return
2320
+ var cObj_ofProperty = cObj_ofCurrentLocation
2321
+ var objectIsSafeClassRef = object.type == "Identifier" && object._isSafeClassRef
2322
+ if (toAllowInliningOutsideOfTheClass && objectIsSafeClassRef && cObj_ofCurrentLocation !== objectIsSafeClassRef) {
2323
+ cObj_ofProperty = objectIsSafeClassRef
2324
+ }
2325
+
2326
+ if (cObj_ofProperty) {
2327
+ var _allProps = cObj_ofProperty._allProps
2328
+ var property = _allProps.get(name)
2329
+ if (!property) return
2330
+ var isRefOutsideOfTheClass = cObj_ofProperty !== cObj_ofCurrentLocation
2331
+ var isClass = cObj_ofProperty._isClass
2332
+ var objectIsThis = object.type == "ThisExpression" && object._isValidThis === cObj_ofProperty
2333
+ var objectIsSafeThisVariable = !objectIsThis && object.type == "Identifier" && object._isSafeThis === cObj_ofProperty
2334
+ var objectIsSafeClassRef = object.type == "Identifier" && object._isSafeClassRef === cObj_ofProperty
2335
+ var safeThis = objectIsThis || objectIsSafeThisVariable
2336
+ var isSafeClassObjectAccess = objectIsThis || objectIsSafeThisVariable || objectIsSafeClassRef
2337
+ var usageOnKnownProperty = isSafeClassObjectAccess && property
2338
+ var containingProp, containingPropIsStatic
2339
+ if(1){
2340
+ let propertyParent = isClass? cObj_ofProperty.body : cObj_ofProperty
2341
+ let parent = node
2342
+ while(parent && parent !== propertyParent) {
2343
+ containingProp = parent
2344
+ parent = parent.parent
2345
+ }
2346
+ if (DEBUG && safeThis && (!containingProp || !containingProp._name || containingProp._cObj !== cObj_ofProperty))
2347
+ throw "!containingProp"
2348
+ containingPropIsStatic = isClass? containingProp.static : true
2349
+ }
2350
+
2351
+ if (!isSafeClassObjectAccess) {
2352
+ if (toInlineSafeLiteralsWherePossible && property._isPropertyValueAlwaysInlinable) {
2353
+ property._mustKeep = 1
2354
+ }
2355
+ else if (removeCandidateProperty(name, _allProps)) return "end"
2356
+ return
2357
+ }
2358
+
2359
+
2360
+
2361
+ var propNode = property?.value
2362
+ var propertyIsStatic = isClass? property.static : true
2363
+ var thisIsInstance = isClass? !containingPropIsStatic : false
2364
+ var isInSameNode = propNode && node.start >= propNode.start && node.end <= propNode.end
2365
+ var isNoAccess = !(safeThis && thisIsInstance != propertyIsStatic)
2366
+ && !(propertyIsStatic && objectIsSafeClassRef)
2367
+ if (isNoAccess) {
2368
+ isUsage = false
2369
+ return
2370
+ }
2371
+
2372
+ if (propNode && isFunctionNode(propNode) && propNode.uses_this) {
2373
+ if (isRefOutsideOfTheClass || containingPropIsStatic != propertyIsStatic) {
2374
+ var incompatibleThis = true
2375
+ }
2376
+ }
2377
+
2378
+ node._name = name
2379
+ node._prop = property
2380
+ if (containingProp) {
2381
+ containingProp._inRefs ??= new Set
2382
+ containingProp._inRefs.add(node)
2383
+ }
2384
+
2385
+ var isPropertyChanged = isAssignedTo(node)
2386
+ var mustKeepProp = isInSameNode || object._mightBeUndef || isPropertyChanged || incompatibleThis
2387
+ if (!mustKeepProp) {
2388
+ property._refs ??= new Set
2389
+ property._refs.add(node)
2390
+ if (isRefOutsideOfTheClass) node._isOutsideOfTheClass = isRefOutsideOfTheClass
2391
+ }
2392
+ else {
2393
+ if (!isPropertyChanged && !incompatibleThis && toInlineSafeLiteralsWherePossible && property._isPropertyValueAlwaysInlinable) {
2394
+ property._mustKeep = 1
2395
+ }
2396
+ else if (removeCandidateProperty(name, _allProps)) return "end"
2397
+ return
2398
+ }
2399
+ }
2400
+ } finally {
2401
+ if (isUsage) {
2402
+ if (usageOnKnownProperty) {
2403
+ usageOnKnownProperty._uses = (usageOnKnownProperty._uses||0)+1
2404
+ }
2405
+ else {
2406
+ for (const {_allProps} of classObjects) {
2407
+ const property = _allProps.get(name)
2408
+ if(property) property._uses = (property._uses||0)+1
2409
+ }
2410
+ }
2411
+ }
2412
+ }
2413
+ })
2414
+ }
2415
+
2416
+ function isPropertyValueAlwaysInlinableLiteral(propNode) {
2417
+ return propNode.type == "Literal" && (
2418
+ typeof propNode.value == "string"
2419
+ || typeof propNode.value == "number"
2420
+ ) || propNode.type == "TemplateLiteral" && !propNode.expressions.length
2421
+ }
2422
+ function findUnusedProps() {
2423
+ let filteredNodes = new Set
2424
+ while (1) {
2425
+ let filtered
2426
+ for (let cObj of classObjects) {
2427
+ for (const [name, prop] of cObj._allProps) {
2428
+ let propValue = prop.value
2429
+ let noUses = !prop._uses
2430
+ if (noUses && !prop._unused && !filteredNodes.has(prop)) {
2431
+ prop._unused = 1
2432
+ filtered = 1
2433
+ filteredNodes.add(prop)
2434
+ if (propValue) {
2435
+ for (let cObj2 of classObjects) {
2436
+ for (const [name2, prop2] of cObj2._allProps) {
2437
+ if (prop2._unused) continue
2438
+ if (prop2._refs) {
2439
+ for (const refNode of prop2._refs) {
2440
+ if (refNode.start >= propValue.start && refNode.start < propValue.end) {
2441
+ prop2._refs.delete(refNode)
2442
+ prop2._uses = Math.max(0, prop2._uses-1)
2443
+ }
2444
+ }
2445
+ }
2446
+
2447
+ }
2448
+ }
2449
+ }
2450
+ }
2451
+ }
2452
+ }
2453
+ if (filtered) {
2454
+ continue
2455
+ }
2456
+ break
2457
+ }
2458
+ }
2459
+ function getPropsAndFilterUnsuitables(cObj, _allProps) {
2460
+
2461
+ function filterByCriteria() {
2462
+ _allProps.forEach((property, name)=>{
2463
+ var isClass = property._isInClass
2464
+ var numRefs = property._refs && property._refs.size||0
2465
+ var propNode = property.value
2466
+ if (propNode) {
2467
+ var isIdentifier = propNode.type == "Identifier"
2468
+ var isLiteral = propNode.type == "Literal" || propNode.type == "TemplateLiteral" && !propNode.expressions.length
2469
+ var isFunction = propNode.type == "FunctionExpression"
2470
+ && (property.method || property.kind == "method" || property.kind == "init")
2471
+ && property.value == propNode
2472
+
2473
+ var isArrowFunction = propNode.type == "ArrowFunctionExpression" && (property.kind == "init" || isClass && property.value == propNode)
2474
+ var isMethod = isFunction || isArrowFunction
2475
+ var usesThis = isMethod && propNode.uses_this
2476
+ }
2477
+ else {
2478
+ var isLiteral = true
2479
+ }
2480
+ if (usesThis && isArrowFunction) isMethod = false
2481
+ let refNodeParent = numRefs && [...property._refs][0].parent
2482
+ let refCallExpression = refNodeParent && refNodeParent.type === "CallExpression"? refNodeParent : null
2483
+ if (isMethod && !refCallExpression) isMethod = false
2484
+
2485
+
2486
+ var ok = numRefs == 1
2487
+ || isLiteral && numRefs > 1 && numRefs <= inlineLiteralValues_maxNumberOfTimes
2488
+ || isIdentifier
2489
+
2490
+ if (!ok) {
2491
+ _allProps.delete(name)
2492
+ return
2493
+ }
2494
+
2495
+ var isValidMethod
2496
+ var cannotBeInlined
2497
+ if (isMethod) {
2498
+ let functionNode = propNode
2499
+ if(functionNode.uses_arguments) return
2500
+ let funcInfo = getFunctionInfo(propNode, refCallExpression, variableNamesChangeable, src)
2501
+ if (funcInfo) {
2502
+ property._isMethod = true
2503
+ propNode._funcInfo = funcInfo
2504
+ isValidMethod = true
2505
+ }
2506
+ }
2507
+ else {
2508
+ let isConstantIdentifier
2509
+ if (isIdentifier) {
2510
+ let binding = scan.getBinding(propNode)
2511
+ isConstantIdentifier = IsBindingConstant(binding, 0, 1)
2512
+ if (toAllowInliningOutsideOfTheClass && numRefs) {
2513
+ if (!isConstantIdentifier) cannotBeInlined = true
2514
+ else {
2515
+ for (const ref of property._refs) {
2516
+ if (ref._isOutsideOfTheClass) {
2517
+ let objectNode = ref.object
2518
+ if ( objectNode._mightBeUndef
2519
+ || !binding._isConstantAtNode(ref)
2520
+ ) {
2521
+ property._refs.delete(ref)
2522
+ property._mustKeep = 1
2523
+ }
2524
+ }
2525
+ }
2526
+ }
2527
+ }
2528
+ }
2529
+
2530
+ property._isConstantValue = isLiteral || isIdentifier && isConstantIdentifier
2531
+ || (isFunction||isArrowFunction) && (property.type === "PropertyDefinition" || property.type === "Property" && !property.method && property.kind === "init")
2532
+ }
2533
+
2534
+ if (!isValidMethod && propNode && isFunctionNode(propNode) &&
2535
+ (refCallExpression || !(
2536
+ isFunction || isArrowFunction && !usesThis
2537
+ ))
2538
+ ){
2539
+ cannotBeInlined = true
2540
+ }
2541
+
2542
+ if (cannotBeInlined) {
2543
+ _allProps.delete(name)
2544
+ }
2545
+ })
2546
+ }
2547
+ function filterNonInlinables() {
2548
+ function getReferencedSpecialNonkeywordValues(property, propNode) {
2549
+ let refs = new Map
2550
+ walk(propNode, node=>{
2551
+ if (node.type === "Identifier") {
2552
+ let name = node.name
2553
+ if (property._outsideRefs.has(name)) {
2554
+ return
2555
+ }
2556
+ if(name === "Infinity" || name === "undefined" || name === "NaN"){
2557
+ let arr = refs.get(name)
2558
+ if (!arr) refs.set(name, arr = [])
2559
+ arr.push(node)
2560
+ }
2561
+ }
2562
+ })
2563
+ for (const [name, nodes] of refs) {
2564
+ property._outsideRefs.set(name, [null, nodes])
2565
+ }
2566
+ }
2567
+ function findOutsideRefs() {
2568
+ for (const [name, property] of _allProps) {
2569
+ var propNode = property.value
2570
+ if (!propNode) continue
2571
+ property._outsideRefs = new Map
2572
+ var aScope = objScope
2573
+ do {
2574
+ for (const [,b] of aScope.bindings) {
2575
+ var refs = getRefsInScope(b.references, propNode)
2576
+ if (refs) {
2577
+ property._outsideRefs.set(b.name, [b, refs])
2578
+ }
2579
+ }
2580
+ if (aScope.undeclaredBindings) {
2581
+ for (const [,b] of aScope.undeclaredBindings) {
2582
+ var refs = getRefsInScope(b.references, propNode)
2583
+ if (refs) {
2584
+ property._outsideRefs.set(b.name, [b, refs])
2585
+ }
2586
+ }
2587
+ }
2588
+ } while (aScope = aScope.parent);
2589
+
2590
+ getReferencedSpecialNonkeywordValues(property, propNode)
2591
+ }
2592
+ }
2593
+ function isInlinedToWithOutsideRefs_orUnfinished(property) {
2594
+ let isVar = !property._isMethod
2595
+ let propNode = property.value
2596
+ if (!propNode || property._isConstantValue) return
2597
+
2598
+ for (var cObj of classObjects) {
2599
+ var _allProps_ = cObj._allProps
2600
+ if (!toAllowInliningOutsideOfTheClass && _allProps_ !== _allProps) continue
2601
+ for (const [name, otherProperty] of _allProps_) {
2602
+ if(otherProperty == property) continue
2603
+ if(!otherProperty._outsideRefs) continue
2604
+ if(isVar && !otherProperty._outsideRefs.size) continue
2605
+ if (otherProperty._refs) {
2606
+ for (const refNode of otherProperty._refs) {
2607
+ if (refNode.start >= propNode.start && refNode.start < propNode.end) {
2608
+ let propNode2 = otherProperty.value
2609
+ if (property._refs && propNode2) {
2610
+ for (const refNode2 of property._refs) {
2611
+ if (refNode2.start >= propNode2.start && refNode2.start < propNode2.end) {
2612
+ _allProps.delete(property._name)
2613
+ _allProps_.delete(otherProperty._name)
2614
+ return
2615
+ }
2616
+ }
2617
+ }
2618
+ return true
2619
+ }
2620
+ }
2621
+ }
2622
+ }
2623
+ }
2624
+ }
2625
+ function findCoveringBindings() {
2626
+ for (const [name, property] of _allProps) {
2627
+ var outsideBindings = property._outsideRefs
2628
+ if (property._refs && outsideBindings) {
2629
+ for (const refNode of property._refs) {
2630
+ var refScope = scan.nearestScope(refNode, true)
2631
+ var commonScope = objScope
2632
+ var aScope = refScope
2633
+ var coveringBindings = []
2634
+ do {
2635
+ if(commonScope == aScope) break
2636
+ for (const [,b] of aScope.bindings) {
2637
+ if(outsideBindings.has(b.name)){
2638
+ coveringBindings.push(b)
2639
+ }
2640
+ }
2641
+ } while (aScope = aScope.parent);
2642
+ if(coveringBindings.length) {
2643
+ refNode._covOutRefs = coveringBindings
2644
+ }
2645
+ }
2646
+ }
2647
+ }
2648
+
2649
+ }
2650
+ function checkMethodArgumentNameCollisions() {
2651
+ var has
2652
+ for (const [name, property] of _allProps) {
2653
+ let propNode = property.value
2654
+ if(!propNode) continue
2655
+ if(!property._isMethod) continue
2656
+ var methodScope = scan.scope(propNode)
2657
+ for (const refNode of property._refs) {
2658
+ let refCallExpressionNode = [...property._refs][0].parent
2659
+ for (var i = 0; i < refCallExpressionNode.arguments.length; i++) {
2660
+ var arg = refCallExpressionNode.arguments[i]
2661
+ walk(arg, n=>{
2662
+ var binding = scan.binding(n)
2663
+ if (binding && methodScope.bindings.has(binding.name)) {
2664
+ has = true
2665
+ return "end"
2666
+ }
2667
+ })
2668
+ if (has) {
2669
+ property._hasArgNameCols = true
2670
+ }
2671
+ }
2672
+ }
2673
+ }
2674
+
2675
+ }
2676
+ checkMethodArgumentNameCollisions()
2677
+
2678
+ findOutsideRefs()
2679
+ _allProps.forEach((prop, name)=>{
2680
+ if (prop._outsideRefs && prop._outsideRefs.size && !prop._isMethod && !prop._isConstantValue && prop._outsideRefs.some(([n,[b, rs]]) => {
2681
+ return b && (!b.definition || !(b.definition.parent.type === 'VariableDeclarator' && b.definition.parent.parent.kind == "const"))
2682
+ })) {
2683
+ _allProps.delete(name)
2684
+ }
2685
+ })
2686
+
2687
+ if (toAllowInliningOutsideOfTheClass) {
2688
+ _allProps.forEach((prop, name)=>{
2689
+ if (prop._refs && prop._outsideRefs && prop._outsideRefs.size && prop._outsideRefs.some(([n,[b, refs]]) => {
2690
+ return !(!b || [...prop._refs].every(node => isBindingInScope(b, node)))
2691
+ })) {
2692
+ _allProps.delete(name)
2693
+ }
2694
+ })
2695
+ }
2696
+
2697
+
2698
+ findCoveringBindings()
2699
+ if(!variableNamesChangeable){
2700
+ _allProps.forEach((prop, name)=>{
2701
+ if (prop._refs.some(r=>(r._covOutRefs && r._covOutRefs.length))) {
2702
+ _allProps.delete(name)
2703
+ }
2704
+ })
2705
+ _allProps.forEach((prop, name)=>{
2706
+ if (prop._hasArgNameCols) {
2707
+ _allProps.delete(name)
2708
+ }
2709
+ })
2710
+ }
2711
+ else{
2712
+ _allProps.forEach((prop, name)=>{
2713
+ if(prop._refs) for (const refNode of prop._refs) {
2714
+ /** @type {[number]} */
2715
+ var coveringBindings = refNode._covOutRefs
2716
+ if(!(coveringBindings && coveringBindings.length)) continue
2717
+ var isAnyRefInWith = coveringBindings.some(b=>b.hasRefsInWith)
2718
+ if (!isAnyRefInWith) {
2719
+ coveringBindings.forEach((b) => {
2720
+ let name = gimmeSomethingUnique()
2721
+ b.references.forEach(r=>r._rn = name)
2722
+ })
2723
+ }
2724
+ else {
2725
+ _allProps.delete(name)
2726
+ }
2727
+ }
2728
+
2729
+ })
2730
+ _allProps.forEach((prop, name)=>{
2731
+ if (prop._hasArgNameCols) {
2732
+ var propNode = prop.value
2733
+ var methodScope = scan.scope(propNode)
2734
+ var isAnyRefInWith = methodScope.bindings.some(b=>b.hasRefsInWith)
2735
+ if (!isAnyRefInWith) {
2736
+ methodScope.bindings.forEach(b=>{
2737
+ let name = gimmeSomethingUnique()
2738
+ b.references.forEach(r=>r._rn = name)
2739
+ })
2740
+ }
2741
+ else {
2742
+ _allProps.delete(name)
2743
+ }
2744
+ }
2745
+ })
2746
+ }
2747
+
2748
+ _allProps.forEach((property, name)=>{
2749
+ if (isInlinedToWithOutsideRefs_orUnfinished(property)) {
2750
+ ++_num_Pending
2751
+ _allProps.delete(name)
2752
+ cObj._setComment_pending = 1
2753
+ }
2754
+ })
2755
+ }
2756
+
2757
+
2758
+ var objScope = getDirectParentScope(cObj)
2759
+ filterByCriteria()
2760
+ filterNonInlinables()
2761
+
2762
+ }
2763
+
2764
+
2765
+ function getTransformedSrc(){
2766
+ var result = astTransformMS({src, ast, prevSourceMap:inputMap, parentChain:1, leave(ctx){
2767
+ var {update, node, source} = ctx
2768
+ if(node._rn){
2769
+ if (node.parent.type === "Property" && node.parent.value === node && node.parent.key.start === node.start) {
2770
+ let propertySrc = source(node.parent.key)
2771
+ if (propertySrc !== node._rn) {
2772
+ update(`${propertySrc}:${node._rn}`, node)
2773
+ }
2774
+ }
2775
+ else{
2776
+ update(node._rn, node)
2777
+ }
2778
+
2779
+ }
2780
+ }})
2781
+ var ctx = result.ctx
2782
+
2783
+ function sortKey(...changeables) {
2784
+ var refDepth = 0
2785
+ var nDepth = changeables.reduce((p, c) => Math.max(getNodeDepth(c), p) , 0)
2786
+ var pos = changeables.reduce((p, c) => Math.min(c.start, p) , Infinity)
2787
+ return refDepth*281474976710656 + (281470681743360-nDepth*4294967296) + pos
2788
+ }
2789
+
2790
+ var all_edits = []
2791
+ for (const prop of allProps) {
2792
+ if (prop._refs) for (const refNode of prop._refs) {
2793
+ if (prop._isMethod) {
2794
+ all_edits.push([prop._name, "inl_F", sortKey(refNode, prop), refNode, prop])
2795
+
2796
+ } else {
2797
+ all_edits.push([prop._name, "inl_V", sortKey(refNode), refNode, prop])
2798
+
2799
+ }
2800
+ }
2801
+ }
2802
+ var sortF = (a,b)=>a[2] - b[2]
2803
+ all_edits.sort(sortF)
2804
+
2805
+ var removedProps = new Set
2806
+ for (let i = 0; i < all_edits.length; i++) {
2807
+ const edit = all_edits[i];
2808
+ let [name, editType,,refNode, prop] = edit
2809
+ let propNode = prop.value
2810
+ let _new = []
2811
+ let isInlined
2812
+
2813
+
2814
+ if (editType == "inl_F") {
2815
+ let refCallExpressionNode = refNode.parent
2816
+ editInlinedFunctionBody(propNode, propNode._funcInfo, refCallExpressionNode, ctx)
2817
+ let info = inlineFunctionBody(propNode, propNode._funcInfo, refCallExpressionNode, ctx)
2818
+ if(propNode._funcInfo.toPrependForExpression){
2819
+ _new.push(["prependFBE "+name, "prependFBE", sortKey(propNode._funcInfo.toPrependForExpression.targetStatement), [propNode._funcInfo.toPrependForExpression.targetStatement, refCallExpressionNode], prop])
2820
+ }
2821
+ else if(info.toPrependForAssignment){
2822
+ if(!all_edits.find(t => t[3] == info.toPrependForAssignment.varDeclarationNode)){
2823
+ _new.push(["prependFBA "+name, "prependFBA", sortKey(info.toPrependForAssignment.varDeclarationNode), info.toPrependForAssignment, prop, ])
2824
+ }
2825
+ }
2826
+ isInlined = true
2827
+ }
2828
+ else if (editType == "inl_V"){
2829
+ if (!propNode) {
2830
+ ctx.update("void(0)", refNode)
2831
+ }
2832
+ else if (prop._isPropertyValueAlwaysInlinable) {
2833
+ let isVariable = propNode.type == "Identifier"
2834
+ let isLiteral = !isVariable
2835
+ let valueStr = isVariable? propNode._rn || propNode.name
2836
+ : isLiteral? ctx.source(propNode) : ""
2837
+
2838
+ if (isLiteral && typeof propNode.value == "number" && refNode.parent.type == "MemberExpression" && refNode.parent.object == refNode) {
2839
+ valueStr = `(${valueStr})`
2840
+ }
2841
+ ctx.update(valueStr, refNode)
2842
+ }
2843
+ else {
2844
+ let toNotWrapInRoundParantheses = ToNotWrapExpressionInRoundParantheses(propNode, refNode)
2845
+ if(!toNotWrapInRoundParantheses){
2846
+ ctx.prepend("(", propNode)
2847
+ ctx.append(")", propNode)
2848
+ }
2849
+
2850
+ if (refNode.parent.type == "ExpressionStatement" && ctx.edit.slice(propNode.start, propNode.start+1) == "(" && !isPreceededBy(refNode.parent, n=>n.type == "EmptyStatement")
2851
+ ) {
2852
+ ctx.prepend(";", propNode)
2853
+ }
2854
+
2855
+ ctx.remove2(refNode.start, refNode.end)
2856
+ ctx.move2(propNode.start, propNode.end, refNode.start)
2857
+ }
2858
+
2859
+ isInlined = true
2860
+ }
2861
+ else if (editType == "prependFBA") {
2862
+ let { varDeclarationNode, varDeclaratorNode, returnVarName} = refNode
2863
+ let declaratorIndex = varDeclarationNode.declarations.indexOf(varDeclaratorNode)
2864
+ let inlinedFunc = varDeclaratorNode._inlinedFunc
2865
+ let refCallExpressionNode = propNode._funcInfo.refCallExpressionNode
2866
+ let inlineTarget = varDeclarationNode.start
2867
+ let isFirstDeclarator = declaratorIndex === 0
2868
+ let isLet = varDeclarationNode.kind === "let"
2869
+ if (!isFirstDeclarator) {
2870
+ let prevDeclarator = varDeclarationNode.declarations[declaratorIndex-1]
2871
+ inlineTarget = prevDeclarator.end
2872
+ ctx.remove2(inlineTarget, varDeclaratorNode.start)
2873
+ if (!isLet) {
2874
+ ctx.append(";", prevDeclarator)
2875
+ }
2876
+ }
2877
+ let prepend0 = (!isFirstDeclarator && isLet? "," : "let ")+returnVarName+";"
2878
+ if (inlinedFunc._prependNodes) {
2879
+ for (const node of inlinedFunc._prependNodes) {
2880
+ if (prepend0) {
2881
+ ctx.prepend(prepend0, node)
2882
+ prepend0 = null
2883
+ }
2884
+ ctx.move2(node.start, node.end, inlineTarget)
2885
+ }
2886
+ }
2887
+ else{
2888
+ ctx.prepend(prepend0, inlinedFunc)
2889
+ }
2890
+ ctx.move2(inlinedFunc.start, inlinedFunc.end, inlineTarget)
2891
+ ctx.remove2(refCallExpressionNode.start, refCallExpressionNode.end)
2892
+ ctx.prepend(returnVarName, refCallExpressionNode)
2893
+ if (!isFirstDeclarator) {
2894
+ ctx.prepend(varDeclarationNode.kind+" ", varDeclaratorNode)
2895
+ }
2896
+
2897
+ if (DEBUG) {
2898
+ ctx.edit.prependLeft(inlineTarget, "/* "+prop._name+" INLINED SATRT: *\/")
2899
+ ctx.edit.appendRight(inlineTarget, "/* "+prop._name+" INLINED END *\/")
2900
+ }
2901
+ isInlined = true
2902
+ }
2903
+ else if (editType == "prependFBE") {
2904
+ let [statement, refCallExpressionNode] = refNode
2905
+ let returnVarName = propNode._funcInfo.toPrependForExpression.returnVarName
2906
+ let inlinedFunc = statement._inlinedFunc
2907
+ let inlineTarget = statement.start
2908
+ let prepend0 = "let "+returnVarName+";"
2909
+ if (inlinedFunc._prependNodes) {
2910
+ for (const node of inlinedFunc._prependNodes) {
2911
+ if (prepend0) {
2912
+ ctx.prepend(prepend0, node)
2913
+ prepend0 = null
2914
+ }
2915
+ ctx.move2(node.start, node.end, inlineTarget)
2916
+ }
2917
+ }
2918
+ else{
2919
+ ctx.prepend(prepend0, inlinedFunc)
2920
+ }
2921
+ ctx.move2(inlinedFunc.start, inlinedFunc.end, inlineTarget)
2922
+ ctx.remove2(refCallExpressionNode.start, refCallExpressionNode.end)
2923
+ ctx.prepend(returnVarName, refCallExpressionNode)
2924
+
2925
+ if (DEBUG) {
2926
+ ctx.edit.prependLeft(inlineTarget, " /* "+prop._name+" INLINED SATRT: *\/ ")
2927
+ ctx.edit.appendRight(inlineTarget, " /* "+prop._name+" INLINED END *\/ ")
2928
+ }
2929
+ isInlined = true
2930
+ }
2931
+
2932
+ if (isInlined && !prop._mustKeep) {
2933
+ removedProps.add(prop)
2934
+ }
2935
+
2936
+ all_edits.splice(i, 1)
2937
+ --i
2938
+ if(_new.length) {
2939
+ all_edits.push(..._new)
2940
+ all_edits.sort(sortF)
2941
+ }
2942
+ }
2943
+
2944
+ var toRemoveProps = new Set( Array.from(removedProps).concat(unusedProps) )
2945
+ if (toRemoveProps.size) {
2946
+ for (const prop of toRemoveProps) {
2947
+ if (prop._isInClass) {
2948
+ ctx.remove2(prop.start, prop.end)
2949
+ }
2950
+ else {
2951
+ let i = prop._i, isFirst = i == 0
2952
+ let classNode = prop._cObj
2953
+ if (isFirst) {
2954
+ let end = prop.end
2955
+ if (i < classNode.properties.length-1) {
2956
+ let ic = findNextIndexInJs(",", src, comments, prop.end, classNode.properties[i+1].start)
2957
+ if (ic >= 0) {
2958
+ end = ic + 1
2959
+ }
2960
+ }
2961
+ ctx.remove2(prop.start, end)
2962
+ }
2963
+ else {
2964
+ let start = prop.start
2965
+ let pAbove = classNode.properties[i-1]
2966
+ let ic = findNextIndexInJs(",", src, comments, pAbove.end, prop.start)
2967
+ if (ic >= 0) {
2968
+ start = ic
2969
+ }
2970
+ ctx.remove2(start, prop.end)
2971
+ }
2972
+ }
2973
+ }
2974
+ }
2975
+
2976
+ for (const p of toRemoveProps) {
2977
+ if (p._comment_toNotInlineHere) {
2978
+ ctx.remove(p._comment_toNotInlineHere)
2979
+ }
2980
+ }
2981
+ for (const cObj of classObjects) {
2982
+ if (cObj._setComment_pending) {
2983
+ ctx.prepend(`/* ${CLASS_OBJECT_MARKER_PENDING} */`, cObj)
2984
+ }
2985
+ if (cObj._comment_pending) {
2986
+ ctx.remove(cObj._comment_pending)
2987
+ }
2988
+ }
2989
+
2990
+ var resultCode = result.toString()
2991
+ if (withSourceMap) {
2992
+ inputMap = result.map
2993
+ options.map = inputMap
2994
+ }
2995
+ return resultCode
2996
+ }
2997
+
2998
+ var _offset = 0
2999
+ var allProps = new Set
3000
+ var _allProps
3001
+ var unusedProps = []
3002
+ var classObjects = []
3003
+ while(1){
3004
+ var cObj = null
3005
+ findClassObject()
3006
+ if (!cObj) break
3007
+ _allProps = new Map
3008
+ cObj._allProps = _allProps
3009
+ var isClass = cObj._isClass
3010
+ findAllObjectProperties(cObj)
3011
+ findSafeClassBindings(cObj)
3012
+ _allProps.forEach((p, n) => (p.kind == "constructor" || p.kind == "get" || p.kind == "set") && _allProps.delete(n))
3013
+ if(!_allProps.size) continue
3014
+ classObjects.push(cObj)
3015
+ _offset += 3
3016
+ }
3017
+
3018
+ if (classObjects.length) {
3019
+ filterIfAccessedOnUnknownObjectsAndGetRefs()
3020
+ findUnusedProps()
3021
+
3022
+ for (var cObj of classObjects) {
3023
+ var _allProps = cObj._allProps
3024
+ unusedProps.push(..._allProps.values().filter((p)=>p._unused).toArray())
3025
+ _allProps.forEach((p, n) => p._unused && _allProps.delete(n))
3026
+ _allProps.forEach((p, n) =>{
3027
+ if (p._comment_toNotInlineHere && p._inRefs) {
3028
+ for (const ref of p._inRefs) {
3029
+ ref._prop._refs?.delete(ref)
3030
+ }
3031
+ }
3032
+ })
3033
+ }
3034
+ }
3035
+
3036
+
3037
+ for (var cObj of classObjects) {
3038
+ var _allProps = cObj._allProps
3039
+ try {
3040
+ getPropsAndFilterUnsuitables(cObj, _allProps)
3041
+
3042
+ if (_allProps.size) {
3043
+ for (const [k, v] of _allProps) allProps.add(v)
3044
+ }
3045
+ } catch (error) {
3046
+ if (DEBUG) {
3047
+ throw error
3048
+ }
3049
+ return
3050
+ }
3051
+ }
3052
+
3053
+ if(allProps.size || unusedProps.length){
3054
+ if (infoObject) {
3055
+ infoObject.inlinedProps ??= new Set
3056
+ allProps.forEach((p)=>infoObject.inlinedProps.add(p._cObj._name+"."+p._name))
3057
+ infoObject.removedUnusedProps ??= new Set
3058
+ unusedProps.forEach((p)=>infoObject.removedUnusedProps.add(p._cObj._name+"."+p._name))
3059
+ }
3060
+
3061
+ try {
3062
+ var transformed = getTransformedSrc()
3063
+ } catch (error) {
3064
+ if (DEBUG) {
3065
+ throw error
3066
+ }
3067
+ return
3068
+ }
3069
+ }
3070
+
3071
+
3072
+
3073
+ return transformed
3074
+ }
3075
+
3076
+ var _changes = 0
3077
+ var firstIteration = true
3078
+ while (1) {
3079
+ var _num_Pending = 0
3080
+ try {
3081
+ var src2 = _inline()
3082
+ } catch (err) {
3083
+ if (DEBUG) {
3084
+ throw err
3085
+ }
3086
+ else return
3087
+ }
3088
+ if(src2){
3089
+ src = src2
3090
+ ++_changes
3091
+ }
3092
+
3093
+ if (!_num_Pending) {
3094
+ break
3095
+ }
3096
+ firstIteration = false
3097
+ }
3098
+ if (infoObject) {
3099
+ infoObject.numInlinedProps = infoObject.inlinedProps?.size || 0
3100
+ infoObject.inlinedProps = [...infoObject.inlinedProps||""]
3101
+ infoObject.inlinedProps.sort()
3102
+ infoObject.removedUnusedProps = [...infoObject.removedUnusedProps||""]
3103
+ infoObject.removedUnusedProps.sort()
3104
+ }
3105
+ return _changes && src || null
3106
+ }
3107
+
3108
+
3109
+
3110
+
3111
+
3112
+ /**
3113
+ * @typedef {Object} Options
3114
+ * @property {any} [all=false] - shrink everything except: numbers, classObjects, functions
3115
+ * @property {any} [literals=true] - shrink string literals
3116
+ * @property {any} [properties=true] - shrink all property names
3117
+ * @property {any} [variables=true] - shrink all variables names
3118
+ * @property {any} [undeclared=true] - shrink all undeclared globals
3119
+ * @property {any} [values=true] - shrink null, undefined, Infinity
3120
+ * @property {any} [this=true] - shrink all "this."
3121
+ * @property {any} [numbers=false] - shrink numbers
3122
+ * @property {number} [numbers_minLength=3] - numbers shorter than this won't be shrunk
3123
+ * @property {number} [numbers_minOccurrences=5] - numbers won't be replaced with variables if they occur less often than this
3124
+ * @property {number} [numbers_maxNumberOfVariables=20] - make no more than this number of variables (for the most frequently occuring numbers)
3125
+ * @property {any} [classObjects=false] - to inline class-object properties and to remove unused properties (see below)
3126
+ * @property {any} [classObjects_classesNeedCommentMarker=false] -
3127
+ * @property {any} [classObjects_allowInliningOutsideOfTheClass=true] - whether to allow properties to be inlined outside of the class/object
3128
+ * @property {number} [classObjects_inlineConstantsMaxNumberOfTimes=3] - properties holding strings/numbers won't be inlined if they're used more often than this
3129
+ * @property {any} [functions=false] - turns non arrow functions into arrow functions wherever possible
3130
+ * @property {any} [allow0Gain=false] - whether to replace strings even if the character difference is 0
3131
+ * @property {"`"|'"'|"'"} [quote="`"] - the quote character to use (default: `)
3132
+ * @property {string[]} [globalsToNotShrink=[]] - undeclared globals to exclude
3133
+ * @property {number} [minPropertyNameLength=3] - property names shorter than this length won't be shrunk
3134
+ * @property {SourceMapOptions?} [sourceMap] - source map options if a source map is to be generated
3135
+ * @property {any} [debug=false] - prints some debug information if truthy
3136
+ * @property {any} [debugInfo] - will hold an info object about the result if debug is truthy
3137
+ * @property {any} [rootIsStrictMode=false] - whether the script is in strict mode from the start
3138
+ * @property {any} [findBestQuoteChar=false] - will try to find the best quote character for each string - not recommended.
3139
+ * @property {string} [declarationsPlaceholder="__JSSHRINK_DECLARATIONS_HERE__"] - custom comment marker used to insert the declarations at a specific location (default: __JSSHRINK_DECLARATIONS_HERE__)
3140
+ * @property {string} [declarationsPlaceholderConst="__JSSHRINK_CONSTANT_DECLARATIONS_HERE__"] - custom comment marker if constant and variable declarations must be separate (default: __JSSHRINK_CONSTANT_DECLARATIONS_HERE__)
3141
+ * @property {string} [declarationsPlaceholderVar="__JSSHRINK_VARIABLE_DECLARATIONS_HERE__"] - custom comment marker if constant and variable declarations must be separate (default: __JSSHRINK_VARIABLE_DECLARATIONS_HERE__)
3142
+ * @property {string} [declarationsConstStart="const "] - default: "const "
3143
+ * @property {string} [declarationsConstEnd=";"] - default: ";"
3144
+ * @property {string} [declarationsVarStart="let "] - default: "let "
3145
+ * @property {string} [declarationsVarEnd=";"] - default: ";"
3146
+ */
3147
+ /**
3148
+ * @typedef {Object} SourceMapOptions
3149
+ * @property {any} [generateSourceMapObject=false] - whether to generate a source map object; it is written to the property: "options.sourceMap.map"
3150
+ * @property {any} [generateSourceMapInline=false] - whether to generate and add an inline source map comment
3151
+ * @property {SourceMap?} [map] - a prior source map object; this key will hold the new source map object if generateSourceMapObject is truthy
3152
+ * @property {string?} [fileName] - filename of the output script file; this is only used to set the "file" property of the source map object
3153
+ * @property {string?} [sourceMapUrl] - url of the source map file; if specified then a '//# sourceMappingURL=' comment is added at the end
3154
+ */
3155
+ /**
3156
+ * @param {string} src - source code
3157
+ * @param {Options} options
3158
+ * @returns {string|false} - returns false if nothing was changed
3159
+ */
3160
+ function Shrink(src, options) {
3161
+ const _TO_SHRINK_ALL = options && "all" in options? options.all : false
3162
+ const _TO_SHRINK_ALL_STRING_LITERALS = _TO_SHRINK_ALL || (options && "literals" in options? options.literals : TO_SHRINK_ALL_STRING_LITERALS)
3163
+ const _TO_SHRINK_ALL_PROPERTY_NAMES = _TO_SHRINK_ALL || (options && "properties" in options? options.properties : TO_SHRINK_ALL_PROPERTY_NAMES)
3164
+ const _TO_SHRINK_ALL_UNDECLARED_GLOBALS = _TO_SHRINK_ALL || (options && "undeclared" in options? options.undeclared : TO_SHRINK_ALL_UNDECLARED_GLOBALS)
3165
+ const _TO_SHRINK_ALL_VARIABLES = _TO_SHRINK_ALL || (options && "variables" in options? options.variables : TO_SHRINK_ALL_VARIABLES_WHEN_POSSIBLE)
3166
+ const _TO_SHRINK_BUILTIN_VALUES = _TO_SHRINK_ALL || (options && "values" in options? options.values : TO_SHRINK_BUILTIN_VALUES)
3167
+ const _TO_SHRINK_ALL_THIS = _TO_SHRINK_ALL || (options && "this" in options? options.this : TO_SHRINK_ALL_THIS)
3168
+ const _MIN_PROPERTY_NAME_LENGTH = options && "minPropertyNameLength" in options? options.minPropertyNameLength : MIN_PROPERTY_NAME_LENGTH
3169
+ const _TO_REPLACE_ON_0_GAIN = options && "allow0Gain" in options? options.allow0Gain : TO_REPLACE_ON_0_GAIN
3170
+ const _CONST_DECLARATION_QUOTE_CHARACTER = options && "quote" in options && typeof options.quote == "string"? options.quote : CONST_DECLARATION_QUOTE_CHARACTER
3171
+ const _NOSHRINK_GLOBALS = options && "globalsToNotShrink" in options && typeof options.globalsToNotShrink == "object"? options.globalsToNotShrink : []
3172
+ const _TO_REPLACE_NUMBERS = options && "numbers" in options? options.numbers : false
3173
+ const _TO_REPLACE_NUMBERS_MINLENGTH = options && "numbers_minLength" in options? Math.max(2, Number(options.numbers_minLength)||3) : 3
3174
+ const _TO_REPLACE_NUMBERS_MINOCCURRENCES = options && "numbers_minOccurrences" in options? Math.max(2, Number(options.numbers_minOccurrences)||5) : 5
3175
+ const _TO_REPLACE_NUMBERS_MAXNUMBERS = options && "numbers_maxNumberOfVariables" in options? Math.max(1, Number(options.numbers_maxNumberOfVariables)||20) : 20
3176
+ const _TO_FORCE_ARROW_FUNCTIONS = options && "functions" in options? options.functions : false
3177
+ const _TO_INLINE_CLASS_OBJECT_PROPERTIES_AND_REMOVE_UNUSED = (options && "classObjects" in options? options.classObjects : TO_INLINE_CLASS_OBJECT_PROPERTIES_AND_REMOVE_UNUSED)
3178
+ const IS_STRICT_MODE = "rootIsStrictMode" in options? options.rootIsStrictMode : false
3179
+ const _DEBUG = options && "debug" in options? options.debug : DEBUG
3180
+ // other options
3181
+ const _DECLARATIONS_MARKER = options && "declarationsPlaceholder" in options && typeof options.declarationsPlaceholder == "string"? options.declarationsPlaceholder : DECLARATIONS_HERE_MARKER
3182
+ const _DECLARATIONS_MARKER_CONST = options && "declarationsPlaceholderConst" in options && typeof options.declarationsPlaceholderConst == "string"? options.declarationsPlaceholderConst : DECLARATIONS_HERE_MARKER_CONST
3183
+ const _DECLARATIONS_MARKER_VAR = options && "declarationsPlaceholderVar" in options && typeof options.declarationsPlaceholderVar == "string"? options.declarationsPlaceholderVar : DECLARATIONS_HERE_MARKER_VAR
3184
+ let _CONST_DECLARATIONS_START = options && "declarationsConstStart" in options && typeof options.declarationsConstStart == "string"? options.declarationsConstStart : "const "
3185
+ const _CONST_DECLARATIONS_END = options && "declarationsConstEnd" in options && typeof options.declarationsConstEnd == "string"? options.declarationsConstEnd : ";"
3186
+ let _VAR_DECLARATIONS_START = options && "declarationsVarStart" in options && typeof options.declarationsVarStart == "string"? options.declarationsVarStart : "let "
3187
+ const _VAR_DECLARATIONS_END = options && "declarationsVarEnd" in options && typeof options.declarationsVarEnd == "string"? options.declarationsVarEnd : ";"
3188
+ if (isJsAlphanum(_CONST_DECLARATIONS_START[_CONST_DECLARATIONS_START.length-1])) _CONST_DECLARATIONS_START += " " // if "const" then it needs a whitespace: "const "
3189
+ if (isJsAlphanum(_VAR_DECLARATIONS_START[_VAR_DECLARATIONS_START.length-1])) _VAR_DECLARATIONS_START += " " // if "let" then it needs a whitespace: "let "
3190
+ const _TO_FIND_BEST_QUOTE = options && "findBestQuoteChar" in options? options.findBestQuoteChar : false
3191
+
3192
+ // source map options
3193
+ var src_start_Length = src.length
3194
+ var srcInit = src
3195
+ var inputMap, inputMapInit
3196
+ const _TO_GENERATE_SOURCEMAP_OBJECT = options?.sourceMap?.generateSourceMapObject
3197
+ const _TO_GENERATE_SOURCEMAP_INLINE = options?.sourceMap?.generateSourceMapInline
3198
+ const _TO_GENERATE_SOURCEMAP = _TO_GENERATE_SOURCEMAP_OBJECT || _TO_GENERATE_SOURCEMAP_INLINE
3199
+ const _INPUT_SOURCEMAP = options?.sourceMap?.map
3200
+ const _SOURCEMAP_FILENAME = typeof options?.sourceMap?.fileName === "string" && options.sourceMap.fileName
3201
+ const _SOURCEMAP_URL = typeof options?.sourceMap?.sourceMapUrl === "string" && options.sourceMap.sourceMapUrl
3202
+ if (_TO_GENERATE_SOURCEMAP) {
3203
+ inputMap = _INPUT_SOURCEMAP || convertSourceMap.fromSource(src)?.toObject();
3204
+ inputMapInit = inputMap
3205
+ src = convertSourceMap.removeComments(src);
3206
+ }
3207
+
3208
+ // inlining ----------------------------------------------------------------------------------------------------------------------------------------------------------
3209
+ var numInlinedItems = 0
3210
+ var numInlinedFunctions = 0
3211
+ var numInlinedVariables = 0
3212
+ // ...
3213
+
3214
+ // class object ----------------------------------------------------------------------------------------------------------------------------------------------------------
3215
+ var numInlinedClassPrperties = options && "inlinedClassPropsPre" in options && Number.isInteger(options.inlinedClassPropsPre)? options.inlinedClassPropsPre : 0
3216
+ var allInlinedClassPrperties = options && "inlinedClassPropsAllPre" in options && options.inlinedClassPropsAllPre instanceof Array? options.inlinedClassPropsAllPre : []
3217
+ var removedUnusedClassProperties = []
3218
+ if (_TO_INLINE_CLASS_OBJECT_PROPERTIES_AND_REMOVE_UNUSED) {
3219
+ let _classObjects_classesNeedCommentMarker = false
3220
+ let _classObjects_allowInliningOutsideOfTheClass = true
3221
+ let _classObjects_inlineConstantsMaxNumberOfTimes = 3
3222
+ if (options) {
3223
+ if ("classObjects_classesNeedCommentMarker" in options) _classObjects_allowInliningOutsideOfTheClass = options.classObjects_classesNeedCommentMarker
3224
+ if ("classObjects_allowInliningOutsideOfTheClass" in options) _classObjects_allowInliningOutsideOfTheClass = options.classObjects_allowInliningOutsideOfTheClass
3225
+ if ("classObjects_inlineConstantsMaxNumberOfTimes" in options) _classObjects_inlineConstantsMaxNumberOfTimes = options.classObjects_inlineConstantsMaxNumberOfTimes
3226
+ }
3227
+
3228
+ let info = {}
3229
+ let options_ = {
3230
+ variableNamesChangeable: _TO_SHRINK_ALL_VARIABLES,
3231
+ rootIsStrictMode: IS_STRICT_MODE,
3232
+ infoObject: info,
3233
+ withSourceMap: _TO_GENERATE_SOURCEMAP,
3234
+ classesNeedCommentMarker: _classObjects_classesNeedCommentMarker,
3235
+ allowInliningOutsideOfTheClass: _classObjects_allowInliningOutsideOfTheClass,
3236
+ inlineConstantsMaxNumberOfTimes: _classObjects_inlineConstantsMaxNumberOfTimes,
3237
+ map: inputMap,
3238
+ }
3239
+ let src2 = inlineClassObjectProperties(src, options_)
3240
+ if (src2) {
3241
+ src = src2
3242
+ numInlinedClassPrperties += info.numInlinedProps
3243
+ if(info.inlinedProps instanceof Array) allInlinedClassPrperties = allInlinedClassPrperties.concat(info.inlinedProps)
3244
+ numInlinedItems += numInlinedClassPrperties
3245
+ removedUnusedClassProperties = info.removedUnusedProps
3246
+ if (_TO_GENERATE_SOURCEMAP) inputMap = options_.map
3247
+ }
3248
+ }
3249
+
3250
+ // Shrinking "this" ----------------------------------------------------------------------------------------------------------------------------------------------------------
3251
+ var estimated_this_Gain = 0, numThisReplaced = 0
3252
+ if (_TO_SHRINK_ALL_THIS && _TO_SHRINK_ALL_VARIABLES) {
3253
+ function shrinkAllThis() {
3254
+ var allThis = []
3255
+ function getAllThisInThisObject(rootNode) {
3256
+ var tuple
3257
+ walk(rootNode, n=>{
3258
+ if(n.type == "ThisExpression"){
3259
+ if(!tuple){
3260
+ tuple = [rootNode, []]
3261
+ allThis.push(tuple)
3262
+ }
3263
+ tuple[1].push(n)
3264
+ }
3265
+ if (n !== rootNode && (n.type === 'FunctionDeclaration' || n.type === 'FunctionExpression')) {
3266
+ getAllThisInThisObject(n)
3267
+ return "jump"
3268
+ }
3269
+ })
3270
+
3271
+ }
3272
+ var ast = acorn.parse(src, {
3273
+ ecmaVersion: "latest",
3274
+ })
3275
+ getAllThisInThisObject(ast)
3276
+ if(!allThis.length) return
3277
+ var changes = 0
3278
+ var numThisReplaced = 0
3279
+ var estimatedSumGain = 0
3280
+ var transformed = astTransformMS({src, ast, prevSourceMap:inputMap })
3281
+ var ctx = transformed.ctx
3282
+ allThis.forEach(t => {
3283
+ var len = t[1].length
3284
+ var gain = len*4 - (len*2+12)
3285
+ var gainOk = _TO_REPLACE_ON_0_GAIN? gain >= 0 : gain > 0
3286
+ if(!gainOk) return
3287
+ var root = t[0]
3288
+ if(root.body && !(root.body instanceof Array)) root = root.body
3289
+ if(!(root.body && root.body instanceof Array && root.body.length)) throw "root body expected"
3290
+ var id = gimmeSomethingUnique()
3291
+ if(DEBUG) id = "this_"+changes+"_"
3292
+ t[1].forEach(n => ctx.update(id, n))
3293
+ ctx.prepend("var "+id+"=this;"+(DEBUG?"\n":""), root.body[0])
3294
+ ++changes
3295
+ numThisReplaced += t[1].length
3296
+ estimatedSumGain += gain
3297
+ })
3298
+ if(!changes) return
3299
+ var src2 = transformed.toString()
3300
+ src = src2
3301
+ if (_TO_GENERATE_SOURCEMAP){
3302
+ inputMap = transformed.map
3303
+ }
3304
+ return [estimatedSumGain, numThisReplaced]
3305
+ }
3306
+ estimated_this_Gain = shrinkAllThis() || 0
3307
+ if(estimated_this_Gain) [estimated_this_Gain, numThisReplaced] = estimated_this_Gain
3308
+ }
3309
+
3310
+
3311
+ // Shrinking Literals ----------------------------------------------------------------------------------------------------------------------------------------------------------
3312
+ /** @type {acorn.Comment[]} */
3313
+ var comments = []
3314
+ var ast = acorn.parse(src, {
3315
+ ecmaVersion: "latest",
3316
+ onComment: comments,
3317
+ // sourceType: "module",
3318
+ })
3319
+ scan.crawl(ast, {isStrictMode:IS_STRICT_MODE})
3320
+ var rootScope = scan.scope(ast)
3321
+
3322
+
3323
+ var hasExcludes = src.includes(EXCLUDE_FUNCTION_FROM_SHRINK_MARKER)
3324
+ if (hasExcludes) {
3325
+ var excludeRanges = getExcludeRanges(src, ast, rootScope)
3326
+ var excludeNodes = excludeRanges?.[1]
3327
+ if (!excludeNodes?.size) {
3328
+ excludeNodes = null
3329
+ }
3330
+ }
3331
+
3332
+ {
3333
+ let _declarationsMarker = _DECLARATIONS_MARKER.trim()
3334
+ let _declarationsMarkerConst = _DECLARATIONS_MARKER_CONST.trim()
3335
+ let _declarationsMarkerVar = _DECLARATIONS_MARKER_VAR.trim()
3336
+ var declarationsMarker = _declarationsMarker && comments.find(c => c.value.trim() === _declarationsMarker)
3337
+ var declarationsMarkerConst = _declarationsMarkerConst && comments.find(c => c.value.trim() === _declarationsMarkerConst) || declarationsMarker
3338
+ var declarationsMarkerVar = _declarationsMarkerVar && comments.find(c => c.value.trim() === _declarationsMarkerVar) || declarationsMarker || declarationsMarkerConst
3339
+ declarationsMarkerConst ||= declarationsMarkerVar
3340
+ declarationsMarker = declarationsMarkerConst
3341
+ }
3342
+
3343
+
3344
+ sortScopeBindingsByPositionInCode(rootScope)
3345
+
3346
+
3347
+ var [stringLiterals, numberLiterals] = findAllLiterals(
3348
+ ast, comments, _TO_SHRINK_ALL_PROPERTY_NAMES, _MIN_PROPERTY_NAME_LENGTH, excludeNodes, src,
3349
+ _TO_REPLACE_NUMBERS && _TO_REPLACE_NUMBERS_MINLENGTH
3350
+ )
3351
+ /** @type {[stringName:string, [nodes: Node[]], createdVariableName?:string, reservedNames?:Set<string>, maxNewIdentifierLength:number, gain:number][]} */
3352
+ var all_string_literals = [...stringLiterals]
3353
+ .filter(([str, tuple]) => {
3354
+ var nodes = tuple[0]
3355
+ var minNumOccurrences = str.length == 1? 4 : str.length == 2? 3 : 2
3356
+ return nodes.length >= minNumOccurrences
3357
+ })
3358
+
3359
+
3360
+ // get maximum length of new identifier for each string with positive net character gain -----------------------------------------------------------------------------
3361
+ all_string_literals.forEach(t => t[4] = getMaxIdentifierLengthForPropsLiterals(t[0], _TO_REPLACE_ON_0_GAIN, t[1][1], t[1][2], t[1][3], t[1][4], t[1][5]))
3362
+ // filter out those with no positive gain
3363
+ all_string_literals = all_string_literals.filter(t => t[4] > 0)
3364
+
3365
+
3366
+
3367
+ /** @typedef {[editType:string, node:Node, string:string, index:number, arg:any]} NodeEdit */
3368
+ /** @type {NodeEdit[]} */
3369
+ var furtherEdits = []
3370
+
3371
+ // get available identifiers for each literal -----------------------------------------------------------------------------
3372
+ var /** @type {[itemType:"s", numOccurrences:number, object:typeof all_string_literals[0]][]} */ items_literals=[],
3373
+ /** @type {[itemType:"b", numOccurrences:number, Node[], maxIdentifierLength:number, name:string][]} */ items_builtins=[],
3374
+ /** @type {[itemType:"u", numOccurrences:number, Binding, maxIdentifierLength:number][]} */ items_undeclared=[],
3375
+ /** @type {[itemType:"n", numOccurrences:number, object:typeof numberLiterals[0]][]} */ items_numbers=[]
3376
+ if(_TO_SHRINK_ALL_STRING_LITERALS) items_literals = all_string_literals.map(t => ["s", t[1][0].length, t])
3377
+ if(_TO_SHRINK_ALL_UNDECLARED_GLOBALS){
3378
+ var undeclaredNotShrunk = {becauseGain:[], becauseUnsafe:[], becauseUserBlacklisted:[], }
3379
+ // for undeclared globals
3380
+ let all_undeclared_bindings = [...rootScope.undeclaredBindings].map(x=>x[1])
3381
+ let items_undeclared_ = all_undeclared_bindings
3382
+ // at least 2 occurrences and at least 3 characters long
3383
+ .filter(b => b.references.size > 1 && b.name.length >= 3 || void(undeclaredNotShrunk.becauseGain.push(b.name)))
3384
+ .filter(b => !isBindingExistenceChecked(b) || void(undeclaredNotShrunk.becauseGain.push(b.name)))
3385
+ .filter(b => !b.hasRefsInWith || void(undeclaredNotShrunk.becauseUnsafe.push(b.name)))
3386
+
3387
+ if (_NOSHRINK_GLOBALS.length) {
3388
+ let blacklisted = new Set(_NOSHRINK_GLOBALS)
3389
+ items_undeclared_ = items_undeclared_.filter(b => !blacklisted.has(b.name))
3390
+ undeclaredNotShrunk.becauseUserBlacklisted.push(..._NOSHRINK_GLOBALS)
3391
+ }
3392
+ if (excludeNodes) {
3393
+ // ignore excluded areas
3394
+ // - Currently, it is not checked whether the global is changed in these excluded functions.
3395
+ // - If these excluded functions use the same global in the same script then the globals may get out of sync with the short variables
3396
+ // But the only reason for excluded areas is so that the functions can be used for script injections or for worker code which are safe cases.
3397
+ // The user can still add those globals to "options.globalsToNotShrink" to avoid sync problems in rare cases.
3398
+ items_undeclared_ = items_undeclared_.filter(b => !removeRefsInExcludedAreas_areAllRefsExcluded(b, excludeNodes) || void(undeclaredNotShrunk.becauseGain.push(b.name)))
3399
+ }
3400
+
3401
+ loop_items_undeclared: for (let i = items_undeclared_.length-1; i >= 0; --i) {
3402
+ let b = items_undeclared_[i];
3403
+ let updateCost = 0
3404
+ let estimatedGain = (b.name.length - 2) * b.references.size
3405
+ let furtherEdits = []
3406
+ let canBeConstant = true
3407
+ for (const ref of b.references) {
3408
+ let node = isAssignmentTarget(ref)
3409
+ if (node) {
3410
+ canBeConstant = false
3411
+ if (node.type === 'AssignmentExpression') {
3412
+ if (node.left.type === 'ArrayPattern' || node.left.type === 'ObjectPattern') {
3413
+ let parent = node.parent
3414
+ if ( parent.type === 'ExpressionStatement'
3415
+ || parent.type === 'SequenceExpression' && (
3416
+ parent.parent.type === 'ExpressionStatement'
3417
+ || parent.expressions.lastIndexOf(node) < parent.expressions.length-1
3418
+ )) {
3419
+ let appendStr = ","+b.name+"=%ID"
3420
+ let appendIndex = node.end
3421
+ furtherEdits.push(["append", parent, appendStr, appendIndex])
3422
+ updateCost += b.name.length+2+2 // assume ID length of 2
3423
+ continue
3424
+ }
3425
+
3426
+ }
3427
+ else if (node.left.type === 'Identifier') {
3428
+ furtherEdits.push(["prepend", node, b.name+"="])
3429
+ updateCost += b.name.length+1
3430
+ continue
3431
+ }
3432
+ items_undeclared_.splice(i,1)
3433
+ continue loop_items_undeclared
3434
+ }
3435
+ else if (node.type === 'UpdateExpression') {
3436
+ let parent = node.parent
3437
+ if ( parent.type === 'ExpressionStatement'
3438
+ || parent.type === 'SequenceExpression' && (
3439
+ parent.parent.type === 'ExpressionStatement'
3440
+ || parent.expressions.lastIndexOf(node) < parent.expressions.length-1
3441
+ )) {
3442
+ if (node.prefix) {
3443
+ furtherEdits.push(["prepend", node, b.name+"="])
3444
+ updateCost += b.name.length+1
3445
+ }
3446
+ else {
3447
+ furtherEdits.push(["prepend", node, b.name+node.operator+","])
3448
+ updateCost += b.name.length+node.operator.length+1
3449
+ }
3450
+ }
3451
+ else{
3452
+ if (node.prefix) {
3453
+ furtherEdits.push(["prepend", node, "("+b.name+"="])
3454
+ furtherEdits.push(["append", node, ")"])
3455
+ updateCost += b.name.length+3
3456
+ }
3457
+ else {
3458
+ furtherEdits.push(["prepend", node, "("+b.name+node.operator+","])
3459
+ furtherEdits.push(["append", node, ")"])
3460
+ updateCost += b.name.length+node.operator.length+3
3461
+ }
3462
+ }
3463
+
3464
+ }
3465
+ }
3466
+ }
3467
+ b.canBeConstant = canBeConstant
3468
+ if (furtherEdits.length) {
3469
+ if (estimatedGain - updateCost < 0) {
3470
+ items_undeclared_.splice(i,1)
3471
+ undeclaredNotShrunk.becauseGain.push(items_undeclared_[i].name)
3472
+ }
3473
+ else{
3474
+ b.furtherEdits = furtherEdits
3475
+ b.updateCost = updateCost
3476
+ }
3477
+ }
3478
+
3479
+ }
3480
+
3481
+ items_undeclared = items_undeclared_.map(binding => {
3482
+ var maxIdentifierLength = maxIdentifierLengthFor(binding.references.size, binding.name.length, _TO_REPLACE_ON_0_GAIN, binding.updateCost||0)
3483
+ return ["u", binding.references.size, binding, maxIdentifierLength]
3484
+ })
3485
+ }
3486
+ if (_TO_SHRINK_BUILTIN_VALUES) {
3487
+ items_builtins = [...findBuiltinValues(ast, excludeNodes)]
3488
+ .map(([name, nodes]) => {
3489
+ var maxIdentifierLength = maxIdentifierLengthFor(nodes.length, name.length, _TO_REPLACE_ON_0_GAIN)
3490
+ return ["b", nodes.length, nodes, maxIdentifierLength, name]
3491
+ })
3492
+ }
3493
+ if (_TO_REPLACE_NUMBERS) {
3494
+ numberLiterals = numberLiterals.filter((tuple) => {
3495
+ const minGain = 10
3496
+ var decl_cost = tuple[1].length + 2 + 2
3497
+ var gain = tuple[6] - 2 * tuple[0].length
3498
+ return gain - decl_cost >= minGain && tuple[0].length >= _TO_REPLACE_NUMBERS_MINOCCURRENCES
3499
+ })
3500
+ numberLiterals.sort((a,b)=>b[2]-a[2])
3501
+ if (numberLiterals.length > _TO_REPLACE_NUMBERS_MAXNUMBERS ) {
3502
+ numberLiterals.length = _TO_REPLACE_NUMBERS_MAXNUMBERS
3503
+ }
3504
+ items_numbers = numberLiterals.map((t) => {
3505
+ return ["n", t[0].length, t]
3506
+ })
3507
+ }
3508
+
3509
+ var all_variables_Gain = 0
3510
+ var iife_wrapper_node = getIIFEBodyBlockNode(ast)
3511
+ var top_scope = iife_wrapper_node && scan.nearestScope(iife_wrapper_node) || scan.scope(ast)
3512
+
3513
+ while(true){
3514
+ var debug_insufficientGainFor = []
3515
+ var undeclared_globals_to_replace = []
3516
+ var undeclared_globals_to_replace_variable = [], undeclared_globals_to_replace_constant = []
3517
+ var builtin_values_to_replace = []
3518
+
3519
+ let all_items = [...items_literals, ...items_undeclared, ...items_builtins, ...items_numbers]
3520
+ all_items.sort(([, aLength], [, bLength]) => bLength - aLength)
3521
+
3522
+ if (_TO_SHRINK_ALL_VARIABLES) {
3523
+ /** @type {[veriableName:string, numOccurrences:number, occurrences:Set<Node>|Binding, maxNameLength:number, name:string, keyOnNode:string][]} */
3524
+ let items = all_items.map(item => {
3525
+ if(item[0] == "s"){
3526
+ return [null, item[1], item[2][1][0], item[2][4]]
3527
+ }
3528
+ else if(item[0] == "u"){
3529
+ return [null, item[1], item[2].references, item[3],]
3530
+ }
3531
+ else if(item[0] == "b"){
3532
+ return [null, item[1], item[2], item[3], item[4]]
3533
+ }
3534
+ else if(item[0] == "n"){
3535
+ return [null, item[1], item[2][0], item[2][4], ]
3536
+ }
3537
+ })
3538
+ var topLevelScopeNode = iife_wrapper_node && iife_wrapper_node.parent || ast
3539
+ all_variables_Gain = obtainNewVariableIdentifiers(topLevelScopeNode, items)
3540
+ for (var i = 0; i < items.length; i++) {
3541
+ var conv = items[i];
3542
+ var orig = all_items[i];
3543
+ if (orig[0] == "s") {
3544
+ orig[2][2] = conv[0]
3545
+ }
3546
+ else if(orig[0] == "u"){
3547
+ if (conv[0]) {
3548
+ orig[2].id = conv[0]
3549
+ undeclared_globals_to_replace.push(orig[2])
3550
+ }
3551
+ }
3552
+ else if(orig[0] == "b"){
3553
+ if (conv[0]) {
3554
+ builtin_values_to_replace.push([orig[4], conv[0], orig[2]])
3555
+ }
3556
+ }
3557
+ if (orig[0] == "n") {
3558
+ orig[2][5] = conv[0]
3559
+ }
3560
+ }
3561
+
3562
+ }
3563
+ else{
3564
+ let all_topLevel_variable_names = getAllScopeVariableNames(top_scope)
3565
+ var all_undeclared_set = new Set([...rootScope.undeclaredBindings].map(x=>x[0]))
3566
+ let availableSkippedIdentifiers = new Set
3567
+ let nameCounter = -1
3568
+
3569
+ literalsLoop:
3570
+ for (const item of all_items) {
3571
+ let isLiterals, isGlobals, isBuiltins, isNumbers
3572
+ if (item[0] == "s") {
3573
+ isLiterals = 1
3574
+ var tuple = item[2]
3575
+ var occurrence_nodes = tuple[1][0]
3576
+ var maxNewIdentifierLength = tuple[4]
3577
+ }
3578
+ else if (item[0] == "u"){
3579
+ isGlobals = 1
3580
+ var binding = item[2]
3581
+ var occurrence_nodes = binding.references
3582
+ var maxNewIdentifierLength = item[3]
3583
+ }
3584
+ else if (item[0] == "b"){
3585
+ isBuiltins = 1
3586
+ var name = item[4]
3587
+ var occurrence_nodes = item[2]
3588
+ var maxNewIdentifierLength = item[3]
3589
+ }
3590
+ else if (item[0] == "n"){
3591
+ isNumbers = 1
3592
+ var tupleN = item[2]
3593
+ var name = tupleN[3]
3594
+ var occurrence_nodes = tupleN[0]
3595
+ var maxNewIdentifierLength = tupleN[4]
3596
+ }
3597
+ else {
3598
+ throw "unknown item"
3599
+ }
3600
+
3601
+ let setaname = (aname)=>{
3602
+ if (isLiterals) {
3603
+ tuple[2] = aname
3604
+ }
3605
+ else if(isGlobals){
3606
+ binding.id = aname
3607
+ undeclared_globals_to_replace.push(binding)
3608
+ }
3609
+ else if(isBuiltins){
3610
+ builtin_values_to_replace.push([name, aname, occurrence_nodes])
3611
+ }
3612
+ else if(isNumbers){
3613
+ tupleN[5] = aname
3614
+ }
3615
+ }
3616
+ var takenNames = getAllTakenNamesFor(occurrence_nodes)
3617
+ for (const aname of availableSkippedIdentifiers) {
3618
+ if(takenNames.has(aname)){
3619
+ continue
3620
+ }
3621
+ if(aname.length <= maxNewIdentifierLength){
3622
+ setaname(aname)
3623
+ availableSkippedIdentifiers.delete(aname)
3624
+ continue literalsLoop
3625
+ }
3626
+ }
3627
+
3628
+ while (true) {
3629
+ let aname = base54(++nameCounter)
3630
+ if(keywords.has(aname)) continue
3631
+ if (all_undeclared_set.has(aname)) {
3632
+ continue
3633
+ }
3634
+ if(all_topLevel_variable_names.has(aname)){
3635
+ continue
3636
+ }
3637
+ if(takenNames.has(aname)){
3638
+ availableSkippedIdentifiers.add(aname)
3639
+ continue
3640
+ }
3641
+ if(aname.length <= maxNewIdentifierLength){
3642
+ availableSkippedIdentifiers.delete(aname)
3643
+ setaname(aname)
3644
+ continue literalsLoop
3645
+ }
3646
+ else{
3647
+ if (isLiterals) {
3648
+ tuple[2] = null
3649
+ _DEBUG && debug_insufficientGainFor.push({
3650
+ literal: tuple[0],
3651
+ maxIdentifierLength: maxNewIdentifierLength,
3652
+ availableIdentifierLength: aname.length,
3653
+ })
3654
+ }
3655
+ continue literalsLoop
3656
+ }
3657
+ }
3658
+ }
3659
+ }
3660
+
3661
+
3662
+ // variable undeclared globals must be in a separate "let ;" statement because they are not constant
3663
+ // if the gain is not enough for the "let" statement then omit the globals and recreate the variables without the globals competing for them
3664
+ var undeclared_globals_Gain = 0
3665
+ var undeclared_globals_variable_Gain = 0
3666
+ var undeclared_globals_constant_Gain = 0
3667
+ var sumGain_let = 0
3668
+ if (_TO_SHRINK_ALL_UNDECLARED_GLOBALS && undeclared_globals_to_replace.length) {
3669
+ var reduceGainFunctionUndeclaredGlobals = (sum, b) =>{
3670
+ var decl_cost = b.name.length + b.id.length + 2
3671
+ var update_cost = b.updateCost||0
3672
+ var gain = (b.name.length - b.id.length) * b.references.size
3673
+ return sum + gain - decl_cost - update_cost
3674
+ }
3675
+ undeclared_globals_to_replace.forEach((binding, i) => {
3676
+ if (!binding.canBeConstant) {
3677
+ undeclared_globals_to_replace_variable.push(binding)
3678
+ }
3679
+ else {
3680
+ undeclared_globals_to_replace_constant.push(binding)
3681
+ }
3682
+ })
3683
+ undeclared_globals_variable_Gain = undeclared_globals_to_replace_variable.reduce(reduceGainFunctionUndeclaredGlobals, 0)
3684
+ undeclared_globals_constant_Gain = undeclared_globals_to_replace_constant.reduce(reduceGainFunctionUndeclaredGlobals, 0)
3685
+ undeclared_globals_Gain = undeclared_globals_variable_Gain + undeclared_globals_constant_Gain
3686
+
3687
+ var sumGain_let = undeclared_globals_variable_Gain
3688
+ sumGain_let -= 4 // "let;"
3689
+ var isGainOk_let = _TO_REPLACE_ON_0_GAIN? sumGain_let >= 0 : sumGain_let > 0
3690
+ if(!isGainOk_let && undeclared_globals_to_replace_variable.length && (_TO_SHRINK_ALL_STRING_LITERALS || _TO_SHRINK_ALL_PROPERTY_NAMES || _TO_SHRINK_BUILTIN_VALUES)){
3691
+ items_undeclared = items_undeclared.filter(item => !undeclared_globals_to_replace_variable.includes(item[2]) || void(undeclaredNotShrunk.becauseGain.push(b.name)))
3692
+ undeclared_globals_to_replace_variable.length = 0
3693
+ undeclared_globals_to_replace = undeclared_globals_to_replace_constant
3694
+ continue
3695
+ }
3696
+ }
3697
+ break
3698
+ }
3699
+
3700
+ // filter out those without a suitable identifier name
3701
+ all_string_literals = all_string_literals.filter(t => t[2] != null)
3702
+ numberLiterals = numberLiterals.filter(t => t[5])
3703
+ all_string_literals.forEach(t => t[5] = getCharacterGain(t[0].length, t[2].length, t[1][1], t[1][2], t[1][3], t[1][4], t[1][5]))
3704
+ if (!_TO_REPLACE_ON_0_GAIN) {
3705
+ all_string_literals = all_string_literals.filter(t => t[5] > 0)
3706
+ }
3707
+
3708
+
3709
+ // calculate sizes -----------------------------------------------------------------------------
3710
+ var literalsAndProps_Gain = 0
3711
+ if (_TO_SHRINK_ALL_STRING_LITERALS || _TO_SHRINK_ALL_PROPERTY_NAMES) {
3712
+ literalsAndProps_Gain = all_string_literals.reduce((sum, t) => t[5] + sum, 0)
3713
+ }
3714
+
3715
+ var builtin_values_Gain = 0
3716
+ if (_TO_SHRINK_BUILTIN_VALUES && builtin_values_to_replace.length) {
3717
+ builtin_values_Gain = builtin_values_to_replace.reduce((sum, b) =>{
3718
+ var decl_cost = b[0].length + b[1].length + 2
3719
+ var gain = (b[0].length - b[1].length) * b[2].length
3720
+ return sum + gain - decl_cost
3721
+ }, 0)
3722
+ }
3723
+ var numbers_Gain = 0
3724
+ if (_TO_REPLACE_NUMBERS) {
3725
+ numbers_Gain = numberLiterals.reduce((sum, b) =>{
3726
+ var decl_cost = b[5].length + b[1].length + 2
3727
+ var gain = b[6] - b[5].length * b[0].length
3728
+ return sum + gain - decl_cost
3729
+ }, 0)
3730
+ }
3731
+ var sumGain_const = literalsAndProps_Gain + builtin_values_Gain + undeclared_globals_constant_Gain + numbers_Gain
3732
+ sumGain_const -= 6 // "const;"
3733
+ var isGainOk_const = _TO_REPLACE_ON_0_GAIN? sumGain_const >= 0 : sumGain_const > 0
3734
+ var sumGain = (isGainOk_const? sumGain_const : 0) + (isGainOk_let? sumGain_let : 0) + all_variables_Gain
3735
+ if (!_TO_FORCE_ARROW_FUNCTIONS && !numInlinedClassPrperties) {
3736
+ if(!isGainOk_const && !isGainOk_let && !all_variables_Gain && !numInlinedItems){
3737
+ console.log("gain not big enough", sumGain);
3738
+ return false
3739
+ }
3740
+ var _allReplacements = all_string_literals.length + undeclared_globals_to_replace_variable.length + undeclared_globals_to_replace_constant.length + builtin_values_to_replace.length + numberLiterals.length
3741
+ if (!_allReplacements && !_TO_SHRINK_ALL_VARIABLES && !numInlinedItems) {
3742
+ console.log("no suitable replacements available");
3743
+ return false
3744
+ }
3745
+ }
3746
+
3747
+ // create the declaration statement (eg. `const a="literal1", b=.....;`) -----------------------------------------------------------------------------
3748
+ var declaration_string_const = ""
3749
+ var declaration_string_var = ""
3750
+ var declaration_string_var_safe = ""
3751
+ if (isGainOk_const) {
3752
+ function escapeWithBestQuote(str) {
3753
+ let single = JsEscapeString(str, "'")
3754
+ let double = JsEscapeString(str, '"')
3755
+ let backtick = JsEscapeString(str, "`").replace(/\$\{/g, "\\${")
3756
+ let singleLen = single.length
3757
+ let doubleLen = double.length
3758
+ let backtickLen = backtick.length
3759
+ let result = 0, bestLen
3760
+ if (singleLen == doubleLen) {
3761
+ result = 3
3762
+ bestLen = singleLen
3763
+ }
3764
+ else if (singleLen < doubleLen){
3765
+ result = 1
3766
+ bestLen = singleLen
3767
+ }
3768
+ else {
3769
+ result = 2
3770
+ bestLen = doubleLen
3771
+ }
3772
+ if (bestLen == backtickLen) {
3773
+ result |= 4
3774
+ }
3775
+ else if(bestLen > backtickLen){
3776
+ result = 4
3777
+ }
3778
+ if (result&1) ++stat_bestQuote_single
3779
+ if (result&2) ++stat_bestQuote_double
3780
+ if (result&4) ++stat_bestQuote_backtick
3781
+ return result&2? '"'+double+'"' : result&1? "'"+single+"'" : "`"+backtick+"`"
3782
+ }
3783
+ let stat_bestQuote_single = 0
3784
+ let stat_bestQuote_double = 0
3785
+ let stat_bestQuote_backtick = 0
3786
+ declaration_string_const += _CONST_DECLARATIONS_START + all_string_literals.map(t => {
3787
+ var escaped = t[0]
3788
+ if (_TO_FIND_BEST_QUOTE) {
3789
+ escaped = escapeWithBestQuote(escaped)
3790
+ }
3791
+ else {
3792
+ escaped = JsEscapeString(escaped, _CONST_DECLARATION_QUOTE_CHARACTER)
3793
+ if (_CONST_DECLARATION_QUOTE_CHARACTER === "`") {
3794
+ escaped = escaped.replace(/\$\{/g, "\\${")
3795
+ }
3796
+ escaped = _CONST_DECLARATION_QUOTE_CHARACTER + escaped + _CONST_DECLARATION_QUOTE_CHARACTER
3797
+ }
3798
+ return t[2] + "=" + escaped
3799
+ })
3800
+ .concat(builtin_values_to_replace.map(b =>
3801
+ b[1] + "=" + b[0]
3802
+ ))
3803
+ .concat(undeclared_globals_to_replace_constant.map(b =>
3804
+ b.id + "=" + b.name
3805
+ ))
3806
+ .concat(numberLiterals.map(b =>
3807
+ b[5] + "=" + b[1]
3808
+ ))
3809
+ .join(",") + _CONST_DECLARATIONS_END
3810
+
3811
+ if (_TO_FIND_BEST_QUOTE) {
3812
+ let all = all_string_literals.length
3813
+ let allf = 100/all
3814
+ var stats_bestQuote = {
3815
+ bestQuote_single: stat_bestQuote_single+`/${all} (${Math.round(stat_bestQuote_single*allf)}%)`,
3816
+ bestQuote_double: stat_bestQuote_double+`/${all} (${Math.round(stat_bestQuote_double*allf)}%)`,
3817
+ bestQuote_backtick: stat_bestQuote_backtick+`/${all} (${Math.round(stat_bestQuote_backtick*allf)}%)`,
3818
+ }
3819
+ }
3820
+ }
3821
+ if (isGainOk_let) {
3822
+ let undeclared_globals_declaration = _VAR_DECLARATIONS_START + undeclared_globals_to_replace_variable.map(b =>
3823
+ b.id + "=" + b.name
3824
+ )
3825
+ .join(",") + _VAR_DECLARATIONS_END
3826
+ let undeclared_globals_declaration_safe = _VAR_DECLARATIONS_START + undeclared_globals_to_replace_variable.map(b =>
3827
+ b.id + "=" + `typeof ${b.name} !== ${_CONST_DECLARATION_QUOTE_CHARACTER}undefined${_CONST_DECLARATION_QUOTE_CHARACTER}?${b.name}:void 0`
3828
+ )
3829
+ .join(",") + _VAR_DECLARATIONS_END
3830
+ declaration_string_var += undeclared_globals_declaration
3831
+ declaration_string_var_safe += undeclared_globals_declaration_safe
3832
+ }
3833
+
3834
+
3835
+
3836
+ // replace literals -----------------------------------------------------------------------------
3837
+ var stringLiterals_nodesMap = new Map
3838
+ if (isGainOk_const) {
3839
+ all_string_literals.forEach(t => t[1][0].forEach(n => stringLiterals_nodesMap.set(n, t)))
3840
+ }
3841
+ if (_TO_SHRINK_ALL_UNDECLARED_GLOBALS) {
3842
+ var undeclared_globals_nodesMap = new Map
3843
+ if (isGainOk_let || isGainOk_const) {
3844
+ undeclared_globals_to_replace.forEach(b => b.references.forEach(n => undeclared_globals_nodesMap.set(n, b)))
3845
+ }
3846
+ }
3847
+ if (_TO_SHRINK_BUILTIN_VALUES) {
3848
+ var builtin_values_nodesMap = new Map
3849
+ if (isGainOk_const) {
3850
+ builtin_values_to_replace.forEach(b => b[2].forEach(n => builtin_values_nodesMap.set(n, b)))
3851
+ }
3852
+ }
3853
+ if (_TO_REPLACE_NUMBERS) {
3854
+ numberLiterals.forEach(b => b[0].forEach(n => n._shrunkNumberVar = b[5]))
3855
+ }
3856
+
3857
+ var debugInfo1 = {
3858
+ replacedPropertyNames: new Set,
3859
+ replacedLiterals: new Set,
3860
+ replacedUndeclared: new Set,
3861
+ }
3862
+ // replace
3863
+ for (const binding of undeclared_globals_to_replace_variable) {
3864
+ /** @type {NodeEdit[]} */
3865
+ let _furtherEdits = binding.furtherEdits
3866
+ if (_furtherEdits) {
3867
+ furtherEdits.push(..._furtherEdits)
3868
+ for (let edit of _furtherEdits) {
3869
+ edit[2] = edit[2].replace("%ID", binding.id)
3870
+ }
3871
+ }
3872
+ }
3873
+
3874
+ var result = astTransformMS({src, ast, parentChain:1, prevSourceMap:inputMap, leave({node, update, source, append, prepend, edit}){
3875
+ var undeclared_global_binding
3876
+ var builtin
3877
+ var l_tuple
3878
+ if (l_tuple = stringLiterals_nodesMap.get(node)) {
3879
+ var id = l_tuple[2]
3880
+ var name = l_tuple[0]
3881
+ if (_TO_SHRINK_ALL_PROPERTY_NAMES) {
3882
+ var needsPropertyKeyBrackets = false
3883
+ let isObjectKey = (node.parent.type == "Property" || node.parent.type == "PropertyDefinition" || node.parent.type == "MethodDefinition") && node.parent.key == node
3884
+ let isPropertyMemberKey = node.parent.type == "MemberExpression" && node.parent.property == node
3885
+ var isPropertyKey = isObjectKey || isPropertyMemberKey
3886
+
3887
+ if (isPropertyKey) {
3888
+ var isComputed = node.parent.computed
3889
+ if (!isComputed) {
3890
+ needsPropertyKeyBrackets = true
3891
+ }
3892
+
3893
+ let caseDelta = node._caseDelta
3894
+ var diff = name - id - caseDelta
3895
+ if(diff < 0 || diff == 0 && !_TO_REPLACE_ON_0_GAIN) return
3896
+
3897
+ if (needsPropertyKeyBrackets) {
3898
+ id = "["+id+"]"
3899
+ if (node._needsSemicol) id = ";"+id
3900
+ // // Fix: shorthand: {prop}
3901
+ if (!_TO_SHRINK_ALL_VARIABLES) {
3902
+ if (isObjectKey && node.parent.value.type === "Identifier" && node.parent.value.start === node.start) {
3903
+ return
3904
+ }
3905
+ }
3906
+ }
3907
+
3908
+
3909
+ if (_DEBUG) {
3910
+ if (!debugInfo1.replacedPropertyNames.has(name)) {
3911
+ debugInfo1.replacedPropertyNames.add(name)
3912
+ }
3913
+
3914
+ }
3915
+ }
3916
+ }
3917
+ else{
3918
+ var diff = name - id + 2
3919
+ if(diff < 0 || diff == 0 && !_TO_REPLACE_ON_0_GAIN) return
3920
+ }
3921
+
3922
+ if (_DEBUG) {
3923
+ if (!isPropertyKey) {
3924
+ if (!debugInfo1.replacedLiterals.has(name)) {
3925
+ debugInfo1.replacedLiterals.add(name)
3926
+ }
3927
+ }
3928
+
3929
+ }
3930
+
3931
+ // Fixes: return"something"
3932
+ if (isJsAlphanum(src[node.start-1])) {
3933
+ id = " "+id
3934
+ }
3935
+ // Fixes: "something"in object1
3936
+ if (isJsAlphanum(src[node.end])) {
3937
+ id = id+" "
3938
+ }
3939
+
3940
+ update(id, node)
3941
+ }
3942
+ // Fix: "object.[A]" => "object[A]"
3943
+ else if(node.type == "MemberExpression" && node.computed == false && !node.optional && stringLiterals_nodesMap.has(node.property)){
3944
+ // remove "."
3945
+ var curSrc = source(node)
3946
+ var i = curSrc.lastIndexOf(".")
3947
+ if(i > 0){
3948
+ var newSrc = curSrc.slice(0, i) + curSrc.slice(i+1)
3949
+ update(newSrc, node)
3950
+ }
3951
+ }
3952
+ else if(_TO_SHRINK_ALL_UNDECLARED_GLOBALS && (undeclared_global_binding = undeclared_globals_nodesMap.get(node))){
3953
+ if (_DEBUG) {
3954
+ debugInfo1.replacedUndeclared.add(undeclared_global_binding.name)
3955
+ }
3956
+ update(undeclared_global_binding.id, node)
3957
+ }
3958
+ else if(_TO_SHRINK_ALL_VARIABLES && (node.type == "Identifier" && node._v)){
3959
+ // Fix: destructuring shorthand: var {prop} = object
3960
+ if (node.parent.type === "Property" && node.parent.value === node && node.parent.key.start === node.start) {
3961
+ let propertySrc = source(node.parent.key)
3962
+ if (propertySrc !== node._v) {
3963
+ update(`${propertySrc}:${node._v}`, node)
3964
+ }
3965
+ }
3966
+ else{
3967
+ update(node._v, node)
3968
+ }
3969
+ }
3970
+ else if(_TO_SHRINK_BUILTIN_VALUES && (builtin = builtin_values_nodesMap.get(node))){
3971
+ update(builtin[1], node)
3972
+ }
3973
+ else if(_TO_REPLACE_NUMBERS && (node.type == "Literal" && (typeof node.value === "number" || typeof node.value === "bigint"))){
3974
+ let replacement = node._shrunkNumberVar || node._shrunkNumber
3975
+ if (replacement) {
3976
+ update(replacement, node)
3977
+ }
3978
+ }
3979
+ else if(!declarationsMarker && iife_wrapper_node && node === iife_wrapper_node){
3980
+ let declarationsStr = declaration_string_const + declaration_string_var
3981
+ let use_strict = getUseStrictExpressionStatement(node)
3982
+ if (use_strict) {
3983
+ if (src[use_strict.end-1] != ";") declarationsStr = ";"+declarationsStr
3984
+ edit.prependLeft(use_strict.end, declarationsStr)
3985
+ }
3986
+ else {
3987
+ edit.remove(node.start, node.start+1)
3988
+ prepend("{" + declaration_string_const + declaration_string_var, node)
3989
+ }
3990
+ }
3991
+ }
3992
+ })
3993
+
3994
+ var numFunctionsConvertedToArrowFunctions = 0
3995
+ if (_TO_FORCE_ARROW_FUNCTIONS) {
3996
+ numFunctionsConvertedToArrowFunctions = forceArrowFunctions(ast, src, result, comments)
3997
+ }
3998
+
3999
+ if (furtherEdits.length) {
4000
+ for (let [type, targetNode, string, targetIndex] of furtherEdits) {
4001
+ if (type === "prepend") {
4002
+ targetIndex ??= targetNode.start
4003
+ result.prependRight(targetIndex, string)
4004
+ }
4005
+ else if (type === "append") {
4006
+ targetIndex ??= targetNode.end
4007
+ result.appendLeft(targetIndex, string)
4008
+ }
4009
+ }
4010
+ }
4011
+
4012
+ if (declarationsMarker) {
4013
+ if (declarationsMarkerConst && declarationsMarkerVar && declarationsMarkerConst !== declarationsMarkerVar) {
4014
+ // separate locations for "const" and "let"
4015
+ result.ctx.update(declaration_string_const, declarationsMarkerConst)
4016
+ result.ctx.update(declaration_string_var, declarationsMarkerVar)
4017
+ }
4018
+ else {
4019
+ // 1 location for both
4020
+ result.ctx.update(declaration_string_const + declaration_string_var, declarationsMarker)
4021
+ }
4022
+ }
4023
+ else if (!iife_wrapper_node) {
4024
+ let declarationsStr = declaration_string_const + declaration_string_var
4025
+ let use_strict = getUseStrictExpressionStatement(ast)
4026
+ if (use_strict) {
4027
+ if (src[use_strict.end-1] != ";") declarationsStr = ";"+declarationsStr
4028
+ result.prependLeft(use_strict.end, declarationsStr)
4029
+ }
4030
+ else {
4031
+ let i = indexOfSeparator("", src, 1)
4032
+ if (i > 0 && src[i-1] == "\n") declarationsStr += "\n"
4033
+ result.prependLeft(i, declarationsStr)
4034
+ }
4035
+ }
4036
+
4037
+ if (_SOURCEMAP_URL && !_TO_GENERATE_SOURCEMAP_INLINE && _TO_GENERATE_SOURCEMAP_OBJECT) {
4038
+ result.append("\n//# sourceMappingURL="+_SOURCEMAP_URL)
4039
+ }
4040
+ var addSourceContentToSourceMap = !inputMapInit && _TO_GENERATE_SOURCEMAP_INLINE
4041
+ var resultCode = result.toString(!!_TO_GENERATE_SOURCEMAP_INLINE, addSourceContentToSourceMap && [srcInit], _SOURCEMAP_FILENAME)
4042
+ if (_TO_GENERATE_SOURCEMAP_OBJECT) {
4043
+ options.map = result.map
4044
+ }
4045
+
4046
+ // debug
4047
+ var realGain = src.length - resultCode.length
4048
+ var totalGain = src_start_Length - resultCode.length
4049
+ var debugInfo2 = {
4050
+ shrinkGain_real: realGain,
4051
+ shrinkGain_predicted: sumGain,
4052
+ discr: realGain-sumGain,
4053
+ totalGain,
4054
+ literalsAndProps_Gain,
4055
+ undeclared_globals_Gain,
4056
+ all_variables_Gain,
4057
+ estimated_this_Gain,
4058
+ numbers_Gain,
4059
+ numNumbersReplaced: numberLiterals.length,
4060
+ numThisReplaced,
4061
+ numFunctionsConvertedToArrowFunctions,
4062
+ numInlinedFunctions,
4063
+ numInlinedVariables,
4064
+ numInlinedClassPrperties,
4065
+ allInlinedClassPrperties,
4066
+ removedUnusedClassProperties,
4067
+ debug_insufficientGainFor,
4068
+ ...debugInfo1,
4069
+ undeclaredNotShrunk,
4070
+ ...stats_bestQuote,
4071
+ }
4072
+ if (options) options.debugInfo = debugInfo2
4073
+ if(_DEBUG) {
4074
+ console.log(debugInfo2);
4075
+ }
4076
+ return resultCode
4077
+ }
4078
+ module.exports = Shrink
4079
+ Shrink.inlineClassObjectProperties = inlineClassObjectProperties
4080
+
4081
+
4082
+
4083
+
4084
+
4085
+
4086
+