浏览代码

added customNodesStorage over Map<string, ICustomNode>

sanex3339 8 年之前
父节点
当前提交
818e31b6bf
共有 25 个文件被更改,包括 424 次插入313 次删除
  1. 242 169
      dist/index.js
  2. 6 51
      src/Obfuscator.ts
  3. 1 0
      src/interfaces/IStorage.d.ts
  4. 6 5
      src/node-transformers/AbstractNodeTransformer.ts
  5. 7 6
      src/node-transformers/AbstractNodeTransformersFactory.ts
  6. 4 4
      src/node-transformers/node-control-flow-transformers/FunctionControlFlowTransformer.ts
  7. 5 5
      src/node-transformers/node-control-flow-transformers/control-flow-replacers/AbstractControlFlowReplacer.ts
  8. 5 4
      src/node-transformers/node-obfuscators/CatchClauseObfuscator.ts
  9. 5 4
      src/node-transformers/node-obfuscators/FunctionDeclarationObfuscator.ts
  10. 5 4
      src/node-transformers/node-obfuscators/FunctionObfuscator.ts
  11. 5 4
      src/node-transformers/node-obfuscators/LabeledStatementObfuscator.ts
  12. 3 3
      src/node-transformers/node-obfuscators/LiteralObfuscator.ts
  13. 2 2
      src/node-transformers/node-obfuscators/MemberExpressionObfuscator.ts
  14. 1 1
      src/node-transformers/node-obfuscators/MethodDefinitionObfuscator.ts
  15. 5 4
      src/node-transformers/node-obfuscators/VariableDeclarationObfuscator.ts
  16. 6 5
      src/node-transformers/node-obfuscators/replacers/AbstractReplacer.ts
  17. 3 11
      src/node-transformers/node-obfuscators/replacers/StringLiteralReplacer.ts
  18. 5 0
      src/storages/ArrayStorage.ts
  19. 5 0
      src/storages/MapStorage.ts
  20. 64 0
      src/storages/custom-nodes/CustomNodesStorage.ts
  21. 2 1
      src/types/TControlFlowReplacer.d.ts
  22. 2 1
      src/types/TNodeTransformer.d.ts
  23. 23 23
      test/fixtures/compile-performance.js
  24. 6 3
      test/unit-tests/node-transformers/node-obfuscators/FunctionDeclarationObfuscator.spec.ts
  25. 6 3
      test/unit-tests/node-transformers/node-obfuscators/FunctionObfuscator.spec.ts

文件差异内容过多而无法显示
+ 242 - 169
dist/index.js


+ 6 - 51
src/Obfuscator.ts

@@ -1,7 +1,6 @@
 import * as estraverse from 'estraverse';
 import * as ESTree from 'estree';
 
-import { TCustomNodesFactory } from './types/TCustomNodesFactory';
 import { TVisitorDirection } from './types/TVisitorDirection';
 
 import { ICustomNode } from './interfaces/custom-nodes/ICustomNode';
@@ -11,41 +10,21 @@ import { IOptions } from './interfaces/IOptions';
 import { INodeTransformer } from './interfaces/INodeTransformer';
 import { INodeTransformersFactory } from './interfaces/INodeTransformersFactory';
 import { IStackTraceAnalyzer } from './interfaces/stack-trace-analyzer/IStackTraceAnalyzer';
-import { IStackTraceData } from './interfaces/stack-trace-analyzer/IStackTraceData';
+import { IStorage } from './interfaces/IStorage';
 
 import { ObfuscationEvents } from './enums/ObfuscationEvents';
 import { VisitorDirection } from './enums/VisitorDirection';
 
-import { ConsoleOutputCustomNodesFactory } from './custom-nodes/console-output-nodes/factory/ConsoleOutputCustomNodesFactory';
-import { DebugProtectionCustomNodesFactory } from './custom-nodes/debug-protection-nodes/factory/DebugProtectionCustomNodesFactory';
-import { DomainLockCustomNodesFactory } from './custom-nodes/domain-lock-nodes/factory/DomainLockCustomNodesFactory';
 import { NodeControlFlowTransformersFactory } from './node-transformers/node-control-flow-transformers/factory/NodeControlFlowTransformersFactory';
 import { NodeObfuscatorsFactory } from './node-transformers/node-obfuscators/factory/NodeObfuscatorsFactory';
-import { SelfDefendingCustomNodesFactory } from './custom-nodes/self-defending-nodes/factory/SelfDefendingCustomNodesFactory';
-import { StringArrayCustomNodesFactory } from './custom-nodes/string-array-nodes/factory/StringArrayCustomNodesFactory';
 
