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

javascript-obfuscator / javascript-obfuscator / 21554265507

27 Jan 2026 09:04PM UTC coverage: 96.658%. Remained the same
21554265507

push

github

web-flow
Fix identifiers generation (#1378)

1895 of 2050 branches covered (92.44%)

Branch coverage included in aggregate %.

35 of 36 new or added lines in 3 files covered. (97.22%)

6 existing lines in 2 files now uncovered.

5885 of 5999 relevant lines covered (98.1%)

30842424.18 hits per line

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

98.82
/src/generators/identifier-names-generators/DictionaryIdentifierNamesGenerator.ts
1
import { inject, injectable } from 'inversify';
6✔
2
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
6✔
3

4
import { IArrayUtils } from '../../interfaces/utils/IArrayUtils';
5
import { IOptions } from '../../interfaces/options/IOptions';
6
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
7

8
import { AbstractIdentifierNamesGenerator } from './AbstractIdentifierNamesGenerator';
6✔
9
import { TNodeWithLexicalScope } from '../../types/node/TNodeWithLexicalScope';
10
import { NodeLexicalScopeUtils } from '../../node/NodeLexicalScopeUtils';
6✔
11

12
@injectable()
13
export class DictionaryIdentifierNamesGenerator extends AbstractIdentifierNamesGenerator {
6✔
14
    /**
15
     * @type {IArrayUtils}
16
     */
17
    private readonly arrayUtils: IArrayUtils;
18

19
    /**
20
     * @type {Set<string>}
21
     */
22
    private identifierNamesSet: Set<string>;
23

24
    /**
25
     * @type {IterableIterator<string>}
26
     */
27
    private identifiersIterator: IterableIterator<string>;
28

29
    /**
30
     * @param {IRandomGenerator} randomGenerator
31
     * @param {IOptions} options
32
     * @param {IArrayUtils} arrayUtils
33
     */
34
    public constructor(
35
        @inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
36
        @inject(ServiceIdentifiers.IOptions) options: IOptions,
37
        @inject(ServiceIdentifiers.IArrayUtils) arrayUtils: IArrayUtils
38
    ) {
39
        super(randomGenerator, options);
1,176✔
40

41
        this.arrayUtils = arrayUtils;
1,176✔
42
        this.identifierNamesSet = new Set(this.getInitialIdentifierNames(this.options.identifiersDictionary));
1,176✔
43
        this.identifiersIterator = this.identifierNamesSet.values();
1,176✔
44
    }
45

46
    /**
47
     * @param {string} identifierName
48
     * @returns {string | null}
49
     */
50
    private static incrementIdentifierName(identifierName: string): string | null {
51
        let newIdentifierName: string = '';
3,948✔
52
        let isSuccess: boolean = false;
3,948✔
53

54
        for (const character of identifierName) {
3,948✔
55
            if (!isSuccess && character === character.toUpperCase()) {
9,846✔
56
                newIdentifierName += character.toLowerCase();
84✔
57
            } else if (!isSuccess && character === character.toLowerCase()) {
9,762✔
58
                newIdentifierName += character.toUpperCase();
3,942✔
59
                isSuccess = true;
3,942✔
60
            } else {
61
                newIdentifierName += character;
5,820✔
62
            }
63
        }
64

65
        if (isSuccess) {
3,948✔
66
            return newIdentifierName;
3,942✔
67
        }
68

69
        return null;
6✔
70
    }
71

72
    public generateNext(): string {
73
        const identifierName: string = this.generateNewDictionaryName();
1,008✔
74

75
        this.preserveName(identifierName);
996✔
76

77
        return identifierName;
996✔
78
    }
79

80
    /**
81
     * @returns {string}
82
     */
83
    public generateForGlobalScope(): string {
84
        return this.generateForGlobalScopeInternal((name) => this.isValidIdentifierName(name));
1,524✔
85
    }
86

87
    /**
88
     * @returns {string}
89
     */
90
    public generateForGlobalScopeWithAllScopesValidation(): string {
NEW
91
        return this.generateForGlobalScopeInternal((name) => this.isValidIdentifierNameInAllScopes(name));
×
92
    }
93

94
    /**
95
     * @param {TNodeWithLexicalScope} lexicalScopeNode
96
     * @returns {string}
97
     */
98
    public generateForLexicalScope(lexicalScopeNode: TNodeWithLexicalScope): string {
99
        const lexicalScopes: TNodeWithLexicalScope[] = [
4,104✔
100
            lexicalScopeNode,
101
            ...NodeLexicalScopeUtils.getLexicalScopes(lexicalScopeNode)
102
        ];
103
        const identifierName: string = this.generateNewDictionaryName((newIdentifierName: string) =>
4,104✔
104
            this.isValidIdentifierNameInLexicalScopes(newIdentifierName, lexicalScopes)
4,767✔
105
        );
106

107
        this.preserveNameForLexicalScope(identifierName, lexicalScopeNode);
4,104✔
108

109
        return identifierName;
4,104✔
110
    }
111

112
    /**
113
     * @param {string} label
114
     * @returns {string}
115
     */
116
    public generateForLabel(label: string): string {
117
        return this.generateNewDictionaryName();
36✔
118
    }
119

120
    /**
121
     * @param {(name: string) => boolean} validationFn
122
     * @returns {string}
123
     */
124
    private generateForGlobalScopeInternal(validationFn: (name: string) => boolean): string {
125
        const prefix: string = this.options.identifiersPrefix ? `${this.options.identifiersPrefix}` : '';
1,500✔
126

127
        const identifierName: string = this.generateNewDictionaryName((newIdentifierName: string) => {
1,500✔
128
            const identifierNameWithPrefix: string = `${prefix}${newIdentifierName}`;
1,524✔
129

130
            return validationFn(identifierNameWithPrefix);
1,524✔
131
        });
132
        const identifierNameWithPrefix = `${prefix}${identifierName}`;
1,500✔
133

134
        this.preserveName(identifierNameWithPrefix);
1,500✔
135

136
        return identifierNameWithPrefix;
1,500✔
137
    }
138

139
    /**
140
     * @param {(newIdentifierName: string) => boolean} validationFunction
141
     * @returns {string}
142
     */
143
    private generateNewDictionaryName(validationFunction?: (newIdentifierName: string) => boolean): string {
144
        const generateNewDictionaryName = (): string => {
6,648✔
145
            if (!this.identifierNamesSet.size) {
8,349✔
146
                throw new Error('Too many identifiers in the code, add more words to identifiers dictionary');
12✔
147
            }
148

149
            const iteratorResult: IteratorResult<string> = this.identifiersIterator.next();
8,337✔
150

151
            if (!iteratorResult.done) {
8,337✔
152
                const identifierName: string = iteratorResult.value;
7,323✔
153

154
                const isValidIdentifierName =
155
                    validationFunction?.(identifierName) ?? this.isValidIdentifierName(identifierName);
7,323✔
156

157
                if (!isValidIdentifierName) {
7,323✔
158
                    return generateNewDictionaryName();
687✔
159
                }
160

161
                return iteratorResult.value;
6,636✔
162
            }
163

164
            this.identifierNamesSet = new Set(this.getIncrementedIdentifierNames([...this.identifierNamesSet]));
1,014✔
165
            this.identifiersIterator = this.identifierNamesSet.values();
1,014✔
166

167
            return generateNewDictionaryName();
1,014✔
168
        };
169

170
        return generateNewDictionaryName();
6,648✔
171
    }
172

173
    /**
174
     * @param {string[]} identifierNames
175
     * @returns {string[]}
176
     */
177
    private getInitialIdentifierNames(identifierNames: string[]): string[] {
178
        const formattedIdentifierNames: string[] = identifierNames
1,176✔
179
            .filter(Boolean)
180
            .map((identifierName: string) => identifierName.toLowerCase());
5,322✔
181

182
        return this.arrayUtils.shuffle(formattedIdentifierNames);
1,176✔
183
    }
184

185
    /**
186
     * @param {string[]} identifierNames
187
     * @returns {string[]}
188
     */
189
    private getIncrementedIdentifierNames(identifierNames: string[]): string[] {
190
        const formattedIdentifierNames: string[] = [];
1,014✔
191

192
        for (const identifierName of identifierNames) {
1,014✔
193
            const newIdentifierName: string | null =
194
                DictionaryIdentifierNamesGenerator.incrementIdentifierName(identifierName);
3,948✔
195

196
            if (newIdentifierName) {
3,948✔
197
                formattedIdentifierNames.push(newIdentifierName);
3,942✔
198
            }
199
        }
200

201
        return this.arrayUtils.shuffle(formattedIdentifierNames);
1,014✔
202
    }
203
}
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