luau-obfuscator 1.0.5 → 1.0.7

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.
@@ -1,185 +1,185 @@
1
- import type {
2
- Program, Block, Statement, Expression,
3
- } from "luau-parser"
4
- import {
5
- identifier, numberLiteral, binary, localStatement, doStatement, block,
6
- ifStatement, ifClause,
7
- } from "./nodeFactory"
8
-
9
- export interface InsertJunkOptions {
10
- /** 기존 statement 하나 앞에 junk를 끼워넣을 확률 (0~1) */
11
- probability: number
12
- /** 블록 하나당 최대 삽입 개수 */
13
- maxPerBlock: number
14
- }
15
-
16
- function randomInt(min: number, max: number): number {
17
- return Math.floor(Math.random() * (max - min + 1)) + min
18
- }
19
-
20
- function randomName(): string {
21
- return "_" + globalThis.crypto.randomUUID().replace(/-/g, "")
22
- }
23
-
24
- function junkNumberExpr(): Expression {
25
- const op = Math.random() < 0.5 ? "+" : "*"
26
- return binary(op, numberLiteral(randomInt(1, 999)), numberLiteral(randomInt(1, 999)))
27
- }
28
-
29
- /**
30
- * 실행돼도 관찰 가능한 부작용이 전혀 없는 더미 statement 하나를 만듦.
31
- * - 매번 새 랜덤 이름을 쓰므로 다른 변수와 충돌하지 않음
32
- * - if 분기 조건이 실제로 참/거짓 어느 쪽이어도 몸통이 쓸모없는 local 선언뿐이라
33
- * 상관없음 (opaque predicate를 엄밀하게 항상 거짓으로 만들 필요가 없음)
34
- */
35
- function buildJunkStatement(): Statement {
36
- const variants: Array<() => Statement> = [
37
- () => localStatement(randomName(), junkNumberExpr()),
38
- () => doStatement(block([localStatement(randomName(), junkNumberExpr())])),
39
- () => ifStatement([
40
- ifClause(
41
- binary("==", numberLiteral(randomInt(1, 999)), numberLiteral(randomInt(1, 999))),
42
- block([localStatement(randomName(), junkNumberExpr())]),
43
- ),
44
- ]),
45
- ]
46
- return variants[randomInt(0, variants.length - 1)]()
47
- }
48
-
49
- export function runInsertJunk(program: Program, options: InsertJunkOptions): void {
50
- function processExpr(expr: Expression): void {
51
- switch (expr.type) {
52
- case "InterpolatedStringExpression":
53
- for (const part of expr.parts) {
54
- if (part.kind === "expression") processExpr(part.expression)
55
- }
56
- return
57
- case "FunctionExpression":
58
- processBlock(expr.func.body)
59
- return
60
- case "TableExpression":
61
- for (const field of expr.fields) {
62
- if (field.type === "TableFieldPositional") processExpr(field.value)
63
- else if (field.type === "TableFieldNamed") processExpr(field.value)
64
- else { processExpr(field.key); processExpr(field.value) }
65
- }
66
- return
67
- case "BinaryExpression":
68
- processExpr(expr.left)
69
- processExpr(expr.right)
70
- return
71
- case "UnaryExpression":
72
- processExpr(expr.argument)
73
- return
74
- case "MemberExpression":
75
- processExpr(expr.object)
76
- return
77
- case "IndexExpression":
78
- processExpr(expr.object)
79
- processExpr(expr.index)
80
- return
81
- case "CallExpression":
82
- processExpr(expr.callee)
83
- expr.arguments.forEach(processExpr)
84
- return
85
- case "MethodCallExpression":
86
- processExpr(expr.object)
87
- expr.arguments.forEach(processExpr)
88
- return
89
- case "ParenthesizedExpression":
90
- processExpr(expr.expression)
91
- return
92
- case "TypeAssertionExpression":
93
- processExpr(expr.expression)
94
- return
95
- case "IfElseExpression":
96
- for (const clause of expr.clauses) {
97
- processExpr(clause.condition)
98
- processExpr(clause.body)
99
- }
100
- processExpr(expr.alternate)
101
- return
102
- default:
103
- return
104
- }
105
- }
106
-
107
- function processStatement(stmt: Statement): void {
108
- switch (stmt.type) {
109
- case "LocalStatement":
110
- stmt.init.forEach(processExpr)
111
- return
112
- case "LocalFunctionStatement":
113
- processBlock(stmt.func.body)
114
- return
115
- case "FunctionDeclarationStatement":
116
- processBlock(stmt.func.body)
117
- return
118
- case "AssignmentStatement":
119
- stmt.targets.forEach(processExpr)
120
- stmt.values.forEach(processExpr)
121
- return
122
- case "CompoundAssignmentStatement":
123
- processExpr(stmt.target)
124
- processExpr(stmt.value)
125
- return
126
- case "CallStatement":
127
- processExpr(stmt.expression)
128
- return
129
- case "DoStatement":
130
- processBlock(stmt.body)
131
- return
132
- case "WhileStatement":
133
- processExpr(stmt.condition)
134
- processBlock(stmt.body)
135
- return
136
- case "RepeatStatement":
137
- processBlock(stmt.body)
138
- processExpr(stmt.condition)
139
- return
140
- case "IfStatement":
141
- for (const clause of stmt.clauses) {
142
- processExpr(clause.condition)
143
- processBlock(clause.body)
144
- }
145
- if (stmt.alternate) processBlock(stmt.alternate)
146
- return
147
- case "NumericForStatement":
148
- processExpr(stmt.start)
149
- processExpr(stmt.end)
150
- if (stmt.step) processExpr(stmt.step)
151
- processBlock(stmt.body)
152
- return
153
- case "GenericForStatement":
154
- stmt.iterators.forEach(processExpr)
155
- processBlock(stmt.body)
156
- return
157
- case "ReturnStatement":
158
- stmt.arguments.forEach(processExpr)
159
- return
160
- default:
161
- return
162
- }
163
- }
164
-
165
- /** 자식 블록들부터 먼저 처리한 뒤(재귀 무한 방지 — 새로 끼워넣는 junk는
166
- * 다시 처리하지 않음), 현재 블록에 junk를 끼워넣음. junk는 기존 statement
167
- * "앞"에만 넣으므로 return/break/continue(항상 블록 맨 끝에만 올 수 있음)
168
- * 뒤에 잘못 삽입될 일이 없음. */
169
- function processBlock(blk: Block): void {
170
- for (const stmt of blk.statements) processStatement(stmt)
171
-
172
- const result: Statement[] = []
173
- let inserted = 0
174
- for (const stmt of blk.statements) {
175
- if (inserted < options.maxPerBlock && Math.random() < options.probability) {
176
- result.push(buildJunkStatement())
177
- inserted++
178
- }
179
- result.push(stmt)
180
- }
181
- blk.statements = result
182
- }
183
-
184
- processBlock(program.body)
1
+ import type {
2
+ Program, Block, Statement, Expression,
3
+ } from "luau-parser"
4
+ import {
5
+ identifier, numberLiteral, binary, localStatement, doStatement, block,
6
+ ifStatement, ifClause,
7
+ } from "./nodeFactory"
8
+
9
+ export interface InsertJunkOptions {
10
+ /** 기존 statement 하나 앞에 junk를 끼워넣을 확률 (0~1) */
11
+ probability: number
12
+ /** 블록 하나당 최대 삽입 개수 */
13
+ maxPerBlock: number
14
+ }
15
+
16
+ function randomInt(min: number, max: number): number {
17
+ return Math.floor(Math.random() * (max - min + 1)) + min
18
+ }
19
+
20
+ function randomName(): string {
21
+ return "_" + globalThis.crypto.randomUUID().replace(/-/g, "")
22
+ }
23
+
24
+ function junkNumberExpr(): Expression {
25
+ const op = Math.random() < 0.5 ? "+" : "*"
26
+ return binary(op, numberLiteral(randomInt(1, 999)), numberLiteral(randomInt(1, 999)))
27
+ }
28
+
29
+ /**
30
+ * 실행돼도 관찰 가능한 부작용이 전혀 없는 더미 statement 하나를 만듦.
31
+ * - 매번 새 랜덤 이름을 쓰므로 다른 변수와 충돌하지 않음
32
+ * - if 분기 조건이 실제로 참/거짓 어느 쪽이어도 몸통이 쓸모없는 local 선언뿐이라
33
+ * 상관없음 (opaque predicate를 엄밀하게 항상 거짓으로 만들 필요가 없음)
34
+ */
35
+ function buildJunkStatement(): Statement {
36
+ const variants: Array<() => Statement> = [
37
+ () => localStatement(randomName(), junkNumberExpr()),
38
+ () => doStatement(block([localStatement(randomName(), junkNumberExpr())])),
39
+ () => ifStatement([
40
+ ifClause(
41
+ binary("==", numberLiteral(randomInt(1, 999)), numberLiteral(randomInt(1, 999))),
42
+ block([localStatement(randomName(), junkNumberExpr())]),
43
+ ),
44
+ ]),
45
+ ]
46
+ return variants[randomInt(0, variants.length - 1)]()
47
+ }
48
+
49
+ export function runInsertJunk(program: Program, options: InsertJunkOptions): void {
50
+ function processExpr(expr: Expression): void {
51
+ switch (expr.type) {
52
+ case "InterpolatedStringExpression":
53
+ for (const part of expr.parts) {
54
+ if (part.kind === "expression") processExpr(part.expression)
55
+ }
56
+ return
57
+ case "FunctionExpression":
58
+ processBlock(expr.func.body)
59
+ return
60
+ case "TableExpression":
61
+ for (const field of expr.fields) {
62
+ if (field.type === "TableFieldPositional") processExpr(field.value)
63
+ else if (field.type === "TableFieldNamed") processExpr(field.value)
64
+ else { processExpr(field.key); processExpr(field.value) }
65
+ }
66
+ return
67
+ case "BinaryExpression":
68
+ processExpr(expr.left)
69
+ processExpr(expr.right)
70
+ return
71
+ case "UnaryExpression":
72
+ processExpr(expr.argument)
73
+ return
74
+ case "MemberExpression":
75
+ processExpr(expr.object)
76
+ return
77
+ case "IndexExpression":
78
+ processExpr(expr.object)
79
+ processExpr(expr.index)
80
+ return
81
+ case "CallExpression":
82
+ processExpr(expr.callee)
83
+ expr.arguments.forEach(processExpr)
84
+ return
85
+ case "MethodCallExpression":
86
+ processExpr(expr.object)
87
+ expr.arguments.forEach(processExpr)
88
+ return
89
+ case "ParenthesizedExpression":
90
+ processExpr(expr.expression)
91
+ return
92
+ case "TypeAssertionExpression":
93
+ processExpr(expr.expression)
94
+ return
95
+ case "IfElseExpression":
96
+ for (const clause of expr.clauses) {
97
+ processExpr(clause.condition)
98
+ processExpr(clause.body)
99
+ }
100
+ processExpr(expr.alternate)
101
+ return
102
+ default:
103
+ return
104
+ }
105
+ }
106
+
107
+ function processStatement(stmt: Statement): void {
108
+ switch (stmt.type) {
109
+ case "LocalStatement":
110
+ stmt.init.forEach(processExpr)
111
+ return
112
+ case "LocalFunctionStatement":
113
+ processBlock(stmt.func.body)
114
+ return
115
+ case "FunctionDeclarationStatement":
116
+ processBlock(stmt.func.body)
117
+ return
118
+ case "AssignmentStatement":
119
+ stmt.targets.forEach(processExpr)
120
+ stmt.values.forEach(processExpr)
121
+ return
122
+ case "CompoundAssignmentStatement":
123
+ processExpr(stmt.target)
124
+ processExpr(stmt.value)
125
+ return
126
+ case "CallStatement":
127
+ processExpr(stmt.expression)
128
+ return
129
+ case "DoStatement":
130
+ processBlock(stmt.body)
131
+ return
132
+ case "WhileStatement":
133
+ processExpr(stmt.condition)
134
+ processBlock(stmt.body)
135
+ return
136
+ case "RepeatStatement":
137
+ processBlock(stmt.body)
138
+ processExpr(stmt.condition)
139
+ return
140
+ case "IfStatement":
141
+ for (const clause of stmt.clauses) {
142
+ processExpr(clause.condition)
143
+ processBlock(clause.body)
144
+ }
145
+ if (stmt.alternate) processBlock(stmt.alternate)
146
+ return
147
+ case "NumericForStatement":
148
+ processExpr(stmt.start)
149
+ processExpr(stmt.end)
150
+ if (stmt.step) processExpr(stmt.step)
151
+ processBlock(stmt.body)
152
+ return
153
+ case "GenericForStatement":
154
+ stmt.iterators.forEach(processExpr)
155
+ processBlock(stmt.body)
156
+ return
157
+ case "ReturnStatement":
158
+ stmt.arguments.forEach(processExpr)
159
+ return
160
+ default:
161
+ return
162
+ }
163
+ }
164
+
165
+ /** 자식 블록들부터 먼저 처리한 뒤(재귀 무한 방지 — 새로 끼워넣는 junk는
166
+ * 다시 처리하지 않음), 현재 블록에 junk를 끼워넣음. junk는 기존 statement
167
+ * "앞"에만 넣으므로 return/break/continue(항상 블록 맨 끝에만 올 수 있음)
168
+ * 뒤에 잘못 삽입될 일이 없음. */
169
+ function processBlock(blk: Block): void {
170
+ for (const stmt of blk.statements) processStatement(stmt)
171
+
172
+ const result: Statement[] = []
173
+ let inserted = 0
174
+ for (const stmt of blk.statements) {
175
+ if (inserted < options.maxPerBlock && Math.random() < options.probability) {
176
+ result.push(buildJunkStatement())
177
+ inserted++
178
+ }
179
+ result.push(stmt)
180
+ }
181
+ blk.statements = result
182
+ }
183
+
184
+ processBlock(program.body)
185
185
  }
@@ -1,6 +1,6 @@
1
- export function minifyPrinted(code: string): string {
2
- return code
3
- .replace(/\r\n|\r|\n/g, " ")
4
- .replace(/[ \t]+/g, " ")
5
- .trim()
1
+ export function minifyPrinted(code: string): string {
2
+ return code
3
+ .replace(/\r\n|\r|\n/g, " ")
4
+ .replace(/[ \t]+/g, " ")
5
+ .trim()
6
6
  }