Browse Source

Merge pull request #180 from javascript-obfuscator/identifirs-prefix

`identifiersPrefix` option
Timofey Kachalov 7 years ago
parent
commit
2b2cc13429
44 changed files with 635 additions and 173 deletions
  1. 1 0
      CHANGELOG.md
  2. 9 0
      README.md
  3. 0 0
      dist/index.js
  4. 11 11
      package.json
  5. 31 6
      src/cli/JavaScriptObfuscatorCLI.ts
  6. 4 4
      src/container/InversifyContainerFacade.ts
  7. 2 0
      src/container/ServiceIdentifiers.ts
  8. 18 0
      src/container/modules/options/OptionsModule.ts
  9. 1 1
      src/custom-nodes/console-output-nodes/ConsoleOutputDisableExpressionNode.ts
  10. 1 1
      src/custom-nodes/console-output-nodes/group/ConsoleOutputCustomNodeGroup.ts
  11. 2 2
      src/custom-nodes/debug-protection-nodes/group/DebugProtectionCustomNodeGroup.ts
  12. 1 1
      src/custom-nodes/domain-lock-nodes/DomainLockNode.ts
  13. 1 1
      src/custom-nodes/domain-lock-nodes/group/DomainLockCustomNodeGroup.ts
  14. 1 1
      src/custom-nodes/self-defending-nodes/SelfDefendingUnicodeNode.ts
  15. 1 1
      src/custom-nodes/self-defending-nodes/group/SelfDefendingCustomNodeGroup.ts
  16. 2 2
      src/custom-nodes/string-array-nodes/StringArrayRotateFunctionNode.ts
  17. 6 2
      src/generators/identifier-names-generators/AbstractIdentifierNamesGenerator.ts
  18. 21 8
      src/generators/identifier-names-generators/HexadecimalIdentifierNamesGenerator.ts
  19. 16 5
      src/generators/identifier-names-generators/MangledIdentifierNamesGenerator.ts
  20. 6 2
      src/interfaces/generators/identifier-names-generators/IIdentifierNamesGenerator.d.ts
  21. 8 2
      src/interfaces/node-transformers/obfuscating-transformers/obfuscating-replacers/IIdentifierObfuscatingReplacer.d.ts
  22. 1 0
      src/interfaces/options/IOptions.d.ts
  23. 9 0
      src/interfaces/options/IOptionsNormalizer.d.ts
  24. 1 1
      src/node-transformers/obfuscating-transformers/CatchClauseTransformer.ts
  25. 15 6
      src/node-transformers/obfuscating-transformers/ClassDeclarationTransformer.ts
  26. 15 6
      src/node-transformers/obfuscating-transformers/FunctionDeclarationTransformer.ts
  27. 2 2
      src/node-transformers/obfuscating-transformers/FunctionTransformer.ts
  28. 1 2
      src/node-transformers/obfuscating-transformers/LabeledStatementTransformer.ts
  29. 15 6
      src/node-transformers/obfuscating-transformers/VariableDeclarationTransformer.ts
  30. 23 4
      src/node-transformers/obfuscating-transformers/obfuscating-replacers/identifier-obfuscating-replacers/BaseIdentifierObfuscatingReplacer.ts
  31. 16 4
      src/options/Options.ts
  32. 6 2
      src/options/OptionsNormalizer.ts
  33. 1 0
      src/options/presets/Default.ts
  34. 1 0
      src/options/presets/NoCustomNodes.ts
  35. 13 2
      src/storages/string-array/StringArrayStorage.ts
  36. 7 6
      test/dev/dev.ts
  37. 80 3
      test/functional-tests/cli/JavaScriptObfuscatorCLI.spec.ts
  38. 135 14
      test/functional-tests/javascript-obfuscator/JavaScriptObfuscator.spec.ts
  39. 7 0
      test/functional-tests/javascript-obfuscator/fixtures/identifiers-prefix.js
  40. 17 5
      test/functional-tests/options/OptionsNormalizer.spec.ts
  41. 1 1
      test/index.spec.ts
  42. 28 18
      test/unit-tests/generators/identifier-names-generators/HexadecimalIdentifierNamesGenerator.spec.ts
  43. 48 7
      test/unit-tests/generators/identifier-names-generators/MangledlIdentifierNamesGenerator.spec.ts
  44. 50 34
      yarn.lock

+ 1 - 0
CHANGELOG.md

@@ -2,6 +2,7 @@ Change Log
 ===
 v0.14.0
 ---
+* **New option:** `identifiersPrefix` sets prefix for all generated identifiers.
 * **New option:** `transformObjectKeys` enables object keys transformation and obfuscation.
 * **New feature:** `eval` expressions obfuscation.
 * **Breaking change:** Now CLI obfuscating directory recursively. Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/157

+ 9 - 0
README.md

@@ -277,6 +277,7 @@ Following options are available for the JS Obfuscator:
     disableConsoleOutput: false,
     domainLock: [],
     identifierNamesGenerator: 'hexadecimal',
+    identifiersPrefix: '',
     log: false,
     renameGlobals: false,
     reservedNames: [],
@@ -314,6 +315,7 @@ Following options are available for the JS Obfuscator:
     --disable-console-output <boolean>
     --domain-lock '<list>' (comma separated)
     --identifier-names-generator <string> [hexadecimal, mangled]
+    --identifiers-prefix <string>
     --log <boolean>
     --rename-globals <boolean>
     --reserved-names '<list>' (comma separated)
@@ -570,6 +572,13 @@ Available values:
 * `hexadecimal`: identifier names like `_0xabc123`
 * `mangled`: short identifier names like `a`, `b`, `c`
 
+### `identifiersPrefix`
+Type: `string` Default: `''`
+
+Sets prefix for all generated identifiers.
+
+Use this option when you want to obfuscate multiple files. This option helps to avoid conflicts between identifiers of these files. Prefix should be different for every file.
+
 ### `log`
 Type: `boolean` Default: `false`
 

File diff suppressed because it is too large
+ 0 - 0
dist/index.js


+ 11 - 11
package.json

@@ -1,6 +1,6 @@
 {
   "name": "javascript-obfuscator",
-  "version": "0.14.0-beta.2",
+  "version": "0.14.0-beta.3",
   "description": "JavaScript obfuscator",
   "keywords": [
     "obfuscator",
@@ -21,9 +21,9 @@
   "dependencies": {
     "chalk": "2.3.0",
     "chance": "1.0.13",
-    "class-validator": "0.7.3",
+    "class-validator": "0.8.1",
     "commander": "2.13.0",
-    "escodegen-wallaby": "1.6.16",
+    "escodegen-wallaby": "1.6.17",
     "esprima": "4.0.0",
     "estraverse": "4.2.0",
     "inversify": "4.9.0",
@@ -32,13 +32,13 @@
     "mkdirp": "0.5.1",
     "opencollective": "1.0.3",
     "pjson": "1.0.9",
-    "reflect-metadata": "0.1.10",
-    "source-map-support": "0.5.0",
+    "reflect-metadata": "0.1.12",
+    "source-map-support": "0.5.2",
     "string-template": "1.0.0",
-    "tslib": "1.8.1"
+    "tslib": "1.9.0"
   },
   "devDependencies": {
-    "@types/chai": "4.1.0",
+    "@types/chai": "4.1.2",
     "@types/chance": "0.7.36",
     "@types/escodegen": "0.0.6",
     "@types/esprima": "4.0.1",
@@ -46,7 +46,7 @@
     "@types/estree": "0.0.38",
     "@types/md5": "2.1.32",
     "@types/mkdirp": "0.5.2",
-    "@types/mocha": "2.2.46",
+    "@types/mocha": "2.2.47",
     "@types/node": "9.3.0",
     "@types/rimraf": "2.0.2",
     "@types/sinon": "4.1.3",
@@ -60,11 +60,11 @@
     "chai": "4.1.2",
     "coveralls": "3.0.0",
     "istanbul": "1.1.0-alpha.1",
-    "mocha": "4.1.0",
+    "mocha": "5.0.0",
     "pre-commit": "1.2.2",
     "rimraf": "2.6.2",
-    "sinon": "4.1.5",
-    "threads": "0.10.0",
+    "sinon": "4.2.1",
+    "threads": "0.10.1",
     "ts-node": "4.1.0",
     "tslint": "5.9.1",
     "tslint-eslint-rules": "4.1.1",

+ 31 - 6
src/cli/JavaScriptObfuscatorCLI.ts

@@ -44,6 +44,11 @@ export class JavaScriptObfuscatorCLI implements IInitializable {
      */
     public static obfuscatedFilePrefix: string = '-obfuscated';
 
+    /**
+     * @type {string}
+     */
+    private static readonly baseIdentifiersPrefix: string = 'a';
+
     /**
      * @type {string[]}
      */
@@ -244,6 +249,10 @@ export class JavaScriptObfuscatorCLI implements IInitializable {
                 '--identifier-names-generator <string> [hexadecimal, mangled]', 'Sets identifier names generator (Default: hexadecimal)',
                 IdentifierNamesGeneratorSanitizer
             )
+            .option(
+                '--identifiers-prefix <string>',
+                'Sets prefix for all generated identifiers.'
+            )
             .option(
                 '--log <boolean>', 'Enables logging of the information to the console',
                 BooleanSanitizer
@@ -295,7 +304,7 @@ export class JavaScriptObfuscatorCLI implements IInitializable {
                 BooleanSanitizer
             )
             .option(
-                '--string-array-encoding <boolean|string> [true, false, base64, rc4]',
+                '--string-array-encoding <string|boolean> [true, false, base64, rc4]',
                 'Encodes all strings in strings array using base64 or rc4 (this option can slow down your code speed',
                 StringArrayEncodingSanitizer
             )
@@ -343,14 +352,14 @@ export class JavaScriptObfuscatorCLI implements IInitializable {
         if (!Array.isArray(sourceCodeData)) {
             const outputCodePath: string = outputPath || CLIUtils.getOutputCodePath(this.inputPath);
 
-            this.processSourceCode(sourceCodeData, outputCodePath);
+            this.processSourceCode(sourceCodeData, outputCodePath, null);
         } else {
-            sourceCodeData.forEach(({ filePath, content }: IFileData) => {
+            sourceCodeData.forEach(({ filePath, content }: IFileData, index: number) => {
                 const outputCodePath: string = outputPath
                     ? path.join(outputPath, filePath)
                     : CLIUtils.getOutputCodePath(filePath);
 
-                this.processSourceCode(content, outputCodePath);
+                this.processSourceCode(content, outputCodePath, index);
             });
         }
     }
@@ -358,9 +367,25 @@ export class JavaScriptObfuscatorCLI implements IInitializable {
     /**
      * @param {string} sourceCode
      * @param {string} outputCodePath
+     * @param {number | null} sourceCodeIndex
      */
-    private processSourceCode (sourceCode: string, outputCodePath: string): void {
-        const options: TInputOptions = this.buildOptions();
+    private processSourceCode (
+        sourceCode: string,
+        outputCodePath: string,
+        sourceCodeIndex: number | null
+    ): void {
+        let options: TInputOptions = this.buildOptions();
+
+        if (sourceCodeIndex !== null) {
+            const baseIdentifiersPrefix: string = this.inputCLIOptions.identifiersPrefix
+                || JavaScriptObfuscatorCLI.baseIdentifiersPrefix;
+            const identifiersPrefix: string = `${baseIdentifiersPrefix}${sourceCodeIndex}`;
+
+            options = {
+                ...options,
+                identifiersPrefix
+            };
+        }
 
         if (options.sourceMap) {
             JavaScriptObfuscatorCLI.processSourceCodeWithSourceMap(sourceCode, outputCodePath, options);

+ 4 - 4
src/container/InversifyContainerFacade.ts

@@ -9,6 +9,7 @@ import { finalizingTransformersModule } from './modules/node-transformers/Finali
 import { generatorsModule } from './modules/generators/GeneratorsModule';
 import { nodeTransformersModule } from './modules/node-transformers/NodeTransformersModule';
 import { obfuscatingTransformersModule } from './modules/node-transformers/ObfuscatingTransformersModule';
+import { optionsModule } from './modules/options/OptionsModule';
 import { preparingTransformersModule } from './modules/node-transformers/PreparingTransformersModule';
 import { storagesModule } from './modules/storages/StoragesModule';
 import { utilsModule } from './modules/utils/UtilsModule';
@@ -20,7 +21,6 @@ import { IJavaScriptObfuscator } from '../interfaces/IJavaScriptObfsucator';
 import { ILogger } from '../interfaces/logger/ILogger';
 import { IObfuscationEventEmitter } from '../interfaces/event-emitters/IObfuscationEventEmitter';
 import { IObfuscationResult } from '../interfaces/IObfuscationResult';
-import { IOptions } from '../interfaces/options/IOptions';
 import { ISourceCode } from '../interfaces/ISourceCode';
 import { ISourceMapCorrector } from '../interfaces/source-map/ISourceMapCorrector';
 import { ITransformersRunner } from '../interfaces/node-transformers/ITransformersRunner';
@@ -29,7 +29,6 @@ import { JavaScriptObfuscator } from '../JavaScriptObfuscator';
 import { Logger } from '../logger/Logger';
 import { ObfuscationEventEmitter } from '../event-emitters/ObfuscationEventEmitter';
 import { ObfuscationResult } from '../ObfuscationResult';
-import { Options } from "../options/Options";
 import { SourceCode } from '../SourceCode';
 import { SourceMapCorrector } from '../source-map/SourceMapCorrector';
 import { TransformersRunner } from '../node-transformers/TransformersRunner';
@@ -147,8 +146,8 @@ export class InversifyContainerFacade implements IInversifyContainerFacade {
             .inSingletonScope();
 
         this.container
-            .bind<IOptions>(ServiceIdentifiers.IOptions)
-            .toDynamicValue(() => new Options(options))
+            .bind<TInputOptions>(ServiceIdentifiers.TInputOptions)
+            .toDynamicValue(() => options)
             .inSingletonScope();
 
         this.container
@@ -203,6 +202,7 @@ export class InversifyContainerFacade implements IInversifyContainerFacade {
         this.container.load(generatorsModule);
         this.container.load(nodeTransformersModule);
         this.container.load(obfuscatingTransformersModule);
+        this.container.load(optionsModule);
         this.container.load(preparingTransformersModule);
         this.container.load(storagesModule);
         this.container.load(utilsModule);

+ 2 - 0
src/container/ServiceIdentifiers.ts

@@ -28,6 +28,7 @@ export enum ServiceIdentifiers {
     IObfuscationEventEmitter = 'IObfuscationEventEmitter',
     IObfuscationResult = 'IObfuscationResult',
     IOptions = 'IOptions',
+    IOptionsNormalizer = 'IOptionsNormalizer',
     IObfuscatingReplacer = 'IObfuscatingReplacer',
     IRandomGenerator = 'IRandomGenerator',
     ISourceCode = 'ISourceCode',
@@ -37,5 +38,6 @@ export enum ServiceIdentifiers {
     Newable__ICustomNode = 'Newable<ICustomNode>',
     Newable__TControlFlowStorage = 'Newable<TControlFlowStorage>',
     TCustomNodeGroupStorage = 'TCustomNodeGroupStorage',
+    TInputOptions = 'TInputOptions',
     TStringArrayStorage = 'TStringArrayStorage'
 }

+ 18 - 0
src/container/modules/options/OptionsModule.ts

@@ -0,0 +1,18 @@
+import { ContainerModule, interfaces } from 'inversify';
+import { ServiceIdentifiers } from '../../ServiceIdentifiers';
+
+import { IOptions } from '../../../interfaces/options/IOptions';
+import { IOptionsNormalizer } from '../../../interfaces/options/IOptionsNormalizer';
+
+import { Options } from '../../../options/Options';
+import { OptionsNormalizer } from '../../../options/OptionsNormalizer';
+
+export const optionsModule: interfaces.ContainerModule = new ContainerModule((bind: interfaces.Bind) => {
+    bind<IOptions>(ServiceIdentifiers.IOptions)
+        .to(Options)
+        .inSingletonScope();
+
+    bind<IOptionsNormalizer>(ServiceIdentifiers.IOptionsNormalizer)
+        .to(OptionsNormalizer)
+        .inSingletonScope();
+});

+ 1 - 1
src/custom-nodes/console-output-nodes/ConsoleOutputDisableExpressionNode.ts

@@ -64,7 +64,7 @@ export class ConsoleOutputDisableExpressionNode extends AbstractCustomNode {
             : GlobalVariableNoEvalTemplate();
 
         return format(ConsoleOutputDisableExpressionTemplate(), {
-            consoleLogDisableFunctionName: this.identifierNamesGenerator.generate(6),
+            consoleLogDisableFunctionName: this.identifierNamesGenerator.generate(),
             globalVariableTemplate,
             singleNodeCallControllerFunctionName: this.callsControllerFunctionName
         });

+ 1 - 1
src/custom-nodes/console-output-nodes/group/ConsoleOutputCustomNodeGroup.ts

@@ -92,7 +92,7 @@ export class ConsoleOutputCustomNodeGroup extends AbstractCustomNodeGroup {
             return;
         }
 
-        const callsControllerFunctionName: string = this.identifierNamesGenerator.generate(6);
+        const callsControllerFunctionName: string = this.identifierNamesGenerator.generate();
 
         const consoleOutputDisableExpressionNode: ICustomNode = this.customNodeFactory(CustomNode.ConsoleOutputDisableExpressionNode);
         const nodeCallsControllerFunctionNode: ICustomNode = this.customNodeFactory(CustomNode.NodeCallsControllerFunctionNode);

+ 2 - 2
src/custom-nodes/debug-protection-nodes/group/DebugProtectionCustomNodeGroup.ts

@@ -105,8 +105,8 @@ export class DebugProtectionCustomNodeGroup extends AbstractCustomNodeGroup {
             return;
         }
 
-        const debugProtectionFunctionName: string = this.identifierNamesGenerator.generate(6);
-        const callsControllerFunctionName: string = this.identifierNamesGenerator.generate(6);
+        const debugProtectionFunctionName: string = this.identifierNamesGenerator.generate();
+        const callsControllerFunctionName: string = this.identifierNamesGenerator.generate();
 
         const debugProtectionFunctionNode: ICustomNode = this.customNodeFactory(CustomNode.DebugProtectionFunctionNode);
         const debugProtectionFunctionCallNode: ICustomNode = this.customNodeFactory(CustomNode.DebugProtectionFunctionCallNode);

+ 1 - 1
src/custom-nodes/domain-lock-nodes/DomainLockNode.ts

@@ -79,7 +79,7 @@ export class DomainLockNode extends AbstractCustomNode {
             : GlobalVariableNoEvalTemplate();
 
         return format(DomainLockNodeTemplate(), {
-            domainLockFunctionName: this.identifierNamesGenerator.generate(6),
+            domainLockFunctionName: this.identifierNamesGenerator.generate(),
             diff: diff,
             domains: hiddenDomainsString,
             globalVariableTemplate,

+ 1 - 1
src/custom-nodes/domain-lock-nodes/group/DomainLockCustomNodeGroup.ts

@@ -92,7 +92,7 @@ export class DomainLockCustomNodeGroup extends AbstractCustomNodeGroup {
             return;
         }
 
-        const callsControllerFunctionName: string = this.identifierNamesGenerator.generate(6);
+        const callsControllerFunctionName: string = this.identifierNamesGenerator.generate();
 
         const domainLockNode: ICustomNode = this.customNodeFactory(CustomNode.DomainLockNode);
         const nodeCallsControllerFunctionNode: ICustomNode = this.customNodeFactory(CustomNode.NodeCallsControllerFunctionNode);

+ 1 - 1
src/custom-nodes/self-defending-nodes/SelfDefendingUnicodeNode.ts

@@ -71,7 +71,7 @@ export class SelfDefendingUnicodeNode extends AbstractCustomNode {
     protected getTemplate (): string {
         return JavaScriptObfuscator.obfuscate(
             format(SelfDefendingTemplate(this.escapeSequenceEncoder), {
-                selfDefendingFunctionName: this.identifierNamesGenerator.generate(6),
+                selfDefendingFunctionName: this.identifierNamesGenerator.generate(),
                 singleNodeCallControllerFunctionName: this.callsControllerFunctionName
             }),
             {

+ 1 - 1
src/custom-nodes/self-defending-nodes/group/SelfDefendingCustomNodeGroup.ts

@@ -92,7 +92,7 @@ export class SelfDefendingCustomNodeGroup extends AbstractCustomNodeGroup {
             return;
         }
 
-        const callsControllerFunctionName: string = this.identifierNamesGenerator.generate(6);
+        const callsControllerFunctionName: string = this.identifierNamesGenerator.generate();
 
         const selfDefendingUnicodeNode: ICustomNode = this.customNodeFactory(CustomNode.SelfDefendingUnicodeNode);
         const nodeCallsControllerFunctionNode: ICustomNode = this.customNodeFactory(CustomNode.NodeCallsControllerFunctionNode);

+ 2 - 2
src/custom-nodes/string-array-nodes/StringArrayRotateFunctionNode.ts

@@ -82,8 +82,8 @@ export class StringArrayRotateFunctionNode extends AbstractCustomNode {
      * @returns {string}
      */
     protected getTemplate (): string {
-        const timesName: string = this.identifierNamesGenerator.generate(6);
-        const whileFunctionName: string = this.identifierNamesGenerator.generate(6);
+        const timesName: string = this.identifierNamesGenerator.generate();
+        const whileFunctionName: string = this.identifierNamesGenerator.generate();
 
         let code: string = '';
 

+ 6 - 2
src/generators/identifier-names-generators/AbstractIdentifierNamesGenerator.ts

@@ -30,8 +30,12 @@ export abstract class AbstractIdentifierNamesGenerator implements IIdentifierNam
     }
 
     /**
-     * @param {number} length
      * @returns {string}
      */
-    public abstract generate (length: number): string;
+    public abstract generate (): string;
+
+    /**
+     * @returns {string}
+     */
+    public abstract generateWithPrefix (): string;
 }

+ 21 - 8
src/generators/identifier-names-generators/HexadecimalIdentifierNamesGenerator.ts

@@ -9,6 +9,11 @@ import { Utils } from '../../utils/Utils';
 
 @injectable()
 export class HexadecimalIdentifierNamesGenerator extends AbstractIdentifierNamesGenerator {
+    /**
+     * @type {number}
+     */
+    private static baseIdentifierNameLength: number = 6;
+
     /**
      * @type {Set<string>}
      */
@@ -26,23 +31,31 @@ export class HexadecimalIdentifierNamesGenerator extends AbstractIdentifierNames
     }
 
     /**
-     * @param {number} length
      * @returns {string}
      */
-    public generate (length: number): string {
-        const prefix: string = `_${Utils.hexadecimalPrefix}`;
+    public generate (): string {
         const rangeMinInteger: number = 10000;
         const rangeMaxInteger: number = 99999999;
         const randomInteger: number = this.randomGenerator.getRandomInteger(rangeMinInteger, rangeMaxInteger);
         const hexadecimalNumber: string = Utils.decToHex(randomInteger);
-        const randomVariableName: string = `${prefix}${hexadecimalNumber.substr(0, length)}`;
+        const baseIdentifierName: string = hexadecimalNumber.substr(0, HexadecimalIdentifierNamesGenerator.baseIdentifierNameLength);
+        const identifierName: string = `_${Utils.hexadecimalPrefix}${baseIdentifierName}`;
 
-        if (this.randomVariableNameSet.has(randomVariableName)) {
-            return this.generate(length);
+        if (this.randomVariableNameSet.has(identifierName)) {
+            return this.generate();
         }
 
-        this.randomVariableNameSet.add(randomVariableName);
+        this.randomVariableNameSet.add(identifierName);
+
+        return identifierName;
+    }
+
+    /**
+     * @returns {string}
+     */
+    public generateWithPrefix (): string {
+        const identifierName: string = this.generate();
 
-        return randomVariableName;
+        return `${this.options.identifiersPrefix}${identifierName}`.replace('__', '_');
     }
 }

+ 16 - 5
src/generators/identifier-names-generators/MangledIdentifierNamesGenerator.ts

@@ -98,14 +98,25 @@ export class MangledIdentifierNamesGenerator extends AbstractIdentifierNamesGene
     }
 
     /**
-     * @param {number} length
      * @returns {string}
      */
-    public generate (length: number): string {
-        const newName: string = MangledIdentifierNamesGenerator.generateNewMangledName(this.previousMangledName);
+    public generate (): string {
+        const identifierName: string = MangledIdentifierNamesGenerator.generateNewMangledName(this.previousMangledName);
 
-        this.previousMangledName = newName;
+        this.previousMangledName = identifierName;
 
-        return newName;
+        return identifierName;
+    }
+
+    /**
+     * @returns {string}
+     */
+    public generateWithPrefix (): string {
+        const prefix: string = this.options.identifiersPrefix ?
+            `${this.options.identifiersPrefix}_`
+            : '';
+        const identifierName: string = this.generate();
+
+        return `${prefix}${identifierName}`;
     }
 }

+ 6 - 2
src/interfaces/generators/identifier-names-generators/IIdentifierNamesGenerator.d.ts

@@ -1,7 +1,11 @@
 export interface IIdentifierNamesGenerator {
     /**
-     * @param {number} length
      * @returns {string}
      */
-    generate (length: number): string;
+    generate (): string;
+
+    /**
+     * @returns {string}
+     */
+    generateWithPrefix (): string;
 }

+ 8 - 2
src/interfaces/node-transformers/obfuscating-transformers/obfuscating-replacers/IIdentifierObfuscatingReplacer.d.ts

@@ -4,8 +4,14 @@ import { IObfuscatingReplacer } from './IObfuscatingReplacer';
 
 export interface IIdentifierObfuscatingReplacer extends IObfuscatingReplacer <ESTree.Identifier> {
     /**
-     * @param nodeValue
+     * @param {string} nodeValue
      * @param {number} nodeIdentifier
      */
-    storeNames (nodeValue: any, nodeIdentifier: number): void;
+    storeGlobalName (nodeValue: string, nodeIdentifier: number): void;
+
+    /**
+     * @param {string} nodeValue
+     * @param {number} nodeIdentifier
+     */
+    storeLocalName (nodeValue: string, nodeIdentifier: number): void;
 }

+ 1 - 0
src/interfaces/options/IOptions.d.ts

@@ -15,6 +15,7 @@ export interface IOptions {
     readonly disableConsoleOutput: boolean;
     readonly domainLock: string[];
     readonly identifierNamesGenerator: IdentifierNamesGenerator;
+    readonly identifiersPrefix: string;
     readonly log: boolean;
     readonly renameGlobals: boolean;
     readonly reservedNames: string[];

+ 9 - 0
src/interfaces/options/IOptionsNormalizer.d.ts

@@ -0,0 +1,9 @@
+import { IOptions } from './IOptions';
+
+export interface IOptionsNormalizer {
+    /**
+     * @param {IOptions} options
+     * @returns {IOptions}
+     */
+    normalize (options: IOptions): IOptions;
+}

+ 1 - 1
src/node-transformers/obfuscating-transformers/CatchClauseTransformer.ts

@@ -90,7 +90,7 @@ export class CatchClauseTransformer extends AbstractNodeTransformer {
      */
     private storeCatchClauseParam (catchClauseNode: ESTree.CatchClause, nodeIdentifier: number): void {
         if (NodeGuards.isIdentifierNode(catchClauseNode.param)) {
-            this.identifierObfuscatingReplacer.storeNames(catchClauseNode.param.name, nodeIdentifier);
+            this.identifierObfuscatingReplacer.storeLocalName(catchClauseNode.param.name, nodeIdentifier);
         }
     }
 

+ 15 - 6
src/node-transformers/obfuscating-transformers/ClassDeclarationTransformer.ts

@@ -86,14 +86,14 @@ export class ClassDeclarationTransformer extends AbstractNodeTransformer {
      */
     public transformNode (classDeclarationNode: ESTree.ClassDeclaration, parentNode: ESTree.Node): ESTree.Node {
         const nodeIdentifier: number = this.nodeIdentifier++;
-        const blockScopeNode: TNodeWithBlockScope = NodeUtils
-            .getBlockScopesOfNode(classDeclarationNode)[0];
+        const blockScopeNode: TNodeWithBlockScope = NodeUtils.getBlockScopesOfNode(classDeclarationNode)[0];
+        const isGlobalDeclaration: boolean = blockScopeNode.type === NodeType.Program;
 
-        if (!this.options.renameGlobals && blockScopeNode.type === NodeType.Program) {
+        if (!this.options.renameGlobals && isGlobalDeclaration) {
             return classDeclarationNode;
         }
 
-        this.storeClassName(classDeclarationNode, nodeIdentifier);
+        this.storeClassName(classDeclarationNode, isGlobalDeclaration, nodeIdentifier);
 
         // check for cached identifiers for current scope node. If exist - loop through them.
         if (this.replaceableIdentifiers.has(blockScopeNode)) {
@@ -107,10 +107,19 @@ export class ClassDeclarationTransformer extends AbstractNodeTransformer {
 
     /**
      * @param {ClassDeclaration} classDeclarationNode
+     * @param {boolean} isGlobalDeclaration
      * @param {number} nodeIdentifier
      */
-    private storeClassName (classDeclarationNode: ESTree.ClassDeclaration, nodeIdentifier: number): void {
-        this.identifierObfuscatingReplacer.storeNames(classDeclarationNode.id.name, nodeIdentifier);
+    private storeClassName (
+        classDeclarationNode: ESTree.ClassDeclaration,
+        isGlobalDeclaration: boolean,
+        nodeIdentifier: number
+    ): void {
+        if (isGlobalDeclaration) {
+            this.identifierObfuscatingReplacer.storeGlobalName(classDeclarationNode.id.name, nodeIdentifier);
+        } else {
+            this.identifierObfuscatingReplacer.storeLocalName(classDeclarationNode.id.name, nodeIdentifier);
+        }
     }
 
     /**

+ 15 - 6
src/node-transformers/obfuscating-transformers/FunctionDeclarationTransformer.ts

@@ -88,14 +88,14 @@ export class FunctionDeclarationTransformer extends AbstractNodeTransformer {
      */
     public transformNode (functionDeclarationNode: ESTree.FunctionDeclaration, parentNode: ESTree.Node): ESTree.Node {
         const nodeIdentifier: number = this.nodeIdentifier++;
-        const blockScopeNode: TNodeWithBlockScope = NodeUtils
-            .getBlockScopesOfNode(functionDeclarationNode)[0];
+        const blockScopeNode: TNodeWithBlockScope = NodeUtils.getBlockScopesOfNode(functionDeclarationNode)[0];
+        const isGlobalDeclaration: boolean = blockScopeNode.type === NodeType.Program;
 
-        if (!this.options.renameGlobals && blockScopeNode.type === NodeType.Program) {
+        if (!this.options.renameGlobals && isGlobalDeclaration) {
             return functionDeclarationNode;
         }
 
-        this.storeFunctionName(functionDeclarationNode, nodeIdentifier);
+        this.storeFunctionName(functionDeclarationNode, isGlobalDeclaration, nodeIdentifier);
 
         // check for cached identifiers for current scope node. If exist - loop through them.
         if (this.replaceableIdentifiers.has(blockScopeNode)) {
@@ -109,10 +109,19 @@ export class FunctionDeclarationTransformer extends AbstractNodeTransformer {
 
     /**
      * @param {FunctionDeclaration} functionDeclarationNode
+     * @param {boolean} isGlobalDeclaration
      * @param {number} nodeIdentifier
      */
-    private storeFunctionName (functionDeclarationNode: ESTree.FunctionDeclaration, nodeIdentifier: number): void {
-        this.identifierObfuscatingReplacer.storeNames(functionDeclarationNode.id.name, nodeIdentifier);
+    private storeFunctionName (
+        functionDeclarationNode: ESTree.FunctionDeclaration,
+        isGlobalDeclaration: boolean,
+        nodeIdentifier: number
+    ): void {
+        if (isGlobalDeclaration) {
+            this.identifierObfuscatingReplacer.storeGlobalName(functionDeclarationNode.id.name, nodeIdentifier);
+        } else {
+            this.identifierObfuscatingReplacer.storeLocalName(functionDeclarationNode.id.name, nodeIdentifier);
+        }
     }
 
     /**

+ 2 - 2
src/node-transformers/obfuscating-transformers/FunctionTransformer.ts

@@ -104,13 +104,13 @@ export class FunctionTransformer extends AbstractNodeTransformer {
                 estraverse.traverse(paramsNode, {
                     enter: (node: ESTree.Node): any => {
                         if (NodeGuards.isAssignmentPatternNode(node) && NodeGuards.isIdentifierNode(node.left)) {
-                            this.identifierObfuscatingReplacer.storeNames(node.left.name, nodeIdentifier);
+                            this.identifierObfuscatingReplacer.storeLocalName(node.left.name, nodeIdentifier);
 
                             return estraverse.VisitorOption.Skip;
                         }
 
                         if (NodeGuards.isIdentifierNode(node)) {
-                            this.identifierObfuscatingReplacer.storeNames(node.name, nodeIdentifier);
+                            this.identifierObfuscatingReplacer.storeLocalName(node.name, nodeIdentifier);
                         }
                     }
                 });

+ 1 - 2
src/node-transformers/obfuscating-transformers/LabeledStatementTransformer.ts

@@ -97,8 +97,7 @@ export class LabeledStatementTransformer extends AbstractNodeTransformer {
      * @param {number} nodeIdentifier
      */
     private storeLabeledStatementName (labeledStatementNode: ESTree.LabeledStatement, nodeIdentifier: number): void {
-        this.identifierObfuscatingReplacer
-            .storeNames(labeledStatementNode.label.name, nodeIdentifier);
+        this.identifierObfuscatingReplacer.storeLocalName(labeledStatementNode.label.name, nodeIdentifier);
     }
 
     /**

+ 15 - 6
src/node-transformers/obfuscating-transformers/VariableDeclarationTransformer.ts

@@ -88,10 +88,10 @@ export class VariableDeclarationTransformer extends AbstractNodeTransformer {
      * @returns {NodeGuards}
      */
     public transformNode (variableDeclarationNode: ESTree.VariableDeclaration, parentNode: ESTree.Node): ESTree.Node {
-        const blockScopeNode: TNodeWithBlockScope = NodeUtils
-            .getBlockScopesOfNode(variableDeclarationNode)[0];
+        const blockScopeNode: TNodeWithBlockScope = NodeUtils.getBlockScopesOfNode(variableDeclarationNode)[0];
+        const isGlobalDeclaration: boolean = blockScopeNode.type === NodeType.Program;
 
-        if (!this.options.renameGlobals && blockScopeNode.type === NodeType.Program) {
+        if (!this.options.renameGlobals && isGlobalDeclaration) {
             return variableDeclarationNode;
         }
 
@@ -100,7 +100,7 @@ export class VariableDeclarationTransformer extends AbstractNodeTransformer {
             ? blockScopeNode
             : parentNode;
 
-        this.storeVariableNames(variableDeclarationNode, nodeIdentifier);
+        this.storeVariableNames(variableDeclarationNode, isGlobalDeclaration, nodeIdentifier);
 
         // check for cached identifiers for current scope node. If exist - loop through them.
         if (this.replaceableIdentifiers.has(scopeNode)) {
@@ -114,11 +114,20 @@ export class VariableDeclarationTransformer extends AbstractNodeTransformer {
 
     /**
      * @param {VariableDeclaration} variableDeclarationNode
+     * @param {boolean} isGlobalDeclaration
      * @param {number} nodeIdentifier
      */
-    private storeVariableNames (variableDeclarationNode: ESTree.VariableDeclaration, nodeIdentifier: number): void {
+    private storeVariableNames (
+        variableDeclarationNode: ESTree.VariableDeclaration,
+        isGlobalDeclaration: boolean,
+        nodeIdentifier: number
+    ): void {
         this.traverseDeclarationIdentifiers(variableDeclarationNode, (identifierNode: ESTree.Identifier) => {
-            this.identifierObfuscatingReplacer.storeNames(identifierNode.name, nodeIdentifier);
+            if (isGlobalDeclaration) {
+                this.identifierObfuscatingReplacer.storeGlobalName(identifierNode.name, nodeIdentifier);
+            } else {
+                this.identifierObfuscatingReplacer.storeLocalName(identifierNode.name, nodeIdentifier);
+            }
         });
     }
 

+ 23 - 4
src/node-transformers/obfuscating-transformers/obfuscating-replacers/identifier-obfuscating-replacers/BaseIdentifierObfuscatingReplacer.ts

@@ -54,18 +54,37 @@ export class BaseIdentifierObfuscatingReplacer extends AbstractObfuscatingReplac
     }
 
     /**
-     * Store all `nodeIdentifier`'s as keys in given `namesMap` with random names as value.
-     * Reserved names will be ignored.
+     * Store `nodeName` of global identifiers as key in map with random name as value.
+     * Reserved name will be ignored.
      *
      * @param {string} nodeName
      * @param {number} nodeIdentifier
      */
-    public storeNames (nodeName: string, nodeIdentifier: number): void {
+    public storeGlobalName (nodeName: string, nodeIdentifier: number): void {
         if (this.isReservedName(nodeName)) {
             return;
         }
 
-        this.namesMap.set(`${nodeName}-${String(nodeIdentifier)}`, this.identifierNamesGenerator.generate(6));
+        const identifierName: string = this.identifierNamesGenerator.generateWithPrefix();
+
+        this.namesMap.set(`${nodeName}-${String(nodeIdentifier)}`, identifierName);
+    }
+
+    /**
+     * Store `nodeName` of local identifier as key in map with random name as value.
+     * Reserved name will be ignored.
+     *
+     * @param {string} nodeName
+     * @param {number} nodeIdentifier
+     */
+    public storeLocalName (nodeName: string, nodeIdentifier: number): void {
+        if (this.isReservedName(nodeName)) {
+            return;
+        }
+
+        const identifierName: string = this.identifierNamesGenerator.generate();
+
+        this.namesMap.set(`${nodeName}-${String(nodeIdentifier)}`, identifierName);
     }
 
     /**

+ 16 - 4
src/options/Options.ts

@@ -1,4 +1,5 @@
-import { injectable } from 'inversify';
+import { inject, injectable } from 'inversify';
+import { ServiceIdentifiers } from '../container/ServiceIdentifiers';
 
 import {
     ArrayUnique,
@@ -20,6 +21,7 @@ import { TInputOptions } from '../types/options/TInputOptions';
 import { TStringArrayEncoding } from '../types/options/TStringArrayEncoding';
 
 import { IOptions } from '../interfaces/options/IOptions';
+import { IOptionsNormalizer } from '../interfaces/options/IOptionsNormalizer';
 
 import { IdentifierNamesGenerator } from '../enums/generators/identifier-names-generators/IdentifierNamesGenerator';
 import { ObfuscationTarget } from '../enums/ObfuscationTarget';
@@ -28,7 +30,6 @@ import { StringArrayEncoding } from '../enums/StringArrayEncoding';
 
 import { DEFAULT_PRESET } from './presets/Default';
 
-import { OptionsNormalizer } from './OptionsNormalizer';
 import { ValidationErrorsFormatter } from './ValidationErrorsFormatter';
 
 @injectable()
@@ -111,6 +112,12 @@ export class Options implements IOptions {
     ])
     public readonly identifierNamesGenerator: IdentifierNamesGenerator;
 
+    /**
+     * @type {string}
+     */
+    @IsString()
+    public readonly identifiersPrefix: string;
+
     /**
      * @type {boolean}
      */
@@ -164,6 +171,7 @@ export class Options implements IOptions {
     @ValidateIf((options: IOptions) => Boolean(options.sourceMapBaseUrl))
     @IsUrl({
         require_protocol: true,
+        require_tld: false,
         require_valid_protocol: true
     })
     public readonly sourceMapBaseUrl: string;
@@ -220,8 +228,12 @@ export class Options implements IOptions {
 
     /**
      * @param {TInputOptions} inputOptions
+     * @param {IOptionsNormalizer} optionsNormalizer
      */
-    constructor (inputOptions: TInputOptions) {
+    constructor (
+        @inject(ServiceIdentifiers.TInputOptions) inputOptions: TInputOptions,
+        @inject(ServiceIdentifiers.IOptionsNormalizer) optionsNormalizer: IOptionsNormalizer
+    ) {
         Object.assign(this, DEFAULT_PRESET, inputOptions);
 
         const errors: ValidationError[] = validateSync(this, Options.validatorOptions);
@@ -230,6 +242,6 @@ export class Options implements IOptions {
             throw new ReferenceError(`Validation failed. errors:\n${ValidationErrorsFormatter.format(errors)}`);
         }
 
-        Object.assign(this, OptionsNormalizer.normalizeOptions(this));
+        Object.assign(this, optionsNormalizer.normalize(this));
     }
 }

+ 6 - 2
src/options/OptionsNormalizer.ts

@@ -1,6 +1,9 @@
+import { injectable } from 'inversify';
+
 import { TOptionsNormalizerRule } from '../types/options/TOptionsNormalizerRule';
 
 import { IOptions } from '../interfaces/options/IOptions';
+import { IOptionsNormalizer } from '../interfaces/options/IOptionsNormalizer';
 
 import { ControlFlowFlatteningThresholdRule } from './normalizer-rules/ControlFlowFlatteningThresholdRule';
 import { DeadCodeInjectionRule } from './normalizer-rules/DeadCodeInjectionRule';
@@ -13,7 +16,8 @@ import { StringArrayRule } from './normalizer-rules/StringArrayRule';
 import { StringArrayEncodingRule } from './normalizer-rules/StringArrayEncodingRule';
 import { StringArrayThresholdRule } from './normalizer-rules/StringArrayThresholdRule';
 
-export class OptionsNormalizer {
+@injectable()
+export class OptionsNormalizer implements IOptionsNormalizer {
     /**
      * @type {TOptionsNormalizerRule[]}
      */
@@ -34,7 +38,7 @@ export class OptionsNormalizer {
      * @param {IOptions} options
      * @returns {IOptions}
      */
-    public static normalizeOptions (options: IOptions): IOptions {
+    public normalize (options: IOptions): IOptions {
         let normalizedOptions: IOptions = {
             ...options
         };

+ 1 - 0
src/options/presets/Default.ts

@@ -16,6 +16,7 @@ export const DEFAULT_PRESET: TInputOptions = Object.freeze({
     disableConsoleOutput: false,
     domainLock: [],
     identifierNamesGenerator: IdentifierNamesGenerator.HexadecimalIdentifierNamesGenerator,
+    identifiersPrefix: '',
     log: false,
     renameGlobals: false,
     reservedNames: [],

+ 1 - 0
src/options/presets/NoCustomNodes.ts

@@ -15,6 +15,7 @@ export const NO_ADDITIONAL_NODES_PRESET: TInputOptions = Object.freeze({
     disableConsoleOutput: false,
     domainLock: [],
     identifierNamesGenerator: IdentifierNamesGenerator.HexadecimalIdentifierNamesGenerator,
+    identifiersPrefix: '',
     log: false,
     renameGlobals: false,
     reservedNames: [],

+ 13 - 2
src/storages/string-array/StringArrayStorage.ts

@@ -12,6 +12,11 @@ import { ArrayStorage } from '../ArrayStorage';
 
 @injectable()
 export class StringArrayStorage extends ArrayStorage <string> {
+    /**
+     * @type {number}
+     */
+    private static readonly stringArrayNameLength: number = 7;
+
     /**
      * @type {IArrayUtils}
      */
@@ -45,8 +50,14 @@ export class StringArrayStorage extends ArrayStorage <string> {
     public initialize (): void {
         super.initialize();
 
-        const stringArrayName: string = this.identifierNamesGenerator.generate(4);
-        const stringArrayCallsWrapperName: string = this.identifierNamesGenerator.generate(4);
+        const baseStringArrayName: string = this.identifierNamesGenerator
+            .generate()
+            .slice(0, StringArrayStorage.stringArrayNameLength);
+        const baseStringArrayCallsWrapperName: string = this.identifierNamesGenerator
+            .generate()
+            .slice(0, StringArrayStorage.stringArrayNameLength);
+        const stringArrayName: string = `${this.options.identifiersPrefix}${baseStringArrayName}`;
+        const stringArrayCallsWrapperName: string = `${this.options.identifiersPrefix}${baseStringArrayCallsWrapperName}`;
 
         this.storageId = `${stringArrayName}|${stringArrayCallsWrapperName}`;
     }

+ 7 - 6
test/dev/dev.ts

@@ -6,17 +6,18 @@ import { NO_ADDITIONAL_NODES_PRESET } from '../../src/options/presets/NoCustomNo
 
     let obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
         `
+        var bar = 1;
+        var baz = 2;
         (function(){
-            function foo () {
-                eval('var s = 1;');
-            }
-        
-            foo();
+            var bark = bar + baz;
         })();
         `,
         {
             ...NO_ADDITIONAL_NODES_PRESET,
-            compact: false
+            compact: false,
+            identifiersPrefix: 'foo',
+            identifierNamesGenerator: 'mangled',
+            renameGlobals: true
         }
     ).getObfuscatedCode();
 

+ 80 - 3
test/functional-tests/cli/JavaScriptObfuscatorCLI.spec.ts

@@ -134,13 +134,18 @@ describe('JavaScriptObfuscatorCLI', function (): void {
             const outputFileName1: string = 'foo-obfuscated.js';
             const outputFileName2: string = 'bar-obfuscated.js';
             const outputFileName3: string = 'baz-obfuscated.js';
+            const readFileEncoding: string = 'utf8';
+            const regExp1: RegExp = /^var *a1_0x(\w){4,6} *= *0x1;$/;
+            const regExp2: RegExp = /^var *a0_0x(\w){4,6} *= *0x2;$/;
 
             let outputFixturesFilePath1: string,
                 outputFixturesFilePath2: string,
                 outputFixturesFilePath3: string,
                 isFileExist1: boolean,
                 isFileExist2: boolean,
-                isFileExist3: boolean;
+                isFileExist3: boolean,
+                fileContent1: string,
+                fileContent2: string;
 
             before(() => {
                 outputFixturesFilePath1 = `${directoryPath}/${outputFileName1}`;
@@ -150,12 +155,17 @@ describe('JavaScriptObfuscatorCLI', function (): void {
                 JavaScriptObfuscator.runCLI([
                     'node',
                     'javascript-obfuscator',
-                    directoryPath
+                    directoryPath,
+                    '--rename-globals',
+                    'true'
                 ]);
 
                 isFileExist1 = fs.existsSync(outputFixturesFilePath1);
                 isFileExist2 = fs.existsSync(outputFixturesFilePath2);
                 isFileExist3 = fs.existsSync(outputFixturesFilePath3);
+
+                fileContent1 = fs.readFileSync(outputFixturesFilePath1, readFileEncoding);
+                fileContent2 = fs.readFileSync(outputFixturesFilePath2, readFileEncoding);
             });
 
             it(`should create file \`${outputFileName1}\` with obfuscated code in \`${fixturesDirName}\` directory`, () => {
@@ -170,13 +180,80 @@ describe('JavaScriptObfuscatorCLI', function (): void {
                 assert.equal(isFileExist3, false);
             });
 
+            it(`match #1: should create file with obfuscated code with prefixed identifier`, () => {
+                assert.match(fileContent1, regExp1);
+            });
+
+            it(`match #2: should create file with obfuscated code with prefixed identifier`, () => {
+                assert.match(fileContent2, regExp2);
+            });
+
+            after(() => {
+                rimraf.sync(outputFixturesFilePath1);
+                rimraf.sync(outputFixturesFilePath2);
+            });
+        });
+
+        describe('Variant #3: obfuscation of directory with `identifiersPrefix` option value', () => {
+            const directoryPath: string = `${fixturesDirName}/directory-obfuscation`;
+            const identifiersPrefix: string = 'foo';
+            const outputFileName1: string = 'foo-obfuscated.js';
+            const outputFileName2: string = 'bar-obfuscated.js';
+            const readFileEncoding: string = 'utf8';
+            const regExp1: RegExp = /^var *foo1_0x(\w){4,6} *= *0x1;$/;
+            const regExp2: RegExp = /^var *foo0_0x(\w){4,6} *= *0x2;$/;
+
+            let outputFixturesFilePath1: string,
+                outputFixturesFilePath2: string,
+                isFileExist1: boolean,
+                isFileExist2: boolean,
+                fileContent1: string,
+                fileContent2: string;
+
+            before(() => {
+                outputFixturesFilePath1 = `${directoryPath}/${outputFileName1}`;
+                outputFixturesFilePath2 = `${directoryPath}/${outputFileName2}`;
+
+                JavaScriptObfuscator.runCLI([
+                    'node',
+                    'javascript-obfuscator',
+                    directoryPath,
+                    '--identifiers-prefix',
+                    identifiersPrefix,
+                    '--rename-globals',
+                    'true'
+                ]);
+
+                isFileExist1 = fs.existsSync(outputFixturesFilePath1);
+                isFileExist2 = fs.existsSync(outputFixturesFilePath2);
+
+                fileContent1 = fs.readFileSync(outputFixturesFilePath1, readFileEncoding);
+                fileContent2 = fs.readFileSync(outputFixturesFilePath2, readFileEncoding);
+            });
+
+            it(`should create file \`${outputFileName1}\` with obfuscated code in \`${fixturesDirName}\` directory`, () => {
+                assert.equal(isFileExist1, true);
+            });
+
+            it(`should create file \`${outputFileName2}\` with obfuscated code in \`${fixturesDirName}\` directory`, () => {
+                assert.equal(isFileExist2, true);
+            });
+
+            it(`match #1: should create file with obfuscated code with prefixed identifier`, () => {
+                assert.match(fileContent1, regExp1);
+            });
+
+            it(`match #2: should create file with obfuscated code with prefixed identifier`, () => {
+                assert.match(fileContent2, regExp2);
+            });
+
             after(() => {
                 rimraf.sync(outputFixturesFilePath1);
                 rimraf.sync(outputFixturesFilePath2);
             });
         });
 
-        describe('Variant #3: obfuscation of directory with `output` option', () => {
+        describe('Variant #4: obfuscation of directory with `output` option', () => {
             const directoryPath: string = `${fixturesDirName}/directory-obfuscation`;
             const outputDirectoryName: string = 'obfuscated';
             const outputDirectoryPath: string = `${directoryPath}/${outputDirectoryName}`;

+ 135 - 14
test/functional-tests/javascript-obfuscator/JavaScriptObfuscator.spec.ts

@@ -186,28 +186,108 @@ describe('JavaScriptObfuscator', () => {
         });
 
         describe('variable inside global scope', () => {
-            const regExp: RegExp = /^var *test *= *0x\d+;$/;
+            describe('variant #1: without `renameGlobals` option', () => {
+                const regExp: RegExp = /^var *test *= *0x\d+;$/;
 
-            let obfuscatedCode: string;
+                let obfuscatedCode: string;
 
-            beforeEach(() => {
-                const code: string = readFileAsString(__dirname + '/fixtures/simple-input-1.js');
-                const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
-                    code,
-                    {
-                        ...NO_ADDITIONAL_NODES_PRESET
-                    }
-                );
+                beforeEach(() => {
+                    const code: string = readFileAsString(__dirname + '/fixtures/simple-input-1.js');
+                    const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
+                        code,
+                        {
+                            ...NO_ADDITIONAL_NODES_PRESET
+                        }
+                    );
 
-                obfuscatedCode = obfuscationResult.getObfuscatedCode();
+                    obfuscatedCode = obfuscationResult.getObfuscatedCode();
+                });
+
+                it('should return correct obfuscated code', () => {
+                    assert.match(obfuscatedCode, regExp);
+                });
             });
 
-            it('should return correct obfuscated code', () => {
-                assert.match(obfuscatedCode, regExp);
+            describe('variant #2: with `renameGlobals` option', () => {
+                const regExp: RegExp = /^var *_0x(\w){4,6} *= *0x\d+;$/;
+
+                let obfuscatedCode: string;
+
+                beforeEach(() => {
+                    const code: string = readFileAsString(__dirname + '/fixtures/simple-input-1.js');
+                    const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
+                        code,
+                        {
+                            ...NO_ADDITIONAL_NODES_PRESET,
+                            renameGlobals: true
+                        }
+                    );
+
+                    obfuscatedCode = obfuscationResult.getObfuscatedCode();
+                });
+
+                it('should return correct obfuscated code', () => {
+                    assert.match(obfuscatedCode, regExp);
+                });
+            });
+
+            describe('variant #3: with `renameGlobals` and `identifiersPrefix` options', () => {
+                const regExp: RegExp = /^var *foo_0x(\w){4,6} *= *0x\d+;$/;
+
+                let obfuscatedCode: string;
+
+                beforeEach(() => {
+                    const code: string = readFileAsString(__dirname + '/fixtures/simple-input-1.js');
+                    const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
+                        code,
+                        {
+                            ...NO_ADDITIONAL_NODES_PRESET,
+                            renameGlobals: true,
+                            identifiersPrefix: 'foo'
+                        }
+                    );
+
+                    obfuscatedCode = obfuscationResult.getObfuscatedCode();
+                });
+
+                it('should return correct obfuscated code', () => {
+                    assert.match(obfuscatedCode, regExp);
+                });
+            });
+
+            describe('variant #4: with `stringArray`, `renameGlobals` and `identifiersPrefix` options', () => {
+                const stringArrayRegExp: RegExp = /^var foo_0x(\w){4} *= *\['abc'\];/;
+                const stringArrayCallRegExp: RegExp = /var *foo_0x(\w){4,6} *= *foo_0x(\w){4}\('0x0'\);$/;
+
+                let obfuscatedCode: string;
+
+                beforeEach(() => {
+                    const code: string = readFileAsString(__dirname + '/fixtures/simple-input-2.js');
+                    const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
+                        code,
+                        {
+                            ...NO_ADDITIONAL_NODES_PRESET,
+                            renameGlobals: true,
+                            identifiersPrefix: 'foo',
+                            stringArray: true,
+                            stringArrayThreshold: 1
+                        }
+                    );
+
+                    obfuscatedCode = obfuscationResult.getObfuscatedCode();
+                });
+
+                it('match #1: should return correct obfuscated code', () => {
+                    assert.match(obfuscatedCode, stringArrayRegExp);
+                });
+
+                it('match #2: should return correct obfuscated code', () => {
+                    assert.match(obfuscatedCode, stringArrayCallRegExp);
+                });
             });
         });
 
-        describe('variable inside global scope', () => {
+        describe('variable inside block scope', () => {
             const regExp: RegExp = /^\(function *\(\) *\{ *var *_0x[\w]+ *= *0x\d+; *\}(\(\)\)|\)\(\));?$/;
 
             let obfuscatedCode: string;
@@ -229,6 +309,47 @@ describe('JavaScriptObfuscator', () => {
             });
         });
 
+        describe('variables inside global and block scopes', () => {
+            describe('variant #1: with `renameGlobals` and `identifiersPrefix` options', () => {
+                const variableDeclaration1: RegExp = /var foo_0x(\w){4,6} *= *0x1;/;
+                const variableDeclaration2: RegExp = /var foo_0x(\w){4,6} *= *0x2;/;
+                const variableDeclaration3: RegExp = /var _0x(\w){4,6} *= *foo_0x(\w){4,6} *\+ *foo_0x(\w){4,6}/;
+                const functionDeclaration: RegExp = /var foo_0x(\w){4,6} *= *function/;
+
+                let obfuscatedCode: string;
+
+                beforeEach(() => {
+                    const code: string = readFileAsString(__dirname + '/fixtures/identifiers-prefix.js');
+                    const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
+                        code,
+                        {
+                            ...NO_ADDITIONAL_NODES_PRESET,
+                            renameGlobals: true,
+                            identifiersPrefix: 'foo'
+                        }
+                    );
+
+                    obfuscatedCode = obfuscationResult.getObfuscatedCode();
+                });
+
+                it('match #1: should return correct obfuscated code', () => {
+                    assert.match(obfuscatedCode, variableDeclaration1);
+                });
+
+                it('match #2: should return correct obfuscated code', () => {
+                    assert.match(obfuscatedCode, variableDeclaration2);
+                });
+
+                it('match #3: should return correct obfuscated code', () => {
+                    assert.match(obfuscatedCode, variableDeclaration3);
+                });
+
+                it('match #4: should return correct obfuscated code', () => {
+                    assert.match(obfuscatedCode, functionDeclaration);
+                });
+            });
+        });
+
         describe('latin literal variable value', () => {
             const stringArrayLatinRegExp: RegExp = /^var _0x(\w){4} *= *\['abc'\];/;
             const stringArrayCallRegExp: RegExp = /var *test *= *_0x(\w){4}\('0x0'\);$/;

+ 7 - 0
test/functional-tests/javascript-obfuscator/fixtures/identifiers-prefix.js

@@ -0,0 +1,7 @@
+var foo = 1;
+var bar = 2;
+var baz = function () {
+    var bark = foo + bar;
+
+    return bark;
+};

+ 17 - 5
test/unit-tests/options/OptionsNormalizer.spec.ts → test/functional-tests/options/OptionsNormalizer.spec.ts

@@ -1,28 +1,40 @@
+import 'reflect-metadata';
+
+import { ServiceIdentifiers } from '../../../src/container/ServiceIdentifiers';
+
 import { assert } from 'chai';
 
 import { TInputOptions } from '../../../src/types/options/TInputOptions';
 
+import { IInversifyContainerFacade } from '../../../src/interfaces/container/IInversifyContainerFacade';
 import { IOptions } from '../../../src/interfaces/options/IOptions';
+import { IOptionsNormalizer } from '../../../src/interfaces/options/IOptionsNormalizer';
 
 import { StringArrayEncoding } from '../../../src/enums/StringArrayEncoding';
 
 import { DEFAULT_PRESET } from '../../../src/options/presets/Default';
 
-import { Options } from '../../../src/options/Options';
-import { OptionsNormalizer } from '../../../src/options/OptionsNormalizer';
+import { InversifyContainerFacade } from '../../../src/container/InversifyContainerFacade';
 
 /**
  * @param optionsPreset
  * @returns {IOptions}
  */
 function getNormalizedOptions (optionsPreset: TInputOptions): TInputOptions {
-    const options: IOptions = new Options(optionsPreset);
+    const inversifyContainerFacade: IInversifyContainerFacade = new InversifyContainerFacade();
+
+    inversifyContainerFacade.load('', optionsPreset);
+
+    const options: IOptions = inversifyContainerFacade
+        .get<IOptions>(ServiceIdentifiers.IOptions);
+    const optionsNormalizer: IOptionsNormalizer = inversifyContainerFacade
+        .get<IOptionsNormalizer>(ServiceIdentifiers.IOptionsNormalizer);
 
-    return OptionsNormalizer.normalizeOptions(options);
+    return optionsNormalizer.normalize(options);
 }
 
 describe('OptionsNormalizer', () => {
-    describe('normalizeOptions (options: IObfuscatorOptions): IObfuscatorOptions', () => {
+    describe('normalize (options: IObfuscatorOptions): IObfuscatorOptions', () => {
         let optionsPreset: TInputOptions,
             expectedOptionsPreset: TInputOptions;
 

+ 1 - 1
test/index.spec.ts

@@ -24,7 +24,6 @@ import './unit-tests/node/node-guards/NodeGuards.spec';
 import './unit-tests/node/node-utils/NodeUtils.spec';
 import './unit-tests/node-transformers/preparing-transformers/ObfuscatingGuardsTransformer.spec';
 import './unit-tests/obfuscation-result/ObfuscationResult.spec';
-import './unit-tests/options/OptionsNormalizer.spec';
 import './unit-tests/options/ValidationErrorsFormatter.spec';
 import './unit-tests/source-map/SourceMapCorrector.spec';
 import './unit-tests/storages/ArrayStorage.spec';
@@ -68,6 +67,7 @@ import './functional-tests/node-transformers/preparing-transformers/eval-call-ex
 import './functional-tests/node-transformers/preparing-transformers/comments-transformer/CommentsTransformer.spec';
 import './functional-tests/node-transformers/preparing-transformers/obfuscating-guards/black-list-obfuscating-guard/BlackListObfuscatingGuard.spec';
 import './functional-tests/node-transformers/preparing-transformers/obfuscating-guards/conditional-comment-obfuscating-guard/ConditionalCommentObfuscatingGuard.spec';
+import './functional-tests/options/OptionsNormalizer.spec';
 import './functional-tests/templates/debug-protection-nodes/DebugProtectionFunctionCallTemplate.spec';
 import './functional-tests/templates/domain-lock-nodes/DomainLockNodeTemplate.spec';
 import './functional-tests/templates/GlobalVariableNoEvalTemplate.spec';

+ 28 - 18
test/unit-tests/generators/identifier-names-generators/HexadecimalIdentifierNamesGenerator.spec.ts

@@ -12,7 +12,7 @@ import { IdentifierNamesGenerator } from '../../../../src/enums/generators/ident
 import { InversifyContainerFacade } from '../../../../src/container/InversifyContainerFacade';
 
 describe('HexadecimalIdentifierNamesGenerator', () => {
-    describe('generate (length: number): string', () => {
+    describe('generate (): string', () => {
         let identifierNamesGenerator: IIdentifierNamesGenerator,
             hexadecimalIdentifierName: string,
             regExp: RegExp;
@@ -24,29 +24,39 @@ describe('HexadecimalIdentifierNamesGenerator', () => {
             identifierNamesGenerator = inversifyContainerFacade.getNamed<IIdentifierNamesGenerator>(
                 ServiceIdentifiers.IIdentifierNamesGenerator,
                 IdentifierNamesGenerator.HexadecimalIdentifierNamesGenerator
-            )
+            );
+
+            hexadecimalIdentifierName = identifierNamesGenerator.generate();
+            regExp = /^_0x(\w){4,6}$/;
         });
 
-        describe('variant #1: hexadecimal name with length `4`', () => {
-            before(() => {
-                hexadecimalIdentifierName = identifierNamesGenerator.generate(4);
-                regExp = /^_0x(\w){4}$/;
-            });
+        it('should return hexadecimal name', () => {
+            assert.match(hexadecimalIdentifierName, regExp);
+        })
+    });
 
-            it('should return hexadecimal name', () => {
-                assert.match(hexadecimalIdentifierName, regExp);
-            })
-        });
+    describe('generateWithPrefix (): string', () => {
+        const regExp: RegExp = /^foo_0x(\w){4,6}$/;
 
-        describe('variant #2: hexadecimal name with length `6`', () => {
-            before(() => {
-                hexadecimalIdentifierName = identifierNamesGenerator.generate(6);
-                regExp = /^_0x(\w){4,6}$/;
+        let identifierNamesGenerator: IIdentifierNamesGenerator,
+            hexadecimalIdentifierName: string;
+
+        before(() => {
+            const inversifyContainerFacade: IInversifyContainerFacade = new InversifyContainerFacade();
+
+            inversifyContainerFacade.load('', {
+                identifiersPrefix: 'foo'
             });
+            identifierNamesGenerator = inversifyContainerFacade.getNamed<IIdentifierNamesGenerator>(
+                ServiceIdentifiers.IIdentifierNamesGenerator,
+                IdentifierNamesGenerator.HexadecimalIdentifierNamesGenerator
+            );
 
-            it('should return hexadecimal name', () => {
-                assert.match(hexadecimalIdentifierName, regExp);
-            })
+            hexadecimalIdentifierName = identifierNamesGenerator.generateWithPrefix();
         });
+
+        it('should return hexadecimal name with prefix', () => {
+            assert.match(hexadecimalIdentifierName, regExp);
+        })
     });
 });

+ 48 - 7
test/unit-tests/generators/identifier-names-generators/MangledlIdentifierNamesGenerator.spec.ts

@@ -12,7 +12,7 @@ import { IdentifierNamesGenerator } from '../../../../src/enums/generators/ident
 import { InversifyContainerFacade } from '../../../../src/container/InversifyContainerFacade';
 
 describe('MangledIdentifierNamesGenerator', () => {
-    describe('generate (length: number): string', () => {
+    describe('generate (): string', () => {
         let identifierNamesGenerator: IIdentifierNamesGenerator,
             mangledIdentifierName: string;
 
@@ -30,7 +30,7 @@ describe('MangledIdentifierNamesGenerator', () => {
             const expectedMangledIdentifierName: string = 'a';
 
             beforeEach(() => {
-                mangledIdentifierName = identifierNamesGenerator.generate(4);
+                mangledIdentifierName = identifierNamesGenerator.generate();
             });
 
             it('should return mangled name', () => {
@@ -44,7 +44,7 @@ describe('MangledIdentifierNamesGenerator', () => {
 
             beforeEach(() => {
                 for (let i: number = 0; i <= expectedMangledIdentifierPosition; i++) {
-                    mangledIdentifierName = identifierNamesGenerator.generate(6);
+                    mangledIdentifierName = identifierNamesGenerator.generate();
                 }
             });
 
@@ -59,7 +59,7 @@ describe('MangledIdentifierNamesGenerator', () => {
 
             beforeEach(() => {
                 for (let i: number = 0; i <= expectedMangledIdentifierPosition; i++) {
-                    mangledIdentifierName = identifierNamesGenerator.generate(6);
+                    mangledIdentifierName = identifierNamesGenerator.generate();
                 }
             });
 
@@ -74,7 +74,7 @@ describe('MangledIdentifierNamesGenerator', () => {
 
             beforeEach(() => {
                 for (let i: number = 0; i <= expectedMangledIdentifierPosition; i++) {
-                    mangledIdentifierName = identifierNamesGenerator.generate(6);
+                    mangledIdentifierName = identifierNamesGenerator.generate();
                 }
             });
 
@@ -89,7 +89,7 @@ describe('MangledIdentifierNamesGenerator', () => {
 
             beforeEach(() => {
                 for (let i: number = 0; i <= expectedMangledIdentifierPosition; i++) {
-                    mangledIdentifierName = identifierNamesGenerator.generate(6);
+                    mangledIdentifierName = identifierNamesGenerator.generate();
                 }
             });
 
@@ -109,7 +109,7 @@ describe('MangledIdentifierNamesGenerator', () => {
 
             beforeEach(() => {
                 for (let i: number = 0; i <= expectedMangledIdentifierPosition2; i++) {
-                    mangledIdentifierName = identifierNamesGenerator.generate(6);
+                    mangledIdentifierName = identifierNamesGenerator.generate();
 
                     if (i === expectedMangledIdentifierPosition1) {
                         mangledIdentifierName1 = mangledIdentifierName;
@@ -128,4 +128,45 @@ describe('MangledIdentifierNamesGenerator', () => {
             });
         });
     });
+
+    describe('generateWithPrefix (): string', () => {
+        let identifierNamesGenerator: IIdentifierNamesGenerator,
+            mangledIdentifierName: string;
+
+        before(() => {
+            const inversifyContainerFacade: IInversifyContainerFacade = new InversifyContainerFacade();
+
+            inversifyContainerFacade.load('', {
+                identifiersPrefix: 'foo'
+            });
+            identifierNamesGenerator = inversifyContainerFacade.getNamed<IIdentifierNamesGenerator>(
+                ServiceIdentifiers.IIdentifierNamesGenerator,
+                IdentifierNamesGenerator.MangledIdentifierNamesGenerator
+            );
+        });
+
+        describe('variant #1: initial mangled name', () => {
+            const expectedMangledIdentifierName: string = 'foo_a';
+
+            beforeEach(() => {
+                mangledIdentifierName = identifierNamesGenerator.generateWithPrefix();
+            });
+
+            it('should return mangled name with prefix', () => {
+                assert.equal(mangledIdentifierName, expectedMangledIdentifierName);
+            });
+        });
+
+        describe('variant #2: second mangled name', () => {
+            const expectedMangledIdentifierName: string = 'foo_b';
+
+            beforeEach(() => {
+                mangledIdentifierName = identifierNamesGenerator.generateWithPrefix();
+            });
+
+            it('should return mangled name with prefix', () => {
+                assert.equal(mangledIdentifierName, expectedMangledIdentifierName);
+            });
+        });
+    });
 });

+ 50 - 34
yarn.lock

@@ -2,9 +2,9 @@
 # yarn lockfile v1
 
 
-"@types/[email protected].0":
-  version "4.1.0"
-  resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.1.0.tgz#d9008fa4c06f6801f93396d121f0227cd4244ac6"
+"@types/[email protected].2":
+  version "4.1.2"
+  resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.1.2.tgz#f1af664769cfb50af805431c407425ed619daa21"
 
 "@types/[email protected]":
   version "0.7.36"
@@ -58,9 +58,9 @@
   dependencies:
     "@types/node" "*"
 
-"@types/[email protected]6":
-  version "2.2.46"
-  resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-2.2.46.tgz#b04713f7759d1cf752effdaae7b3969e285ebc16"
+"@types/[email protected]7":
+  version "2.2.47"
+  resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-2.2.47.tgz#30bbd880834d4af0f609025f282a69b8d4458f06"
 
 "@types/node@*":
   version "8.0.53"
@@ -1016,11 +1016,11 @@ class-utils@^0.3.5:
     lazy-cache "^2.0.2"
     static-extend "^0.1.1"
 
-class-validator@0.7.3:
-  version "0.7.3"
-  resolved "https://registry.yarnpkg.com/class-validator/-/class-validator-0.7.3.tgz#3c2821b8cf35fd8d5f4fcb8063bc57fb50049e7e"
+class-validator@0.8.1:
+  version "0.8.1"
+  resolved "https://registry.yarnpkg.com/class-validator/-/class-validator-0.8.1.tgz#f5efd5c613927e3c2f68692e8f14d53a2644fb2f"
   dependencies:
-    validator "^7.0.0"
+    validator "9.2.0"
 
 cli-cursor@^2.1.0:
   version "2.1.0"
@@ -1446,9 +1446,9 @@ [email protected], escape-string-regexp@^1.0.2, escape-string-regexp@^1
   version "1.0.5"
   resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
 
[email protected]6:
-  version "1.6.16"
-  resolved "https://registry.yarnpkg.com/escodegen-wallaby/-/escodegen-wallaby-1.6.16.tgz#f55b65d1a846d98584f1be18a2bf463f96280527"
[email protected]7:
+  version "1.6.17"
+  resolved "https://registry.yarnpkg.com/escodegen-wallaby/-/escodegen-wallaby-1.6.17.tgz#3e1f334884d4214c94309cf734ec7cfa0b3d438d"
   dependencies:
     esprima "^2.7.1"
     estraverse "^1.9.1"
@@ -2566,9 +2566,9 @@ [email protected], [email protected], "mkdirp@>=0.5 0", mkdirp@^0.5.1, mkdirp@~0.5.0:
   dependencies:
     minimist "0.0.8"
 
-mocha@4.1.0:
-  version "4.1.0"
-  resolved "https://registry.yarnpkg.com/mocha/-/mocha-4.1.0.tgz#7d86cfbcf35cb829e2754c32e17355ec05338794"
+mocha@5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/mocha/-/mocha-5.0.0.tgz#cccac988b0bc5477119cba0e43de7af6d6ad8f4e"
   dependencies:
     browser-stdout "1.3.0"
     commander "2.11.0"
@@ -3107,9 +3107,9 @@ readdirp@^2.0.0:
     readable-stream "^2.0.2"
     set-immediate-shim "^1.0.1"
 
[email protected]0:
-  version "0.1.10"
-  resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.10.tgz#b4f83704416acad89988c9b15635d47e03b9344a"
[email protected]2:
+  version "0.1.12"
+  resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.12.tgz#311bf0c6b63cd782f228a81abe146a2bfa9c56f2"
 
 regenerate@^1.2.1:
   version "1.3.3"
@@ -3329,16 +3329,16 @@ signal-exit@^3.0.0, signal-exit@^3.0.2:
   version "3.0.2"
   resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
 
-sinon@4.1.4:
-  version "4.1.4"
-  resolved "https://registry.yarnpkg.com/sinon/-/sinon-4.1.4.tgz#36bb237bae38ddf9cc92dcc1b16c51e7785bbc9c"
+sinon@4.2.1:
+  version "4.2.1"
+  resolved "https://registry.yarnpkg.com/sinon/-/sinon-4.2.1.tgz#3664e90ea4bccec6ebde3c06e3da8179983371d9"
   dependencies:
     diff "^3.1.0"
     formatio "1.2.0"
     lodash.get "^4.4.2"
     lolex "^2.2.0"
     nise "^1.2.0"
-    supports-color "^4.4.0"
+    supports-color "^5.1.0"
     type-detect "^4.0.5"
 
 slash@^1.0.0:
@@ -3392,9 +3392,9 @@ source-map-resolve@^0.5.0:
     source-map-url "^0.4.0"
     urix "^0.1.0"
 
[email protected].0, source-map-support@^0.5.0:
-  version "0.5.0"
-  resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.0.tgz#2018a7ad2bdf8faf2691e5fddab26bed5a2bacab"
[email protected].2:
+  version "0.5.2"
+  resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.2.tgz#1a6297fd5b2e762b39688c7fc91233b60984f0a5"
   dependencies:
     source-map "^0.6.0"
 
@@ -3404,6 +3404,12 @@ source-map-support@^0.4.15:
   dependencies:
     source-map "^0.5.6"
 
+source-map-support@^0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.0.tgz#2018a7ad2bdf8faf2691e5fddab26bed5a2bacab"
+  dependencies:
+    source-map "^0.6.0"
+
 source-map-url@^0.4.0:
   version "0.4.0"
   resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3"
@@ -3576,12 +3582,18 @@ supports-color@^3.1.2:
   dependencies:
     has-flag "^1.0.0"
 
-supports-color@^4.0.0, supports-color@^4.2.1, supports-color@^4.4.0:
+supports-color@^4.0.0, supports-color@^4.2.1:
   version "4.5.0"
   resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.5.0.tgz#be7a0de484dec5c5cddf8b3d59125044912f635b"
   dependencies:
     has-flag "^2.0.0"
 
+supports-color@^5.1.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.1.0.tgz#058a021d1b619f7ddf3980d712ea3590ce7de3d5"
+  dependencies:
+    has-flag "^2.0.0"
+
 tapable@^0.2.5, tapable@^0.2.7:
   version "0.2.8"
   resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.2.8.tgz#99372a5c999bf2df160afc0d74bed4f47948cd22"
@@ -3611,9 +3623,9 @@ text-encoding@^0.6.4:
   version "0.6.4"
   resolved "https://registry.yarnpkg.com/text-encoding/-/text-encoding-0.6.4.tgz#e399a982257a276dae428bb92845cb71bdc26d19"
 
[email protected].0:
-  version "0.10.0"
-  resolved "https://registry.yarnpkg.com/threads/-/threads-0.10.0.tgz#a6b0bc5d916fa75434b166c612769684b65fead5"
[email protected].1:
+  version "0.10.1"
+  resolved "https://registry.yarnpkg.com/threads/-/threads-0.10.1.tgz#637765dc434ab3373d3c14754c8f7ac6515d6815"
   dependencies:
     eventemitter3 "^2.0.2"
     native-promise-only "^0.8.1"
@@ -3697,7 +3709,11 @@ tsconfig@^7.0.0:
     strip-bom "^3.0.0"
     strip-json-comments "^2.0.0"
 
[email protected], tslib@^1.0.0, tslib@^1.7.1, tslib@^1.8.0:
[email protected]:
+  version "1.9.0"
+  resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.0.tgz#e37a86fda8cbbaf23a057f473c9f4dc64e5fc2e8"
+
+tslib@^1.0.0, tslib@^1.7.1, tslib@^1.8.0:
   version "1.8.1"
   resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.8.1.tgz#6946af2d1d651a7b1863b531d6e5afa41aa44eac"
 
@@ -3879,9 +3895,9 @@ validate-npm-package-license@^3.0.1:
     spdx-correct "~1.0.0"
     spdx-expression-parse "~1.0.0"
 
-validator@^7.0.0:
-  version "7.2.0"
-  resolved "https://registry.yarnpkg.com/validator/-/validator-7.2.0.tgz#a63dcbaba51d4350bf8df20988e0d5a54d711791"
+validator@9.2.0:
+  version "9.2.0"
+  resolved "https://registry.yarnpkg.com/validator/-/validator-9.2.0.tgz#ad216eed5f37cac31a6fe00ceab1f6b88bded03e"
 
 [email protected]:
   version "1.10.0"

Some files were not shown because too many files changed in this diff