javascript-obfuscator
Version:
JavaScript obfuscator
173 lines (141 loc) • 6.86 kB
text/typescript
import { inject, injectable } from 'inversify';
import { ServiceIdentifiers } from '../container/ServiceIdentifiers';
import * as estraverse from 'estraverse';
import * as ESTree from 'estree';
import { TNodeTransformerFactory } from '../types/container/node-transformers/TNodeTransformerFactory';
import { TNormalizedNodeTransformers } from '../types/node-transformers/TNormalizedNodeTransformers';
import { TTransformersRunnerData } from '../types/node-transformers/TTransformersRunnerData';
import { TVisitorDirection } from '../types/node-transformers/TVisitorDirection';
import { TVisitorFunction } from '../types/node-transformers/TVisitorFunction';
import { TVisitorResult } from '../types/node-transformers/TVisitorResult';
import { INodeTransformer } from '../interfaces/node-transformers/INodeTransformer';
import { INodeTransformerNamesGroupsBuilder } from '../interfaces/utils/INodeTransformerNamesGroupsBuilder';
import { ITransformersRunner } from '../interfaces/node-transformers/ITransformersRunner';
import { IVisitor } from '../interfaces/node-transformers/IVisitor';
import { NodeTransformer } from '../enums/node-transformers/NodeTransformer';
import { TransformationStage } from '../enums/node-transformers/TransformationStage';
import { VisitorDirection } from '../enums/node-transformers/VisitorDirection';
import { NodeGuards } from '../node/NodeGuards';
import { NodeMetadata } from '../node/NodeMetadata';
export class TransformersRunner implements ITransformersRunner {
/**
* @type {Map<NodeTransformer[], TTransformersRunnerData>}
*/
private readonly cachedNodeTransformersData: Map<NodeTransformer[], TTransformersRunnerData> = new Map();
/**
* @type {TNodeTransformerFactory}
*/
private readonly nodeTransformerFactory: TNodeTransformerFactory;
/**
* @type {INodeTransformerNamesGroupsBuilder}
*/
private readonly nodeTransformerNamesGroupsBuilder: INodeTransformerNamesGroupsBuilder;
/**
* @param {TNodeTransformerFactory} nodeTransformerFactory
* @param {INodeTransformerNamesGroupsBuilder} nodeTransformerNamesGroupsBuilder
*/
public constructor (
nodeTransformerFactory: TNodeTransformerFactory,
nodeTransformerNamesGroupsBuilder: INodeTransformerNamesGroupsBuilder,
) {
this.nodeTransformerFactory = nodeTransformerFactory;
this.nodeTransformerNamesGroupsBuilder = nodeTransformerNamesGroupsBuilder;
}
/**
* @param {T} astTree
* @param {NodeTransformer[]} nodeTransformerNames
* @param {TransformationStage} transformationStage
* @returns {T}
*/
public transform <T extends ESTree.Node = ESTree.Program> (
astTree: T,
nodeTransformerNames: NodeTransformer[],
transformationStage: TransformationStage
): T {
if (!nodeTransformerNames.length) {
return astTree;
}
let normalizedNodeTransformers: TNormalizedNodeTransformers;
let nodeTransformerNamesGroups: NodeTransformer[][];
if (!this.cachedNodeTransformersData.has(nodeTransformerNames)) {
normalizedNodeTransformers = this.buildNormalizedNodeTransformers(nodeTransformerNames);
nodeTransformerNamesGroups = this.nodeTransformerNamesGroupsBuilder.build(normalizedNodeTransformers);
this.cachedNodeTransformersData.set(nodeTransformerNames, [normalizedNodeTransformers, nodeTransformerNamesGroups]);
} else {
[
normalizedNodeTransformers,
nodeTransformerNamesGroups
] = <TTransformersRunnerData>this.cachedNodeTransformersData.get(nodeTransformerNames);
}
for (const nodeTransformerNamesGroup of nodeTransformerNamesGroups) {
const enterVisitors: IVisitor[] = [];
const leaveVisitors: IVisitor[] = [];
for (const nodeTransformerName of nodeTransformerNamesGroup) {
const nodeTransformer: INodeTransformer = normalizedNodeTransformers[nodeTransformerName];
const visitor: IVisitor | null = nodeTransformer.getVisitor(transformationStage);
if (!visitor) {
continue;
}
if (visitor.enter) {
enterVisitors.push({ enter: visitor.enter });
}
if (visitor.leave) {
leaveVisitors.push({ leave: visitor.leave });
}
}
if (!enterVisitors.length && !leaveVisitors.length) {
continue;
}
estraverse.replace(astTree, {
enter: this.mergeVisitorsForDirection(enterVisitors, VisitorDirection.Enter),
leave: this.mergeVisitorsForDirection(leaveVisitors, VisitorDirection.Leave)
});
}
return astTree;
}
/**
* @param {NodeTransformer[]} nodeTransformerNames
* @returns {TNormalizedNodeTransformers}
*/
private buildNormalizedNodeTransformers (nodeTransformerNames: NodeTransformer[]): TNormalizedNodeTransformers {
return nodeTransformerNames
.reduce<TNormalizedNodeTransformers>(
(acc: TNormalizedNodeTransformers, nodeTransformerName: NodeTransformer) => ({
...acc,
[nodeTransformerName]: this.nodeTransformerFactory(nodeTransformerName)
}),
{}
);
}
/**
* @param {IVisitor[]} visitors
* @param {TVisitorDirection} direction
* @returns {TVisitorFunction}
*/
private mergeVisitorsForDirection (visitors: IVisitor[], direction: TVisitorDirection): TVisitorFunction {
const visitorsLength: number = visitors.length;
if (!visitorsLength) {
return (node: ESTree.Node, parentNode: ESTree.Node | null): ESTree.Node => node;
}
return (node: ESTree.Node, parentNode: ESTree.Node | null): ESTree.Node | estraverse.VisitorOption => {
if (NodeMetadata.isIgnoredNode(node)) {
return estraverse.VisitorOption.Skip;
}
for (let i: number = 0; i < visitorsLength; i++) {
const visitorFunction: TVisitorFunction | undefined = visitors[i][direction];
if (!visitorFunction) {
continue;
}
const visitorResult: TVisitorResult = visitorFunction(node, parentNode);
if (!visitorResult || !NodeGuards.isNode(visitorResult)) {
continue;
}
node = visitorResult;
}
return node;
};
}
}