From 061bffe2c4ecc5609e00489eb5c35a93cfbe3166 Mon Sep 17 00:00:00 2001 From: sanex Date: Sun, 8 Aug 2021 23:56:45 +0300 Subject: [PATCH] Refactoring related to ArrayUtils, NodeMetadata and StringArray transformets --- .../AbstractStringArrayCallNode.ts | 4 +- src/declarations/ESTree.d.ts | 2 +- src/interfaces/utils/IArrayUtils.ts | 7 +++ .../SplitStringTransformer.ts | 25 +++----- .../MetadataTransformer.ts | 2 +- .../RenamePropertiesTransformer.ts | 25 ++++---- .../StringArrayTransformer.ts | 23 ++++--- src/node/NodeFactory.ts | 2 +- src/node/NodeMetadata.ts | 7 ++- .../VisitedLexicalScopeNodesStackStorage.ts | 4 +- src/utils/ArrayUtils.ts | 11 +++- .../node/node-metadata/NodeMetadata.spec.ts | 17 ++--- test/unit-tests/utils/ArrayUtils.spec.ts | 62 +++++++++++++++++++ 13 files changed, 137 insertions(+), 54 deletions(-) diff --git a/src/custom-nodes/string-array-nodes/AbstractStringArrayCallNode.ts b/src/custom-nodes/string-array-nodes/AbstractStringArrayCallNode.ts index eb56201b..72915e05 100644 --- a/src/custom-nodes/string-array-nodes/AbstractStringArrayCallNode.ts +++ b/src/custom-nodes/string-array-nodes/AbstractStringArrayCallNode.ts @@ -105,7 +105,7 @@ export abstract class AbstractStringArrayCallNode extends AbstractCustomNode { const stringArrayCallIndexNode: ESTree.Expression = this.stringArrayIndexNodeFactory(stringArrayIndexNodeName) .getNode(normalizedIndex); - NodeMetadata.set(stringArrayCallIndexNode, { replacedLiteral: true }); + NodeMetadata.set(stringArrayCallIndexNode, { stringArrayCallLiteralNode: true }); const hexadecimalNode: ESTree.Expression = isPositive ? stringArrayCallIndexNode @@ -126,7 +126,7 @@ export abstract class AbstractStringArrayCallNode extends AbstractCustomNode { protected getRc4KeyLiteralNode (decodeKey: string): ESTree.Literal { const rc4KeyLiteralNode: ESTree.Literal = NodeFactory.literalNode(decodeKey); - NodeMetadata.set(rc4KeyLiteralNode, { replacedLiteral: true }); + NodeMetadata.set(rc4KeyLiteralNode, { stringArrayCallLiteralNode: true }); return rc4KeyLiteralNode; } diff --git a/src/declarations/ESTree.d.ts b/src/declarations/ESTree.d.ts index 3254c127..252dfd76 100644 --- a/src/declarations/ESTree.d.ts +++ b/src/declarations/ESTree.d.ts @@ -14,7 +14,7 @@ declare module 'estree' { } export interface LiteralNodeMetadata extends BaseNodeMetadata { - replacedLiteral?: boolean; + stringArrayCallLiteralNode?: boolean; } /** diff --git a/src/interfaces/utils/IArrayUtils.ts b/src/interfaces/utils/IArrayUtils.ts index 86f52c9c..9394adc8 100644 --- a/src/interfaces/utils/IArrayUtils.ts +++ b/src/interfaces/utils/IArrayUtils.ts @@ -24,6 +24,13 @@ export interface IArrayUtils { */ getLastElement (array: T[]): T | undefined; + /** + * @param {T[]} array + * @param {number} index + * @returns {T | undefined} + */ + getLastElementByIndex (array: T[], index: number): T | undefined; + /** * @param array * @param times diff --git a/src/node-transformers/converting-transformers/SplitStringTransformer.ts b/src/node-transformers/converting-transformers/SplitStringTransformer.ts index 81ded683..8bf62e68 100644 --- a/src/node-transformers/converting-transformers/SplitStringTransformer.ts +++ b/src/node-transformers/converting-transformers/SplitStringTransformer.ts @@ -80,14 +80,14 @@ export class SplitStringTransformer extends AbstractNodeTransformer { * @returns {IVisitor | null} */ public getVisitor (nodeTransformationStage: NodeTransformationStage): IVisitor | null { + if (!this.options.splitStrings) { + return null; + } + switch (nodeTransformationStage) { case NodeTransformationStage.Converting: return { enter: (node: ESTree.Node, parentNode: ESTree.Node | null): ESTree.Node | undefined => { - if (!this.options.splitStrings) { - return; - } - if (parentNode && NodeGuards.isLiteralNode(node)) { return this.transformNode(node, parentNode); } @@ -115,7 +115,6 @@ export class SplitStringTransformer extends AbstractNodeTransformer { // pass #1: split string on a large chunks with length of `firstPassChunkLength` const firstPassChunksNode: ESTree.Node = this.transformLiteralNodeByChunkLength( literalNode, - parentNode, SplitStringTransformer.firstPassChunkLength ); @@ -123,28 +122,28 @@ export class SplitStringTransformer extends AbstractNodeTransformer { const secondPassChunksNode: ESTree.Node = estraverse.replace(firstPassChunksNode, { // eslint-disable-next-line @typescript-eslint/no-shadow enter: (node: ESTree.Node, parentNode: ESTree.Node | null) => { - if (parentNode && NodeGuards.isLiteralNode(node)) { + if (NodeGuards.isLiteralNode(node)) { return this.transformLiteralNodeByChunkLength( node, - parentNode, this.options.splitStringsChunkLength ); } } }); + NodeUtils.parentizeNode(secondPassChunksNode, parentNode); + NodeUtils.parentizeAst(secondPassChunksNode); + return secondPassChunksNode; } /** * @param {Literal} literalNode - * @param {Node} parentNode * @param {number} chunkLength * @returns {Node} */ private transformLiteralNodeByChunkLength ( literalNode: ESTree.Literal, - parentNode: ESTree.Node, chunkLength: number ): ESTree.Node { if (!NodeLiteralUtils.isStringLiteralNode(literalNode)) { @@ -163,13 +162,7 @@ export class SplitStringTransformer extends AbstractNodeTransformer { chunkLength ); - const binaryExpressionNode: ESTree.BinaryExpression = - this.transformStringChunksToBinaryExpressionNode(stringChunks); - - NodeUtils.parentizeAst(binaryExpressionNode); - NodeUtils.parentizeNode(binaryExpressionNode, parentNode); - - return binaryExpressionNode; + return this.transformStringChunksToBinaryExpressionNode(stringChunks); } /** diff --git a/src/node-transformers/preparing-transformers/MetadataTransformer.ts b/src/node-transformers/preparing-transformers/MetadataTransformer.ts index 6d97722d..0df45daf 100644 --- a/src/node-transformers/preparing-transformers/MetadataTransformer.ts +++ b/src/node-transformers/preparing-transformers/MetadataTransformer.ts @@ -65,7 +65,7 @@ export class MetadataTransformer extends AbstractNodeTransformer { NodeMetadata.set(node, { ignoredNode: false }); if (NodeGuards.isLiteralNode(node)) { - NodeMetadata.set(node, { replacedLiteral: false }); + NodeMetadata.set(node, { stringArrayCallLiteralNode: false }); } return node; diff --git a/src/node-transformers/rename-properties-transformers/RenamePropertiesTransformer.ts b/src/node-transformers/rename-properties-transformers/RenamePropertiesTransformer.ts index 1391acb6..1dcbfdb9 100644 --- a/src/node-transformers/rename-properties-transformers/RenamePropertiesTransformer.ts +++ b/src/node-transformers/rename-properties-transformers/RenamePropertiesTransformer.ts @@ -9,11 +9,12 @@ import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator'; import { IVisitor } from '../../interfaces/node-transformers/IVisitor'; import { NodeTransformationStage } from '../../enums/node-transformers/NodeTransformationStage'; +import { RenamePropertiesMode } from '../../enums/node-transformers/rename-properties-transformers/RenamePropertiesMode'; import { AbstractNodeTransformer } from '../AbstractNodeTransformer'; import { NodeGuards } from '../../node/NodeGuards'; import { NodeLiteralUtils } from '../../node/NodeLiteralUtils'; -import { RenamePropertiesMode } from '../../enums/node-transformers/rename-properties-transformers/RenamePropertiesMode'; +import { NodeUtils } from '../../node/NodeUtils'; @injectable() export class RenamePropertiesTransformer extends AbstractNodeTransformer { @@ -106,20 +107,20 @@ export class RenamePropertiesTransformer extends AbstractNodeTransformer { * @returns {Node} */ public transformNode (node: ESTree.Node, parentNode: ESTree.Node): ESTree.Node { + let propertyNode: ESTree.Node | null = null; + if (NodeGuards.isPropertyNode(node)) { - return this.transformPropertyNode(node); + propertyNode = this.transformPropertyNode(node); + } else if (NodeGuards.isPropertyDefinitionNode(node)) { + propertyNode = this.transformPropertyDefinitionNode(node); + } else if (NodeGuards.isMemberExpressionNode(node)) { + propertyNode = this.transformMemberExpressionNode(node); + } else if (NodeGuards.isMethodDefinitionNode(node)) { + propertyNode = this.transformMethodDefinitionNode(node); } - if (NodeGuards.isPropertyDefinitionNode(node)) { - return this.transformPropertyDefinitionNode(node); - } - - if (NodeGuards.isMemberExpressionNode(node)) { - return this.transformMemberExpressionNode(node); - } - - if (NodeGuards.isMethodDefinitionNode(node)) { - return this.transformMethodDefinitionNode(node); + if (propertyNode) { + NodeUtils.parentizeNode(propertyNode, parentNode); } return node; diff --git a/src/node-transformers/string-array-transformers/StringArrayTransformer.ts b/src/node-transformers/string-array-transformers/StringArrayTransformer.ts index 0ffabe75..747791f4 100644 --- a/src/node-transformers/string-array-transformers/StringArrayTransformer.ts +++ b/src/node-transformers/string-array-transformers/StringArrayTransformer.ts @@ -139,7 +139,11 @@ export class StringArrayTransformer extends AbstractNodeTransformer { this.prepareNode(node); } - if (parentNode && NodeGuards.isLiteralNode(node) && !NodeMetadata.isReplacedLiteral(node)) { + if ( + parentNode + && NodeGuards.isLiteralNode(node) + && !NodeMetadata.isStringArrayCallLiteralNode(node) + ) { return this.transformNode(node, parentNode); } } @@ -187,16 +191,19 @@ export class StringArrayTransformer extends AbstractNodeTransformer { const cacheKey: string = this.literalNodesCacheStorage.buildKey(literalValue, stringArrayStorageItemData); const useCachedValue: boolean = this.literalNodesCacheStorage.shouldUseCachedValue(cacheKey, stringArrayStorageItemData); + let resultNode: ESTree.Node; + if (useCachedValue) { - return this.literalNodesCacheStorage.get(cacheKey); + const nodeFromCache: ESTree.Node = this.literalNodesCacheStorage.get(cacheKey); + + resultNode = NodeUtils.clone(nodeFromCache); + } else { + resultNode = stringArrayStorageItemData + ? this.getStringArrayCallNode(stringArrayStorageItemData) + : literalNode; + this.literalNodesCacheStorage.set(cacheKey, resultNode); } - const resultNode: ESTree.Node = stringArrayStorageItemData - ? this.getStringArrayCallNode(stringArrayStorageItemData) - : literalNode; - - this.literalNodesCacheStorage.set(cacheKey, resultNode); - NodeUtils.parentizeNode(resultNode, parentNode); return resultNode; diff --git a/src/node/NodeFactory.ts b/src/node/NodeFactory.ts index 8c33e744..a759ff46 100644 --- a/src/node/NodeFactory.ts +++ b/src/node/NodeFactory.ts @@ -63,7 +63,7 @@ export class NodeFactory { public static binaryExpressionNode ( operator: ESTree.BinaryOperator, left: ESTree.Expression, - right: ESTree.Expression, + right: ESTree.Expression ): ESTree.BinaryExpression { return { type: NodeType.BinaryExpression, diff --git a/src/node/NodeMetadata.ts b/src/node/NodeMetadata.ts index 702165c5..acb1e7e4 100644 --- a/src/node/NodeMetadata.ts +++ b/src/node/NodeMetadata.ts @@ -43,7 +43,10 @@ export class NodeMetadata { * @param {Node} literalNode * @returns {boolean} */ - public static isReplacedLiteral (literalNode: ESTree.Literal): boolean { - return NodeMetadata.get(literalNode, 'replacedLiteral') === true; + public static isStringArrayCallLiteralNode (literalNode: ESTree.Literal): boolean { + return NodeMetadata.get< + ESTree.LiteralNodeMetadata, + 'stringArrayCallLiteralNode' + >(literalNode, 'stringArrayCallLiteralNode') === true; } } diff --git a/src/storages/string-array-transformers/VisitedLexicalScopeNodesStackStorage.ts b/src/storages/string-array-transformers/VisitedLexicalScopeNodesStackStorage.ts index b2b32550..80a5883e 100644 --- a/src/storages/string-array-transformers/VisitedLexicalScopeNodesStackStorage.ts +++ b/src/storages/string-array-transformers/VisitedLexicalScopeNodesStackStorage.ts @@ -43,9 +43,7 @@ export class VisitedLexicalScopeNodesStackStorage extends ArrayStorage (array: T[]): T | undefined { + return this.getLastElementByIndex(array, 0); + } + + /** + * @param {T[]} array + * @param {number} index + * @returns {T | undefined} + */ + public getLastElementByIndex (array: T[], index: number): T | undefined { const arrayLength: number = array.length; - return array[arrayLength - 1] ?? undefined; + return array[arrayLength - 1 - index] ?? undefined; } /** diff --git a/test/unit-tests/node/node-metadata/NodeMetadata.spec.ts b/test/unit-tests/node/node-metadata/NodeMetadata.spec.ts index ca0ddd29..c73a8436 100644 --- a/test/unit-tests/node/node-metadata/NodeMetadata.spec.ts +++ b/test/unit-tests/node/node-metadata/NodeMetadata.spec.ts @@ -11,7 +11,7 @@ describe('NodeMetadata', () => { describe('set', () => { const expectedMetadata: ESTree.LiteralNodeMetadata = { ignoredNode: true, - replacedLiteral: true + stringArrayCallLiteralNode: true }; let node: ESTree.Literal; @@ -20,7 +20,7 @@ describe('NodeMetadata', () => { node = NodeFactory.literalNode('foo'); NodeMetadata.set(node, { ignoredNode: true, - replacedLiteral: true + stringArrayCallLiteralNode: true }) }); @@ -38,8 +38,11 @@ describe('NodeMetadata', () => { before(() => { node = NodeFactory.literalNode('foo'); node.metadata = {}; - node.metadata.replacedLiteral = true; - value = NodeMetadata.get(node, 'replacedLiteral'); + node.metadata.stringArrayCallLiteralNode = true; + value = NodeMetadata.get< + ESTree.LiteralNodeMetadata, + 'stringArrayCallLiteralNode' + >(node, 'stringArrayCallLiteralNode'); }); it('should get metadata value of the node', () => { @@ -83,7 +86,7 @@ describe('NodeMetadata', () => { }); }); - describe('isReplacedLiteral', () => { + describe('isStringArrayCallLiteralNode', () => { const expectedValue: boolean = true; let node: ESTree.Literal, @@ -92,8 +95,8 @@ describe('NodeMetadata', () => { before(() => { node = NodeFactory.literalNode('foo'); node.metadata = {}; - node.metadata.replacedLiteral = true; - value = NodeMetadata.isReplacedLiteral(node); + node.metadata.stringArrayCallLiteralNode = true; + value = NodeMetadata.isStringArrayCallLiteralNode(node); }); it('should return metadata value', () => { diff --git a/test/unit-tests/utils/ArrayUtils.spec.ts b/test/unit-tests/utils/ArrayUtils.spec.ts index e5ba41d1..0d8d1419 100644 --- a/test/unit-tests/utils/ArrayUtils.spec.ts +++ b/test/unit-tests/utils/ArrayUtils.spec.ts @@ -215,6 +215,68 @@ describe('ArrayUtils', () => { }); }); + describe('getLastElementByIndex', () => { + describe('empty array', () => { + const array: string[] = []; + const expectedLastElement: undefined = undefined; + + let lastElement: string | undefined; + + before(() => { + lastElement = arrayUtils.getLastElementByIndex(array, 1); + }); + + it('should return undefined if array is empty', () => { + assert.equal(lastElement, expectedLastElement); + }); + }); + + describe('array length: `1` and index is out of array boundary', () => { + const array: string[] = ['foo']; + const expectedLastElement: undefined = undefined; + + let lastElement: string | undefined; + + before(() => { + lastElement = arrayUtils.getLastElementByIndex(array, 2); + }); + + it('should return undefined', () => { + assert.equal(lastElement, expectedLastElement); + }); + }); + + describe('array length: `3` and index is `0`', () => { + const array: string[] = ['foo', 'bar', 'baz']; + const expectedLastElement: string = 'baz'; + + let lastElement: string | undefined; + + before(() => { + lastElement = arrayUtils.getLastElementByIndex(array, 0); + }); + + it('should return element with a correct index', () => { + assert.equal(lastElement, expectedLastElement); + }); + }); + + describe('array length: `3` and index is `1`', () => { + const array: string[] = ['foo', 'bar', 'baz']; + const expectedLastElement: string = 'bar'; + + let lastElement: string | undefined; + + before(() => { + lastElement = arrayUtils.getLastElementByIndex(array, 1); + }); + + it('should return element with a correct index', () => { + assert.equal(lastElement, expectedLastElement); + }); + }); + }); + describe('rotate', () => { let array: number[], rotatedArray: number[];