浏览代码

Support for class static blocks

sanex 3 年之前
父节点
当前提交
6b8ead0b2b

+ 4 - 0
CHANGELOG.md

@@ -1,5 +1,9 @@
 Change Log
 
+v3.1.0
+---
+* Added support of `es2022` features: class static block
+
 v3.0.1
 ---
 * Dependencies update

+ 2 - 2
package.json

@@ -1,6 +1,6 @@
 {
   "name": "javascript-obfuscator",
-  "version": "3.0.1",
+  "version": "3.1.0",
   "description": "JavaScript obfuscator",
   "keywords": [
     "obfuscator",
@@ -21,7 +21,7 @@
   },
   "types": "typings/index.d.ts",
   "dependencies": {
-    "@javascript-obfuscator/escodegen": "2.2.2",
+    "@javascript-obfuscator/escodegen": "2.3.0",
     "@javascript-obfuscator/estraverse": "5.4.0",
     "@nuxtjs/opencollective": "0.3.2",
     "acorn": "8.7.0",

+ 5 - 0
src/declarations/ESTree.d.ts

@@ -3,6 +3,7 @@
 import * as acorn from 'acorn';
 import * as escodegen from '@javascript-obfuscator/escodegen';
 import * as eslintScope from 'eslint-scope';
+import { BlockStatement } from 'estree';
 
 declare module 'estree' {
     /**
@@ -53,4 +54,8 @@ declare module 'estree' {
         metadata?: LiteralNodeMetadata;
         'x-verbatim-property'?: escodegen.XVerbatimProperty;
     }
+
+    interface StaticBlock extends Omit<BlockStatement, 'type'> {
+        type: 'StaticBlock'
+    }
 }

+ 1 - 0
src/enums/node/NodeType.ts

@@ -47,6 +47,7 @@ export enum NodeType {
     ReturnStatement = 'ReturnStatement',
     SequenceExpression = 'SequenceExpression',
     SpreadElement = 'SpreadElement',
+    StaticBlock = 'StaticBlock',
     Super = 'Super',
     SwitchCase = 'SwitchCase',
     SwitchStatement = 'SwitchStatement',

+ 12 - 0
src/node/NodeFactory.ts

@@ -544,6 +544,18 @@ export class NodeFactory {
         };
     }
 
+    /**
+     * @param {Statement[]} body
+     * @returns {StaticBlock}
+     */
+    public static staticBlockNode (body: ESTree.Statement[] = []): ESTree.StaticBlock {
+        return {
+            type: NodeType.StaticBlock,
+            body,
+            metadata: { ignoredNode: false }
+        };
+    }
+
     /**
      * @param {Expression} discriminant
      * @param {SwitchCase[]} cases

+ 14 - 1
src/node/NodeGuards.ts

@@ -365,7 +365,9 @@ export class NodeGuards {
      * @returns {boolean}
      */
     public static isNodeWithBlockLexicalScope (node: ESTree.Node): node is TNodeWithLexicalScope {
-        return NodeGuards.isNodeWithLexicalScope(node) || NodeGuards.isBlockStatementNode(node);
+        return NodeGuards.isNodeWithLexicalScope(node)
+            || NodeGuards.isBlockStatementNode(node)
+            || NodeGuards.isStaticBlockNode(node);
     }
 
     /**
@@ -417,6 +419,7 @@ export class NodeGuards {
     public static isNodeWithStatements (node: ESTree.Node): node is TNodeWithStatements {
         return NodeGuards.isProgramNode(node)
             || NodeGuards.isBlockStatementNode(node)
+            || NodeGuards.isStaticBlockNode(node)
             || NodeGuards.isSwitchCaseNode(node);
     }
 
@@ -500,6 +503,16 @@ export class NodeGuards {
         return node.type === NodeType.SpreadElement;
     }
 
+    /**
+     * @param {Node} node
+     * @returns {boolean}
+     */
+    // TODO: add type guard after @types/estree update
+    public static isStaticBlockNode (node: ESTree.Node): boolean {
+        // TODO: Update @types/estree
+        return (<any>node).type === NodeType.StaticBlock;
+    }
+
     /**
      * @param {Node} node
      * @returns {boolean}

+ 9 - 7
test/dev/dev.ts

@@ -1,18 +1,20 @@
 'use strict';
 
-import { readFileAsString } from '../helpers/readFileAsString';
-
 (function () {
     const JavaScriptObfuscator: any = require('../../index');
-    const code: string = readFileAsString(__dirname + '/../functional-tests/javascript-obfuscator/fixtures/custom-nodes-identifier-names-collision.js');
+    const code: string = `
+        class Foo {
+            static {
+                let abc = 2;
+                abc = 3;
+            }
+        }
+    `;
 
     let obfuscationResult = JavaScriptObfuscator.obfuscate(
         code,
         {
-            identifierNamesGenerator: 'mangled',
-            compact: false,
-            stringArray: true,
-            seed: 429105580
+            compact: false
         }
     );
 

+ 36 - 0
test/functional-tests/javascript-obfuscator/JavaScriptObfuscator.spec.ts

@@ -984,6 +984,42 @@ describe('JavaScriptObfuscator', () => {
             });
         });
 
+        describe('Class static block support', () => {
+            const regExp: RegExp = new RegExp(
+                'let _0x(\\w){4,6} *= *0x1; *' +
+                'class _0x(\\w){4,6} *{ *' +
+                    'static *\\[\'_0x(\\w){4,6}\']; *' +
+                    'static *{ *' +
+                        'let _0x(\\w){4,6} *= *0x2; *' +
+                        '_0x(\\w){4,6}\\[\'_0x(\\w){4,6}\'] *= *0x3; *' +
+                        '_0x(\\w){4,6} *= *0x4; *' +
+                        '_0x(\\w){4,6} *= *0x5; *' +
+                    '} *' +
+                '}'
+            );
+
+            let obfuscatedCode: string;
+
+            beforeEach(() => {
+                const code: string = readFileAsString(__dirname + '/fixtures/class-static-block-support-1.js');
+
+                obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                    code,
+                    {
+                        ...NO_ADDITIONAL_NODES_PRESET,
+                        renameGlobals: true,
+                        renameProperties: true
+                    }
+                ).getObfuscatedCode();
+
+                console.log(obfuscatedCode);
+            });
+
+            it('should support class static block await', () => {
+                assert.match(obfuscatedCode, regExp);
+            });
+        });
+
         describe('Private identifiers support', () => {
             const regExp: RegExp = new RegExp(
                 'class Foo *{ *' +

+ 11 - 0
test/functional-tests/javascript-obfuscator/fixtures/class-static-block-support-1.js

@@ -0,0 +1,11 @@
+let foo = 1;
+class Foo {
+    static abc;
+
+    static {
+        let bar = 2;
+        Foo.abc = 3;
+        foo = 4;
+        bar = 5;
+    }
+}

+ 17 - 1
test/unit-tests/node/node-guards/NodeGuards.spec.ts

@@ -705,7 +705,23 @@ describe('NodeGuards', () => {
                 });
             });
 
-            describe('Variant #3: switch case node', () => {
+            describe('Variant #3: static block node', () => {
+                const expectedResult: boolean = true;
+                // TODO: remove typecast after @types/estree update
+                const node: ESTree.Node = <any>NodeFactory.staticBlockNode();
+
+                let result: boolean;
+
+                before(() => {
+                    result = NodeGuards.isNodeWithStatements(node);
+                });
+
+                it('should check if node has statements', () => {
+                    assert.equal(result, expectedResult);
+                });
+            });
+
+            describe('Variant #4: switch case node', () => {
                 const expectedResult: boolean = true;
                 const node: ESTree.Node = NodeFactory.switchCaseNode(
                     NodeFactory.literalNode(1),

+ 4 - 4
yarn.lock

@@ -259,10 +259,10 @@
   resolved "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz"
   integrity sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==
 
-"@javascript-obfuscator/escodegen@2.2.2":
-  version "2.2.2"
-  resolved "https://registry.yarnpkg.com/@javascript-obfuscator/escodegen/-/escodegen-2.2.2.tgz#518aa621f6258fa369eb48b865e54dc58fc44cfa"
-  integrity sha512-0VoGJun/lpGEPv8J8R8fpwt1iAGyctUjHTQoYoCbKY2rcGc6d+NycrqSMo61vRXhZiTnHgud1UF8dOI7UAPdTw==
+"@javascript-obfuscator/escodegen@2.3.0":
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/@javascript-obfuscator/escodegen/-/escodegen-2.3.0.tgz#ff7eb7f8a7c004532e93b14ae8b2196dcf9a1a9e"
+  integrity sha512-QVXwMIKqYMl3KwtTirYIA6gOCiJ0ZDtptXqAv/8KWLG9uQU2fZqTVy7a/A5RvcoZhbDoFfveTxuGxJ5ibzQtkw==
   dependencies:
     "@javascript-obfuscator/estraverse" "^5.3.0"
     esprima "^4.0.1"