• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

javascript-obfuscator / javascript-obfuscator / 19907815758

03 Dec 2025 08:27PM UTC coverage: 97.319%. Remained the same
19907815758

push

github

sanex3339
Adjust precommit hook

1770 of 1891 branches covered (93.6%)

Branch coverage included in aggregate %.

5671 of 5755 relevant lines covered (98.54%)

34102965.58 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.67
/src/node-transformers/simplifying-transformers/IfStatementSimplifyTransformer.ts
1
import { inject, injectable } from 'inversify';
6✔
2
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
6✔
3

4
import * as ESTree from 'estree';
5

6
import { IOptions } from '../../interfaces/options/IOptions';
7
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
8
import { IStatementSimplifyData } from '../../interfaces/node-transformers/simplifying-transformers/IStatementSimplifyData';
9
import { IVisitor } from '../../interfaces/node-transformers/IVisitor';
10

11
import { NodeTransformationStage } from '../../enums/node-transformers/NodeTransformationStage';
6✔
12

13
import { AbstractStatementSimplifyTransformer } from './AbstractStatementSimplifyTransformer';
6✔
14
import { NodeGuards } from '../../node/NodeGuards';
6✔
15
import { NodeFactory } from '../../node/NodeFactory';
6✔
16
import { NodeUtils } from '../../node/NodeUtils';
6✔
17

18
/**
19
 * Simplifies `IfStatement` node
20
 */
