# JavaScript Obfuscator - Project Documentation

## Project Overview

**JavaScript Obfuscator** is a powerful, enterprise-grade code obfuscation tool for JavaScript and Node.js applications. It transforms readable JavaScript code into a protected, difficult-to-understand format while maintaining full functionality. The project is widely used for protecting intellectual property and preventing reverse engineering.

- **Version**: 5.0.0
- **Author**: Timofei Kachalov (@sanex3339)
- **License**: BSD-2-Clause
- **Repository**: https://github.com/javascript-obfuscator/javascript-obfuscator
- **Homepage**: https://obfuscator.io/
- **Node Requirement**: >=18.0.0

## Key Features

### Core Obfuscation Techniques

1. **Variable & Function Renaming**: Replaces identifiable names with cryptic hexadecimal or mangled identifiers
2. **String Extraction & Encryption**: Moves string literals to an encoded array with base64/rc4 encryption
3. **Dead Code Injection**: Inserts non-functional code blocks to confuse static analysis
4. **Control Flow Flattening**: Restructures code flow using switch statements to obscure logic
5. **Code Transformations**: Multiple AST-level transformations including:
   - Boolean literal obfuscation
   - Number to expression conversion
   - Object key transformation
   - Template literal transformation
   - Property renaming (safe/unsafe modes)

### Advanced Protection Features

- **Self-Defending Code**: Code that breaks when beautified or modified
- **Debug Protection**: Anti-debugging mechanisms to prevent DevTools usage
- **Domain Lock**: Restricts code execution to specific domains/subdomains
- **Console Output Disabling**: Removes console.* functionality
- **Unicode Escape Sequences**: Additional string obfuscation layer

## Architecture Overview

### Technology Stack

- **Language**: TypeScript 4.9.5
- **Parser**: Acorn 8.8.2 (ES3-ES2020 support)
- **Code Generator**: @javascript-obfuscator/escodegen 2.3.0
- **AST Traversal**: @javascript-obfuscator/estraverse 5.4.0
- **DI Framework**: InversifyJS 7.10.8
- **Testing**: Mocha 10.4.0 + Chai 4.3.7
- **Build System**: Webpack 5.75.0

### Project Structure

```
javascript-obfuscator/
├── src/                              # Source code
│   ├── JavaScriptObfuscator.ts      # Main obfuscator class
│   ├── JavaScriptObfuscatorFacade.ts # Public API facade
│   ├── JavaScriptObfuscatorCLIFacade.ts # CLI interface
│   ├── ASTParserFacade.ts           # AST parsing wrapper
│   │
│   ├── analyzers/                    # Code analysis components
│   │   ├── calls-graph-analyzer/    # Function call graph analysis
│   │   ├── scope-analyzer/          # Variable scope analysis
│   │   ├── string-array-storage-analyzer/ # String array optimization
│   │   ├── number-numerical-expression-analyzer/
│   │   └── prevailing-kind-of-variables-analyzer/
│   │
│   ├── node-transformers/            # AST transformation pipeline
│   │   ├── AbstractNodeTransformer.ts
│   │   ├── NodeTransformersRunner.ts
│   │   ├── converting-transformers/ # Node type conversions
│   │   ├── control-flow-transformers/ # Control flow flattening
│   │   ├── dead-code-injection-transformers/ # Dead code generation
│   │   ├── finalizing-transformers/ # Post-processing transforms
│   │   ├── initializing-transformers/ # Pre-processing transforms
│   │   ├── preparing-transformers/  # Preparation phase
│   │   ├── rename-identifiers-transformers/ # Variable renaming
│   │   ├── rename-properties-transformers/ # Property renaming
│   │   ├── simplifying-transformers/ # Code simplification
│   │   └── string-array-transformers/ # String array handling
│   │
│   ├── code-transformers/            # Code-level (not AST) transformers
│   │   ├── AbstractCodeTransformer.ts
│   │   ├── CodeTransformersRunner.ts
│   │   └── CodeTransformerNamesGroupsBuilder.ts
│   │
│   ├── custom-code-helpers/          # Injectable code helpers
│   │   ├── common/                   # Global variable templates
│   │   ├── console-output/          # Console disabling templates
│   │   ├── debug-protection/        # Anti-debugging templates
│   │   ├── domain-lock/             # Domain restriction templates
│   │   ├── self-defending/          # Self-defense templates
│   │   └── string-array/            # String array wrapper templates
│   │
│   ├── custom-nodes/                 # Custom AST node generators
│   │   ├── control-flow-flattening-nodes/
│   │   ├── dead-code-injection-nodes/
│   │   ├── object-expression-keys-transformer-nodes/
│   │   └── string-array-nodes/
│   │
│   ├── container/                    # Dependency injection
│   │   ├── InversifyContainerFacade.ts
│   │   ├── ServiceIdentifiers.ts
│   │   └── modules/                 # DI module definitions
│   │
│   ├── options/                      # Configuration system
│   │   ├── Options.ts
│   │   ├── OptionsNormalizer.ts
│   │   ├── validators/              # Option validation
│   │   ├── normalizer-rules/        # Option normalization
│   │   └── presets/                 # Obfuscation presets
│   │
│   ├── storages/                     # Data storage components
│   │   ├── string-array-transformers/
│   │   ├── control-flow-transformers/
│   │   ├── custom-code-helpers/
│   │   └── identifier-names-cache/
│   │
│   ├── node/                         # AST node utilities
│   │   ├── NodeGuards.ts            # Type guards
│   │   ├── NodeFactory.ts           # Node creation
│   │   ├── NodeAppender.ts          # Node insertion
│   │   ├── NodeStatementUtils.ts
│   │   └── NodeUtils.ts
│   │
│   ├── generators/                   # Name/value generators
│   │   ├── identifier-names-generators/
│   │   └── string-array-index-nodes-generators/
│   │
│   ├── utils/                        # Utility functions
│   │   ├── RandomGenerator.ts
│   │   ├── ArrayUtils.ts
│   │   ├── CryptUtils.ts
│   │   ├── LevelledTopologicalSorter.ts
│   │   └── Utils.ts
│   │
│   ├── cli/                          # CLI utilities
│   │   ├── sanitizers/              # Input sanitizers
│   │   └── utils/                   # File handling
│   │
│   ├── enums/                        # Enumerations
│   ├── interfaces/                   # TypeScript interfaces
│   ├── types/                        # Type definitions
│   ├── constants/                    # Constants
│   ├── decorators/                   # Decorators
│   └── logger/                       # Logging system
│
├── test/                             # Test suite
│   ├── functional-tests/            # Feature tests
│   ├── unit-tests/                  # Unit tests
│   ├── performance-tests/           # Performance benchmarks
│   └── index.spec.ts
│
├── webpack/                          # Build configurations
│   ├── webpack.node.config.js
│   └── webpack.browser.config.js
│
├── dist/                             # Compiled output
│   ├── index.js                     # Node.js bundle
│   └── index.browser.js             # Browser bundle
│
├── bin/                              # CLI executable
│   └── javascript-obfuscator
│
└── typings/                          # TypeScript declarations
```

