Browse Source

Merge pull request #532 from javascript-obfuscator/sanitize-of-class-scopes

Added class scope sanitizing
Timofey Kachalov 5 years ago
parent
commit
a6e40b40c3

+ 4 - 0
CHANGELOG.md

@@ -1,5 +1,9 @@
 Change Log
 
+v0.24.1
+---
+* Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/531
+
 v0.24.0
 ---
 * **Internal refactoring:** completely new mechanism to rename variable names

File diff suppressed because it is too large
+ 0 - 0
dist/index.browser.js


File diff suppressed because it is too large
+ 0 - 0
dist/index.cli.js


File diff suppressed because it is too large
+ 0 - 0
dist/index.js


+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "javascript-obfuscator",
-  "version": "0.24.0",
+  "version": "0.24.1",
   "description": "JavaScript obfuscator",
   "keywords": [
     "obfuscator",

+ 30 - 20
src/analyzers/scope-analyzer/ScopeAnalyzer.ts

@@ -1,15 +1,11 @@
-import { inject, injectable, } from 'inversify';
-import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
+import { injectable, } from 'inversify';
 
 import * as eslintScope from 'eslint-scope';
 import * as estraverse from 'estraverse';
 import * as ESTree from 'estree';
 
-import { IOptions } from '../../interfaces/options/IOptions';
 import { IScopeAnalyzer } from '../../interfaces/analyzers/scope-analyzer/IScopeAnalyzer';
 
-import { ObfuscationTarget } from '../../enums/ObfuscationTarget';
-
 import { ecmaVersion } from '../../constants/EcmaVersion';
 
 import { NodeGuards } from '../../node/NodeGuards';
@@ -37,25 +33,11 @@ export class ScopeAnalyzer implements IScopeAnalyzer {
      */
     private static readonly emptyRangeValue: number = 0;
 
-    /**
-     * @type {IOptions}
-     */
-    private readonly options: IOptions;
-
     /**
      * @type {eslintScope.ScopeManager | null}
      */
     private scopeManager: eslintScope.ScopeManager | null = null;
 
-    /**
-     * @param {IOptions} options
-     */
-    constructor (
-        @inject(ServiceIdentifiers.IOptions) options: IOptions
-    ) {
-        this.options = options;
-    }
-
     /**
      * `eslint-scope` reads `ranges` property of a nodes
      * Should attach that property to the some custom nodes
@@ -97,7 +79,6 @@ export class ScopeAnalyzer implements IScopeAnalyzer {
             try {
                 this.scopeManager = eslintScope.analyze(astTree, {
                     ...ScopeAnalyzer.eslintScopeOptions,
-                    nodejsScope: this.options.target === ObfuscationTarget.Node,
                     sourceType: ScopeAnalyzer.sourceTypes[i]
                 });
 
@@ -132,6 +113,35 @@ export class ScopeAnalyzer implements IScopeAnalyzer {
             throw new Error('Cannot acquire scope for node');
         }
 
+        this.sanitizeScopes(scope);
+
         return scope;
     }
+
+    /**
+     * @param {Scope} scope
+     */
+    private sanitizeScopes (scope: eslintScope.Scope): void {
+        scope.childScopes.forEach((childScope: eslintScope.Scope) => {
+            // fix of class scopes
+            // trying to move class scope references to the parent scope
+            if (childScope.type === 'class' && childScope.upper) {
+                const upperVariable: eslintScope.Variable | undefined = childScope.upper.variables
+                    .find((variable: eslintScope.Variable) => {
+                        // class name variable is always first
+                        const classNameVariable: eslintScope.Variable = childScope.variables[0];
+                        const isValidClassNameVariable: boolean = classNameVariable.defs
+                            .some((definition: eslintScope.Definition) => definition.type === 'ClassName');
+
+                        return isValidClassNameVariable && variable.name === classNameVariable.name;
+                    });
+
+                upperVariable?.references.push(...childScope.variables[0].references);
+            }
+        });
+
+        for (const childScope of scope.childScopes) {
+            this.sanitizeScopes(childScope);
+        }
+    }
 }

+ 23 - 3
test/dev/dev.ts

@@ -7,13 +7,33 @@ import { NO_ADDITIONAL_NODES_PRESET } from '../../src/options/presets/NoCustomNo
 
     let obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
         `
-            var passthrough = value => value;
-            var foo = 1, bar = {baz: passthrough(foo)}
+            class A {
+                foo() {
+                    return A;
+                }
+                
+                bar() {
+                    var A = 1;
+                    return A;
+                }
+            }
+            
+            console.log(A);
+            
+            function foo () {
+                class B {
+                    foo() {
+                        return B;
+                    }
+                }
+                
+                console.log(B);
+            }
         `,
         {
             ...NO_ADDITIONAL_NODES_PRESET,
             compact: false,
-            transformObjectKeys: true
+            target: 'node'
         }
     ).getObfuscatedCode();
 

