From 25427bcc0b8058de04fc9f434066a922e8bf5e38 Mon Sep 17 00:00:00 2001 From: Timofey Kachalov Date: Tue, 3 Feb 2026 20:22:11 +0400 Subject: [PATCH 01/25] Add Pro API support to CLI including support for large files obfuscation (#1381) --- CHANGELOG.md | 5 + README.md | 222 +++++- bin/javascript-obfuscator | 5 +- package.json | 3 +- src/JavaScriptObfuscatorCLIFacade.ts | 5 +- src/JavaScriptObfuscatorFacade.ts | 15 +- src/cli/JavaScriptObfuscatorCLI.ts | 215 +++++- src/cli/sanitizers/StrictModeSanitizer.ts | 13 + src/interfaces/options/ICLIOptions.ts | 2 + src/interfaces/pro-api/IProApiClient.ts | 8 + src/pro-api/ProApiClient.ts | 272 ++++++-- src/pro-api/enums/VMBytecodeFormat.ts | 9 + src/pro-api/enums/VMTargetFunctionsMode.ts | 9 + .../cli/JavaScriptObfuscatorCLI.spec.ts | 368 +++++++--- .../pro-api/ProApiClient.spec.ts | 652 +++++++++--------- test/index.spec.ts | 1 + test/unit-tests/pro-api/ProApiClient.spec.ts | 183 ++++- yarn.lock | 43 ++ 18 files changed, 1523 insertions(+), 507 deletions(-) create mode 100644 src/cli/sanitizers/StrictModeSanitizer.ts create mode 100644 src/pro-api/enums/VMBytecodeFormat.ts create mode 100644 src/pro-api/enums/VMTargetFunctionsMode.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 670232a2f..35118b467 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ Change Log +v5.3.0 +--- +* Add Pro API support to CLI +* Add large files upload support to Pro API + v5.2.1 --- * Fixed `transformObjectKeys` incorrectly hoisting object literal outside of loop when loop body is a single statement without braces, causing all iterations to share the same object reference. Fixes https://github.com/javascript-obfuscator/javascript-obfuscator/issues/1300 diff --git a/README.md b/README.md index 128eaba72..fe9b9759a 100644 --- a/README.md +++ b/README.md @@ -15,18 +15,20 @@ Huge thanks to all supporters! --- -### :rocket: JavaScript Obfuscator Pro with VM Obfuscation is out! +### :rocket: Obfuscator.io with VM Obfuscation is out! -**JavaScript Obfuscator Pro** features **VM-based bytecode obfuscation** — the most advanced code protection available. Your JavaScript functions are transformed into custom bytecode running on an embedded virtual machine, making reverse engineering extremely difficult. +**Obfuscator.io** features **VM-based bytecode obfuscation** — the most advanced code protection available. Your JavaScript functions are transformed into custom bytecode running on an embedded virtual machine, making reverse engineering extremely difficult. [Try it at obfuscator.io](https://obfuscator.io) +This package provides access to Obfuscator.io Pro API via CLI and Node.js API. + --- JavaScript Obfuscator is a powerful free obfuscator for JavaScript, containing a variety of features which provide protection for your source code. **Key features:** -- VM bytecode obfuscation (via [JavaScript Obfuscator Pro](https://obfuscator.io/)) +- VM bytecode obfuscation (via [Obfuscator.io](https://obfuscator.io/)) - variables renaming - strings extraction and encryption - dead code injection @@ -314,17 +316,17 @@ console.log(result.getObfuscatedCode()); **Parameters:** * `sourceCode` (`string`) – source code to obfuscate -* `options` (`Object`) – obfuscation options. **Must include `vmObfuscation: true`** +* `options` (`Object`) – obfuscation options. **Must include at least one Pro feature: `vmObfuscation: true` or `parseHtml: true`** * `apiConfig` (`Object`) – Pro API configuration: * `apiToken` (`string`, required) – your API token from obfuscator.io * `timeout` (`number`, optional) – request timeout in ms (default: `300000` - 5 minutes) - * `version` (`string`, optional) – JavaScript Obfuscator Pro version to use (e.g., `'5.0.0-beta.20'`). Defaults to latest version if not specified. + * `version` (`string`, optional) – Obfuscator.io version to use (e.g., `'5.0.3'`). Defaults to latest version if not specified. * `onProgress` (`function`, optional) – callback for progress updates during obfuscation **Returns:** `Promise` **Throws:** `ApiError` if: -- `vmObfuscation` is not enabled in options +- No Pro features (`vmObfuscation` or `parseHtml`) are enabled in options - API token is invalid or expired - API request fails @@ -341,7 +343,7 @@ const result = await JavaScriptObfuscator.obfuscatePro( }, { apiToken: 'your_javascript_obfuscator_pro_api_token', - version: '5.0.0-beta.20' // Use specific version + version: '5.0.3' // Use specific version } ); ``` @@ -367,6 +369,28 @@ const result = await JavaScriptObfuscator.obfuscatePro( ); ``` +### Checking for Pro Features + +Use `ProApiClient.hasProFeatures()` to check if options require the Pro API: + +```javascript +const { ProApiClient } = require('javascript-obfuscator'); + +const options = { vmObfuscation: true, compact: true }; + +if (ProApiClient.hasProFeatures(options)) { + // Use obfuscatePro() - requires API token + const result = await JavaScriptObfuscator.obfuscatePro(sourceCode, options, { apiToken }); +} else { + // Use regular obfuscate() - no API token needed + const result = JavaScriptObfuscator.obfuscate(sourceCode, options); +} +``` + +Pro features include: +- `vmObfuscation: true` – VM-based bytecode obfuscation +- `parseHtml: true` – HTML parsing with inline JavaScript obfuscation + ### Error Handling ```javascript @@ -383,6 +407,36 @@ try { } ``` +### CLI Usage with Pro API + +You can also use Pro API features directly from the CLI by providing your API token: + +```sh +javascript-obfuscator input.js --pro-api-token YOUR_API_TOKEN --vm-obfuscation true -o output.js +``` + +With a specific obfuscator version: + +```sh +javascript-obfuscator input.js --pro-api-token YOUR_API_TOKEN --pro-api-version 5.0.3 --vm-obfuscation true -o output.js +``` + +**CLI Options:** +- `--pro-api-token ` – Your API token from [obfuscator.io](https://obfuscator.io) +- `--pro-api-version ` – Obfuscator.io version to use (optional, defaults to latest) + +The CLI automatically detects when Pro features (`vmObfuscation` or `parseHtml`) are enabled and routes the request through the Pro API. + +### Large File Uploads + +For files larger than ~4MB, the Pro API uses client-side uploads to Vercel Blob storage. To enable this feature, install the optional `@vercel/blob` package: + +```sh +npm install @vercel/blob +``` + +Without this package, large file obfuscation will fail with an error message prompting you to install it. + --- ## CLI usage @@ -583,6 +637,37 @@ Following options are available for the JS Obfuscator: --target [browser, browser-no-eval, node] --transform-object-keys --unicode-escape-sequence + --pro-api-token + --pro-api-version + --vm-obfuscation + --vm-obfuscation-threshold + --vm-preprocess-identifiers + --vm-dynamic-opcodes + --vm-target-functions '' (comma separated) + --vm-exclude-functions '' (comma separated) + --vm-target-functions-mode [root, comment] + --vm-wrap-top-level-initializers + --vm-opcode-shuffle + --vm-bytecode-encoding + --vm-bytecode-array-encoding + --vm-bytecode-array-encoding-key + --vm-bytecode-array-encoding-key-getter + --vm-instruction-shuffle + --vm-jumps-encoding + --vm-decoy-opcodes + --vm-dead-code-injection + --vm-split-dispatcher + --vm-macro-ops + --vm-debug-protection + --vm-runtime-opcode-derivation + --vm-stateful-opcodes + --vm-stack-encoding + --vm-randomize-keys + --vm-indirect-dispatch + --vm-compact-dispatcher + --vm-bytecode-format [binary, json] + --parse-html + --strict-mode ``` @@ -1766,9 +1851,9 @@ The performance will be at a relatively normal level -## JavaScript Obfuscator Pro Options +## Obfuscator.io Pro Options -> :warning: **The following VM obfuscation/Pro options are available only via the [JavaScript Obfuscator Pro API](https://obfuscator.io/).** +> :warning: **The following VM obfuscation/Pro options are available only via the [Obfuscator.io Pro API](https://obfuscator.io/).** > > To use these options, you need a Pro API token from [obfuscator.io](https://obfuscator.io) and must call the `obfuscatePro()` method instead of `obfuscate()`. See the [Pro API Methods](#shield-pro-api-methods-vm-obfuscation) section for details. @@ -1785,6 +1870,8 @@ Type: `number` Default: `1` Controls what percentage of your root-level functions get VM protection. +> **Warning:** Values other than `1` may cause runtime bugs when VM-obfuscated and non-VM-obfuscated code share top-level variables. A value of `1` is strongly recommended. For selective function obfuscation, use `vmTargetFunctionsMode: 'comment'` with the `// javascript-obfuscator:vm` directive instead. + ### `vmPreprocessIdentifiers` Type: `boolean` Default: `true` @@ -1915,6 +2002,56 @@ Type: `boolean` Default: `false` Encodes the entire bytecode array as a single block. The array is decoded once at startup before execution begins. Use together with `vmBytecodeEncoding` for two layers of protection. +### `vmBytecodeArrayEncodingKey` +Type: `string` Default: `''` + +Custom encryption key for bytecode array encoding. When set, this key is used instead of the default environment-derived key. The key must be provided at runtime via `vmBytecodeArrayEncodingKeyGetter`. + +This option externalizes the encryption key - it's not embedded in the obfuscated code itself. While the key is still accessible at runtime (and thus not truly secret), this separation prevents static analysis tools from finding the key by examining the code alone. + +**Important:** The key must be available **synchronously** when the obfuscated code loads. Use synchronous storage like cookies, localStorage, sessionStorage, global variables, or DOM elements (e.g., server-injected meta tags). Async methods like `fetch()` cannot be used directly in the key getter expression. + +### `vmBytecodeArrayEncodingKeyGetter` +Type: `string` Default: `''` + +**Synchronous** JavaScript expression that **returns** the encryption key at runtime. This expression is evaluated when the obfuscated code loads, and must return the same key that was provided in `vmBytecodeArrayEncodingKey`. + +**The obfuscated code will only work when the key getter returns exactly the same key that was used during obfuscation.** If the keys don't match, decryption will fail and the code will produce garbage or errors. If the key getter returns `undefined`, `null`, or an empty string, the code will throw an error: "VM decryption key not available". + +**Important:** The key should NOT be defined in the same JavaScript file/script as the obfuscated code. Doing so defeats the purpose of key externalization, as static analysis could still find the key. Store the key in a separate source: server-set cookies, localStorage populated by another script, server-injected HTML meta tags, or a global variable set by a different script that loads before the obfuscated code. + +Examples: +```ts +// From cookie +vmBytecodeArrayEncodingKeyGetter: "document.cookie.match(/vmKey=([^;]+)/)?.[1]" + +// From localStorage +vmBytecodeArrayEncodingKeyGetter: "localStorage.getItem('vmKey')" + +// From global variable +vmBytecodeArrayEncodingKeyGetter: "window.__VM_KEY__" + +// From meta tag (server-injected) +vmBytecodeArrayEncodingKeyGetter: "document.querySelector('meta[name=\"vm-key\"]').content" + +// From nested object +vmBytecodeArrayEncodingKeyGetter: "window.config.encryption.key" +``` + +**Usage example:** +```ts +// Build time +JavaScriptObfuscator.obfuscate(code, { + vmObfuscation: true, + vmBytecodeArrayEncoding: true, + vmBytecodeArrayEncodingKey: 'mySecretKey123', + vmBytecodeArrayEncodingKeyGetter: 'window.__VM_KEY__' +}); + +// Runtime - key must be set before obfuscated code runs +window.__VM_KEY__ = 'mySecretKey123'; +``` + ### `vmJumpsEncoding` Type: `boolean` Default: `false` @@ -2001,6 +2138,17 @@ Encrypts values on the VM stack during execution. Values are encoded when pushed This option heavily affects performance. +### `vmInstructionShuffle` +Type: `boolean` Default: `false` + +Randomizes the bytecode instruction layout per function. Each function can have a different instruction array format: +- Layout 0: `[op, arg, op, arg, ...]` (interleaved - default) +- Layout 1: `[arg, op, arg, op, ...]` (swapped interleaved) +- Layout 2: `[op0, op1, ..., arg0, arg1, ...]` (opcodes first, then arguments) +- Layout 3: `[arg0, arg1, ..., op0, op1, ...]` (arguments first, then opcodes) + +This makes pattern recognition across functions harder during analysis. + ### `vmRandomizeKeys` Type: `boolean` Default: `false` @@ -2025,6 +2173,62 @@ Available values: * `true` - force strict mode treatment for all code, even without explicit `'use strict'` directive. Use this when your code will run in strict mode context (e.g., in ES modules, bundlers, or modern frameworks). * `false` - only explicit strict mode indicators (`'use strict'`, ES modules, class methods) are treated as strict. Parent scope inheritance still applies per JS spec. +### `parseHtml` +Type: `boolean` Default: `false` + +Enables obfuscation of JavaScript within HTML ` + + + + +`; + +JavaScriptObfuscator.obfuscate(html, { + parseHtml: true, + stringArray: true +}); + +// output: HTML with only the marked script obfuscated +``` + ## Frequently Asked Questions ### What javascript versions are supported? diff --git a/bin/javascript-obfuscator b/bin/javascript-obfuscator index 0946b4521..144f7b8ad 100755 --- a/bin/javascript-obfuscator +++ b/bin/javascript-obfuscator @@ -1,3 +1,6 @@ #!/usr/bin/env node -require('../dist/index.cli').obfuscate(process.argv); \ No newline at end of file +require('../dist/index.cli').obfuscate(process.argv).catch((error) => { + console.error(error.message); + process.exit(1); +}); \ No newline at end of file diff --git a/package.json b/package.json index 4baf28c3f..2519534eb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "javascript-obfuscator", - "version": "5.2.1", + "version": "5.3.0", "description": "JavaScript obfuscator", "keywords": [ "obfuscator", @@ -23,6 +23,7 @@ "dependencies": { "@javascript-obfuscator/escodegen": "2.3.1", "@javascript-obfuscator/estraverse": "5.4.0", + "@vercel/blob": ">=0.23.0", "acorn": "8.15.0", "assert": "2.1.0", "chalk": "4.1.2", diff --git a/src/JavaScriptObfuscatorCLIFacade.ts b/src/JavaScriptObfuscatorCLIFacade.ts index 09a66604b..075f21be5 100644 --- a/src/JavaScriptObfuscatorCLIFacade.ts +++ b/src/JavaScriptObfuscatorCLIFacade.ts @@ -6,11 +6,12 @@ class JavaScriptObfuscatorCLIFacade { /** * @param {string[]} argv */ - public static obfuscate(argv: string[]): void { + public static async obfuscate(argv: string[]): Promise { const javaScriptObfuscatorCLI: JavaScriptObfuscatorCLI = new JavaScriptObfuscatorCLI(argv); javaScriptObfuscatorCLI.initialize(); - javaScriptObfuscatorCLI.run(); + + return javaScriptObfuscatorCLI.run(); } } diff --git a/src/JavaScriptObfuscatorFacade.ts b/src/JavaScriptObfuscatorFacade.ts index d5128d0ee..91356e7c3 100644 --- a/src/JavaScriptObfuscatorFacade.ts +++ b/src/JavaScriptObfuscatorFacade.ts @@ -11,12 +11,10 @@ import { IInversifyContainerFacade } from './interfaces/container/IInversifyCont import { IJavaScriptObfuscator } from './interfaces/IJavaScriptObfsucator'; import { IObfuscationResult } from './interfaces/source-code/IObfuscationResult'; import { IProApiConfig, IProObfuscationResult, TProApiProgressCallback } from './interfaces/pro-api/IProApiClient'; -import { ApiError } from './pro-api/ApiError'; import { InversifyContainerFacade } from './container/InversifyContainerFacade'; import { Options } from './options/Options'; import { Utils } from './utils/Utils'; -import { ProApiClient } from './pro-api/ProApiClient'; class JavaScriptObfuscatorFacade { /** @@ -94,6 +92,7 @@ class JavaScriptObfuscatorFacade { /** * Obfuscate code using the Pro API (obfuscator.io) * This method requires a valid API token from obfuscator.io and only works with VM obfuscation. + * Only available in Node.js environment. * * @param {string} sourceCode - Source code to obfuscate * @param {TInputOptions} inputOptions - Obfuscation options (must include vmObfuscation: true) @@ -108,13 +107,13 @@ class JavaScriptObfuscatorFacade { proApiConfig: IProApiConfig, onProgress?: TProApiProgressCallback ): Promise { - if (!inputOptions.vmObfuscation) { - throw new ApiError( - 'obfuscatePro method works only with VM obfuscation. Set vmObfuscation: true in options.', - 400 - ); + if (typeof window !== 'undefined') { + const { ApiError } = await import('./pro-api/ApiError'); + + throw new ApiError('obfuscatePro is only available in Node.js environment', 500); } + const { ProApiClient } = await import('./pro-api/ProApiClient'); const client = new ProApiClient(proApiConfig); return client.obfuscate(sourceCode, inputOptions, onProgress); @@ -123,4 +122,4 @@ class JavaScriptObfuscatorFacade { export { JavaScriptObfuscatorFacade as JavaScriptObfuscator }; export { ApiError } from './pro-api/ApiError'; -export type { IProApiConfig, TProApiProgressCallback } from './interfaces/pro-api/IProApiClient'; +export type { IProApiConfig, IProObfuscationResult, TProApiProgressCallback } from './interfaces/pro-api/IProApiClient'; diff --git a/src/cli/JavaScriptObfuscatorCLI.ts b/src/cli/JavaScriptObfuscatorCLI.ts index 9d905accd..99b16d53a 100644 --- a/src/cli/JavaScriptObfuscatorCLI.ts +++ b/src/cli/JavaScriptObfuscatorCLI.ts @@ -8,6 +8,8 @@ import { TInputOptions } from '../types/options/TInputOptions'; import { IFileData } from '../interfaces/cli/IFileData'; import { IInitializable } from '../interfaces/IInitializable'; import { IObfuscationResult } from '../interfaces/source-code/IObfuscationResult'; +import { ProApiClient } from '../pro-api/ProApiClient'; +import { IProObfuscationResult } from '../interfaces/pro-api/IProApiClient'; import { initializable } from '../decorators/Initializable'; @@ -34,6 +36,9 @@ import { Logger } from '../logger/Logger'; import { ObfuscatedCodeFileUtils } from './utils/ObfuscatedCodeFileUtils'; import { SourceCodeFileUtils } from './utils/SourceCodeFileUtils'; import { Utils } from '../utils/Utils'; +import { VMTargetFunctionsMode } from '../pro-api/enums/VMTargetFunctionsMode'; +import { VMBytecodeFormat } from '../pro-api/enums/VMBytecodeFormat'; +import { StrictModeSanitizer } from './sanitizers/StrictModeSanitizer'; export class JavaScriptObfuscatorCLI implements IInitializable { /** @@ -155,7 +160,7 @@ export class JavaScriptObfuscatorCLI implements IInitializable { ); } - public run(): void { + public async run(): Promise { const canShowHelp: boolean = !this.arguments.length || this.arguments.includes('--help'); if (canShowHelp) { @@ -166,7 +171,7 @@ export class JavaScriptObfuscatorCLI implements IInitializable { const sourceCodeData: IFileData[] = this.sourceCodeFileUtils.readSourceCode(); - this.processSourceCodeData(sourceCodeData); + await this.processSourceCodeData(sourceCodeData); } private configureCommands(): void { @@ -210,7 +215,7 @@ export class JavaScriptObfuscatorCLI implements IInitializable { ) .option( '--domain-lock-redirect-url ', - 'Allows the browser to be redirected to a passed URL if the source code isn\'t run on the domains specified by --domain-lock' + "Allows the browser to be redirected to a passed URL if the source code isn't run on the domains specified by --domain-lock" ) .option( '--exclude (comma separated, without whitespaces)', @@ -390,6 +395,153 @@ export class JavaScriptObfuscatorCLI implements IInitializable { 'Allows to enable/disable string conversion to unicode escape sequence', BooleanSanitizer ) + .option( + '--pro-api-token ', + 'API token for Pro obfuscation via obfuscator.io (enables VM obfuscation via cloud API)' + ) + .option('--pro-api-version ', 'Obfuscator version to use with Pro API (e.g., "5.0.0")') + .option( + '--vm-obfuscation ', + 'Enables VM-based bytecode obfuscation for functions', + BooleanSanitizer + ) + .option( + '--vm-obfuscation-threshold ', + 'The probability that VM obfuscation will be applied to a function (Default: 1, Min: 0, Max: 1)', + parseFloat + ) + .option( + '--vm-preprocess-identifiers ', + 'Preprocesses identifiers before VM transformation (Default: false)', + BooleanSanitizer + ) + .option( + '--vm-dynamic-opcodes ', + 'Dynamically assembles VM dispatcher with shuffled case order and filters unused opcodes based on code analysis', + BooleanSanitizer + ) + .option( + '--vm-target-functions (comma separated, without whitespaces)', + 'List of specific function names to apply VM obfuscation to (comma separated)', + ArraySanitizer + ) + .option( + '--vm-exclude-functions (comma separated, without whitespaces)', + 'List of function names to exclude from VM obfuscation (comma separated)', + ArraySanitizer + ) + .option( + '--vm-target-functions-mode ', + 'Controls how functions are selected for VM obfuscation. ' + + `Values: ${CLIUtils.stringifyOptionAvailableValues(VMTargetFunctionsMode)}. ` + + `Default: ${VMTargetFunctionsMode.Root}` + ) + .option( + '--vm-wrap-top-level-initializers ', + 'Wraps top-level variable initializers in IIFEs so they can be VM-obfuscated (Default: false)', + BooleanSanitizer + ) + .option( + '--vm-opcode-shuffle ', + 'Randomizes the numeric values assigned to each opcode (Default: false)', + BooleanSanitizer + ) + .option( + '--vm-bytecode-encoding ', + 'Enables bytecode encryption with per-function keys (Default: false)', + BooleanSanitizer + ) + .option( + '--vm-bytecode-array-encoding ', + 'Enables encrypted bytecode array with lazy decryption (Default: false)', + BooleanSanitizer + ) + .option('--vm-bytecode-array-encoding-key ', 'Custom static key for bytecode array encoding') + .option( + '--vm-bytecode-array-encoding-key-getter ', + 'Custom key getter function code for bytecode array encoding' + ) + .option( + '--vm-instruction-shuffle ', + 'Shuffles instruction order within basic blocks (Default: false)', + BooleanSanitizer + ) + .option( + '--vm-jumps-encoding ', + 'Enables jump target encoding to prevent CFG reconstruction (Default: false)', + BooleanSanitizer + ) + .option( + '--vm-decoy-opcodes ', + 'Enables insertion of decoy opcodes and dead instructions (Default: false)', + BooleanSanitizer + ) + .option( + '--vm-dead-code-injection ', + 'Enables dead code injection with opaque predicates in bytecode (Default: false)', + BooleanSanitizer + ) + .option( + '--vm-split-dispatcher ', + 'Splits the VM interpreter into multiple category-based dispatchers (Default: false)', + BooleanSanitizer + ) + .option( + '--vm-macro-ops ', + 'Enables macro-op fusion to combine common instruction sequences (Default: false)', + BooleanSanitizer + ) + .option( + '--vm-debug-protection ', + 'Enables anti-debugging measures with state corruption (Default: false)', + BooleanSanitizer + ) + .option( + '--vm-runtime-opcode-derivation ', + 'Enables runtime opcode derivation from seeds instead of static mappings (Default: false)', + BooleanSanitizer + ) + .option( + '--vm-stateful-opcodes ', + 'Enables position-based stateful opcode decoding to prevent pattern matching (Default: false)', + BooleanSanitizer + ) + .option( + '--vm-stack-encoding ', + 'Enables stack value encoding to prevent stack inspection (Default: false)', + BooleanSanitizer + ) + .option( + '--vm-randomize-keys ', + 'Randomizes bytecode property keys to prevent pattern matching (Default: false)', + BooleanSanitizer + ) + .option( + '--vm-indirect-dispatch ', + 'Uses indirect dispatch via handler function table instead of switch statement (Default: false)', + BooleanSanitizer + ) + .option( + '--vm-compact-dispatcher ', + 'Uses a single unified dispatcher for both sync and generator execution, reducing code size (Default: false)', + BooleanSanitizer + ) + .option( + '--vm-bytecode-format ', + 'Sets the bytecode storage format. ' + + `Values: ${CLIUtils.stringifyOptionAvailableValues(VMBytecodeFormat)}. ` + + `Default: ${VMBytecodeFormat.Binary}` + ) + .option( + '--parse-html ', + 'Enables obfuscation of JavaScript within HTML