storm-lua-minify 0.1.3 → 0.3.0

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/src/ast2lua.ts DELETED
@@ -1,812 +0,0 @@
1
- // based on "luamin": Copyright Mathias Bynens <https://mathiasbynens.be/>
2
- // SPDX-License-Identifier: MIT
3
-
4
- /* eslint-disable @typescript-eslint/no-unnecessary-condition */
5
- import Parser, { Comment } from "luaparse";
6
- import { SourceNode } from "source-map";
7
- import { Minifier, MinifierMode } from "./minifier";
8
-
9
- export type Chunk = Parser.Chunk & {
10
- globals?: (Parser.Base<"Identifer"> & {
11
- name: string;
12
- isLocal: boolean;
13
- })[];
14
- comments?: Comment[];
15
- };
16
-
17
- const PRECEDENCE: Record<string, number> = {
18
- or: 1,
19
- and: 2,
20
- "<": 3,
21
- ">": 3,
22
- "<=": 3,
23
- ">=": 3,
24
- "~=": 3,
25
- "==": 3,
26
- "..": 5,
27
- "+": 6,
28
- "-": 6, // binary -
29
- "*": 7,
30
- "/": 7,
31
- "%": 7,
32
- unarynot: 8,
33
- "unary#": 8,
34
- "unary-": 8, // unary -
35
- "^": 10,
36
- };
37
-
38
- const IDENTIFIER_PARTS = [
39
- "0",
40
- "1",
41
- "2",
42
- "3",
43
- "4",
44
- "5",
45
- "6",
46
- "7",
47
- "8",
48
- "9",
49
- "a",
50
- "b",
51
- "c",
52
- "d",
53
- "e",
54
- "f",
55
- "g",
56
- "h",
57
- "i",
58
- "j",
59
- "k",
60
- "l",
61
- "m",
62
- "n",
63
- "o",
64
- "p",
65
- "q",
66
- "r",
67
- "s",
68
- "t",
69
- "u",
70
- "v",
71
- "w",
72
- "x",
73
- "y",
74
- "z",
75
- "A",
76
- "B",
77
- "C",
78
- "D",
79
- "E",
80
- "F",
81
- "G",
82
- "H",
83
- "I",
84
- "J",
85
- "K",
86
- "L",
87
- "M",
88
- "N",
89
- "O",
90
- "P",
91
- "Q",
92
- "R",
93
- "S",
94
- "T",
95
- "U",
96
- "V",
97
- "W",
98
- "X",
99
- "Y",
100
- "Z",
101
- "_",
102
- ];
103
-
104
- function wrapArray<T>(obj: T | T[]): T[] {
105
- if (Array.isArray(obj)) {
106
- return obj;
107
- }
108
- return [obj];
109
- }
110
-
111
- function generateZeroes(length: number) {
112
- let zero = "0";
113
- let result = "";
114
- if (length < 1) {
115
- return result;
116
- }
117
- if (length == 1) {
118
- return zero;
119
- }
120
- while (length) {
121
- if (length & 1) {
122
- result += zero;
123
- }
124
- // eslint-disable-next-line no-cond-assign
125
- if ((length >>= 1)) {
126
- zero += zero;
127
- }
128
- }
129
- return result;
130
- }
131
-
132
- function isKeyword(id: string) {
133
- switch (id.length) {
134
- case 2:
135
- return "do" == id || "if" == id || "in" == id || "or" == id;
136
- case 3:
137
- return (
138
- "and" == id || "end" == id || "for" == id || "nil" == id || "not" == id
139
- );
140
- case 4:
141
- return "else" == id || "goto" == id || "then" == id || "true" == id;
142
- case 5:
143
- return (
144
- "break" == id ||
145
- "false" == id ||
146
- "local" == id ||
147
- "until" == id ||
148
- "while" == id
149
- );
150
- case 6:
151
- return "elseif" == id || "repeat" == id || "return" == id;
152
- case 8:
153
- return "function" == id;
154
- }
155
- return false;
156
- }
157
-
158
- function isNeedSeparator(a: string, b: string) {
159
- const lastCharA = a.slice(-1);
160
- const firstCharB = b.charAt(0);
161
-
162
- const regexAlphaUnderscore = /[a-zA-Z_]/;
163
- const regexAlphaNumUnderscore = /[a-zA-Z0-9_]/;
164
- const regexDigits = /[0-9]/;
165
-
166
- if (lastCharA == "" || firstCharB == "") {
167
- return false;
168
- }
169
- if (regexAlphaUnderscore.test(lastCharA)) {
170
- if (regexAlphaNumUnderscore.test(firstCharB)) {
171
- // e.g. `while` + `1`
172
- // e.g. `local a` + `local b`
173
- return true;
174
- } else {
175
- // e.g. `not` + `(2>3 or 3<2)`
176
- // e.g. `x` + `^`
177
- return false;
178
- }
179
- }
180
- if (regexDigits.test(lastCharA)) {
181
- if (
182
- firstCharB == "(" ||
183
- !(firstCharB == "." || regexAlphaUnderscore.test(firstCharB))
184
- ) {
185
- // e.g. `1` + `+`
186
- // e.g. `1` + `==`
187
- return false;
188
- } else {
189
- // e.g. `1` + `..`
190
- // e.g. `1` + `and`
191
- return true;
192
- }
193
- }
194
- if (lastCharA == firstCharB && lastCharA == "-") {
195
- // e.g. `1-` + `-2`
196
- return true;
197
- }
198
- const secondLastCharA = a.slice(-2, -1);
199
- if (
200
- lastCharA == "." &&
201
- secondLastCharA != "." &&
202
- regexAlphaNumUnderscore.test(firstCharB)
203
- ) {
204
- // e.g. `1.` + `print`
205
- return true;
206
- }
207
- return false;
208
- }
209
-
210
- interface ExpressionOptoions {
211
- precedence?: number;
212
- preserveIdentifiers?: boolean;
213
- direction?: "left" | "right" | undefined;
214
- parent?: string | undefined;
215
- }
216
-
217
- function addWithSeparator(
218
- val: SourceNode,
219
- adding: (string | SourceNode)[] | SourceNode | string,
220
- separator = " "
221
- ) {
222
- if (
223
- isNeedSeparator(
224
- val.toString(),
225
- wrapArray(adding)
226
- .map((p) => p.toString())
227
- .join()
228
- )
229
- ) {
230
- val.add(separator);
231
- }
232
- val.add(adding);
233
- return val;
234
- }
235
-
236
- function prependWithSeparator(
237
- val: SourceNode,
238
- prepending: (string | SourceNode)[] | SourceNode | string,
239
- separator = " "
240
- ) {
241
- if (
242
- isNeedSeparator(
243
- wrapArray(prepending)
244
- .map((p) => p.toString())
245
- .join(),
246
- val.toString()
247
- )
248
- ) {
249
- val.prepend(separator);
250
- }
251
- val.prepend(prepending);
252
- return val;
253
- }
254
-
255
- function insertSeparator(
256
- a: string | SourceNode,
257
- b: string | SourceNode,
258
- separator = " "
259
- ) {
260
- return isNeedSeparator(a.toString(), b.toString()) ? separator : undefined;
261
- }
262
-
263
- export class MinifyFile {
264
- private fileName: string;
265
- private ast: Chunk;
266
- private minifier: Minifier;
267
- private mode: MinifierMode;
268
-
269
- constructor(
270
- fileName: string,
271
- ast: Chunk,
272
- minifier: Minifier,
273
- mode: MinifierMode
274
- ) {
275
- this.fileName = fileName;
276
- this.ast = ast;
277
- this.minifier = minifier;
278
- this.mode = mode;
279
- }
280
-
281
- parse(noComment: boolean) {
282
- const body = this.formatStatementList(this.ast.body);
283
- if (!noComment && this.ast.comments) {
284
- const comments = this.ast.comments as Comment[];
285
- comments.reverse().filter(v => v.raw.includes("--#") || v.raw.includes("[[#")).forEach(comment => {
286
- body.prepend([this.sourceNodeHelper(comment, comment.raw), "\n"]);
287
- })
288
- return body;
289
- } else {
290
- return body;
291
- }
292
- }
293
-
294
- private sourceNodeHelper(
295
- node: Parser.Node | undefined,
296
- chuncks: (SourceNode | string)[] | SourceNode | string,
297
- name?: string
298
- ) {
299
- const line = node?.loc?.start.line;
300
- const column = node?.loc?.start.column;
301
- return new SourceNode(
302
- line == undefined ? null : line,
303
- column == undefined ? null : column,
304
- this.fileName, // 本当に自分のファイル名でよいかは要検討
305
- chuncks,
306
- name
307
- );
308
- }
309
-
310
- private formatStatementList(body: Parser.Statement[] | Parser.Statement) {
311
- const result = this.sourceNodeHelper(undefined, []);
312
- wrapArray(body).forEach((statement) => {
313
- addWithSeparator(result, this.formatStatement(statement), "\n");
314
- });
315
- return result;
316
- }
317
-
318
- private formatStatement(statement: Parser.Statement): SourceNode {
319
- if (statement.type == "AssignmentStatement") {
320
- // left-hand side
321
- const variables = statement.variables
322
- .map((variable) => [this.formatExpression(variable), ","])
323
- .flat();
324
- const inits = statement.init
325
- .map((init) => [this.formatExpression(init), ","])
326
- .flat();
327
-
328
- const result = this.sourceNodeHelper(
329
- statement,
330
- this.sourceNodeHelper(undefined, variables.slice(0, -1))
331
- );
332
- addWithSeparator(result, "=");
333
- addWithSeparator(
334
- result,
335
- this.sourceNodeHelper(undefined, inits.slice(0, -1))
336
- );
337
- return result;
338
- } else if (statement.type == "LocalStatement") {
339
- const variables = statement.variables
340
- .map((variable) => [this.formatExpression(variable), ","])
341
- .flat();
342
- const result = this.sourceNodeHelper(statement, [
343
- "local ",
344
- this.sourceNodeHelper(undefined, variables.slice(0, -1)),
345
- ]);
346
-
347
- if (statement.init.length) {
348
- const inits = statement.init
349
- .map((init) => [this.formatExpression(init), ","])
350
- .flat();
351
-
352
- addWithSeparator(result, "=");
353
- addWithSeparator(
354
- result,
355
- this.sourceNodeHelper(undefined, inits.slice(0, -1))
356
- );
357
- }
358
- return result;
359
- } else if (statement.type == "CallStatement") {
360
- return this.formatExpression(statement.expression); // NOTE: もう一度囲んでもいい
361
- } else if (statement.type == "IfStatement") {
362
- const result = this.sourceNodeHelper(statement, []);
363
- statement.clauses.forEach((clause) => {
364
- const clauseMap = this.sourceNodeHelper(clause, []);
365
- if (clause.type == "IfClause") {
366
- addWithSeparator(clauseMap, "if");
367
- addWithSeparator(clauseMap, this.formatExpression(clause.condition));
368
- addWithSeparator(clauseMap, "then");
369
- } else if (clause.type == "ElseifClause") {
370
- addWithSeparator(clauseMap, "elseif");
371
- addWithSeparator(clauseMap, this.formatExpression(clause.condition));
372
- addWithSeparator(clauseMap, "then");
373
- } else {
374
- addWithSeparator(clauseMap, "else");
375
- }
376
- addWithSeparator(clauseMap, this.formatStatementList(clause.body));
377
- addWithSeparator(result, clauseMap);
378
- });
379
- addWithSeparator(result, "end");
380
- return result;
381
- } else if (statement.type == "WhileStatement") {
382
- const result = this.sourceNodeHelper(statement, "while");
383
- addWithSeparator(result, this.formatExpression(statement.condition));
384
- addWithSeparator(result, "do");
385
- addWithSeparator(result, this.formatStatementList(statement.body));
386
- addWithSeparator(result, "end");
387
- return result;
388
- } else if (statement.type == "DoStatement") {
389
- const result = this.sourceNodeHelper(statement, "do");
390
- addWithSeparator(result, this.formatStatementList(statement.body));
391
- addWithSeparator(result, "end");
392
- return result;
393
- } else if (statement.type == "ReturnStatement") {
394
- const result = this.sourceNodeHelper(statement, "return");
395
- if (statement.arguments.length) {
396
- const returns = statement.arguments
397
- .map((argument) => [this.formatExpression(argument), ","])
398
- .flat();
399
- addWithSeparator(result, returns.slice(0, -1));
400
- }
401
- return result;
402
- } else if (statement.type == "BreakStatement") {
403
- return this.sourceNodeHelper(statement, "break");
404
- } else if (statement.type == "RepeatStatement") {
405
- const result = this.sourceNodeHelper(statement, "repeat");
406
- addWithSeparator(result, this.formatStatementList(statement.body));
407
- addWithSeparator(result, "until");
408
- addWithSeparator(result, this.formatExpression(statement.condition));
409
- return result;
410
- } else if (statement.type == "FunctionDeclaration") {
411
- const result = this.sourceNodeHelper(
412
- statement,
413
- (statement.isLocal ? "local " : "") + "function "
414
- );
415
- if (statement.identifier) {
416
- addWithSeparator(result, this.formatExpression(statement.identifier));
417
- }
418
- addWithSeparator(result, "(");
419
-
420
- if (statement.parameters.length) {
421
- const parameters = statement.parameters
422
- .map((parameter) => {
423
- return [
424
- parameter.type == "Identifier"
425
- ? this.generateIdentifier(parameter)
426
- : parameter.value,
427
- ",",
428
- ];
429
- })
430
- .flat();
431
- addWithSeparator(result, parameters.slice(0, -1));
432
- }
433
-
434
- addWithSeparator(result, ")");
435
- addWithSeparator(result, this.formatStatementList(statement.body));
436
- addWithSeparator(result, "end");
437
- return result;
438
- } else if (statement.type == "ForGenericStatement") {
439
- // see also `ForNumericStatement`
440
- const result = this.sourceNodeHelper(statement, "for");
441
- const variables = statement.variables
442
- .map((variable) => [this.generateIdentifier(variable), ","])
443
- .flat();
444
- const iterators = statement.iterators
445
- .map((iterator) => [this.formatExpression(iterator), ","])
446
- .flat();
447
- addWithSeparator(result, variables.slice(0, -1));
448
- addWithSeparator(result, "in");
449
- addWithSeparator(result, iterators.slice(0, -1));
450
- addWithSeparator(result, "do");
451
- addWithSeparator(result, this.formatStatementList(statement.body));
452
- addWithSeparator(result, "end");
453
- return result;
454
- } else if (statement.type == "ForNumericStatement") {
455
- // The variables in a `ForNumericStatement` are always local
456
- const result = this.sourceNodeHelper(statement, "for");
457
- addWithSeparator(result, this.generateIdentifier(statement.variable));
458
- addWithSeparator(result, "=");
459
- addWithSeparator(result, this.formatExpression(statement.start));
460
- addWithSeparator(result, ",");
461
- addWithSeparator(result, this.formatExpression(statement.end));
462
-
463
- if (statement.step) {
464
- addWithSeparator(result, ",");
465
- addWithSeparator(result, this.formatExpression(statement.step));
466
- }
467
-
468
- addWithSeparator(result, "do");
469
- addWithSeparator(result, this.formatStatementList(statement.body));
470
- addWithSeparator(result, "end");
471
- return result;
472
- } else if (statement.type == "LabelStatement") {
473
- // The identifier names in a `LabelStatement` can safely be renamed
474
- return this.sourceNodeHelper(statement, [
475
- "::",
476
- this.generateIdentifier(statement.label),
477
- "::",
478
- ]);
479
- } else if (statement.type == "GotoStatement") {
480
- // The identifier names in a `GotoStatement` can safely be renamed
481
- return this.sourceNodeHelper(statement, [
482
- "goto ",
483
- this.generateIdentifier(statement.label),
484
- ]);
485
- } else {
486
- throw TypeError(
487
- "Unknown statement type: `" + JSON.stringify(statement) + "`"
488
- );
489
- }
490
- }
491
-
492
- /*function joinStatements(a: string | SourceNode, b: string | SourceNode, separator = " ") {
493
- return isNeedSeparator(a.toString(), b.toString()) ? a.toString() + separator + b.toString() : a.toString() + b.toString();
494
- }*/
495
-
496
- private formatExpression(
497
- expression: Parser.Expression,
498
- argOptions?: ExpressionOptoions
499
- ): SourceNode {
500
- if (expression.type == "Identifier") {
501
- return this.sourceNodeHelper(
502
- expression,
503
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment, @typescript-eslint/prefer-ts-expect-error
504
- //@ts-ignore
505
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
506
- expression.isLocal
507
- ? this.generateIdentifier(expression, true)
508
- : expression.name,
509
- expression.name
510
- );
511
- } else if (
512
- expression.type == "StringLiteral" ||
513
- expression.type == "NumericLiteral" ||
514
- expression.type == "BooleanLiteral" ||
515
- expression.type == "NilLiteral" ||
516
- expression.type == "VarargLiteral"
517
- ) {
518
- return this.sourceNodeHelper(expression, expression.raw);
519
- } else if (
520
- expression.type == "LogicalExpression" ||
521
- expression.type == "BinaryExpression"
522
- ) {
523
- const operator = expression.operator;
524
- const currentPrecedence = PRECEDENCE[operator];
525
- let associativity: "left" | "right" = "left";
526
- const options = {
527
- precedence: 0,
528
- preserveIdentifiers: false,
529
- ...argOptions,
530
- };
531
-
532
- const leftHand = this.formatExpression(expression.left, {
533
- precedence: currentPrecedence,
534
- direction: "left",
535
- parent: operator,
536
- });
537
- const rightHand = this.formatExpression(expression.right, {
538
- precedence: currentPrecedence,
539
- direction: "right",
540
- parent: operator,
541
- });
542
- if (operator == "^" || operator == "..") {
543
- associativity = "right";
544
- } else if (
545
- currentPrecedence < options.precedence ||
546
- (currentPrecedence == options.precedence &&
547
- associativity != options.direction &&
548
- options.parent != "+" &&
549
- !(options.parent == "*" && (operator == "/" || operator == "*")))
550
- ) {
551
- return this.sourceNodeHelper(
552
- expression,
553
- [
554
- "(",
555
- leftHand,
556
- insertSeparator(leftHand, operator),
557
- operator,
558
- insertSeparator(operator, rightHand),
559
- rightHand,
560
- ")",
561
- ].filter((p): p is Exclude<typeof p, undefined> => p !== undefined)
562
- );
563
- }
564
- return this.sourceNodeHelper(
565
- expression,
566
- [
567
- leftHand,
568
- insertSeparator(leftHand, operator),
569
- operator,
570
- insertSeparator(operator, rightHand),
571
- rightHand,
572
- ].filter((p): p is Exclude<typeof p, undefined> => p !== undefined)
573
- );
574
- } else if (expression.type == "UnaryExpression") {
575
- const operator = expression.operator;
576
- const currentPrecedence = PRECEDENCE["unary" + operator];
577
- const options = {
578
- precedence: 0,
579
- ...argOptions,
580
- };
581
-
582
- const p2 = this.formatExpression(expression.argument, {
583
- precedence: currentPrecedence,
584
- });
585
- const result = this.sourceNodeHelper(
586
- expression,
587
- [operator, insertSeparator(operator, p2), p2].filter(
588
- (p): p is Exclude<typeof p, undefined> => p !== undefined
589
- )
590
- );
591
-
592
- if (
593
- currentPrecedence < options.precedence &&
594
- // In principle, we should parenthesize the RHS of an
595
- // expression like `3^-2`, because `^` has higher precedence
596
- // than unary `-` according to the manual. But that is
597
- // misleading on the RHS of `^`, since the parser will
598
- // always try to find a unary operator regardless of
599
- // precedence.
600
- !(options.parent == "^" && options.direction == "right")
601
- ) {
602
- result.prepend("(");
603
- result.add(")");
604
- }
605
- return result;
606
- } else if (expression.type == "CallExpression") {
607
- // requireの展開モードは2種類: SLモード-その場に読み込み, FLモード-require相当の関数で呼び出し
608
- const callExpr = this.formatBase(expression.base).toString();
609
- if (
610
- (callExpr === "require" || callExpr === "dofile") &&
611
- expression?.arguments[0].type === "StringLiteral"
612
- ) {
613
- const moduleName = expression.arguments[0].raw
614
- .replaceAll('"', "")
615
- .replaceAll("'", "");
616
-
617
- const res = this.minifier.parseModule(moduleName);
618
-
619
- if (this.mode.moduleLikeLua) {
620
- if (callExpr === "dofile") {
621
- return (
622
- res || this.sourceNodeHelper(undefined, "")
623
- );
624
- }
625
- // requireならスキップ
626
- } else {
627
- return (
628
- res || this.sourceNodeHelper(undefined, "")
629
- );
630
- }
631
- }
632
- const args = expression.arguments
633
- .map((arg) => [this.formatExpression(arg), ","])
634
- .flat();
635
- return this.sourceNodeHelper(expression, [
636
- this.formatBase(expression.base),
637
- "(",
638
- this.sourceNodeHelper(undefined, args.slice(0, -1)),
639
- ")",
640
- ]);
641
- } else if (expression.type == "TableCallExpression") {
642
- return this.sourceNodeHelper(expression, [
643
- this.formatExpression(expression.base),
644
- this.formatExpression(expression.arguments),
645
- ]);
646
- } else if (expression.type == "StringCallExpression") {
647
- return this.sourceNodeHelper(expression, [
648
- this.formatExpression(expression.base),
649
- this.formatExpression(expression.argument),
650
- ]);
651
- } else if (expression.type == "IndexExpression") {
652
- return this.sourceNodeHelper(expression, [
653
- this.formatBase(expression.base),
654
- "[",
655
- this.formatExpression(expression.index),
656
- "]",
657
- ]);
658
- } else if (expression.type == "MemberExpression") {
659
- return this.sourceNodeHelper(expression, [
660
- this.formatBase(expression.base),
661
- expression.indexer,
662
- this.formatExpression(expression.identifier, {
663
- preserveIdentifiers: true,
664
- }),
665
- ]);
666
- } else if (expression.type == "FunctionDeclaration") {
667
- const result = this.sourceNodeHelper(expression, ["function", "("]);
668
-
669
- if (expression.parameters.length) {
670
- const parameters = expression.parameters
671
- .map((parameter) => {
672
- return [
673
- this.sourceNodeHelper(
674
- parameter,
675
- parameter.type === "Identifier"
676
- ? this.generateIdentifier(parameter)
677
- : parameter.value
678
- ),
679
- ",",
680
- ];
681
- })
682
- .flat();
683
- addWithSeparator(result, parameters.slice(0, -1));
684
- }
685
- result.add(")");
686
- const body = this.formatStatementList(expression.body);
687
- addWithSeparator(result, body);
688
- addWithSeparator(result, "end");
689
- return result;
690
- } else if (expression.type == "TableConstructorExpression") {
691
- const result = this.sourceNodeHelper(expression, "{");
692
- const fields = expression.fields
693
- .map((field, ix, ar) => {
694
- // Stormworks "propert" Trailing Comma: https://nona-takahara.github.io/blog/entry11.html
695
- const comma =
696
- ix !== ar.length - 1 ||
697
- this.formatExpression(field.value).toString().includes("property")
698
- ? ","
699
- : undefined;
700
-
701
- if (field.type == "TableKey") {
702
- return this.sourceNodeHelper(
703
- field,
704
- [
705
- this.sourceNodeHelper(undefined, [
706
- "[",
707
- this.formatExpression(field.key),
708
- "]",
709
- ]),
710
- "=",
711
- this.formatExpression(field.value),
712
- comma,
713
- ].filter(
714
- (p): p is Exclude<typeof p, undefined> => p !== undefined
715
- )
716
- );
717
- } else if (field.type == "TableValue") {
718
- return [this.formatExpression(field.value), comma].filter(
719
- (p): p is Exclude<typeof p, undefined> => p !== undefined
720
- );
721
- } else {
722
- // at this point, `field.type == 'TableKeyString'`
723
- // TODO: keep track of nested scopes (#18)
724
- return this.sourceNodeHelper(
725
- field,
726
- [
727
- this.formatExpression(field.key, { preserveIdentifiers: true }),
728
- "=",
729
- this.formatExpression(field.value),
730
- comma,
731
- ].filter(
732
- (p): p is Exclude<typeof p, undefined> => p !== undefined
733
- )
734
- );
735
- }
736
- })
737
- .flat();
738
- addWithSeparator(result, fields);
739
- addWithSeparator(result, "}");
740
- return result;
741
- } else {
742
- throw TypeError(
743
- "Unknown expression type: `" + JSON.stringify(expression) + "`"
744
- );
745
- }
746
- }
747
-
748
- private formatBase(base: Parser.Expression): SourceNode {
749
- const type = base.type;
750
- const needsParens =
751
- type == "CallExpression" ||
752
- type == "BinaryExpression" ||
753
- type == "FunctionDeclaration" ||
754
- type == "TableConstructorExpression" ||
755
- type == "LogicalExpression" ||
756
- type == "StringLiteral";
757
- const result = this.sourceNodeHelper(base, this.formatExpression(base));
758
- if (needsParens) {
759
- prependWithSeparator(result, "(");
760
- addWithSeparator(result, ")");
761
- }
762
- return result;
763
- }
764
-
765
- private currentIdentifier = "";
766
-
767
- private generateIdentifier(
768
- nameItem: Parser.Identifier,
769
- nested = false
770
- ): SourceNode {
771
- if (nameItem.name === "self") {
772
- return this.sourceNodeHelper(nameItem, "self", "self");
773
- }
774
-
775
- const defined = this.minifier.identifierMap.get(nameItem.name);
776
- if (defined) {
777
- return this.sourceNodeHelper(nameItem, defined, nameItem.name); // 第3引数は要調査
778
- }
779
-
780
- const length = this.currentIdentifier.length;
781
- let position = length - 1;
782
- let character: string;
783
- let index;
784
- while (position >= 0) {
785
- character = this.currentIdentifier.charAt(position);
786
- index = IDENTIFIER_PARTS.indexOf(character);
787
- if (index != IDENTIFIER_PARTS.length - 1) {
788
- this.currentIdentifier =
789
- this.currentIdentifier.substring(0, position) +
790
- IDENTIFIER_PARTS[index + 1] +
791
- generateZeroes(length - (position + 1));
792
- if (
793
- isKeyword(this.currentIdentifier) ||
794
- this.minifier.identifiersInUse.has(this.currentIdentifier)
795
- ) {
796
- return this.generateIdentifier(nameItem, nested);
797
- }
798
- this.minifier.identifierMap.set(nameItem.name, this.currentIdentifier);
799
- return this.generateIdentifier(nameItem, nested);
800
- }
801
- --position;
802
- }
803
- this.currentIdentifier = "a" + generateZeroes(length);
804
- if (this.minifier.identifiersInUse.has(this.currentIdentifier)) {
805
- return this.generateIdentifier(nameItem, nested);
806
- }
807
- this.minifier.identifierMap.set(nameItem.name, this.currentIdentifier);
808
- return this.generateIdentifier(nameItem, nested);
809
-
810
- // return this.sourceNodeHelper(nameItem, nameItem.name, nested ? nameItem.name : undefined);
811
- }
812
- }