mirror of
https://github.com/javascript-obfuscator/javascript-obfuscator
synced 2026-08-09 12:42:29 +00:00
Merge pull request #520 from javascript-obfuscator/object-expression-keys-transformer-rework
Object expression keys transformer rework
This commit is contained in:
@@ -6,6 +6,7 @@ v0.24.0
|
||||
* Dynamic import and `import.meta` support. Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/505
|
||||
* Now usage of some browser-related options with `target: 'node'` will cause a validation error
|
||||
* **CLI:** a file path will be displayed on obfuscation error. Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/513
|
||||
* Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/516
|
||||
* Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/512
|
||||
* Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/496
|
||||
* **Internal:** switched from `awesome-typescript-loader` on `ts-loader`
|
||||
|
||||
Vendored
+6
-6
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "javascript-obfuscator",
|
||||
"version": "0.24.0-rc.0",
|
||||
"version": "0.24.0-rc.1",
|
||||
"description": "JavaScript obfuscator",
|
||||
"keywords": [
|
||||
"obfuscator",
|
||||
|
||||
@@ -12,6 +12,7 @@ import { IStringArrayStorageItemData } from '../../interfaces/storages/string-ar
|
||||
|
||||
import { NodeGuards } from '../../node/NodeGuards';
|
||||
import { NodeMetadata } from '../../node/NodeMetadata';
|
||||
import { NodeLiteralUtils } from '../../node/NodeLiteralUtils';
|
||||
|
||||
/**
|
||||
* Adds values of literal nodes to the string array storage
|
||||
@@ -67,7 +68,11 @@ export class StringArrayStorageAnalyzer implements IStringArrayStorageAnalyzer {
|
||||
}
|
||||
|
||||
estraverse.traverse(astTree, {
|
||||
enter: (node: ESTree.Node): estraverse.VisitorOption | void => {
|
||||
enter: (node: ESTree.Node, parentNode: ESTree.Node | null): estraverse.VisitorOption | void => {
|
||||
if (!parentNode) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (NodeMetadata.isIgnoredNode(node)) {
|
||||
return estraverse.VisitorOption.Skip;
|
||||
}
|
||||
@@ -76,7 +81,7 @@ export class StringArrayStorageAnalyzer implements IStringArrayStorageAnalyzer {
|
||||
return;
|
||||
}
|
||||
|
||||
this.analyzeLiteralNode(node);
|
||||
this.analyzeLiteralNode(node, parentNode);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -91,12 +96,17 @@ export class StringArrayStorageAnalyzer implements IStringArrayStorageAnalyzer {
|
||||
|
||||
/**
|
||||
* @param {Literal} literalNode
|
||||
* @param {Node} parentNode
|
||||
*/
|
||||
private analyzeLiteralNode (literalNode: ESTree.Literal): void {
|
||||
private analyzeLiteralNode (literalNode: ESTree.Literal, parentNode: ESTree.Node): void {
|
||||
if (typeof literalNode.value !== 'string') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (NodeLiteralUtils.isProhibitedLiteralNode(literalNode, parentNode)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.shouldAddValueToStringArray(literalNode.value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ export enum ServiceIdentifiers {
|
||||
Factory__IObfuscatedCode = 'Factory<IObfuscatedCode>',
|
||||
Factory__IObfuscatingReplacer = 'Factory<IObfuscatingReplacer>',
|
||||
Factory__IObjectExpressionKeysTransformerCustomNode = 'Factory<IObjectExpressionKeysTransformerCustomNode>',
|
||||
Factory__IPropertiesExtractor = 'Factory<IPropertiesExtractor>',
|
||||
Factory__IObjectExpressionExtractor = 'Factory<IObjectExpressionExtractor>',
|
||||
Factory__TControlFlowStorage = 'Factory<TControlFlowStorage>',
|
||||
IArrayUtils = 'IArrayUtils',
|
||||
ICalleeDataExtractor = 'ICalleeDataExtractor',
|
||||
@@ -37,7 +37,7 @@ export enum ServiceIdentifiers {
|
||||
IOptionsNormalizer = 'IOptionsNormalizer',
|
||||
IObfuscatingReplacer = 'IObfuscatingReplacer',
|
||||
IPrevailingKindOfVariablesAnalyzer = 'IPrevailingKindOfVariablesAnalyzer',
|
||||
IPropertiesExtractor = 'IPropertiesExtractor',
|
||||
IObjectExpressionExtractor = 'IObjectExpressionExtractor',
|
||||
IRandomGenerator = 'IRandomGenerator',
|
||||
ISourceCode = 'ISourceCode',
|
||||
ISourceMapCorrector = 'ISourceMapCorrector',
|
||||
|
||||
@@ -18,7 +18,7 @@ import { DomainLockCustomNodeGroup } from '../../../custom-nodes/domain-lock-nod
|
||||
import { SelfDefendingCustomNodeGroup } from '../../../custom-nodes/self-defending-nodes/group/SelfDefendingCustomNodeGroup';
|
||||
import { StringArrayCustomNodeGroup } from '../../../custom-nodes/string-array-nodes/group/StringArrayCustomNodeGroup';
|
||||
|
||||
import { BasePropertiesExtractorObjectExpressionHostNode } from '../../../custom-nodes/object-expression-keys-transformer-nodes/BasePropertiesExtractorObjectExpressionHostNode';
|
||||
import { ObjectExpressionVariableDeclarationHostNode } from '../../../custom-nodes/object-expression-keys-transformer-nodes/ObjectExpressionVariableDeclarationHostNode';
|
||||
import { BinaryExpressionFunctionNode } from '../../../custom-nodes/control-flow-flattening-nodes/BinaryExpressionFunctionNode';
|
||||
import { BlockStatementControlFlowFlatteningNode } from '../../../custom-nodes/control-flow-flattening-nodes/BlockStatementControlFlowFlatteningNode';
|
||||
import { BlockStatementDeadCodeInjectionNode } from '../../../custom-nodes/dead-code-injection-nodes/BlockStatementDeadCodeInjectionNode';
|
||||
@@ -127,8 +127,8 @@ export const customNodesModule: interfaces.ContainerModule = new ContainerModule
|
||||
|
||||
// object expression keys transformer nodes
|
||||
bind<interfaces.Newable<ICustomNode>>(ServiceIdentifiers.Newable__ICustomNode)
|
||||
.toConstructor(BasePropertiesExtractorObjectExpressionHostNode)
|
||||
.whenTargetNamed(ObjectExpressionKeysTransformerCustomNode.BasePropertiesExtractorObjectExpressionHostNode);
|
||||
.toConstructor(ObjectExpressionVariableDeclarationHostNode)
|
||||
.whenTargetNamed(ObjectExpressionKeysTransformerCustomNode.ObjectExpressionVariableDeclarationHostNode);
|
||||
|
||||
// node groups
|
||||
bind<ICustomNodeGroup>(ServiceIdentifiers.ICustomNodeGroup)
|
||||
|
||||
@@ -3,20 +3,19 @@ import { InversifyContainerFacade } from '../../InversifyContainerFacade';
|
||||
import { ServiceIdentifiers } from '../../ServiceIdentifiers';
|
||||
|
||||
import { INodeTransformer } from '../../../interfaces/node-transformers/INodeTransformer';
|
||||
import { IPropertiesExtractor } from '../../../interfaces/node-transformers/converting-transformers/properties-extractors/IPropertiesExtractor';
|
||||
import { IObjectExpressionExtractor } from '../../../interfaces/node-transformers/converting-transformers/object-expression-extractors/IObjectExpressionExtractor';
|
||||
|
||||
import { NodeTransformer } from '../../../enums/node-transformers/NodeTransformer';
|
||||
import { PropertiesExtractor } from '../../../enums/node-transformers/converting-transformers/properties-extractors/PropertiesExtractor';
|
||||
import { ObjectExpressionExtractor } from '../../../enums/node-transformers/converting-transformers/properties-extractors/ObjectExpressionExtractor';
|
||||
|
||||
import { AssignmentExpressionPropertiesExtractor } from '../../../node-transformers/converting-transformers/properties-extractors/AssignmentExpressionPropertiesExtractor';
|
||||
import { BasePropertiesExtractor } from '../../../node-transformers/converting-transformers/properties-extractors/BasePropertiesExtractor';
|
||||
import { ObjectExpressionToVariableDeclarationExtractor } from '../../../node-transformers/converting-transformers/object-expression-extractors/ObjectExpressionToVariableDeclarationExtractor';
|
||||
import { MemberExpressionTransformer } from '../../../node-transformers/converting-transformers/MemberExpressionTransformer';
|
||||
import { MethodDefinitionTransformer } from '../../../node-transformers/converting-transformers/MethodDefinitionTransformer';
|
||||
import { ObjectExpressionKeysTransformer } from '../../../node-transformers/converting-transformers/ObjectExpressionKeysTransformer';
|
||||
import { ObjectExpressionTransformer } from '../../../node-transformers/converting-transformers/ObjectExpressionTransformer';
|
||||
import { SplitStringTransformer } from '../../../node-transformers/converting-transformers/SplitStringTransformer';
|
||||
import { TemplateLiteralTransformer } from '../../../node-transformers/converting-transformers/TemplateLiteralTransformer';
|
||||
import { VariableDeclaratorPropertiesExtractor } from '../../../node-transformers/converting-transformers/properties-extractors/VariableDeclaratorPropertiesExtractor';
|
||||
import { BasePropertiesExtractor } from '../../../node-transformers/converting-transformers/object-expression-extractors/BasePropertiesExtractor';
|
||||
|
||||
export const convertingTransformersModule: interfaces.ContainerModule = new ContainerModule((bind: interfaces.Bind) => {
|
||||
// converting transformers
|
||||
@@ -44,23 +43,19 @@ export const convertingTransformersModule: interfaces.ContainerModule = new Cont
|
||||
.to(TemplateLiteralTransformer)
|
||||
.whenTargetNamed(NodeTransformer.TemplateLiteralTransformer);
|
||||
|
||||
// properties extractors
|
||||
bind<IPropertiesExtractor>(ServiceIdentifiers.IPropertiesExtractor)
|
||||
.to(AssignmentExpressionPropertiesExtractor)
|
||||
.whenTargetNamed(PropertiesExtractor.AssignmentExpressionPropertiesExtractor);
|
||||
// object expression extractors
|
||||
bind<IObjectExpressionExtractor>(ServiceIdentifiers.IObjectExpressionExtractor)
|
||||
.to(ObjectExpressionToVariableDeclarationExtractor)
|
||||
.whenTargetNamed(ObjectExpressionExtractor.ObjectExpressionToVariableDeclarationExtractor);
|
||||
|
||||
bind<IPropertiesExtractor>(ServiceIdentifiers.IPropertiesExtractor)
|
||||
bind<IObjectExpressionExtractor>(ServiceIdentifiers.IObjectExpressionExtractor)
|
||||
.to(BasePropertiesExtractor)
|
||||
.whenTargetNamed(PropertiesExtractor.BasePropertiesExtractor);
|
||||
.whenTargetNamed(ObjectExpressionExtractor.BasePropertiesExtractor);
|
||||
|
||||
bind<IPropertiesExtractor>(ServiceIdentifiers.IPropertiesExtractor)
|
||||
.to(VariableDeclaratorPropertiesExtractor)
|
||||
.whenTargetNamed(PropertiesExtractor.VariableDeclaratorPropertiesExtractor);
|
||||
|
||||
// properties extractor factory
|
||||
bind<IPropertiesExtractor>(ServiceIdentifiers.Factory__IPropertiesExtractor)
|
||||
.toFactory<IPropertiesExtractor>(InversifyContainerFacade
|
||||
.getCacheFactory<PropertiesExtractor, IPropertiesExtractor>(
|
||||
ServiceIdentifiers.IPropertiesExtractor
|
||||
// object expression extractor factory
|
||||
bind<IObjectExpressionExtractor>(ServiceIdentifiers.Factory__IObjectExpressionExtractor)
|
||||
.toFactory<IObjectExpressionExtractor>(InversifyContainerFacade
|
||||
.getCacheFactory<ObjectExpressionExtractor, IObjectExpressionExtractor>(
|
||||
ServiceIdentifiers.IObjectExpressionExtractor
|
||||
));
|
||||
});
|
||||
|
||||
+12
-3
@@ -1,6 +1,8 @@
|
||||
import { inject, injectable, } from 'inversify';
|
||||
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
|
||||
|
||||
import * as ESTree from 'estree';
|
||||
|
||||
import { TIdentifierNamesGeneratorFactory } from '../../types/container/generators/TIdentifierNamesGeneratorFactory';
|
||||
import { TStatement } from '../../types/node/TStatement';
|
||||
|
||||
@@ -12,7 +14,12 @@ import { AbstractCustomNode } from '../AbstractCustomNode';
|
||||
import { NodeFactory } from '../../node/NodeFactory';
|
||||
|
||||
@injectable()
|
||||
export class BasePropertiesExtractorObjectExpressionHostNode extends AbstractCustomNode {
|
||||
export class ObjectExpressionVariableDeclarationHostNode extends AbstractCustomNode {
|
||||
/**
|
||||
* @ type {Property}
|
||||
*/
|
||||
private properties!: ESTree.Property[];
|
||||
|
||||
/**
|
||||
* @param {TIdentifierNamesGeneratorFactory} identifierNamesGeneratorFactory
|
||||
* @param {ICustomNodeFormatter} customNodeFormatter
|
||||
@@ -29,7 +36,9 @@ export class BasePropertiesExtractorObjectExpressionHostNode extends AbstractCus
|
||||
super(identifierNamesGeneratorFactory, customNodeFormatter, randomGenerator, options);
|
||||
}
|
||||
|
||||
public initialize (): void {}
|
||||
public initialize (properties: ESTree.Property[]): void {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} nodeTemplate
|
||||
@@ -42,7 +51,7 @@ export class BasePropertiesExtractorObjectExpressionHostNode extends AbstractCus
|
||||
NodeFactory.identifierNode(
|
||||
this.identifierNamesGenerator.generate()
|
||||
),
|
||||
NodeFactory.objectExpressionNode([])
|
||||
NodeFactory.objectExpressionNode(this.properties)
|
||||
)
|
||||
],
|
||||
'const'
|
||||
@@ -1,4 +1,4 @@
|
||||
export enum ObjectExpressionKeysTransformerCustomNode {
|
||||
BasePropertiesExtractorObjectExpressionHostNode =
|
||||
'BasePropertiesExtractorObjectExpressionHostNode'
|
||||
ObjectExpressionVariableDeclarationHostNode =
|
||||
'ObjectExpressionVariableDeclarationHostNode'
|
||||
}
|
||||
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
export enum ObjectExpressionExtractor {
|
||||
BasePropertiesExtractor = 'BasePropertiesExtractor',
|
||||
ObjectExpressionToVariableDeclarationExtractor = 'ObjectExpressionToVariableDeclarationExtractor'
|
||||
}
|
||||
-5
@@ -1,5 +0,0 @@
|
||||
export enum PropertiesExtractor {
|
||||
AssignmentExpressionPropertiesExtractor = 'AssignmentExpressionPropertiesExtractor',
|
||||
BasePropertiesExtractor = 'BasePropertiesExtractor',
|
||||
VariableDeclaratorPropertiesExtractor = 'VariableDeclaratorPropertiesExtractor'
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
import * as ESTree from 'estree';
|
||||
|
||||
import { IObjectExpressionExtractorResult } from './IObjectExpressionExtractorResult';
|
||||
|
||||
export interface IObjectExpressionExtractor {
|
||||
/**
|
||||
* @param {ObjectExpression} objectExpressionNode
|
||||
* @param {Statement} hostStatement
|
||||
* @returns {IObjectExpressionExtractorResult}
|
||||
*/
|
||||
extract (
|
||||
objectExpressionNode: ESTree.ObjectExpression,
|
||||
hostStatement: ESTree.Statement
|
||||
): IObjectExpressionExtractorResult;
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
import * as ESTree from 'estree';
|
||||
|
||||
export interface IObjectExpressionExtractorResult {
|
||||
/**
|
||||
* @type {Node}
|
||||
*/
|
||||
nodeToReplace: ESTree.Node;
|
||||
|
||||
/**
|
||||
* @type {Statement}
|
||||
*/
|
||||
objectExpressionHostStatement: ESTree.Statement;
|
||||
|
||||
/**
|
||||
* @type {ObjectExpression}
|
||||
*/
|
||||
objectExpressionNode: ESTree.ObjectExpression;
|
||||
}
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
import * as ESTree from 'estree';
|
||||
|
||||
export interface IPropertiesExtractor {
|
||||
/**
|
||||
* @param {ObjectExpression} objectExpressionNode
|
||||
* @param {Node} hostNode
|
||||
* @returns {Node}
|
||||
*/
|
||||
extract (
|
||||
objectExpressionNode: ESTree.ObjectExpression,
|
||||
hostNode: ESTree.Node
|
||||
): ESTree.Node;
|
||||
}
|
||||
@@ -1,51 +1,164 @@
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
|
||||
|
||||
import * as estraverse from 'estraverse';
|
||||
import * as ESTree from 'estree';
|
||||
|
||||
import { TPropertiesExtractorFactory } from '../../types/container/node-transformers/TPropertiesExtractorFactory';
|
||||
import { TObjectExpressionExtractorFactory } from '../../types/container/node-transformers/TObjectExpressionExtractorFactory';
|
||||
|
||||
import { IOptions } from '../../interfaces/options/IOptions';
|
||||
import { IPropertiesExtractor } from '../../interfaces/node-transformers/converting-transformers/properties-extractors/IPropertiesExtractor';
|
||||
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
|
||||
import { IVisitor } from '../../interfaces/node-transformers/IVisitor';
|
||||
|
||||
import { NodeType } from '../../enums/node/NodeType';
|
||||
import { PropertiesExtractor } from '../../enums/node-transformers/converting-transformers/properties-extractors/PropertiesExtractor';
|
||||
import { TransformationStage } from '../../enums/node-transformers/TransformationStage';
|
||||
|
||||
import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
|
||||
import { NodeGuards } from '../../node/NodeGuards';
|
||||
import { NodeStatementUtils } from '../../node/NodeStatementUtils';
|
||||
import { ObjectExpressionExtractor } from '../../enums/node-transformers/converting-transformers/properties-extractors/ObjectExpressionExtractor';
|
||||
|
||||
@injectable()
|
||||
export class ObjectExpressionKeysTransformer extends AbstractNodeTransformer {
|
||||
/**
|
||||
* @type {Map<string, PropertiesExtractor>}
|
||||
* @type {ObjectExpressionExtractor[]}
|
||||
*/
|
||||
private static readonly propertiesExtractorsMap: Map <string, PropertiesExtractor> = new Map([
|
||||
[NodeType.AssignmentExpression, PropertiesExtractor.AssignmentExpressionPropertiesExtractor],
|
||||
[NodeType.VariableDeclarator, PropertiesExtractor.VariableDeclaratorPropertiesExtractor]
|
||||
]);
|
||||
private static readonly objectExpressionExtractorNames: ObjectExpressionExtractor[] = [
|
||||
ObjectExpressionExtractor.ObjectExpressionToVariableDeclarationExtractor,
|
||||
ObjectExpressionExtractor.BasePropertiesExtractor
|
||||
];
|
||||
|
||||
/**
|
||||
* @type {TPropertiesExtractorFactory}
|
||||
* @type {TObjectExpressionExtractorFactory}
|
||||
*/
|
||||
private readonly propertiesExtractorFactory: TPropertiesExtractorFactory;
|
||||
private readonly objectExpressionExtractorFactory: TObjectExpressionExtractorFactory;
|
||||
|
||||
/**
|
||||
* @param {TPropertiesExtractorFactory} propertiesExtractorFactory
|
||||
* @param {TObjectExpressionExtractorFactory} objectExpressionExtractorFactory
|
||||
* @param {IRandomGenerator} randomGenerator
|
||||
* @param {IOptions} options
|
||||
*/
|
||||
constructor (
|
||||
@inject(ServiceIdentifiers.Factory__IPropertiesExtractor)
|
||||
propertiesExtractorFactory: TPropertiesExtractorFactory,
|
||||
@inject(ServiceIdentifiers.Factory__IObjectExpressionExtractor)
|
||||
objectExpressionExtractorFactory: TObjectExpressionExtractorFactory,
|
||||
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
|
||||
@inject(ServiceIdentifiers.IOptions) options: IOptions
|
||||
) {
|
||||
super(randomGenerator, options);
|
||||
|
||||
this.propertiesExtractorFactory = propertiesExtractorFactory;
|
||||
this.objectExpressionExtractorFactory = objectExpressionExtractorFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ObjectExpression} objectExpressionNode
|
||||
* @param {Statement} hostStatement
|
||||
* @returns {boolean}
|
||||
*/
|
||||
private static isProhibitedHostStatement (
|
||||
objectExpressionNode: ESTree.ObjectExpression,
|
||||
hostStatement: ESTree.Statement
|
||||
): boolean {
|
||||
return ObjectExpressionKeysTransformer.isProhibitedVariableDeclarationHostStatement(objectExpressionNode, hostStatement)
|
||||
|| ObjectExpressionKeysTransformer.isProhibitedFunctionHostStatement(objectExpressionNode, hostStatement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix of https://github.com/javascript-obfuscator/javascript-obfuscator/issues/516
|
||||
* If object expression is placed inside any expression inside variable declaration with 2+ declarators
|
||||
* - should mark host node as prohibited
|
||||
*
|
||||
* @param {ObjectExpression} objectExpressionNode
|
||||
* @param {Statement} hostStatement
|
||||
* @returns {boolean}
|
||||
*/
|
||||
private static isProhibitedVariableDeclarationHostStatement (
|
||||
objectExpressionNode: ESTree.ObjectExpression,
|
||||
hostStatement: ESTree.Statement
|
||||
): boolean {
|
||||
if (!NodeGuards.isVariableDeclarationNode(hostStatement) || !hostStatement.declarations.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ObjectExpressionKeysTransformer.isReferencedIdentifierName(
|
||||
objectExpressionNode,
|
||||
hostStatement.declarations
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ObjectExpression} objectExpressionNode
|
||||
* @param {Statement} hostStatement
|
||||
* @returns {boolean}
|
||||
*/
|
||||
private static isProhibitedFunctionHostStatement (
|
||||
objectExpressionNode: ESTree.ObjectExpression,
|
||||
hostStatement: ESTree.Statement
|
||||
): boolean {
|
||||
if (!NodeGuards.isFunctionNode(hostStatement) || !hostStatement.params.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const hostNode: ESTree.Node | undefined = objectExpressionNode.parentNode;
|
||||
|
||||
if (!hostNode || !NodeGuards.isAssignmentPatternNode(hostNode)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ObjectExpressionKeysTransformer.isReferencedIdentifierName(
|
||||
objectExpressionNode,
|
||||
hostStatement.params
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ObjectExpression} objectExpressionNode
|
||||
* @param {Node[]} nodesToSearch
|
||||
* @returns {boolean}
|
||||
*/
|
||||
private static isReferencedIdentifierName (
|
||||
objectExpressionNode: ESTree.ObjectExpression,
|
||||
nodesToSearch: ESTree.Node[],
|
||||
): boolean {
|
||||
if (nodesToSearch.length === 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const identifierNamesSet: string[] = [];
|
||||
|
||||
let isReferencedIdentifierName: boolean = false;
|
||||
let isCurrentNode: boolean = false;
|
||||
|
||||
// should mark node as prohibited if identifier of node is referenced somewhere inside other nodes
|
||||
for (const nodeToSearch of nodesToSearch) {
|
||||
const identifierNamesSetForCurrentNode: string[] = [];
|
||||
|
||||
estraverse.traverse(nodeToSearch, {
|
||||
enter: (node: ESTree.Node): void | estraverse.VisitorOption => {
|
||||
if (node === objectExpressionNode) {
|
||||
isCurrentNode = true;
|
||||
}
|
||||
|
||||
if (!NodeGuards.isIdentifierNode(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isCurrentNode) {
|
||||
identifierNamesSetForCurrentNode.push(node.name);
|
||||
} else if (identifierNamesSet.includes(node.name)) {
|
||||
isReferencedIdentifierName = true;
|
||||
|
||||
return estraverse.VisitorOption.Break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (isCurrentNode || isReferencedIdentifierName) {
|
||||
break;
|
||||
} else {
|
||||
identifierNamesSet.push(...identifierNamesSetForCurrentNode);
|
||||
}
|
||||
}
|
||||
|
||||
return isReferencedIdentifierName;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,28 +170,22 @@ export class ObjectExpressionKeysTransformer extends AbstractNodeTransformer {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (transformationStage !== TransformationStage.Converting) {
|
||||
return null;
|
||||
}
|
||||
switch (transformationStage) {
|
||||
case TransformationStage.Converting:
|
||||
return {
|
||||
leave: (node: ESTree.Node, parentNode: ESTree.Node | null) => {
|
||||
if (
|
||||
parentNode
|
||||
&& NodeGuards.isObjectExpressionNode(node)
|
||||
) {
|
||||
return this.transformNode(node, parentNode);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
enter: (node: ESTree.Node, parentNode: ESTree.Node | null) => {
|
||||
if (
|
||||
parentNode
|
||||
&& NodeGuards.isObjectExpressionNode(node)
|
||||
) {
|
||||
return this.transformNode(node, parentNode);
|
||||
}
|
||||
},
|
||||
leave: (node: ESTree.Node, parentNode: ESTree.Node | null) => {
|
||||
if (
|
||||
parentNode
|
||||
&& NodeGuards.isObjectExpressionNode(node)
|
||||
) {
|
||||
return this.transformNodeWithBaseExtractor(node, parentNode);
|
||||
}
|
||||
}
|
||||
};
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -89,9 +196,10 @@ export class ObjectExpressionKeysTransformer extends AbstractNodeTransformer {
|
||||
* };
|
||||
*
|
||||
* on:
|
||||
* var object = {};
|
||||
* object['foo'] = 1;
|
||||
* object['bar'] = 2;
|
||||
* var _0xabc123 = {};
|
||||
* _0xabc123['foo'] = 1;
|
||||
* _0xabc123['bar'] = 2;
|
||||
* var object = _0xabc123;
|
||||
*
|
||||
* @param {ObjectExpression} objectExpressionNode
|
||||
* @param {Node} parentNode
|
||||
@@ -102,43 +210,51 @@ export class ObjectExpressionKeysTransformer extends AbstractNodeTransformer {
|
||||
return objectExpressionNode;
|
||||
}
|
||||
|
||||
const propertiesExtractorName: PropertiesExtractor | undefined = ObjectExpressionKeysTransformer
|
||||
.propertiesExtractorsMap
|
||||
.get(parentNode.type);
|
||||
const hostStatement: ESTree.Statement = NodeStatementUtils.getRootStatementOfNode(objectExpressionNode);
|
||||
|
||||
if (!propertiesExtractorName) {
|
||||
if (ObjectExpressionKeysTransformer.isProhibitedHostStatement(objectExpressionNode, hostStatement)) {
|
||||
return objectExpressionNode;
|
||||
}
|
||||
|
||||
const propertiesExtractor: IPropertiesExtractor = this.propertiesExtractorFactory(propertiesExtractorName);
|
||||
|
||||
return propertiesExtractor.extract(objectExpressionNode, parentNode);
|
||||
return this.applyObjectExpressionKeysExtractorsRecursive(
|
||||
ObjectExpressionKeysTransformer.objectExpressionExtractorNames,
|
||||
objectExpressionNode,
|
||||
hostStatement
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* replaces:
|
||||
* return {
|
||||
* foo: 1,
|
||||
* bar: 2
|
||||
* };
|
||||
*
|
||||
* on:
|
||||
* var object = {};
|
||||
* object['foo'] = 1;
|
||||
* object['bar'] = 2;
|
||||
* return object;
|
||||
*
|
||||
* @param {ObjectExpressionExtractor[]} objectExpressionExtractorNames
|
||||
* @param {ObjectExpression} objectExpressionNode
|
||||
* @param {Node} parentNode
|
||||
* @returns {NodeGuards}
|
||||
* @param {Statement} hostStatement
|
||||
* @returns {Node}
|
||||
*/
|
||||
public transformNodeWithBaseExtractor (objectExpressionNode: ESTree.ObjectExpression, parentNode: ESTree.Node): ESTree.Node {
|
||||
if (!objectExpressionNode.properties.length) {
|
||||
private applyObjectExpressionKeysExtractorsRecursive (
|
||||
objectExpressionExtractorNames: ObjectExpressionExtractor[],
|
||||
objectExpressionNode: ESTree.ObjectExpression,
|
||||
hostStatement: ESTree.Statement
|
||||
): ESTree.Node {
|
||||
const newObjectExpressionExtractorNames: ObjectExpressionExtractor[] = [...objectExpressionExtractorNames];
|
||||
const objectExpressionExtractor: ObjectExpressionExtractor | undefined =
|
||||
newObjectExpressionExtractorNames.shift();
|
||||
|
||||
if (!objectExpressionExtractor) {
|
||||
return objectExpressionNode;
|
||||
}
|
||||
|
||||
const propertiesExtractor: IPropertiesExtractor = this.propertiesExtractorFactory(PropertiesExtractor.BasePropertiesExtractor);
|
||||
const {
|
||||
nodeToReplace,
|
||||
objectExpressionHostStatement: newObjectExpressionHostStatement,
|
||||
objectExpressionNode: newObjectExpressionNode
|
||||
} = this.objectExpressionExtractorFactory(objectExpressionExtractor)
|
||||
.extract(objectExpressionNode, hostStatement);
|
||||
|
||||
return propertiesExtractor.extract(objectExpressionNode, parentNode);
|
||||
this.applyObjectExpressionKeysExtractorsRecursive(
|
||||
newObjectExpressionExtractorNames,
|
||||
newObjectExpressionNode,
|
||||
newObjectExpressionHostStatement
|
||||
);
|
||||
|
||||
return nodeToReplace;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@ import { TransformationStage } from '../../enums/node-transformers/Transformatio
|
||||
import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
|
||||
import { NodeFactory } from '../../node/NodeFactory';
|
||||
import { NodeGuards } from '../../node/NodeGuards';
|
||||
import { IEscapeSequenceEncoder } from '../../interfaces/utils/IEscapeSequenceEncoder';
|
||||
|
||||
/**
|
||||
* replaces:
|
||||
@@ -24,23 +23,14 @@ import { IEscapeSequenceEncoder } from '../../interfaces/utils/IEscapeSequenceEn
|
||||
@injectable()
|
||||
export class ObjectExpressionTransformer extends AbstractNodeTransformer {
|
||||
/**
|
||||
* @type {IEscapeSequenceEncoder}
|
||||
*/
|
||||
private readonly escapeSequenceEncoder: IEscapeSequenceEncoder;
|
||||
|
||||
/**
|
||||
* @param {IEscapeSequenceEncoder} escapeSequenceEncoder
|
||||
* @param {IRandomGenerator} randomGenerator
|
||||
* @param {IOptions} options
|
||||
*/
|
||||
constructor (
|
||||
@inject(ServiceIdentifiers.IEscapeSequenceEncoder) escapeSequenceEncoder: IEscapeSequenceEncoder,
|
||||
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
|
||||
@inject(ServiceIdentifiers.IOptions) options: IOptions
|
||||
) {
|
||||
super(randomGenerator, options);
|
||||
|
||||
this.escapeSequenceEncoder = escapeSequenceEncoder;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -93,7 +83,7 @@ export class ObjectExpressionTransformer extends AbstractNodeTransformer {
|
||||
return;
|
||||
}
|
||||
|
||||
property.key = NodeFactory.literalNode(this.getPropertyKeyValue(property.key.value));
|
||||
property.key = NodeFactory.literalNode(property.key.value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -108,16 +98,6 @@ export class ObjectExpressionTransformer extends AbstractNodeTransformer {
|
||||
return;
|
||||
}
|
||||
|
||||
property.key = NodeFactory.literalNode(this.getPropertyKeyValue(property.key.name));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} inputValue
|
||||
* @returns {string}
|
||||
*/
|
||||
private getPropertyKeyValue (inputValue: string): string {
|
||||
return this.options.unicodeEscapeSequence
|
||||
? this.escapeSequenceEncoder.encode(inputValue, true)
|
||||
: inputValue;
|
||||
property.key = NodeFactory.literalNode(property.key.name);
|
||||
}
|
||||
}
|
||||
|
||||
+77
-118
@@ -1,13 +1,11 @@
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
|
||||
import { injectable } from 'inversify';
|
||||
|
||||
import * as ESTree from 'estree';
|
||||
|
||||
import { TNodeWithStatements } from '../../../types/node/TNodeWithStatements';
|
||||
import { IObjectExpressionExtractorResult } from '../../../interfaces/node-transformers/converting-transformers/object-expression-extractors/IObjectExpressionExtractorResult';
|
||||
|
||||
import { IOptions } from '../../../interfaces/options/IOptions';
|
||||
import { IPropertiesExtractor } from '../../../interfaces/node-transformers/converting-transformers/properties-extractors/IPropertiesExtractor';
|
||||
import { IRandomGenerator } from '../../../interfaces/utils/IRandomGenerator';
|
||||
import { IObjectExpressionExtractor } from '../../../interfaces/node-transformers/converting-transformers/object-expression-extractors/IObjectExpressionExtractor';
|
||||
|
||||
import { NodeAppender } from '../../../node/NodeAppender';
|
||||
import { NodeFactory } from '../../../node/NodeFactory';
|
||||
@@ -15,48 +13,12 @@ import { NodeGuards } from '../../../node/NodeGuards';
|
||||
import { NodeStatementUtils } from '../../../node/NodeStatementUtils';
|
||||
|
||||
@injectable()
|
||||
export abstract class AbstractPropertiesExtractor implements IPropertiesExtractor {
|
||||
/**
|
||||
* @type {Map<ESTree.ObjectExpression, TNodeWithStatements>}
|
||||
*/
|
||||
protected readonly cachedHostNodesWithStatementsMap: Map <ESTree.ObjectExpression, TNodeWithStatements> = new Map();
|
||||
|
||||
/**
|
||||
* @type {Map<ESTree.ObjectExpression, ESTree.Statement>}
|
||||
*/
|
||||
protected readonly cachedHostStatementsMap: Map <ESTree.ObjectExpression, ESTree.Statement> = new Map();
|
||||
|
||||
/**
|
||||
* @type {IOptions}
|
||||
*/
|
||||
protected readonly options: IOptions;
|
||||
|
||||
/**
|
||||
* @type {IRandomGenerator}
|
||||
*/
|
||||
protected readonly randomGenerator: IRandomGenerator;
|
||||
|
||||
/**
|
||||
* @param {IRandomGenerator} randomGenerator
|
||||
* @param {IOptions} options
|
||||
*/
|
||||
constructor (
|
||||
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
|
||||
@inject(ServiceIdentifiers.IOptions) options: IOptions
|
||||
) {
|
||||
this.randomGenerator = randomGenerator;
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
export class BasePropertiesExtractor implements IObjectExpressionExtractor {
|
||||
/**
|
||||
* @param {Property} propertyNode
|
||||
* @returns {string | null}
|
||||
*/
|
||||
protected static getPropertyNodeKeyName (propertyNode: ESTree.Property): string | null {
|
||||
if (!propertyNode.key) {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static getPropertyNodeKeyName (propertyNode: ESTree.Property): string | null {
|
||||
const propertyKeyNode: ESTree.Expression = propertyNode.key;
|
||||
|
||||
if (
|
||||
@@ -80,7 +42,7 @@ export abstract class AbstractPropertiesExtractor implements IPropertiesExtracto
|
||||
* @param {Node} node
|
||||
* @returns {propertyValueNode is Pattern}
|
||||
*/
|
||||
protected static isProhibitedPattern (node: ESTree.Node): node is ESTree.Pattern {
|
||||
private static isProhibitedPattern (node: ESTree.Node): node is ESTree.Pattern {
|
||||
return !node
|
||||
|| NodeGuards.isObjectPatternNode(node)
|
||||
|| NodeGuards.isArrayPatternNode(node)
|
||||
@@ -89,22 +51,82 @@ export abstract class AbstractPropertiesExtractor implements IPropertiesExtracto
|
||||
}
|
||||
|
||||
/**
|
||||
* extracts object expression properties:
|
||||
* var _0xabc123 = {
|
||||
* foo: 1,
|
||||
* bar: 2
|
||||
* };
|
||||
*
|
||||
* to:
|
||||
* var _0xabc123 = {};
|
||||
* _0xabc123['foo'] = 1;
|
||||
* _0xabc123['bar'] = 2;
|
||||
*
|
||||
* @param {ObjectExpression} objectExpressionNode
|
||||
* @param {Node} hostNode
|
||||
* @returns {Node}
|
||||
* @param {Statement} hostStatement
|
||||
* @returns {IObjectExpressionExtractorResult}
|
||||
*/
|
||||
public abstract extract (
|
||||
public extract (
|
||||
objectExpressionNode: ESTree.ObjectExpression,
|
||||
hostNode: ESTree.Node
|
||||
): ESTree.Node;
|
||||
hostStatement: ESTree.Statement
|
||||
): IObjectExpressionExtractorResult {
|
||||
const hostNode: ESTree.Node | undefined = objectExpressionNode.parentNode;
|
||||
|
||||
if (
|
||||
hostNode
|
||||
&& NodeGuards.isVariableDeclaratorNode(hostNode)
|
||||
&& NodeGuards.isIdentifierNode(hostNode.id)
|
||||
) {
|
||||
return this.transformObjectExpressionNode(objectExpressionNode, hostStatement, hostNode.id);
|
||||
}
|
||||
|
||||
return {
|
||||
nodeToReplace: objectExpressionNode,
|
||||
objectExpressionHostStatement: hostStatement,
|
||||
objectExpressionNode: objectExpressionNode
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ObjectExpression} objectExpressionNode
|
||||
* @param {Statement} hostStatement
|
||||
* @param {Expression} memberExpressionHostNode
|
||||
* @returns {IObjectExpressionExtractorResult}
|
||||
*/
|
||||
private transformObjectExpressionNode (
|
||||
objectExpressionNode: ESTree.ObjectExpression,
|
||||
hostStatement: ESTree.Statement,
|
||||
memberExpressionHostNode: ESTree.Expression
|
||||
): IObjectExpressionExtractorResult {
|
||||
const properties: ESTree.Property[] = objectExpressionNode.properties;
|
||||
const [expressionStatements, removablePropertyIds]: [ESTree.ExpressionStatement[], number[]] = this
|
||||
.extractPropertiesToExpressionStatements(
|
||||
properties,
|
||||
hostStatement,
|
||||
memberExpressionHostNode
|
||||
);
|
||||
|
||||
const hostNodeWithStatements: TNodeWithStatements = NodeStatementUtils.getScopeOfNode(hostStatement);
|
||||
|
||||
this.filterExtractedObjectExpressionProperties(objectExpressionNode, removablePropertyIds);
|
||||
NodeAppender.insertAfter(hostNodeWithStatements, expressionStatements, hostStatement);
|
||||
|
||||
return {
|
||||
nodeToReplace: objectExpressionNode,
|
||||
objectExpressionHostStatement: hostStatement,
|
||||
objectExpressionNode: objectExpressionNode
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Property[]} properties
|
||||
* @param {Statement} hostStatement
|
||||
* @param {Expression} memberExpressionHostNode
|
||||
* @returns {[ExpressionStatement[] , number[]]}
|
||||
* @returns {[ExpressionStatement[], number[]]}
|
||||
*/
|
||||
protected extractPropertiesToExpressionStatements (
|
||||
private extractPropertiesToExpressionStatements (
|
||||
properties: ESTree.Property[],
|
||||
hostStatement: ESTree.Statement,
|
||||
memberExpressionHostNode: ESTree.Expression
|
||||
): [ESTree.ExpressionStatement[], number[]] {
|
||||
const propertiesLength: number = properties.length;
|
||||
@@ -116,14 +138,14 @@ export abstract class AbstractPropertiesExtractor implements IPropertiesExtracto
|
||||
const propertyValue: ESTree.Expression | ESTree.Pattern = property.value;
|
||||
|
||||
// invalid property nodes
|
||||
if (AbstractPropertiesExtractor.isProhibitedPattern(propertyValue)) {
|
||||
if (BasePropertiesExtractor.isProhibitedPattern(propertyValue)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stage 1: extract property node key names
|
||||
*/
|
||||
const propertyKeyName: string | null = AbstractPropertiesExtractor.getPropertyNodeKeyName(property);
|
||||
const propertyKeyName: string | null = BasePropertiesExtractor.getPropertyNodeKeyName(property);
|
||||
|
||||
if (!propertyKeyName) {
|
||||
continue;
|
||||
@@ -147,7 +169,7 @@ export abstract class AbstractPropertiesExtractor implements IPropertiesExtracto
|
||||
* Stage 3: recursively processing nested object expressions
|
||||
*/
|
||||
if (NodeGuards.isObjectExpressionNode(property.value)) {
|
||||
this.transformObjectExpressionNode(property.value, memberExpressionNode);
|
||||
this.transformObjectExpressionNode(property.value, hostStatement, memberExpressionNode);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -164,74 +186,11 @@ export abstract class AbstractPropertiesExtractor implements IPropertiesExtracto
|
||||
* @param {ObjectExpression} objectExpressionNode
|
||||
* @param {number[]} removablePropertyIds
|
||||
*/
|
||||
protected filterExtractedObjectExpressionProperties (
|
||||
private filterExtractedObjectExpressionProperties (
|
||||
objectExpressionNode: ESTree.ObjectExpression,
|
||||
removablePropertyIds: number[]
|
||||
): void {
|
||||
objectExpressionNode.properties = objectExpressionNode.properties
|
||||
.filter((property: ESTree.Property, index: number) => !removablePropertyIds.includes(index));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ObjectExpression} objectExpressionNode
|
||||
* @param {Expression} memberExpressionHostNode
|
||||
* @returns {Node}
|
||||
*/
|
||||
protected transformObjectExpressionNode (
|
||||
objectExpressionNode: ESTree.ObjectExpression,
|
||||
memberExpressionHostNode: ESTree.Expression
|
||||
): ESTree.Node {
|
||||
const properties: ESTree.Property[] = objectExpressionNode.properties;
|
||||
const [expressionStatements, removablePropertyIds]: [ESTree.ExpressionStatement[], number[]] = this
|
||||
.extractPropertiesToExpressionStatements(properties, memberExpressionHostNode);
|
||||
|
||||
const hostStatement: ESTree.Statement = this.getHostStatement(objectExpressionNode);
|
||||
const hostNodeWithStatements: TNodeWithStatements = this.getHostNodeWithStatements(
|
||||
objectExpressionNode,
|
||||
hostStatement
|
||||
);
|
||||
|
||||
this.filterExtractedObjectExpressionProperties(objectExpressionNode, removablePropertyIds);
|
||||
NodeAppender.insertAfter(hostNodeWithStatements, expressionStatements, hostStatement);
|
||||
|
||||
return objectExpressionNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ObjectExpression} objectExpressionNode
|
||||
* @param {Statement} hostStatement
|
||||
* @returns {TNodeWithStatements}
|
||||
*/
|
||||
protected getHostNodeWithStatements (
|
||||
objectExpressionNode: ESTree.ObjectExpression,
|
||||
hostStatement: ESTree.Statement
|
||||
): TNodeWithStatements {
|
||||
if (this.cachedHostNodesWithStatementsMap.has(objectExpressionNode)) {
|
||||
return <TNodeWithStatements>this.cachedHostNodesWithStatementsMap.get(objectExpressionNode);
|
||||
}
|
||||
|
||||
const nodeWithStatements: TNodeWithStatements = NodeStatementUtils.getScopeOfNode(hostStatement);
|
||||
|
||||
this.cachedHostNodesWithStatementsMap.set(objectExpressionNode, nodeWithStatements);
|
||||
|
||||
return nodeWithStatements;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns host statement of object expression node
|
||||
*
|
||||
* @param {NodeGuards} objectExpressionNode
|
||||
* @returns {Node}
|
||||
*/
|
||||
protected getHostStatement (objectExpressionNode: ESTree.ObjectExpression): ESTree.Statement {
|
||||
if (this.cachedHostStatementsMap.has(objectExpressionNode)) {
|
||||
return <ESTree.Statement>this.cachedHostStatementsMap.get(objectExpressionNode);
|
||||
}
|
||||
|
||||
const hostStatement: ESTree.Statement = NodeStatementUtils.getRootStatementOfNode(objectExpressionNode);
|
||||
|
||||
this.cachedHostStatementsMap.set(objectExpressionNode, hostStatement);
|
||||
|
||||
return hostStatement;
|
||||
}
|
||||
}
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
|
||||
|
||||
import * as ESTree from 'estree';
|
||||
|
||||
import { TNodeWithStatements } from '../../../types/node/TNodeWithStatements';
|
||||
import { TObjectExpressionKeysTransformerCustomNodeFactory } from '../../../types/container/custom-nodes/TObjectExpressionKeysTransformerCustomNodeFactory';
|
||||
import { IObjectExpressionExtractorResult } from '../../../interfaces/node-transformers/converting-transformers/object-expression-extractors/IObjectExpressionExtractorResult';
|
||||
import { TStatement } from '../../../types/node/TStatement';
|
||||
|
||||
import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
|
||||
import { TInitialData } from '../../../types/TInitialData';
|
||||
import { IObjectExpressionExtractor } from '../../../interfaces/node-transformers/converting-transformers/object-expression-extractors/IObjectExpressionExtractor';
|
||||
|
||||
import { ObjectExpressionKeysTransformerCustomNode } from '../../../enums/custom-nodes/ObjectExpressionKeysTransformerCustomNode';
|
||||
|
||||
import { ObjectExpressionVariableDeclarationHostNode } from '../../../custom-nodes/object-expression-keys-transformer-nodes/ObjectExpressionVariableDeclarationHostNode';
|
||||
import { NodeAppender } from '../../../node/NodeAppender';
|
||||
import { NodeGuards } from '../../../node/NodeGuards';
|
||||
import { NodeStatementUtils } from '../../../node/NodeStatementUtils';
|
||||
import { NodeUtils } from '../../../node/NodeUtils';
|
||||
|
||||
@injectable()
|
||||
export class ObjectExpressionToVariableDeclarationExtractor implements IObjectExpressionExtractor {
|
||||
/**
|
||||
* @type {TObjectExpressionKeysTransformerCustomNodeFactory}
|
||||
*/
|
||||
private readonly objectExpressionKeysTransformerCustomNodeFactory: TObjectExpressionKeysTransformerCustomNodeFactory;
|
||||
|
||||
/**
|
||||
* @param {TObjectExpressionKeysTransformerCustomNodeFactory} objectExpressionKeysTransformerCustomNodeFactory
|
||||
*/
|
||||
constructor (
|
||||
@inject(ServiceIdentifiers.Factory__IObjectExpressionKeysTransformerCustomNode)
|
||||
objectExpressionKeysTransformerCustomNodeFactory: TObjectExpressionKeysTransformerCustomNodeFactory,
|
||||
) {
|
||||
this.objectExpressionKeysTransformerCustomNodeFactory = objectExpressionKeysTransformerCustomNodeFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* extracts object expression:
|
||||
* var object = {
|
||||
* foo: 1,
|
||||
* bar: 2
|
||||
* };
|
||||
*
|
||||
* to:
|
||||
* var _0xabc123 = {
|
||||
* foo: 1,
|
||||
* bar: 2
|
||||
* };
|
||||
* var object = _0xabc123;
|
||||
*
|
||||
* @param {ObjectExpression} objectExpressionNode
|
||||
* @param {Statement} hostStatement
|
||||
* @returns {IObjectExpressionExtractorResult}
|
||||
*/
|
||||
public extract (
|
||||
objectExpressionNode: ESTree.ObjectExpression,
|
||||
hostStatement: ESTree.Statement
|
||||
): IObjectExpressionExtractorResult {
|
||||
return this.transformObjectExpressionToVariableDeclaration(
|
||||
objectExpressionNode,
|
||||
hostStatement
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ObjectExpression} objectExpressionNode
|
||||
* @param {Statement} hostStatement
|
||||
* @returns {Node}
|
||||
*/
|
||||
private transformObjectExpressionToVariableDeclaration (
|
||||
objectExpressionNode: ESTree.ObjectExpression,
|
||||
hostStatement: ESTree.Statement
|
||||
): IObjectExpressionExtractorResult {
|
||||
const properties: ESTree.Property[] = objectExpressionNode.properties;
|
||||
|
||||
const newObjectExpressionHostStatement: ESTree.VariableDeclaration = this.getObjectExpressionHostNode(properties);
|
||||
const newObjectExpressionIdentifier: ESTree.Identifier = this.getObjectExpressionIdentifierNode(newObjectExpressionHostStatement);
|
||||
const newObjectExpressionNode: ESTree.ObjectExpression = this.getObjectExpressionNode(newObjectExpressionHostStatement);
|
||||
|
||||
const statementsToInsert: TStatement[] = [newObjectExpressionHostStatement];
|
||||
const hostNodeWithStatements: TNodeWithStatements = NodeStatementUtils.getScopeOfNode(hostStatement);
|
||||
|
||||
NodeAppender.insertBefore(hostNodeWithStatements, statementsToInsert, hostStatement);
|
||||
NodeUtils.parentizeAst(newObjectExpressionHostStatement);
|
||||
NodeUtils.parentizeNode(newObjectExpressionHostStatement, hostNodeWithStatements);
|
||||
|
||||
return {
|
||||
nodeToReplace: newObjectExpressionIdentifier,
|
||||
objectExpressionHostStatement: newObjectExpressionHostStatement,
|
||||
objectExpressionNode: newObjectExpressionNode
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Property[]} properties
|
||||
* @returns {VariableDeclaration}
|
||||
*/
|
||||
private getObjectExpressionHostNode (properties: ESTree.Property[]): ESTree.VariableDeclaration {
|
||||
const variableDeclarationHostNodeCustomNode: ICustomNode<TInitialData<ObjectExpressionVariableDeclarationHostNode>> =
|
||||
this.objectExpressionKeysTransformerCustomNodeFactory(
|
||||
ObjectExpressionKeysTransformerCustomNode.ObjectExpressionVariableDeclarationHostNode
|
||||
);
|
||||
|
||||
variableDeclarationHostNodeCustomNode.initialize(properties);
|
||||
|
||||
const statementNode: TStatement = variableDeclarationHostNodeCustomNode.getNode()[0];
|
||||
|
||||
if (
|
||||
!statementNode
|
||||
|| !NodeGuards.isVariableDeclarationNode(statementNode)
|
||||
) {
|
||||
throw new Error(`\`objectExpressionHostCustomNode.getNode()[0]\` should returns array with \`VariableDeclaration\` node`);
|
||||
}
|
||||
|
||||
return statementNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {VariableDeclaration} objectExpressionHostNode
|
||||
* @returns {Identifier}
|
||||
*/
|
||||
private getObjectExpressionIdentifierNode (objectExpressionHostNode: ESTree.VariableDeclaration): ESTree.Identifier {
|
||||
const newObjectExpressionIdentifierNode: ESTree.Pattern = objectExpressionHostNode.declarations[0].id;
|
||||
|
||||
if (!NodeGuards.isIdentifierNode(newObjectExpressionIdentifierNode)) {
|
||||
throw new Error(`\`objectExpressionHostNode\` should contain \`VariableDeclarator\` node with \`Identifier\` id property`);
|
||||
}
|
||||
|
||||
return newObjectExpressionIdentifierNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {VariableDeclaration} objectExpressionHostNode
|
||||
* @returns {Identifier}
|
||||
*/
|
||||
private getObjectExpressionNode (objectExpressionHostNode: ESTree.VariableDeclaration): ESTree.ObjectExpression {
|
||||
const newObjectExpressionNode: ESTree.Expression | null = objectExpressionHostNode.declarations[0].init ?? null;
|
||||
|
||||
if (!newObjectExpressionNode || !NodeGuards.isObjectExpressionNode(newObjectExpressionNode)) {
|
||||
throw new Error(`\`objectExpressionHostNode\` should contain \`VariableDeclarator\` node with \`ObjectExpression\` init property`);
|
||||
}
|
||||
|
||||
return newObjectExpressionNode;
|
||||
}
|
||||
}
|
||||
-81
@@ -1,81 +0,0 @@
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
|
||||
|
||||
import * as ESTree from 'estree';
|
||||
|
||||
import { IOptions } from '../../../interfaces/options/IOptions';
|
||||
import { IRandomGenerator } from '../../../interfaces/utils/IRandomGenerator';
|
||||
|
||||
import { AbstractPropertiesExtractor } from './AbstractPropertiesExtractor';
|
||||
import { NodeGuards } from '../../../node/NodeGuards';
|
||||
|
||||
@injectable()
|
||||
export class AssignmentExpressionPropertiesExtractor extends AbstractPropertiesExtractor {
|
||||
/**
|
||||
* @param {IRandomGenerator} randomGenerator
|
||||
* @param {IOptions} options
|
||||
*/
|
||||
constructor (
|
||||
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
|
||||
@inject(ServiceIdentifiers.IOptions) options: IOptions
|
||||
) {
|
||||
super(randomGenerator, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Node} node
|
||||
* @returns {propertyValueNode is Pattern}
|
||||
*/
|
||||
private static isProhibitedHostParent (node: ESTree.Node): node is ESTree.Pattern {
|
||||
if (NodeGuards.isMemberExpressionNode(node)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (AssignmentExpressionPropertiesExtractor.isProhibitedStatementNode(node)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// statements without block statement
|
||||
return NodeGuards.isExpressionStatementNode(node)
|
||||
&& !!node.parentNode
|
||||
&& AssignmentExpressionPropertiesExtractor.isProhibitedStatementNode(node.parentNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Node} node
|
||||
* @returns {boolean}
|
||||
*/
|
||||
private static isProhibitedStatementNode (node: ESTree.Node): boolean {
|
||||
return NodeGuards.isIfStatementNode(node)
|
||||
|| NodeGuards.isForStatementTypeNode(node)
|
||||
|| NodeGuards.isWhileStatementNode(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ObjectExpression} objectExpressionNode
|
||||
* @param {AssignmentExpression} hostNode
|
||||
* @returns {Node}
|
||||
*/
|
||||
public extract (
|
||||
objectExpressionNode: ESTree.ObjectExpression,
|
||||
hostNode: ESTree.AssignmentExpression
|
||||
): ESTree.Node {
|
||||
const hostParentNode: ESTree.Node | undefined = hostNode.parentNode;
|
||||
const leftNode: ESTree.MemberExpression | ESTree.Pattern = hostNode.left;
|
||||
|
||||
// left node shouldn't be as Pattern node
|
||||
if (AbstractPropertiesExtractor.isProhibitedPattern(leftNode)) {
|
||||
return objectExpressionNode;
|
||||
}
|
||||
|
||||
// left node shouldn't be as prohibited node
|
||||
if (hostParentNode && AssignmentExpressionPropertiesExtractor.isProhibitedHostParent(hostParentNode)) {
|
||||
return objectExpressionNode;
|
||||
}
|
||||
|
||||
return this.transformObjectExpressionNode(
|
||||
objectExpressionNode,
|
||||
leftNode
|
||||
);
|
||||
}
|
||||
}
|
||||
-129
@@ -1,129 +0,0 @@
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
|
||||
|
||||
import * as ESTree from 'estree';
|
||||
|
||||
import { TNodeWithStatements } from '../../../types/node/TNodeWithStatements';
|
||||
import { TObjectExpressionKeysTransformerCustomNodeFactory } from '../../../types/container/custom-nodes/TObjectExpressionKeysTransformerCustomNodeFactory';
|
||||
import { TStatement } from '../../../types/node/TStatement';
|
||||
|
||||
import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
|
||||
import { TInitialData } from '../../../types/TInitialData';
|
||||
import { IOptions } from '../../../interfaces/options/IOptions';
|
||||
import { IRandomGenerator } from '../../../interfaces/utils/IRandomGenerator';
|
||||
|
||||
import { ObjectExpressionKeysTransformerCustomNode } from '../../../enums/custom-nodes/ObjectExpressionKeysTransformerCustomNode';
|
||||
|
||||
import { AbstractPropertiesExtractor } from './AbstractPropertiesExtractor';
|
||||
import { BasePropertiesExtractorObjectExpressionHostNode } from '../../../custom-nodes/object-expression-keys-transformer-nodes/BasePropertiesExtractorObjectExpressionHostNode';
|
||||
import { NodeAppender } from '../../../node/NodeAppender';
|
||||
import { NodeGuards } from '../../../node/NodeGuards';
|
||||
|
||||
@injectable()
|
||||
export class BasePropertiesExtractor extends AbstractPropertiesExtractor {
|
||||
/**
|
||||
* @type {TObjectExpressionKeysTransformerCustomNodeFactory}
|
||||
*/
|
||||
private readonly objectExpressionKeysTransformerCustomNodeFactory: TObjectExpressionKeysTransformerCustomNodeFactory;
|
||||
|
||||
/**
|
||||
* @param {IRandomGenerator} randomGenerator
|
||||
* @param {IOptions} options
|
||||
* @param {TObjectExpressionKeysTransformerCustomNodeFactory} objectExpressionKeysTransformerCustomNodeFactory
|
||||
*/
|
||||
constructor (
|
||||
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
|
||||
@inject(ServiceIdentifiers.IOptions) options: IOptions,
|
||||
@inject(ServiceIdentifiers.Factory__IObjectExpressionKeysTransformerCustomNode)
|
||||
objectExpressionKeysTransformerCustomNodeFactory: TObjectExpressionKeysTransformerCustomNodeFactory,
|
||||
) {
|
||||
super(randomGenerator, options);
|
||||
|
||||
this.objectExpressionKeysTransformerCustomNodeFactory = objectExpressionKeysTransformerCustomNodeFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ObjectExpression} objectExpressionNode
|
||||
* @param {Node} parentNode
|
||||
* @returns {Node}
|
||||
*/
|
||||
public extract (
|
||||
objectExpressionNode: ESTree.ObjectExpression,
|
||||
parentNode: ESTree.Node
|
||||
): ESTree.Node {
|
||||
return this.transformObjectExpressionNode(
|
||||
objectExpressionNode,
|
||||
parentNode
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ObjectExpression} objectExpressionNode
|
||||
* @param {Node} parentNode
|
||||
* @returns {Node}
|
||||
*/
|
||||
protected transformObjectExpressionNode (
|
||||
objectExpressionNode: ESTree.ObjectExpression,
|
||||
parentNode: ESTree.Node
|
||||
): ESTree.Node {
|
||||
const newObjectExpressionHostNode: ESTree.VariableDeclaration = this.getObjectExpressionHostNode();
|
||||
const newObjectExpressionIdentifier: ESTree.Identifier = this.getObjectExpressionIdentifierNode(newObjectExpressionHostNode);
|
||||
|
||||
const properties: ESTree.Property[] = objectExpressionNode.properties;
|
||||
|
||||
const [expressionStatements, removablePropertyIds]: [ESTree.ExpressionStatement[], number[]] = this
|
||||
.extractPropertiesToExpressionStatements(properties, newObjectExpressionIdentifier);
|
||||
const statementsToInsert: TStatement[] = [
|
||||
newObjectExpressionHostNode,
|
||||
...expressionStatements
|
||||
];
|
||||
|
||||
const hostStatement: ESTree.Statement = this.getHostStatement(objectExpressionNode);
|
||||
const hostNodeWithStatements: TNodeWithStatements = this.getHostNodeWithStatements(
|
||||
objectExpressionNode,
|
||||
hostStatement
|
||||
);
|
||||
|
||||
this.filterExtractedObjectExpressionProperties(objectExpressionNode, removablePropertyIds);
|
||||
NodeAppender.insertBefore(hostNodeWithStatements, statementsToInsert, hostStatement);
|
||||
|
||||
return newObjectExpressionIdentifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {VariableDeclaration}
|
||||
*/
|
||||
private getObjectExpressionHostNode (): ESTree.VariableDeclaration {
|
||||
const objectExpressionHostCustomNode: ICustomNode<TInitialData<BasePropertiesExtractorObjectExpressionHostNode>> =
|
||||
this.objectExpressionKeysTransformerCustomNodeFactory(
|
||||
ObjectExpressionKeysTransformerCustomNode.BasePropertiesExtractorObjectExpressionHostNode
|
||||
);
|
||||
|
||||
objectExpressionHostCustomNode.initialize();
|
||||
|
||||
const statementNode: TStatement = objectExpressionHostCustomNode.getNode()[0];
|
||||
|
||||
if (
|
||||
!statementNode
|
||||
|| !NodeGuards.isVariableDeclarationNode(statementNode)
|
||||
) {
|
||||
throw new Error(`\`objectExpressionHostCustomNode.getNode()[0]\` should returns array with \`VariableDeclaration\` node`);
|
||||
}
|
||||
|
||||
return statementNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {VariableDeclaration} objectExpressionHostNode
|
||||
* @returns {Identifier}
|
||||
*/
|
||||
private getObjectExpressionIdentifierNode (objectExpressionHostNode: ESTree.VariableDeclaration): ESTree.Identifier {
|
||||
const newObjectExpressionIdentifierNode: ESTree.Pattern = objectExpressionHostNode.declarations[0].id;
|
||||
|
||||
if (!NodeGuards.isIdentifierNode(newObjectExpressionIdentifierNode)) {
|
||||
throw new Error(`\`objectExpressionHostNode\` should contain \`VariableDeclarator\` node with \`Identifier\` id property`);
|
||||
}
|
||||
|
||||
return newObjectExpressionIdentifierNode;
|
||||
}
|
||||
}
|
||||
-118
@@ -1,118 +0,0 @@
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
|
||||
|
||||
import * as estraverse from 'estraverse';
|
||||
import * as ESTree from 'estree';
|
||||
|
||||
import { IOptions } from '../../../interfaces/options/IOptions';
|
||||
import { IRandomGenerator } from '../../../interfaces/utils/IRandomGenerator';
|
||||
|
||||
import { AbstractPropertiesExtractor } from './AbstractPropertiesExtractor';
|
||||
import { NodeGuards } from '../../../node/NodeGuards';
|
||||
|
||||
@injectable()
|
||||
export class VariableDeclaratorPropertiesExtractor extends AbstractPropertiesExtractor {
|
||||
/**
|
||||
* @param {IRandomGenerator} randomGenerator
|
||||
* @param {IOptions} options
|
||||
*/
|
||||
constructor (
|
||||
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
|
||||
@inject(ServiceIdentifiers.IOptions) options: IOptions
|
||||
) {
|
||||
super(randomGenerator, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ObjectExpression} objectExpressionNode
|
||||
* @param {VariableDeclarator} hostNode
|
||||
* @returns {Node}
|
||||
*/
|
||||
public extract (
|
||||
objectExpressionNode: ESTree.ObjectExpression,
|
||||
hostNode: ESTree.VariableDeclarator
|
||||
): ESTree.Node {
|
||||
if (
|
||||
!NodeGuards.isIdentifierNode(hostNode.id)
|
||||
|| this.isProhibitedObjectExpressionNode(objectExpressionNode, hostNode.id)
|
||||
) {
|
||||
return objectExpressionNode;
|
||||
}
|
||||
|
||||
return this.transformObjectExpressionNode(objectExpressionNode, hostNode.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ObjectExpression} objectExpressionNode
|
||||
* @returns {VariableDeclarator}
|
||||
*/
|
||||
private getHostVariableDeclaratorNode (objectExpressionNode: ESTree.ObjectExpression): ESTree.VariableDeclarator | never {
|
||||
const { parentNode } = objectExpressionNode;
|
||||
|
||||
if (!parentNode || !NodeGuards.isVariableDeclaratorNode(parentNode)) {
|
||||
throw new Error('Cannot get `VariableDeclarator` node for `ObjectExpression` node');
|
||||
}
|
||||
|
||||
return parentNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {VariableDeclarator} variableDeclaratorNode
|
||||
* @returns {VariableDeclaration}
|
||||
*/
|
||||
private getHostVariableDeclarationNode (variableDeclaratorNode: ESTree.VariableDeclarator): ESTree.VariableDeclaration | never {
|
||||
const { parentNode } = variableDeclaratorNode;
|
||||
|
||||
if (!parentNode || !NodeGuards.isVariableDeclarationNode(parentNode)) {
|
||||
throw new Error('Cannot get `VariableDeclaration` node for `VariableDeclarator` node');
|
||||
}
|
||||
|
||||
return parentNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ObjectExpression} objectExpressionNode
|
||||
* @param {Identifier} memberExpressionHostNode
|
||||
* @returns {boolean}
|
||||
*/
|
||||
private isProhibitedObjectExpressionNode (
|
||||
objectExpressionNode: ESTree.ObjectExpression,
|
||||
memberExpressionHostNode: ESTree.Identifier
|
||||
): boolean {
|
||||
const hostVariableDeclarator: ESTree.VariableDeclarator = this.getHostVariableDeclaratorNode(objectExpressionNode);
|
||||
const hostVariableDeclaration: ESTree.VariableDeclaration = this.getHostVariableDeclarationNode(hostVariableDeclarator);
|
||||
const { declarations } = hostVariableDeclaration;
|
||||
const indexOfDeclarator: number = declarations.indexOf(hostVariableDeclarator);
|
||||
const isLastDeclarator: boolean = indexOfDeclarator === (declarations.length - 1);
|
||||
|
||||
// avoid unnecessary checks
|
||||
if (isLastDeclarator) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const declaratorsAfterCurrentDeclarator: ESTree.VariableDeclarator[] = declarations.slice(indexOfDeclarator);
|
||||
|
||||
let isProhibitedObjectExpressionNode: boolean = false;
|
||||
|
||||
// should mark node as prohibited if that node using inside other variable declarators
|
||||
declaratorsAfterCurrentDeclarator.forEach((variableDeclarator: ESTree.VariableDeclarator) => {
|
||||
estraverse.traverse(variableDeclarator, {
|
||||
enter: (node: ESTree.Node): estraverse.VisitorOption | ESTree.Node => {
|
||||
if (
|
||||
NodeGuards.isMemberExpressionNode(node)
|
||||
&& NodeGuards.isIdentifierNode(node.object)
|
||||
&& node.object.name === memberExpressionHostNode.name
|
||||
) {
|
||||
isProhibitedObjectExpressionNode = true;
|
||||
|
||||
return estraverse.VisitorOption.Break;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return isProhibitedObjectExpressionNode;
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import * as ESTree from 'estree';
|
||||
|
||||
import { TLiteralObfuscatingReplacerFactory } from '../../types/container/node-transformers/TLiteralObfuscatingReplacerFactory';
|
||||
|
||||
import { IEscapeSequenceEncoder } from '../../interfaces/utils/IEscapeSequenceEncoder';
|
||||
import { IOptions } from '../../interfaces/options/IOptions';
|
||||
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
|
||||
import { IStringArrayStorageAnalyzer } from '../../interfaces/analyzers/string-array-storage-analyzer/IStringArrayStorageAnalyzer';
|
||||
@@ -14,12 +15,19 @@ import { LiteralObfuscatingReplacer } from '../../enums/node-transformers/obfusc
|
||||
import { TransformationStage } from '../../enums/node-transformers/TransformationStage';
|
||||
|
||||
import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
|
||||
import { NodeFactory } from '../../node/NodeFactory';
|
||||
import { NodeGuards } from '../../node/NodeGuards';
|
||||
import { NodeLiteralUtils } from '../../node/NodeLiteralUtils';
|
||||
import { NodeMetadata } from '../../node/NodeMetadata';
|
||||
import { NodeUtils } from '../../node/NodeUtils';
|
||||
|
||||
@injectable()
|
||||
export class LiteralTransformer extends AbstractNodeTransformer {
|
||||
/**
|
||||
* @type {IEscapeSequenceEncoder}
|
||||
*/
|
||||
private readonly escapeSequenceEncoder: IEscapeSequenceEncoder;
|
||||
|
||||
/**
|
||||
* @type {TLiteralObfuscatingReplacerFactory}
|
||||
*/
|
||||
@@ -35,18 +43,21 @@ export class LiteralTransformer extends AbstractNodeTransformer {
|
||||
* @param {IRandomGenerator} randomGenerator
|
||||
* @param {IOptions} options
|
||||
* @param {IStringArrayStorageAnalyzer} stringArrayStorageAnalyzer
|
||||
* @param {IEscapeSequenceEncoder} escapeSequenceEncoder
|
||||
*/
|
||||
constructor (
|
||||
@inject(ServiceIdentifiers.Factory__IObfuscatingReplacer)
|
||||
literalObfuscatingReplacerFactory: TLiteralObfuscatingReplacerFactory,
|
||||
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
|
||||
@inject(ServiceIdentifiers.IOptions) options: IOptions,
|
||||
@inject(ServiceIdentifiers.IStringArrayStorageAnalyzer) stringArrayStorageAnalyzer: IStringArrayStorageAnalyzer
|
||||
@inject(ServiceIdentifiers.IStringArrayStorageAnalyzer) stringArrayStorageAnalyzer: IStringArrayStorageAnalyzer,
|
||||
@inject(ServiceIdentifiers.IEscapeSequenceEncoder) escapeSequenceEncoder: IEscapeSequenceEncoder
|
||||
) {
|
||||
super(randomGenerator, options);
|
||||
|
||||
this.literalObfuscatingReplacerFactory = literalObfuscatingReplacerFactory;
|
||||
this.stringArrayStorageAnalyzer = stringArrayStorageAnalyzer;
|
||||
this.escapeSequenceEncoder = escapeSequenceEncoder;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -68,6 +79,15 @@ export class LiteralTransformer extends AbstractNodeTransformer {
|
||||
}
|
||||
};
|
||||
|
||||
case TransformationStage.Finalizing:
|
||||
return {
|
||||
enter: (node: ESTree.Node, parentNode: ESTree.Node | null) => {
|
||||
if (parentNode && NodeGuards.isLiteralNode(node)) {
|
||||
return this.encodeLiteralNodeToEscapeSequence(node, parentNode);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
@@ -83,7 +103,7 @@ export class LiteralTransformer extends AbstractNodeTransformer {
|
||||
* @returns {NodeGuards}
|
||||
*/
|
||||
public transformNode (literalNode: ESTree.Literal, parentNode: ESTree.Node): ESTree.Node {
|
||||
if (this.isProhibitedNode(literalNode, parentNode)) {
|
||||
if (NodeLiteralUtils.isProhibitedLiteralNode(literalNode, parentNode)) {
|
||||
return literalNode;
|
||||
}
|
||||
|
||||
@@ -123,17 +143,18 @@ export class LiteralTransformer extends AbstractNodeTransformer {
|
||||
/**
|
||||
* @param {Literal} literalNode
|
||||
* @param {Node} parentNode
|
||||
* @returns {boolean}
|
||||
* @returns {Literal}
|
||||
*/
|
||||
private isProhibitedNode (literalNode: ESTree.Literal, parentNode: ESTree.Node): boolean {
|
||||
if (NodeGuards.isPropertyNode(parentNode) && parentNode.key === literalNode) {
|
||||
return true;
|
||||
private encodeLiteralNodeToEscapeSequence (
|
||||
literalNode: ESTree.Literal,
|
||||
parentNode: ESTree.Node
|
||||
): ESTree.Literal {
|
||||
if (typeof literalNode.value !== 'string') {
|
||||
return literalNode;
|
||||
}
|
||||
|
||||
if (NodeGuards.isImportDeclarationNode(parentNode)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return NodeFactory.literalNode(
|
||||
this.escapeSequenceEncoder.encode(literalNode.value, this.options.unicodeEscapeSequence)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-15
@@ -3,7 +3,6 @@ import { ServiceIdentifiers } from '../../../../container/ServiceIdentifiers';
|
||||
|
||||
import * as ESTree from 'estree';
|
||||
|
||||
import { IEscapeSequenceEncoder } from '../../../../interfaces/utils/IEscapeSequenceEncoder';
|
||||
import { IInitializable } from '../../../../interfaces/IInitializable';
|
||||
import { IOptions } from '../../../../interfaces/options/IOptions';
|
||||
import { IStringArrayStorage } from '../../../../interfaces/storages/string-array-storage/IStringArrayStorage';
|
||||
@@ -22,11 +21,6 @@ import { Utils } from '../../../../utils/Utils';
|
||||
|
||||
@injectable()
|
||||
export class StringLiteralObfuscatingReplacer extends AbstractObfuscatingReplacer implements IInitializable {
|
||||
/**
|
||||
* @type {IEscapeSequenceEncoder}
|
||||
*/
|
||||
private readonly escapeSequenceEncoder: IEscapeSequenceEncoder;
|
||||
|
||||
/**
|
||||
* @type {Map<string, ESTree.Node>}
|
||||
*/
|
||||
@@ -51,20 +45,17 @@ export class StringLiteralObfuscatingReplacer extends AbstractObfuscatingReplace
|
||||
/**
|
||||
* @param {IStringArrayStorage} stringArrayStorage
|
||||
* @param {IStringArrayStorageAnalyzer} stringArrayStorageAnalyzer
|
||||
* @param {IEscapeSequenceEncoder} escapeSequenceEncoder
|
||||
* @param {IOptions} options
|
||||
*/
|
||||
constructor (
|
||||
@inject(ServiceIdentifiers.TStringArrayStorage) stringArrayStorage: IStringArrayStorage,
|
||||
@inject(ServiceIdentifiers.IStringArrayStorageAnalyzer) stringArrayStorageAnalyzer: IStringArrayStorageAnalyzer,
|
||||
@inject(ServiceIdentifiers.IEscapeSequenceEncoder) escapeSequenceEncoder: IEscapeSequenceEncoder,
|
||||
@inject(ServiceIdentifiers.IOptions) options: IOptions
|
||||
) {
|
||||
super(options);
|
||||
|
||||
this.stringArrayStorage = stringArrayStorage;
|
||||
this.stringArrayStorageAnalyzer = stringArrayStorageAnalyzer;
|
||||
this.escapeSequenceEncoder = escapeSequenceEncoder;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,9 +129,7 @@ export class StringLiteralObfuscatingReplacer extends AbstractObfuscatingReplace
|
||||
* @returns {Node}
|
||||
*/
|
||||
private replaceWithLiteralNode (value: string): ESTree.Node {
|
||||
return NodeFactory.literalNode(
|
||||
this.escapeSequenceEncoder.encode(value, this.options.unicodeEscapeSequence)
|
||||
);
|
||||
return NodeFactory.literalNode(value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -156,9 +145,7 @@ export class StringLiteralObfuscatingReplacer extends AbstractObfuscatingReplace
|
||||
];
|
||||
|
||||
if (decodeKey) {
|
||||
callExpressionArgs.push(StringLiteralObfuscatingReplacer.getRc4KeyLiteralNode(
|
||||
this.escapeSequenceEncoder.encode(decodeKey, this.options.unicodeEscapeSequence)
|
||||
));
|
||||
callExpressionArgs.push(StringLiteralObfuscatingReplacer.getRc4KeyLiteralNode(decodeKey));
|
||||
}
|
||||
|
||||
const stringArrayIdentifierNode: ESTree.Identifier = NodeFactory.identifierNode(this.stringArrayStorageCallsWrapperName);
|
||||
|
||||
@@ -228,6 +228,23 @@ export class NodeFactory {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {(ImportSpecifier | ImportDefaultSpecifier | ImportNamespaceSpecifier)[]} specifiers
|
||||
* @param {Literal} source
|
||||
* @returns {ImportDeclaration}
|
||||
*/
|
||||
public static importDeclarationNode (
|
||||
specifiers: (ESTree.ImportSpecifier | ESTree.ImportDefaultSpecifier | ESTree.ImportNamespaceSpecifier)[],
|
||||
source: ESTree.Literal
|
||||
): ESTree.ImportDeclaration {
|
||||
return {
|
||||
type: NodeType.ImportDeclaration,
|
||||
specifiers,
|
||||
source,
|
||||
metadata: { ignoredNode: false }
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {boolean | number | string} value
|
||||
* @param {string} raw
|
||||
|
||||
@@ -80,14 +80,6 @@ export class NodeGuards {
|
||||
return node.type === NodeType.CallExpression;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Node} node
|
||||
* @returns {boolean}
|
||||
*/
|
||||
public static isCatchClauseNode (node: ESTree.Node): node is ESTree.CatchClause {
|
||||
return node.type === NodeType.CatchClause;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Node} node
|
||||
* @returns {boolean}
|
||||
@@ -132,42 +124,6 @@ export class NodeGuards {
|
||||
&& !('directive' in node);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Node} node
|
||||
* @returns {boolean}
|
||||
*/
|
||||
public static isForStatementTypeNode (
|
||||
node: ESTree.Node
|
||||
): node is ESTree.ForStatement | ESTree.ForInStatement | ESTree.ForOfStatement {
|
||||
return NodeGuards.isForStatementNode(node)
|
||||
|| NodeGuards.isForInStatementNode(node)
|
||||
|| NodeGuards.isForOfStatementNode(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Node} node
|
||||
* @returns {boolean}
|
||||
*/
|
||||
public static isForStatementNode (node: ESTree.Node): node is ESTree.ForStatement {
|
||||
return node.type === NodeType.ForStatement;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Node} node
|
||||
* @returns {boolean}
|
||||
*/
|
||||
public static isForInStatementNode (node: ESTree.Node): node is ESTree.ForInStatement {
|
||||
return node.type === NodeType.ForInStatement;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Node} node
|
||||
* @returns {boolean}
|
||||
*/
|
||||
public static isForOfStatementNode (node: ESTree.Node): node is ESTree.ForOfStatement {
|
||||
return node.type === NodeType.ForOfStatement;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Node} node
|
||||
* @returns {boolean}
|
||||
@@ -204,14 +160,6 @@ export class NodeGuards {
|
||||
return node.type === NodeType.Identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Node} node
|
||||
* @returns {boolean}
|
||||
*/
|
||||
public static isIfStatementNode (node: ESTree.Node): node is ESTree.IfStatement {
|
||||
return node.type === NodeType.IfStatement;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Node} node
|
||||
* @returns {boolean}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import * as ESTree from 'estree';
|
||||
|
||||
import { NodeGuards } from './NodeGuards';
|
||||
|
||||
export class NodeLiteralUtils {
|
||||
/**
|
||||
* @param {Literal} literalNode
|
||||
* @param {Node} parentNode
|
||||
* @returns {boolean}
|
||||
*/
|
||||
public static isProhibitedLiteralNode (literalNode: ESTree.Literal, parentNode: ESTree.Node): boolean {
|
||||
if (NodeGuards.isPropertyNode(parentNode) && !parentNode.computed && parentNode.key === literalNode) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (NodeGuards.isImportDeclarationNode(parentNode)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -218,6 +218,7 @@ export class StringArrayStorage extends MapStorage <string, IStringArrayStorageI
|
||||
return Array
|
||||
.from(this.storage.values())
|
||||
.map((stringArrayStorageItemData: IStringArrayStorageItemData) => {
|
||||
// we have to encode here, because of possible errors during `parse` of StringArrayCustomNode
|
||||
return `'${this.escapeSequenceEncoder.encode(
|
||||
stringArrayStorageItemData.encodedValue,
|
||||
this.options.unicodeEscapeSequence
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
import { IObjectExpressionExtractor } from '../../../interfaces/node-transformers/converting-transformers/object-expression-extractors/IObjectExpressionExtractor';
|
||||
|
||||
import { ObjectExpressionExtractor } from '../../../enums/node-transformers/converting-transformers/properties-extractors/ObjectExpressionExtractor';
|
||||
|
||||
export type TObjectExpressionExtractorFactory =
|
||||
(objectExpressionExtractorName: ObjectExpressionExtractor) => IObjectExpressionExtractor;
|
||||
@@ -1,5 +0,0 @@
|
||||
import { IPropertiesExtractor } from '../../../interfaces/node-transformers/converting-transformers/properties-extractors/IPropertiesExtractor';
|
||||
|
||||
import { PropertiesExtractor } from '../../../enums/node-transformers/converting-transformers/properties-extractors/PropertiesExtractor';
|
||||
|
||||
export type TPropertiesExtractorFactory = (propertiesExtractorName: PropertiesExtractor) => IPropertiesExtractor;
|
||||
+5
-6
@@ -7,15 +7,14 @@ import { NO_ADDITIONAL_NODES_PRESET } from '../../src/options/presets/NoCustomNo
|
||||
|
||||
let obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
|
||||
`
|
||||
const foo = \`\${{
|
||||
foo: 'bar',
|
||||
baz: 'bark'
|
||||
}.baz}\`;
|
||||
console.log(foo);
|
||||
var foo = {['foo']: 1};
|
||||
`,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
transformObjectKeys: true
|
||||
compact: false,
|
||||
unicodeEscapeSequence: true,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
|
||||
|
||||
+279
-29
@@ -39,10 +39,11 @@ describe('ObjectExpressionKeysTransformer', () => {
|
||||
|
||||
describe('Variant #2: variable declaration without initialization', () => {
|
||||
const match: string = `` +
|
||||
`var *${variableMatch};` +
|
||||
`${variableMatch} *= *{};` +
|
||||
`var ${variableMatch};` +
|
||||
`var ${variableMatch} *= *{};` +
|
||||
`${variableMatch}\\['foo'] *= *'bar';` +
|
||||
`${variableMatch}\\['baz'] *= *'bark';` +
|
||||
`${variableMatch} *= *${variableMatch};` +
|
||||
``;
|
||||
const regExp: RegExp = new RegExp(match);
|
||||
|
||||
@@ -151,11 +152,14 @@ describe('ObjectExpressionKeysTransformer', () => {
|
||||
|
||||
describe('Variant #6: nested objects #1', () => {
|
||||
const match: string = `` +
|
||||
`var *${variableMatch} *= *{};` +
|
||||
`${variableMatch}\\['baz'] *= *'bark';` +
|
||||
`var *${variableMatch} *= *{};` +
|
||||
`${variableMatch}\\['inner1'] *= *${variableMatch};` +
|
||||
`var *${variableMatch} *= *{};` +
|
||||
`${variableMatch}\\['foo'] *= *'bar';` +
|
||||
`${variableMatch}\\['inner'] *= *{};` +
|
||||
`${variableMatch}\\['inner']\\['inner1'] *= *{};` +
|
||||
`${variableMatch}\\['inner']\\['inner1']\\['baz'] *= *'bark';` +
|
||||
`${variableMatch}\\['inner'] *= *${variableMatch};` +
|
||||
`var object *= *${variableMatch};` +
|
||||
``;
|
||||
const regExp: RegExp = new RegExp(match);
|
||||
|
||||
@@ -180,14 +184,17 @@ describe('ObjectExpressionKeysTransformer', () => {
|
||||
|
||||
describe('Variant #7: nested objects #2', () => {
|
||||
const match: string = `` +
|
||||
`var *${variableMatch} *= *{};` +
|
||||
`${variableMatch}\\['hawk'] *= *'geek';` +
|
||||
`var *${variableMatch} *= *{};` +
|
||||
`${variableMatch}\\['baz'] *= *'bark';` +
|
||||
`${variableMatch}\\['inner1'] *= *${variableMatch};` +
|
||||
`${variableMatch}\\['cow'] *= *'bear';` +
|
||||
`var *${variableMatch} *= *{};` +
|
||||
`${variableMatch}\\['foo'] *= *'bar';` +
|
||||
`${variableMatch}\\['inner'] *= *{};` +
|
||||
`${variableMatch}\\['inner'] *= *${variableMatch};` +
|
||||
`${variableMatch}\\['ball'] *= *'door';` +
|
||||
`${variableMatch}\\['inner']\\['baz'] *= *'bark';` +
|
||||
`${variableMatch}\\['inner']\\['inner1'] *= *{};` +
|
||||
`${variableMatch}\\['inner']\\['cow'] *= *'bear';` +
|
||||
`${variableMatch}\\['inner']\\['inner1']\\['hawk'] *= *'geek';` +
|
||||
`var *object *= *${variableMatch};` +
|
||||
``;
|
||||
const regExp: RegExp = new RegExp(match);
|
||||
|
||||
@@ -251,6 +258,7 @@ describe('ObjectExpressionKeysTransformer', () => {
|
||||
`${variableMatch}\\['\\w{5}'] *= *function *\\(${variableMatch}, *${variableMatch}\\) *{` +
|
||||
`return *${variableMatch} *\\+ *${variableMatch};` +
|
||||
`};` +
|
||||
`var *${variableMatch} *= *${variableMatch};` +
|
||||
`var *${variableMatch} *= *${variableMatch}\\['\\w{5}']\\(0x1, *0x2\\);` +
|
||||
``;
|
||||
const regExp: RegExp = new RegExp(match);
|
||||
@@ -282,6 +290,7 @@ describe('ObjectExpressionKeysTransformer', () => {
|
||||
`${variableMatch}\\['\\w{5}'] *= *function *\\(${variableMatch}, *${variableMatch}\\) *{` +
|
||||
`return *${variableMatch} *\\+ *${variableMatch};` +
|
||||
`};` +
|
||||
`var *${variableMatch} *= *${variableMatch};` +
|
||||
`var *${variableMatch} *= *{};` +
|
||||
`${variableMatch}\\['foo'] *= *0x1;` +
|
||||
`var *${variableMatch} *= *{};` +
|
||||
@@ -367,6 +376,31 @@ describe('ObjectExpressionKeysTransformer', () => {
|
||||
assert.match(obfuscatedCode, regExp);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #3', () => {
|
||||
const match: string = `` +
|
||||
`var *${variableMatch} *= *0x1, *${variableMatch} *= *{'foo' *: *${variableMatch}};` +
|
||||
``;
|
||||
const regExp: RegExp = new RegExp(match);
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/variable-declarator-with-object-call-6.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
transformObjectKeys: true
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('should transform object keys', () => {
|
||||
assert.match(obfuscatedCode, regExp);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #12: assignment expression and member expression', () => {
|
||||
@@ -452,15 +486,164 @@ describe('ObjectExpressionKeysTransformer', () => {
|
||||
assert.match(obfuscatedCode, regExp);
|
||||
});
|
||||
});
|
||||
|
||||
// issue https://github.com/javascript-obfuscator/javascript-obfuscator/issues/516
|
||||
describe('Variant #15: function default values', () => {
|
||||
const match: string = `` +
|
||||
`var *${variableMatch} *= *{};` +
|
||||
`${variableMatch}\\['value'] *= *0x1;` +
|
||||
`function test *\\(${variableMatch} *= *0x1, *${variableMatch} *= *${variableMatch}\\) *{ *}` +
|
||||
``;
|
||||
const regExp: RegExp = new RegExp(match);
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/function-default-values.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
transformObjectKeys: true
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('shouldn ignore default parameter object if it references other parameter', () => {
|
||||
assert.match(obfuscatedCode, regExp);
|
||||
});
|
||||
});
|
||||
|
||||
// issue https://github.com/javascript-obfuscator/javascript-obfuscator/issues/516
|
||||
describe('Variant #16: object expression inside inside variable declaration', () => {
|
||||
describe('Without reference on other property', () => {
|
||||
describe('Variant #1: Single variable declarator and object expression parent node is expression node', () => {
|
||||
const match: string = `` +
|
||||
`var *passthrough *= *${variableMatch} *=> *${variableMatch};` +
|
||||
`var *${variableMatch} *= *{};` +
|
||||
`${variableMatch}\\['foo'] *= *0x1;` +
|
||||
`var foo *= *passthrough *\\(${variableMatch}\\);` +
|
||||
``;
|
||||
const regExp: RegExp = new RegExp(match);
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/object-expression-inside-variable-declaration-1.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
transformObjectKeys: true
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('should transform object expression keys', () => {
|
||||
assert.match(obfuscatedCode, regExp);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #2: Multiple variable declarators and object expression parent node is variable declarator node', () => {
|
||||
const match: string = `` +
|
||||
`var ${variableMatch} *= *{};` +
|
||||
`${variableMatch}\\['foo'] *= *0x1;` +
|
||||
`var ${variableMatch} *= *{};` +
|
||||
`${variableMatch}\\['bar'] *= *0x2;` +
|
||||
`var foo *= *${variableMatch}, *bar *= *${variableMatch};` +
|
||||
``;
|
||||
const regExp: RegExp = new RegExp(match);
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/object-expression-inside-variable-declaration-2.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
transformObjectKeys: true
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('should transform object expressions keys', () => {
|
||||
assert.match(obfuscatedCode, regExp);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('With reference on other property', () => {
|
||||
describe('Variant #1: Object expression parent node is variable declarator node', () => {
|
||||
const match: string = `` +
|
||||
`var *passthrough *= *${variableMatch} *=> *${variableMatch};` +
|
||||
`var *${variableMatch} *= *{};` +
|
||||
`${variableMatch}\\['foo'] *= *0x1;` +
|
||||
`var foo *= *${variableMatch}, *bar *= *{'bar': *foo\\['foo']};` +
|
||||
``;
|
||||
const regExp: RegExp = new RegExp(match);
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/object-expression-inside-variable-declaration-3.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
transformObjectKeys: true
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('should transform first object expression keys and ignore second object expression keys', () => {
|
||||
assert.match(obfuscatedCode, regExp);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #2: Object expression parent node is any expression node', () => {
|
||||
const match: string = `` +
|
||||
`var *passthrough *= *${variableMatch} *=> *${variableMatch};` +
|
||||
`var *${variableMatch} *= *{};` +
|
||||
`${variableMatch}\\['foo'] *= *0x1;` +
|
||||
`var foo *= *${variableMatch}, *bar *= *passthrough *\\({ *'bar' *: *foo\\['foo'] *}\\);` +
|
||||
``;
|
||||
const regExp: RegExp = new RegExp(match);
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/object-expression-inside-variable-declaration-4.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
transformObjectKeys: true
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('should transform first object expression keys and ignore second object expression keys', () => {
|
||||
assert.match(obfuscatedCode, regExp);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('member expression as host of object expression', () => {
|
||||
describe('Variant #1: simple', () => {
|
||||
const match: string = `` +
|
||||
`this\\['state'] *= *{};` +
|
||||
`this\\['state']\\['foo'] *= *'bar';` +
|
||||
`this\\['state']\\['baz'] *= *'bark';` +
|
||||
``;
|
||||
`var ${variableMatch} *= *{};` +
|
||||
`${variableMatch}\\['foo'] *= *'bar';` +
|
||||
`${variableMatch}\\['baz'] *= *'bark';` +
|
||||
`this\\['state'] *= *${variableMatch};` +
|
||||
``;
|
||||
const regExp: RegExp = new RegExp(match);
|
||||
|
||||
let obfuscatedCode: string;
|
||||
@@ -484,10 +667,11 @@ describe('ObjectExpressionKeysTransformer', () => {
|
||||
|
||||
describe('Variant #2: long members chain', () => {
|
||||
const match: string = `` +
|
||||
`this\\['state']\\['foo'] *= *{};` +
|
||||
`this\\['state']\\['foo']\\['foo'] *= *'bar';` +
|
||||
`this\\['state']\\['foo']\\['baz'] *= *'bark';` +
|
||||
``;
|
||||
`var ${variableMatch} *= *{};` +
|
||||
`${variableMatch}\\['foo'] *= *'bar';` +
|
||||
`${variableMatch}\\['baz'] *= *'bark';` +
|
||||
`this\\['state']\\['foo'] *= *${variableMatch};` +
|
||||
``;
|
||||
const regExp: RegExp = new RegExp(match);
|
||||
|
||||
let obfuscatedCode: string;
|
||||
@@ -515,10 +699,11 @@ describe('ObjectExpressionKeysTransformer', () => {
|
||||
describe('Variant #1: with block statement', () => {
|
||||
const match: string = `` +
|
||||
`if *\\(!!\\[]\\) *{` +
|
||||
`var *${variableMatch} *= *{};` +
|
||||
`${variableMatch}\\['foo'] *= *'bar';` +
|
||||
`var ${variableMatch} *= *{};` +
|
||||
`${variableMatch}\\['foo'] *= *'bar';` +
|
||||
`var ${variableMatch} *= *${variableMatch};` +
|
||||
`}` +
|
||||
``;
|
||||
``;
|
||||
const regExp: RegExp = new RegExp(match);
|
||||
|
||||
let obfuscatedCode: string;
|
||||
@@ -606,8 +791,9 @@ describe('ObjectExpressionKeysTransformer', () => {
|
||||
describe('Variant #1: with block statement', () => {
|
||||
const match: string = `` +
|
||||
`for *\\(var *${variableMatch} *= *0x0; *${variableMatch} *< *0xa; *${variableMatch}\\+\\+\\) *{` +
|
||||
`var *${variableMatch} *= *{};` +
|
||||
`var ${variableMatch} *= *{};` +
|
||||
`${variableMatch}\\['foo'] *= *'bar';` +
|
||||
`var ${variableMatch} *= *${variableMatch};` +
|
||||
`}` +
|
||||
``;
|
||||
const regExp: RegExp = new RegExp(match);
|
||||
@@ -666,8 +852,9 @@ describe('ObjectExpressionKeysTransformer', () => {
|
||||
const match: string = `` +
|
||||
`var ${variableMatch} *= *{};` +
|
||||
`for *\\(var *${variableMatch} in *${variableMatch}\\) *{` +
|
||||
`${variableMatch} *= *{};` +
|
||||
`var ${variableMatch} *= *{};` +
|
||||
`${variableMatch}\\['bar'] *= *'bar';` +
|
||||
`${variableMatch} *= *${variableMatch};` +
|
||||
`}` +
|
||||
``;
|
||||
const regExp: RegExp = new RegExp(match);
|
||||
@@ -726,8 +913,9 @@ describe('ObjectExpressionKeysTransformer', () => {
|
||||
const match: string = `` +
|
||||
`var ${variableMatch} *= *\\[];` +
|
||||
`for *\\(var *${variableMatch} of *${variableMatch}\\) *{` +
|
||||
`${variableMatch} *= *{};` +
|
||||
`var ${variableMatch} *= *{};` +
|
||||
`${variableMatch}\\['bar'] *= *'bar';` +
|
||||
`${variableMatch} *= *${variableMatch};` +
|
||||
`}` +
|
||||
``;
|
||||
const regExp: RegExp = new RegExp(match);
|
||||
@@ -787,6 +975,7 @@ describe('ObjectExpressionKeysTransformer', () => {
|
||||
`while *\\(!!\\[]\\) *{` +
|
||||
`var *${variableMatch} *= *{};` +
|
||||
`${variableMatch}\\['foo'] *= *'bar';` +
|
||||
`var ${variableMatch} *= *${variableMatch};` +
|
||||
`}` +
|
||||
``;
|
||||
const regExp: RegExp = new RegExp(match);
|
||||
@@ -873,6 +1062,7 @@ describe('ObjectExpressionKeysTransformer', () => {
|
||||
`try *{` +
|
||||
`var *${variableMatch} *= *{};` +
|
||||
`${variableMatch}\\['foo'] *= *'bar';` +
|
||||
`var ${variableMatch} *= *${variableMatch};` +
|
||||
`} *catch *\\(${variableMatch}\\) *{` +
|
||||
`}` +
|
||||
``;
|
||||
@@ -903,6 +1093,7 @@ describe('ObjectExpressionKeysTransformer', () => {
|
||||
`} *catch *\\(${variableMatch}\\) *{` +
|
||||
`var *${variableMatch} *= *{};` +
|
||||
`${variableMatch}\\['foo'] *= *'bar';` +
|
||||
`var ${variableMatch} *= *${variableMatch};` +
|
||||
`}` +
|
||||
``;
|
||||
const regExp: RegExp = new RegExp(match);
|
||||
@@ -932,6 +1123,7 @@ describe('ObjectExpressionKeysTransformer', () => {
|
||||
`case *!!\\[]:` +
|
||||
`var *${variableMatch} *= *{};` +
|
||||
`${variableMatch}\\['foo'] *= *'bar';` +
|
||||
`var ${variableMatch} *= *${variableMatch};` +
|
||||
`}` +
|
||||
``;
|
||||
const regExp: RegExp = new RegExp(match);
|
||||
@@ -960,6 +1152,7 @@ describe('ObjectExpressionKeysTransformer', () => {
|
||||
const match: string = `` +
|
||||
`const *${variableMatch} *= *{}; *` +
|
||||
`${variableMatch}\\['foo'] *= *'foo'; *` +
|
||||
`const ${variableMatch} *= *${variableMatch};` +
|
||||
`const *${variableMatch} *= *${variableMatch}\\['foo'];` +
|
||||
``;
|
||||
const regExp: RegExp = new RegExp(match);
|
||||
@@ -985,10 +1178,11 @@ describe('ObjectExpressionKeysTransformer', () => {
|
||||
|
||||
describe('Variant #2', () => {
|
||||
const match: string = `` +
|
||||
`const *${variableMatch} *= *0x1, *` +
|
||||
`${variableMatch} *= *{}; *` +
|
||||
`const ${variableMatch} *= *{}; *` +
|
||||
`${variableMatch}\\['foo'] *= *'foo'; *` +
|
||||
`const *${variableMatch} *= *${variableMatch}\\['foo'];` +
|
||||
`const ${variableMatch} *= *0x1, *` +
|
||||
`${variableMatch} *= *${variableMatch}; *` +
|
||||
`const ${variableMatch} *= *${variableMatch}\\['foo'];` +
|
||||
``;
|
||||
const regExp: RegExp = new RegExp(match);
|
||||
|
||||
@@ -1013,12 +1207,13 @@ describe('ObjectExpressionKeysTransformer', () => {
|
||||
|
||||
describe('Variant #3: two objects', () => {
|
||||
const match: string = `` +
|
||||
`var *${variableMatch} *= *{};` +
|
||||
`${variableMatch}\\['foo'] *= *'foo';` +
|
||||
`var *${variableMatch} *= *{};` +
|
||||
`${variableMatch}\\['bar'] *= *'bar';` +
|
||||
`var *${variableMatch} *= *{}, *` +
|
||||
`var *${variableMatch} *= *${variableMatch}, *` +
|
||||
`${variableMatch} *= *${variableMatch}, *` +
|
||||
`${variableMatch} *= *${variableMatch}\\['bar']; *` +
|
||||
`${variableMatch}\\['foo'] *= *'foo';` +
|
||||
`console\\['log']\\(${variableMatch}\\);` +
|
||||
``;
|
||||
const regExp: RegExp = new RegExp(match);
|
||||
@@ -1176,5 +1371,60 @@ describe('ObjectExpressionKeysTransformer', () => {
|
||||
assert.match(obfuscatedCode, regExp);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #3: function default value reference', () => {
|
||||
const match: string = `` +
|
||||
`function test *\\(${variableMatch} *= *0x1, *${variableMatch} *= *{'value' *: *${variableMatch}}\\) *{ *}` +
|
||||
``;
|
||||
const regExp: RegExp = new RegExp(match);
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/function-default-value-reference.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
transformObjectKeys: true
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('shouldn ignore default parameter object if it references other parameter', () => {
|
||||
assert.match(obfuscatedCode, regExp);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #4: member expression node as property key', () => {
|
||||
const match: string = `` +
|
||||
`var ${variableMatch} *= *{};` +
|
||||
`${variableMatch}\\['foo'] *= *'test';` +
|
||||
`var foo *= *${variableMatch};` +
|
||||
`var ${variableMatch} *= *{\\[foo\\['foo']] *: *'1'};` +
|
||||
`${variableMatch}\\['bar'] *= *'2';` +
|
||||
`var bar *= *${variableMatch};` +
|
||||
``;
|
||||
const regExp: RegExp = new RegExp(match);
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/computed-key-member-expression.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
transformObjectKeys: true
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('shouldn ignore extraction of property with member expression key', () => {
|
||||
assert.match(obfuscatedCode, regExp);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
var foo = {
|
||||
foo: 'test'
|
||||
};
|
||||
var bar = {
|
||||
[foo.foo]: '1',
|
||||
bar: '2'
|
||||
};
|
||||
+1
@@ -0,0 +1 @@
|
||||
function test (param1 = 1, param2 = {value: param1}) {}
|
||||
+1
@@ -0,0 +1 @@
|
||||
function test (param1 = 1, param2 = {value: 1}) {}
|
||||
+7
-9
@@ -1,10 +1,8 @@
|
||||
(function(){
|
||||
var object = {
|
||||
foo: 'bar',
|
||||
inner: {
|
||||
inner1: {
|
||||
baz: 'bark'
|
||||
}
|
||||
var object = {
|
||||
foo: 'bar',
|
||||
inner: {
|
||||
inner1: {
|
||||
baz: 'bark'
|
||||
}
|
||||
};
|
||||
})();
|
||||
}
|
||||
};
|
||||
+11
-13
@@ -1,14 +1,12 @@
|
||||
(function(){
|
||||
var object = {
|
||||
foo: 'bar',
|
||||
inner: {
|
||||
baz: 'bark',
|
||||
inner1: {
|
||||
hawk: 'geek'
|
||||
},
|
||||
cow: 'bear',
|
||||
|
||||
var object = {
|
||||
foo: 'bar',
|
||||
inner: {
|
||||
baz: 'bark',
|
||||
inner1: {
|
||||
hawk: 'geek'
|
||||
},
|
||||
ball: 'door',
|
||||
};
|
||||
})();
|
||||
cow: 'bear',
|
||||
|
||||
},
|
||||
ball: 'door',
|
||||
};
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
var passthrough = (object) => object;
|
||||
var foo = passthrough({foo: 1});
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
var foo = {foo: 1},
|
||||
bar = {bar: 2};
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
var passthrough = (object) => object;
|
||||
var foo = {foo: 1},
|
||||
bar = {bar: foo.foo};
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
var passthrough = (object) => object;
|
||||
var foo = {foo: 1},
|
||||
bar = passthrough({bar: foo.foo});
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
(function () {
|
||||
var object = 1,
|
||||
variable = {foo: object};
|
||||
})();
|
||||
+6
-1
@@ -165,6 +165,11 @@ describe('SplitStringTransformer', () => {
|
||||
|
||||
describe('Variant #10: Integration with `transformObjectKeys` option', () => {
|
||||
it('should correctly transform string when `transformObjectKeys` option is enabled', () => {
|
||||
const regExp: RegExp = new RegExp(`` +
|
||||
`var _0x[a-f0-9]{4,6} *= *{};` +
|
||||
`*_0x[a-f0-9]{4,6}\\['ab' *\\+ *'cd' *\\+ *'ef' *\\+ *'g'] *= *'ab' *\\+ *'cd' *\\+ *'ef' *\\+ *'g';` +
|
||||
`var test *= *_0x[a-f0-9]{4,6};` +
|
||||
``);
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/object-string-literal.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
@@ -179,7 +184,7 @@ describe('SplitStringTransformer', () => {
|
||||
|
||||
assert.match(
|
||||
obfuscatedCode,
|
||||
/^var *test *= *{}; *test\['ab' *\+ *'cd' *\+ *'ef' *\+ *'g'] *= *'ab' *\+ *'cd' *\+ *'ef' *\+ *'g';$/
|
||||
regExp
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
+60
-2
@@ -135,7 +135,7 @@ describe('LiteralTransformer', () => {
|
||||
|
||||
describe('Variant #6: `unicodeEscapeSequence` and `stringArray` options are enabled', () => {
|
||||
const stringArrayRegExp: RegExp = /^var *_0x([a-f0-9]){4} *= *\['\\x74\\x65\\x73\\x74'\];/;
|
||||
const stringArrayCallRegExp: RegExp = /var *test *= *_0x([a-f0-9]){4}\('0x0'\);/;
|
||||
const stringArrayCallRegExp: RegExp = /var *test *= *_0x([a-f0-9]){4}\('\\x30\\x78\\x30'\);/;
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
@@ -157,7 +157,7 @@ describe('LiteralTransformer', () => {
|
||||
assert.match(obfuscatedCode, stringArrayRegExp);
|
||||
});
|
||||
|
||||
it('match #1: should replace literal node value with unicode escape sequence from string array', () => {
|
||||
it('match #2: should replace literal node value with unicode escape sequence from string array', () => {
|
||||
assert.match(obfuscatedCode, stringArrayCallRegExp);
|
||||
});
|
||||
});
|
||||
@@ -518,6 +518,64 @@ describe('LiteralTransformer', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #13: object expression key literal', () => {
|
||||
describe('Variant #1: base key literal', () => {
|
||||
const stringArrayRegExp: RegExp = /^var _0x([a-f0-9]){4} *= *\['bar'];/;
|
||||
const objectExpressionRegExp: RegExp = /var test *= *{'foo' *: *_0x([a-f0-9]){4}\('0x0'\)};/;
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/object-expression-key-literal.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('match #1: should not add object expression key literal to the string array', () => {
|
||||
assert.match(obfuscatedCode, stringArrayRegExp);
|
||||
});
|
||||
|
||||
it('match #2: should keep object expression key literal', () => {
|
||||
assert.match(obfuscatedCode, objectExpressionRegExp);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #2: computed key literal', () => {
|
||||
const stringArrayRegExp: RegExp = /^var _0x([a-f0-9]){4} *= *\['foo', *'bar'];/;
|
||||
const objectExpressionRegExp: RegExp = /var test *= *{\[_0x([a-f0-9]){4}\('0x0'\)] *: *_0x([a-f0-9]){4}\('0x1'\)};/;
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/object-expression-computed-key-literal.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('match #1: should add object expression computed key literal to the string array', () => {
|
||||
assert.match(obfuscatedCode, stringArrayRegExp);
|
||||
});
|
||||
|
||||
it('match #2: should replace object expression computed key literal on call to the string array', () => {
|
||||
assert.match(obfuscatedCode, objectExpressionRegExp);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('transformation of literal node with boolean value', () => {
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
var test = {['foo']: 'bar'};
|
||||
+1
@@ -0,0 +1 @@
|
||||
var test = {'foo': 'bar'};
|
||||
@@ -28,6 +28,7 @@ import './unit-tests/node/node-appender/NodeAppender.spec';
|
||||
import './unit-tests/node/node-guards/NodeGuards.spec';
|
||||
import './unit-tests/node/node-metadata/NodeMetadata.spec';
|
||||
import './unit-tests/node/node-lexical-scope-utils/NodeLexicalScopeUtils.spec';
|
||||
import './unit-tests/node/node-literal-utils/NodeLiteralUtils.spec';
|
||||
import './unit-tests/node/node-statement-utils/NodeStatementUtils.spec';
|
||||
import './unit-tests/node/node-utils/NodeUtils.spec';
|
||||
import './unit-tests/node-transformers/preparing-transformers/ObfuscatingGuardsTransformer.spec';
|
||||
|
||||
+49
@@ -157,6 +157,55 @@ describe('StringArrayStorageAnalyzer', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Analyzes of the AST tree with prohibited string literal nodes', () => {
|
||||
const literalNode1: ESTree.Literal = NodeFactory.literalNode('foo');
|
||||
const literalNode2: ESTree.Literal = NodeFactory.literalNode('bar');
|
||||
|
||||
const expectedStringArrayStorageItemData1: IStringArrayStorageItemData = {
|
||||
encodedValue: 'foo',
|
||||
decodeKey: null,
|
||||
index: 0,
|
||||
value: 'foo'
|
||||
};
|
||||
const expectedStringArrayStorageItemData2: undefined = undefined;
|
||||
|
||||
let stringArrayStorageItemData1: IStringArrayStorageItemData | undefined;
|
||||
let stringArrayStorageItemData2: IStringArrayStorageItemData | undefined;
|
||||
|
||||
before(() => {
|
||||
stringArrayStorageAnalyzer = getStringArrayStorageAnalyzer({
|
||||
stringArrayThreshold: 1
|
||||
});
|
||||
|
||||
const astTree: ESTree.Program = NodeFactory.programNode([
|
||||
NodeFactory.expressionStatementNode(literalNode1),
|
||||
NodeFactory.variableDeclarationNode([
|
||||
NodeFactory.variableDeclaratorNode(
|
||||
NodeFactory.identifierNode('bar'),
|
||||
NodeFactory.objectExpressionNode([
|
||||
NodeFactory.propertyNode(
|
||||
literalNode2,
|
||||
NodeFactory.literalNode(1)
|
||||
)
|
||||
])
|
||||
)
|
||||
])
|
||||
]);
|
||||
|
||||
stringArrayStorageAnalyzer.analyze(astTree);
|
||||
stringArrayStorageItemData1 = stringArrayStorageAnalyzer.getItemDataForLiteralNode(literalNode1);
|
||||
stringArrayStorageItemData2 = stringArrayStorageAnalyzer.getItemDataForLiteralNode(literalNode2);
|
||||
});
|
||||
|
||||
it('Variant #1: should return correct string array storage item data for literal node #1', () => {
|
||||
assert.deepEqual(stringArrayStorageItemData1, expectedStringArrayStorageItemData1);
|
||||
});
|
||||
|
||||
it('Variant #2: should return correct string array storage item data for literal node #1', () => {
|
||||
assert.deepEqual(stringArrayStorageItemData2, expectedStringArrayStorageItemData2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Analyzes of the AST tree with ignored nodes', () => {
|
||||
const literalNode1: ESTree.Literal = NodeFactory.literalNode('foo');
|
||||
const literalNode2: ESTree.Literal = NodeFactory.literalNode('bar');
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
import * as ESTree from 'estree';
|
||||
|
||||
import { assert } from 'chai';
|
||||
|
||||
import { NodeFactory } from '../../../../src/node/NodeFactory';
|
||||
import { NodeLiteralUtils } from '../../../../src/node/NodeLiteralUtils';
|
||||
|
||||
describe('NodeLiteralUtils', () => {
|
||||
describe('isProhibitedLiteralNode', () => {
|
||||
describe('String literal node', () => {
|
||||
describe('Variant #1: base string literal node', () => {
|
||||
const literalNode: ESTree.Literal = NodeFactory.literalNode('foo');
|
||||
|
||||
let statementNode: ESTree.Statement;
|
||||
|
||||
before(() => {
|
||||
statementNode = NodeFactory.expressionStatementNode(
|
||||
literalNode
|
||||
);
|
||||
|
||||
literalNode.parentNode = statementNode;
|
||||
});
|
||||
|
||||
it('should return false for base string literal node', () => {
|
||||
assert.equal(NodeLiteralUtils.isProhibitedLiteralNode(literalNode, statementNode), false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #2: property literal node', () => {
|
||||
describe('Variant #1: property key literal node', () => {
|
||||
const literalNode: ESTree.Literal = NodeFactory.literalNode('foo');
|
||||
|
||||
let propertyNode: ESTree.Property;
|
||||
|
||||
before(() => {
|
||||
propertyNode = NodeFactory.propertyNode(
|
||||
literalNode,
|
||||
NodeFactory.literalNode(1)
|
||||
);
|
||||
|
||||
literalNode.parentNode = propertyNode;
|
||||
});
|
||||
|
||||
it('should return false for property key literal node', () => {
|
||||
assert.equal(NodeLiteralUtils.isProhibitedLiteralNode(literalNode, propertyNode), true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #2: computed property key literal node', () => {
|
||||
const literalNode: ESTree.Literal = NodeFactory.literalNode('foo');
|
||||
|
||||
let propertyNode: ESTree.Property;
|
||||
|
||||
before(() => {
|
||||
propertyNode = NodeFactory.propertyNode(
|
||||
literalNode,
|
||||
NodeFactory.literalNode(1),
|
||||
true
|
||||
);
|
||||
|
||||
literalNode.parentNode = propertyNode;
|
||||
});
|
||||
|
||||
it('should return false for computed property key literal node', () => {
|
||||
assert.equal(NodeLiteralUtils.isProhibitedLiteralNode(literalNode, propertyNode), false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #3: property value literal node', () => {
|
||||
const literalNode: ESTree.Literal = NodeFactory.literalNode('foo');
|
||||
|
||||
let propertyNode: ESTree.Property;
|
||||
|
||||
before(() => {
|
||||
propertyNode = NodeFactory.propertyNode(
|
||||
NodeFactory.literalNode(1),
|
||||
literalNode
|
||||
);
|
||||
|
||||
literalNode.parentNode = propertyNode;
|
||||
});
|
||||
|
||||
it('should return false for property value literal node', () => {
|
||||
assert.equal(NodeLiteralUtils.isProhibitedLiteralNode(literalNode, propertyNode), false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #3: import declaration node', () => {
|
||||
describe('Variant #1: base import declaration literal node', () => {
|
||||
const literalNode: ESTree.Literal = NodeFactory.literalNode('foo');
|
||||
|
||||
let importDeclarationNode: ESTree.ImportDeclaration;
|
||||
|
||||
before(() => {
|
||||
importDeclarationNode = NodeFactory.importDeclarationNode(
|
||||
[],
|
||||
literalNode
|
||||
);
|
||||
|
||||
literalNode.parentNode = importDeclarationNode;
|
||||
});
|
||||
|
||||
it('should return false for import declaration literal node', () => {
|
||||
assert.equal(NodeLiteralUtils.isProhibitedLiteralNode(literalNode, importDeclarationNode), true);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Number literal node', () => {
|
||||
describe('Variant #1: base number literal node', () => {
|
||||
const literalNode: ESTree.Literal = NodeFactory.literalNode(1);
|
||||
|
||||
let statementNode: ESTree.Statement;
|
||||
|
||||
before(() => {
|
||||
statementNode = NodeFactory.expressionStatementNode(
|
||||
literalNode
|
||||
);
|
||||
|
||||
const blockStatementNode: ESTree.BlockStatement = NodeFactory.blockStatementNode([
|
||||
statementNode
|
||||
]);
|
||||
|
||||
statementNode.parentNode = blockStatementNode;
|
||||
literalNode.parentNode = statementNode;
|
||||
});
|
||||
|
||||
it('should return false for base number literal node', () => {
|
||||
assert.equal(NodeLiteralUtils.isProhibitedLiteralNode(literalNode, statementNode), false);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user