Browse Source

Added few utility helpers for finding sibling statement nodes

sanex3339 7 years ago
parent
commit
a8c4660875

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


+ 5 - 5
package.json

@@ -19,10 +19,10 @@
     "javascript-obfuscator": "./bin/javascript-obfuscator"
   },
   "dependencies": {
-    "chalk": "2.3.0",
+    "chalk": "2.3.1",
     "chance": "1.0.13",
     "class-validator": "0.8.1",
-    "commander": "2.14.0",
+    "commander": "2.14.1",
     "escodegen-wallaby": "1.6.17",
     "esprima": "4.0.0",
     "estraverse": "4.2.0",
@@ -47,7 +47,7 @@
     "@types/md5": "2.1.32",
     "@types/mkdirp": "0.5.2",
     "@types/mocha": "2.2.48",
-    "@types/node": "9.4.1",
+    "@types/node": "9.4.5",
     "@types/rimraf": "2.0.2",
     "@types/sinon": "4.1.3",
     "@types/string-template": "1.0.2",
@@ -63,7 +63,7 @@
     "mocha": "5.0.0",
     "pre-commit": "1.2.2",
     "rimraf": "2.6.2",
-    "sinon": "4.2.2",
+    "sinon": "4.3.0",
     "threads": "0.10.1",
     "ts-node": "4.1.0",
     "tslint": "5.9.1",
@@ -71,7 +71,7 @@
     "tslint-language-service": "0.9.8",
     "tslint-webpack-plugin": "1.1.1",
     "typescript": "2.7.1",
-    "webpack": "3.10.0",
+    "webpack": "3.11.0",
     "webpack-node-externals": "1.6.0"
   },
   "repository": {

+ 31 - 0
src/node/NodeUtils.ts

@@ -71,6 +71,22 @@ export class NodeUtils {
         return NodeUtils.getBlockScopesOfNodeRecursive(targetNode);
     }
 
+    /**
+     * @param {Statement} node
+     * @returns {Node | null}
+     */
+    public static getNextSiblingStatementNode (node: ESTree.Statement): ESTree.Node | null {
+        return NodeUtils.getSiblingStatementNodeByOffset(node, 1);
+    }
+
+    /**
+     * @param {Statement} node
+     * @returns {Node | null}
+     */
+    public static getPreviousSiblingStatementNode (node: ESTree.Statement): ESTree.Node | null {
+        return NodeUtils.getSiblingStatementNodeByOffset(node, -1);
+    }
+
     /**
      * @param {NodeGuards} node
      * @returns {TNodeWithScope}
@@ -208,4 +224,19 @@ export class NodeUtils {
 
         return blockScopes;
     }
+
+    /**
+     * @param {Statement} node
+     * @param {number} offset
+     * @returns {Node | null}
+     */
+    private static getSiblingStatementNodeByOffset (node: ESTree.Statement, offset: number): ESTree.Node | null {
+        const scopeNode: TNodeWithScope = NodeUtils.getScopeOfNode(node);
+        const scopeBody: TStatement[] = !NodeGuards.isSwitchCaseNode(scopeNode)
+            ? scopeNode.body
+            : scopeNode.consequent;
+        const indexInScope: number = scopeBody.indexOf(node);
+
+        return scopeBody[indexInScope + offset] || null;
+    }
 }

+ 44 - 3
test/functional-tests/node-transformers/converting-transformers/template-literal-transformer/TemplateLiteralTransformer.spec.ts

@@ -24,7 +24,48 @@ describe('TemplateLiteralTransformer', () => {
         });
     });
 
-    describe('variant #1: simple template literal with expression only', () => {
+    describe('variant #2: multiline template literals', () => {
+        it('variant #1: should transform es6 multiline template literal to es5', () => {
+            const code: string = readFileAsString(__dirname + '/fixtures/multiline-template-literal.js');
+            const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
+                code,
+                {
+                    ...NO_ADDITIONAL_NODES_PRESET,
+                    unicodeEscapeSequence: false
+                }
+            );
+
+            assert.match(obfuscationResult.getObfuscatedCode(),  /^var *test *= *'foo\\x0abar';$/);
+        });
+
+        it('variant #2: should transform es6 multiline template literal inside return statement', () => {
+            const code: string = readFileAsString(__dirname + '/fixtures/multiline-template-literal-return-statement-1.js');
+            const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
+                code,
+                {
+                    ...NO_ADDITIONAL_NODES_PRESET,
+                    unicodeEscapeSequence: false
+                }
+            );
+
+            assert.match(obfuscationResult.getObfuscatedCode(),  /return *'foo\\x0abar';$/);
+        });
+
+        it('variant #3: should transform es6 multiline template literal inside return statement', () => {
+            const code: string = readFileAsString(__dirname + '/fixtures/multiline-template-literal-return-statement-2.js');
+            const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
+                code,
+                {
+                    ...NO_ADDITIONAL_NODES_PRESET,
+                    unicodeEscapeSequence: false
+                }
+            );
+
+            assert.match(obfuscationResult.getObfuscatedCode(),  /return *'foo\\x0abar';$/);
+        });
+    });
+
+    describe('variant #3: simple template literal with expression only', () => {
         it('should transform es6 template literal to es5 and add empty literal node before expression node', () => {
             const code: string = readFileAsString(__dirname + '/fixtures/expression-only.js');
             const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
@@ -39,7 +80,7 @@ describe('TemplateLiteralTransformer', () => {
         });
     });
 
-    describe('variant #3: literal node inside expression', () => {
+    describe('variant #4: literal node inside expression', () => {
         it('should transform es6 template literal to es5', () => {
             const code: string = readFileAsString(__dirname + '/fixtures/literal-inside-expression.js');
             const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
@@ -54,7 +95,7 @@ describe('TemplateLiteralTransformer', () => {
         });
     });
 
-    describe('variant #4: multiple expressions', () => {
+    describe('variant #5: multiple expressions', () => {
         it('should transform es6 template literal to es5', () => {
             const code: string = readFileAsString(__dirname + '/fixtures/multiple-expressions.js');
             const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(

+ 4 - 0
test/functional-tests/node-transformers/converting-transformers/template-literal-transformer/fixtures/multiline-template-literal-return-statement-1.js

@@ -0,0 +1,4 @@
+function foo() {
+    return `foo
+bar`;
+}

+ 7 - 0
test/functional-tests/node-transformers/converting-transformers/template-literal-transformer/fixtures/multiline-template-literal-return-statement-2.js

@@ -0,0 +1,7 @@
+function hi() {
+    switch (true) {
+        case true:
+            return `foo
+bar`;
+    }
+}

+ 2 - 0
test/functional-tests/node-transformers/converting-transformers/template-literal-transformer/fixtures/multiline-template-literal.js

@@ -0,0 +1,2 @@
+var test = `foo
+bar`;

+ 170 - 0
test/unit-tests/node/node-utils/NodeUtils.spec.ts

@@ -294,6 +294,176 @@ describe('NodeUtils', () => {
         });
     });
 
+    describe('getNextSiblingStatementNode (node: ESTree.Statement): ESTree.Node | null', () => {
+        describe('variant #1: block statement node as scope node', () => {
+                let statementNode1: ESTree.Statement,
+                statementNode2: ESTree.Statement,
+                statementNode3: ESTree.Statement;
+
+            before(() => {
+                statementNode1 = Nodes.getExpressionStatementNode(
+                    Nodes.getIdentifierNode('a')
+                );
+                statementNode2 = Nodes.getExpressionStatementNode(
+                    Nodes.getIdentifierNode('b')
+                );
+                statementNode3 = Nodes.getExpressionStatementNode(
+                    Nodes.getIdentifierNode('c')
+                );
+
+                const blockStatementNode: ESTree.BlockStatement = Nodes.getBlockStatementNode([
+                    statementNode1,
+                    statementNode2,
+                    statementNode3
+                ]);
+
+                statementNode1.parentNode = blockStatementNode;
+                statementNode2.parentNode = blockStatementNode;
+                statementNode3.parentNode = blockStatementNode;
+            });
+
+            it('should return next sibling statement node', () => {
+                assert.deepEqual(NodeUtils.getNextSiblingStatementNode(statementNode1), statementNode2);
+            });
+
+            it('should return next sibling statement node', () => {
+                assert.deepEqual(NodeUtils.getNextSiblingStatementNode(statementNode2), statementNode3);
+            });
+
+            it('should return `null` if given statement node is last node in the scope', () => {
+                assert.deepEqual(NodeUtils.getNextSiblingStatementNode(statementNode3), null);
+            });
+        });
+
+        describe('variant #2: switch case node as scope node', () => {
+            let statementNode1: ESTree.Statement,
+                statementNode2: ESTree.Statement,
+                statementNode3: ESTree.Statement;
+
+            before(() => {
+                statementNode1 = Nodes.getExpressionStatementNode(
+                    Nodes.getIdentifierNode('a')
+                );
+                statementNode2 = Nodes.getExpressionStatementNode(
+                    Nodes.getIdentifierNode('b')
+                );
+                statementNode3 = Nodes.getExpressionStatementNode(
+                    Nodes.getIdentifierNode('c')
+                );
+
+                const switchCaseNode: ESTree.SwitchCase = Nodes.getSwitchCaseNode(
+                    Nodes.getLiteralNode(true),
+                    [
+                        statementNode1,
+                        statementNode2,
+                        statementNode3
+                    ]
+                );
+
+                statementNode1.parentNode = switchCaseNode;
+                statementNode2.parentNode = switchCaseNode;
+                statementNode3.parentNode = switchCaseNode;
+            });
+
+            it('should return next sibling statement node', () => {
+                assert.deepEqual(NodeUtils.getNextSiblingStatementNode(statementNode1), statementNode2);
+            });
+
+            it('should return next sibling statement node', () => {
+                assert.deepEqual(NodeUtils.getNextSiblingStatementNode(statementNode2), statementNode3);
+            });
+
+            it('should return `null` if given statement node is last node in the scope', () => {
+                assert.deepEqual(NodeUtils.getNextSiblingStatementNode(statementNode3), null);
+            });
+        });
+    });
+
+    describe('getPreviousSiblingStatementNode (node: ESTree.Statement): ESTree.Node | null', () => {
+        describe('variant #1: block statement node as scope node', () => {
+            let statementNode1: ESTree.Statement,
+                statementNode2: ESTree.Statement,
+                statementNode3: ESTree.Statement;
+
+            before(() => {
+                statementNode1 = Nodes.getExpressionStatementNode(
+                    Nodes.getIdentifierNode('a')
+                );
+                statementNode2 = Nodes.getExpressionStatementNode(
+                    Nodes.getIdentifierNode('b')
+                );
+                statementNode3 = Nodes.getExpressionStatementNode(
+                    Nodes.getIdentifierNode('c')
+                );
+
+                const blockStatementNode: ESTree.BlockStatement = Nodes.getBlockStatementNode([
+                    statementNode1,
+                    statementNode2,
+                    statementNode3
+                ]);
+
+                statementNode1.parentNode = blockStatementNode;
+                statementNode2.parentNode = blockStatementNode;
+                statementNode3.parentNode = blockStatementNode;
+            });
+
+            it('should return next sibling statement node', () => {
+                assert.deepEqual(NodeUtils.getPreviousSiblingStatementNode(statementNode1), null);
+            });
+
+            it('should return next sibling statement node', () => {
+                assert.deepEqual(NodeUtils.getPreviousSiblingStatementNode(statementNode2), statementNode1);
+            });
+
+            it('should return `null` if given statement node is last node in the scope', () => {
+                assert.deepEqual(NodeUtils.getPreviousSiblingStatementNode(statementNode3), statementNode2);
+            });
+        });
+
+        describe('variant #2: switch case node as scope node', () => {
+            let statementNode1: ESTree.Statement,
+                statementNode2: ESTree.Statement,
+                statementNode3: ESTree.Statement;
+
+            before(() => {
+                statementNode1 = Nodes.getExpressionStatementNode(
+                    Nodes.getIdentifierNode('a')
+                );
+                statementNode2 = Nodes.getExpressionStatementNode(
+                    Nodes.getIdentifierNode('b')
+                );
+                statementNode3 = Nodes.getExpressionStatementNode(
+                    Nodes.getIdentifierNode('c')
+                );
+
+                const switchCaseNode: ESTree.SwitchCase = Nodes.getSwitchCaseNode(
+                    Nodes.getLiteralNode(true),
+                    [
+                        statementNode1,
+                        statementNode2,
+                        statementNode3
+                    ]
+                );
+
+                statementNode1.parentNode = switchCaseNode;
+                statementNode2.parentNode = switchCaseNode;
+                statementNode3.parentNode = switchCaseNode;
+            });
+
+            it('should return next sibling statement node', () => {
+                assert.deepEqual(NodeUtils.getPreviousSiblingStatementNode(statementNode1), null);
+            });
+
+            it('should return next sibling statement node', () => {
+                assert.deepEqual(NodeUtils.getPreviousSiblingStatementNode(statementNode2), statementNode1);
+            });
+
+            it('should return `null` if given statement node is last node in the scope', () => {
+                assert.deepEqual(NodeUtils.getPreviousSiblingStatementNode(statementNode3), statementNode2);
+            });
+        });
+    });
+
     describe('getScopeOfNode (node: ESTree.Node): TNodeWithScope | null', () => {
         let functionDeclarationBlockStatementNode: ESTree.BlockStatement,
             ifStatementBlockStatementNode1: ESTree.BlockStatement,

+ 49 - 26
yarn.lock

@@ -2,6 +2,12 @@
 # yarn lockfile v1
 
 
+"@sinonjs/formatio@^2.0.0":
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/@sinonjs/formatio/-/formatio-2.0.0.tgz#84db7e9eb5531df18a8c5e0bfb6e449e55e654b2"
+  dependencies:
+    samsam "1.3.0"
+
 "@types/[email protected]":
   version "4.1.2"
   resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.1.2.tgz#f1af664769cfb50af805431c407425ed619daa21"
@@ -66,9 +72,9 @@
   version "8.0.53"
   resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.53.tgz#396b35af826fa66aad472c8cb7b8d5e277f4e6d8"
 
-"@types/[email protected].1":
-  version "9.4.1"
-  resolved "https://registry.yarnpkg.com/@types/node/-/node-9.4.1.tgz#0f636f7837e15d2d73a7f6f3ea0e322eb2a5ab65"
+"@types/[email protected].5":
+  version "9.4.5"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-9.4.5.tgz#d2a90c634208173d1b1a0a6ba9f1df3de62edcf5"
 
 "@types/[email protected]":
   version "2.0.2"
@@ -115,9 +121,9 @@ acorn@^5.0.0:
   version "5.2.1"
   resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.2.1.tgz#317ac7821826c22c702d66189ab8359675f135d7"
 
-ajv-keywords@^2.0.0:
-  version "2.1.1"
-  resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762"
+ajv-keywords@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.1.0.tgz#ac2b27939c543e95d2c06e7f7f5c27be4aa543be"
 
 ajv@^4.9.1:
   version "4.11.8"
@@ -126,11 +132,10 @@ ajv@^4.9.1:
     co "^4.6.0"
     json-stable-stringify "^1.0.1"
 
-ajv@^5.1.5:
-  version "5.3.0"
-  resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.3.0.tgz#4414ff74a50879c208ee5fdc826e32c303549eda"
+ajv@^6.1.0:
+  version "6.1.1"
+  resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.1.1.tgz#978d597fbc2b7d0e5a5c3ddeb149a682f2abfa0e"
   dependencies:
-    co "^4.6.0"
     fast-deep-equal "^1.0.0"
     fast-json-stable-stringify "^2.0.0"
     json-schema-traverse "^0.3.0"
@@ -163,7 +168,7 @@ ansi-styles@^2.2.1:
   version "2.2.1"
   resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
 
-ansi-styles@^3.1.0:
+ansi-styles@^3.1.0, ansi-styles@^3.2.0:
   version "3.2.0"
   resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.0.tgz#c159b8d5be0f9e5a6f346dab94f16ce022161b88"
   dependencies:
@@ -964,7 +969,15 @@ [email protected], chalk@^1.0.0, chalk@^1.1.3:
     strip-ansi "^3.0.0"
     supports-color "^2.0.0"
 
[email protected], chalk@^2.1.0, chalk@^2.3.0:
[email protected]:
+  version "2.3.1"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.1.tgz#523fe2678aec7b04e8041909292fe8b17059b796"
+  dependencies:
+    ansi-styles "^3.2.0"
+    escape-string-regexp "^1.0.5"
+    supports-color "^5.2.0"
+
+chalk@^2.1.0, chalk@^2.3.0:
   version "2.3.0"
   resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.0.tgz#b5ea48efc9c1793dccc9b4767c93914d3f2d52ba"
   dependencies:
@@ -1087,9 +1100,9 @@ [email protected]:
   version "2.11.0"
   resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563"
 
[email protected].0:
-  version "2.14.0"
-  resolved "https://registry.yarnpkg.com/commander/-/commander-2.14.0.tgz#7b25325963e6aace20d3a9285b09379b0c2208b5"
[email protected].1:
+  version "2.14.1"
+  resolved "https://registry.yarnpkg.com/commander/-/commander-2.14.1.tgz#2235123e37af8ca3c65df45b026dbd357b01b9aa"
 
 commander@^2.11.0:
   version "2.12.2"
@@ -1684,7 +1697,7 @@ form-data@~2.1.1:
     combined-stream "^1.0.5"
     mime-types "^2.1.12"
 
-[email protected], formatio@^1.2.0:
+formatio@^1.2.0:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/formatio/-/formatio-1.2.0.tgz#f3b2167d9068c4698a8d51f4f760a39a54d818eb"
   dependencies:
@@ -1834,6 +1847,10 @@ has-flag@^2.0.0:
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51"
 
+has-flag@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
+
 has-unicode@^2.0.0:
   version "2.0.1"
   resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
@@ -3268,7 +3285,7 @@ safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@~5.1.0,
   version "5.1.1"
   resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853"
 
[email protected]:
+[email protected], [email protected]:
   version "1.3.0"
   resolved "https://registry.yarnpkg.com/samsam/-/samsam-1.3.0.tgz#8d1d9350e25622da30de3e44ba692b5221ab7c50"
 
@@ -3333,12 +3350,12 @@ 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.2.2:
-  version "4.2.2"
-  resolved "https://registry.yarnpkg.com/sinon/-/sinon-4.2.2.tgz#e039ab27bdb426fc61363c380726e996a2e2c620"
+sinon@4.3.0:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/sinon/-/sinon-4.3.0.tgz#cec9b27d5f4e2c63c1a79c9dc1c05d34bb088234"
   dependencies:
+    "@sinonjs/formatio" "^2.0.0"
     diff "^3.1.0"
-    formatio "1.2.0"
     lodash.get "^4.4.2"
     lolex "^2.2.0"
     nise "^1.2.0"
@@ -3598,6 +3615,12 @@ supports-color@^5.1.0:
   dependencies:
     has-flag "^2.0.0"
 
+supports-color@^5.2.0:
+  version "5.2.0"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.2.0.tgz#b0d5333b1184dd3666cbe5aa0b45c5ac7ac17a4a"
+  dependencies:
+    has-flag "^3.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"
@@ -3936,14 +3959,14 @@ webpack-sources@^1.0.1:
     source-list-map "^2.0.0"
     source-map "~0.5.3"
 
[email protected]0.0:
-  version "3.10.0"
-  resolved "https://registry.yarnpkg.com/webpack/-/webpack-3.10.0.tgz#5291b875078cf2abf42bdd23afe3f8f96c17d725"
[email protected]1.0:
+  version "3.11.0"
+  resolved "https://registry.yarnpkg.com/webpack/-/webpack-3.11.0.tgz#77da451b1d7b4b117adaf41a1a93b5742f24d894"
   dependencies:
     acorn "^5.0.0"
     acorn-dynamic-import "^2.0.0"
-    ajv "^5.1.5"
-    ajv-keywords "^2.0.0"
+    ajv "^6.1.0"
+    ajv-keywords "^3.1.0"
     async "^2.1.2"
     enhanced-resolve "^3.4.0"
     escope "^3.6.0"

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