## Core Workflow

### Obfuscation Pipeline

The obfuscation process follows a multi-stage pipeline defined in `JavaScriptObfuscator.ts`:

```
1. Code Transformation Stage: PreparingTransformers
   └─> Raw code preprocessing (e.g., hashbang handling)

2. AST Parsing
   └─> Parse source code into ESTree-compliant AST using Acorn

3. Node Transformation Stages (sequential):
   ├─> Initializing
   │   └─> Initial AST setup, parentification, metadata
   ├─> Preparing
   │   └─> Scope analysis, obfuscating guards, identifier collection
   ├─> DeadCodeInjection (optional)
   │   └─> Insert dead code blocks
   ├─> ControlFlowFlattening (optional)
   │   └─> Flatten control flow with switch statements
   ├─> RenameProperties (optional)
   │   └─> Rename object properties
   ├─> Converting
   │   └─> Transform nodes (literals, expressions, etc.)
   ├─> RenameIdentifiers
   │   └─> Rename variables and functions
   ├─> StringArray
   │   └─> Extract strings to array, add wrappers
   ├─> Simplifying (optional)
   │   └─> Simplify and merge statements
   └─> Finalizing
       └─> Final cleanup, directive placement

4. Code Generation
   └─> Generate obfuscated code using escodegen

5. Code Transformation Stage: FinalizingTransformers
   └─> Post-processing on generated code

6. Source Map Generation (optional)
   └─> Create source maps for debugging
```

### Dependency Injection Architecture

The project uses **InversifyJS v7** for dependency injection, providing:

- **Modularity**: Clean separation of concerns
- **Testability**: Easy mocking and testing
- **Flexibility**: Runtime configuration of transformers
- **Scalability**: Easy addition of new transformers

All components are registered in container modules located in `src/container/modules/`.

**Key Changes in InversifyJS v7:**
- Container modules now use `ContainerModuleLoadOptions` instead of separate `bind`, `unbind`, etc. parameters
- `getNamed`, `getTagged`, etc. are replaced by `get(serviceId, { name: ... })` or `get(serviceId, { tag: ... })`
- `load()` and `unload()` are now async, with `loadSync()` and `unloadSync()` alternatives for synchronous operations
- Types like `Context`, `Newable`, `Factory` are now directly exported instead of through `interfaces` namespace
- Custom metadata and middleware features have been removed

## Key Components Deep Dive

### 1. JavaScriptObfuscator (Main Engine)

**Location**: `src/JavaScriptObfuscator.ts`

The core orchestrator that:
- Manages the complete obfuscation pipeline
- Coordinates code and node transformers
- Handles AST parsing and code generation
- Integrates with logger and random generator

**Key Methods**:
- `obfuscate(sourceCode: string): IObfuscationResult` - Main entry point
- `parseCode()` - AST parsing with Acorn
- `transformAstTree()` - Applies transformation stages
- `generateCode()` - Code generation with escodegen

### 2. Node Transformers

**Location**: `src/node-transformers/`

Each transformer implements `INodeTransformer` interface with:
- `getVisitor(stage): IVisitor | null` - Returns visitor for specific stage
- `transformNode(node, parent): Node` - Transforms individual AST node

**Key Transformers**:

- **StringArrayTransformer**: Extracts string literals to centralized array
- **BooleanLiteralTransformer**: Converts true/false to `!![]` and `![]`
- **NumberToNumericalExpressionTransformer**: Converts numbers to expressions
- **BlockStatementControlFlowTransformer**: Implements control flow flattening
- **DeadCodeInjectionTransformer**: Injects dead code blocks
- **RenamePropertiesTransformer**: Renames object properties
- **ScopeIdentifiersTransformer**: Renames variables based on scope

### 3. Analyzers

**Location**: `src/analyzers/`

- **CallsGraphAnalyzer**: Builds function call dependency graph
- **ScopeAnalyzer**: Analyzes variable scopes using eslint-scope
- **StringArrayStorageAnalyzer**: Optimizes string array storage
- **PrevailingKindOfVariablesAnalyzer**: Determines var/let/const usage
- **NumberNumericalExpressionAnalyzer**: Analyzes numeric expressions

### 4. Custom Code Helpers

**Location**: `src/custom-code-helpers/`

Injectable runtime helpers that provide:
- **String Array Decoders**: Base64/RC4 decoding functions
- **Debug Protection**: Anti-debugging wrapper code
- **Domain Lock**: Domain validation code
- **Self-Defending**: Code integrity checks
- **Console Output Disable**: Console method replacements

### 5. Options System

**Location**: `src/options/`

Sophisticated configuration system with:
- **Validation**: Using class-validator decorators
- **Normalization**: Automatic option interdependency handling
- **Presets**: Default, low, medium, and high obfuscation presets
- **Type Safety**: Full TypeScript support

**Key Option Categories**:
- Code output (compact, target)
- String transformations (stringArray*, splitStrings)
- Control flow (controlFlowFlattening, deadCodeInjection)
- Naming (identifierNamesGenerator, renameGlobals, renameProperties)
- Protection (selfDefending, debugProtection, domainLock)
- Advanced (numbersToExpressions, simplify, transformObjectKeys)

## Important Patterns and Conventions

### 1. Visitor Pattern

Transformers use the visitor pattern for AST traversal:

```typescript
interface IVisitor {
    enter?: (node: Node, parent: Node) => Node | VisitorOption;
    leave?: (node: Node, parent: Node) => Node | VisitorOption;
}
```

### 2. Initializable Pattern

Many components implement `IInitializable` for lazy initialization:

```typescript
interface IInitializable {
    initialize(...args: any[]): void;
}
```

Managed via `@Initializable()` decorator.

### 3. Stage-Based Processing

Both code and node transformers operate in stages:

**Code Transformation Stages**:
- PreparingTransformers
- FinalizingTransformers

**Node Transformation Stages**:
- Initializing
- Preparing
- DeadCodeInjection
- ControlFlowFlattening
- RenameProperties
- Converting
- RenameIdentifiers
- StringArray
- Simplifying
- Finalizing

### 4. Factory Pattern

Extensive use of factories for object creation:
- `TObfuscationResultFactory`
- Custom node factories
- Identifier name generators

### 5. Storage Pattern

Centralized storages for shared data:
- String array storage
- Custom code helpers storage
- Identifier names cache storage
- Control flow transformers storage

## CLI Usage

**Location**: `bin/javascript-obfuscator`, `src/JavaScriptObfuscatorCLIFacade.ts`

### Basic Commands

```bash
# Obfuscate single file
javascript-obfuscator input.js --output output.js

# Obfuscate directory
javascript-obfuscator ./src --output ./dist

# Use configuration file
javascript-obfuscator input.js --config config.json

# High obfuscation preset
javascript-obfuscator input.js --options-preset high-obfuscation
```

### CLI Features

- Automatic identifier prefix for multiple files
- Glob pattern exclusions
- Source map support
- Identifier names cache (cross-file consistency)
- Progress logging

## API Usage

### Basic Obfuscation

```javascript
const JavaScriptObfuscator = require('javascript-obfuscator');

const obfuscationResult = JavaScriptObfuscator.obfuscate(
    `
    var foo = 'Hello World';
    console.log(foo);
    `,
    {
        compact: true,
        controlFlowFlattening: true
    }
);

console.log(obfuscationResult.getObfuscatedCode());
console.log(obfuscationResult.getSourceMap());
console.log(obfuscationResult.getIdentifierNamesCache());
```

### Multiple Files

```javascript
const sourceCodesObject = {
    'file1.js': 'var foo = 1;',
    'file2.js': 'var bar = 2;'
};

const obfuscationResults = JavaScriptObfuscator.obfuscateMultiple(
    sourceCodesObject,
    options
);
```

### Identifier Names Cache (Cross-File Consistency)

```javascript
// First file
const result1 = JavaScriptObfuscator.obfuscate(code1, {
    identifierNamesCache: {},
    renameGlobals: true
});
const cache = result1.getIdentifierNamesCache();

// Second file using same cache
const result2 = JavaScriptObfuscator.obfuscate(code2, {
    identifierNamesCache: cache,
    renameGlobals: true
});
```

## Browser Support

The project includes a browser build at `dist/index.browser.js` that can be used in web environments:

```html
<script src="https://cdn.jsdelivr.net/npm/javascript-obfuscator/dist/index.browser.js"></script>
<script>
    const obfuscationResult = JavaScriptObfuscator.obfuscate(code, options);
</script>
```

**Note**: No eval() in `browser-no-eval` target.

## Build System

### Webpack Configuration

- **Node.js build**: `webpack/webpack.node.config.js`
  - Target: CommonJS module
  - External dependencies: node_modules
  - Output: `dist/index.js`

- **Browser build**: `webpack/webpack.browser.config.js`
  - Target: UMD module
  - Bundled dependencies
  - Output: `dist/index.browser.js`

### Build Scripts

```bash
# Production build
npm run build

# Development watch mode
npm run watch

# Build TypeScript typings
npm run build:typings

# Linting
npm run eslint
```

## Testing

### Test Structure

**Location**: `test/`

- **Functional tests**: Feature-level tests for transformers and options
- **Unit tests**: Component-level tests
- **Performance tests**: Memory and speed benchmarks

### Running Tests

#### Quick Start

```bash
# Install dependencies first
npm install
# or
yarn install

# Run all tests (includes dev test, coverage, and memory performance)
npm test
# or
yarn test
```

#### Individual Test Commands

```bash
# Run full test suite (test:dev + test:mocha-coverage + test:mocha-memory-performance). This is slow.
npm run test:full
yarn run test:full

# Run Mocha tests only (no coverage)
npm run test:mocha
yarn run test:mocha

# Run tests with coverage report
npm run test:mocha-coverage
yarn run test:mocha-coverage

# Generate detailed coverage report (after running test:mocha-coverage)
npm run test:mocha-coverage:report
yarn run test:mocha-coverage:report

# Run memory performance tests (tests memory constraints)
npm run test:mocha-memory-performance
yarn run test:mocha-memory-performance

# Run development test (custom dev test file)
npm run test:dev
yarn run test:dev

# Run compile performance test
npm run test:devCompilePerformance
yarn run test:devCompilePerformance

# Run runtime performance test
npm run test:devRuntimePerformance
yarn run test:devRuntimePerformance
```

#### Test Details

**test:full**
- Runs the complete test suite
- Includes: development tests, coverage tests, and memory performance tests
- This is what runs when you execute `npm test`

**test:mocha**
- Runs all Mocha tests from `test/index.spec.ts`
- Uses ts-node for TypeScript execution
- No code coverage reporting

**test:mocha-coverage**
- Runs Mocha tests with NYC (Istanbul) code coverage
- Allocates up to 4GB memory (`--max-old-space-size=4096`)
- Generates coverage reports (text-summary by default)
- Use `test:mocha-coverage:report` to generate detailed lcov report

**test:mocha-memory-performance**
- Tests obfuscator memory usage under constraints
- Allocates only 280MB memory to test memory efficiency
- Located at: `test/performance-tests/JavaScriptObfuscatorMemory.spec.ts`

**test:dev**
- Custom development test script
- Located at: `test/dev/dev.ts`
- Useful for quick testing during development

### Test Configuration Files

- **`.mocharc.json`**: Mocha test runner configuration
- **`.nycrc.json`**: NYC (Istanbul) coverage tool configuration
- **TypeScript**: Uses ts-node for direct TS execution without compilation

### Running Specific Test Files

You can run individual test files or groups of tests for faster iteration during development.

#### Basic Command Format

```bash
npx mocha --require ts-node/register --require source-map-support/register <path-to-test-file>
```

#### Common Examples

```bash
# Run a specific test file by exact path
npx mocha --require ts-node/register --require source-map-support/register test/functional-tests/options/Options.spec.ts

# Run CLI tests
npx mocha --require ts-node/register --require source-map-support/register test/functional-tests/cli/JavaScriptObfuscatorCLI.spec.ts

# Run a specific analyzer test
npx mocha --require ts-node/register --require source-map-support/register test/functional-tests/analyzers/calls-graph-analyzer/CallsGraphAnalyzer.spec.ts

# Run scope analyzer tests
npx mocha --require ts-node/register --require source-map-support/register test/functional-tests/analyzers/scope-analyzer/ScopeAnalyzer.spec.ts

# Run string array tests
npx mocha --require ts-node/register --require source-map-support/register test/functional-tests/custom-code-helpers/string-array/StringArrayCodeHelper.spec.ts

# Run self-defending code tests
npx mocha --require ts-node/register --require source-map-support/register test/functional-tests/custom-code-helpers/self-defending/SelfDefendingCodeHelper.spec.ts
```

#### Pattern Matching

Use glob patterns to run multiple related test files:

```bash
# Run all options-related tests
npx mocha --require ts-node/register --require source-map-support/register "test/functional-tests/options/**/*.spec.ts"

# Run all analyzer tests
npx mocha --require ts-node/register --require source-map-support/register "test/functional-tests/analyzers/**/*.spec.ts"

# Run all string array related tests
npx mocha --require ts-node/register --require source-map-support/register "test/functional-tests/**/*StringArray*.spec.ts"

# Run all control flow tests
npx mocha --require ts-node/register --require source-map-support/register "test/functional-tests/**/*ControlFlow*.spec.ts"

# Run all node transformer tests
npx mocha --require ts-node/register --require source-map-support/register "test/functional-tests/node-transformers/**/*.spec.ts"

# Run all unit tests only
npx mocha --require ts-node/register --require source-map-support/register "test/unit-tests/**/*.spec.ts"

# Run all functional tests only
npx mocha --require ts-node/register --require source-map-support/register "test/functional-tests/**/*.spec.ts"
```

#### Running Tests by Category

The test suite is organized into these main categories:

**Functional Tests** (`test/functional-tests/`):
```bash
# Options tests
npx mocha --require ts-node/register --require source-map-support/register "test/functional-tests/options/**/*.spec.ts"

# Analyzers tests
npx mocha --require ts-node/register --require source-map-support/register "test/functional-tests/analyzers/**/*.spec.ts"

# Node transformers tests
npx mocha --require ts-node/register --require source-map-support/register "test/functional-tests/node-transformers/**/*.spec.ts"

# Code transformers tests
npx mocha --require ts-node/register --require source-map-support/register "test/functional-tests/code-transformers/**/*.spec.ts"

# Custom code helpers tests
npx mocha --require ts-node/register --require source-map-support/register "test/functional-tests/custom-code-helpers/**/*.spec.ts"

# Storage tests
npx mocha --require ts-node/register --require source-map-support/register "test/functional-tests/storages/**/*.spec.ts"

# CLI tests
npx mocha --require ts-node/register --require source-map-support/register "test/functional-tests/cli/**/*.spec.ts"

# Generator tests
npx mocha --require ts-node/register --require source-map-support/register "test/functional-tests/generators/**/*.spec.ts"

# Main obfuscator tests
npx mocha --require ts-node/register --require source-map-support/register "test/functional-tests/javascript-obfuscator/**/*.spec.ts"

# Issue regression tests
npx mocha --require ts-node/register --require source-map-support/register "test/functional-tests/issues/**/*.spec.ts"
```

**Unit Tests** (`test/unit-tests/`):
```bash
# All unit tests
npx mocha --require ts-node/register --require source-map-support/register "test/unit-tests/**/*.spec.ts"

# Options unit tests
npx mocha --require ts-node/register --require source-map-support/register "test/unit-tests/options/**/*.spec.ts"

# Utils unit tests
npx mocha --require ts-node/register --require source-map-support/register "test/unit-tests/utils/**/*.spec.ts"

# Node utilities unit tests
npx mocha --require ts-node/register --require source-map-support/register "test/unit-tests/node/**/*.spec.ts"
```

**Performance Tests** (`test/performance-tests/`):
```bash
# Memory performance tests
npx mocha --require ts-node/register --require source-map-support/register test/performance-tests/JavaScriptObfuscatorMemory.spec.ts
```

#### Using Mocha Options with Individual Tests

```bash
# Run with grep to filter by test description
npx mocha --require ts-node/register --require source-map-support/register test/functional-tests/options/Options.spec.ts --grep "compact"

# Run and show slow tests
npx mocha --require ts-node/register --require source-map-support/register test/functional-tests/options/Options.spec.ts --reporter spec

# Run with timeout override (default is 10000ms)
npx mocha --require ts-node/register --require source-map-support/register test/functional-tests/options/Options.spec.ts --timeout 20000

# Run with bail (stop on first failure)
npx mocha --require ts-node/register --require source-map-support/register "test/functional-tests/**/*.spec.ts" --bail

# Run and watch for changes
npx mocha --require ts-node/register --require source-map-support/register test/functional-tests/options/Options.spec.ts --watch

# Run with specific reporter
npx mocha --require ts-node/register --require source-map-support/register test/functional-tests/options/Options.spec.ts --reporter json
```

#### Creating Test Aliases (Optional)

For convenience, you can add these aliases to your `package.json` scripts:

```json
{
  "scripts": {
    "test:options": "mocha --require ts-node/register --require source-map-support/register 'test/functional-tests/options/**/*.spec.ts'",
    "test:analyzers": "mocha --require ts-node/register --require source-map-support/register 'test/functional-tests/analyzers/**/*.spec.ts'",
    "test:transformers": "mocha --require ts-node/register --require source-map-support/register 'test/functional-tests/node-transformers/**/*.spec.ts'",
    "test:unit": "mocha --require ts-node/register --require source-map-support/register 'test/unit-tests/**/*.spec.ts'",
    "test:functional": "mocha --require ts-node/register --require source-map-support/register 'test/functional-tests/**/*.spec.ts'"
  }
}
```

Then run with:
```bash
npm run test:options
npm run test:analyzers
npm run test:transformers
```

#### Tips for Running Individual Tests

1. **Use quotes around glob patterns** to prevent shell expansion:
   ```bash
   # Good
   npx mocha "test/**/*.spec.ts"

   # Bad (shell will expand the pattern)
   npx mocha test/**/*.spec.ts
   ```

2. **Use --grep to run specific test cases** within a file:
   ```bash
   npx mocha --require ts-node/register test/functional-tests/options/Options.spec.ts --grep "should enable compact"
   ```

3. **Use --bail to stop on first failure** when debugging:
   ```bash
   npx mocha --require ts-node/register "test/**/*.spec.ts" --bail
   ```

4. **Check the exit code** to verify test success in scripts:
   ```bash
   npx mocha --require ts-node/register test/functional-tests/options/Options.spec.ts && echo "Tests passed!"
   ```

5. **Combine with watch mode** for TDD workflow:
   ```bash
   npx mocha --require ts-node/register test/functional-tests/options/Options.spec.ts --watch --reporter min
   ```

## Linting

### Running ESLint

#### Quick Start

```bash
# Lint all TypeScript files in src/
npm run eslint
yarn run eslint
```

This runs: `eslint src/**/*.ts`

#### Linting Individual Files

You can lint specific files or directories for faster feedback during development.

**Basic Command Format:**
```bash
npx eslint <path-to-file-or-directory>
```

**Common Examples:**

```bash
# Lint a specific file
npx eslint src/JavaScriptObfuscator.ts

# Lint the main facade file
npx eslint src/JavaScriptObfuscatorFacade.ts

# Lint a specific transformer
npx eslint src/node-transformers/converting-transformers/StringArrayTransformer.ts

# Lint a specific analyzer
npx eslint src/analyzers/calls-graph-analyzer/CallsGraphAnalyzer.ts

# Lint options file
npx eslint src/options/Options.ts

# Lint a custom code helper
npx eslint src/custom-code-helpers/string-array/StringArrayCodeHelper.ts

# Lint container files
npx eslint src/container/InversifyContainerFacade.ts
```

#### Linting Multiple Files or Directories

```bash
# Lint entire src directory
npx eslint src/

# Lint all files in a specific subdirectory
npx eslint src/node-transformers/

# Lint all analyzers
npx eslint src/analyzers/

# Lint all transformers
npx eslint src/node-transformers/**/*.ts

# Lint all options-related files
npx eslint src/options/

# Lint all custom code helpers
npx eslint src/custom-code-helpers/

# Lint all utils
npx eslint src/utils/

# Lint CLI files
npx eslint src/cli/

# Lint container modules
npx eslint src/container/

# Lint storage files
npx eslint src/storages/
```

#### Using Glob Patterns

```bash
# Lint all TypeScript files in src (same as npm run eslint)
npx eslint "src/**/*.ts"

# Lint all transformer files
npx eslint "src/**/*Transformer.ts"

# Lint all analyzer files
npx eslint "src/**/*Analyzer.ts"

# Lint all storage files
npx eslint "src/**/*Storage.ts"

# Lint all helper files
npx eslint "src/**/*Helper.ts"

# Lint all files containing "String" in the name
npx eslint "src/**/*String*.ts"

# Lint all files in node-transformers subdirectories
npx eslint "src/node-transformers/**/*.ts"
```

