瀏覽代碼

`minify` option and variable declarations merge transformer

sanex3339 4 年之前
父節點
當前提交
1d86852e45

+ 4 - 0
CHANGELOG.md

@@ -1,5 +1,9 @@
 Change Log
 Change Log
 
 
+v1.3.0
+---
+* **New option:** `minify` enables code minification.
+
 v1.2.1
 v1.2.1
 ---
 ---
 * Support of old browsers when `selfDefending` is enabled. https://github.com/javascript-obfuscator/javascript-obfuscator/issues/615
 * Support of old browsers when `selfDefending` is enabled. https://github.com/javascript-obfuscator/javascript-obfuscator/issues/615

+ 13 - 1
README.md

@@ -329,6 +329,7 @@ Following options are available for the JS Obfuscator:
     identifiersPrefix: '',
     identifiersPrefix: '',
     inputFileName: '',
     inputFileName: '',
     log: false,
     log: false,
+    minify: true,
     renameGlobals: false,
     renameGlobals: false,
     renameProperties: false,
     renameProperties: false,
     reservedNames: [],
     reservedNames: [],
@@ -374,6 +375,7 @@ Following options are available for the JS Obfuscator:
     --identifiers-dictionary '<list>' (comma separated)
     --identifiers-dictionary '<list>' (comma separated)
     --identifiers-prefix <string>
     --identifiers-prefix <string>
     --log <boolean>
     --log <boolean>
+    --minify <boolean>
     --rename-globals <boolean>
     --rename-globals <boolean>
     --rename-properties <boolean>
     --rename-properties <boolean>
     --reserved-names '<list>' (comma separated)
     --reserved-names '<list>' (comma separated)
@@ -657,13 +659,20 @@ Use this option when you want to obfuscate multiple files. This option helps to
 ### `inputFileName`
 ### `inputFileName`
 Type: `string` Default: `''`
 Type: `string` Default: `''`
 
 
-Allows to set name of the input file with source code. This name will used internally for source map generation.
+Allows to set name of the input file with source code. This name will be used internally for source map generation.
 
 
 ### `log`
 ### `log`
 Type: `boolean` Default: `false`
 Type: `boolean` Default: `false`
 
 
 Enables logging of the information to the console.
 Enables logging of the information to the console.
 
 
+### `minify`
+Type: `boolean` Default: `true`
+
+Enables code minification.
+
+##### :warning: this option doesn't affect identifier names.
+
 ### `renameGlobals`
 ### `renameGlobals`
 Type: `boolean` Default: `false`
 Type: `boolean` Default: `false`
 
 
@@ -947,6 +956,7 @@ Performance will 50-100% slower than without obfuscation
     disableConsoleOutput: true,
     disableConsoleOutput: true,
     identifierNamesGenerator: 'hexadecimal',
     identifierNamesGenerator: 'hexadecimal',
     log: false,
     log: false,
+    minify: true,
     renameGlobals: false,
     renameGlobals: false,
     rotateStringArray: true,
     rotateStringArray: true,
     selfDefending: true,
     selfDefending: true,
@@ -977,6 +987,7 @@ Performance will 30-35% slower than without obfuscation
     disableConsoleOutput: true,
     disableConsoleOutput: true,
     identifierNamesGenerator: 'hexadecimal',
     identifierNamesGenerator: 'hexadecimal',
     log: false,
     log: false,
+    minify: true,
     renameGlobals: false,
     renameGlobals: false,
     rotateStringArray: true,
     rotateStringArray: true,
     selfDefending: true,
     selfDefending: true,
@@ -1005,6 +1016,7 @@ Performance will slightly slower than without obfuscation
     disableConsoleOutput: true,
     disableConsoleOutput: true,
     identifierNamesGenerator: 'hexadecimal',
     identifierNamesGenerator: 'hexadecimal',
     log: false,
     log: false,
+    minify: true,
     renameGlobals: false,
     renameGlobals: false,
     rotateStringArray: true,
     rotateStringArray: true,
     selfDefending: true,
     selfDefending: true,

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


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


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


+ 2 - 2
package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "javascript-obfuscator",
   "name": "javascript-obfuscator",
