Explorar o código

Merge branch 'master' into rotate-string-array-improvements

# Conflicts:
#	CHANGELOG.md
#	dist/index.browser.js
#	dist/index.cli.js
#	dist/index.js
#	package.json
sanex %!s(int64=4) %!d(string=hai) anos
pai
achega
b71b39f5e7
Modificáronse 23 ficheiros con 358 adicións e 31 borrados
  1. 4 0
      CHANGELOG.md
  2. 1 1
      README.md
  3. 0 0
      dist/index.browser.js
  4. 0 0
      dist/index.cli.js
  5. 0 0
      dist/index.js
  6. 1 0
      src/JavaScriptObfuscator.ts
  7. 5 0
      src/container/modules/node-transformers/FinalizingTransformersModule.ts
  8. 37 10
      src/declarations/ESTree.d.ts
  9. 1 0
      src/enums/node-transformers/NodeTransformer.ts
  10. 143 0
      src/node-transformers/finalizing-transformers/DirectivePlacementTransformer.ts
  11. 1 1
      src/node-transformers/preparing-transformers/obfuscating-guards/BlackListObfuscatingGuard.ts
  12. 0 9
      src/node/NodeGuards.ts
  13. 20 4
      src/node/NodeMetadata.ts
  14. 3 3
      test/functional-tests/node-transformers/converting-transformers/split-string-transformer/SplitStringTransformer.spec.ts
  15. 2 1
      test/functional-tests/node-transformers/converting-transformers/split-string-transformer/fixtures/string-with-emoji-1.js
  16. 2 1
      test/functional-tests/node-transformers/converting-transformers/split-string-transformer/fixtures/string-with-emoji-2.js
  17. 124 0
      test/functional-tests/node-transformers/finalizing-transformers/directive-placement-transformer/DirectivePlacementTransformer.spec.ts
  18. 4 0
      test/functional-tests/node-transformers/finalizing-transformers/directive-placement-transformer/fixtures/middle-of-function-scope.js
  19. 2 0
      test/functional-tests/node-transformers/finalizing-transformers/directive-placement-transformer/fixtures/middle-of-program-scope.js
  20. 4 0
      test/functional-tests/node-transformers/finalizing-transformers/directive-placement-transformer/fixtures/top-of-function-scope.js
  21. 2 0
      test/functional-tests/node-transformers/finalizing-transformers/directive-placement-transformer/fixtures/top-of-program-scope.js
  22. 1 0
      test/index.spec.ts
  23. 1 1
      test/unit-tests/node/node-metadata/NodeMetadata.spec.ts

+ 4 - 0
CHANGELOG.md

@@ -4,6 +4,10 @@ v2.10.0
 ---
 * Improved `rotateStringArray` option
 
+v2.9.6
+---
+* Preventing move of `"use strict";` directive during obfuscation
+
 v2.9.5
 ---
 * Fixed runtime errors in large obfuscated code when both `rc4` and `base64` encodings are enabled

+ 1 - 1
README.md

