mirror of
https://github.com/javascript-obfuscator/javascript-obfuscator
synced 2026-08-09 12:42:29 +00:00
172 lines
5.5 KiB
TypeScript
172 lines
5.5 KiB
TypeScript
import * as ESTree from 'estree';
|
|
|
|
import { TNodeWithBlockScope } from '../types/node/TNodeWithBlockScope';
|
|
import { TStatement } from '../types/node/TStatement';
|
|
|
|
import { IStackTraceData } from '../interfaces/analyzers/stack-trace-analyzer/IStackTraceData';
|
|
import { TNodeWithScope } from '../types/node/TNodeWithScope';
|
|
import { NodeGuards } from './NodeGuards';
|
|
|
|
export class NodeAppender {
|
|
/**
|
|
* @param {TNodeWithScope} scopeNode
|
|
* @param {TStatement[]} scopeStatements
|
|
*/
|
|
public static appendNode (scopeNode: TNodeWithScope, scopeStatements: TStatement[]): void {
|
|
scopeStatements = NodeAppender.parentizeScopeStatementsBeforeAppend(scopeNode, scopeStatements);
|
|
|
|
NodeAppender.setScopeNodeStatements(scopeNode, [
|
|
...NodeAppender.getScopeNodeStatements(scopeNode),
|
|
...scopeStatements
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Appends node into a first deepest BlockStatement in order of function calls
|
|
*
|
|
* For example:
|
|
*
|
|
* function Foo () {
|
|
* var baz = function () {
|
|
*
|
|
* }
|
|
*
|
|
* baz();
|
|
* }
|
|
*
|
|
* foo();
|
|
*
|
|
* Appends node into block statement of `baz` function expression
|
|
*
|
|
* @param {IStackTraceData[]} blockScopeStackTraceData
|
|
* @param {TNodeWithBlockScope} blockScopeNode
|
|
* @param {TStatement[]} nodeBodyStatements
|
|
* @param {number} index
|
|
*/
|
|
public static appendNodeToOptimalBlockScope (
|
|
blockScopeStackTraceData: IStackTraceData[],
|
|
blockScopeNode: TNodeWithBlockScope,
|
|
nodeBodyStatements: TStatement[],
|
|
index: number = 0
|
|
): void {
|
|
let targetBlockScope: TNodeWithBlockScope;
|
|
|
|
if (!blockScopeStackTraceData.length) {
|
|
targetBlockScope = blockScopeNode;
|
|
} else {
|
|
targetBlockScope = NodeAppender.getOptimalBlockScope(
|
|
blockScopeStackTraceData,
|
|
index
|
|
);
|
|
}
|
|
|
|
NodeAppender.prependNode(targetBlockScope, nodeBodyStatements);
|
|
}
|
|
|
|
/**
|
|
* Returns deepest block scope node at given deep.
|
|
*
|
|
* @param {IStackTraceData[]} blockScopeTraceData
|
|
* @param {number} index
|
|
* @param {number} deep
|
|
* @returns {BlockStatement}
|
|
*/
|
|
public static getOptimalBlockScope (
|
|
blockScopeTraceData: IStackTraceData[],
|
|
index: number,
|
|
deep: number = Infinity
|
|
): ESTree.BlockStatement {
|
|
const firstCall: IStackTraceData = blockScopeTraceData[index];
|
|
|
|
if (deep <= 0) {
|
|
throw new Error(`Invalid \`deep\` argument value. Value should be bigger then 0.`);
|
|
}
|
|
|
|
if (deep > 1 && firstCall.stackTrace.length) {
|
|
return NodeAppender.getOptimalBlockScope(firstCall.stackTrace, 0, --deep);
|
|
} else {
|
|
return firstCall.callee;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {TNodeWithScope} scopeNode
|
|
* @param {TStatement[]} scopeStatements
|
|
* @param {Node} targetStatement
|
|
*/
|
|
public static insertNodeAfter (scopeNode: TNodeWithScope, scopeStatements: TStatement[], targetStatement: ESTree.Statement): void {
|
|
const indexInScopeStatement: number = NodeAppender
|
|
.getScopeNodeStatements(scopeNode)
|
|
.indexOf(targetStatement);
|
|
|
|
NodeAppender.insertNodeAtIndex(scopeNode, scopeStatements, indexInScopeStatement + 1);
|
|
}
|
|
|
|
/**
|
|
* @param {TNodeWithScope} scopeNode
|
|
* @param {TStatement[]} scopeStatements
|
|
* @param {number} index
|
|
*/
|
|
public static insertNodeAtIndex (scopeNode: TNodeWithScope, scopeStatements: TStatement[], index: number): void {
|
|
scopeStatements = NodeAppender.parentizeScopeStatementsBeforeAppend(scopeNode, scopeStatements);
|
|
|
|
NodeAppender.setScopeNodeStatements(scopeNode, [
|
|
...NodeAppender.getScopeNodeStatements(scopeNode).slice(0, index),
|
|
...scopeStatements,
|
|
...NodeAppender.getScopeNodeStatements(scopeNode).slice(index)
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* @param {TNodeWithScope} scopeNode
|
|
* @param {TStatement[]} scopeStatements
|
|
*/
|
|
public static prependNode (scopeNode: TNodeWithScope, scopeStatements: TStatement[]): void {
|
|
scopeStatements = NodeAppender.parentizeScopeStatementsBeforeAppend(scopeNode, scopeStatements);
|
|
|
|
NodeAppender.setScopeNodeStatements(scopeNode, [
|
|
...scopeStatements,
|
|
...NodeAppender.getScopeNodeStatements(scopeNode),
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* @param {TNodeWithScope} scopeNode
|
|
* @returns {TStatement[]}
|
|
*/
|
|
private static getScopeNodeStatements (scopeNode: TNodeWithScope): TStatement[] {
|
|
if (NodeGuards.isSwitchCaseNode(scopeNode)) {
|
|
return scopeNode.consequent;
|
|
}
|
|
|
|
return scopeNode.body;
|
|
}
|
|
|
|
/**
|
|
* @param {TNodeWithScope} scopeNode
|
|
* @param {TStatement[]} scopeStatements
|
|
* @returns {TStatement[]}
|
|
*/
|
|
private static parentizeScopeStatementsBeforeAppend (scopeNode: TNodeWithScope, scopeStatements: TStatement[]): TStatement[] {
|
|
scopeStatements.forEach((statement: TStatement) => {
|
|
statement.parentNode = scopeNode;
|
|
});
|
|
|
|
return scopeStatements;
|
|
}
|
|
|
|
/**
|
|
* @param {TNodeWithScope} scopeNode
|
|
* @param {TStatement[]} statements
|
|
*/
|
|
private static setScopeNodeStatements (scopeNode: TNodeWithScope, statements: TStatement[]): void {
|
|
if (NodeGuards.isSwitchCaseNode(scopeNode)) {
|
|
scopeNode.consequent = <ESTree.Statement[]>statements;
|
|
|
|
return;
|
|
}
|
|
|
|
scopeNode.body = statements;
|
|
}
|
|
}
|