-  "version": "1.2.1",
+  "version": "1.3.0",
   "description": "JavaScript obfuscator",
   "description": "JavaScript obfuscator",
   "keywords": [
   "keywords": [
     "obfuscator",
     "obfuscator",
@@ -48,7 +48,7 @@
     "@types/chance": "1.1.0",
     "@types/chance": "1.1.0",
     "@types/escodegen": "0.0.6",
     "@types/escodegen": "0.0.6",
     "@types/eslint-scope": "3.7.0",
     "@types/eslint-scope": "3.7.0",
-    "@types/estraverse": "0.0.6",
+    "@types/estraverse": "5.1.0",
     "@types/estree": "0.0.44",
     "@types/estree": "0.0.44",
     "@types/md5": "2.2.0",
     "@types/md5": "2.2.0",
     "@types/mkdirp": "1.0.1",
     "@types/mkdirp": "1.0.1",

+ 6 - 0
src/JavaScriptObfuscator.ts

@@ -81,6 +81,7 @@ export class JavaScriptObfuscator implements IJavaScriptObfuscator {
         NodeTransformer.ScopeIdentifiersTransformer,
         NodeTransformer.ScopeIdentifiersTransformer,
         NodeTransformer.SplitStringTransformer,
         NodeTransformer.SplitStringTransformer,
         NodeTransformer.TemplateLiteralTransformer,
         NodeTransformer.TemplateLiteralTransformer,
+        NodeTransformer.VariableDeclarationsMergeTransformer,
         NodeTransformer.VariablePreserveTransformer
         NodeTransformer.VariablePreserveTransformer
     ];
     ];
 
 
@@ -215,6 +216,11 @@ export class JavaScriptObfuscator implements IJavaScriptObfuscator {
 
 
         astTree = this.runNodeTransformationStage(astTree, NodeTransformationStage.Converting);
         astTree = this.runNodeTransformationStage(astTree, NodeTransformationStage.Converting);
         astTree = this.runNodeTransformationStage(astTree, NodeTransformationStage.Obfuscating);
         astTree = this.runNodeTransformationStage(astTree, NodeTransformationStage.Obfuscating);
+
+        if (this.options.minify) {
+            astTree = this.runNodeTransformationStage(astTree, NodeTransformationStage.Minification);
+        }
+
         astTree = this.runNodeTransformationStage(astTree, NodeTransformationStage.Finalizing);
         astTree = this.runNodeTransformationStage(astTree, NodeTransformationStage.Finalizing);
 
 
         return astTree;
         return astTree;

+ 4 - 0
src/cli/JavaScriptObfuscatorCLI.ts

@@ -249,6 +249,10 @@ export class JavaScriptObfuscatorCLI implements IInitializable {
                 '--log <boolean>', 'Enables logging of the information to the console',
                 '--log <boolean>', 'Enables logging of the information to the console',
                 BooleanSanitizer
                 BooleanSanitizer
             )
             )
+            .option(
+                '--minify <boolean>', 'Enables code minification',
+                BooleanSanitizer
+            )
             .option(
             .option(
                 '--reserved-names <list> (comma separated, without whitespaces)',
                 '--reserved-names <list> (comma separated, without whitespaces)',
                 'Disables obfuscation and generation of identifiers, which being matched by passed RegExp patterns (comma separated)',
                 'Disables obfuscation and generation of identifiers, which being matched by passed RegExp patterns (comma separated)',

+ 2 - 0
src/container/InversifyContainerFacade.ts

@@ -10,6 +10,7 @@ import { customNodesModule } from './modules/custom-nodes/CustomNodesModule';
 import { finalizingTransformersModule } from './modules/node-transformers/FinalizingTransformersModule';
 import { finalizingTransformersModule } from './modules/node-transformers/FinalizingTransformersModule';
 import { generatorsModule } from './modules/generators/GeneratorsModule';
 import { generatorsModule } from './modules/generators/GeneratorsModule';
 import { initializingTransformersModule } from './modules/node-transformers/InitializingTransformersModule';
 import { initializingTransformersModule } from './modules/node-transformers/InitializingTransformersModule';
+import { minificationTransformersModule } from './modules/node-transformers/MinificationTransformersModule';
 import { nodeModule } from './modules/node/NodeModule';
 import { nodeModule } from './modules/node/NodeModule';
 import { nodeTransformersModule } from './modules/node-transformers/NodeTransformersModule';
 import { nodeTransformersModule } from './modules/node-transformers/NodeTransformersModule';
 import { obfuscatingTransformersModule } from './modules/node-transformers/ObfuscatingTransformersModule';
 import { obfuscatingTransformersModule } from './modules/node-transformers/ObfuscatingTransformersModule';
@@ -211,6 +212,7 @@ export class InversifyContainerFacade implements IInversifyContainerFacade {
         this.container.load(finalizingTransformersModule);
         this.container.load(finalizingTransformersModule);
         this.container.load(generatorsModule);
         this.container.load(generatorsModule);
         this.container.load(initializingTransformersModule);
         this.container.load(initializingTransformersModule);
+        this.container.load(minificationTransformersModule);
         this.container.load(nodeModule);
         this.container.load(nodeModule);
         this.container.load(nodeTransformersModule);
         this.container.load(nodeTransformersModule);
         this.container.load(obfuscatingTransformersModule);
         this.container.load(obfuscatingTransformersModule);

+ 15 - 0
src/container/modules/node-transformers/MinificationTransformersModule.ts

@@ -0,0 +1,15 @@
+import { ContainerModule, interfaces } from 'inversify';
+import { ServiceIdentifiers } from '../../ServiceIdentifiers';
+
+import { INodeTransformer } from '../../../interfaces/node-transformers/INodeTransformer';
+
+import { NodeTransformer } from '../../../enums/node-transformers/NodeTransformer';
+
+import { VariableDeclarationsMergeTransformer } from '../../../node-transformers/minification-transformers/VariableDeclarationsMergeTransformer';
+
+export const minificationTransformersModule: interfaces.ContainerModule = new ContainerModule((bind: interfaces.Bind) => {
+    // minification transformers
+    bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
+        .to(VariableDeclarationsMergeTransformer)
+        .whenTargetNamed(NodeTransformer.VariableDeclarationsMergeTransformer);
+});

+ 1 - 0
src/enums/node-transformers/NodeTransformationStage.ts

@@ -6,5 +6,6 @@ export enum NodeTransformationStage {
     RenameProperties = 'RenameProperties',
     RenameProperties = 'RenameProperties',
     Converting = 'Converting',
     Converting = 'Converting',
     Obfuscating = 'Obfuscating',
     Obfuscating = 'Obfuscating',
+    Minification = 'Minification',
     Finalizing = 'Finalizing'
     Finalizing = 'Finalizing'
 }
 }

+ 1 - 0
src/enums/node-transformers/NodeTransformer.ts

@@ -18,5 +18,6 @@ export enum NodeTransformer {
     ScopeIdentifiersTransformer = 'ScopeIdentifiersTransformer',
     ScopeIdentifiersTransformer = 'ScopeIdentifiersTransformer',
     SplitStringTransformer = 'SplitStringTransformer',
     SplitStringTransformer = 'SplitStringTransformer',
     TemplateLiteralTransformer = 'TemplateLiteralTransformer',
     TemplateLiteralTransformer = 'TemplateLiteralTransformer',
+    VariableDeclarationsMergeTransformer = 'VariableDeclarationsMergeTransformer',
     VariablePreserveTransformer = 'VariablePreserveTransformer'
     VariablePreserveTransformer = 'VariablePreserveTransformer'
 }
 }

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

@@ -21,6 +21,7 @@ export interface IOptions {
     readonly identifiersPrefix: string;
     readonly identifiersPrefix: string;
     readonly inputFileName: string;
     readonly inputFileName: string;
     readonly log: boolean;
     readonly log: boolean;
+    readonly minify: boolean;
     readonly renameGlobals: boolean;
     readonly renameGlobals: boolean;
     readonly renameProperties: boolean;
     readonly renameProperties: boolean;
     readonly reservedNames: string[];
     readonly reservedNames: string[];

+ 91 - 0
src/node-transformers/minification-transformers/VariableDeclarationsMergeTransformer.ts

@@ -0,0 +1,91 @@
+import { inject, injectable, } from 'inversify';
+import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
+
+import * as estraverse from 'estraverse';
+import * as ESTree from 'estree';
+
+import { TStatement } from '../../types/node/TStatement';
+
+import { IOptions } from '../../interfaces/options/IOptions';
+import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
+import { IVisitor } from '../../interfaces/node-transformers/IVisitor';
+
+import { NodeTransformationStage } from '../../enums/node-transformers/NodeTransformationStage';
+
+import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
+import { NodeGuards } from '../../node/NodeGuards';
+import { NodeStatementUtils } from '../../node/NodeStatementUtils';
+
+/**
+ * replaces:
+ *     var foo = 1;
+ *     var bar = 2;
+ *
+ * on:
+ *     var foo = 1,
+ *         bar = 2;
+ */
+@injectable()
+export class VariableDeclarationsMergeTransformer extends AbstractNodeTransformer {
+    /**
+     * @param {IRandomGenerator} randomGenerator
+     * @param {IOptions} options
+     */
+    public constructor (
+        @inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
+        @inject(ServiceIdentifiers.IOptions) options: IOptions
+    ) {
+        super(randomGenerator, options);
+    }
+
+    /**
+     * @param {NodeTransformationStage} nodeTransformationStage
+     * @returns {IVisitor | null}
+     */
+    public getVisitor (nodeTransformationStage: NodeTransformationStage): IVisitor | null {
+        switch (nodeTransformationStage) {
+            case NodeTransformationStage.Minification:
+                return {
+                    enter: (
+                        node: ESTree.Node,
+                        parentNode: ESTree.Node | null
+                    ): ESTree.Node | estraverse.VisitorOption | undefined => {
+                        if (parentNode && NodeGuards.isVariableDeclarationNode(node)) {
+                            return this.transformNode(node, parentNode);
+                        }
+                    }
+                };
+
+            default:
+                return null;
+        }
+    }
+
+    /**
+     * @param {ESTree.VariableDeclaration} variableDeclarationNode
+     * @param {ESTree.Node} parentNode
+     * @returns {ESTree.VariableDeclaration | estraverse.VisitorOption}
+     */
+    public transformNode (
+        variableDeclarationNode: ESTree.VariableDeclaration,
+        parentNode: ESTree.Node
+    ): ESTree.VariableDeclaration | estraverse.VisitorOption {
+        if (!NodeGuards.isNodeWithStatements(parentNode)) {
+            return variableDeclarationNode;
+        }
+
+        const prevStatement: TStatement | null = NodeStatementUtils.getPreviousSiblingStatement(variableDeclarationNode);
+
+        if (!prevStatement || !NodeGuards.isVariableDeclarationNode(prevStatement)) {
+            return variableDeclarationNode;
+        }
+
+        if (variableDeclarationNode.kind !== prevStatement.kind) {
+            return variableDeclarationNode;
+        }
+
+        prevStatement.declarations.push(...variableDeclarationNode.declarations);
+
+        return estraverse.VisitorOption.Remove;
+    }
+}

+ 6 - 0
src/options/Options.ts

@@ -150,6 +150,12 @@ export class Options implements IOptions {
     @IsBoolean()
     @IsBoolean()
     public readonly log!: boolean;
     public readonly log!: boolean;
 
 
+    /**
+     * @type {boolean}
+     */
+    @IsBoolean()
+    public readonly minify!: boolean;
+
     /**
     /**
      * @type {boolean}
      * @type {boolean}
      */
      */

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

@@ -21,6 +21,7 @@ export const DEFAULT_PRESET: TInputOptions = Object.freeze({
     identifiersDictionary: [],
     identifiersDictionary: [],
     inputFileName: '',
     inputFileName: '',
     log: false,
     log: false,
+    minify: true,
     renameGlobals: false,
     renameGlobals: false,
     renameProperties: false,
     renameProperties: false,
     reservedNames: [],
     reservedNames: [],

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

@@ -20,6 +20,7 @@ export const NO_ADDITIONAL_NODES_PRESET: TInputOptions = Object.freeze({
     identifiersDictionary: [],
     identifiersDictionary: [],
     inputFileName: '',
     inputFileName: '',
     log: false,
     log: false,
+    minify: false,
     renameGlobals: false,
     renameGlobals: false,
     renameProperties: false,
     renameProperties: false,
     reservedNames: [],
     reservedNames: [],

+ 5 - 4
test/dev/dev.ts

@@ -7,14 +7,15 @@ import { NO_ADDITIONAL_NODES_PRESET } from '../../src/options/presets/NoCustomNo
 
 
     let obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
     let obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
         `
         `
-            class Foo {
-                [(1, Symbol.asyncIterator)]() {}
-            }
+            const foo = 1;
+            let bar = 2;
+            
+            bar = 3;
         `,
         `,
         {
         {
             ...NO_ADDITIONAL_NODES_PRESET,
             ...NO_ADDITIONAL_NODES_PRESET,
             compact: false,
             compact: false,
-            renameProperties: true
+            minify: true
         }
         }
     ).getObfuscatedCode();
     ).getObfuscatedCode();
 
 

+ 4 - 4
yarn.lock

@@ -297,10 +297,10 @@
     "@types/estree" "*"
     "@types/estree" "*"
     "@types/json-schema" "*"
     "@types/json-schema" "*"
 
 
-"@types/estraverse@0.0.6":
-  version "0.0.6"
-  resolved "https://registry.yarnpkg.com/@types/estraverse/-/estraverse-0.0.6.tgz#669f7cdf72ab797e6125f8d00fed33d4cf30c221"
-  integrity sha1-Zp9833KreX5hJfjQD+0z1M8wwiE=
+"@types/estraverse@5.1.0":
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/@types/estraverse/-/estraverse-5.1.0.tgz#7a16cf8a8ee7764c05ccef3b2701bbcde6d5d0ae"
+  integrity sha512-vH2ItsZq47KprWHdv8OMjlfpygPHp1P7X4zuJuTghXldyezatpaotNSujld/HNsxh9TUS7+JRB0HEldkv67qaw==
   dependencies:
   dependencies:
     "@types/estree" "*"
     "@types/estree" "*"
 
 

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