#### Auto-fixing Issues

ESLint can automatically fix many issues:

```bash
# Auto-fix all files in src/
npx eslint src/**/*.ts --fix

# Auto-fix a specific file
npx eslint src/JavaScriptObfuscator.ts --fix

# Auto-fix specific directory
npx eslint src/node-transformers/ --fix

# Auto-fix with glob pattern
npx eslint "src/analyzers/**/*.ts" --fix

# Auto-fix only safe fixes (no potentially breaking changes)
npx eslint src/JavaScriptObfuscator.ts --fix --fix-type suggestion,layout
```

#### Checking Specific Rules

```bash
# Show only errors (no warnings)
npx eslint src/JavaScriptObfuscator.ts --quiet

# Check specific rule only
npx eslint src/JavaScriptObfuscator.ts --rule 'no-console: error'

# Disable specific rules for a file check
npx eslint src/JavaScriptObfuscator.ts --rule 'no-console: off'

# Output format options
npx eslint src/JavaScriptObfuscator.ts --format stylish  # Default
npx eslint src/JavaScriptObfuscator.ts --format json     # JSON output
npx eslint src/JavaScriptObfuscator.ts --format compact  # Compact output
npx eslint src/JavaScriptObfuscator.ts --format unix     # Unix style
```

#### Getting Detailed Information

```bash
# Show more details about errors
npx eslint src/JavaScriptObfuscator.ts --format stylish

# List all files that would be linted (dry-run)
npx eslint src/ --debug 2>&1 | grep "Processing"

# Show timing information for rules
npx eslint src/JavaScriptObfuscator.ts --debug

# Get statistics about linting
npx eslint src/ --format json | jq '.[] | {file: .filePath, errors: .errorCount, warnings: .warningCount}'
```

#### Linting by Component

Organized by project structure:

**Core Files:**
```bash
npx eslint src/JavaScriptObfuscator.ts
npx eslint src/JavaScriptObfuscatorFacade.ts
npx eslint src/ASTParserFacade.ts
```

**Node Transformers:**
```bash
# All node transformers
npx eslint src/node-transformers/

# Converting transformers
npx eslint src/node-transformers/converting-transformers/

# Control flow transformers
npx eslint src/node-transformers/control-flow-transformers/

# String array transformers
npx eslint src/node-transformers/string-array-transformers/

# Rename transformers
npx eslint src/node-transformers/rename-identifiers-transformers/
npx eslint src/node-transformers/rename-properties-transformers/
```

**Analyzers:**
```bash
# All analyzers
npx eslint src/analyzers/

# Specific analyzers
npx eslint src/analyzers/calls-graph-analyzer/
npx eslint src/analyzers/scope-analyzer/
npx eslint src/analyzers/string-array-storage-analyzer/
```

**Options System:**
```bash
# All options files
npx eslint src/options/

# Core options
npx eslint src/options/Options.ts
npx eslint src/options/OptionsNormalizer.ts

# Validators
npx eslint src/options/validators/

# Presets
npx eslint src/options/presets/
```

**Custom Code Helpers:**
```bash
# All helpers
npx eslint src/custom-code-helpers/

# String array helpers
npx eslint src/custom-code-helpers/string-array/

# Debug protection helpers
npx eslint src/custom-code-helpers/debug-protection/

# Self-defending helpers
npx eslint src/custom-code-helpers/self-defending/
```

**Utilities:**
```bash
# All utils
npx eslint src/utils/

# Specific utils
npx eslint src/utils/RandomGenerator.ts
npx eslint src/utils/ArrayUtils.ts
npx eslint src/utils/CryptUtils.ts
```

#### Integrating with Git

```bash
# Lint only staged files (useful for pre-commit)
git diff --cached --name-only --diff-filter=ACM | grep '\.ts$' | xargs npx eslint

# Lint files changed in current branch
git diff --name-only master | grep '\.ts$' | xargs npx eslint

# Lint files changed in last commit
git diff HEAD~1 --name-only | grep '\.ts$' | xargs npx eslint
```

#### Creating Lint Aliases (Optional)

Add these to your `package.json` scripts for convenience:

```json
{
  "scripts": {
    "lint": "eslint src/**/*.ts",
    "lint:fix": "eslint src/**/*.ts --fix",
    "lint:transformers": "eslint src/node-transformers/**/*.ts",
    "lint:analyzers": "eslint src/analyzers/**/*.ts",
    "lint:options": "eslint src/options/**/*.ts",
    "lint:utils": "eslint src/utils/**/*.ts",
    "lint:quiet": "eslint src/**/*.ts --quiet",
    "lint:staged": "git diff --cached --name-only --diff-filter=ACM | grep '\\.ts$' | xargs eslint"
  }
}
```

Then run with:
```bash
npm run lint:transformers
npm run lint:analyzers
npm run lint:fix
```

### ESLint Configuration

**Location**: `.eslintrc.js`

The project uses:
- **@typescript-eslint**: TypeScript-specific linting rules
- **eslint-plugin-import**: Import/export validation
- **eslint-plugin-jsdoc**: JSDoc comment validation
- **eslint-plugin-no-null**: Prevents null usage (prefer undefined)
- **eslint-plugin-prefer-arrow**: Enforces arrow functions
- **eslint-plugin-unicorn**: Additional code quality rules

**Ignored files**: `.eslintignore`

#### Viewing Current ESLint Config