@@ -44,7 +44,7 @@ The example of obfuscated code: [github.com](https://github.com/javascript-obfus
 * (OpenCollective) https://opencollective.com/javascript-obfuscator
 * PayPal credit card [https://www.paypal.com/donate](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&[email protected]&lc=US&no_note=0&item_name=Support+javascript-obfuscator&cn=&curency_code=USD&bn=PP-DonationsBF:btn_donateCC_LG.gif:NonHosted)
 * PayPal https://www.paypal.me/javascriptobfuscator
-* (Bitcoin) 14yhtZxLNp6ekZAgmEmPJqEKUP2VtUxQK6
+* (Bitcoin) 1Nv2773RDNzodHDxuxaYkTvwBkYRHmPhnG
 
 Huge thanks to all supporters!
 

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
dist/index.browser.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
dist/index.cli.js


A diferenza do arquivo foi suprimida porque é demasiado grande
+ 0 - 0
dist/index.js


+ 1 - 0
src/JavaScriptObfuscator.ts

@@ -92,6 +92,7 @@ export class JavaScriptObfuscator implements IJavaScriptObfuscator {
         NodeTransformer.StringArrayScopeCallsWrapperTransformer,
         NodeTransformer.StringArrayTransformer,
         NodeTransformer.TemplateLiteralTransformer,
+        NodeTransformer.DirectivePlacementTransformer,
         NodeTransformer.VariableDeclarationsMergeTransformer,
         NodeTransformer.VariablePreserveTransformer
     ];

+ 5 - 0
src/container/modules/node-transformers/FinalizingTransformersModule.ts

@@ -5,10 +5,15 @@ import { INodeTransformer } from '../../../interfaces/node-transformers/INodeTra
 
 import { NodeTransformer } from '../../../enums/node-transformers/NodeTransformer';
 
+import { DirectivePlacementTransformer } from '../../../node-transformers/finalizing-transformers/DirectivePlacementTransformer';
 import { EscapeSequenceTransformer } from '../../../node-transformers/finalizing-transformers/EscapeSequenceTransformer';
 
 export const finalizingTransformersModule: interfaces.ContainerModule = new ContainerModule((bind: interfaces.Bind) => {
     // finalizing transformers
+    bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
+        .to(DirectivePlacementTransformer)
+        .whenTargetNamed(NodeTransformer.DirectivePlacementTransformer);
+
     bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
         .to(EscapeSequenceTransformer)
         .whenTargetNamed(NodeTransformer.EscapeSequenceTransformer);

+ 37 - 10
src/declarations/ESTree.d.ts

@@ -5,40 +5,67 @@ import * as escodegen from '@javascript-obfuscator/escodegen';
 import * as eslintScope from 'eslint-scope';
 
 declare module 'estree' {
+    /**
+     * Nodes metadata
+     */
     export interface BaseNodeMetadata {
         forceTransformNode?: boolean;
         ignoredNode?: boolean;
     }
 
-    export interface Comment {
-        start: number;
-        end: number;
-        loc?: acorn.SourceLocation;
+    export interface FunctionNodeMetadata extends BaseNodeMetadata {
+        directiveNode?: Directive | null;
     }
 
     export interface LiteralNodeMetadata extends BaseNodeMetadata {
         replacedLiteral?: boolean;
     }
 
+    export interface ProgramNodeMetadata extends BaseNodeMetadata {
+        directiveNode?: Directive | null;
+    }
+
+    /**
+     * Nodes
+     */
+    interface ArrowFunctionExpression extends BaseNode {
+        metadata?: FunctionNodeMetadata;
+    }
+
     interface BaseNode {
         metadata?: BaseNodeMetadata;
         parentNode?: Node;
     }
 
+    interface BigIntLiteral extends SimpleLiteral {
+        bigint: string;
+    }
+
+    export interface Comment {
+        start: number;
+        end: number;
+        loc?: acorn.SourceLocation;
+    }
+
+    interface FunctionExpression extends BaseNode {
+        metadata?: FunctionNodeMetadata;
+    }
+
+    interface FunctionDeclaration extends BaseNode {
+        metadata?: FunctionNodeMetadata;
+    }
+
     interface Program extends BaseNode {
+        metadata?: ProgramNodeMetadata;
         scope?: eslintScope.Scope | null;
     }
 
-    interface SimpleLiteral extends BaseNode {
+    interface RegExpLiteral extends BaseNode {
         metadata?: LiteralNodeMetadata;
         'x-verbatim-property'?: escodegen.XVerbatimProperty;
     }
 
-    interface BigIntLiteral extends SimpleLiteral {
-        bigint: string;
-    }
-
-    interface RegExpLiteral extends BaseNode {
+    interface SimpleLiteral extends BaseNode {
         metadata?: LiteralNodeMetadata;
         'x-verbatim-property'?: escodegen.XVerbatimProperty;
     }

+ 1 - 0
src/enums/node-transformers/NodeTransformer.ts

@@ -5,6 +5,7 @@ export enum NodeTransformer {
     CommentsTransformer = 'CommentsTransformer',
     CustomCodeHelpersTransformer = 'CustomCodeHelpersTransformer',
     DeadCodeInjectionTransformer = 'DeadCodeInjectionTransformer',
+    DirectivePlacementTransformer = 'DirectivePlacementTransformer',
     EscapeSequenceTransformer = 'EscapeSequenceTransformer',
     EvalCallExpressionTransformer = 'EvalCallExpressionTransformer',
     ExportSpecifierTransformer = 'ExportSpecifierTransformer',

+ 143 - 0
src/node-transformers/finalizing-transformers/DirectivePlacementTransformer.ts

@@ -0,0 +1,143 @@
+import { inject, injectable, } from 'inversify';
+import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
+
+import * as estraverse from 'estraverse';
+import * as ESTree from 'estree';
+
+import { TNodeWithLexicalScopeStatements } from '../../types/node/TNodeWithLexicalScopeStatements';
+
+import { IOptions } from '../../interfaces/options/IOptions';
+import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
+import { IVisitor } from '../../interfaces/node-transformers/IVisitor';
+
+import { NodeTransformationStage } from '../../enums/node-transformers/NodeTransformationStage';
+import { NodeTransformer } from '../../enums/node-transformers/NodeTransformer';
+
+import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
+import { NodeAppender } from '../../node/NodeAppender';
+import { NodeGuards } from '../../node/NodeGuards';
+import { NodeMetadata } from '../../node/NodeMetadata';
+import { NodeUtils } from '../../node/NodeUtils';
+
+/**
+ * It's easier to fix "use strict"; placement after obfuscation as a separate stage
+ * than ignore this directive in other transformers like control flow and dead code injection transformers
+ */
+@injectable()
+export class DirectivePlacementTransformer extends AbstractNodeTransformer {
+    /**
+     * @type {NodeTransformer[]}
+     */
+    public readonly runAfter: NodeTransformer[] = [
+        NodeTransformer.CustomCodeHelpersTransformer
+    ];
+
+    /**
+     * @param {IRandomGenerator} randomGenerator
+     * @param {IOptions} options
+     */
+    public constructor (
+        @inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
+        @inject(ServiceIdentifiers.IOptions) options: IOptions,
+    ) {
+        super(randomGenerator, options);
+    }
+
+    /**
+     * @param {NodeTransformationStage} nodeTransformationStage
+     * @returns {IVisitor | null}
+     */
+    public getVisitor (nodeTransformationStage: NodeTransformationStage): IVisitor | null {
+        switch (nodeTransformationStage) {
+            case NodeTransformationStage.Preparing:
+                return {
+                    enter: (
+                        node: ESTree.Node,
+                        parentNode: ESTree.Node | null
+                    ): ESTree.Node | estraverse.VisitorOption | undefined => {
+                        if (parentNode && NodeGuards.isNodeWithLexicalScopeStatements(node, parentNode)) {
+                            return this.analyzeNode(node, parentNode);
+                        }
+                    }
+                };
+
+            case NodeTransformationStage.Finalizing:
+                return {
+                    enter: (
+                        node: ESTree.Node,
+                        parentNode: ESTree.Node | null
+                    ): ESTree.Node | estraverse.VisitorOption | undefined => {
+                        if (parentNode && NodeGuards.isNodeWithLexicalScopeStatements(node, parentNode)) {
+                            return this.transformNode(node, parentNode);
+                        }
+                    }
+                };
+
+            default:
+                return null;
+        }
+    }
+
+    /**
+     * @param {TNodeWithLexicalScopeStatements} nodeWithLexicalScopeStatements
+     * @param {Node} parentNode
+     * @returns {TNodeWithLexicalScopeStatements}
+     */
+    public analyzeNode (
+        nodeWithLexicalScopeStatements: TNodeWithLexicalScopeStatements,
+        parentNode: ESTree.Node
+    ): TNodeWithLexicalScopeStatements {
+        if (!NodeGuards.isNodeWithLexicalScope(parentNode)) {
+            return nodeWithLexicalScopeStatements;
+        }
+
+        const firstStatementNode = nodeWithLexicalScopeStatements.body[0] ?? null;
+
+        if (firstStatementNode && NodeGuards.isDirectiveNode(firstStatementNode)) {
+            NodeMetadata.set(parentNode, {directiveNode: firstStatementNode});
+        }
+
+        return nodeWithLexicalScopeStatements;
+    }
+
+    /**
+     * @param {TNodeWithLexicalScopeStatements} nodeWithLexicalScopeStatements
+     * @param {Node | null} parentNode
+     * @returns {TNodeWithLexicalScope}
+     */
+    public transformNode (
+        nodeWithLexicalScopeStatements: TNodeWithLexicalScopeStatements,
+        parentNode: ESTree.Node
+    ): TNodeWithLexicalScopeStatements {
+        if (!NodeGuards.isNodeWithLexicalScope(parentNode)) {
+            return nodeWithLexicalScopeStatements;
+        }
+
+        const directiveNode: ESTree.Directive | null | undefined = NodeMetadata.getDirectiveNode(parentNode);
+
+        if (directiveNode) {
+            const newDirectiveNode: ESTree.Directive = NodeUtils.clone(directiveNode);
+
+            // append new directive node at the top of lexical scope statements
+            NodeAppender.prepend(nodeWithLexicalScopeStatements, [newDirectiveNode]);
+
+            // remove found directive node
+            let isDirectiveNodeRemoved: boolean = false;
+            estraverse.replace(nodeWithLexicalScopeStatements, {
+                enter: (node: ESTree.Node): estraverse.VisitorOption | undefined => {
+                    if (isDirectiveNodeRemoved) {
+                        return estraverse.VisitorOption.Break;
+                    }
+
+                    if (node === directiveNode) {
+                        isDirectiveNodeRemoved = true;
+
+                        return estraverse.VisitorOption.Remove;
+                    }
+                }
+            });
+        }
+
+        return nodeWithLexicalScopeStatements;
+    }
+}

+ 1 - 1
src/node-transformers/preparing-transformers/obfuscating-guards/BlackListObfuscatingGuard.ts

@@ -14,7 +14,7 @@ export class BlackListObfuscatingGuard implements IObfuscatingGuard {
      * @type {((node: Node) => boolean)[]}
      */
     private static readonly blackListGuards: ((node: ESTree.Node) => boolean)[] = [
-        NodeGuards.isUseStrictOperator
+        NodeGuards.isDirectiveNode
     ];
 
     /**

+ 0 - 9
src/node/NodeGuards.ts

@@ -422,15 +422,6 @@ export class NodeGuards {
         return node.type === NodeType.UnaryExpression;
     }
 
-    /**
-     * @param {Node} node
-     * @returns {boolean}
-     */
-    public static isUseStrictOperator (node: ESTree.Node): node is ESTree.Directive {
-        return NodeGuards.isDirectiveNode(node)
-            && node.directive === 'use strict';
-    }
-
     /**
      * @param {Node} node
      * @returns {boolean}

+ 20 - 4
src/node/NodeMetadata.ts

@@ -1,4 +1,5 @@
 import * as ESTree from 'estree';
+import { TNodeWithLexicalScope } from '../types/node/TNodeWithLexicalScope';
 
 export class NodeMetadata {
     /**
@@ -14,7 +15,10 @@ export class NodeMetadata {
      * @param {keyof T} metadataKey
      * @returns {T[keyof T] | undefined}
      */
-    public static get <T extends ESTree.BaseNodeMetadata> (node: ESTree.Node, metadataKey: keyof T): T[keyof T] | undefined {
+    public static get <
+        T extends ESTree.BaseNodeMetadata,
+        TMetadataKey extends keyof T
+    > (node: ESTree.Node, metadataKey: TMetadataKey): T[TMetadataKey] | undefined {
         return node.metadata !== undefined
             ? (<T>node.metadata)[metadataKey]
             : undefined;
@@ -25,7 +29,7 @@ export class NodeMetadata {
      * @returns {boolean}
      */
     public static isForceTransformNode (node: ESTree.Node): boolean {
-        return NodeMetadata.get(node, 'forceTransformNode') === true;
+        return NodeMetadata.get<ESTree.BaseNodeMetadata, 'forceTransformNode'>(node, 'forceTransformNode') === true;
     }
 
     /**
@@ -33,7 +37,7 @@ export class NodeMetadata {
      * @returns {boolean}
      */
     public static isIgnoredNode (node: ESTree.Node): boolean {
-        return NodeMetadata.get(node, 'ignoredNode') === true;
+        return NodeMetadata.get<ESTree.BaseNodeMetadata, 'ignoredNode'>(node, 'ignoredNode') === true;
     }
 
     /**
@@ -41,6 +45,18 @@ export class NodeMetadata {
      * @returns {boolean}
      */
     public static isReplacedLiteral (literalNode: ESTree.Literal): boolean {
-        return NodeMetadata.get<ESTree.LiteralNodeMetadata>(literalNode, 'replacedLiteral') === true;
+        return NodeMetadata.get<ESTree.LiteralNodeMetadata, 'replacedLiteral'>(literalNode, 'replacedLiteral') === true;
+    }
+
+    /**
+     * @param {TNodeWithLexicalScope} nodeWithLexicalScope
+     * @returns {Directive | null | undefined}
+     */
+    public static getDirectiveNode (nodeWithLexicalScope: TNodeWithLexicalScope): ESTree.Directive | null | undefined {
+        return NodeMetadata.get<
+            ESTree.ProgramNodeMetadata
+            | ESTree.FunctionNodeMetadata,
+            'directiveNode'
+        >(nodeWithLexicalScope, 'directiveNode');
     }
 }

+ 3 - 3
test/functional-tests/node-transformers/converting-transformers/split-string-transformer/SplitStringTransformer.spec.ts

@@ -168,7 +168,7 @@ describe('SplitStringTransformer', () => {
     describe('Variant #10: string with emoji', () => {
         describe('Variant #1: single emoji', () => {
             it('should correctly split string with emoji', () => {
-                const regExp: RegExp = /^'a' *\+ *'b' *\+ *'👋🏼' *\+ *'c' *\+ *'d';$/;
+                const regExp: RegExp = /^var test *= *'a' *\+ *'b' *\+ *'👋🏼' *\+ *'c' *\+ *'d'; *test;$/;
 
                 const code: string = readFileAsString(__dirname + '/fixtures/string-with-emoji-1.js');
 
@@ -206,7 +206,7 @@ describe('SplitStringTransformer', () => {
 
         describe('Variant #2: multiple emoji', () => {
             it('should correctly split string with emoji', () => {
-                const regExp: RegExp = /^'a' *\+ *'b' *\+ *'😴' *\+ *'😄' *\+ *'c' *\+ *'d';$/;
+                const regExp: RegExp = /^var test *= *'a' *\+ *'b' *\+ *'😴' *\+ *'😄' *\+ *'c' *\+ *'d'; *test;$/;
 
                 const code: string = readFileAsString(__dirname + '/fixtures/string-with-emoji-2.js');
 
@@ -244,7 +244,7 @@ describe('SplitStringTransformer', () => {
 
         describe('Variant #3: correct split emoji', () => {
             it('should correctly split string with emoji', () => {
-                const regExp: RegExp = /^'ab👋🏼' *\+ *'cd';$/;
+                const regExp: RegExp = /^var test *= *'ab👋🏼' *\+ *'cd'; *test;$/;
 
                 const code: string = readFileAsString(__dirname + '/fixtures/string-with-emoji-1.js');
 

+ 2 - 1
test/functional-tests/node-transformers/converting-transformers/split-string-transformer/fixtures/string-with-emoji-1.js

@@ -1 +1,2 @@
-'ab👋🏼cd';
+var test = 'ab👋🏼cd';
+test;

+ 2 - 1
test/functional-tests/node-transformers/converting-transformers/split-string-transformer/fixtures/string-with-emoji-2.js

@@ -1 +1,2 @@
-'ab😴😄cd';
+var test = 'ab😴😄cd';
+test;

+ 124 - 0
test/functional-tests/node-transformers/finalizing-transformers/directive-placement-transformer/DirectivePlacementTransformer.spec.ts

@@ -0,0 +1,124 @@
+import { assert } from 'chai';
+
+import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/NoCustomNodes';
+
+import { readFileAsString } from '../../../../helpers/readFileAsString';
+
+import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscatorFacade';
+
+describe('DirectivePlacementTransformer', function () {
+    this.timeout(120000);
+
+    describe('Program lexical scope', () => {
+        describe('Variant #1: directive at the top of program scope', () => {
+            const directiveRegExp: RegExp = /^'use strict'; *var _0x([a-f0-9]){4} *= *\['test'];/;
+
+            let obfuscatedCode: string;
+
+            before(() => {
+                const code: string = readFileAsString(__dirname + '/fixtures/top-of-program-scope.js');
+
+                obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                    code,
+                    {
+                        ...NO_ADDITIONAL_NODES_PRESET,
+                        stringArray: true,
+                        stringArrayThreshold: 1
+                    }
+                ).getObfuscatedCode();
+            });
+
+            it('should keep directive at the top of program scope', () => {
+                assert.match(obfuscatedCode, directiveRegExp);
+            });
+        });
+
+        describe('Variant #2: directive-like string literal at the middle of program scope', () => {
+            const directiveRegExp: RegExp = new RegExp(
+                '^var _0x([a-f0-9]){4} *= *\\[\'test\', *\'use\\\\x20strict\']; *' +
+                '.*?' +
+                'var test *= *_0x([a-f0-9]){4}\\(0x0\\); *' +
+                '_0x([a-f0-9]){4}\\(0x1\\);'
+            );
+
+            let obfuscatedCode: string;
+
+            before(() => {
+                const code: string = readFileAsString(__dirname + '/fixtures/middle-of-program-scope.js');
+
+                obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                    code,
+                    {
+                        ...NO_ADDITIONAL_NODES_PRESET,
+                        stringArray: true,
+                        stringArrayThreshold: 1
+                    }
+                ).getObfuscatedCode();
+            });
+
+            it('should keep directive-like string literal at the middle of program scope', () => {
+                assert.match(obfuscatedCode, directiveRegExp);
+            });
+        });
+    });
+
+    describe('Function lexical scope', () => {
+        describe('Variant #1: directive at the top of function scope', () => {
+            const directiveRegExp: RegExp = new RegExp(
+                'function test\\(\\) *{ *' +
+                    '\'use strict\'; *' +
+                    'var _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4}; *' +
+                    'var _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(0x0\\);'
+            );
+
+            let obfuscatedCode: string;
+
+            before(() => {
+                const code: string = readFileAsString(__dirname + '/fixtures/top-of-function-scope.js');
+
+                obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                    code,
+                    {
+                        ...NO_ADDITIONAL_NODES_PRESET,
+                        stringArray: true,
+                        stringArrayThreshold: 1,
+                        stringArrayWrappersCount: 1
+                    }
+                ).getObfuscatedCode();
+            });
+
+            it('should keep directive at the top of function scope', () => {
+                assert.match(obfuscatedCode, directiveRegExp);
+            });
+        });
+
+        describe('Variant #2: directive-like string literal at the middle of function scope', () => {
+            const directiveRegExp: RegExp = new RegExp(
+                'function test\\(\\) *{ *' +
+                    'var _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4}; *' +
+                    'var _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(0x0\\);' +
+                    '_0x([a-f0-9]){4,6}\\(0x1\\);'
+            );
+
+            let obfuscatedCode: string;
+
+            before(() => {
+                const code: string = readFileAsString(__dirname + '/fixtures/middle-of-function-scope.js');
+
+                obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                    code,
+                    {
+                        ...NO_ADDITIONAL_NODES_PRESET,
+                        stringArray: true,
+                        stringArrayThreshold: 1,
+                        stringArrayWrappersCount: 1
+                    }
+                ).getObfuscatedCode();
+            });
+
+            it('should keep directive-like string literal at the middle of function scope', () => {
+                assert.match(obfuscatedCode, directiveRegExp);
+            });
+        })
+    });
+});

+ 4 - 0
test/functional-tests/node-transformers/finalizing-transformers/directive-placement-transformer/fixtures/middle-of-function-scope.js

@@ -0,0 +1,4 @@
+function test () {
+    var test = 'test';
+    'use strict';
+}

+ 2 - 0
test/functional-tests/node-transformers/finalizing-transformers/directive-placement-transformer/fixtures/middle-of-program-scope.js

@@ -0,0 +1,2 @@
+var test = 'test';
+'use strict';

+ 4 - 0
test/functional-tests/node-transformers/finalizing-transformers/directive-placement-transformer/fixtures/top-of-function-scope.js

@@ -0,0 +1,4 @@
+function test () {
+    'use strict';
+    var test = 'test';
+}

+ 2 - 0
test/functional-tests/node-transformers/finalizing-transformers/directive-placement-transformer/fixtures/top-of-program-scope.js

@@ -0,0 +1,2 @@
+'use strict';
+var test = 'test';

+ 1 - 0
test/index.spec.ts

@@ -98,6 +98,7 @@ import './functional-tests/node-transformers/converting-transformers/object-patt
 import './functional-tests/node-transformers/converting-transformers/split-string-transformer/SplitStringTransformer.spec';
 import './functional-tests/node-transformers/converting-transformers/template-literal-transformer/TemplateLiteralTransformer.spec';
 import './functional-tests/node-transformers/dead-code-injection-transformers/DeadCodeInjectionTransformer.spec';
+import './functional-tests/node-transformers/finalizing-transformers/directive-placement-transformer/DirectivePlacementTransformer.spec';
 import './functional-tests/node-transformers/finalizing-transformers/escape-sequence-transformer/EscapeSequenceTransformer.spec';
 import './functional-tests/node-transformers/initializing-transformers/comments-transformer/CommentsTransformer.spec';
 import './functional-tests/node-transformers/preparing-transformers/eval-call-expression-transformer/EvalCallExpressionTransformer.spec';

+ 1 - 1
test/unit-tests/node/node-metadata/NodeMetadata.spec.ts

@@ -39,7 +39,7 @@ describe('NodeMetadata', () => {
             node = NodeFactory.literalNode('foo');
             node.metadata = {};
             node.metadata.replacedLiteral = true;
-            value = NodeMetadata.get<ESTree.LiteralNodeMetadata>(node, 'replacedLiteral');
+            value = NodeMetadata.get<ESTree.LiteralNodeMetadata, 'replacedLiteral'>(node, 'replacedLiteral');
         });
 
         it('should get metadata value of the node', () => {

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio