• 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

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

4
import * as estraverse from '@javascript-obfuscator/estraverse';
6✔
5
import * as ESTree from 'estree';
6
import * as stringz from 'stringz';
6✔
7

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

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

15
import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
6✔
16
import { NodeFactory } from '../../node/NodeFactory';
6✔
17
import { NodeGuards } from '../../node/NodeGuards';
6✔
18
import { NodeLiteralUtils } from '../../node/NodeLiteralUtils';
6✔
19
import { NodeUtils } from '../../node/NodeUtils';
6✔
20

21
/**
22
 * Splits strings into parts
23
 */
24
@injectable()
25
export class SplitStringTransformer extends AbstractNodeTransformer {
6✔
26
    /**
27
     * @type {number}
28
     */
29
    private static readonly firstPassChunkLength: number = 1000;
6✔
30

31
    /**
32
     * @type {NodeTransformer[]}
33
     */
34
    public override runAfter: NodeTransformer[] = [
197,808✔
35
        NodeTransformer.ObjectExpressionKeysTransformer,
36
        NodeTransformer.TemplateLiteralTransformer
37
    ];
38

39
    /**
40
     * @param {IRandomGenerator} randomGenerator
41
     * @param {IOptions} options
42
     */
43
    public constructor(
44
        @inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
45
        @inject(ServiceIdentifiers.IOptions) options: IOptions
46
    ) {
47
        super(randomGenerator, options);
197,808✔
48
    }
49

50
    /**
51
     * @param {string} string
52
     * @param {number} stringLength
53
     * @param {number} chunkSize
54
     * @returns {string[]}
55
     */
56
    private static chunkString(string: string, stringLength: number, chunkSize: number): string[] {
57
        const chunksCount: number = Math.ceil(stringLength / chunkSize);
2,489,112✔
58
        const chunks: string[] = [];
2,489,112✔
59

60
        let nextChunkStartIndex: number = 0;
2,489,112✔
61

62
        for (let chunkIndex: number = 0; chunkIndex < chunksCount; ++chunkIndex, nextChunkStartIndex += chunkSize) {
2,489,112✔
63
            // eslint-disable-next-line unicorn/prefer-string-slice
64
            chunks[chunkIndex] = stringz.substr(string, nextChunkStartIndex, chunkSize);
9,878,089✔
65
        }
66

67
        return chunks;
2,489,112✔
68
    }
69

70
    /**
71
     * @param {NodeTransformationStage} nodeTransformationStage
72
     * @returns {IVisitor | null}
73
     */
74
    public getVisitor(nodeTransformationStage: NodeTransformationStage): IVisitor | null {
75
        if (!this.options.splitStrings) {
1,415,778✔
76
            return null;
1,408,056✔
77
        }
78

79
        switch (nodeTransformationStage) {
7,722✔
80
            case NodeTransformationStage.Converting:
7,722✔
81
                return {
1,488✔
82
                    enter: (node: ESTree.Node, parentNode: ESTree.Node | null): ESTree.Node | undefined => {
83
                        if (parentNode && NodeGuards.isLiteralNode(node)) {
36,702,733✔
84
                            return this.transformNode(node, parentNode);
14,775,599✔
85
                        }
86
                    }
87
                };
88

89
            default:
90
                return null;
6,234✔
91
        }
92
    }
93

94
    /**
95
     * Needs to split string on chunks of length `splitStringsChunkLength` in two pass, because of
96
     * `Maximum call stack size exceeded` error in `esrecurse` package
97
     *
98
     * @param {Literal} literalNode
99
     * @param {Node} parentNode
100
     * @returns {Node}
101
     */
102
    public transformNode(literalNode: ESTree.Literal, parentNode: ESTree.Node): ESTree.Node {
103
        if (NodeLiteralUtils.isProhibitedLiteralNode(literalNode, parentNode)) {
14,775,599✔
104
            return literalNode;
828,463✔
105
        }
106

107
        // pass #1: split string on a large chunks with length of `firstPassChunkLength`
108
        const firstPassChunksNode: ESTree.Node = this.transformLiteralNodeByChunkLength(
13,947,136✔
109
            literalNode,
110
            SplitStringTransformer.firstPassChunkLength
111
        );
112

113
        // pass #2: split large chunks on a chunks with length of `splitStringsChunkLength`
114
        const secondPassChunksNode: ESTree.Node = estraverse.replace(firstPassChunksNode, {
13,947,136✔
115
            // eslint-disable-next-line @typescript-eslint/no-shadow
116
            enter: (node: ESTree.Node, parentNode: ESTree.Node | null) => {
117
                if (NodeGuards.isLiteralNode(node)) {
28,725,090✔
118
                    return this.transformLiteralNodeByChunkLength(node, this.options.splitStringsChunkLength);
23,825,146✔
119
                }
120
            }
121
        });
122

123
        NodeUtils.parentizeNode(secondPassChunksNode, parentNode);
13,947,136✔
124
        NodeUtils.parentizeAst(secondPassChunksNode);
13,947,136✔
125

126
        return secondPassChunksNode;
13,947,136✔
127
    }
128

129
    /**
130
     * @param {Literal} literalNode
131
     * @param {number} chunkLength
132
     * @returns {Node}
133
     */
134
    private transformLiteralNodeByChunkLength(literalNode: ESTree.Literal, chunkLength: number): ESTree.Node {
135
        if (!NodeLiteralUtils.isStringLiteralNode(literalNode)) {
37,772,282✔
136
            return literalNode;
2,969,844✔
137
        }
138

139
        const valueLength: number = stringz.length(literalNode.value);
34,802,438✔
140

141
        if (chunkLength >= valueLength) {
34,802,438✔
142
            return literalNode;
32,313,326✔
143
        }
144

145
        const stringChunks: string[] = SplitStringTransformer.chunkString(literalNode.value, valueLength, chunkLength);
2,489,112✔
146

147
        return this.transformStringChunksToBinaryExpressionNode(stringChunks);
2,489,112✔
148
    }
149

150
    /**
151
     * @param {string[]} chunks
152
     * @returns {BinaryExpression}
153
     */
154
    private transformStringChunksToBinaryExpressionNode(chunks: string[]): ESTree.BinaryExpression {
155
        const firstChunk: string | undefined = chunks.shift();
2,489,112✔
156
        const secondChunk: string | undefined = chunks.shift();
2,489,112✔
157

158
        if (!firstChunk || !secondChunk) {
2,489,112!
159
            throw new Error('First and second chunks values should not be empty');
×
160
        }
161

162
        const initialBinaryExpressionNode: ESTree.BinaryExpression = NodeFactory.binaryExpressionNode(
2,489,112✔
163
            '+',
164
            NodeFactory.literalNode(firstChunk),
165
            NodeFactory.literalNode(secondChunk)
166
        );
167

168
        return chunks.reduce<ESTree.BinaryExpression>(
2,489,112✔
169
            (binaryExpressionNode: ESTree.BinaryExpression, chunk: string) => {
170
                const chunkLiteralNode: ESTree.Literal = NodeFactory.literalNode(chunk);
4,899,865✔
171

172
                return NodeFactory.binaryExpressionNode('+', binaryExpressionNode, chunkLiteralNode);
4,899,865✔
173
            },
174
            initialBinaryExpressionNode
175
        );
176
    }
177
}
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