+import { CustomNodesStorage } from './storages/custom-nodes/CustomNodesStorage';
 import { Node } from './node/Node';
 import { NodeUtils } from './node/NodeUtils';
 import { StackTraceAnalyzer } from './stack-trace-analyzer/StackTraceAnalyzer';
 import { ObfuscationEventEmitter } from './event-emitters/ObfuscationEventEmitter';
 
 export class Obfuscator implements IObfuscator {
-    /**
-     * @type {TCustomNodesFactory[]}
-     */
-    private static readonly customNodesFactories: TCustomNodesFactory[] = [
-        DomainLockCustomNodesFactory,
-        SelfDefendingCustomNodesFactory,
-        ConsoleOutputCustomNodesFactory,
-        DebugProtectionCustomNodesFactory,
-        StringArrayCustomNodesFactory
-    ];
-
-    /**
-     * @type {Map<string, AbstractCustomNode>}
-     */
-    private customNodes: Map <string, ICustomNode>;
-
     /**
      * @type {IOptions}
      */
@@ -71,22 +50,23 @@ export class Obfuscator implements IObfuscator {
 
         const obfuscationEventEmitter: IObfuscationEventEmitter = new ObfuscationEventEmitter();
         const stackTraceAnalyzer: IStackTraceAnalyzer = new StackTraceAnalyzer();
+        const customNodesStorage: IStorage<ICustomNode> = new CustomNodesStorage(this.options);
 
-        this.initializeCustomNodes(obfuscationEventEmitter, stackTraceAnalyzer.analyze(astTree.body));
+        customNodesStorage.initialize(obfuscationEventEmitter, stackTraceAnalyzer.analyze(astTree.body));
 
         obfuscationEventEmitter.emit(ObfuscationEvents.BeforeObfuscation, astTree);
 
         // first pass: control flow flattening
         if (this.options.controlFlowFlattening) {
             this.transformAstTree(astTree, VisitorDirection.leave, new NodeControlFlowTransformersFactory(
-                this.customNodes,
+                customNodesStorage,
                 this.options
             ));
         }
 
         // second pass: nodes obfuscation
         this.transformAstTree(astTree, VisitorDirection.enter, new NodeObfuscatorsFactory(
-            this.customNodes,
+            customNodesStorage,
             this.options
         ));
 
@@ -95,31 +75,6 @@ export class Obfuscator implements IObfuscator {
         return astTree;
     }
 
-    /**
-     * @param obfuscationEventEmitter
-     * @param stackTraceData
-     */
-    private initializeCustomNodes (obfuscationEventEmitter: IObfuscationEventEmitter, stackTraceData: IStackTraceData[]): void {
-        const customNodes: [string, ICustomNode][] = [];
-
-        Obfuscator.customNodesFactories.forEach((customNodesFactoryConstructor: TCustomNodesFactory) => {
-            const customNodesFactory: Map <string, ICustomNode> | undefined = new customNodesFactoryConstructor(
-                this.options
-            ).initializeCustomNodes(
-                obfuscationEventEmitter,
-                stackTraceData
-            );
-
-            if (!customNodesFactory) {
-                return;
-            }
-
-            customNodes.push(...customNodesFactory);
-        });
-
-        this.customNodes = new Map <string, ICustomNode> (customNodes);
-    }
-
     /**
      * @param astTree
      * @param direction

+ 1 - 0
src/interfaces/IStorage.d.ts

@@ -3,6 +3,7 @@ export interface IStorage <T> {
     getKeyOf (value: T): string | number | null;
     getLength (): number;
     getStorage (): any;
+    initialize (...args: any[]): void;
     set (key: string | number | null, value: T): void;
     toString (): string;
 }

+ 6 - 5
src/node-transformers/AbstractNodeTransformer.ts

@@ -3,12 +3,13 @@ import * as ESTree from 'estree';
 import { ICustomNode } from '../interfaces/custom-nodes/ICustomNode';
 import { INodeTransformer } from '../interfaces/INodeTransformer';
 import { IOptions } from '../interfaces/IOptions';
+import { IStorage } from '../interfaces/IStorage';
 
 export abstract class AbstractNodeTransformer implements INodeTransformer {
     /**
-     * @type Map <string, AbstractCustomNode>
+     * @type IStorage<ICustomNode>
      */
-    protected readonly nodes: Map <string, ICustomNode>;
+    protected readonly customNodesStorage: IStorage<ICustomNode>;
 
     /**
      * @type {IOptions}
@@ -16,11 +17,11 @@ export abstract class AbstractNodeTransformer implements INodeTransformer {
     protected readonly options: IOptions;
 
     /**
-     * @param nodes
+     * @param customNodesStorage
      * @param options
      */
-    constructor (nodes: Map <string, ICustomNode>, options: IOptions) {
-        this.nodes = nodes;
+    constructor (customNodesStorage: IStorage<ICustomNode>, options: IOptions) {
+        this.customNodesStorage = customNodesStorage;
         this.options = options;
     }
 

+ 7 - 6
src/node-transformers/AbstractNodeTransformersFactory.ts

@@ -4,6 +4,7 @@ import { ICustomNode } from '../interfaces/custom-nodes/ICustomNode';
 import { INodeTransformer } from '../interfaces/INodeTransformer';
 import { INodeTransformersFactory } from '../interfaces/INodeTransformersFactory';
 import { IOptions } from '../interfaces/IOptions';
+import { IStorage } from '../interfaces/IStorage';
 
 export abstract class AbstractNodeTransformersFactory implements INodeTransformersFactory {
     /**
@@ -12,9 +13,9 @@ export abstract class AbstractNodeTransformersFactory implements INodeTransforme
     protected abstract readonly nodeTransformers: Map <string, TNodeTransformer[]>;
 
     /**
-     * @type Map <string, AbstractCustomNode>
+     * @type IStorage<ICustomNode>
      */
-    protected readonly customNodes: Map <string, ICustomNode>;
+    protected readonly customNodesStorage: IStorage<ICustomNode>;
 
     /**
      * @type {IOptions}
@@ -22,11 +23,11 @@ export abstract class AbstractNodeTransformersFactory implements INodeTransforme
     protected readonly options: IOptions;
 
     /**
-     * @param customNodes
+     * @param customNodesStorage
      * @param options
      */
-    constructor (customNodes: Map <string, ICustomNode>, options: IOptions) {
-        this.customNodes = customNodes;
+    constructor (customNodesStorage: IStorage<ICustomNode>, options: IOptions) {
+        this.customNodesStorage = customNodesStorage;
         this.options = options;
     }
 
@@ -40,7 +41,7 @@ export abstract class AbstractNodeTransformersFactory implements INodeTransforme
 
         nodeTransformers.forEach((transformer: TNodeTransformer) => {
             instancesArray.push(
-                new transformer(this.customNodes, this.options)
+                new transformer(this.customNodesStorage, this.options)
             );
         });
 

+ 4 - 4
src/node-transformers/node-control-flow-transformers/FunctionControlFlowTransformer.ts

@@ -28,11 +28,11 @@ export class FunctionControlFlowTransformer extends AbstractNodeTransformer {
     ]);
 
     /**
-     * @param nodes
+     * @param customNodesStorage
      * @param options
      */
-    constructor (nodes: Map <string, ICustomNode>, options: IOptions) {
-        super(nodes, options);
+    constructor (customNodesStorage: IStorage<ICustomNode>, options: IOptions) {
+        super(customNodesStorage, options);
     }
 
     /**
@@ -65,7 +65,7 @@ export class FunctionControlFlowTransformer extends AbstractNodeTransformer {
                 }
 
                 const controlFlowStorageCallCustomNode: ICustomNode | undefined = new controlFlowReplacer(
-                    this.nodes,
+                    this.customNodesStorage,
                     this.options
                 ).replace(node, parentNode, controlFlowStorage, controlFlowStorageCustomNodeName);
 

+ 5 - 5
src/node-transformers/node-control-flow-transformers/control-flow-replacers/AbstractControlFlowReplacer.ts

@@ -9,9 +9,9 @@ import { Utils } from '../../../Utils';
 
 export abstract class AbstractControlFlowReplacer implements IControlFlowReplacer {
     /**
-     * @type Map <string, AbstractCustomNode>
+     * @type IStorage<ICustomNode>
      */
-    protected readonly nodes: Map <string, ICustomNode>;
+    protected readonly customNodesStorage: IStorage<ICustomNode>;
 
     /**
      * @type {IOptions}
@@ -19,11 +19,11 @@ export abstract class AbstractControlFlowReplacer implements IControlFlowReplace
     protected readonly options : IOptions;
 
     /**
-     * @param nodes
+     * @param customNodesStorage
      * @param options
      */
-    constructor (nodes: Map <string, ICustomNode>, options: IOptions) {
-        this.nodes = nodes;
+    constructor (customNodesStorage: IStorage<ICustomNode>, options: IOptions) {
+        this.customNodesStorage = customNodesStorage;
         this.options = options;
     }
 

+ 5 - 4
src/node-transformers/node-obfuscators/CatchClauseObfuscator.ts

@@ -3,6 +3,7 @@ import * as ESTree from 'estree';
 
 import { ICustomNode } from '../../interfaces/custom-nodes/ICustomNode';
 import { IOptions } from '../../interfaces/IOptions';
+import { IStorage } from '../../interfaces/IStorage';
 
 import { NodeType } from '../../enums/NodeType';
 
@@ -26,13 +27,13 @@ export class CatchClauseObfuscator extends AbstractNodeTransformer {
     private readonly identifierReplacer: IdentifierReplacer;
 
     /**
-     * @param nodes
+     * @param customNodesStorage
      * @param options
      */
-    constructor(nodes: Map <string, ICustomNode>, options: IOptions) {
-        super(nodes, options);
+    constructor(customNodesStorage: IStorage<ICustomNode>, options: IOptions) {
+        super(customNodesStorage, options);
 
-        this.identifierReplacer = new IdentifierReplacer(this.nodes, this.options);
+        this.identifierReplacer = new IdentifierReplacer(this.customNodesStorage, this.options);
     }
 
     /**

+ 5 - 4
src/node-transformers/node-obfuscators/FunctionDeclarationObfuscator.ts

@@ -5,6 +5,7 @@ import { TNodeWithBlockStatement } from '../../types/TNodeWithBlockStatement';
 
 import { ICustomNode } from '../../interfaces/custom-nodes/ICustomNode';
 import { IOptions } from '../../interfaces/IOptions';
+import { IStorage } from '../../interfaces/IStorage';
 
 import { NodeType } from '../../enums/NodeType';
 
@@ -29,13 +30,13 @@ export class FunctionDeclarationObfuscator extends AbstractNodeTransformer {
     private readonly identifierReplacer: IdentifierReplacer;
 
     /**
-     * @param nodes
+     * @param customNodesStorage
      * @param options
      */
-    constructor(nodes: Map <string, ICustomNode>, options: IOptions) {
-        super(nodes, options);
+    constructor(customNodesStorage: IStorage<ICustomNode>, options: IOptions) {
+        super(customNodesStorage, options);
 
-        this.identifierReplacer = new IdentifierReplacer(this.nodes, this.options);
+        this.identifierReplacer = new IdentifierReplacer(this.customNodesStorage, this.options);
     }
 
     /**

+ 5 - 4
src/node-transformers/node-obfuscators/FunctionObfuscator.ts

@@ -3,6 +3,7 @@ import * as ESTree from 'estree';
 
 import { ICustomNode } from '../../interfaces/custom-nodes/ICustomNode';
 import { IOptions } from '../../interfaces/IOptions';
+import { IStorage } from '../../interfaces/IStorage';
 
 import { NodeType } from '../../enums/NodeType';
 
@@ -26,13 +27,13 @@ export class FunctionObfuscator extends AbstractNodeTransformer {
     private readonly identifierReplacer: IdentifierReplacer;
 
     /**
-     * @param nodes
+     * @param customNodesStorage
      * @param options
      */
-    constructor(nodes: Map <string, ICustomNode>, options: IOptions) {
-        super(nodes, options);
+    constructor(customNodesStorage: IStorage<ICustomNode>, options: IOptions) {
+        super(customNodesStorage, options);
 
-        this.identifierReplacer = new IdentifierReplacer(this.nodes, this.options);
+        this.identifierReplacer = new IdentifierReplacer(this.customNodesStorage, this.options);
     }
 
     /**

+ 5 - 4
src/node-transformers/node-obfuscators/LabeledStatementObfuscator.ts

@@ -3,6 +3,7 @@ import * as ESTree from 'estree';
 
 import { ICustomNode } from '../../interfaces/custom-nodes/ICustomNode';
 import { IOptions } from '../../interfaces/IOptions';
+import { IStorage } from '../../interfaces/IStorage';
 
 import { NodeType } from '../../enums/NodeType';
 
@@ -34,13 +35,13 @@ export class LabeledStatementObfuscator extends AbstractNodeTransformer {
     private readonly identifierReplacer: IdentifierReplacer;
 
     /**
-     * @param nodes
+     * @param customNodesStorage
      * @param options
      */
-    constructor(nodes: Map <string, ICustomNode>, options: IOptions) {
-        super(nodes, options);
+    constructor(customNodesStorage: IStorage<ICustomNode>, options: IOptions) {
+        super(customNodesStorage, options);
 
-        this.identifierReplacer = new IdentifierReplacer(this.nodes, this.options);
+        this.identifierReplacer = new IdentifierReplacer(this.customNodesStorage, this.options);
     }
 
     /**

+ 3 - 3
src/node-transformers/node-obfuscators/LiteralObfuscator.ts

@@ -21,19 +21,19 @@ export class LiteralObfuscator extends AbstractNodeTransformer {
 
         switch (typeof literalNode.value) {
             case 'boolean':
-                content = new BooleanLiteralReplacer(this.nodes, this.options)
+                content = new BooleanLiteralReplacer(this.customNodesStorage, this.options)
                     .replace(<boolean>literalNode.value);
 
                 break;
 
             case 'number':
-                content = new NumberLiteralReplacer(this.nodes, this.options)
+                content = new NumberLiteralReplacer(this.customNodesStorage, this.options)
                     .replace(<number>literalNode.value);
 
                 break;
 
             case 'string':
-                content = new StringLiteralReplacer(this.nodes, this.options)
+                content = new StringLiteralReplacer(this.customNodesStorage, this.options)
                     .replace(<string>literalNode.value);
 
                 break;

+ 2 - 2
src/node-transformers/node-obfuscators/MemberExpressionObfuscator.ts

@@ -50,7 +50,7 @@ export class MemberExpressionObfuscator extends AbstractNodeTransformer {
         const literalNode: ESTree.Literal = {
             raw: `'${nodeValue}'`,
             'x-verbatim-property': {
-                content : new StringLiteralReplacer(this.nodes, this.options).replace(nodeValue),
+                content : new StringLiteralReplacer(this.customNodesStorage, this.options).replace(nodeValue),
                 precedence: escodegen.Precedence.Primary
             },
             type: NodeType.Literal,
@@ -74,7 +74,7 @@ export class MemberExpressionObfuscator extends AbstractNodeTransformer {
     private obfuscateLiteralProperty (node: ESTree.Literal): void {
         if (typeof node.value === 'string' && !node['x-verbatim-property']) {
             node['x-verbatim-property'] = {
-                content : new StringLiteralReplacer(this.nodes, this.options).replace(node.value),
+                content : new StringLiteralReplacer(this.customNodesStorage, this.options).replace(node.value),
                 precedence: escodegen.Precedence.Primary
             };
         }

+ 1 - 1
src/node-transformers/node-obfuscators/MethodDefinitionObfuscator.ts

@@ -39,7 +39,7 @@ export class MethodDefinitionObfuscator extends AbstractNodeTransformer {
                     methodDefinitionNode.computed === false
                 ) {
                     methodDefinitionNode.computed = true;
-                    node.name = new StringLiteralReplacer(this.nodes, this.options)
+                    node.name = new StringLiteralReplacer(this.customNodesStorage, this.options)
                         .replace(node.name);
 
                     return;

+ 5 - 4
src/node-transformers/node-obfuscators/VariableDeclarationObfuscator.ts

@@ -5,6 +5,7 @@ import { TNodeWithBlockStatement } from '../../types/TNodeWithBlockStatement';
 
 import { ICustomNode } from '../../interfaces/custom-nodes/ICustomNode';
 import { IOptions } from '../../interfaces/IOptions';
+import { IStorage } from '../../interfaces/IStorage';
 
 import { NodeType } from '../../enums/NodeType';
 
@@ -30,13 +31,13 @@ export class VariableDeclarationObfuscator extends AbstractNodeTransformer {
     private readonly identifierReplacer: IdentifierReplacer;
 
     /**
-     * @param nodes
+     * @param customNodesStorage
      * @param options
      */
-    constructor(nodes: Map <string, ICustomNode>, options: IOptions) {
-        super(nodes, options);
+    constructor(customNodesStorage: IStorage<ICustomNode>, options: IOptions) {
+        super(customNodesStorage, options);
 
-        this.identifierReplacer = new IdentifierReplacer(this.nodes, this.options);
+        this.identifierReplacer = new IdentifierReplacer(this.customNodesStorage, this.options);
     }
 
     /**

+ 6 - 5
src/node-transformers/node-obfuscators/replacers/AbstractReplacer.ts

@@ -1,12 +1,13 @@
 import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
 import { IOptions } from '../../../interfaces/IOptions';
 import { IReplacer } from '../../../interfaces/IReplacer';
+import { IStorage } from '../../../interfaces/IStorage';
 
 export abstract class AbstractReplacer implements IReplacer {
     /**
-     * @type Map <string, AbstractCustomNode>
+     * @type IStorage<ICustomNode>
      */
-    protected readonly nodes: Map <string, ICustomNode>;
+    protected readonly customNodesStorage: IStorage<ICustomNode>;
 
     /**
      * @type {IOptions}
@@ -14,11 +15,11 @@ export abstract class AbstractReplacer implements IReplacer {
     protected readonly options : IOptions;
 
     /**
-     * @param nodes
+     * @param customNodesStorage
      * @param options
      */
-    constructor (nodes: Map <string, ICustomNode>, options: IOptions) {
-        this.nodes = nodes;
+    constructor (customNodesStorage: IStorage<ICustomNode>, options: IOptions) {
+        this.customNodesStorage = customNodesStorage;
         this.options = options;
     }
 

+ 3 - 11
src/node-transformers/node-obfuscators/replacers/StringLiteralReplacer.ts

@@ -42,11 +42,7 @@ export class StringLiteralReplacer extends AbstractReplacer {
      * @returns {string}
      */
     private replaceStringLiteralWithStringArrayCall (value: string): string {
-        const stringArrayNode: ICustomNodeWithData = <ICustomNodeWithData>this.nodes.get('stringArrayNode');
-
-        if (!stringArrayNode) {
-            throw new ReferenceError('`stringArrayNode` node is not found in Map with custom nodes.');
-        }
+        const stringArrayNode: ICustomNodeWithData = <ICustomNodeWithData>this.customNodesStorage.get('stringArrayNode');
 
         let rc4Key: string = '';
 
@@ -79,12 +75,8 @@ export class StringLiteralReplacer extends AbstractReplacer {
             stringArray.set(null, value);
         }
 
-        const stringArrayCallsWrapper: ICustomNodeWithIdentifier = <ICustomNodeWithIdentifier>this.nodes.get('stringArrayCallsWrapper');
-        const hexadecimalIndex: string = new NumberLiteralReplacer(this.nodes, this.options).replace(indexOfValue);
-
-        if (!stringArrayCallsWrapper) {
-            throw new ReferenceError('`stringArrayCallsWrapper` node is not found in Map with custom node.');
-        }
+        const stringArrayCallsWrapper: ICustomNodeWithIdentifier = <ICustomNodeWithIdentifier>this.customNodesStorage.get('stringArrayCallsWrapper');
+        const hexadecimalIndex: string = new NumberLiteralReplacer(this.customNodesStorage, this.options).replace(indexOfValue);
 
         if (this.options.stringArrayEncoding === StringArrayEncoding.rc4) {
             return `${stringArrayCallsWrapper.getNodeIdentifier()}('${hexadecimalIndex}', '${Utils.stringToUnicodeEscapeSequence(rc4Key)}')`;

+ 5 - 0
src/storages/ArrayStorage.ts

@@ -42,6 +42,11 @@ export abstract class ArrayStorage <T> implements IStorage <T> {
         return this.storage;
     }
 
+    /**
+     * @param args
+     */
+    public initialize (...args: any[]): void {}
+
     /**
      * @param key
      * @param value

+ 5 - 0
src/storages/MapStorage.ts

@@ -44,6 +44,11 @@ export abstract class MapStorage <T> implements IStorage <T> {
         return this.storage;
     }
 
+    /**
+     * @param args
+     */
+    public initialize (...args: any[]): void {}
+
     /**
      * @param key
      * @param value

+ 64 - 0
src/storages/custom-nodes/CustomNodesStorage.ts

@@ -0,0 +1,64 @@
+import { TCustomNodesFactory } from '../../types/TCustomNodesFactory';
+
+import { ICustomNode } from '../../interfaces/custom-nodes/ICustomNode';
+import { IObfuscationEventEmitter } from '../../interfaces/IObfuscationEventEmitter';
+import { IOptions } from '../../interfaces/IOptions';
+import { IStackTraceData } from '../../interfaces/stack-trace-analyzer/IStackTraceData';
+
+import { ConsoleOutputCustomNodesFactory } from '../../custom-nodes/console-output-nodes/factory/ConsoleOutputCustomNodesFactory';
+import { DebugProtectionCustomNodesFactory } from '../../custom-nodes/debug-protection-nodes/factory/DebugProtectionCustomNodesFactory';
+import { DomainLockCustomNodesFactory } from '../../custom-nodes/domain-lock-nodes/factory/DomainLockCustomNodesFactory';
+import { MapStorage } from '../MapStorage';
+import { SelfDefendingCustomNodesFactory } from '../../custom-nodes/self-defending-nodes/factory/SelfDefendingCustomNodesFactory';
+import { StringArrayCustomNodesFactory } from '../../custom-nodes/string-array-nodes/factory/StringArrayCustomNodesFactory';
+
+export class CustomNodesStorage extends MapStorage <ICustomNode> {
+    /**
+     * @type {TCustomNodesFactory[]}
+     */
+    private static readonly customNodesFactories: TCustomNodesFactory[] = [
+        DomainLockCustomNodesFactory,
+        SelfDefendingCustomNodesFactory,
+        ConsoleOutputCustomNodesFactory,
+        DebugProtectionCustomNodesFactory,
+        StringArrayCustomNodesFactory
+    ];
+
+    /**
+     * @type {IOptions}
+     */
+    private readonly options: IOptions;
+
+    /**
+     * @param options
+     */
+    constructor (options: IOptions) {
+        super();
+
+        this.options = options;
+    }
+    /**
+     * @param obfuscationEventEmitter
+     * @param stackTraceData
+     */
+    public initialize (obfuscationEventEmitter: IObfuscationEventEmitter, stackTraceData: IStackTraceData[]): void {
+        const customNodes: [string, ICustomNode][] = [];
+
+        CustomNodesStorage.customNodesFactories.forEach((customNodesFactoryConstructor: TCustomNodesFactory) => {
+            const customNodesFactory: Map <string, ICustomNode> | undefined = new customNodesFactoryConstructor(
+                this.options
+            ).initializeCustomNodes(
+                obfuscationEventEmitter,
+                stackTraceData
+            );
+
+            if (!customNodesFactory) {
+                return;
+            }
+
+            customNodes.push(...customNodesFactory);
+        });
+
+        this.storage = new Map <string, ICustomNode> (customNodes);
+    }
+}

+ 2 - 1
src/types/TControlFlowReplacer.d.ts

@@ -1,5 +1,6 @@
 import { IControlFlowReplacer } from '../interfaces/IControlFlowReplacer';
 import { ICustomNode } from '../interfaces/custom-nodes/ICustomNode';
 import { IOptions } from '../interfaces/IOptions';
+import { IStorage } from '../interfaces/IStorage';
 
-export type TControlFlowReplacer = (new (nodes: Map <string, ICustomNode>, options: IOptions) => IControlFlowReplacer);
+export type TControlFlowReplacer = (new (customNodesStorage: IStorage<ICustomNode>, options: IOptions) => IControlFlowReplacer);

+ 2 - 1
src/types/TNodeTransformer.d.ts

@@ -1,5 +1,6 @@
 import { ICustomNode } from '../interfaces/custom-nodes/ICustomNode';
 import { INodeTransformer } from '../interfaces/INodeTransformer';
 import { IOptions } from '../interfaces/IOptions';
+import { IStorage } from '../interfaces/IStorage';
 
-export type TNodeTransformer = (new (nodes: Map <string, ICustomNode>, options: IOptions) => INodeTransformer);
+export type TNodeTransformer = (new (customNodesStorage: IStorage<ICustomNode>, options: IOptions) => INodeTransformer);

+ 23 - 23
test/fixtures/compile-performance.js

@@ -14892,7 +14892,7 @@
                     // Transform ICU messages to angular directives
                     var expandedHtmlAst = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_10__ml_parser_icu_ast_expander__["a" /* expandNodes */])(htmlAstWithErrors.rootNodes);
                     errors.push.apply(errors, expandedHtmlAst.errors);
-                    htmlAstWithErrors = new __WEBPACK_IMPORTED_MODULE_9__ml_parser_html_parser__["a" /* ParseTreeResult */](expandedHtmlAst.nodes, errors);
+                    htmlAstWithErrors = new __WEBPACK_IMPORTED_MODULE_9__ml_parser_html_parser__["a" /* ParseTreeResult */](expandedHtmlAst.customNodesStorage, errors);
                 }
                 if (htmlAstWithErrors.rootNodes.length > 0) {
                     var uniqDirectives = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__compile_metadata__["f" /* removeIdentifierDuplicates */])(directives);
@@ -20398,7 +20398,7 @@
          * found in the LICENSE file at https://angular.io/license
          */
         function digestMessage(message) {
-            return sha1(serializeNodes(message.nodes).join('') + ("[" + message.meaning + "]"));
+            return sha1(serializeNodes(message.customNodesStorage).join('') + ("[" + message.meaning + "]"));
         }
         /**
          * Serialize the i18n ast to something xml-like in order to generate an UID.
@@ -30516,7 +30516,7 @@
                 var significantChildren = directChildren.reduce(function (count, node) { return count + (node instanceof __WEBPACK_IMPORTED_MODULE_0__ml_parser_ast__["a" /* Comment */] ? 0 : 1); }, 0);
                 if (significantChildren == 1) {
                     for (var i = this._messages.length - 1; i >= startIndex; i--) {
-                        var ast = this._messages[i].nodes;
+                        var ast = this._messages[i].customNodesStorage;
                         if (!(ast.length == 1 && ast[0] instanceof __WEBPACK_IMPORTED_MODULE_3__i18n_ast__["f" /* Text */])) {
                             this._messages.splice(i, 1);
                             break;
@@ -30876,7 +30876,7 @@
                 Object.keys(messageMap).forEach(function (id) {
                     var message = messageMap[id];
                     var transUnit = new __WEBPACK_IMPORTED_MODULE_5__xml_helper__["b" /* Tag */](_UNIT_TAG, { id: id, datatype: 'html' });
-                    transUnit.children.push(_CR(8), new __WEBPACK_IMPORTED_MODULE_5__xml_helper__["b" /* Tag */](_SOURCE_TAG, {}, visitor.serialize(message.nodes)), _CR(8), new __WEBPACK_IMPORTED_MODULE_5__xml_helper__["b" /* Tag */](_TARGET_TAG));
+                    transUnit.children.push(_CR(8), new __WEBPACK_IMPORTED_MODULE_5__xml_helper__["b" /* Tag */](_SOURCE_TAG, {}, visitor.serialize(message.customNodesStorage)), _CR(8), new __WEBPACK_IMPORTED_MODULE_5__xml_helper__["b" /* Tag */](_TARGET_TAG));
                     if (message.description) {
                         transUnit.children.push(_CR(8), new __WEBPACK_IMPORTED_MODULE_5__xml_helper__["b" /* Tag */]('note', { priority: '1', from: 'description' }, [new __WEBPACK_IMPORTED_MODULE_5__xml_helper__["a" /* Text */](message.description)]));
                     }
@@ -31109,7 +31109,7 @@
                     if (message.meaning) {
                         attrs['meaning'] = message.meaning;
                     }
-                    rootNode.children.push(new __WEBPACK_IMPORTED_MODULE_1__xml_helper__["a" /* Text */]('  '), new __WEBPACK_IMPORTED_MODULE_1__xml_helper__["b" /* Tag */](_MESSAGE_TAG, attrs, visitor.serialize(message.nodes)), new __WEBPACK_IMPORTED_MODULE_1__xml_helper__["a" /* Text */]('\n'));
+                    rootNode.children.push(new __WEBPACK_IMPORTED_MODULE_1__xml_helper__["a" /* Text */]('  '), new __WEBPACK_IMPORTED_MODULE_1__xml_helper__["b" /* Tag */](_MESSAGE_TAG, attrs, visitor.serialize(message.customNodesStorage)), new __WEBPACK_IMPORTED_MODULE_1__xml_helper__["a" /* Text */]('\n'));
                 });
                 return __WEBPACK_IMPORTED_MODULE_1__xml_helper__["c" /* serialize */]([
                     new __WEBPACK_IMPORTED_MODULE_1__xml_helper__["d" /* Declaration */]({ version: '1.0', encoding: 'UTF-8' }),
@@ -34513,7 +34513,7 @@
         function finishView(view, targetStatements) {
             view.afterNodes();
             createViewTopLevelStmts(view, targetStatements);
-            view.nodes.forEach(function (node) {
+            view.customNodesStorage.forEach(function (node) {
                 if (node instanceof __WEBPACK_IMPORTED_MODULE_10__compile_element__["a" /* CompileElement */] && node.hasEmbeddedView) {
                     finishView(node.embeddedView, targetStatements);
                 }
@@ -34567,17 +34567,17 @@
                 return this._visitText(ast, ast.value, parent);
             };
             ViewBuilderVisitor.prototype._visitText = function (ast, value, parent) {
-                var fieldName = "_text_" + this.view.nodes.length;
+                var fieldName = "_text_" + this.view.customNodesStorage.length;
                 this.view.fields.push(new __WEBPACK_IMPORTED_MODULE_6__output_output_ast__["s" /* ClassField */](fieldName, __WEBPACK_IMPORTED_MODULE_6__output_output_ast__["c" /* importType */](this.view.genConfig.renderTypes.renderText)));
                 var renderNode = __WEBPACK_IMPORTED_MODULE_6__output_output_ast__["n" /* THIS_EXPR */].prop(fieldName);
-                var compileNode = new __WEBPACK_IMPORTED_MODULE_10__compile_element__["b" /* CompileNode */](parent, this.view, this.view.nodes.length, renderNode, ast);
+                var compileNode = new __WEBPACK_IMPORTED_MODULE_10__compile_element__["b" /* CompileNode */](parent, this.view, this.view.customNodesStorage.length, renderNode, ast);
                 var createRenderNode = __WEBPACK_IMPORTED_MODULE_6__output_output_ast__["n" /* THIS_EXPR */].prop(fieldName)
                     .set(__WEBPACK_IMPORTED_MODULE_12__constants__["c" /* ViewProperties */].renderer.callMethod('createText', [
                         this._getParentRenderNode(parent), __WEBPACK_IMPORTED_MODULE_6__output_output_ast__["a" /* literal */](value),
-                        this.view.createMethod.resetDebugInfoExpr(this.view.nodes.length, ast)
+                        this.view.createMethod.resetDebugInfoExpr(this.view.customNodesStorage.length, ast)
                     ]))
                     .toStmt();
-                this.view.nodes.push(compileNode);
+                this.view.customNodesStorage.push(compileNode);
                 this.view.createMethod.addStmt(createRenderNode);
                 this._addRootNodeAndProject(compileNode);
                 return renderNode;
@@ -34612,7 +34612,7 @@
             };
             ViewBuilderVisitor.prototype.visitElement = function (ast, parent) {
                 var _this = this;
-                var nodeIndex = this.view.nodes.length;
+                var nodeIndex = this.view.customNodesStorage.length;
                 var createRenderNodeExpr;
                 var debugContextExpr = this.view.createMethod.resetDebugInfoExpr(nodeIndex, ast);
                 if (nodeIndex === 0 && this.view.viewType === __WEBPACK_IMPORTED_MODULE_7__private_import_core__["j" /* ViewType */].HOST) {
@@ -34645,7 +34645,7 @@
                     }
                 }
                 var compileElement = new __WEBPACK_IMPORTED_MODULE_10__compile_element__["a" /* CompileElement */](parent, this.view, nodeIndex, renderNode, ast, component, directives, ast.providers, ast.hasViewContainer, false, ast.references);
-                this.view.nodes.push(compileElement);
+                this.view.customNodesStorage.push(compileElement);
                 var compViewExpr = null;
                 if (__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_4__facade_lang__["a" /* isPresent */])(component)) {
                     var nestedComponentIdentifier = new __WEBPACK_IMPORTED_MODULE_2__compile_metadata__["a" /* CompileIdentifierMetadata */]({ name: __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_13__util__["d" /* getViewFactoryName */])(component, 0) });
@@ -34667,7 +34667,7 @@
                 compileElement.beforeChildren();
                 this._addRootNodeAndProject(compileElement);
                 __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_8__template_parser_template_ast__["c" /* templateVisitAll */])(this, ast.children, compileElement);
-                compileElement.afterChildren(this.view.nodes.length - nodeIndex - 1);
+                compileElement.afterChildren(this.view.customNodesStorage.length - nodeIndex - 1);
                 if (__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_4__facade_lang__["a" /* isPresent */])(compViewExpr)) {
                     var codeGenContentNodes;
                     if (this.view.component.type.isHost) {
@@ -34683,7 +34683,7 @@
                 return null;
             };
             ViewBuilderVisitor.prototype.visitEmbeddedTemplate = function (ast, parent) {
-                var nodeIndex = this.view.nodes.length;
+                var nodeIndex = this.view.customNodesStorage.length;
                 var fieldName = "_anchor_" + nodeIndex;
                 this.view.fields.push(new __WEBPACK_IMPORTED_MODULE_6__output_output_ast__["s" /* ClassField */](fieldName, __WEBPACK_IMPORTED_MODULE_6__output_output_ast__["c" /* importType */](this.view.genConfig.renderTypes.renderComment)));
                 this.view.createMethod.addStmt(__WEBPACK_IMPORTED_MODULE_6__output_output_ast__["n" /* THIS_EXPR */].prop(fieldName)
@@ -34696,7 +34696,7 @@
                 var templateVariableBindings = ast.variables.map(function (varAst) { return [varAst.value.length > 0 ? varAst.value : IMPLICIT_TEMPLATE_VAR, varAst.name]; });
                 var directives = ast.directives.map(function (directiveAst) { return directiveAst.directive; });
                 var compileElement = new __WEBPACK_IMPORTED_MODULE_10__compile_element__["a" /* CompileElement */](parent, this.view, nodeIndex, renderNode, ast, null, directives, ast.providers, ast.hasViewContainer, true, ast.references);
-                this.view.nodes.push(compileElement);
+                this.view.customNodesStorage.push(compileElement);
                 var compiledAnimations = this._animationCompiler.compileComponent(this.view.component, [ast]);
                 this.nestedViewCount++;
                 var embeddedView = new __WEBPACK_IMPORTED_MODULE_11__compile_view__["a" /* CompileView */](this.view.component, this.view.genConfig, this.view.pipeMetas, __WEBPACK_IMPORTED_MODULE_6__output_output_ast__["h" /* NULL_EXPR */], compiledAnimations.triggers, this.view.viewIndex + this.nestedViewCount, compileElement, templateVariableBindings);
@@ -34788,7 +34788,7 @@
             if (view.genConfig.genDebugInfo) {
                 nodeDebugInfosVar = __WEBPACK_IMPORTED_MODULE_6__output_output_ast__["e" /* variable */]("nodeDebugInfos_" + view.component.type.name + view.viewIndex); // fix highlighting: `
                 targetStatements.push(nodeDebugInfosVar
-                    .set(__WEBPACK_IMPORTED_MODULE_6__output_output_ast__["g" /* literalArr */](view.nodes.map(createStaticNodeDebugInfo), new __WEBPACK_IMPORTED_MODULE_6__output_output_ast__["q" /* ArrayType */](new __WEBPACK_IMPORTED_MODULE_6__output_output_ast__["I" /* ExternalType */](__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_5__identifiers__["d" /* resolveIdentifier */])(__WEBPACK_IMPORTED_MODULE_5__identifiers__["b" /* Identifiers */].StaticNodeDebugInfo)), [__WEBPACK_IMPORTED_MODULE_6__output_output_ast__["d" /* TypeModifier */].Const])))
+                    .set(__WEBPACK_IMPORTED_MODULE_6__output_output_ast__["g" /* literalArr */](view.customNodesStorage.map(createStaticNodeDebugInfo), new __WEBPACK_IMPORTED_MODULE_6__output_output_ast__["q" /* ArrayType */](new __WEBPACK_IMPORTED_MODULE_6__output_output_ast__["I" /* ExternalType */](__webpack_require__.i(__WEBPACK_IMPORTED_MODULE_5__identifiers__["d" /* resolveIdentifier */])(__WEBPACK_IMPORTED_MODULE_5__identifiers__["b" /* Identifiers */].StaticNodeDebugInfo)), [__WEBPACK_IMPORTED_MODULE_6__output_output_ast__["d" /* TypeModifier */].Const])))
                     .toDeclStmt(null, [__WEBPACK_IMPORTED_MODULE_6__output_output_ast__["u" /* StmtModifier */].Final]));
             }
             var renderCompTypeVar = __WEBPACK_IMPORTED_MODULE_6__output_output_ast__["e" /* variable */]("renderType_" + view.component.type.name); // fix highlighting: `
@@ -34897,7 +34897,7 @@
             }
             var resultExpr;
             if (view.viewType === __WEBPACK_IMPORTED_MODULE_7__private_import_core__["j" /* ViewType */].HOST) {
-                resultExpr = view.nodes[0].appElement;
+                resultExpr = view.customNodesStorage[0].appElement;
             }
             else {
                 resultExpr = __WEBPACK_IMPORTED_MODULE_6__output_output_ast__["h" /* NULL_EXPR */];
@@ -34906,7 +34906,7 @@
                 __WEBPACK_IMPORTED_MODULE_6__output_output_ast__["n" /* THIS_EXPR */]
                     .callMethod('init', [
                         __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_13__util__["e" /* createFlatArray */])(view.rootNodesOrAppElements),
-                        __WEBPACK_IMPORTED_MODULE_6__output_output_ast__["g" /* literalArr */](view.nodes.map(function (node) { return node.renderNode; })), __WEBPACK_IMPORTED_MODULE_6__output_output_ast__["g" /* literalArr */](view.disposables),
+                        __WEBPACK_IMPORTED_MODULE_6__output_output_ast__["g" /* literalArr */](view.customNodesStorage.map(function (node) { return node.renderNode; })), __WEBPACK_IMPORTED_MODULE_6__output_output_ast__["g" /* literalArr */](view.disposables),
                         __WEBPACK_IMPORTED_MODULE_6__output_output_ast__["g" /* literalArr */](view.subscriptions)
                     ])
                     .toStmt(),
@@ -50449,7 +50449,7 @@
                 }
                 var expansionResult = expandNodes(c.expression);
                 errors.push.apply(errors, expansionResult.errors);
-                return new __WEBPACK_IMPORTED_MODULE_1__ast__["e" /* Element */]("template", [new __WEBPACK_IMPORTED_MODULE_1__ast__["f" /* Attribute */]('ngPluralCase', "" + c.value, c.valueSourceSpan)], expansionResult.nodes, c.sourceSpan, c.sourceSpan, c.sourceSpan);
+                return new __WEBPACK_IMPORTED_MODULE_1__ast__["e" /* Element */]("template", [new __WEBPACK_IMPORTED_MODULE_1__ast__["f" /* Attribute */]('ngPluralCase', "" + c.value, c.valueSourceSpan)], expansionResult.customNodesStorage, c.sourceSpan, c.sourceSpan, c.sourceSpan);
             });
             var switchAttr = new __WEBPACK_IMPORTED_MODULE_1__ast__["f" /* Attribute */]('[ngPlural]', ast.switchValue, ast.switchValueSourceSpan);
             return new __WEBPACK_IMPORTED_MODULE_1__ast__["e" /* Element */]('ng-container', [switchAttr], children, ast.sourceSpan, ast.sourceSpan, ast.sourceSpan);
@@ -50458,7 +50458,7 @@
             var children = ast.cases.map(function (c) {
                 var expansionResult = expandNodes(c.expression);
                 errors.push.apply(errors, expansionResult.errors);
-                return new __WEBPACK_IMPORTED_MODULE_1__ast__["e" /* Element */]("template", [new __WEBPACK_IMPORTED_MODULE_1__ast__["f" /* Attribute */]('ngSwitchCase', "" + c.value, c.valueSourceSpan)], expansionResult.nodes, c.sourceSpan, c.sourceSpan, c.sourceSpan);
+                return new __WEBPACK_IMPORTED_MODULE_1__ast__["e" /* Element */]("template", [new __WEBPACK_IMPORTED_MODULE_1__ast__["f" /* Attribute */]('ngSwitchCase', "" + c.value, c.valueSourceSpan)], expansionResult.customNodesStorage, c.sourceSpan, c.sourceSpan, c.sourceSpan);
             });
             var switchAttr = new __WEBPACK_IMPORTED_MODULE_1__ast__["f" /* Attribute */]('[ngSwitch]', ast.switchValue, ast.switchValueSourceSpan);
             return new __WEBPACK_IMPORTED_MODULE_1__ast__["e" /* Element */]('ng-container', [switchAttr], children, ast.sourceSpan, ast.sourceSpan, ast.sourceSpan);
@@ -53334,7 +53334,7 @@
                 animationOutputs.forEach(function (entry) { _this._animationOutputsMap[entry.fullPropertyName] = entry; });
             }
             ViewBinderVisitor.prototype.visitBoundText = function (ast, parent) {
-                var node = this.view.nodes[this._nodeIndex++];
+                var node = this.view.customNodesStorage[this._nodeIndex++];
                 __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_3__property_binder__["a" /* bindRenderText */])(ast, node, this.view);
                 return null;
             };
@@ -53345,7 +53345,7 @@
             ViewBinderVisitor.prototype.visitNgContent = function (ast, parent) { return null; };
             ViewBinderVisitor.prototype.visitElement = function (ast, parent) {
                 var _this = this;
-                var compileElement = this.view.nodes[this._nodeIndex++];
+                var compileElement = this.view.customNodesStorage[this._nodeIndex++];
                 var eventListeners = [];
                 var animationEventListeners = [];
                 __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__event_binder__["a" /* collectEventListeners */])(ast.outputs, ast.directives, compileElement).forEach(function (entry) {
@@ -53388,7 +53388,7 @@
                 return null;
             };
             ViewBinderVisitor.prototype.visitEmbeddedTemplate = function (ast, parent) {
-                var compileElement = this.view.nodes[this._nodeIndex++];
+                var compileElement = this.view.customNodesStorage[this._nodeIndex++];
                 var eventListeners = __webpack_require__.i(__WEBPACK_IMPORTED_MODULE_1__event_binder__["a" /* collectEventListeners */])(ast.outputs, ast.directives, compileElement);
                 ast.directives.forEach(function (directiveAst) {
                     var directiveInstance = compileElement.instances.get(directiveAst.directive.type.reference);

+ 6 - 3
test/unit-tests/node-transformers/node-obfuscators/FunctionDeclarationObfuscator.spec.ts

@@ -1,9 +1,10 @@
 import * as ESTree from 'estree';
 
-import { ICustomNode } from '../../../../src/interfaces/custom-nodes/ICustomNode';
+import { IOptions } from '../../../../src/interfaces/IOptions';
 
 import { DEFAULT_PRESET } from '../../../../src/preset-options/DefaultPreset';
 
+import { CustomNodesStorage } from '../../../../src/storages/custom-nodes/CustomNodesStorage';
 import { FunctionDeclarationObfuscator } from '../../../../src/node-transformers/node-obfuscators/FunctionDeclarationObfuscator';
 import { NodeMocks } from '../../../mocks/NodeMocks';
 import { Options } from '../../../../src/options/Options';
@@ -23,9 +24,11 @@ describe('FunctionDeclarationObfuscator', () => {
                 NodeMocks.getCallExpressionNode(NodeMocks.getIdentifierNode(functionName))
             );
 
+            const options: IOptions = new Options(DEFAULT_PRESET);
+
             functionDeclarationObfuscator = new FunctionDeclarationObfuscator(
-                new Map<string, ICustomNode>(),
-                new Options(DEFAULT_PRESET)
+                new CustomNodesStorage(options),
+                options
             );
 
             functionDeclarationNode = NodeMocks.getFunctionDeclarationNode(

+ 6 - 3
test/unit-tests/node-transformers/node-obfuscators/FunctionObfuscator.spec.ts

@@ -1,9 +1,10 @@
 import * as ESTree from 'estree';
 
-import { ICustomNode } from '../../../../src/interfaces/custom-nodes/ICustomNode';
+import { IOptions } from '../../../../src/interfaces/IOptions';
 
 import { DEFAULT_PRESET } from '../../../../src/preset-options/DefaultPreset';
 
+import { CustomNodesStorage } from '../../../../src/storages/custom-nodes/CustomNodesStorage';
 import { FunctionObfuscator } from '../../../../src/node-transformers/node-obfuscators/FunctionObfuscator';
 import { NodeMocks } from '../../../mocks/NodeMocks';
 import { Options } from '../../../../src/options/Options';
@@ -61,9 +62,11 @@ describe('FunctionObfuscator', () => {
             identifierNode1['parentNode'] = functionDeclarationNode;
             expressionStatementNode1['parentNode'] = blockStatementNode;
 
+            const options: IOptions = new Options(DEFAULT_PRESET);
+
             functionObfuscator = new FunctionObfuscator(
-                new Map<string, ICustomNode>(),
-                new Options(DEFAULT_PRESET)
+                new CustomNodesStorage(options),
+                options
             );
 
             functionObfuscator.transformNode(functionDeclarationNode);

部分文件因为文件数量过多而无法显示