Просмотр исходного кода

Handle more cases of `IfStatement` simplify

sanex3339 4 лет назад
Родитель
Сommit
5b64f75dac

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
dist/index.browser.js


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
dist/index.cli.js


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
dist/index.js


+ 18 - 0
src/interfaces/node-transformers/minification-transformers/IIfStatementIteratedStatementsData.ts

@@ -0,0 +1,18 @@
+import * as ESTree from 'estree';
+
+export interface IIfStatementIteratedStatementsData {
+    /**
+     * @type {number | null}
+     */
+    startIndex: number | null;
+
+    /**
+     * @type {ESTree.Expression[]}
+     */
+    unwrappedExpressions: ESTree.Expression[];
+
+    /**
+     * @type {boolean}
+     */
+    hasReturnStatement: boolean;
+}

+ 10 - 13
src/interfaces/node-transformers/minification-transformers/IIfStatementSimplifyData.ts

@@ -6,23 +6,20 @@ export interface IIfStatementSimplifyData {
      */
     leadingStatements: ESTree.Statement[];
 
-    /**
-     * @type {ESTree.Statement}
-     */
-    statement: ESTree.Statement;
+    trailingStatement: {
+        /**
+         * @type {ESTree.Statement | null}
+         */
+        statement: ESTree.Statement;
 
-    /**
-     * @type {ESTree.Expression}
-     */
-    expression: ESTree.Expression;
+        /**
+         * @type {ESTree.Expression | null}
+         */
+        expression: ESTree.Expression;
+    } | null;
 
     /**
      * @type {boolean}
      */
     hasReturnStatement: boolean;
-
-    /**
-     * @type {boolean}
-     */
-    hasSingleExpression: boolean;
 }

+ 110 - 50
src/node-transformers/minification-transformers/IfStatementSimplifyTransformer.ts

@@ -4,6 +4,7 @@ import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
 import * as ESTree from 'estree';
 
 import { IIfStatementSimplifyData } from '../../interfaces/node-transformers/minification-transformers/IIfStatementSimplifyData';
+import { IIfStatementIteratedStatementsData } from '../../interfaces/node-transformers/minification-transformers/IIfStatementIteratedStatementsData';
 import { IOptions } from '../../interfaces/options/IOptions';
 import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
 import { IVisitor } from '../../interfaces/node-transformers/IVisitor';
@@ -64,12 +65,12 @@ export class IfStatementSimplifyTransformer extends AbstractNodeTransformer {
     ): ESTree.Node {
         const consequentSimplifyData: IIfStatementSimplifyData | null = this.getIfStatementSimplifyData(ifStatementNode.consequent);
 
-        // Variant #1: no valid consequent expression
+        // Variant #1: no valid consequent expression data
         if (!consequentSimplifyData) {
             return ifStatementNode;
         }
 
-        // Variant #2: valid consequent expression only
+        // Variant #2: valid data for consequent expression only
         if (!ifStatementNode.alternate) {
             return this.getConsequentNode(ifStatementNode, consequentSimplifyData);
         }
@@ -80,7 +81,7 @@ export class IfStatementSimplifyTransformer extends AbstractNodeTransformer {
             return ifStatementNode;
         }
 
-        // Variant #3: valid consequent and alternate expressions
+        // Variant #3: valid data for consequent and alternate expressions
         return this.getConsequentAndAlternateNode(ifStatementNode, consequentSimplifyData, alternateSimplifyData);
     }
 
@@ -107,13 +108,13 @@ export class IfStatementSimplifyTransformer extends AbstractNodeTransformer {
          *     return console.log(1), 1;
          * }
          */
-        if (consequentSimplifyData.leadingStatements.length) {
+        if (
+            consequentSimplifyData.leadingStatements.length
+            || !consequentSimplifyData.trailingStatement
+        ) {
             return NodeFactory.ifStatementNode(
                 ifStatementNode.test,
-                NodeFactory.blockStatementNode([
-                    ...consequentSimplifyData.leadingStatements,
-                    consequentSimplifyData.statement
-                ])
+                this.getPartialBlockStatementNode(consequentSimplifyData)
             );
         }
 
@@ -130,7 +131,7 @@ export class IfStatementSimplifyTransformer extends AbstractNodeTransformer {
         if (consequentSimplifyData.hasReturnStatement) {
             return NodeFactory.ifStatementNode(
                 ifStatementNode.test,
-                consequentSimplifyData.statement
+                consequentSimplifyData.trailingStatement.statement
             );
         }
 
@@ -147,7 +148,7 @@ export class IfStatementSimplifyTransformer extends AbstractNodeTransformer {
             NodeFactory.logicalExpressionNode(
                 '&&',
                 ifStatementNode.test,
-                consequentSimplifyData.expression,
+                consequentSimplifyData.trailingStatement.expression
             )
         );
     }
@@ -177,21 +178,16 @@ export class IfStatementSimplifyTransformer extends AbstractNodeTransformer {
          *     return console.log(1), 1;
          * }
          */
-        if (consequentSimplifyData.leadingStatements.length || alternateSimplifyData.leadingStatements.length) {
+        if (
+            consequentSimplifyData.leadingStatements.length
+            || alternateSimplifyData.leadingStatements.length
+            || !consequentSimplifyData.trailingStatement
+            || !alternateSimplifyData.trailingStatement
+        ) {
             return NodeFactory.ifStatementNode(
                 ifStatementNode.test,
-                consequentSimplifyData.leadingStatements.length
-                    ? NodeFactory.blockStatementNode([
-                        ...consequentSimplifyData.leadingStatements,
-                        consequentSimplifyData.statement
-                    ])
-                    : consequentSimplifyData.statement,
-                alternateSimplifyData.leadingStatements.length
-                    ? NodeFactory.blockStatementNode([
-                        ...alternateSimplifyData.leadingStatements,
-                        alternateSimplifyData.statement
-                    ])
-                    : alternateSimplifyData.statement
+                this.getPartialBlockStatementNode(consequentSimplifyData),
+                this.getPartialBlockStatementNode(alternateSimplifyData)
             );
         }
 
@@ -210,8 +206,8 @@ export class IfStatementSimplifyTransformer extends AbstractNodeTransformer {
             return NodeFactory.returnStatementNode(
                 NodeFactory.conditionalExpressionNode(
                     ifStatementNode.test,
-                    consequentSimplifyData.expression,
-                    alternateSimplifyData.expression
+                    consequentSimplifyData.trailingStatement.expression,
+                    alternateSimplifyData.trailingStatement.expression
                 )
             );
         }
@@ -233,8 +229,8 @@ export class IfStatementSimplifyTransformer extends AbstractNodeTransformer {
         if (consequentSimplifyData.hasReturnStatement || alternateSimplifyData.hasReturnStatement) {
             return NodeFactory.ifStatementNode(
                 ifStatementNode.test,
-                consequentSimplifyData.statement,
-                alternateSimplifyData.statement
+                consequentSimplifyData.trailingStatement.statement,
+                alternateSimplifyData.trailingStatement.statement
             );
         }
 
@@ -252,17 +248,18 @@ export class IfStatementSimplifyTransformer extends AbstractNodeTransformer {
         return NodeFactory.expressionStatementNode(
             NodeFactory.conditionalExpressionNode(
                 ifStatementNode.test,
-                consequentSimplifyData.expression,
-                alternateSimplifyData.expression
+                consequentSimplifyData.trailingStatement.expression,
+                alternateSimplifyData.trailingStatement.expression
             )
         );
     }
 
     /**
+     * Returns IIfStatementSimplifyData based on `IfStatement` node body
+     *
      * @param {ESTree.Statement | null | undefined} statementNode
      * @returns {IIfStatementSimplifyData | null}
      */
-    // eslint-disable-next-line complexity
     private getIfStatementSimplifyData (
         statementNode: ESTree.Statement | null | undefined
     ): IIfStatementSimplifyData | null {
@@ -270,6 +267,51 @@ export class IfStatementSimplifyTransformer extends AbstractNodeTransformer {
             return null;
         }
 
+        const {
+            startIndex,
+            unwrappedExpressions,
+            hasReturnStatement
+        } = this.collectIteratedStatementsData(statementNode);
+
+        const leadingStatements: ESTree.Statement[] = this.getLeadingStatements(statementNode, startIndex);
+
+        if (!unwrappedExpressions.length) {
+            return {
+                leadingStatements,
+                trailingStatement: null,
+                hasReturnStatement
+            };
+        }
+
+        const hasSingleExpression: boolean = unwrappedExpressions.length === 1;
+
+        const expression: ESTree.Expression = hasSingleExpression
+            ? unwrappedExpressions[0]
+            : NodeFactory.sequenceExpressionNode(unwrappedExpressions);
+
+        const statement: ESTree.Statement = hasReturnStatement
+            ? NodeFactory.returnStatementNode(expression)
+            : NodeFactory.expressionStatementNode(expression);
+
+        return {
+            leadingStatements,
+            trailingStatement: {
+                statement,
+                expression
+            },
+            hasReturnStatement
+        };
+    }
+
+    /**
+     * Iterates over `IfStatement` node body and collects data
+     *
+     * @param {ESTree.Statement | null | undefined} statementNode
+     * @returns {IIfStatementIteratedStatementsData}
+     */
+    private collectIteratedStatementsData (
+        statementNode: ESTree.BlockStatement
+    ): IIfStatementIteratedStatementsData {
         const statementNodeBodyLength: number = statementNode.body.length;
         const unwrappedExpressions: ESTree.Expression[] = [];
 
@@ -301,29 +343,47 @@ export class IfStatementSimplifyTransformer extends AbstractNodeTransformer {
             unwrappedExpressions.length = 0;
         }
 
-        if (startIndex === null || !unwrappedExpressions.length) {
-            return null;
-        }
+        return {
+            startIndex,
+            unwrappedExpressions,
+            hasReturnStatement
+        };
+    }
 
-        const hasSingleExpression: boolean = unwrappedExpressions.length === 1;
+    /**
+     * Returns leading statements for IIfStatementSimplifyData
+     *
+     * @param {ESTree.BlockStatement} statementNode
+     * @param {number | null} startIndex
+     * @returns {ESTree.Statement[]}
+     */
+    private getLeadingStatements (statementNode: ESTree.BlockStatement, startIndex: number | null): ESTree.Statement[] {
+        // variant #1: no valid statements inside `IfStatement` are found
+        if (startIndex === null) {
+            return statementNode.body;
+        }
 
-        const expression: ESTree.Expression = hasSingleExpression
-            ? unwrappedExpressions[0]
-            : NodeFactory.sequenceExpressionNode(unwrappedExpressions);
+        return startIndex === 0
+            // variant #2: all statements inside `IfStatement` branch are valid
+            ? []
+            // variant #3: only last N statements inside `IfStatement` branch are valid
+            : statementNode.body.slice(0, startIndex);
+    }
 
-        const leadingStatements: ESTree.Statement[] = startIndex > 0
-            ? statementNode.body.slice(0, startIndex)
-            : [];
-        const statement: ESTree.Statement = hasReturnStatement
-            ? NodeFactory.returnStatementNode(expression)
-            : NodeFactory.expressionStatementNode(expression);
+    /**
+     * @param {IIfStatementSimplifyData} ifStatementSimplifyData
+     * @returns {ESTree.BlockStatement}
+     */
+    private getPartialBlockStatementNode (ifStatementSimplifyData: IIfStatementSimplifyData): ESTree.Statement {
+        // variant #1: all statements inside `IfStatement` branch are valid
+        if (!ifStatementSimplifyData.leadingStatements.length && ifStatementSimplifyData.trailingStatement) {
+            return ifStatementSimplifyData.trailingStatement.statement;
+        }
 
-        return {
-            leadingStatements,
-            statement,
-            expression,
-            hasReturnStatement,
-            hasSingleExpression
-        };
+        // variant #2: only last N statements inside `IfStatement` branch are valid
+        return NodeFactory.blockStatementNode([
+            ...ifStatementSimplifyData.leadingStatements,
+            ...ifStatementSimplifyData.trailingStatement ? [ifStatementSimplifyData.trailingStatement.statement] : []
+        ]);
     }
 }

+ 5 - 6
test/functional-tests/node-transformers/minification-transformers/if-statement-simplify-transformer/IfStatementSimplifyTransformer.spec.ts

@@ -503,7 +503,7 @@ describe('IfStatementSimplifyTransformer', () => {
                 describe('Variant #3: mixed statements #1', () => {
                     const regExp: RegExp = new RegExp(
                         'if *\\(!!\\[]\\) *{ *' +
-                            'const *_0x([a-f0-9]){4,6} *= *baz\\(\\), *' +
+                            'const *_0x([a-f0-9]){4,6} *= *baz\\(\\); *' +
                         '} *else *{ *' +
                             'const *_0x([a-f0-9]){4,6} *= *hawk\\(\\); *' +
                             'eagle\\(\\), *dog\\(\\);' +
@@ -565,9 +565,9 @@ describe('IfStatementSimplifyTransformer', () => {
             describe('With consequent `ReturnStatement`', () => {
                 describe('Variant #1: single statement', () => {
                     const regExp: RegExp = new RegExp(
-                        'if *\\(!!\\[]\\) *{ *' +
+                        'if *\\(!!\\[]\\) *' +
                             'return *bar\\(\\); *' +
-                        '} *else *{ *' +
+                        'else *{ *' +
                             'const *_0x([a-f0-9]){4,6} *= *bark\\(\\); *' +
                         '}'
                     );
@@ -630,9 +630,8 @@ describe('IfStatementSimplifyTransformer', () => {
                     const regExp: RegExp = new RegExp(
                         'if *\\(!!\\[]\\) *{ *' +
                             'const *_0x([a-f0-9]){4,6} *= *baz\\(\\); *' +
-                        '} *else *{ *' +
-                            'return *bark\\(\\); *' +
-                        '}'
+                        '} *else *' +
+                            'return *bark\\(\\);'
                     );
 
 

Некоторые файлы не были показаны из-за большого количества измененных файлов