```bash
# Print effective configuration for a file
npx eslint --print-config src/JavaScriptObfuscator.ts

# List all rules being applied
npx eslint --print-config src/JavaScriptObfuscator.ts | grep rules -A 1000
```

### Code Quality Checks

```bash
# Run full build (includes webpack, eslint, and tests)
npm run build
yarn run build

# The build script runs:
# 1. webpack:prod (production build)
# 2. eslint (linting)
# 3. test (full test suite)
```

### Tips for Effective Linting

1. **Lint before committing**: Always run linting before creating commits
   ```bash
   npx eslint src/ && git commit -m "Your message"
   ```

2. **Use --fix cautiously**: Review changes before committing auto-fixes
   ```bash
   npx eslint src/MyFile.ts --fix
   git diff  # Review changes
   ```

3. **Focus on errors first**: Use `--quiet` to see only errors
   ```bash
   npx eslint src/ --quiet
   ```

4. **Lint specific files during development**: Don't lint everything when working on one file
   ```bash
   npx eslint src/node-transformers/MyNewTransformer.ts
   ```

5. **Check exit code**: Useful in scripts and CI/CD
   ```bash
   npx eslint src/ || echo "Linting failed!"
   ```

## Development Workflow

### Setting Up Development Environment

```bash
# 1. Clone the repository
git clone https://github.com/javascript-obfuscator/javascript-obfuscator.git
cd javascript-obfuscator

# 2. Install dependencies
npm install
# or
yarn install

# 3. Install Husky hooks (for pre-commit checks)
npm run prepare
# or
yarn run prepare
```

### Development Commands

```bash
# Start development mode with watch (auto-recompile on changes)
npm start
# or
npm run watch
# or
yarn run watch

# Build for production
npm run webpack:prod
yarn run webpack:prod

# Build TypeScript type definitions
npm run build:typings
yarn run build:typings

# Full build (webpack + eslint + tests)
npm run build
yarn run build
```

### Pre-commit Hooks

The project uses **Husky** for git hooks:

- **pre-commit**: Automatically runs `npm run build` before each commit
  - Ensures code compiles
  - Ensures linting passes
  - Ensures all tests pass

**Configuration**: `.husky/` directory

### Development Tips

1. **Use watch mode during development**:
   ```bash
   npm run watch
   ```
   This rebuilds automatically when you save files.

2. **Run specific tests during development**:
   ```bash
   npm run test:dev
   ```
   Faster than full test suite.

3. **Check linting before committing**:
   ```bash
   npm run eslint
   ```
   Fix issues before the pre-commit hook runs.

4. **Test memory usage**:
   ```bash
   npm run test:mocha-memory-performance
   ```
   Ensure your changes don't cause memory issues.

5. **Generate coverage reports**:
   ```bash
   npm run test:mocha-coverage
   npm run test:mocha-coverage:report
   ```
   Check test coverage in the generated `coverage/` directory.

## Performance Considerations

### Impact on Code Size

- **Default**: ~15-30% increase
- **Dead Code Injection**: Up to 200% increase
- **String Array**: 20-50% increase
- **Control Flow Flattening**: 30-80% increase

### Runtime Performance

- **No obfuscation**: Baseline
- **Low preset**: ~10-20% slower
- **Medium preset**: ~30-50% slower
- **High preset**: ~50-80% slower

### Optimization Tips

1. Use **thresholds** to apply transformations selectively:
   - `controlFlowFlatteningThreshold`
   - `deadCodeInjectionThreshold`
   - `stringArrayThreshold`

2. Avoid obfuscating:
   - Third-party libraries
   - Polyfills
   - Large vendor bundles

3. Use **seed** option for reproducible builds

4. Enable **simplify** for better performance (enabled by default)

## Security Considerations

### What It Protects

- Makes reverse engineering harder
- Prevents casual code inspection
- Protects string literals and algorithms
- Adds anti-debugging measures
- Can lock code to specific domains

### What It Doesn't Protect

- Determined attackers with time and tools
- Network traffic and API endpoints
- Runtime behavior analysis
- Secrets embedded in code (use environment variables!)

### Best Practices

1. **Never obfuscate secrets**: Use environment variables or secure vaults
2. **Combine with other protections**: Minification, HTTPS, CSP headers
3. **Test thoroughly**: Obfuscation can introduce subtle bugs
4. **Monitor performance**: High obfuscation impacts runtime speed
5. **Use source maps carefully**: Keep them private for debugging

## Conditional Comments

Control obfuscation for specific code sections:

```javascript
var foo = 1;
// javascript-obfuscator:disable
var bar = 2; // This won't be obfuscated
// javascript-obfuscator:enable
var baz = 3;
```

## Integration with Build Tools

### Webpack