21
@injectable()
22
export class IfStatementSimplifyTransformer extends AbstractStatementSimplifyTransformer {
6✔
23
    /**
24
     * @param {IRandomGenerator} randomGenerator
25
     * @param {IOptions} options
26
     */
27
    public constructor(
28
        @inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
29
        @inject(ServiceIdentifiers.IOptions) options: IOptions
30
    ) {
31
        super(randomGenerator, options);
197,808✔
32
    }
33

34
    /**
35
     * @param {NodeTransformationStage} nodeTransformationStage
36
     * @returns {IVisitor | null}
37
     */
38
    public getVisitor(nodeTransformationStage: NodeTransformationStage): IVisitor | null {
39
        switch (nodeTransformationStage) {
1,434,528✔
40
            case NodeTransformationStage.Simplifying:
1,434,528✔
41
                return {
38,988✔
42
                    leave: (node: ESTree.Node, parentNode: ESTree.Node | null): ESTree.Node | undefined => {
43
                        if (parentNode && NodeGuards.isIfStatementNode(node)) {
350,135,044✔
44
                            return this.transformNode(node, parentNode);
213,307✔
45
                        }
46
                    }
47
                };
48

49
            default:
50
                return null;
1,395,540✔
51
        }
52
    }
53

54
    /**
55
     * @param {ESTree.IfStatement} ifStatementNode
56
     * @param {ESTree.Node} parentNode
57
     * @returns {ESTree.IfStatement}
58
     */
59
    public transformNode(ifStatementNode: ESTree.IfStatement, parentNode: ESTree.Node): ESTree.Node {
60
        const consequentSimplifyData: IStatementSimplifyData | null = this.getStatementSimplifyData(
213,307✔
61
            ifStatementNode.consequent
62
        );
63

64
        // Variant #1: no valid consequent expression data
65
        if (!consequentSimplifyData) {
213,307!
66
            return ifStatementNode;
×
67
        }
68

69
        let transformedNode: ESTree.Node;
70

71
        if (!ifStatementNode.alternate) {
213,307✔
72
            // Variant #2: valid data for consequent expression only
73
            transformedNode = this.getConsequentNode(ifStatementNode, consequentSimplifyData);
83,509✔
74
        } else {
75
            const alternateSimplifyData: IStatementSimplifyData | null = this.getStatementSimplifyData(
129,798✔
76
                ifStatementNode.alternate
77
            );
78

79
            if (!alternateSimplifyData) {
129,798!
80
                return ifStatementNode;
×
81
            }
82

83
            // Variant #3: valid data for consequent and alternate expressions
84
            transformedNode = this.getConsequentAndAlternateNode(
129,798✔
85
                ifStatementNode,
86
                consequentSimplifyData,
87
                alternateSimplifyData
88
            );
89
        }
90

91
        return NodeUtils.parentizeNode(transformedNode, parentNode);
213,307✔
92
    }
93

94
    /**
95
     * @param {ESTree.IfStatement} ifStatementNode
96
     * @param {IStatementSimplifyData} consequentSimplifyData
97
     * @returns {ESTree.Node}
98
     */
99
    protected getConsequentNode(
100
        ifStatementNode: ESTree.IfStatement,
101
        consequentSimplifyData: IStatementSimplifyData
102
    ): ESTree.Node {
103
        /**
104
         * Converts:
105
         * if (true) {
106
         *     const foo = 1;
107
         *     console.log(1);
108
         *     return 1;
109
         * }
110
         *
111
         * to:
112
         * if (true) {
113
         *     const foo = 1;
114
         *     return console.log(1), 1;
115
         * }
116
         */
117
        if (consequentSimplifyData.leadingStatements.length || !consequentSimplifyData.trailingStatement) {
83,509✔
118
            return NodeFactory.ifStatementNode(ifStatementNode.test, this.getPartialStatement(consequentSimplifyData));
78,386✔
119
        }
120

121
        /**
122
         * Converts:
123
         * if (true) {
124
         *     return 1;
125
         * }
126
         *
127
         * to:
128
         * if (true)
129
         *     return 1;
130
         */
131
        if (consequentSimplifyData.hasReturnStatement) {
5,123✔
132
            return NodeFactory.ifStatementNode(
1,899✔
133
                ifStatementNode.test,
134
                consequentSimplifyData.trailingStatement.statement
135
            );
136
        }
137

138
        /**
139
         * Converts:
140
         * if (true) {
141
         *     console.log(1);
142
         * }
143
         *
144
         * to:
145
         * true && console.log(1);
146
         */
147
        return NodeFactory.expressionStatementNode(
3,224✔
148
            NodeFactory.logicalExpressionNode(
149
                '&&',
150
                ifStatementNode.test,
151
                consequentSimplifyData.trailingStatement.expression
152
            )
153
        );
154
    }
155

156
    /**
157
     * @param {ESTree.IfStatement} ifStatementNode
158
     * @param {IStatementSimplifyData} consequentSimplifyData
159
     * @param {IStatementSimplifyData} alternateSimplifyData
160
     * @returns {ESTree.Node}
161
     */
162
    protected getConsequentAndAlternateNode(
163
        ifStatementNode: ESTree.IfStatement,
164
        consequentSimplifyData: IStatementSimplifyData,
165
        alternateSimplifyData: IStatementSimplifyData
166
    ): ESTree.Node {
167
        /**
168
         * Converts:
169
         * if (true) {
170
         *     const foo = 1;
171
         *     console.log(1);
172
         *     return 1;
173
         * }
174
         *
175
         * to:
176
         * if (true) {
177
         *     const foo = 1;
178
         *     return console.log(1), 1;
179
         * }
180
         */
181
        if (
129,798✔
182
            consequentSimplifyData.leadingStatements.length ||
220,067✔
183
            alternateSimplifyData.leadingStatements.length ||
184
            !consequentSimplifyData.trailingStatement ||
185
            !alternateSimplifyData.trailingStatement
186
        ) {
187
            return NodeFactory.ifStatementNode(
107,817✔
188
                ifStatementNode.test,
189
                this.getPartialStatement(consequentSimplifyData),
190
                this.getPartialStatement(alternateSimplifyData)
191
            );
192
        }
193

194
        /**
195
         * Converts:
196
         * if (true) {
197
         *     return 1;
198
         * } else {
199
         *     return 2;
200
         * }
201
         *
202
         * to:
203
         * return true ? 1 : 2;
204
         */
205
        if (consequentSimplifyData.hasReturnStatement && alternateSimplifyData.hasReturnStatement) {
21,981✔
206
            return NodeFactory.returnStatementNode(
3,069✔
207
                NodeFactory.conditionalExpressionNode(
208
                    ifStatementNode.test,
209
                    consequentSimplifyData.trailingStatement.expression,
210
                    alternateSimplifyData.trailingStatement.expression
211
                )
212
            );
213
        }
214

215
        /**
216
         * Converts:
217
         * if (true) {
218
         *     return 1;
219
         * } else {
220
         *     console.log(2);
221
         * }
222
         *
223
         * to:
224
         * if (true)
225
         *     return 1;
226
         * else
227
         *     console.log(2);
228
         */
229
        if (consequentSimplifyData.hasReturnStatement || alternateSimplifyData.hasReturnStatement) {
18,912✔
230
            return NodeFactory.ifStatementNode(
9,046✔
231
                ifStatementNode.test,
232
                consequentSimplifyData.trailingStatement.statement,
233
                alternateSimplifyData.trailingStatement.statement
234
            );
235
        }
236

237
        /**
238
         * Converts:
239
         * if (true) {
240
         *     console.log(1);
241
         * } else {
242
         *     console.log(2);
243
         * }
244
         *
245
         * to:
246
         * true ? console.log(1) : console.log(2);
247
         */
248
        return NodeFactory.expressionStatementNode(
9,866✔
249
            NodeFactory.conditionalExpressionNode(
250
                ifStatementNode.test,
251
                consequentSimplifyData.trailingStatement.expression,
252
                alternateSimplifyData.trailingStatement.expression
253
            )
254
        );
255
    }
256

257
    /**
258
     * @param {IStatementSimplifyData} statementSimplifyData
259
     * @returns {ESTree.Statement}
260
     */
261
    protected override getPartialStatement(statementSimplifyData: IStatementSimplifyData): ESTree.Statement {
262
        const partialStatement: ESTree.Statement = super.getPartialStatement(statementSimplifyData);
294,020✔
263

264
        if (!NodeGuards.isBlockStatementNode(partialStatement)) {
294,020✔
265
            return partialStatement;
55,391✔
266
        }
267

268
        return partialStatement.body.length === 1 &&
238,629✔
269
            !this.isProhibitedSingleStatementForIfStatementBranch(partialStatement.body[0])
270
            ? partialStatement.body[0]
238,629✔
271
            : partialStatement;
272
    }
273

274
    /**
275
     * @param {ESTree.Statement} statement
276
     * @returns {boolean}
277
     */
278
    protected isProhibitedSingleStatementForIfStatementBranch(statement: ESTree.Statement): boolean {
279
        /**
280
         * Function declaration is not allowed outside of block in `strict` mode
281
         */
282
        return (
115,388✔
283
            NodeGuards.isFunctionDeclarationNode(statement) ||
384,254✔
284
            /**
285
             * Have to ignore all `IfStatement` nodes
286
             * Also have to ignore any nodes with a single statement as a `body`
287
             * Without ignore it can break following code:
288
             * Input:
289
             * if (condition1) {
290
             *     if (condition2) {
291
             *         var foo = bar();
292
             *     }
293
             * } else {
294
             *     var baz = bark();
295
             * }
296
             *
297
             * Invalid output:
298
             * if (condition1)
299
             *     if (condition2)
300
             *         var foo = bar();
301
             *     else
302
             *         var baz = bark();
303
             *
304
             * See issue: https://github.com/javascript-obfuscator/javascript-obfuscator/issues/860
305
             */
306
            NodeGuards.isIfStatementNode(statement) ||
307
            NodeGuards.isNodeWithSingleStatementBody(statement) ||
308
            /**
309
             * `let` and `const` variable declarations are not allowed outside of `IfStatement` block statement
310
             * Input:
311
             * if (condition1) {
312
             *     const foo = 1;
313
             * }
314
             *
315
             * Invalid output with runtime error:
316
             * if (condition1)
317
             *     const foo = 1;
318
             */
319
            (NodeGuards.isVariableDeclarationNode(statement) && statement.kind !== 'var')
320
        );
321
    }
322
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc