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

javascript-obfuscator / javascript-obfuscator / 21638611094

03 Feb 2026 04:23PM UTC coverage: 96.273% (-0.4%) from 96.658%
21638611094

push

github

sanex3339
Set version 5.3.0 to beta

1924 of 2096 branches covered (91.79%)

Branch coverage included in aggregate %.

5955 of 6088 relevant lines covered (97.82%)

30517016.95 hits per line

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

89.71
/src/cli/JavaScriptObfuscatorCLI.ts
1
/* eslint-disable max-lines */
2
import * as commander from 'commander';
6✔
3
import * as path from 'path';
6✔
4

5
import { TInputCLIOptions } from '../types/options/TInputCLIOptions';
6
import { TInputOptions } from '../types/options/TInputOptions';
7

8
import { IFileData } from '../interfaces/cli/IFileData';
9
import { IInitializable } from '../interfaces/IInitializable';
10
import { IObfuscationResult } from '../interfaces/source-code/IObfuscationResult';
11
import { ProApiClient } from '../pro-api/ProApiClient';
6✔
12
import { IProObfuscationResult } from '../interfaces/pro-api/IProApiClient';
13

14
import { initializable } from '../decorators/Initializable';
6✔
15

16
import { IdentifierNamesGenerator } from '../enums/generators/identifier-names-generators/IdentifierNamesGenerator';
6✔
17
import { LoggingPrefix } from '../enums/logger/LoggingPrefix';
6✔
18
import { ObfuscationTarget } from '../enums/ObfuscationTarget';
6✔
19
import { OptionsPreset } from '../enums/options/presets/OptionsPreset';
6✔
20
import { RenamePropertiesMode } from '../enums/node-transformers/rename-properties-transformers/RenamePropertiesMode';
6✔
21
import { SourceMapMode } from '../enums/source-map/SourceMapMode';
6✔
22
import { SourceMapSourcesMode } from '../enums/source-map/SourceMapSourcesMode';
6✔
23
import { StringArrayEncoding } from '../enums/node-transformers/string-array-transformers/StringArrayEncoding';
6✔
24
import { StringArrayIndexesType } from '../enums/node-transformers/string-array-transformers/StringArrayIndexesType';
6✔
25
import { StringArrayWrappersType } from '../enums/node-transformers/string-array-transformers/StringArrayWrappersType';
6✔
26

27
import { DEFAULT_PRESET } from '../options/presets/Default';
6✔
28

29
import { ArraySanitizer } from './sanitizers/ArraySanitizer';
6✔
30
import { BooleanSanitizer } from './sanitizers/BooleanSanitizer';
6✔
31

32
import { CLIUtils } from './utils/CLIUtils';
6✔
33
import { IdentifierNamesCacheFileUtils } from './utils/IdentifierNamesCacheFileUtils';
6✔
34
import { JavaScriptObfuscator } from '../JavaScriptObfuscatorFacade';
6✔
35
import { Logger } from '../logger/Logger';
6✔
36
import { ObfuscatedCodeFileUtils } from './utils/ObfuscatedCodeFileUtils';
6✔
37
import { SourceCodeFileUtils } from './utils/SourceCodeFileUtils';
6✔
38
import { Utils } from '../utils/Utils';
6✔
39
import { VMTargetFunctionsMode } from '../pro-api/enums/VMTargetFunctionsMode';
6✔
40
import { VMBytecodeFormat } from '../pro-api/enums/VMBytecodeFormat';
6✔
41
import { StrictModeSanitizer } from './sanitizers/StrictModeSanitizer';
6✔
42

43
export class JavaScriptObfuscatorCLI implements IInitializable {
6✔
44
    /**
45
     * @type {string[]}
46
     */
47
    public static readonly availableInputExtensions: string[] = ['.js', '.mjs', '.cjs'];
6✔
48

49
    /**
50
     * @type {BufferEncoding}
51
     */
52
    public static readonly encoding: BufferEncoding = 'utf8';
6✔
53

54
    /**
55
     * @type {string}
56
     */
57
    public static readonly obfuscatedFilePrefix: string = '-obfuscated';
6✔
58

59
    /**
60
     * @type {commander.Command}
61
     */
62
    @initializable()
63
    private commands!: commander.Command;
6✔
64

65
    /**
66
     * @type {IdentifierNamesCacheFileUtils}
67
     */
68
    @initializable()
69
    private identifierNamesCacheFileUtils!: IdentifierNamesCacheFileUtils;
6✔
70

71
    /**
72
     * @type {TInputCLIOptions}
73
     */
74
    @initializable()
75
    private inputCLIOptions!: TInputCLIOptions;
6✔
76

77
    /**
78
     * @type {string}
79
     */
80
    @initializable()
81
    private inputPath!: string;
6✔
82

83
    /**
84
     * @type {SourceCodeFileUtils}
85
     */
86
    @initializable()
87
    private sourceCodeFileUtils!: SourceCodeFileUtils;
6✔
88

89
    /**
90
     * @type {ObfuscatedCodeFileUtils}
91
     */
92
    @initializable()
93
    private obfuscatedCodeFileUtils!: ObfuscatedCodeFileUtils;
6✔
94

95
    /**
96
     * @type {string[]}
97
     */
98
    private readonly arguments: string[];
99

100
    /**
101
     * @type {string[]}
102
     */
103
    private readonly rawArguments: string[];
104

105
    /**
106
     * @param {string[]} argv
107
     */
108
    public constructor(argv: string[]) {
109
        this.rawArguments = argv;
198✔
110
        this.arguments = argv.slice(2);
198✔
111
    }
112

113
    /**
114
     * @param {TInputCLIOptions} inputOptions
115
     * @returns {TInputOptions}
116
     */
117
    private static buildOptions(inputOptions: TInputCLIOptions): TInputOptions {
118
        const inputCLIOptions: TInputOptions = JavaScriptObfuscatorCLI.filterOptions(inputOptions);
198✔
119
        const configFilePath: string | undefined = inputOptions.config;
198✔
120
        const configFileLocation: string = configFilePath ? path.resolve(configFilePath, '.') : '';
198✔
121
        const configFileOptions: TInputOptions = configFileLocation ? CLIUtils.getUserConfig(configFileLocation) : {};
198✔
122

123
        return {
198✔
124
            ...DEFAULT_PRESET,
125
            ...configFileOptions,
126
            ...inputCLIOptions
127
        };
128
    }
129

130
    /**
131
     * @param {TObject} options
132
     * @returns {TInputOptions}
133
     */
134
    private static filterOptions(options: TInputCLIOptions): TInputOptions {
135
        const filteredOptions: TInputOptions = {};
198✔
136

137
        Object.keys(options).forEach((option: keyof TInputCLIOptions) => {
198✔
138
            if (options[option] === undefined) {
480!
139
                return;
×
140
            }
141

142
            filteredOptions[option] = options[option];
480✔
143
        });
144

145
        return filteredOptions;
198✔
146
    }
147

148
    public initialize(): void {
149
        this.commands = new commander.Command();
198✔
150

151
        this.configureCommands();
198✔
152
        this.configureHelp();
198✔
153

154
        this.inputPath = path.normalize(this.commands.args[0] || '');
198✔
155
        this.inputCLIOptions = JavaScriptObfuscatorCLI.buildOptions(this.commands.opts());
198✔
156
        this.sourceCodeFileUtils = new SourceCodeFileUtils(this.inputPath, this.inputCLIOptions);
198✔
157
        this.obfuscatedCodeFileUtils = new ObfuscatedCodeFileUtils(this.inputPath, this.inputCLIOptions);
198✔
158
        this.identifierNamesCacheFileUtils = new IdentifierNamesCacheFileUtils(
198✔
159
            this.inputCLIOptions.identifierNamesCachePath
160
        );
161
    }
162

163
    public async run(): Promise<void> {
164
        const canShowHelp: boolean = !this.arguments.length || this.arguments.includes('--help');
198✔
165

166
        if (canShowHelp) {
198✔
167
            this.commands.outputHelp();
24✔
168

169
            return;
24✔
170
        }
171

172
        const sourceCodeData: IFileData[] = this.sourceCodeFileUtils.readSourceCode();
174✔
173

174
        await this.processSourceCodeData(sourceCodeData);
156✔
175
    }
176

177
    private configureCommands(): void {
178
        this.commands
198✔
179
            .usage('<inputPath> [options]')
180
            .version(Utils.buildVersionMessage(process.env.VERSION, process.env.BUILD_TIMESTAMP), '-v, --version')
181
            .option('-o, --output <path>', 'Output path for obfuscated code')
182
            .option('--compact <boolean>', 'Disable one line output code compacting', BooleanSanitizer)
183
            .option('--config <boolean>', 'Name of js / json config file')
184
            .option('--control-flow-flattening <boolean>', 'Enables control flow flattening', BooleanSanitizer)
185
            .option(
186
                '--control-flow-flattening-threshold <number>',
187
                'The probability that the control flow flattening transformation will be applied to the node',
188
                parseFloat
189
            )
190
            .option('--dead-code-injection <boolean>', 'Enables dead code injection', BooleanSanitizer)
191
            .option(
192
                '--dead-code-injection-threshold <number>',
193
                'The probability that the dead code injection transformation will be applied to the node',
194
                parseFloat
195
            )
196
            .option(
197
                '--debug-protection <boolean>',
198
                'Disable browser Debug panel (can cause DevTools enabled browser freeze)',
199
                BooleanSanitizer
200
            )
201
            .option(
202
                '--debug-protection-interval <number>',
203
                'Sets interval in milliseconds for debug protection so it is working even after page was loaded (can cause DevTools enabled browser freeze)',
204
                parseInt
205
            )
206
            .option(
207
                '--disable-console-output <boolean>',
208
                'Allow console.log, console.info, console.error and console.warn messages output into browser console',
209
                BooleanSanitizer
210
            )
211
            .option(
212
                '--domain-lock <list> (comma separated, without whitespaces)',
213
                'Allows to run the obfuscated source code only on specific domains and/or sub-domains (comma separated)',
214
                ArraySanitizer
215
            )
216
            .option(
217
                '--domain-lock-redirect-url <string>',
218
                "Allows the browser to be redirected to a passed URL if the source code isn't run on the domains specified by --domain-lock"
219
            )
220
            .option(
221
                '--exclude <list> (comma separated, without whitespaces)',
222
                'A filename or glob which indicates files to exclude from obfuscation',
223
                ArraySanitizer
224
            )
225
            .option(
226
                '--force-transform-strings <list> (comma separated, without whitespaces)',
227
                'Enables force transformation of string literals, which being matched by passed RegExp patterns (comma separated)',
228
                ArraySanitizer
229
            )
230
            .option('--identifier-names-cache-path <string>', 'Sets path for identifier names cache')
231
            .option(
232
                '--identifier-names-generator <string>',
233
                'Sets identifier names generator. ' +
234
                    `Values: ${CLIUtils.stringifyOptionAvailableValues(IdentifierNamesGenerator)}. ` +
235
                    `Default: ${IdentifierNamesGenerator.HexadecimalIdentifierNamesGenerator}`
236
            )
237
            .option('--identifiers-prefix <string>', 'Sets prefix for all global identifiers')
238
            .option(
239
                '--identifiers-dictionary <list> (comma separated, without whitespaces)',
240
                'Identifiers dictionary (comma separated) for `--identifier-names-generator dictionary` option',
241
                ArraySanitizer
242
            )
243
            .option(
244
                '--ignore-imports <boolean>',
245
                'Prevents obfuscation of `require` and `dynamic` imports',
246
                BooleanSanitizer
247
            )
248
            .option('--log <boolean>', 'Enables logging of the information to the console', BooleanSanitizer)
249
            .option('--numbers-to-expressions <boolean>', 'Enables numbers conversion to expressions', BooleanSanitizer)
250
            .option(
251
                '--options-preset <string>',
252
                'Allows to set options preset. ' +
253
                    `Values: ${CLIUtils.stringifyOptionAvailableValues(OptionsPreset)}. ` +
254
                    `Default: ${OptionsPreset.Default}`
255
            )
256
            .option(
257
                '--reserved-names <list> (comma separated, without whitespaces)',
258
                'Disables obfuscation and generation of identifiers, which being matched by passed RegExp patterns (comma separated)',
259
                ArraySanitizer
260
            )
261
            .option(
262
                '--reserved-strings <list> (comma separated, without whitespaces)',
263
                'Disables transformation of string literals, which being matched by passed RegExp patterns (comma separated)',
264
                ArraySanitizer
265
            )
266
            .option(
267
                '--rename-globals <boolean>',
268
                'Allows to enable obfuscation of global variable and function names with declaration',
269
                BooleanSanitizer
270
            )
271
            .option(
272
                '--rename-properties <boolean>',
273
                'UNSAFE: Enables renaming of property names. This probably MAY break your code',
274
                BooleanSanitizer
275
            )
276
            .option(
277
                '--rename-properties-mode <boolean>',
278
                'Specify `--rename-properties` option mode. ' +
279
                    `Values: ${CLIUtils.stringifyOptionAvailableValues(RenamePropertiesMode)}. ` +
280
                    `Default: ${RenamePropertiesMode.Safe}`
281
            )
282
            .option(
283
                '--seed <string|number>',
284
                'Sets seed for random generator. This is useful for creating repeatable results.',
285
                parseFloat
286
            )
287
            .option('--self-defending <boolean>', 'Disables self-defending for obfuscated code', BooleanSanitizer)
288
            .option(
289
                '--simplify <boolean>',
290
                'Enables additional code obfuscation through simplification',
291
                BooleanSanitizer
292
            )
293
            .option('--source-map <boolean>', 'Enables source map generation', BooleanSanitizer)
294
            .option(
295
                '--source-map-base-url <string>',
296
                'Sets base url to the source map import url when `--source-map-mode=separate`'
297
            )
298
            .option(
299
                '--source-map-file-name <string>',
300
                'Sets file name for output source map when `--source-map-mode=separate`'
301
            )
302
            .option(
303
                '--source-map-mode <string>',
304
                'Specify source map output mode. ' +
305
                    `Values: ${CLIUtils.stringifyOptionAvailableValues(SourceMapMode)}. ` +
306
                    `Default: ${SourceMapMode.Separate}`
307
            )
308
            .option(
309
                '--source-map-sources-mode <string>',
310
                'Specify source map sources mode. ' +
311
                    `Values: ${CLIUtils.stringifyOptionAvailableValues(SourceMapSourcesMode)}. ` +
312
                    `Default: ${SourceMapSourcesMode.SourcesContent}`
313
            )
314
            .option(
315
                '--split-strings <boolean>',
316
                'Splits literal strings into chunks with length of `splitStringsChunkLength` option value',
317
                BooleanSanitizer
318
            )
319
            .option('--split-strings-chunk-length <number>', 'Sets chunk length of `splitStrings` option', parseFloat)
320
            .option(
321
                '--string-array <boolean>',
322
                'Enables gathering of all literal strings into an array and replacing every literal string with an array call',
323
                BooleanSanitizer
324
            )
325
            .option(
326
                '--string-array-calls-transform <boolean>',
327
                'Enables the transformation of calls to the string array',
328
                BooleanSanitizer
329
            )
330
            .option(
331
                '--string-array-calls-transform-threshold <number>',
332
                'The probability that that calls to the string array will be transformed',
333
                parseFloat
334
            )
335
            .option(
336
                '--string-array-encoding <list> (comma separated, without whitespaces)',
337
                'Encodes each string in strings array using base64 or rc4 (this option can slow down your code speed). ' +
338
                    `Values: ${CLIUtils.stringifyOptionAvailableValues(StringArrayEncoding)}. ` +
339
                    `Default: ${StringArrayEncoding.None}`,
340
                ArraySanitizer
341
            )
342
            .option(
343
                '--string-array-indexes-type <list> (comma separated, without whitespaces)',
344
                'Encodes each string in strings array using base64 or rc4 (this option can slow down your code speed). ' +
345
                    `Values: ${CLIUtils.stringifyOptionAvailableValues(StringArrayIndexesType)}. ` +
346
                    `Default: ${StringArrayIndexesType.HexadecimalNumber}`,
347
                ArraySanitizer
348
            )
349
            .option(
350
                '--string-array-index-shift <boolean>',
351
                'Enables additional index shift for all string array calls',
352
                BooleanSanitizer
353
            )
354
            .option(
355
                '--string-array-rotate <boolean>',
356
                'Enable rotation of string array values during obfuscation',
357
                BooleanSanitizer
358
            )
359
            .option('--string-array-shuffle <boolean>', 'Randomly shuffles string array items', BooleanSanitizer)
360
            .option(
361
                '--string-array-wrappers-count <number>',
362
                'Sets the count of wrappers for the string array inside each root or function scope',
363
                parseInt
364
            )
365
            .option(
366
                '--string-array-wrappers-chained-calls <boolean>',
367
                'Enables the chained calls between string array wrappers',
368
                BooleanSanitizer
369
            )
370
            .option(
371
                '--string-array-wrappers-parameters-max-count <number>',
372
                'Allows to control the maximum number of string array wrappers parameters',
373
                parseInt
374
            )
375
            .option(
376
                '--string-array-wrappers-type <string>',
377
                'Allows to select a type of the wrappers that are appending by the `--string-array-wrappers-count` option. ' +
378
                    `Values: ${CLIUtils.stringifyOptionAvailableValues(StringArrayWrappersType)}. ` +
379
                    `Default: ${StringArrayWrappersType.Variable}`
380
            )
381
            .option(
382
                '--string-array-threshold <number>',
383
                'The probability that the literal string will be inserted into stringArray (Default: 0.8, Min: 0, Max: 1)',
384
                parseFloat
385
            )
386
            .option(
387
                '--target <string>',
388
                'Allows to set target environment for obfuscated code. ' +
389
                    `Values: ${CLIUtils.stringifyOptionAvailableValues(ObfuscationTarget)}. ` +
390
                    `Default: ${ObfuscationTarget.Browser}`
391
            )
392
            .option('--transform-object-keys <boolean>', 'Enables transformation of object keys', BooleanSanitizer)
393
            .option(
394
                '--unicode-escape-sequence <boolean>',
395
                'Allows to enable/disable string conversion to unicode escape sequence',
396
                BooleanSanitizer
397
            )
398
            .option(
399
                '--pro-api-token <string>',
400
                'API token for Pro obfuscation via obfuscator.io (enables VM obfuscation via cloud API)'
401
            )
402
            .option('--pro-api-version <string>', 'Obfuscator version to use with Pro API (e.g., "5.0.0")')
403
            .option(
404
                '--vm-obfuscation <boolean>',
405
                'Enables VM-based bytecode obfuscation for functions',
406
                BooleanSanitizer
407
            )
408
            .option(
409
                '--vm-obfuscation-threshold <number>',
410
                'The probability that VM obfuscation will be applied to a function (Default: 1, Min: 0, Max: 1)',
411
                parseFloat
412
            )
413
            .option(
414
                '--vm-preprocess-identifiers <boolean>',
415
                'Preprocesses identifiers before VM transformation (Default: false)',
416
                BooleanSanitizer
417
            )
418
            .option(
419
                '--vm-dynamic-opcodes <boolean>',
420
                'Dynamically assembles VM dispatcher with shuffled case order and filters unused opcodes based on code analysis',
421
                BooleanSanitizer
422
            )
423
            .option(
424
                '--vm-target-functions <list> (comma separated, without whitespaces)',
425
                'List of specific function names to apply VM obfuscation to (comma separated)',
426
                ArraySanitizer
427
            )
428
            .option(
429
                '--vm-exclude-functions <list> (comma separated, without whitespaces)',
430
                'List of function names to exclude from VM obfuscation (comma separated)',
431
                ArraySanitizer
432
            )
433
            .option(
434
                '--vm-target-functions-mode <string>',
435
                'Controls how functions are selected for VM obfuscation. ' +
436
                    `Values: ${CLIUtils.stringifyOptionAvailableValues(VMTargetFunctionsMode)}. ` +
437
                    `Default: ${VMTargetFunctionsMode.Root}`
438
            )
439
            .option(
440
                '--vm-wrap-top-level-initializers <boolean>',
441
                'Wraps top-level variable initializers in IIFEs so they can be VM-obfuscated (Default: false)',
442
                BooleanSanitizer
443
            )
444
            .option(
445
                '--vm-opcode-shuffle <boolean>',
446
                'Randomizes the numeric values assigned to each opcode (Default: false)',
447
                BooleanSanitizer
448
            )
449
            .option(
450
                '--vm-bytecode-encoding <boolean>',
451
                'Enables bytecode encryption with per-function keys (Default: false)',
452
                BooleanSanitizer
453
            )
454
            .option(
455
                '--vm-bytecode-array-encoding <boolean>',
456
                'Enables encrypted bytecode array with lazy decryption (Default: false)',
457
                BooleanSanitizer
458
            )
459
            .option('--vm-bytecode-array-encoding-key <string>', 'Custom static key for bytecode array encoding')
460
            .option(
461
                '--vm-bytecode-array-encoding-key-getter <string>',
462
                'Custom key getter function code for bytecode array encoding'
463
            )
464
            .option(
465
                '--vm-instruction-shuffle <boolean>',
466
                'Shuffles instruction order within basic blocks (Default: false)',
467
                BooleanSanitizer
468
            )
469
            .option(
470
                '--vm-jumps-encoding <boolean>',
471
                'Enables jump target encoding to prevent CFG reconstruction (Default: false)',
472
                BooleanSanitizer
473
            )
474
            .option(
475
                '--vm-decoy-opcodes <boolean>',
476
                'Enables insertion of decoy opcodes and dead instructions (Default: false)',
477
                BooleanSanitizer
478
            )
479
            .option(
480
                '--vm-dead-code-injection <boolean>',
481
                'Enables dead code injection with opaque predicates in bytecode (Default: false)',
482
                BooleanSanitizer
483
            )
484
            .option(
485
                '--vm-split-dispatcher <boolean>',
486
                'Splits the VM interpreter into multiple category-based dispatchers (Default: false)',
487
                BooleanSanitizer
488
            )
489
            .option(
490
                '--vm-macro-ops <boolean>',
491
                'Enables macro-op fusion to combine common instruction sequences (Default: false)',
492
                BooleanSanitizer
493
            )
494
            .option(
495
                '--vm-debug-protection <boolean>',
496
                'Enables anti-debugging measures with state corruption (Default: false)',
497
                BooleanSanitizer
498
            )
499
            .option(
500
                '--vm-runtime-opcode-derivation <boolean>',
501
                'Enables runtime opcode derivation from seeds instead of static mappings (Default: false)',
502
                BooleanSanitizer
503
            )
504
            .option(
505
                '--vm-stateful-opcodes <boolean>',
506
                'Enables position-based stateful opcode decoding to prevent pattern matching (Default: false)',
507
                BooleanSanitizer
508
            )
509
            .option(
510
                '--vm-stack-encoding <boolean>',
511
                'Enables stack value encoding to prevent stack inspection (Default: false)',
512
                BooleanSanitizer
513
            )
514
            .option(
515
                '--vm-randomize-keys <boolean>',
516
                'Randomizes bytecode property keys to prevent pattern matching (Default: false)',
517
                BooleanSanitizer
518
            )
519
            .option(
520
                '--vm-indirect-dispatch <boolean>',
521
                'Uses indirect dispatch via handler function table instead of switch statement (Default: false)',
522
                BooleanSanitizer
523
            )
524
            .option(
525
                '--vm-compact-dispatcher <boolean>',
526
                'Uses a single unified dispatcher for both sync and generator execution, reducing code size (Default: false)',
527
                BooleanSanitizer
528
            )
529
            .option(
530
                '--vm-bytecode-format <string>',
531
                'Sets the bytecode storage format. ' +
532
                    `Values: ${CLIUtils.stringifyOptionAvailableValues(VMBytecodeFormat)}. ` +
533
                    `Default: ${VMBytecodeFormat.Binary}`
534
            )
535
            .option(
536
                '--parse-html <boolean>',
537
                'Enables obfuscation of JavaScript within HTML <script> tags (Default: false)',
538
                BooleanSanitizer
539
            )
540
            .option(
541
                '--strict-mode <boolean | null>',
542
                'Allows to specify how the obfuscator should treat code regarding JavaScript strict mode (Default: null)',
543
                StrictModeSanitizer
544
            )
545
            .parse(this.rawArguments);
546
    }
547

548
    private configureHelp(): void {
549
        this.commands.on('--help', () => {
198✔
550
            console.log('  Examples:\n');
24✔
551
            console.log('    %> javascript-obfuscator input_file_name.js --compact true --self-defending false');
24✔
552
            console.log(
24✔
553
                '    %> javascript-obfuscator input_file_name.js --output output_file_name.js --compact true --self-defending false'
554
            );
555
            console.log('    %> javascript-obfuscator input_directory_name --compact true --self-defending false');
24✔
556
            console.log('');
24✔
557
        });
558
    }
559

560
    /**
561
     * @param {IFileData[]} sourceCodeData
562
     */
563
    private async processSourceCodeData(sourceCodeData: IFileData[]): Promise<void> {
564
        for (let index = 0; index < sourceCodeData.length; index++) {
156✔
565
            const { filePath, content } = sourceCodeData[index];
186✔
566
            const outputCodePath: string = this.obfuscatedCodeFileUtils.getOutputCodePath(filePath);
186✔
567

568
            try {
186✔
569
                Logger.log(Logger.colorInfo, LoggingPrefix.CLI, `Obfuscating file: ${filePath}...`);
186✔
570

571
                await this.processSourceCode(content, filePath, outputCodePath, index);
186✔
572
            } catch (error) {
573
                Logger.log(Logger.colorInfo, LoggingPrefix.CLI, `Error in file: ${filePath}...`);
12✔
574

575
                throw error;
12✔
576
            }
577
        }
578
    }
579

580
    /**
581
     * @param {string} sourceCode
582
     * @param {string} inputCodePath
583
     * @param {string} outputCodePath
584
     * @param {number | null} sourceCodeIndex
585
     */
586
    private async processSourceCode(
587
        sourceCode: string,
588
        inputCodePath: string,
589
        outputCodePath: string,
590
        sourceCodeIndex: number | null
591
    ): Promise<void> {
592
        const options: TInputOptions = {
186✔
593
            ...this.inputCLIOptions,
594
            identifierNamesCache: this.identifierNamesCacheFileUtils.readFile(),
595
            inputFileName: path.basename(inputCodePath),
596
            ...(sourceCodeIndex !== null && {
372✔
597
                identifiersPrefix: Utils.getIdentifiersPrefixForMultipleSources(
598
                    this.inputCLIOptions.identifiersPrefix,
599
                    sourceCodeIndex
600
                )
601
            })
602
        };
603

604
        // Use Pro API if token is provided and Pro features are enabled
605
        const proApiToken = this.inputCLIOptions.proApiToken;
186✔
606

607
        if (proApiToken) {
186✔
608
            await this.processSourceCodeWithProApi(sourceCode, outputCodePath, options, proApiToken);
24✔
609

610
            return;
18✔
611
        }
612

613
        if (options.sourceMap) {
162✔
614
            this.processSourceCodeWithSourceMap(sourceCode, outputCodePath, options);
60✔
615
        } else {
616
            this.processSourceCodeWithoutSourceMap(sourceCode, outputCodePath, options);
102✔
617
        }
618
    }
619

620
    /**
621
     * Process source code using Pro API (cloud-based VM obfuscation)
622
     */
623
    private async processSourceCodeWithProApi(
624
        sourceCode: string,
625
        outputCodePath: string,
626
        options: TInputOptions,
627
        apiToken: string
628
    ): Promise<void> {
629
        const proApiVersion = this.inputCLIOptions.proApiVersion;
24✔
630

631
        const client = new ProApiClient({
24✔
632
            apiToken,
633
            version: proApiVersion
634
        });
635

636
        const result: IProObfuscationResult = await client.obfuscate(sourceCode, options, (message: string) => {
24✔
637
            Logger.log(Logger.colorInfo, LoggingPrefix.CLI, message);
×
638
        });
639

640
        this.obfuscatedCodeFileUtils.writeFile(outputCodePath, result.getObfuscatedCode());
18✔
641

642
        // Write source map if enabled and available
643
        if (options.sourceMap && result.getSourceMap()) {
18!
644
            const outputSourceMapPath: string = this.obfuscatedCodeFileUtils.getOutputSourceMapPath(
×
645
                outputCodePath,
646
                options.sourceMapFileName ?? ''
×
647
            );
648

649
            if (options.sourceMapMode === SourceMapMode.Separate) {
×
650
                this.obfuscatedCodeFileUtils.writeFile(outputSourceMapPath, result.getSourceMap());
×
651
            }
652
        }
653
    }
654

655
    /**
656
     * @param {string} sourceCode
657
     * @param {string} outputCodePath
658
     * @param {TInputOptions} options
659
     */
660
    private processSourceCodeWithoutSourceMap(
661
        sourceCode: string,
662
        outputCodePath: string,
663
        options: TInputOptions
664
    ): void {
665
        const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(sourceCode, options);
102✔
666

667
        this.obfuscatedCodeFileUtils.writeFile(outputCodePath, obfuscationResult.getObfuscatedCode());
96✔
668
        this.identifierNamesCacheFileUtils.writeFile(obfuscationResult.getIdentifierNamesCache());
96✔
669
    }
670

671
    /**
672
     * @param {string} sourceCode
673
     * @param {string} outputCodePath
674
     * @param {TInputOptions} options
675
     */
676
    private processSourceCodeWithSourceMap(sourceCode: string, outputCodePath: string, options: TInputOptions): void {
677
        const outputSourceMapPath: string = this.obfuscatedCodeFileUtils.getOutputSourceMapPath(
60✔
678
            outputCodePath,
679
            options.sourceMapFileName ?? ''
180!
680
        );
681

682
        options = {
60✔
683
            ...options,
684
            sourceMapFileName: path.basename(outputSourceMapPath)
685
        };
686

687
        const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(sourceCode, options);
60✔
688

689
        this.obfuscatedCodeFileUtils.writeFile(outputCodePath, obfuscationResult.getObfuscatedCode());
60✔
690
        this.identifierNamesCacheFileUtils.writeFile(obfuscationResult.getIdentifierNamesCache());
60✔
691

692
        if (options.sourceMapMode === SourceMapMode.Separate && obfuscationResult.getSourceMap()) {
60✔
693
            this.obfuscatedCodeFileUtils.writeFile(outputSourceMapPath, obfuscationResult.getSourceMap());
42✔
694
        }
695
    }
696
}
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