소스 검색

Improved `stringArrayIntermediateVariablesCount` option with function intermediate calls

sanex 4 년 전
부모
커밋
84432e87e8
33개의 변경된 파일595개의 추가작업 그리고 104개의 파일을 삭제
  1. 0 0
      dist/index.cli.js
  2. 0 0
      dist/index.js
  3. 3 3
      package.json
  4. 2 2
      src/analyzers/string-array-storage-analyzer/StringArrayStorageAnalyzer.ts
  5. 1 0
      src/container/ServiceIdentifiers.ts
  6. 8 2
      src/container/modules/storages/StoragesModule.ts
  7. 1 1
      src/custom-code-helpers/self-defending/templates/SelfDefendingNoEvalTemplate.ts
  8. 1 1
      src/custom-code-helpers/string-array/StringArrayCallsWrapperCodeHelper.ts
  9. 1 1
      src/custom-code-helpers/string-array/StringArrayCodeHelper.ts
  10. 2 2
      src/custom-code-helpers/string-array/group/StringArrayCodeHelperGroup.ts
  11. 1 1
      src/interfaces/IEncodedValue.ts
  12. 1 1
      src/interfaces/analyzers/string-array-storage-analyzer/IStringArrayStorageAnalyzer.ts
  13. 0 0
      src/interfaces/node-transformers/string-array-transformers/IStringArrayCallsWrapperNames.ts
  14. 13 0
      src/interfaces/node-transformers/string-array-transformers/IStringArrayFunctionCallsWrapperName.ts
  15. 26 0
      src/interfaces/storages/string-array-transformers/ILiteralNodesCacheStorage.ts
  16. 1 1
      src/interfaces/storages/string-array-transformers/IStringArrayStorage.ts
  17. 0 0
      src/interfaces/storages/string-array-transformers/IStringArrayStorageItem.ts
  18. 6 0
      src/interfaces/utils/IArrayUtils.ts
  19. 183 22
      src/node-transformers/string-array-transformers/StringArrayTransformer.ts
  20. 55 0
      src/storages/string-array-transformers/LiteralNodesCacheStorage.ts
  21. 7 3
      src/storages/string-array-transformers/StringArrayStorage.ts
  22. 7 0
      src/types/node-transformers/string-array-transformers/TStringArrayFunctionCallsWrapperNamesMap.ts
  23. 10 0
      src/utils/ArrayUtils.ts
  24. 3 6
      test/dev/dev.ts
  25. 3 3
      test/functional-tests/storages/string-array-transformers/string-array-storage/StringArrayStorage.spec.ts
  26. 0 0
      test/functional-tests/storages/string-array-transformers/string-array-storage/fixtures/one-string.js
  27. 0 0
      test/functional-tests/storages/string-array-transformers/string-array-storage/fixtures/three-strings.js
  28. 3 2
      test/index.spec.ts
  29. 1 1
      test/unit-tests/analyzers/string-array-storage-analyzer/StringArrayStorageAnalyzer.spec.ts
  30. 157 0
      test/unit-tests/storages/string-array-transformers/literal-nodes-cache/LiteralNodesCacheStorage.spec.ts
  31. 7 7
      test/unit-tests/storages/string-array-transformers/string-array/StringArrayStorage.spec.ts
  32. 47 0
      test/unit-tests/utils/ArrayUtils.spec.ts
  33. 45 45
      yarn.lock

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 0 - 0
dist/index.cli.js


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 0 - 0
dist/index.js


+ 3 - 3
package.json

@@ -62,14 +62,14 @@
     "@types/sinon": "9.0.5",
     "@types/string-template": "1.0.2",
     "@types/webpack-env": "1.15.2",
-    "@typescript-eslint/eslint-plugin": "4.0.1",
-    "@typescript-eslint/parser": "4.0.1",
+    "@typescript-eslint/eslint-plugin": "4.1.0",
+    "@typescript-eslint/parser": "4.1.0",
     "chai": "4.2.0",
     "chai-exclude": "2.0.2",
     "coveralls": "3.1.0",
     "eslint": "7.8.1",
     "eslint-plugin-import": "2.22.0",
-    "eslint-plugin-jsdoc": "30.3.1",
+    "eslint-plugin-jsdoc": "30.3.3",
     "eslint-plugin-no-null": "1.0.2",
     "eslint-plugin-prefer-arrow": "1.2.2",
     "eslint-plugin-unicorn": "21.0.0",

+ 2 - 2
src/analyzers/string-array-storage-analyzer/StringArrayStorageAnalyzer.ts

@@ -6,9 +6,9 @@ import * as ESTree from 'estree';
 
 import { IOptions } from '../../interfaces/options/IOptions';
 import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
-import { IStringArrayStorage } from '../../interfaces/storages/string-array-storage/IStringArrayStorage';
+import { IStringArrayStorage } from '../../interfaces/storages/string-array-transformers/IStringArrayStorage';
 import { IStringArrayStorageAnalyzer } from '../../interfaces/analyzers/string-array-storage-analyzer/IStringArrayStorageAnalyzer';
-import { IStringArrayStorageItemData } from '../../interfaces/storages/string-array-storage/IStringArrayStorageItem';
+import { IStringArrayStorageItemData } from '../../interfaces/storages/string-array-transformers/IStringArrayStorageItem';
 
 import { NodeGuards } from '../../node/NodeGuards';
 import { NodeMetadata } from '../../node/NodeMetadata';

+ 1 - 0
src/container/ServiceIdentifiers.ts

@@ -31,6 +31,7 @@ export enum ServiceIdentifiers {
     IIdentifierReplacer = 'IIdentifierReplacer',
     IJavaScriptObfuscator = 'IJavaScriptObfuscator',
     ILevelledTopologicalSorter = 'ILevelledTopologicalSorter',
+    ILiteralNodesCacheStorage = 'ILiteralNodesCacheStorage',
     ILogger = 'ILogger',
     INodeGuard = 'INodeGuard',
     INodeTransformer = 'INodeTransformer',

+ 8 - 2
src/container/modules/storages/StoragesModule.ts

@@ -4,13 +4,15 @@ import { ServiceIdentifiers } from '../../ServiceIdentifiers';
 import { TControlFlowStorage } from '../../../types/storages/TControlFlowStorage';
 import { TCustomCodeHelperGroupStorage } from '../../../types/storages/TCustomCodeHelperGroupStorage';
 
+import { ILiteralNodesCacheStorage } from '../../../interfaces/storages/string-array-transformers/ILiteralNodesCacheStorage';
 import { IOptions } from '../../../interfaces/options/IOptions';
 import { IRandomGenerator } from '../../../interfaces/utils/IRandomGenerator';
-import { IStringArrayStorage } from '../../../interfaces/storages/string-array-storage/IStringArrayStorage';
+import { IStringArrayStorage } from '../../../interfaces/storages/string-array-transformers/IStringArrayStorage';
 
 import { ControlFlowStorage } from '../../../storages/custom-nodes/ControlFlowStorage';
 import { CustomCodeHelperGroupStorage } from '../../../storages/custom-code-helpers/CustomCodeHelperGroupStorage';
-import { StringArrayStorage } from '../../../storages/string-array/StringArrayStorage';
+import { LiteralNodesCacheStorage } from '../../../storages/string-array-transformers/LiteralNodesCacheStorage';
+import { StringArrayStorage } from '../../../storages/string-array-transformers/StringArrayStorage';
 
 export const storagesModule: interfaces.ContainerModule = new ContainerModule((bind: interfaces.Bind) => {
     // storages
@@ -18,6 +20,10 @@ export const storagesModule: interfaces.ContainerModule = new ContainerModule((b
         .to(CustomCodeHelperGroupStorage)
         .inSingletonScope();
 
+    bind<ILiteralNodesCacheStorage>(ServiceIdentifiers.ILiteralNodesCacheStorage)
+        .to(LiteralNodesCacheStorage)
+        .inSingletonScope();
+
     bind<IStringArrayStorage>(ServiceIdentifiers.IStringArrayStorage)
         .to(StringArrayStorage)
         .inSingletonScope();

+ 1 - 1
src/custom-code-helpers/self-defending/templates/SelfDefendingNoEvalTemplate.ts

@@ -1,5 +1,5 @@
 /**
- * Notice, that second and third call to recursiveFunc1('indexOf') has cyrillic `е` character instead latin
+ * SelfDefendingTemplate. Enters code in infinity loop.
  *
  * @returns {string}
  */

+ 1 - 1
src/custom-code-helpers/string-array/StringArrayCallsWrapperCodeHelper.ts

@@ -9,7 +9,7 @@ import { ICustomCodeHelperObfuscator } from '../../interfaces/custom-code-helper
 import { IEscapeSequenceEncoder } from '../../interfaces/utils/IEscapeSequenceEncoder';
 import { IOptions } from '../../interfaces/options/IOptions';
 import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
-import { IStringArrayCallsWrapperNames } from '../../interfaces/storages/string-array-storage/IStringArrayCallsWrapperNames';
+import { IStringArrayCallsWrapperNames } from '../../interfaces/node-transformers/string-array-transformers/IStringArrayCallsWrapperNames';
 
 import { initializable } from '../../decorators/Initializable';
 

+ 1 - 1
src/custom-code-helpers/string-array/StringArrayCodeHelper.ts

@@ -8,7 +8,7 @@ import { ICustomCodeHelperFormatter } from '../../interfaces/custom-code-helpers
 import { ICustomCodeHelperObfuscator } from '../../interfaces/custom-code-helpers/ICustomCodeHelperObfuscator';
 import { IOptions } from '../../interfaces/options/IOptions';
 import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
-import { IStringArrayStorage } from '../../interfaces/storages/string-array-storage/IStringArrayStorage';
+import { IStringArrayStorage } from '../../interfaces/storages/string-array-transformers/IStringArrayStorage';
 
 import { initializable } from '../../decorators/Initializable';
 

+ 2 - 2
src/custom-code-helpers/string-array/group/StringArrayCodeHelperGroup.ts

@@ -11,8 +11,8 @@ import { ICallsGraphData } from '../../../interfaces/analyzers/calls-graph-analy
 import { ICustomCodeHelper } from '../../../interfaces/custom-code-helpers/ICustomCodeHelper';
 import { IOptions } from '../../../interfaces/options/IOptions';
 import { IRandomGenerator } from '../../../interfaces/utils/IRandomGenerator';
-import { IStringArrayCallsWrapperNames } from '../../../interfaces/storages/string-array-storage/IStringArrayCallsWrapperNames';
-import { IStringArrayStorage } from '../../../interfaces/storages/string-array-storage/IStringArrayStorage';
+import { IStringArrayCallsWrapperNames } from '../../../interfaces/node-transformers/string-array-transformers/IStringArrayCallsWrapperNames';
+import { IStringArrayStorage } from '../../../interfaces/storages/string-array-transformers/IStringArrayStorage';
 
 import { initializable } from '../../../decorators/Initializable';
 

+ 1 - 1
src/interfaces/IEncodedValue.ts

@@ -1,7 +1,7 @@
 import { TStringArrayEncoding } from '../types/options/TStringArrayEncoding';
 
 export interface IEncodedValue {
-    encoding: TStringArrayEncoding | null;
+    encoding: TStringArrayEncoding;
     encodedValue: string;
     decodeKey: string | null;
 }

+ 1 - 1
src/interfaces/analyzers/string-array-storage-analyzer/IStringArrayStorageAnalyzer.ts

@@ -1,7 +1,7 @@
 import * as ESTree from 'estree';
 
 import { IAnalyzer } from '../IAnalyzer';
-import { IStringArrayStorageItemData } from '../../storages/string-array-storage/IStringArrayStorageItem';
+import { IStringArrayStorageItemData } from '../../storages/string-array-transformers/IStringArrayStorageItem';
 
 export interface IStringArrayStorageAnalyzer extends IAnalyzer<[ESTree.Program], void> {
     /**

+ 0 - 0
src/interfaces/storages/string-array-storage/IStringArrayCallsWrapperNames.ts → src/interfaces/node-transformers/string-array-transformers/IStringArrayCallsWrapperNames.ts


+ 13 - 0
src/interfaces/node-transformers/string-array-transformers/IStringArrayFunctionCallsWrapperName.ts

@@ -0,0 +1,13 @@
+import { TStringArrayEncoding } from '../../../types/options/TStringArrayEncoding';
+
+export interface IStringArrayFunctionCallsWrapperName {
+    /**
+     * @type {TStringArrayEncoding}
+     */
+    encoding: TStringArrayEncoding;
+
+    /**
+     * @type {string}
+     */
+    name: string;
+}

+ 26 - 0
src/interfaces/storages/string-array-transformers/ILiteralNodesCacheStorage.ts

@@ -0,0 +1,26 @@
+import * as ESTree from 'estree';
+
+import { IMapStorage } from '../IMapStorage';
+import { IStringArrayStorageItemData } from './IStringArrayStorageItem';
+
+export interface ILiteralNodesCacheStorage extends IMapStorage <string, ESTree.Node> {
+    /**
+     * @param {string} literalValue
+     * @param {IStringArrayStorageItemData | undefined} stringArrayStorageItemData
+     * @returns {string}
+     */
+    buildKey (
+        literalValue: string,
+        stringArrayStorageItemData: IStringArrayStorageItemData | undefined,
+    ): string;
+
+    /**
+     * @param {string} key
+     * @param {IStringArrayStorageItemData | undefined} stringArrayStorageItemData
+     * @returns {boolean}
+     */
+    shouldUseCachedValue (
+        key: string,
+        stringArrayStorageItemData: IStringArrayStorageItemData | undefined
+    ): boolean;
+}

+ 1 - 1
src/interfaces/storages/string-array-storage/IStringArrayStorage.ts → src/interfaces/storages/string-array-transformers/IStringArrayStorage.ts

@@ -1,7 +1,7 @@
 import { TStringArrayEncoding } from '../../../types/options/TStringArrayEncoding';
 
 import { IMapStorage } from '../IMapStorage';
-import { IStringArrayCallsWrapperNames } from './IStringArrayCallsWrapperNames';
+import { IStringArrayCallsWrapperNames } from '../../node-transformers/string-array-transformers/IStringArrayCallsWrapperNames';
 import { IStringArrayStorageItemData } from './IStringArrayStorageItem';
 
 export interface IStringArrayStorage extends IMapStorage <string, IStringArrayStorageItemData> {

+ 0 - 0
src/interfaces/storages/string-array-storage/IStringArrayStorageItem.ts → src/interfaces/storages/string-array-transformers/IStringArrayStorageItem.ts


+ 6 - 0
src/interfaces/utils/IArrayUtils.ts

@@ -11,6 +11,12 @@ export interface IArrayUtils {
      */
     findMostOccurringElement <T extends string | number> (array: T[]): T | null;
 
+    /**
+     * @param {T[]} array
+     * @returns {T | null}
+     */
+    getLastElement <T> (array: T[]): T | null;
+
     /**
      * @param array
      * @param times

+ 183 - 22
src/node-transformers/string-array-transformers/StringArrayTransformer.ts

@@ -3,19 +3,26 @@ import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
 
 import * as ESTree from 'estree';
 
+import { TStringArrayEncoding } from '../../types/options/TStringArrayEncoding';
+import { TStringArrayFunctionCallsWrapperNamesMap } from '../../types/node-transformers/string-array-transformers/TStringArrayFunctionCallsWrapperNamesMap';
+
+import { IArrayUtils } from '../../interfaces/utils/IArrayUtils';
 import { IEscapeSequenceEncoder } from '../../interfaces/utils/IEscapeSequenceEncoder';
+import { IIdentifierNamesGenerator } from '../../interfaces/generators/identifier-names-generators/IIdentifierNamesGenerator';
+import { TIdentifierNamesGeneratorFactory } from '../../types/container/generators/TIdentifierNamesGeneratorFactory';
+import { ILiteralNodesCacheStorage } from '../../interfaces/storages/string-array-transformers/ILiteralNodesCacheStorage';
 import { IOptions } from '../../interfaces/options/IOptions';
 import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
-import { IStringArrayCallsWrapperNames } from '../../interfaces/storages/string-array-storage/IStringArrayCallsWrapperNames';
-import { IStringArrayStorage } from '../../interfaces/storages/string-array-storage/IStringArrayStorage';
+import { IStringArrayCallsWrapperNames } from '../../interfaces/node-transformers/string-array-transformers/IStringArrayCallsWrapperNames';
+import { IStringArrayStorage } from '../../interfaces/storages/string-array-transformers/IStringArrayStorage';
 import { IStringArrayStorageAnalyzer } from '../../interfaces/analyzers/string-array-storage-analyzer/IStringArrayStorageAnalyzer';
-import { IStringArrayStorageItemData } from '../../interfaces/storages/string-array-storage/IStringArrayStorageItem';
+import { IStringArrayStorageItemData } from '../../interfaces/storages/string-array-transformers/IStringArrayStorageItem';
 import { IVisitor } from '../../interfaces/node-transformers/IVisitor';
 
 import { NodeTransformationStage } from '../../enums/node-transformers/NodeTransformationStage';
-import { StringArrayEncoding } from '../../enums/StringArrayEncoding';
 
 import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
+import { NodeAppender } from '../../node/NodeAppender';
 import { NodeFactory } from '../../node/NodeFactory';
 import { NodeGuards } from '../../node/NodeGuards';
 import { NodeLiteralUtils } from '../../node/NodeLiteralUtils';
@@ -25,15 +32,31 @@ import { NumberUtils } from '../../utils/NumberUtils';
 
 @injectable()
 export class StringArrayTransformer extends AbstractNodeTransformer {
+    /**
+     * @type {IArrayUtils}
+     */
+    private readonly arrayUtils: IArrayUtils;
+
     /**
      * @type {IEscapeSequenceEncoder}
      */
     private readonly escapeSequenceEncoder: IEscapeSequenceEncoder;
 
     /**
-     * @type {Map<string, ESTree.Node>}
+     * @type {IIdentifierNamesGenerator}
+     */
+    private readonly identifierNamesGenerator: IIdentifierNamesGenerator;
+
+    /**
+     * @type {ILiteralNodesCacheStorage}
+     */
+    private readonly literalNodesCacheStorage: ILiteralNodesCacheStorage;
+
+    /**
+     * @type {Map<ESTree.Function, TStringArrayFunctionCallsWrapperNamesMap>}
      */
-    private readonly nodesCache: Map <string, ESTree.Node> = new Map();
+    private readonly stringArrayFunctionsCallsWrapperNamesMap:
+        Map<ESTree.Function, TStringArrayFunctionCallsWrapperNamesMap> = new Map();
 
     /**
      * @type {IStringArrayStorage}
@@ -45,25 +68,40 @@ export class StringArrayTransformer extends AbstractNodeTransformer {
      */
     private readonly stringArrayStorageAnalyzer: IStringArrayStorageAnalyzer;
 
+    /**
+     * @type {ESTree.Function[]}
+     */
+    private readonly visitedFunctionNodesStack: ESTree.Function[] = [];
+
     /**
      * @param {IRandomGenerator} randomGenerator
      * @param {IOptions} options
+     * @param {ILiteralNodesCacheStorage} literalNodesCacheStorage
      * @param {IStringArrayStorage} stringArrayStorage
      * @param {IStringArrayStorageAnalyzer} stringArrayStorageAnalyzer
+     * @param {IArrayUtils} arrayUtils
      * @param {IEscapeSequenceEncoder} escapeSequenceEncoder
+     * @param {TIdentifierNamesGeneratorFactory} identifierNamesGeneratorFactory
      */
     public constructor (
         @inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
         @inject(ServiceIdentifiers.IOptions) options: IOptions,
+        @inject(ServiceIdentifiers.ILiteralNodesCacheStorage) literalNodesCacheStorage: ILiteralNodesCacheStorage,
         @inject(ServiceIdentifiers.IStringArrayStorage) stringArrayStorage: IStringArrayStorage,
         @inject(ServiceIdentifiers.IStringArrayStorageAnalyzer) stringArrayStorageAnalyzer: IStringArrayStorageAnalyzer,
-        @inject(ServiceIdentifiers.IEscapeSequenceEncoder) escapeSequenceEncoder: IEscapeSequenceEncoder
+        @inject(ServiceIdentifiers.IArrayUtils) arrayUtils: IArrayUtils,
+        @inject(ServiceIdentifiers.IEscapeSequenceEncoder) escapeSequenceEncoder: IEscapeSequenceEncoder,
+        @inject(ServiceIdentifiers.Factory__IIdentifierNamesGenerator)
+            identifierNamesGeneratorFactory: TIdentifierNamesGeneratorFactory,
     ) {
         super(randomGenerator, options);
 
+        this.literalNodesCacheStorage = literalNodesCacheStorage;
         this.stringArrayStorage = stringArrayStorage;
         this.stringArrayStorageAnalyzer = stringArrayStorageAnalyzer;
+        this.arrayUtils = arrayUtils;
         this.escapeSequenceEncoder = escapeSequenceEncoder;
+        this.identifierNamesGenerator = identifierNamesGeneratorFactory(options);
     }
 
     /**
@@ -103,9 +141,20 @@ export class StringArrayTransformer extends AbstractNodeTransformer {
                             this.prepareNode(node);
                         }
 
+                        if (NodeGuards.isFunctionNode(node)) {
+                            this.onFunctionNodeEnter(node);
+                        }
+
                         if (parentNode && NodeGuards.isLiteralNode(node) && !NodeMetadata.isReplacedLiteral(node)) {
                             return this.transformNode(node, parentNode);
                         }
+                    },
+                    leave: (node: ESTree.Node): ESTree.Node | undefined => {
+                        if (NodeGuards.isFunctionNode(node)) {
+                            this.onFunctionNodeLeave();
+
+                            return this.transformFunctionNode(node);
+                        }
                     }
                 };
 
@@ -150,21 +199,20 @@ export class StringArrayTransformer extends AbstractNodeTransformer {
 
         const literalValue: ESTree.SimpleLiteral['value'] = literalNode.value;
 
-        const stringArrayStorageItemData: IStringArrayStorageItemData | undefined = this.stringArrayStorageAnalyzer
-            .getItemDataForLiteralNode(literalNode);
-        const cacheKey: string = `${literalValue}-${Boolean(stringArrayStorageItemData)}`;
-        const useCachedValue: boolean = this.nodesCache.has(cacheKey)
-            && stringArrayStorageItemData?.encoding !== StringArrayEncoding.Rc4;
+        const stringArrayStorageItemData: IStringArrayStorageItemData | undefined =
+            this.stringArrayStorageAnalyzer.getItemDataForLiteralNode(literalNode);
+        const cacheKey: string = this.literalNodesCacheStorage.buildKey(literalValue, stringArrayStorageItemData);
+        const useCachedValue: boolean = this.literalNodesCacheStorage.shouldUseCachedValue(cacheKey, stringArrayStorageItemData);
 
         if (useCachedValue) {
-            return <ESTree.Node>this.nodesCache.get(cacheKey);
+            return <ESTree.Node>this.literalNodesCacheStorage.get(cacheKey);
         }
 
         const resultNode: ESTree.Node = stringArrayStorageItemData
             ? this.getStringArrayCallNode(stringArrayStorageItemData)
             : this.getLiteralNode(literalValue);
 
-        this.nodesCache.set(cacheKey, resultNode);
+        this.literalNodesCacheStorage.set(cacheKey, resultNode);
 
         NodeUtils.parentizeNode(resultNode, parentNode);
 
@@ -184,7 +232,7 @@ export class StringArrayTransformer extends AbstractNodeTransformer {
      * @returns {Node}
      */
     private getStringArrayCallNode (stringArrayStorageItemData: IStringArrayStorageItemData): ESTree.Node {
-        const { index, encoding, decodeKey } = stringArrayStorageItemData;
+        const { index, decodeKey } = stringArrayStorageItemData;
 
         const hexadecimalIndex: string = NumberUtils.toHex(index);
         const callExpressionArgs: (ESTree.Expression | ESTree.SpreadElement)[] = [
@@ -195,13 +243,7 @@ export class StringArrayTransformer extends AbstractNodeTransformer {
             callExpressionArgs.push(StringArrayTransformer.getRc4KeyLiteralNode(decodeKey));
         }
 
-        const stringArrayCallsWrapperNames: IStringArrayCallsWrapperNames =
-            this.stringArrayStorage.getStorageCallsWrapperNames(encoding);
-        const stringArrayCallsWrapperName: string = stringArrayCallsWrapperNames.intermediateNames.length
-            ? this.randomGenerator
-                .getRandomGenerator()
-                .pickone(stringArrayCallsWrapperNames.intermediateNames)
-            : stringArrayCallsWrapperNames.name;
+        const stringArrayCallsWrapperName: string = this.getStringArrayCallsWrapperName(stringArrayStorageItemData);
 
         const stringArrayIdentifierNode: ESTree.Identifier = NodeFactory.identifierNode(
             stringArrayCallsWrapperName
@@ -213,6 +255,125 @@ export class StringArrayTransformer extends AbstractNodeTransformer {
         );
     }
 
+    /**
+     * @param {IStringArrayStorageItemData} stringArrayStorageItemData
+     * @returns {string}
+     */
+    private getStringArrayCallsWrapperName (stringArrayStorageItemData: IStringArrayStorageItemData): string {
+        const {encoding} = stringArrayStorageItemData;
+
+        const stringArrayCallsWrapperNames: IStringArrayCallsWrapperNames =
+            this.stringArrayStorage.getStorageCallsWrapperNames(encoding);
+
+        // Name of the string array calls wrapper itself
+        if (!this.options.stringArrayIntermediateVariablesCount) {
+            return stringArrayCallsWrapperNames.name;
+        }
+
+        const currentFunctionNode: ESTree.Function | null = this.arrayUtils.getLastElement(this.visitedFunctionNodesStack);
+
+        // Variant #1: inside `Program` scope, return name of root calls wrapper
+        if (!currentFunctionNode) {
+            return this.getStringArrayIntermediateCallsWrapperName(encoding);
+        }
+
+        // Variant #2: inside `Function` scope, return name of function calls wrapper
+        const stringArrayIntermediateCallsWrapperNames: TStringArrayFunctionCallsWrapperNamesMap = currentFunctionNode
+            ? this.stringArrayFunctionsCallsWrapperNamesMap.get(currentFunctionNode) ?? {}
+            : {};
+        let stringArrayIntermediateCallsWrapperName: string = stringArrayIntermediateCallsWrapperNames[encoding]?.name ?? '';
+
+        if (currentFunctionNode && !stringArrayIntermediateCallsWrapperName) {
+            stringArrayIntermediateCallsWrapperName = this.identifierNamesGenerator.generateForLexicalScope(currentFunctionNode);
+            stringArrayIntermediateCallsWrapperNames[encoding] = {
+                encoding,
+                name: stringArrayIntermediateCallsWrapperName
+            };
+
+            this.stringArrayFunctionsCallsWrapperNamesMap.set(
+                currentFunctionNode,
+                stringArrayIntermediateCallsWrapperNames
+            );
+        }
+
+        return stringArrayIntermediateCallsWrapperName;
+    }
+
+    /**
+     * @param {TStringArrayEncoding} encoding
+     * @returns {string}
+     */
+    private getStringArrayIntermediateCallsWrapperName (encoding: TStringArrayEncoding): string {
+        const stringArrayCallsWrapperNames: IStringArrayCallsWrapperNames =
+            this.stringArrayStorage.getStorageCallsWrapperNames(encoding);
+
+        return stringArrayCallsWrapperNames.intermediateNames.length
+            ? this.randomGenerator
+                .getRandomGenerator()
+                .pickone(stringArrayCallsWrapperNames.intermediateNames)
+            : stringArrayCallsWrapperNames.name;
+    }
+
+    /**
+     * @param {Function} functionNode
+     */
+    private onFunctionNodeEnter (functionNode: ESTree.Function): void {
+        this.visitedFunctionNodesStack.push(functionNode);
+    }
+
+    private onFunctionNodeLeave (): void {
+        this.visitedFunctionNodesStack.pop();
+    }
+
+    /**
+     * @param {Function} functionNode
+     * @returns {Function}
+     */
+    private transformFunctionNode (functionNode: ESTree.Function): ESTree.Function {
+        if (!this.options.stringArrayIntermediateVariablesCount) {
+            return functionNode;
+        }
+
+        if (!NodeGuards.isBlockStatementNode(functionNode.body)) {
+            return functionNode;
+        }
+
+        const stringArrayFunctionCallsWrapperNamesMap: TStringArrayFunctionCallsWrapperNamesMap | null =
+            this.stringArrayFunctionsCallsWrapperNamesMap.get(functionNode) ?? null;
+
+        if (!stringArrayFunctionCallsWrapperNamesMap) {
+            return functionNode;
+        }
+
+        const stringArrayFunctionCallsWrapperNames = Object.values(stringArrayFunctionCallsWrapperNamesMap);
+
+        for (const stringArrayFunctionCallsWrapperName of stringArrayFunctionCallsWrapperNames) {
+            if (!stringArrayFunctionCallsWrapperName) {
+                continue;
+            }
+
+            const {encoding, name} = stringArrayFunctionCallsWrapperName;
+            const stringArrayCallsWrapperName: string = this.getStringArrayIntermediateCallsWrapperName(encoding);
+
+            NodeAppender.prepend(
+                functionNode.body,
+                [
+                    NodeFactory.variableDeclarationNode(
+                        [
+                            NodeFactory.variableDeclaratorNode(
+                                NodeFactory.identifierNode(name),
+                                NodeFactory.identifierNode(stringArrayCallsWrapperName)
+                            )
+                        ],
+                        'var',
+                    )
+                ]
+            );
+        }
+
+        return functionNode;
+    }
+
     /**
      * @param {Literal} literalNode
      * @param {Node} parentNode

+ 55 - 0
src/storages/string-array-transformers/LiteralNodesCacheStorage.ts

@@ -0,0 +1,55 @@
+import { inject, injectable } from 'inversify';
+import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
+
+import * as ESTree from 'estree';
+
+import { ILiteralNodesCacheStorage } from '../../interfaces/storages/string-array-transformers/ILiteralNodesCacheStorage';
+import { IOptions } from '../../interfaces/options/IOptions';
+import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
+import { IStringArrayStorageItemData } from '../../interfaces/storages/string-array-transformers/IStringArrayStorageItem';
+
+import { StringArrayEncoding } from '../../enums/StringArrayEncoding';
+
+import { MapStorage } from '../MapStorage';
+
+@injectable()
+export class LiteralNodesCacheStorage extends MapStorage <string, ESTree.Node> implements ILiteralNodesCacheStorage {
+    /**
+     * @param {IRandomGenerator} randomGenerator
+     * @param {IOptions} options
+     */
+    public constructor (
+        @inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
+        @inject(ServiceIdentifiers.IOptions) options: IOptions
+    ) {
+        super(randomGenerator, options);
+    }
+
+    /**
+     * @param {string} literalValue
+     * @param {IStringArrayStorageItemData | undefined} stringArrayStorageItemData
+     * @returns {string}
+     */
+    public buildKey (
+        literalValue: string,
+        stringArrayStorageItemData: IStringArrayStorageItemData | undefined,
+    ): string {
+        return `${literalValue}-${Boolean(stringArrayStorageItemData)}`;
+    }
+
+    /**
+     * @param {string} key
+     * @param {IStringArrayStorageItemData | undefined} stringArrayStorageItemData
+     * @returns {boolean}
+     */
+    public shouldUseCachedValue (
+        key: string,
+        stringArrayStorageItemData: IStringArrayStorageItemData | undefined
+    ): boolean {
+        // for each function scope different nodes will be created, so cache have no sense
+        return !this.options.stringArrayIntermediateVariablesCount
+            // different nodes will be created with different rc4 keys, so cache have no sense
+            && stringArrayStorageItemData?.encoding !== StringArrayEncoding.Rc4
+            && this.storage.has(key);
+    }
+}

+ 7 - 3
src/storages/string-array/StringArrayStorage.ts → src/storages/string-array-transformers/StringArrayStorage.ts

@@ -11,9 +11,9 @@ import { IEscapeSequenceEncoder } from '../../interfaces/utils/IEscapeSequenceEn
 import { IIdentifierNamesGenerator } from '../../interfaces/generators/identifier-names-generators/IIdentifierNamesGenerator';
 import { IOptions } from '../../interfaces/options/IOptions';
 import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
-import { IStringArrayCallsWrapperNames } from '../../interfaces/storages/string-array-storage/IStringArrayCallsWrapperNames';
-import { IStringArrayStorage } from '../../interfaces/storages/string-array-storage/IStringArrayStorage';
-import { IStringArrayStorageItemData } from '../../interfaces/storages/string-array-storage/IStringArrayStorageItem';
+import { IStringArrayCallsWrapperNames } from '../../interfaces/node-transformers/string-array-transformers/IStringArrayCallsWrapperNames';
+import { IStringArrayStorage } from '../../interfaces/storages/string-array-transformers/IStringArrayStorage';
+import { IStringArrayStorageItemData } from '../../interfaces/storages/string-array-transformers/IStringArrayStorageItem';
 
 import { StringArrayEncoding } from '../../enums/StringArrayEncoding';
 
@@ -276,6 +276,10 @@ export class StringArrayStorage extends MapStorage <string, IStringArrayStorageI
                 .pickone(this.options.stringArrayEncoding)
             : null;
 
+        if (!encoding) {
+            throw new Error('`stringArrayEncoding` option array is empty');
+        }
+
         switch (encoding) {
             /**
              * For rc4 there is a possible chance of a collision between encoded values that were received from

+ 7 - 0
src/types/node-transformers/string-array-transformers/TStringArrayFunctionCallsWrapperNamesMap.ts

@@ -0,0 +1,7 @@
+import { TStringArrayEncoding } from '../../options/TStringArrayEncoding';
+
+import { IStringArrayFunctionCallsWrapperName } from '../../../interfaces/node-transformers/string-array-transformers/IStringArrayFunctionCallsWrapperName';
+
+export type TStringArrayFunctionCallsWrapperNamesMap = Partial<{
+    [key in TStringArrayEncoding]: IStringArrayFunctionCallsWrapperName;
+}>;

+ 10 - 0
src/utils/ArrayUtils.ts

@@ -65,6 +65,16 @@ export class ArrayUtils implements IArrayUtils {
         return mostOccurringElement;
     }
 
+    /**
+     * @param {T[]} array
+     * @returns {T | null}
+     */
+    public getLastElement <T> (array: T[]): T | null {
+        const arrayLength: number = array.length;
+
+        return array[arrayLength - 1] ?? null;
+    }
+
     /**
      * @param {T[]} array
      * @param {number} times

+ 3 - 6
test/dev/dev.ts

@@ -9,19 +9,16 @@ import { StringArrayEncoding } from '../../src/enums/StringArrayEncoding';
     let obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
         `
             const foo = 'foo';
-            const bar = 'bar';
-            const baz = 'baz';
-            
-            console.log(foo, bar, baz);
+            const bar = 'foo';
         `,
         {
             ...NO_ADDITIONAL_NODES_PRESET,
             compact: false,
             stringArray: true,
             stringArrayThreshold: 1,
-            stringArrayIntermediateVariablesCount: 2,
+            stringArrayIntermediateVariablesCount: 0,
             stringArrayEncoding: [
-                StringArrayEncoding.Rc4
+                StringArrayEncoding.None
             ]
         }
     ).getObfuscatedCode();

+ 3 - 3
test/functional-tests/storages/string-array-storage/StringArrayStorage.spec.ts → test/functional-tests/storages/string-array-transformers/string-array-storage/StringArrayStorage.spec.ts

@@ -1,10 +1,10 @@
 import { assert } from 'chai';
 
-import { NO_ADDITIONAL_NODES_PRESET } from '../../../../src/options/presets/NoCustomNodes';
+import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/NoCustomNodes';
 
-import { readFileAsString } from '../../../helpers/readFileAsString';
+import { readFileAsString } from '../../../../helpers/readFileAsString';
 
-import { JavaScriptObfuscator } from '../../../../src/JavaScriptObfuscatorFacade';
+import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscatorFacade';
 
 describe('StringArrayStorage', () => {
     describe('Rotate string array', function () {

+ 0 - 0
test/functional-tests/storages/string-array-storage/fixtures/one-string.js → test/functional-tests/storages/string-array-transformers/string-array-storage/fixtures/one-string.js


+ 0 - 0
test/functional-tests/storages/string-array-storage/fixtures/three-strings.js → test/functional-tests/storages/string-array-transformers/string-array-storage/fixtures/three-strings.js


+ 3 - 2
test/index.spec.ts

@@ -36,7 +36,8 @@ import './unit-tests/options/ValidationErrorsFormatter.spec';
 import './unit-tests/source-code/ObfuscatedCode.spec';
 import './unit-tests/storages/ArrayStorage.spec';
 import './unit-tests/storages/MapStorage.spec';
-import './unit-tests/storages/string-array/StringArrayStorage.spec';
+import './unit-tests/storages/string-array-transformers/literal-nodes-cache/LiteralNodesCacheStorage.spec';
+import './unit-tests/storages/string-array-transformers/string-array/StringArrayStorage.spec';
 import './unit-tests/utils/ArrayUtils.spec';
 import './unit-tests/utils/CryptUtils.spec';
 import './unit-tests/utils/CryptUtilsSwappedAlphabet.spec';
@@ -116,7 +117,7 @@ import './functional-tests/node-transformers/simplifying-transformers/variable-d
 import './functional-tests/node-transformers/string-array-transformers/string-array-transformer/StringArrayTransformer.spec';
 import './functional-tests/options/OptionsNormalizer.spec';
 import './functional-tests/options/domain-lock/Validation.spec';
-import './functional-tests/storages/string-array-storage/StringArrayStorage.spec';
+import './functional-tests/storages/string-array-transformers/string-array-storage/StringArrayStorage.spec';
 
 /**
  * Performance tests

+ 1 - 1
test/unit-tests/analyzers/string-array-storage-analyzer/StringArrayStorageAnalyzer.spec.ts

@@ -9,7 +9,7 @@ import { TInputOptions } from '../../../../src/types/options/TInputOptions';
 
 import { IInversifyContainerFacade } from '../../../../src/interfaces/container/IInversifyContainerFacade';
 import { IStringArrayStorageAnalyzer } from '../../../../src/interfaces/analyzers/string-array-storage-analyzer/IStringArrayStorageAnalyzer';
-import { IStringArrayStorageItemData } from '../../../../src/interfaces/storages/string-array-storage/IStringArrayStorageItem';
+import { IStringArrayStorageItemData } from '../../../../src/interfaces/storages/string-array-transformers/IStringArrayStorageItem';
 
 import { StringArrayEncoding } from '../../../../src/enums/StringArrayEncoding';
 

+ 157 - 0
test/unit-tests/storages/string-array-transformers/literal-nodes-cache/LiteralNodesCacheStorage.spec.ts

@@ -0,0 +1,157 @@
+import 'reflect-metadata';
+
+import { assert } from 'chai';
+import * as ESTree from 'estree';
+
+import { ServiceIdentifiers } from '../../../../../src/container/ServiceIdentifiers';
+
+import { TInputOptions } from '../../../../../src/types/options/TInputOptions';
+
+import { IInversifyContainerFacade } from '../../../../../src/interfaces/container/IInversifyContainerFacade';
+import { ILiteralNodesCacheStorage } from '../../../../../src/interfaces/storages/string-array-transformers/ILiteralNodesCacheStorage';
+
+import { StringArrayEncoding } from '../../../../../src/enums/StringArrayEncoding';
+
+import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/NoCustomNodes';
+
+import { InversifyContainerFacade } from '../../../../../src/container/InversifyContainerFacade';
+import { NodeFactory } from '../../../../../src/node/NodeFactory';
+
+/**
+ * @returns {IMapStorage<string, V>}
+ */
+const getStorageInstance = (options: TInputOptions = {}): ILiteralNodesCacheStorage => {
+    const inversifyContainerFacade: IInversifyContainerFacade = new InversifyContainerFacade();
+
+    inversifyContainerFacade.load('', '', {
+        ...NO_ADDITIONAL_NODES_PRESET,
+        ...options
+    });
+
+    const storage: ILiteralNodesCacheStorage = inversifyContainerFacade.get(ServiceIdentifiers.ILiteralNodesCacheStorage);
+
+    storage.initialize();
+
+    return storage;
+};
+
+describe('LiteralNodesCacheStorage', () => {
+    describe('buildKey', () => {
+        const expectedCacheKey: string = 'foo-true';
+
+       let cacheKey: string;
+
+        before(() => {
+            const literalNodesCacheStorage: ILiteralNodesCacheStorage = getStorageInstance();
+
+            cacheKey = literalNodesCacheStorage.buildKey(
+                'foo',
+                {
+                    index: 1,
+                    value: '_0x123abc',
+                    encoding: StringArrayEncoding.Rc4,
+                    encodedValue: 'encoded_value',
+                    decodeKey: 'key'
+                }
+            );
+        });
+
+        it('should build a key for the storage', () => {
+            assert.equal(cacheKey, expectedCacheKey);
+        });
+    });
+
+    describe('shouldUseCachedValue', () => {
+        const literalNode: ESTree.Literal =  NodeFactory.literalNode('foo');
+        const key: string = 'key';
+
+        describe('Encoding is not `rc4` and `stringArrayIntermediateVariablesCount` option is disabled', () => {
+            const expectedResult: boolean = true;
+
+            let result: boolean;
+
+            before(() => {
+                const literalNodesCacheStorage: ILiteralNodesCacheStorage = getStorageInstance({
+                    stringArrayIntermediateVariablesCount: 0
+                });
+
+                literalNodesCacheStorage.set(key, literalNode);
+
+                result = literalNodesCacheStorage.shouldUseCachedValue(
+                    key,
+                    {
+                        index: 1,
+                        value: '_0x123abc',
+                        encoding: StringArrayEncoding.Base64,
+                        encodedValue: 'encoded_value',
+                        decodeKey: 'key'
+                    },
+                );
+            });
+
+            it('should check if can use cached value', () => {
+                assert.equal(result, expectedResult);
+            });
+        });
+
+        describe('Encoding is `rc4` and `stringArrayIntermediateVariablesCount` option is disabled', () => {
+            const expectedResult: boolean = false
+
+            let result: boolean;
+
+            before(() => {
+                const literalNodesCacheStorage: ILiteralNodesCacheStorage = getStorageInstance({
+                    stringArrayIntermediateVariablesCount: 0
+                });
+
+                literalNodesCacheStorage.set(key, literalNode);
+
+                result = literalNodesCacheStorage.shouldUseCachedValue(
+                    key,
+                    {
+                        index: 1,
+                        value: '_0x123abc',
+                        encoding: StringArrayEncoding.Rc4,
+                        encodedValue: 'encoded_value',
+                        decodeKey: 'key'
+                    },
+                );
+            });
+
+            it('should check if can use cached value', () => {
+                assert.equal(result, expectedResult);
+            });
+        });
+
+        describe('Encoding is not `rc4` and `stringArrayIntermediateVariablesCount` option is enabled', () => {
+            const expectedResult: boolean = false;
+
+            let result: boolean;
+
+            before(() => {
+                const literalNodesCacheStorage: ILiteralNodesCacheStorage = getStorageInstance({
+                    stringArray: true,
+                    stringArrayThreshold: 1,
+                    stringArrayIntermediateVariablesCount: 5
+                });
+
+                literalNodesCacheStorage.set(key, literalNode);
+
+                result = literalNodesCacheStorage.shouldUseCachedValue(
+                    key,
+                    {
+                        index: 1,
+                        value: '_0x123abc',
+                        encoding: StringArrayEncoding.Base64,
+                        encodedValue: 'encoded_value',
+                        decodeKey: 'key'
+                    },
+                );
+            });
+
+            it('should check if can use cached value', () => {
+                assert.equal(result, expectedResult);
+            });
+        });
+    });
+});

+ 7 - 7
test/unit-tests/storages/string-array/StringArrayStorage.spec.ts → test/unit-tests/storages/string-array-transformers/string-array/StringArrayStorage.spec.ts

@@ -2,18 +2,18 @@ import 'reflect-metadata';
 
 import { assert } from 'chai';
 
-import { ServiceIdentifiers } from '../../../../src/container/ServiceIdentifiers';
+import { ServiceIdentifiers } from '../../../../../src/container/ServiceIdentifiers';
 
-import { TInputOptions } from '../../../../src/types/options/TInputOptions';
+import { TInputOptions } from '../../../../../src/types/options/TInputOptions';
 
-import { IInversifyContainerFacade } from '../../../../src/interfaces/container/IInversifyContainerFacade';
-import { IStringArrayStorage } from '../../../../src/interfaces/storages/string-array-storage/IStringArrayStorage';
+import { IInversifyContainerFacade } from '../../../../../src/interfaces/container/IInversifyContainerFacade';
+import { IStringArrayStorage } from '../../../../../src/interfaces/storages/string-array-transformers/IStringArrayStorage';
 
-import { StringArrayEncoding } from '../../../../src/enums/StringArrayEncoding';
+import { StringArrayEncoding } from '../../../../../src/enums/StringArrayEncoding';
 
-import { NO_ADDITIONAL_NODES_PRESET } from '../../../../src/options/presets/NoCustomNodes';
+import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/NoCustomNodes';
 
-import { InversifyContainerFacade } from '../../../../src/container/InversifyContainerFacade';
+import { InversifyContainerFacade } from '../../../../../src/container/InversifyContainerFacade';
 
 /**
  * @returns {IMapStorage<string, V>}

+ 47 - 0
test/unit-tests/utils/ArrayUtils.spec.ts

@@ -113,6 +113,53 @@ describe('ArrayUtils', () => {
         });
     });
 
+    describe('getLastElement', () => {
+        describe('empty array', () => {
+            const array: string[] = [];
+            const expectedLastElement: null = null;
+
+            let lastElement: string | null;
+
+            before(() => {
+                lastElement = arrayUtils.getLastElement(array);
+            });
+
+            it('should return null if array is empty', () => {
+                assert.equal(lastElement, expectedLastElement);
+            });
+        });
+
+        describe('array length: `1`', () => {
+            const array: string[] = ['foo'];
+            const expectedLastElement: string = 'foo';
+
+            let lastElement: string | null;
+
+            before(() => {
+                lastElement = arrayUtils.getLastElement(array);
+            });
+
+            it('should return first element for array with length: `1`', () => {
+                assert.equal(lastElement, expectedLastElement);
+            });
+        });
+
+        describe('array length: `3`', () => {
+            const array: string[] = ['foo', 'bar', 'baz'];
+            const expectedLastElement: string = 'baz';
+
+            let lastElement: string | null;
+
+            before(() => {
+                lastElement = arrayUtils.getLastElement(array);
+            });
+
+            it('should return last element for array with length: `3`', () => {
+                assert.equal(lastElement, expectedLastElement);
+            });
+        });
+    });
+
     describe('rotate', () => {
         let array: number[],
             rotatedArray: number[];

+ 45 - 45
yarn.lock

@@ -465,61 +465,61 @@
   resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.15.2.tgz#927997342bb9f4a5185a86e6579a0a18afc33b0a"
   integrity sha512-67ZgZpAlhIICIdfQrB5fnDvaKFcDxpKibxznfYRVAT4mQE41Dido/3Ty+E3xGBmTogc5+0Qb8tWhna+5B8z1iQ==
 
-"@typescript-eslint/eslint-plugin@4.0.1":
-  version "4.0.1"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.0.1.tgz#88bde9239e29d688315718552cf80a3490491017"
-  integrity sha512-pQZtXupCn11O4AwpYVUX4PDFfmIJl90ZgrEBg0CEcqlwvPiG0uY81fimr1oMFblZnpKAq6prrT9a59pj1x58rw==
+"@typescript-eslint/[email protected].0":
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.1.0.tgz#7d309f60815ff35e9627ad85e41928d7b7fd443f"
+  integrity sha512-U+nRJx8XDUqJxYF0FCXbpmD9nWt/xHDDG0zsw1vrVYAmEAuD/r49iowfurjSL2uTA2JsgtpsyG7mjO7PHf2dYw==
   dependencies:
-    "@typescript-eslint/experimental-utils" "4.0.1"
-    "@typescript-eslint/scope-manager" "4.0.1"
+    "@typescript-eslint/experimental-utils" "4.1.0"
+    "@typescript-eslint/scope-manager" "4.1.0"
     debug "^4.1.1"
     functional-red-black-tree "^1.0.1"
     regexpp "^3.0.0"
     semver "^7.3.2"
     tsutils "^3.17.1"
 
-"@typescript-eslint/experimental-utils@4.0.1":
-  version "4.0.1"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.0.1.tgz#7d9a3ab6821ad5274dad2186c1aa0d93afd696eb"
-  integrity sha512-gAqOjLiHoED79iYTt3F4uSHrYmg/GPz/zGezdB0jAdr6S6gwNiR/j7cTZ8nREKVzMVKLd9G3xbg1sV9GClW3sw==
+"@typescript-eslint/[email protected].0":
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.1.0.tgz#263d7225645c09a411c8735eeffd417f50f49026"
+  integrity sha512-paEYLA37iqRIDPeQwAmoYSiZ3PiHsaAc3igFeBTeqRHgPnHjHLJ9OGdmP6nwAkF65p2QzEsEBtpjNUBWByNWzA==
   dependencies:
     "@types/json-schema" "^7.0.3"
-    "@typescript-eslint/scope-manager" "4.0.1"
-    "@typescript-eslint/types" "4.0.1"
-    "@typescript-eslint/typescript-estree" "4.0.1"
+    "@typescript-eslint/scope-manager" "4.1.0"
+    "@typescript-eslint/types" "4.1.0"
+    "@typescript-eslint/typescript-estree" "4.1.0"
     eslint-scope "^5.0.0"
     eslint-utils "^2.0.0"
 
-"@typescript-eslint/parser@4.0.1":
-  version "4.0.1"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.0.1.tgz#73772080db7a7a4534a35d719e006f503e664dc3"
-  integrity sha512-1+qLmXHNAWSQ7RB6fdSQszAiA7JTwzakj5cNYjBTUmpH2cqilxMZEIV+DRKjVZs8NzP3ALmKexB0w/ExjcK9Iw==
+"@typescript-eslint/[email protected].0":
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.1.0.tgz#9b0409411725f14cd7faa81a664e5051225961db"
+  integrity sha512-hM/WNCQTzDHgS0Ke3cR9zPndL3OTKr9OoN9CL3UqulsAjYDrglSwIIgswSmHBcSbOzLmgaMARwrQEbIumIglvQ==
   dependencies:
-    "@typescript-eslint/scope-manager" "4.0.1"
-    "@typescript-eslint/types" "4.0.1"
-    "@typescript-eslint/typescript-estree" "4.0.1"
+    "@typescript-eslint/scope-manager" "4.1.0"
+    "@typescript-eslint/types" "4.1.0"
+    "@typescript-eslint/typescript-estree" "4.1.0"
     debug "^4.1.1"
 
-"@typescript-eslint/scope-manager@4.0.1":
-  version "4.0.1"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.0.1.tgz#24d93c3000bdfcc5a157dc4d32b742405a8631b5"
-  integrity sha512-u3YEXVJ8jsj7QCJk3om0Y457fy2euEOkkzxIB/LKU3MdyI+FJ2gI0M4aKEaXzwCSfNDiZ13a3lDo5DVozc+XLQ==
+"@typescript-eslint/[email protected].0":
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.1.0.tgz#9e389745ee9cfe12252ed1e9958808abd6b3a683"
+  integrity sha512-HD1/u8vFNnxwiHqlWKC/Pigdn0Mvxi84Y6GzbZ5f5sbLrFKu0al02573Er+D63Sw67IffVUXR0uR8rpdfdk+vA==
   dependencies:
-    "@typescript-eslint/types" "4.0.1"
-    "@typescript-eslint/visitor-keys" "4.0.1"
+    "@typescript-eslint/types" "4.1.0"
+    "@typescript-eslint/visitor-keys" "4.1.0"
 
-"@typescript-eslint/types@4.0.1":
-  version "4.0.1"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.0.1.tgz#1cf72582f764931f085cb8230ff215980fe467b2"
-  integrity sha512-S+gD3fgbkZYW2rnbjugNMqibm9HpEjqZBZkTiI3PwbbNGWmAcxolWIUwZ0SKeG4Dy2ktpKKaI/6+HGYVH8Qrlg==
+"@typescript-eslint/[email protected].0":
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.1.0.tgz#edbd3fec346f34e13ce7aa176b03b497a32c496a"
+  integrity sha512-rkBqWsO7m01XckP9R2YHVN8mySOKKY2cophGM8K5uDK89ArCgahItQYdbg/3n8xMxzu2elss+an1TphlUpDuJw==
 
-"@typescript-eslint/typescript-estree@4.0.1":
-  version "4.0.1"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.0.1.tgz#29a43c7060641ec51c902d9f50ac7c5866ec479f"
-  integrity sha512-zGzleORFXrRWRJAMLTB2iJD1IZbCPkg4hsI8mGdpYlKaqzvKYSEWVAYh14eauaR+qIoZVWrXgYSXqLtTlxotiw==
+"@typescript-eslint/[email protected].0":
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.1.0.tgz#394046ead25164494218c0e3d6b960695ea967f6"
+  integrity sha512-r6et57qqKAWU173nWyw31x7OfgmKfMEcjJl9vlJEzS+kf9uKNRr4AVTRXfTCwebr7bdiVEkfRY5xGnpPaNPe4Q==
   dependencies:
-    "@typescript-eslint/types" "4.0.1"
-    "@typescript-eslint/visitor-keys" "4.0.1"
+    "@typescript-eslint/types" "4.1.0"
+    "@typescript-eslint/visitor-keys" "4.1.0"
     debug "^4.1.1"
     globby "^11.0.1"
     is-glob "^4.0.1"
@@ -527,12 +527,12 @@
     semver "^7.3.2"
     tsutils "^3.17.1"
 
-"@typescript-eslint/visitor-keys@4.0.1":
-  version "4.0.1"
-  resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.0.1.tgz#d4e8de62775f2a6db71c7e8539633680039fdd6c"
-  integrity sha512-yBSqd6FjnTzbg5RUy9J+9kJEyQjTI34JdGMJz+9ttlJzLCnGkBikxw+N5n2VDcc3CesbIEJ0MnZc5uRYnrEnCw==
+"@typescript-eslint/[email protected].0":
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.1.0.tgz#b2d528c9484e7eda1aa4f86ccf0432fb16e4d545"
+  integrity sha512-+taO0IZGCtCEsuNTTF2Q/5o8+fHrlml8i9YsZt2AiDCdYEJzYlsmRY991l/6f3jNXFyAWepdQj7n8Na6URiDRQ==
   dependencies:
-    "@typescript-eslint/types" "4.0.1"
+    "@typescript-eslint/types" "4.1.0"
     eslint-visitor-keys "^2.0.0"
 
 "@webassemblyjs/[email protected]":
@@ -2035,10 +2035,10 @@ [email protected]:
     resolve "^1.17.0"
     tsconfig-paths "^3.9.0"
 
[email protected].1:
-  version "30.3.1"
-  resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-30.3.1.tgz#be38fec54ccd07011b19a9dfee040e166c1414f0"
-  integrity sha512-185ARou6Wj/68DP0g9kLLBnvmVwgg6/E/7Z8Z7Dz7Z63WgvRNaSvOLQiXkzIOEwstQfwI9PCuFPh4qBJov907A==
[email protected].3:
+  version "30.3.3"
+  resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-30.3.3.tgz#25ddf2e59164a6182c5a9e12e6560d69e252013d"
+  integrity sha512-u2z0LUTm00KLrWB2h7y+hkzYcTIDIi87efXRnv36cFvs23hIOuT77FdZNDBxbB4dxquHBNsyxLpyEuERYUVNEA==
   dependencies:
     comment-parser "^0.7.6"
     debug "^4.1.1"

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.