mirror of
https://github.com/javascript-obfuscator/javascript-obfuscator
synced 2026-08-09 12:42:29 +00:00
227 lines
5.9 KiB
TypeScript
227 lines
5.9 KiB
TypeScript
import * as estraverse from 'estraverse';
|
|
|
|
import { IBlockStatementNode } from "./interfaces/nodes/IBlockStatementNode";
|
|
import { IIdentifierNode } from "./interfaces/nodes/IIdentifierNode";
|
|
import { ILiteralNode } from "./interfaces/nodes/ILiteralNode";
|
|
import { IMemberExpressionNode } from "./interfaces/nodes/IMemberExpressionNode";
|
|
import { IProgramNode } from "./interfaces/nodes/IProgramNode";
|
|
import { IPropertyNode } from "./interfaces/nodes/IPropertyNode";
|
|
import { INode } from './interfaces/nodes/INode';
|
|
import { IVariableDeclaratorNode } from "./interfaces/nodes/IVariableDeclaratorNode";
|
|
|
|
import { TBlockScopeNode } from "./types/TBlockScopeNode";
|
|
|
|
import { NodeType } from "./enums/NodeType";
|
|
|
|
import { Utils } from "./Utils";
|
|
|
|
export class NodeUtils {
|
|
/**
|
|
* @type {string[]}
|
|
*/
|
|
private static scopeNodes: string[] = [
|
|
NodeType.ArrowFunctionExpression,
|
|
NodeType.FunctionDeclaration,
|
|
NodeType.FunctionExpression,
|
|
NodeType.MethodDefinition
|
|
];
|
|
|
|
/**
|
|
* @param node
|
|
*/
|
|
public static addXVerbatimPropertyToLiterals (node: INode): void {
|
|
estraverse.replace(node, {
|
|
enter: (node: INode, parentNode: INode): any => {
|
|
if (NodeUtils.isLiteralNode(node)) {
|
|
node['x-verbatim-property'] = node.raw;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* @param blockScopeBody
|
|
* @param node
|
|
*/
|
|
public static appendNode (blockScopeBody: INode[], node: INode): void {
|
|
if (!NodeUtils.validateNode(node)) {
|
|
return;
|
|
}
|
|
|
|
blockScopeBody.push(node);
|
|
}
|
|
|
|
/**
|
|
* @param node
|
|
* @param index
|
|
* @returns {INode}
|
|
*/
|
|
public static getBlockScopeNodeByIndex (node: INode, index: number = 0): INode {
|
|
if (NodeUtils.isNodeHasBlockScope(node) && node.body[index]) {
|
|
return node.body[index];
|
|
}
|
|
|
|
return node;
|
|
}
|
|
|
|
/**
|
|
* @param node
|
|
* @param depth
|
|
* @returns {INode}
|
|
*/
|
|
public static getBlockScopeOfNode (node: INode, depth: number = 0): TBlockScopeNode {
|
|
if (!node.parentNode) {
|
|
throw new ReferenceError('`parentNode` property of given node is `undefined`');
|
|
}
|
|
|
|
if (node.parentNode.type === NodeType.Program) {
|
|
return <TBlockScopeNode> node.parentNode;
|
|
}
|
|
|
|
if (!Utils.arrayContains(NodeUtils.scopeNodes, node.parentNode.type)) {
|
|
return NodeUtils.getBlockScopeOfNode(node.parentNode, depth);
|
|
}
|
|
|
|
if (depth > 0) {
|
|
return NodeUtils.getBlockScopeOfNode(node.parentNode, --depth);
|
|
}
|
|
|
|
if (node.type !== NodeType.BlockStatement) {
|
|
return NodeUtils.getBlockScopeOfNode(node.parentNode);
|
|
}
|
|
|
|
return <TBlockScopeNode> node; // blocks statement of scopeNodes
|
|
}
|
|
|
|
/**
|
|
* @param bodyNode
|
|
* @returns IProgramNode
|
|
*/
|
|
public static getProgramNode (bodyNode: INode[]): IProgramNode {
|
|
return {
|
|
'type': NodeType.Program,
|
|
'body': bodyNode
|
|
};
|
|
}
|
|
|
|
/**
|
|
* @param blockScopeBody
|
|
* @param node
|
|
* @param index
|
|
*/
|
|
public static insertNodeAtIndex (blockScopeBody: INode[], node: INode, index: number): void {
|
|
if (!NodeUtils.validateNode(node)) {
|
|
return;
|
|
}
|
|
|
|
blockScopeBody.splice(index, 0, node);
|
|
}
|
|
|
|
/**
|
|
* @param node
|
|
* @returns {boolean}
|
|
*/
|
|
public static isBlockStatementNode (node: INode): node is IBlockStatementNode {
|
|
return node.type === NodeType.BlockStatement;
|
|
}
|
|
|
|
/**
|
|
* @param node
|
|
* @returns {boolean}
|
|
*/
|
|
public static isIdentifierNode (node: INode): node is IIdentifierNode {
|
|
return node.type === NodeType.Identifier;
|
|
}
|
|
|
|
/**
|
|
* @param node
|
|
* @returns {boolean}
|
|
*/
|
|
public static isLiteralNode (node: INode): node is ILiteralNode {
|
|
return node.type === NodeType.Literal;
|
|
}
|
|
|
|
/**
|
|
* @param node
|
|
* @returns {boolean}
|
|
*/
|
|
public static isMemberExpressionNode (node: INode): node is IMemberExpressionNode {
|
|
return node.type === NodeType.MemberExpression;
|
|
}
|
|
|
|
/**
|
|
* @param node
|
|
* @returns {boolean}
|
|
*/
|
|
public static isNodeHasBlockScope (node: INode): node is TBlockScopeNode {
|
|
return node.hasOwnProperty('body');
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param node
|
|
* @returns {boolean}
|
|
*/
|
|
public static isProgramNode (node: INode): node is IProgramNode {
|
|
return node.type === NodeType.Program;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param node
|
|
* @returns {boolean}
|
|
*/
|
|
public static isPropertyNode (node: INode): node is IPropertyNode {
|
|
return node.type === NodeType.Property;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param node
|
|
* @returns {boolean}
|
|
*/
|
|
public static isVariableDeclaratorNode (node: INode): node is IVariableDeclaratorNode {
|
|
return node.type === NodeType.VariableDeclarator;
|
|
}
|
|
|
|
/**
|
|
* @param node
|
|
*/
|
|
public static parentize (node: INode): void {
|
|
let isRootNode: boolean = true;
|
|
|
|
estraverse.replace(node, {
|
|
enter: (node: INode, parentNode: INode): any => {
|
|
Object.defineProperty(node, 'parentNode', {
|
|
configurable: true,
|
|
enumerable: true,
|
|
value: isRootNode ? NodeUtils.getProgramNode([node]) : parentNode || node,
|
|
writable: true
|
|
});
|
|
|
|
isRootNode = false;
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* @param blockScopeBody
|
|
* @param node
|
|
*/
|
|
public static prependNode (blockScopeBody: INode[], node: INode): void {
|
|
if (!NodeUtils.validateNode(node)) {
|
|
return;
|
|
}
|
|
|
|
blockScopeBody.unshift(node);
|
|
}
|
|
|
|
/**
|
|
* @param node
|
|
* @returns {boolean}
|
|
*/
|
|
private static validateNode (node: INode): boolean {
|
|
return !!node;
|
|
}
|
|
}
|