mirror of
https://github.com/javascript-obfuscator/javascript-obfuscator
synced 2026-08-09 12:42:29 +00:00
Improved mangled identifier names generator. Improved variable preserving.
This commit is contained in:
@@ -2,6 +2,7 @@ Change Log
|
||||
|
||||
v0.25.0
|
||||
---
|
||||
* Improved `mangled` identifier names generator logic
|
||||
* Fixed conflicts between generated names and names from untouched identifiers from source code. Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/550. Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/549
|
||||
* Prevented transformation of object keys in sequence expression that has `super` call
|
||||
|
||||
|
||||
Vendored
+5
-5
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
@@ -2,6 +2,7 @@ import { inject, injectable } from 'inversify';
|
||||
import { ServiceIdentifiers } from '../container/ServiceIdentifiers';
|
||||
|
||||
import { TIdentifierNamesGeneratorFactory } from '../types/container/generators/TIdentifierNamesGeneratorFactory';
|
||||
import { TInputOptions } from '../types/options/TInputOptions';
|
||||
import { TStatement } from '../types/node/TStatement';
|
||||
|
||||
import { ICustomNode } from '../interfaces/custom-nodes/ICustomNode';
|
||||
@@ -13,6 +14,10 @@ import { ICustomNodeFormatter } from '../interfaces/custom-nodes/ICustomNodeForm
|
||||
import { GlobalVariableTemplate1 } from '../templates/GlobalVariableTemplate1';
|
||||
import { GlobalVariableTemplate2 } from '../templates/GlobalVariableTemplate2';
|
||||
|
||||
import { NO_ADDITIONAL_NODES_PRESET } from '../options/presets/NoCustomNodes';
|
||||
|
||||
import { JavaScriptObfuscator } from '../JavaScriptObfuscatorFacade';
|
||||
|
||||
@injectable()
|
||||
export abstract class AbstractCustomNode <
|
||||
TInitialData extends any[] = any[]
|
||||
@@ -100,16 +105,39 @@ export abstract class AbstractCustomNode <
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} template
|
||||
* @param {TInputOptions} options
|
||||
* @returns {string}
|
||||
*/
|
||||
protected obfuscateTemplate (template: string, options: TInputOptions = {}): string {
|
||||
const reservedNames: string[] = this.getPreservedNames(options.reservedNames);
|
||||
|
||||
return JavaScriptObfuscator.obfuscate(
|
||||
template,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
identifierNamesGenerator: this.options.identifierNamesGenerator,
|
||||
identifiersDictionary: this.options.identifiersDictionary,
|
||||
seed: this.randomGenerator.getRawSeed(),
|
||||
...options,
|
||||
reservedNames
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string[]} additionalNames
|
||||
* @returns {string[]}
|
||||
*/
|
||||
protected getPreservedNames (additionalNames: string[]): string[] {
|
||||
return Array.from(new Set([
|
||||
...Array.from(this.identifierNamesGenerator.getPreservedNames().values()),
|
||||
...additionalNames
|
||||
]).values())
|
||||
.map((preservedName: string) => `^${preservedName}$`);
|
||||
private getPreservedNames (additionalNames: string[] = []): string[] {
|
||||
return Array
|
||||
.from(new Set([
|
||||
...Array.from(this.identifierNamesGenerator.getPreservedNames().values()),
|
||||
...additionalNames
|
||||
])
|
||||
.values())
|
||||
.map((preservedName: string) => `^${preservedName}$`);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,6 +4,7 @@ import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
|
||||
import { TIdentifierNamesGeneratorFactory } from '../../types/container/generators/TIdentifierNamesGeneratorFactory';
|
||||
import { TStatement } from '../../types/node/TStatement';
|
||||
|
||||
import { ICustomNodeFormatter } from '../../interfaces/custom-nodes/ICustomNodeFormatter';
|
||||
import { IOptions } from '../../interfaces/options/IOptions';
|
||||
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
|
||||
|
||||
@@ -13,12 +14,8 @@ import { initializable } from '../../decorators/Initializable';
|
||||
|
||||
import { SingleNodeCallControllerTemplate } from '../../templates/SingleNodeCallControllerTemplate';
|
||||
|
||||
import { NO_ADDITIONAL_NODES_PRESET } from '../../options/presets/NoCustomNodes';
|
||||
|
||||
import { AbstractCustomNode } from '../AbstractCustomNode';
|
||||
import { JavaScriptObfuscator } from '../../JavaScriptObfuscatorFacade';
|
||||
import { NodeUtils } from '../../node/NodeUtils';
|
||||
import { ICustomNodeFormatter } from '../../interfaces/custom-nodes/ICustomNodeFormatter';
|
||||
|
||||
@injectable()
|
||||
export class NodeCallsControllerFunctionNode extends AbstractCustomNode {
|
||||
@@ -72,17 +69,11 @@ export class NodeCallsControllerFunctionNode extends AbstractCustomNode {
|
||||
*/
|
||||
protected getNodeTemplate (): string {
|
||||
if (this.appendEvent === ObfuscationEvent.AfterObfuscation) {
|
||||
return JavaScriptObfuscator.obfuscate(
|
||||
return this.obfuscateTemplate(
|
||||
this.customNodeFormatter.formatTemplate(SingleNodeCallControllerTemplate(), {
|
||||
singleNodeCallControllerFunctionName: this.callsControllerFunctionName
|
||||
}),
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
identifierNamesGenerator: this.options.identifierNamesGenerator,
|
||||
identifiersDictionary: this.options.identifiersDictionary,
|
||||
seed: this.options.seed
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return this.customNodeFormatter.formatTemplate(SingleNodeCallControllerTemplate(), {
|
||||
|
||||
+8
-2
@@ -4,6 +4,7 @@ import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
|
||||
import * as ESTree from 'estree';
|
||||
|
||||
import { TIdentifierNamesGeneratorFactory } from '../../types/container/generators/TIdentifierNamesGeneratorFactory';
|
||||
import { TNodeWithLexicalScope } from '../../types/node/TNodeWithLexicalScope';
|
||||
import { TStatement } from '../../types/node/TStatement';
|
||||
|
||||
import { IOptions } from '../../interfaces/options/IOptions';
|
||||
@@ -15,6 +16,10 @@ import { NodeFactory } from '../../node/NodeFactory';
|
||||
|
||||
@injectable()
|
||||
export class ObjectExpressionVariableDeclarationHostNode extends AbstractCustomNode {
|
||||
/**
|
||||
* @type {TNodeWithLexicalScope}
|
||||
*/
|
||||
private lexicalScopeNode!: TNodeWithLexicalScope;
|
||||
/**
|
||||
* @ type {Property}
|
||||
*/
|
||||
@@ -36,7 +41,8 @@ export class ObjectExpressionVariableDeclarationHostNode extends AbstractCustomN
|
||||
super(identifierNamesGeneratorFactory, customNodeFormatter, randomGenerator, options);
|
||||
}
|
||||
|
||||
public initialize (properties: ESTree.Property[]): void {
|
||||
public initialize (lexicalScopeNode: TNodeWithLexicalScope, properties: ESTree.Property[]): void {
|
||||
this.lexicalScopeNode = lexicalScopeNode;
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@@ -49,7 +55,7 @@ export class ObjectExpressionVariableDeclarationHostNode extends AbstractCustomN
|
||||
[
|
||||
NodeFactory.variableDeclaratorNode(
|
||||
NodeFactory.identifierNode(
|
||||
this.identifierNamesGenerator.generate()
|
||||
this.identifierNamesGenerator.generateForLexicalScope(this.lexicalScopeNode)
|
||||
),
|
||||
NodeFactory.objectExpressionNode(this.properties)
|
||||
)
|
||||
|
||||
@@ -11,12 +11,9 @@ import { ICustomNodeFormatter } from '../../interfaces/custom-nodes/ICustomNodeF
|
||||
|
||||
import { initializable } from '../../decorators/Initializable';
|
||||
|
||||
import { NO_ADDITIONAL_NODES_PRESET } from '../../options/presets/NoCustomNodes';
|
||||
|
||||
import { SelfDefendingTemplate } from '../../templates/self-defending-nodes/self-defending-unicode-node/SelfDefendingTemplate';
|
||||
|
||||
import { AbstractCustomNode } from '../AbstractCustomNode';
|
||||
import { JavaScriptObfuscator } from '../../JavaScriptObfuscatorFacade';
|
||||
import { NodeUtils } from '../../node/NodeUtils';
|
||||
|
||||
@injectable()
|
||||
@@ -71,18 +68,14 @@ export class SelfDefendingUnicodeNode extends AbstractCustomNode {
|
||||
* @returns {string}
|
||||
*/
|
||||
protected getNodeTemplate (): string {
|
||||
return JavaScriptObfuscator.obfuscate(
|
||||
return this.obfuscateTemplate(
|
||||
this.customNodeFormatter.formatTemplate(SelfDefendingTemplate(this.escapeSequenceEncoder), {
|
||||
selfDefendingFunctionName: this.identifierNamesGenerator.generate(),
|
||||
singleNodeCallControllerFunctionName: this.callsControllerFunctionName
|
||||
}),
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
identifierNamesGenerator: this.options.identifierNamesGenerator,
|
||||
identifiersDictionary: this.options.identifiersDictionary,
|
||||
seed: this.options.seed,
|
||||
unicodeEscapeSequence: true
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,8 +14,6 @@ import { StringArrayEncoding } from '../../enums/StringArrayEncoding';
|
||||
|
||||
import { initializable } from '../../decorators/Initializable';
|
||||
|
||||
import { NO_ADDITIONAL_NODES_PRESET } from '../../options/presets/NoCustomNodes';
|
||||
|
||||
import { AtobTemplate } from '../../templates/AtobTemplate';
|
||||
import { GlobalVariableNoEvalTemplate } from '../../templates/GlobalVariableNoEvalTemplate';
|
||||
import { Rc4Template } from '../../templates/Rc4Template';
|
||||
@@ -25,7 +23,6 @@ import { StringArrayCallsWrapperTemplate } from '../../templates/string-array-no
|
||||
import { StringArrayRc4DecodeNodeTemplate } from '../../templates/string-array-nodes/string-array-calls-wrapper/StringArrayRC4DecodeNodeTemplate';
|
||||
|
||||
import { AbstractCustomNode } from '../AbstractCustomNode';
|
||||
import { JavaScriptObfuscator } from '../../JavaScriptObfuscatorFacade';
|
||||
import { NodeUtils } from '../../node/NodeUtils';
|
||||
|
||||
@injectable()
|
||||
@@ -93,24 +90,18 @@ export class StringArrayCallsWrapper extends AbstractCustomNode {
|
||||
protected getNodeTemplate (): string {
|
||||
const decodeNodeTemplate: string = this.getDecodeStringArrayTemplate();
|
||||
|
||||
const preservedNames: string[] = this.getPreservedNames([this.stringArrayName]);
|
||||
const preservedNames: string[] = [this.stringArrayName];
|
||||
|
||||
return JavaScriptObfuscator.obfuscate(
|
||||
return this.obfuscateTemplate(
|
||||
this.customNodeFormatter.formatTemplate(StringArrayCallsWrapperTemplate(), {
|
||||
decodeNodeTemplate,
|
||||
stringArrayCallsWrapperName: this.stringArrayCallsWrapperName,
|
||||
stringArrayName: this.stringArrayName
|
||||
}),
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
identifierNamesGenerator: this.options.identifierNamesGenerator,
|
||||
identifiersDictionary: this.options.identifiersDictionary,
|
||||
reservedNames: [
|
||||
...preservedNames
|
||||
],
|
||||
seed: this.randomGenerator.getRawSeed()
|
||||
reservedNames: preservedNames
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,13 +11,10 @@ import { ICustomNodeFormatter } from '../../interfaces/custom-nodes/ICustomNodeF
|
||||
|
||||
import { initializable } from '../../decorators/Initializable';
|
||||
|
||||
import { NO_ADDITIONAL_NODES_PRESET } from '../../options/presets/NoCustomNodes';
|
||||
|
||||
import { SelfDefendingTemplate } from '../../templates/string-array-nodes/string-array-rotate-function-node/SelfDefendingTemplate';
|
||||
import { StringArrayRotateFunctionTemplate } from '../../templates/string-array-nodes/string-array-rotate-function-node/StringArrayRotateFunctionTemplate';
|
||||
|
||||
import { AbstractCustomNode } from '../AbstractCustomNode';
|
||||
import { JavaScriptObfuscator } from '../../JavaScriptObfuscatorFacade';
|
||||
import { NodeUtils } from '../../node/NodeUtils';
|
||||
import { NumberUtils } from '../../utils/NumberUtils';
|
||||
|
||||
@@ -86,6 +83,7 @@ export class StringArrayRotateFunctionNode extends AbstractCustomNode {
|
||||
protected getNodeTemplate (): string {
|
||||
const timesName: string = this.identifierNamesGenerator.generate();
|
||||
const whileFunctionName: string = this.identifierNamesGenerator.generate();
|
||||
const preservedNames: string[] = [this.stringArrayName];
|
||||
|
||||
let code: string = '';
|
||||
|
||||
@@ -98,20 +96,17 @@ export class StringArrayRotateFunctionNode extends AbstractCustomNode {
|
||||
code = `${whileFunctionName}(++${timesName})`;
|
||||
}
|
||||
|
||||
return JavaScriptObfuscator.obfuscate(
|
||||
return this.obfuscateTemplate(
|
||||
this.customNodeFormatter.formatTemplate(StringArrayRotateFunctionTemplate(), {
|
||||
code,
|
||||
timesName,
|
||||
whileFunctionName,
|
||||
stringArrayName: this.stringArrayName,
|
||||
stringArrayRotationAmount: NumberUtils.toHex(this.stringArrayRotationAmount),
|
||||
whileFunctionName
|
||||
stringArrayRotationAmount: NumberUtils.toHex(this.stringArrayRotationAmount)
|
||||
}),
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
identifierNamesGenerator: this.options.identifierNamesGenerator,
|
||||
identifiersDictionary: this.options.identifiersDictionary,
|
||||
seed: this.randomGenerator.getRawSeed()
|
||||
reservedNames: preservedNames
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,14 @@ export abstract class AbstractIdentifierNamesGenerator implements IIdentifierNam
|
||||
* @returns {Set<string>}
|
||||
*/
|
||||
public getPreservedNames (): Set<string> {
|
||||
return this.preservedNamesSet;
|
||||
const lexicalScopesPreservedNames: Set<string>[] = Array.from(this.lexicalScopesPreservedNamesMap.values());
|
||||
const preservedNames: string[] = Array.from(this.preservedNamesSet);
|
||||
|
||||
for (const lexicalScopePreservedNames of lexicalScopesPreservedNames) {
|
||||
preservedNames.push(...lexicalScopePreservedNames);
|
||||
}
|
||||
|
||||
return new Set(preservedNames);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -60,8 +67,6 @@ export abstract class AbstractIdentifierNamesGenerator implements IIdentifierNam
|
||||
* @param {TNodeWithLexicalScope} lexicalScopeNode
|
||||
*/
|
||||
public preserveNameForLexicalScope (name: string, lexicalScopeNode: TNodeWithLexicalScope): void {
|
||||
this.preservedNamesSet.add(name);
|
||||
|
||||
const preservedNamesForLexicalScopeSet: Set<string> =
|
||||
this.lexicalScopesPreservedNamesMap.get(lexicalScopeNode) ?? new Set();
|
||||
|
||||
@@ -80,22 +85,28 @@ export abstract class AbstractIdentifierNamesGenerator implements IIdentifierNam
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @param {TNodeWithLexicalScope} lexicalScopeNode
|
||||
* @param {TNodeWithLexicalScope[]} lexicalScopeNodes
|
||||
* @returns {boolean}
|
||||
*/
|
||||
public isValidIdentifierNameInLexicalScope (name: string, lexicalScopeNode: TNodeWithLexicalScope): boolean {
|
||||
if (!this.notReservedName(name)) {
|
||||
public isValidIdentifierNameInLexicalScopes (name: string, lexicalScopeNodes: TNodeWithLexicalScope[]): boolean {
|
||||
if (!this.isValidIdentifierName(name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const preservedNamesForLexicalScopeSet: Set<string> | null =
|
||||
this.lexicalScopesPreservedNamesMap.get(lexicalScopeNode) ?? null;
|
||||
for (const lexicalScope of lexicalScopeNodes) {
|
||||
const preservedNamesForLexicalScopeSet: Set<string> | null =
|
||||
this.lexicalScopesPreservedNamesMap.get(lexicalScope) ?? null;
|
||||
|
||||
if (!preservedNamesForLexicalScopeSet) {
|
||||
return true;
|
||||
if (!preservedNamesForLexicalScopeSet) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (preservedNamesForLexicalScopeSet.has(name)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return !preservedNamesForLexicalScopeSet.has(name);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,6 +7,7 @@ import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
|
||||
|
||||
import { AbstractIdentifierNamesGenerator } from './AbstractIdentifierNamesGenerator';
|
||||
import { TNodeWithLexicalScope } from '../../types/node/TNodeWithLexicalScope';
|
||||
import { NodeLexicalScopeUtils } from '../../node/NodeLexicalScopeUtils';
|
||||
|
||||
@injectable()
|
||||
export class DictionaryIdentifierNamesGenerator extends AbstractIdentifierNamesGenerator {
|
||||
@@ -69,26 +70,11 @@ export class DictionaryIdentifierNamesGenerator extends AbstractIdentifierNamesG
|
||||
}
|
||||
|
||||
public generate (): string {
|
||||
if (!this.identifierNamesSet.size) {
|
||||
throw new Error('Too many identifiers in the code, add more words to identifiers dictionary');
|
||||
}
|
||||
const identifierName: string = this.generateNewDictionaryName();
|
||||
|
||||
const iteratorResult: IteratorResult<string> = this.identifiersIterator.next();
|
||||
this.preserveName(identifierName);
|
||||
|
||||
if (!iteratorResult.done) {
|
||||
const identifierName: string =iteratorResult.value;
|
||||
|
||||
if (!this.isValidIdentifierName(identifierName)) {
|
||||
return this.generate();
|
||||
}
|
||||
|
||||
return iteratorResult.value;
|
||||
}
|
||||
|
||||
this.identifierNamesSet = new Set(this.getIncrementedIdentifierNames([...this.identifierNamesSet]));
|
||||
this.identifiersIterator = this.identifierNamesSet.values();
|
||||
|
||||
return this.generate();
|
||||
return identifierName;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -96,12 +82,18 @@ export class DictionaryIdentifierNamesGenerator extends AbstractIdentifierNamesG
|
||||
* @returns {string}
|
||||
*/
|
||||
public generateForLexicalScope (lexicalScopeNode: TNodeWithLexicalScope): string {
|
||||
const identifierName: string = this.generate();
|
||||
const lexicalScopes: TNodeWithLexicalScope[] = [
|
||||
lexicalScopeNode,
|
||||
...NodeLexicalScopeUtils.getLexicalScopes(lexicalScopeNode)
|
||||
];
|
||||
const identifierName: string = this.generateNewDictionaryName();
|
||||
|
||||
if (!this.isValidIdentifierNameInLexicalScope(identifierName, lexicalScopeNode)) {
|
||||
if (!this.isValidIdentifierNameInLexicalScopes(identifierName, lexicalScopes)) {
|
||||
return this.generateForLexicalScope(lexicalScopeNode);
|
||||
}
|
||||
|
||||
this.preserveNameForLexicalScope(identifierName, lexicalScopeNode);
|
||||
|
||||
return identifierName;
|
||||
}
|
||||
|
||||
@@ -112,7 +104,7 @@ export class DictionaryIdentifierNamesGenerator extends AbstractIdentifierNamesG
|
||||
const prefix: string = this.options.identifiersPrefix ?
|
||||
`${this.options.identifiersPrefix}`
|
||||
: '';
|
||||
const identifierName: string = this.generate();
|
||||
const identifierName: string = this.generateNewDictionaryName();
|
||||
const identifierNameWithPrefix: string = `${prefix}${identifierName}`;
|
||||
|
||||
if (!this.isValidIdentifierName(identifierNameWithPrefix)) {
|
||||
@@ -124,6 +116,32 @@ export class DictionaryIdentifierNamesGenerator extends AbstractIdentifierNamesG
|
||||
return identifierNameWithPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string}
|
||||
*/
|
||||
private generateNewDictionaryName (): string {
|
||||
if (!this.identifierNamesSet.size) {
|
||||
throw new Error('Too many identifiers in the code, add more words to identifiers dictionary');
|
||||
}
|
||||
|
||||
const iteratorResult: IteratorResult<string> = this.identifiersIterator.next();
|
||||
|
||||
if (!iteratorResult.done) {
|
||||
const identifierName: string =iteratorResult.value;
|
||||
|
||||
if (!this.isValidIdentifierName(identifierName)) {
|
||||
return this.generateNewDictionaryName();
|
||||
}
|
||||
|
||||
return iteratorResult.value;
|
||||
}
|
||||
|
||||
this.identifierNamesSet = new Set(this.getIncrementedIdentifierNames([...this.identifierNamesSet]));
|
||||
this.identifiersIterator = this.identifierNamesSet.values();
|
||||
|
||||
return this.generateNewDictionaryName();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string[]} identifierNames
|
||||
* @returns {string[]}
|
||||
|
||||
@@ -7,6 +7,7 @@ import { IOptions } from '../../interfaces/options/IOptions';
|
||||
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
|
||||
|
||||
import { AbstractIdentifierNamesGenerator } from './AbstractIdentifierNamesGenerator';
|
||||
import { NodeLexicalScopeUtils } from '../../node/NodeLexicalScopeUtils';
|
||||
|
||||
@injectable()
|
||||
export class MangledIdentifierNamesGenerator extends AbstractIdentifierNamesGenerator {
|
||||
@@ -15,6 +16,11 @@ export class MangledIdentifierNamesGenerator extends AbstractIdentifierNamesGene
|
||||
*/
|
||||
private static readonly initMangledNameCharacter: string = '9';
|
||||
|
||||
/**
|
||||
* @type {Map<TNodeWithLexicalScope, string>}
|
||||
*/
|
||||
private static readonly lastMangledNameInScopeMap: Map <TNodeWithLexicalScope, string> = new Map();
|
||||
|
||||
/**
|
||||
* @type {string[]}
|
||||
*/
|
||||
@@ -56,6 +62,7 @@ export class MangledIdentifierNamesGenerator extends AbstractIdentifierNamesGene
|
||||
const identifierName: string = this.generateNewMangledName(this.previousMangledName);
|
||||
|
||||
this.previousMangledName = identifierName;
|
||||
this.preserveName(identifierName);
|
||||
|
||||
return identifierName;
|
||||
}
|
||||
@@ -66,13 +73,22 @@ export class MangledIdentifierNamesGenerator extends AbstractIdentifierNamesGene
|
||||
* @returns {string}
|
||||
*/
|
||||
public generateForLexicalScope (lexicalScopeNode: TNodeWithLexicalScope, nameLength?: number): string {
|
||||
const identifierName: string = this.generateNewMangledName(this.previousMangledName);
|
||||
const lexicalScopes: TNodeWithLexicalScope[] = [
|
||||
lexicalScopeNode,
|
||||
...NodeLexicalScopeUtils.getLexicalScopes(lexicalScopeNode)
|
||||
];
|
||||
|
||||
if (!this.isValidIdentifierNameInLexicalScope(identifierName, lexicalScopeNode)) {
|
||||
return this.generateForLexicalScope(lexicalScopeNode, nameLength);
|
||||
}
|
||||
const lastMangledNameForScope: string = this.getLastMangledNameForScopes(lexicalScopes);
|
||||
|
||||
this.previousMangledName = identifierName;
|
||||
let identifierName: string = lastMangledNameForScope;
|
||||
|
||||
do {
|
||||
identifierName = this.generateNewMangledName(identifierName);
|
||||
} while (!this.isValidIdentifierNameInLexicalScopes(identifierName, lexicalScopes));
|
||||
|
||||
MangledIdentifierNamesGenerator.lastMangledNameInScopeMap.set(lexicalScopeNode, identifierName);
|
||||
|
||||
this.preserveNameForLexicalScope(identifierName, lexicalScopeNode);
|
||||
|
||||
return identifierName;
|
||||
}
|
||||
@@ -85,9 +101,11 @@ export class MangledIdentifierNamesGenerator extends AbstractIdentifierNamesGene
|
||||
const prefix: string = this.options.identifiersPrefix ?
|
||||
`${this.options.identifiersPrefix}`
|
||||
: '';
|
||||
const identifierName: string = this.generate(nameLength);
|
||||
const identifierName: string = this.generateNewMangledName(this.previousMangledName);
|
||||
const identifierNameWithPrefix: string = `${prefix}${identifierName}`;
|
||||
|
||||
this.previousMangledName = identifierName;
|
||||
|
||||
if (!this.isValidIdentifierName(identifierNameWithPrefix)) {
|
||||
return this.generateWithPrefix(nameLength);
|
||||
}
|
||||
@@ -150,4 +168,23 @@ export class MangledIdentifierNamesGenerator extends AbstractIdentifierNamesGene
|
||||
|
||||
return newMangledName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {TNodeWithLexicalScope[]} lexicalScopeNodes
|
||||
* @returns {string}
|
||||
*/
|
||||
private getLastMangledNameForScopes (lexicalScopeNodes: TNodeWithLexicalScope[]): string {
|
||||
for (const lexicalScope of lexicalScopeNodes) {
|
||||
const lastMangledName: string | null = MangledIdentifierNamesGenerator.lastMangledNameInScopeMap
|
||||
.get(lexicalScope) ?? null;
|
||||
|
||||
if (!lastMangledName) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return lastMangledName;
|
||||
}
|
||||
|
||||
return MangledIdentifierNamesGenerator.initMangledNameCharacter;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,10 +34,10 @@ export interface IIdentifierNamesGenerator {
|
||||
|
||||
/**
|
||||
* @param {string} identifierName
|
||||
* @param {TNodeWithLexicalScope} lexicalScopeNode
|
||||
* @param {TNodeWithLexicalScope[]} lexicalScopeNodes
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isValidIdentifierNameInLexicalScope (identifierName: string, lexicalScopeNode: TNodeWithLexicalScope): boolean;
|
||||
isValidIdentifierNameInLexicalScopes (identifierName: string, lexicalScopeNodes: TNodeWithLexicalScope[]): boolean;
|
||||
|
||||
/**
|
||||
* @param {string} identifierName
|
||||
|
||||
+21
-6
@@ -19,6 +19,8 @@ import { NodeAppender } from '../../../node/NodeAppender';
|
||||
import { NodeGuards } from '../../../node/NodeGuards';
|
||||
import { NodeStatementUtils } from '../../../node/NodeStatementUtils';
|
||||
import { NodeUtils } from '../../../node/NodeUtils';
|
||||
import { TNodeWithLexicalScope } from '../../../types/node/TNodeWithLexicalScope';
|
||||
import { NodeLexicalScopeUtils } from '../../../node/NodeLexicalScopeUtils';
|
||||
|
||||
@injectable()
|
||||
export class ObjectExpressionToVariableDeclarationExtractor implements IObjectExpressionExtractor {
|
||||
@@ -74,12 +76,18 @@ export class ObjectExpressionToVariableDeclarationExtractor implements IObjectEx
|
||||
objectExpressionNode: ESTree.ObjectExpression,
|
||||
hostStatement: ESTree.Statement
|
||||
): IObjectExpressionExtractorResult {
|
||||
const lexicalScopeNode: TNodeWithLexicalScope | null = NodeLexicalScopeUtils.getLexicalScope(hostStatement) ?? null;
|
||||
|
||||
if (!lexicalScopeNode) {
|
||||
throw new Error('Cannot find lexical scope node for the host statement node');
|
||||
}
|
||||
|
||||
const properties: ESTree.Property[] = objectExpressionNode.properties;
|
||||
|
||||
const newObjectExpressionHostStatement: ESTree.VariableDeclaration = this.getObjectExpressionHostNode(properties);
|
||||
const newObjectExpressionIdentifier: ESTree.Identifier = this.getObjectExpressionIdentifierNode(newObjectExpressionHostStatement);
|
||||
const newObjectExpressionNode: ESTree.ObjectExpression = this.getObjectExpressionNode(newObjectExpressionHostStatement);
|
||||
|
||||
const newObjectExpressionHostStatement: ESTree.VariableDeclaration = this.getObjectExpressionHostNode(
|
||||
lexicalScopeNode,
|
||||
properties
|
||||
);
|
||||
const statementsToInsert: TStatement[] = [newObjectExpressionHostStatement];
|
||||
const hostNodeWithStatements: TNodeWithStatements = NodeStatementUtils.getScopeOfNode(hostStatement);
|
||||
|
||||
@@ -87,6 +95,9 @@ export class ObjectExpressionToVariableDeclarationExtractor implements IObjectEx
|
||||
NodeUtils.parentizeAst(newObjectExpressionHostStatement);
|
||||
NodeUtils.parentizeNode(newObjectExpressionHostStatement, hostNodeWithStatements);
|
||||
|
||||
const newObjectExpressionIdentifier: ESTree.Identifier = this.getObjectExpressionIdentifierNode(newObjectExpressionHostStatement);
|
||||
const newObjectExpressionNode: ESTree.ObjectExpression = this.getObjectExpressionNode(newObjectExpressionHostStatement);
|
||||
|
||||
return {
|
||||
nodeToReplace: newObjectExpressionIdentifier,
|
||||
objectExpressionHostStatement: newObjectExpressionHostStatement,
|
||||
@@ -95,16 +106,20 @@ export class ObjectExpressionToVariableDeclarationExtractor implements IObjectEx
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {TNodeWithLexicalScope} lexicalScopeNode
|
||||
* @param {Property[]} properties
|
||||
* @returns {VariableDeclaration}
|
||||
*/
|
||||
private getObjectExpressionHostNode (properties: ESTree.Property[]): ESTree.VariableDeclaration {
|
||||
private getObjectExpressionHostNode (
|
||||
lexicalScopeNode: TNodeWithLexicalScope,
|
||||
properties: ESTree.Property[]
|
||||
): ESTree.VariableDeclaration {
|
||||
const variableDeclarationHostNodeCustomNode: ICustomNode<TInitialData<ObjectExpressionVariableDeclarationHostNode>> =
|
||||
this.objectExpressionKeysTransformerCustomNodeFactory(
|
||||
ObjectExpressionKeysTransformerCustomNode.ObjectExpressionVariableDeclarationHostNode
|
||||
);
|
||||
|
||||
variableDeclarationHostNodeCustomNode.initialize(properties);
|
||||
variableDeclarationHostNodeCustomNode.initialize(lexicalScopeNode, properties);
|
||||
|
||||
const statementNode: TStatement = variableDeclarationHostNodeCustomNode.getNode()[0];
|
||||
|
||||
|
||||
@@ -117,15 +117,6 @@ export class VariablePreserveTransformer extends AbstractNodeTransformer {
|
||||
identifierNode: ESTree.Identifier,
|
||||
parentNode: ESTree.Node
|
||||
): void {
|
||||
if (
|
||||
!NodeGuards.parentNodeIsPropertyNode(identifierNode, parentNode)
|
||||
&& !NodeGuards.parentNodeIsMemberExpressionNode(identifierNode, parentNode)
|
||||
&& !NodeGuards.parentNodeIsMethodDefinitionNode(identifierNode, parentNode)
|
||||
&& !NodeGuards.isLabelIdentifierNode(identifierNode, parentNode)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const lexicalScope of this.enteredLexicalScopesStack) {
|
||||
this.identifierObfuscatingReplacer.preserveNameForLexicalScope(identifierNode, lexicalScope);
|
||||
}
|
||||
|
||||
+10
-8
@@ -7,21 +7,23 @@ import { NO_ADDITIONAL_NODES_PRESET } from '../../src/options/presets/NoCustomNo
|
||||
|
||||
let obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
|
||||
`
|
||||
function foo () {
|
||||
const testA = 'abc';
|
||||
const testB = 'abc';
|
||||
const testC = 'abc';
|
||||
const testD = 'abc';
|
||||
function a (a, b) {
|
||||
|
||||
}
|
||||
|
||||
function b (b, c) {
|
||||
|
||||
}
|
||||
`,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
compact: false,
|
||||
identifierNamesGenerator: 'dictionary',
|
||||
identifiersDictionary: ['a', 'b', 'aa'],
|
||||
identifierNamesGenerator: 'mangled',
|
||||
identifiersPrefix: 'a',
|
||||
transformObjectKeys: true,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1
|
||||
stringArrayThreshold: 1,
|
||||
log: true
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
|
||||
|
||||
+15
-5
@@ -78,6 +78,7 @@ describe('MangledIdentifierNamesGenerator', () => {
|
||||
describe('Variant #2: should not generate same prefixed name for identifier in code as prefixed name of string array', () => {
|
||||
describe('Variant #1: `renameGlobals` option is disabled', () => {
|
||||
const stringArrayStorageRegExp: RegExp = /const aa *= *\['abc', *'last'];/;
|
||||
const functionDeclarationIdentifierNameRegExp: RegExp = /function foo *\(\) *{/;
|
||||
const lastVariableDeclarationIdentifierNameRegExp: RegExp = /const ac *= *ab\('0x1'\);/;
|
||||
|
||||
let obfuscatedCode: string;
|
||||
@@ -98,18 +99,23 @@ describe('MangledIdentifierNamesGenerator', () => {
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('Match #1: should generate correct identifier for string array', () => {
|
||||
it('Match #1: should generate correct identifier name for string array', () => {
|
||||
assert.match(obfuscatedCode, stringArrayStorageRegExp);
|
||||
});
|
||||
|
||||
it('Match #2: should keep identifier name for last variable declaration', () => {
|
||||
it('Match #2: should keep identifier name for function declaration', () => {
|
||||
assert.match(obfuscatedCode, functionDeclarationIdentifierNameRegExp);
|
||||
});
|
||||
|
||||
it('Match #3: should keep identifier name for last variable declaration', () => {
|
||||
assert.match(obfuscatedCode, lastVariableDeclarationIdentifierNameRegExp);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #2: `renameGlobals` option is enabled', () => {
|
||||
const stringArrayStorageRegExp: RegExp = /const aa *= *\['abc', *'last'];/;
|
||||
const lastVariableDeclarationIdentifierNameRegExp: RegExp = /const ae *= *ab\('0x1'\);/;
|
||||
const functionDeclarationIdentifierNameRegExp: RegExp = /function ac *\(\) *{/;
|
||||
const lastVariableDeclarationIdentifierNameRegExp: RegExp = /const ad *= *ab\('0x1'\);/;
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
@@ -130,11 +136,15 @@ describe('MangledIdentifierNamesGenerator', () => {
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('Match #1: should generate correct identifier for string array', () => {
|
||||
it('Match #1: should generate correct identifier name for string array', () => {
|
||||
assert.match(obfuscatedCode, stringArrayStorageRegExp);
|
||||
});
|
||||
|
||||
it('Match #2: should keep identifier name for last variable declaration', () => {
|
||||
it('Match #2: should generate correct identifier name for function declaration', () => {
|
||||
assert.match(obfuscatedCode, functionDeclarationIdentifierNameRegExp);
|
||||
});
|
||||
|
||||
it('Match #3: should keep identifier name for last variable declaration', () => {
|
||||
assert.match(obfuscatedCode, lastVariableDeclarationIdentifierNameRegExp);
|
||||
});
|
||||
});
|
||||
|
||||
+3
-1
@@ -59,5 +59,7 @@ function foo () {
|
||||
const test32 = 'abc';
|
||||
const test33 = 'abc';
|
||||
const test34 = 'abc';
|
||||
const test35 = 'last';
|
||||
const test35 = 'abc';
|
||||
const test36 = 'abc';
|
||||
const test38 = 'last';
|
||||
}
|
||||
+8
-8
@@ -482,15 +482,15 @@ describe('ScopeIdentifiersTransformer ClassDeclaration identifiers', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #3: already renamed identifiers shouldn\'t be renamed twice', () => {
|
||||
const classDeclarationRegExp: RegExp = /class *b *{/;
|
||||
const variableDeclarationsRegExp: RegExp = /let c, *d, *e, *f;/;
|
||||
const classReferenceRegExp: RegExp = /new b\(\);/;
|
||||
describe('Variant #3: preserved identifier names shouldn\'t be used as identifier names', () => {
|
||||
const classDeclarationRegExp: RegExp = /class *f *{/;
|
||||
const variableDeclarationsRegExp: RegExp = /let g, *h, *i, *j;/;
|
||||
const classReferenceRegExp: RegExp = /new f\(\);/;
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/prevent-renaming-of-renamed-identifiers.js');
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/prevent-using-of-preserved-identifiers.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
@@ -501,15 +501,15 @@ describe('ScopeIdentifiersTransformer ClassDeclaration identifiers', () => {
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('Match #1: shouldn\'t rename twice class declaration name', () => {
|
||||
it('Match #1: shouldn\'t use preserved identifier name as class declaration name', () => {
|
||||
assert.match(obfuscatedCode, classDeclarationRegExp);
|
||||
});
|
||||
|
||||
it('Match #2: should correctly rename variable declarations', () => {
|
||||
it('Match #2: shouldn\'t use preserved identifier name as variable declarations', () => {
|
||||
assert.match(obfuscatedCode, variableDeclarationsRegExp);
|
||||
});
|
||||
|
||||
it('Match #3: should correctly rename class reference identifier', () => {
|
||||
it('Match #3: shouldn\'t use preserved identifier name as class reference identifier', () => {
|
||||
assert.match(obfuscatedCode, classReferenceRegExp);
|
||||
});
|
||||
});
|
||||
|
||||
+6
-6
@@ -143,15 +143,15 @@ describe('ScopeIdentifiersTransformer FunctionDeclaration identifiers', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #5: already renamed identifiers shouldn\'t be renamed twice', () => {
|
||||
describe('Variant #5: preserved identifier names shouldn\'t be used as identifier names', () => {
|
||||
describe('Variant #1', () => {
|
||||
const functionDeclarationRegExp: RegExp = /function *a\(\) *{/;
|
||||
const variableDeclarationsRegExp: RegExp = /let c, *d, *e, *f;/;
|
||||
const functionDeclarationRegExp: RegExp = /function *e\(\) *{/;
|
||||
const variableDeclarationsRegExp: RegExp = /let g, *h, *i, *j;/;
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/prevent-renaming-of-renamed-identifiers-1.js');
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/prevent-using-of-preserved-identifiers-1.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
@@ -162,11 +162,11 @@ describe('ScopeIdentifiersTransformer FunctionDeclaration identifiers', () => {
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('Match #1: shouldn\'t rename twice function declaration name', () => {
|
||||
it('Match #1: shouldn\'t use preserved identifier name as function declaration name', () => {
|
||||
assert.match(obfuscatedCode, functionDeclarationRegExp);
|
||||
});
|
||||
|
||||
it('Match #2: should correctly rename variable declarations', () => {
|
||||
it('Match #2: shouldn\'t use preserved identifier name as variable declarations', () => {
|
||||
assert.match(obfuscatedCode, variableDeclarationsRegExp);
|
||||
});
|
||||
});
|
||||
|
||||
+18
-18
@@ -454,18 +454,18 @@ describe('ScopeIdentifiersTransformer VariableDeclaration identifiers', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #13: already renamed identifiers shouldn\'t be renamed twice', () => {
|
||||
describe('Variant #13: preserved identifier names shouldn\'t be used as identifier names', () => {
|
||||
describe('Variant #1', () => {
|
||||
const variableDeclarationRegExp: RegExp = /var b *= *0x1;/;
|
||||
const functionDeclarationRegExp1: RegExp = /function *c *\(\) *{}/;
|
||||
const functionDeclarationRegExp2: RegExp = /function *d *\(\) *{}/;
|
||||
const functionDeclarationRegExp3: RegExp = /function *e *\(\) *{}/;
|
||||
const functionDeclarationRegExp4: RegExp = /function *f *\(\) *{}/;
|
||||
const variableDeclarationRegExp: RegExp = /var f *= *0x1;/;
|
||||
const functionDeclarationRegExp1: RegExp = /function *g *\(\) *{}/;
|
||||
const functionDeclarationRegExp2: RegExp = /function *h *\(\) *{}/;
|
||||
const functionDeclarationRegExp3: RegExp = /function *i *\(\) *{}/;
|
||||
const functionDeclarationRegExp4: RegExp = /function *j *\(\) *{}/;
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/prevent-renaming-of-renamed-identifiers-1.js');
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/prevent-using-of-preserved-identifiers-1.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
@@ -476,23 +476,23 @@ describe('ScopeIdentifiersTransformer VariableDeclaration identifiers', () => {
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('Match #1: shouldn\'t rename twice variable declaration name', () => {
|
||||
it('Match #1: shouldn\'t use preserved identifier name as variable declaration name', () => {
|
||||
assert.match(obfuscatedCode, variableDeclarationRegExp);
|
||||
});
|
||||
|
||||
it('Match #2: should correctly rename function declaration name', () => {
|
||||
it('Match #2: shouldn\'t use preserved identifier name as function declaration name', () => {
|
||||
assert.match(obfuscatedCode, functionDeclarationRegExp1);
|
||||
});
|
||||
|
||||
it('Match #3: should correctly rename function declaration name', () => {
|
||||
it('Match #3: shouldn\'t use preserved identifier name as function declaration name', () => {
|
||||
assert.match(obfuscatedCode, functionDeclarationRegExp2);
|
||||
});
|
||||
|
||||
it('Match #4: should correctly rename function declaration name', () => {
|
||||
it('Match #4: shouldn\'t use preserved identifier name as function declaration name', () => {
|
||||
assert.match(obfuscatedCode, functionDeclarationRegExp3);
|
||||
});
|
||||
|
||||
it('Match #5: should correctly rename function declaration name', () => {
|
||||
it('Match #5: shouldn\'t use preserved identifier name as function declaration name', () => {
|
||||
assert.match(obfuscatedCode, functionDeclarationRegExp4);
|
||||
});
|
||||
});
|
||||
@@ -501,12 +501,12 @@ describe('ScopeIdentifiersTransformer VariableDeclaration identifiers', () => {
|
||||
const variableDeclarationRegExp1: RegExp = /var b *= *0x1;/;
|
||||
const variableDeclarationRegExp2: RegExp = /var c;/;
|
||||
const functionDeclarationRegExp: RegExp = /function *d *\(\) *{/;
|
||||
const variableDeclarationRegExp3: RegExp = /var e *= *function *\(\) *{}/;
|
||||
const variableDeclarationRegExp3: RegExp = /var f *= *function *\(\) *{}/;
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/prevent-renaming-of-renamed-identifiers-2.js');
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/prevent-using-of-preserved-identifiers-2.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
@@ -517,19 +517,19 @@ describe('ScopeIdentifiersTransformer VariableDeclaration identifiers', () => {
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('Match #1: shouldn\'t rename twice variable declaration name', () => {
|
||||
it('Match #1: shouldn\'t use preserved identifier name as variable declaration name', () => {
|
||||
assert.match(obfuscatedCode, variableDeclarationRegExp1);
|
||||
});
|
||||
|
||||
it('Match #2: shouldn\'t rename twice variable declaration name', () => {
|
||||
it('Match #2: shouldn\'t use preserved identifier name as variable declaration name', () => {
|
||||
assert.match(obfuscatedCode, variableDeclarationRegExp2);
|
||||
});
|
||||
|
||||
it('Match #3: should correctly rename function declaration name', () => {
|
||||
it('Match #3: shouldn\'t use preserved identifier name as function declaration name', () => {
|
||||
assert.match(obfuscatedCode, functionDeclarationRegExp);
|
||||
});
|
||||
|
||||
it('Match #4: should correctly rename variable declaration name', () => {
|
||||
it('Match #4: shouldn\'t use preserved identifier name as variable declaration name', () => {
|
||||
assert.match(obfuscatedCode, variableDeclarationRegExp3);
|
||||
});
|
||||
});
|
||||
|
||||
+2
-2
@@ -98,8 +98,8 @@ describe('VariablePreserveTransformer', () => {
|
||||
});
|
||||
|
||||
describe('Variant #2: `renameGlobals` option is enabled', () => {
|
||||
const transformObjectKeysNameRegExp: RegExp = /const c *= *{};/;
|
||||
const identifierNameRegExp: RegExp = /const d *= *c;/;
|
||||
const transformObjectKeysNameRegExp: RegExp = /const b *= *{};/;
|
||||
const identifierNameRegExp: RegExp = /const c *= *b;/;
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user