+ 378 - 16
test/functional-tests/node-transformers/obfuscating-transformers/scope-identifiers-transformer/class-declaration/ClassDeclaration.spec.ts

@@ -1,12 +1,14 @@
 import { assert } from 'chai';
 
+import { IdentifierNamesGenerator } from '../../../../../../src/enums/generators/identifier-names-generators/IdentifierNamesGenerator';
+import { ObfuscationTarget } from '../../../../../../src/enums/ObfuscationTarget';
+
 import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../../src/options/presets/NoCustomNodes';
 
 import { getRegExpMatch } from '../../../../../helpers/getRegExpMatch';
 import { readFileAsString } from '../../../../../helpers/readFileAsString';
 
 import { JavaScriptObfuscator } from '../../../../../../src/JavaScriptObfuscatorFacade';
-import { IdentifierNamesGenerator } from '../../../../../../src/enums/generators/identifier-names-generators/IdentifierNamesGenerator';
 
 describe('ScopeIdentifiersTransformer ClassDeclaration identifiers', () => {
     describe('transformation of `classDeclaration` node names', () => {
@@ -38,28 +40,192 @@ describe('ScopeIdentifiersTransformer ClassDeclaration identifiers', () => {
 
         describe('Variant #2: `classDeclaration` parent block scope is a `ProgramNode`', () => {
             describe('Variant #1: `renameGlobals` option is disabled', () => {
-                const classNameIdentifierRegExp: RegExp = /class *Foo *\{/;
-                const classCallIdentifierRegExp: RegExp = /new *Foo *\( *\);/;
+                describe('Variant #1: base', () => {
+                    const classNameIdentifierRegExp: RegExp = /class *Foo *\{/;
+                    const classCallIdentifierRegExp: RegExp = /new *Foo *\( *\);/;
 
-                let obfuscatedCode: string;
+                    let obfuscatedCode: string;
 
-                before(() => {
-                    const code: string = readFileAsString(__dirname + '/fixtures/parent-block-scope-is-program-node.js');
+                    before(() => {
+                        const code: string = readFileAsString(__dirname + '/fixtures/parent-block-scope-is-program-node.js');
 
-                    obfuscatedCode = JavaScriptObfuscator.obfuscate(
-                        code,
-                        {
-                            ...NO_ADDITIONAL_NODES_PRESET
-                        }
-                    ).getObfuscatedCode();
+                        obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                            code,
+                            {
+                                ...NO_ADDITIONAL_NODES_PRESET
+                            }
+                        ).getObfuscatedCode();
+                    });
+
+                    it('match #1: shouldn\'t transform class name', () => {
+                        assert.match(obfuscatedCode, classNameIdentifierRegExp);
+                    });
+
+                    it('match #2: shouldn\'t transform class name', () => {
+                        assert.match(obfuscatedCode, classCallIdentifierRegExp);
+                    });
                 });
 
-                it('match #1: shouldn\'t transform class name', () => {
-                    assert.match(obfuscatedCode, classNameIdentifierRegExp);
+                describe('Variant #2: target `browser', () => {
+                    describe('Variant #1: correct class name references in global scope', () => {
+                        const classNameIdentifierRegExp: RegExp = /class A *\{/;
+                        const outerClassNameReferenceRegExp: RegExp = /console\['log']\(A\);/;
+                        const innerClassNameReferenceRegExp: RegExp = /return A;/;
+
+                        let obfuscatedCode: string;
+
+                        before(() => {
+                            const code: string = readFileAsString(__dirname + '/fixtures/class-name-references-global-scope.js');
+
+                            obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                                code,
+                                {
+                                    ...NO_ADDITIONAL_NODES_PRESET,
+                                    target: ObfuscationTarget.Browser
+                                }
+                            ).getObfuscatedCode();
+                        });
+
+                        it('match #1: shouldn\'t transform class name', () => {
+                            assert.match(obfuscatedCode, classNameIdentifierRegExp);
+                        });
+
+                        it('match #2: shouldn\'t transform class name reference outside of class', () => {
+                            assert.match(obfuscatedCode, outerClassNameReferenceRegExp);
+                        });
+
+                        it('match #3: shouldn\'t transform class name reference inside class', () => {
+                            assert.match(obfuscatedCode, innerClassNameReferenceRegExp);
+                        });
+                    });
+
+                    describe('Variant #2: correct class name references in function scope', () => {
+                        const classNameIdentifierRegExp: RegExp = /class (_0x[a-f0-9]{4,6}) *\{/;
+                        const outerClassNameReferenceRegExp: RegExp = /console\['log']\((_0x[a-f0-9]{4,6})\);/;
+                        const innerClassNameReferenceRegExp: RegExp = /return (_0x[a-f0-9]{4,6});/;
+
+                        let obfuscatedCode: string;
+                        let classNameIdentifier: string;
+                        let outerClassNameReferenceIdentifierName: string;
+                        let innerClassNameReferenceIdentifierName: string;
+
+                        before(() => {
+                            const code: string = readFileAsString(__dirname + '/fixtures/class-name-references-function-scope.js');
+
+                            obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                                code,
+                                {
+                                    ...NO_ADDITIONAL_NODES_PRESET,
+                                    target: ObfuscationTarget.Browser
+                                }
+                            ).getObfuscatedCode();
+
+                            classNameIdentifier = getRegExpMatch(obfuscatedCode, classNameIdentifierRegExp);
+                            outerClassNameReferenceIdentifierName = getRegExpMatch(obfuscatedCode, outerClassNameReferenceRegExp);
+                            innerClassNameReferenceIdentifierName = getRegExpMatch(obfuscatedCode, innerClassNameReferenceRegExp);
+                        });
+
+                        it('match #1: should transform class name', () => {
+                            assert.match(obfuscatedCode, classNameIdentifierRegExp);
+                        });
+
+                        it('match #2: should transform class name reference outside of class', () => {
+                            assert.match(obfuscatedCode, outerClassNameReferenceRegExp);
+                        });
+
+                        it('match #3: should transform class name reference inside class', () => {
+                            assert.match(obfuscatedCode, innerClassNameReferenceRegExp);
+                        });
+
+                        it('match #4: should generate same identifier names for class name and outer class name reference', () => {
+                            assert.equal(classNameIdentifier, outerClassNameReferenceIdentifierName);
+                        });
+
+                        it('match #5: should generate same identifier names for class name and inner class name reference', () => {
+                            assert.equal(classNameIdentifier, innerClassNameReferenceIdentifierName);
+                        });
+                    });
                 });
 
-                it('match #2: shouldn\'t transform class name', () => {
-                    assert.match(obfuscatedCode, classCallIdentifierRegExp);
+                describe('Variant #3: target `node', () => {
+                    describe('Variant #1: correct class name references in global scope', () => {
+                        const classNameIdentifierRegExp: RegExp = /class A *\{/;
+                        const outerClassNameReferenceRegExp: RegExp = /console\['log']\(A\);/;
+                        const innerClassNameReferenceRegExp: RegExp = /return A;/;
+
+                        let obfuscatedCode: string;
+
+                        before(() => {
+                            const code: string = readFileAsString(__dirname + '/fixtures/class-name-references-global-scope.js');
+
+                            obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                                code,
+                                {
+                                    ...NO_ADDITIONAL_NODES_PRESET,
+                                    target: ObfuscationTarget.Node
+                                }
+                            ).getObfuscatedCode();
+                        });
+
+                        it('match #1: shouldn\'t transform class name', () => {
+                            assert.match(obfuscatedCode, classNameIdentifierRegExp);
+                        });
+
+                        it('match #2: shouldn\'t transform class name reference outside of class', () => {
+                            assert.match(obfuscatedCode, outerClassNameReferenceRegExp);
+                        });
+
+                        it('match #3: shouldn\'t transform class name reference inside class', () => {
+                            assert.match(obfuscatedCode, innerClassNameReferenceRegExp);
+                        });
+                    });
+
+                    describe('Variant #2: correct class name references in function scope', () => {
+                        const classNameIdentifierRegExp: RegExp = /class (_0x[a-f0-9]{4,6}) *\{/;
+                        const outerClassNameReferenceRegExp: RegExp = /console\['log']\((_0x[a-f0-9]{4,6})\);/;
+                        const innerClassNameReferenceRegExp: RegExp = /return (_0x[a-f0-9]{4,6});/;
+
+                        let obfuscatedCode: string;
+                        let classNameIdentifier: string;
+                        let outerClassNameReferenceIdentifierName: string;
+                        let innerClassNameReferenceIdentifierName: string;
+
+                        before(() => {
+                            const code: string = readFileAsString(__dirname + '/fixtures/class-name-references-function-scope.js');
+
+                            obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                                code,
+                                {
+                                    ...NO_ADDITIONAL_NODES_PRESET,
+                                    target: ObfuscationTarget.Node
+                                }
+                            ).getObfuscatedCode();
+
+                            classNameIdentifier = getRegExpMatch(obfuscatedCode, classNameIdentifierRegExp);
+                            outerClassNameReferenceIdentifierName = getRegExpMatch(obfuscatedCode, outerClassNameReferenceRegExp);
+                            innerClassNameReferenceIdentifierName = getRegExpMatch(obfuscatedCode, innerClassNameReferenceRegExp);
+                        });
+
+                        it('match #1: should transform class name', () => {
+                            assert.match(obfuscatedCode, classNameIdentifierRegExp);
+                        });
+
+                        it('match #2: should transform class name reference outside of class', () => {
+                            assert.match(obfuscatedCode, outerClassNameReferenceRegExp);
+                        });
+
+                        it('match #3: should transform class name reference inside class', () => {
+                            assert.match(obfuscatedCode, innerClassNameReferenceRegExp);
+                        });
+
+                        it('match #4: should generate same identifier names for class name and outer class name reference', () => {
+                            assert.equal(classNameIdentifier, outerClassNameReferenceIdentifierName);
+                        });
+
+                        it('match #5: should generate same identifier names for class name and inner class name reference', () => {
+                            assert.equal(classNameIdentifier, innerClassNameReferenceIdentifierName);
+                        });
+                    });
                 });
             });
 
@@ -117,6 +283,202 @@ describe('ScopeIdentifiersTransformer ClassDeclaration identifiers', () => {
                         assert.match(obfuscatedCode, identifierRegExp2);
                     });
                 });
+
+                describe('Variant #3: target: `browser', () => {
+                    describe('Variant #1: correct class name references in global scope', () => {
+                        const classNameIdentifierRegExp: RegExp = /class (_0x[a-f0-9]{4,6}) *\{/;
+                        const outerClassNameReferenceRegExp: RegExp = /console\['log']\((_0x[a-f0-9]{4,6})\);/;
+                        const innerClassNameReferenceRegExp: RegExp = /return (_0x[a-f0-9]{4,6});/;
+
+                        let obfuscatedCode: string;
+                        let classNameIdentifier: string;
+                        let outerClassNameReferenceIdentifierName: string;
+                        let innerClassNameReferenceIdentifierName: string;
+
+                        before(() => {
+                            const code: string = readFileAsString(__dirname + '/fixtures/class-name-references-global-scope.js');
+
+                            obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                                code,
+                                {
+                                    ...NO_ADDITIONAL_NODES_PRESET,
+                                    renameGlobals: true,
+                                    target: ObfuscationTarget.Browser
+                                }
+                            ).getObfuscatedCode();
+
+                            classNameIdentifier = getRegExpMatch(obfuscatedCode, classNameIdentifierRegExp);
+                            outerClassNameReferenceIdentifierName = getRegExpMatch(obfuscatedCode, outerClassNameReferenceRegExp);
+                            innerClassNameReferenceIdentifierName = getRegExpMatch(obfuscatedCode, innerClassNameReferenceRegExp);
+                        });
+
+                        it('match #1: should transform class name', () => {
+                            assert.match(obfuscatedCode, classNameIdentifierRegExp);
+                        });
+
+                        it('match #2: should transform class name reference outside of class', () => {
+                            assert.match(obfuscatedCode, outerClassNameReferenceRegExp);
+                        });
+
+                        it('match #3: should transform class name reference inside class', () => {
+                            assert.match(obfuscatedCode, innerClassNameReferenceRegExp);
+                        });
+
+                        it('match #4: should generate same identifier names for class name and outer class name reference', () => {
+                            assert.equal(classNameIdentifier, outerClassNameReferenceIdentifierName);
+                        });
+
+                        it('match #5: should generate same identifier names for class name and inner class name reference', () => {
+                            assert.equal(classNameIdentifier, innerClassNameReferenceIdentifierName);
+                        });
+                    });
+
+                    describe('Variant #2: correct class name references in function scope', () => {
+                        const classNameIdentifierRegExp: RegExp = /class (_0x[a-f0-9]{4,6}) *\{/;
+                        const outerClassNameReferenceRegExp: RegExp = /console\['log']\((_0x[a-f0-9]{4,6})\);/;
+                        const innerClassNameReferenceRegExp: RegExp = /return (_0x[a-f0-9]{4,6});/;
+
+                        let obfuscatedCode: string;
+                        let classNameIdentifier: string;
+                        let outerClassNameReferenceIdentifierName: string;
+                        let innerClassNameReferenceIdentifierName: string;
+
+                        before(() => {
+                            const code: string = readFileAsString(__dirname + '/fixtures/class-name-references-function-scope.js');
+
+                            obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                                code,
+                                {
+                                    ...NO_ADDITIONAL_NODES_PRESET,
+                                    renameGlobals: true,
+                                    target: ObfuscationTarget.Browser
+                                }
+                            ).getObfuscatedCode();
+
+                            classNameIdentifier = getRegExpMatch(obfuscatedCode, classNameIdentifierRegExp);
+                            outerClassNameReferenceIdentifierName = getRegExpMatch(obfuscatedCode, outerClassNameReferenceRegExp);
+                            innerClassNameReferenceIdentifierName = getRegExpMatch(obfuscatedCode, innerClassNameReferenceRegExp);
+                        });
+
+                        it('match #1: should transform class name', () => {
+                            assert.match(obfuscatedCode, classNameIdentifierRegExp);
+                        });
+
+                        it('match #2: should transform class name reference outside of class', () => {
+                            assert.match(obfuscatedCode, outerClassNameReferenceRegExp);
+                        });
+
+                        it('match #3: should transform class name reference inside class', () => {
+                            assert.match(obfuscatedCode, innerClassNameReferenceRegExp);
+                        });
+
+                        it('match #4: should generate same identifier names for class name and outer class name reference', () => {
+                            assert.equal(classNameIdentifier, outerClassNameReferenceIdentifierName);
+                        });
+
+                        it('match #5: should generate same identifier names for class name and inner class name reference', () => {
+                            assert.equal(classNameIdentifier, innerClassNameReferenceIdentifierName);
+                        });
+                    });
+                });
+
+                describe('Variant #3: target: `node', () => {
+                    describe('Variant #1: correct class name references in global scope', () => {
+                        const classNameIdentifierRegExp: RegExp = /class (_0x[a-f0-9]{4,6}) *\{/;
+                        const outerClassNameReferenceRegExp: RegExp = /console\['log']\((_0x[a-f0-9]{4,6})\);/;
+                        const innerClassNameReferenceRegExp: RegExp = /return (_0x[a-f0-9]{4,6});/;
+
+                        let obfuscatedCode: string;
+                        let classNameIdentifier: string;
+                        let outerClassNameReferenceIdentifierName: string;
+                        let innerClassNameReferenceIdentifierName: string;
+
+                        before(() => {
+                            const code: string = readFileAsString(__dirname + '/fixtures/class-name-references-global-scope.js');
+
+                            obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                                code,
+                                {
+                                    ...NO_ADDITIONAL_NODES_PRESET,
+                                    renameGlobals: true,
+                                    target: ObfuscationTarget.Node
+                                }
+                            ).getObfuscatedCode();
+
+                            classNameIdentifier = getRegExpMatch(obfuscatedCode, classNameIdentifierRegExp);
+                            outerClassNameReferenceIdentifierName = getRegExpMatch(obfuscatedCode, outerClassNameReferenceRegExp);
+                            innerClassNameReferenceIdentifierName = getRegExpMatch(obfuscatedCode, innerClassNameReferenceRegExp);
+                        });
+
+                        it('match #1: should transform class name', () => {
+                            assert.match(obfuscatedCode, classNameIdentifierRegExp);
+                        });
+
+                        it('match #2: should transform class name reference outside of class', () => {
+                            assert.match(obfuscatedCode, outerClassNameReferenceRegExp);
+                        });
+
+                        it('match #3: should transform class name reference inside class', () => {
+                            assert.match(obfuscatedCode, innerClassNameReferenceRegExp);
+                        });
+
+                        it('match #4: should generate same identifier names for class name and outer class name reference', () => {
+                            assert.equal(classNameIdentifier, outerClassNameReferenceIdentifierName);
+                        });
+
+                        it('match #5: should generate same identifier names for class name and inner class name reference', () => {
+                            assert.equal(classNameIdentifier, innerClassNameReferenceIdentifierName);
+                        });
+                    });
+
+                    describe('Variant #2: correct class name references in function scope', () => {
+                        const classNameIdentifierRegExp: RegExp = /class (_0x[a-f0-9]{4,6}) *\{/;
+                        const outerClassNameReferenceRegExp: RegExp = /console\['log']\((_0x[a-f0-9]{4,6})\);/;
+                        const innerClassNameReferenceRegExp: RegExp = /return (_0x[a-f0-9]{4,6});/;
+
+                        let obfuscatedCode: string;
+                        let classNameIdentifier: string;
+                        let outerClassNameReferenceIdentifierName: string;
+                        let innerClassNameReferenceIdentifierName: string;
+
+                        before(() => {
+                            const code: string = readFileAsString(__dirname + '/fixtures/class-name-references-function-scope.js');
+
+                            obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                                code,
+                                {
+                                    ...NO_ADDITIONAL_NODES_PRESET,
+                                    renameGlobals: true,
+                                    target: ObfuscationTarget.Node
+                                }
+                            ).getObfuscatedCode();
+
+                            classNameIdentifier = getRegExpMatch(obfuscatedCode, classNameIdentifierRegExp);
+                            outerClassNameReferenceIdentifierName = getRegExpMatch(obfuscatedCode, outerClassNameReferenceRegExp);
+                            innerClassNameReferenceIdentifierName = getRegExpMatch(obfuscatedCode, innerClassNameReferenceRegExp);
+                        });
+
+                        it('match #1: should transform class name', () => {
+                            assert.match(obfuscatedCode, classNameIdentifierRegExp);
+                        });
+
+                        it('match #2: should transform class name reference outside of class', () => {
+                            assert.match(obfuscatedCode, outerClassNameReferenceRegExp);
+                        });
+
+                        it('match #3: should transform class name reference inside class', () => {
+                            assert.match(obfuscatedCode, innerClassNameReferenceRegExp);
+                        });
+
+                        it('match #4: should generate same identifier names for class name and outer class name reference', () => {
+                            assert.equal(classNameIdentifier, outerClassNameReferenceIdentifierName);
+                        });
+
+                        it('match #5: should generate same identifier names for class name and inner class name reference', () => {
+                            assert.equal(classNameIdentifier, innerClassNameReferenceIdentifierName);
+                        });
+                    });
+                });
             });
         });
 

+ 9 - 0
test/functional-tests/node-transformers/obfuscating-transformers/scope-identifiers-transformer/class-declaration/fixtures/class-name-references-function-scope.js

@@ -0,0 +1,9 @@
+function foo () {
+    class B {
+        foo() {
+            return B;
+        }
+    }
+
+    console.log(B);
+}

+ 7 - 0
test/functional-tests/node-transformers/obfuscating-transformers/scope-identifiers-transformer/class-declaration/fixtures/class-name-references-global-scope.js

@@ -0,0 +1,7 @@
+class A {
+    foo() {
+        return A;
+    }
+}
+
+console.log(A);

Some files were not shown because too many files changed in this diff