Use [webpack-obfuscator](https://github.com/javascript-obfuscator/webpack-obfuscator) plugin

### Gulp

Use [gulp-javascript-obfuscator](https://github.com/javascript-obfuscator/gulp-javascript-obfuscator)

### Rollup

Use [rollup-plugin-javascript-obfuscator](https://github.com/javascript-obfuscator/rollup-plugin-javascript-obfuscator)

### Grunt

Use [grunt-contrib-obfuscator](https://github.com/javascript-obfuscator/grunt-contrib-obfuscator)

## Common Issues and Solutions

### Issue: Code breaks after obfuscation

**Solutions**:
- Add function/variable names to `reservedNames`
- Add strings to `reservedStrings`
- Use `renamePropertiesMode: 'safe'` instead of 'unsafe'
- Disable `renameProperties` if safe mode doesn't work
- Check for dynamic property access like `obj[dynamicKey]`

### Issue: Performance is too slow

**Solutions**:
- Use lower obfuscation preset
- Reduce threshold values
- Disable `controlFlowFlattening` and `deadCodeInjection`
- Use `target: 'browser-no-eval'` if applicable

### Issue: Code size is too large

**Solutions**:
- Disable `deadCodeInjection`
- Reduce `stringArrayWrappersCount`
- Use lower `stringArrayThreshold`
- Disable `unicodeEscapeSequence`

### Issue: Source maps not working

**Solutions**:
- Ensure `sourceMap: true` in options
- Set correct `sourceMapMode` ('inline' or 'separate')
- Specify `inputFileName` when using NodeJS API
- Use `sourceMapSourcesMode: 'sources-content'` for embedded source

### Issue: Domain lock not working

**Solutions**:
- Don't use with `target: 'node'`
- Test in actual browser environment
- Check domain format (`.example.com` for all subdomains)
- Ensure `domainLockRedirectUrl` is set

## Extension Points

### Adding Custom Transformers

1. Create transformer class extending `AbstractNodeTransformer`
2. Implement `getVisitor()` and `transformNode()` methods
3. Register in appropriate module (`src/container/modules/node-transformers/`)
4. Add to transformer list in `JavaScriptObfuscator.ts`
5. Add to `NodeTransformer` enum

### Adding Custom Options

1. Add property to `IOptions` interface
2. Add validation decorator in `Options.ts`
3. Add normalizer rule if needed in `options/normalizer-rules/`
4. Add preset values if applicable

### Adding Custom Code Helpers

1. Create helper group extending `AbstractCustomCodeHelperGroup`
2. Create template files in `custom-code-helpers/[group]/templates/`
3. Register in `CustomCodeHelpersModule`
4. Add to `CustomCodeHelper` enum

## TypeScript Configuration

### Main Config

**Location**: `tsconfig.json`

- **Target**: ES2018
- **Module**: CommonJS
- **Strict mode**: Enabled
- **Decorators**: Enabled (experimental)
- **Emit decorator metadata**: Enabled

### Special Configs

- `tsconfig.browser.json`: Browser-specific settings
- `tsconfig.node.json`: Node.js-specific settings
- `tsconfig.typings.json`: Type declarations generation

## Dependencies Overview

### Production Dependencies

- **@javascript-obfuscator/escodegen**: Modified escodegen for code generation
- **@javascript-obfuscator/estraverse**: Modified estraverse for AST traversal
- **acorn**: JavaScript parser (ES3-ES2020)
- **inversify**: Dependency injection container
- **eslint-scope**: Scope analysis (from ESLint)
- **class-validator**: Options validation
- **chance**: Random data generation
- **commander**: CLI argument parsing
- **chalk**: Terminal colors
- **md5**: Hashing for identifiers

### Development Dependencies

- **TypeScript**: Type system and compiler
- **Webpack**: Module bundler
- **Mocha + Chai**: Testing framework
- **NYC**: Code coverage
- **ESLint**: Code linting
- **Sinon**: Test mocking

## Contributing

**Location**: `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`

1. Fork the repository
2. Create feature branch
3. Write tests for new features
4. Ensure all tests pass
5. Follow existing code style (ESLint)
6. Submit pull request

## Versioning and Releases

- Follows semantic versioning (SemVer)
- Changelog maintained in `CHANGELOG.md`
- Precommit hooks run build and tests (Husky)
- Automated CI/CD via GitHub Actions

## Support and Community

- **GitHub Issues**: Bug reports and feature requests
- **GitHub Discussions**: Questions and general discussion
- **GitHub Sponsors**: Direct sponsorship

## License

**BSD-2-Clause License**

Copyright (C) 2016-2026 Timofei Kachalov

See `LICENSE.BSD` for full license text.

## Project Statistics

- **First Release**: 2016
- **Language**: TypeScript (~90% of codebase)
- **Test Coverage**: Extensive functional and unit test suite
- **Supported JavaScript Versions**: ES3, ES5, ES2015-ES2019, partial ES2020
- **Downloads**: Widely used in production applications
- **Maintenance**: Actively maintained

## Resources

- **Main Repository**: https://github.com/javascript-obfuscator/javascript-obfuscator
- **Online Tool**: https://obfuscator.io
- **NPM Package**: https://www.npmjs.com/package/javascript-obfuscator
- **Documentation**: In README.md and inline code comments

---

## Quick Reference: File Locations

| Component | Primary Location |
|-----------|------------------|
| Main Obfuscator | `src/JavaScriptObfuscator.ts` |
| Public API | `src/JavaScriptObfuscatorFacade.ts` |
| CLI | `bin/javascript-obfuscator`, `src/JavaScriptObfuscatorCLIFacade.ts` |
| Options | `src/options/Options.ts` |
| Transformers | `src/node-transformers/` |
| Analyzers | `src/analyzers/` |
| DI Container | `src/container/InversifyContainerFacade.ts` |
| Tests | `test/` |
| Build Config | `webpack/` |
| Distribution | `dist/` |

## Quick Reference: Key Enums

- **CodeTransformationStage**: PreparingTransformers, FinalizingTransformers
- **NodeTransformationStage**: Initializing, Preparing, DeadCodeInjection, ControlFlowFlattening, RenameProperties, Converting, RenameIdentifiers, StringArray, Simplifying, Finalizing
- **OptionsPreset**: default, low-obfuscation, medium-obfuscation, high-obfuscation
- **StringArrayEncoding**: none, base64, rc4
- **IdentifierNamesGenerator**: hexadecimal, mangled, mangled-shuffled, dictionary
- **RenamePropertiesMode**: safe, unsafe
- **Target**: browser, browser-no-eval, node
