mirror of
https://github.com/javascript-obfuscator/javascript-obfuscator
synced 2026-08-09 12:42:29 +00:00
Merge pull request #462 from javascript-obfuscator/dictionary-identifier-names-generator
Dictionary identifier names generator
This commit is contained in:
+1
-1
@@ -2,9 +2,9 @@ sudo: false
|
||||
language: node_js
|
||||
|
||||
node_js:
|
||||
- "8"
|
||||
- "10"
|
||||
- "12"
|
||||
- "13"
|
||||
- "stable"
|
||||
|
||||
cache:
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
Change Log
|
||||
|
||||
v0.20.0
|
||||
---
|
||||
* **Breaking:** dropped support of Node 8 because of end of maintenance support
|
||||
* **New option value:** `identifierNamesGenerator` now allows to set new `dictionary` identifier names generator
|
||||
* **New option:** `identifiersDictionary` sets identifiers dictionary for `identifierNamesGenerator: dictionary` option
|
||||
|
||||
Thanks to our contributors!
|
||||
* [adiantek](https://github.com/adiantek)
|
||||
|
||||
v0.19.4
|
||||
---
|
||||
* Fixed `reservedNames` option
|
||||
|
||||
@@ -292,6 +292,7 @@ Following options are available for the JS Obfuscator:
|
||||
disableConsoleOutput: false,
|
||||
domainLock: [],
|
||||
identifierNamesGenerator: 'hexadecimal',
|
||||
identifiersDictionary: [],
|
||||
identifiersPrefix: '',
|
||||
inputFileName: '',
|
||||
log: false,
|
||||
@@ -334,7 +335,8 @@ Following options are available for the JS Obfuscator:
|
||||
--disable-console-output <boolean>
|
||||
--domain-lock '<list>' (comma separated)
|
||||
--exclude '<list>' (comma separated)
|
||||
--identifier-names-generator <string> [hexadecimal, mangled]
|
||||
--identifier-names-generator <string> [dictionary, hexadecimal, mangled]
|
||||
--identifiers-dictionary '<list>' (comma separated)
|
||||
--identifiers-prefix <string>
|
||||
--log <boolean>
|
||||
--rename-globals <boolean>
|
||||
@@ -597,9 +599,15 @@ Type: `string` Default: `hexadecimal`
|
||||
Sets identifier names generator.
|
||||
|
||||
Available values:
|
||||
* `dictionary`: identifier names from [`identifiersDictionary`](#identifiersDictionary) list
|
||||
* `hexadecimal`: identifier names like `_0xabc123`
|
||||
* `mangled`: short identifier names like `a`, `b`, `c`
|
||||
|
||||
### `identifiersDictionary`
|
||||
Type: `string[]` Default: `[]`
|
||||
|
||||
Sets identifiers dictionary for [`identifierNamesGenerator`](#identifierNamesGenerator): `dictionary` option
|
||||
|
||||
### `identifiersPrefix`
|
||||
Type: `string` Default: `''`
|
||||
|
||||
|
||||
Vendored
+4
-4
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
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "javascript-obfuscator",
|
||||
"version": "0.19.4",
|
||||
"version": "0.20.0",
|
||||
"description": "JavaScript obfuscator",
|
||||
"keywords": [
|
||||
"obfuscator",
|
||||
@@ -12,7 +12,7 @@
|
||||
"js obfuscator"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
"node": ">=10"
|
||||
},
|
||||
"main": "dist/index.js",
|
||||
"browser": "dist/index.browser.js",
|
||||
|
||||
@@ -251,7 +251,7 @@ export class JavaScriptObfuscatorCLI implements IInitializable {
|
||||
.option(
|
||||
'--identifier-names-generator <string>',
|
||||
'Sets identifier names generator. ' +
|
||||
'Values: hexadecimal, mangled. ' +
|
||||
'Values: hexadecimal, mangled, dictionary. ' +
|
||||
'Default: hexadecimal',
|
||||
IdentifierNamesGeneratorSanitizer
|
||||
)
|
||||
@@ -259,6 +259,11 @@ export class JavaScriptObfuscatorCLI implements IInitializable {
|
||||
'--identifiers-prefix <string>',
|
||||
'Sets prefix for all global identifiers.'
|
||||
)
|
||||
.option(
|
||||
'--identifiers-dictionary <list> (comma separated, without whitespaces)',
|
||||
'Identifiers dictionary (comma separated) for `--identifier-names-generator dictionary` option',
|
||||
ArraySanitizer
|
||||
)
|
||||
.option(
|
||||
'--log <boolean>', 'Enables logging of the information to the console',
|
||||
BooleanSanitizer
|
||||
|
||||
@@ -6,11 +6,17 @@ import { IOptions } from '../../../interfaces/options/IOptions';
|
||||
|
||||
import { IdentifierNamesGenerator } from '../../../enums/generators/identifier-names-generators/IdentifierNamesGenerator';
|
||||
|
||||
import { DictionaryIdentifierNamesGenerator } from '../../../generators/identifier-names-generators/DictionaryIdentifierNamesGenerator';
|
||||
import { HexadecimalIdentifierNamesGenerator } from '../../../generators/identifier-names-generators/HexadecimalIdentifierNamesGenerator';
|
||||
import { MangledIdentifierNamesGenerator } from '../../../generators/identifier-names-generators/MangledIdentifierNamesGenerator';
|
||||
|
||||
export const generatorsModule: interfaces.ContainerModule = new ContainerModule((bind: interfaces.Bind) => {
|
||||
// identifier name generators
|
||||
bind<IIdentifierNamesGenerator>(ServiceIdentifiers.IIdentifierNamesGenerator)
|
||||
.to(DictionaryIdentifierNamesGenerator)
|
||||
.inSingletonScope()
|
||||
.whenTargetNamed(IdentifierNamesGenerator.DictionaryIdentifierNamesGenerator);
|
||||
|
||||
bind<IIdentifierNamesGenerator>(ServiceIdentifiers.IIdentifierNamesGenerator)
|
||||
.to(HexadecimalIdentifierNamesGenerator)
|
||||
.inSingletonScope()
|
||||
@@ -34,6 +40,14 @@ export const generatorsModule: interfaces.ContainerModule = new ContainerModule(
|
||||
let identifierNamesGenerator: IIdentifierNamesGenerator;
|
||||
|
||||
switch (options.identifierNamesGenerator) {
|
||||
case IdentifierNamesGenerator.DictionaryIdentifierNamesGenerator:
|
||||
identifierNamesGenerator = context.container.getNamed<IIdentifierNamesGenerator>(
|
||||
ServiceIdentifiers.IIdentifierNamesGenerator,
|
||||
IdentifierNamesGenerator.DictionaryIdentifierNamesGenerator
|
||||
);
|
||||
|
||||
break;
|
||||
|
||||
case IdentifierNamesGenerator.MangledIdentifierNamesGenerator:
|
||||
identifierNamesGenerator = context.container.getNamed<IIdentifierNamesGenerator>(
|
||||
ServiceIdentifiers.IIdentifierNamesGenerator,
|
||||
|
||||
@@ -77,6 +77,7 @@ export class NodeCallsControllerFunctionNode extends AbstractCustomNode {
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
identifierNamesGenerator: this.options.identifierNamesGenerator,
|
||||
identifiersDictionary: this.options.identifiersDictionary,
|
||||
seed: this.options.seed
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
|
||||
@@ -77,6 +77,7 @@ export class SelfDefendingUnicodeNode extends AbstractCustomNode {
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
identifierNamesGenerator: this.options.identifierNamesGenerator,
|
||||
identifiersDictionary: this.options.identifiersDictionary,
|
||||
seed: this.options.seed,
|
||||
unicodeEscapeSequence: true
|
||||
}
|
||||
|
||||
@@ -100,6 +100,7 @@ export class StringArrayCallsWrapper extends AbstractCustomNode {
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
identifierNamesGenerator: this.options.identifierNamesGenerator,
|
||||
identifiersDictionary: this.options.identifiersDictionary,
|
||||
seed: this.options.seed
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
|
||||
@@ -107,6 +107,7 @@ export class StringArrayRotateFunctionNode extends AbstractCustomNode {
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
identifierNamesGenerator: this.options.identifierNamesGenerator,
|
||||
identifiersDictionary: this.options.identifiersDictionary,
|
||||
seed: this.options.seed
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export enum IdentifierNamesGenerator {
|
||||
DictionaryIdentifierNamesGenerator = 'dictionary',
|
||||
HexadecimalIdentifierNamesGenerator = 'hexadecimal',
|
||||
MangledIdentifierNamesGenerator = 'mangled'
|
||||
}
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
|
||||
|
||||
import { IArrayUtils } from '../../interfaces/utils/IArrayUtils';
|
||||
import { IOptions } from '../../interfaces/options/IOptions';
|
||||
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
|
||||
|
||||
import { AbstractIdentifierNamesGenerator } from './AbstractIdentifierNamesGenerator';
|
||||
|
||||
@injectable()
|
||||
export class DictionaryIdentifierNamesGenerator extends AbstractIdentifierNamesGenerator {
|
||||
/**
|
||||
* @type {IArrayUtils}
|
||||
*/
|
||||
private readonly arrayUtils: IArrayUtils;
|
||||
|
||||
/**
|
||||
* @type {string[]}
|
||||
*/
|
||||
private identifierNames: string[] = [];
|
||||
|
||||
/**
|
||||
* @type {IterableIterator<string>}
|
||||
*/
|
||||
private identifiersIterator: IterableIterator<string>;
|
||||
|
||||
/**
|
||||
* @param {IRandomGenerator} randomGenerator
|
||||
* @param {IOptions} options
|
||||
* @param {IArrayUtils} arrayUtils
|
||||
*/
|
||||
constructor (
|
||||
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
|
||||
@inject(ServiceIdentifiers.IOptions) options: IOptions,
|
||||
@inject(ServiceIdentifiers.IArrayUtils) arrayUtils: IArrayUtils,
|
||||
) {
|
||||
super(randomGenerator, options);
|
||||
|
||||
this.arrayUtils = arrayUtils;
|
||||
this.identifierNames = this.getInitialIdentifierNames(this.options.identifiersDictionary);
|
||||
this.identifiersIterator = this.identifierNames.values();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} identifierName
|
||||
* @returns {string | null}
|
||||
*/
|
||||
private static incrementIdentifierName (identifierName: string): string | null {
|
||||
let newIdentifierName: string = '';
|
||||
let isSuccess: boolean = false;
|
||||
|
||||
for (const character of identifierName) {
|
||||
if (!isSuccess && character === character.toUpperCase()) {
|
||||
newIdentifierName += character.toLowerCase();
|
||||
} else if (!isSuccess && character === character.toLowerCase()) {
|
||||
newIdentifierName += character.toUpperCase();
|
||||
isSuccess = true;
|
||||
} else {
|
||||
newIdentifierName += character;
|
||||
}
|
||||
}
|
||||
|
||||
if (isSuccess) {
|
||||
return newIdentifierName;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public generate (): string {
|
||||
if (!this.identifierNames.length) {
|
||||
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) {
|
||||
return iteratorResult.value;
|
||||
}
|
||||
|
||||
this.identifierNames = this.getIncrementedIdentifierNames(this.identifierNames);
|
||||
this.identifiersIterator = this.identifierNames.values();
|
||||
|
||||
return this.generate();
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string}
|
||||
*/
|
||||
public generateWithPrefix (): string {
|
||||
const prefix: string = this.options.identifiersPrefix ?
|
||||
`${this.options.identifiersPrefix}_`
|
||||
: '';
|
||||
const identifierName: string = this.generate();
|
||||
|
||||
return `${prefix}${identifierName}`.replace('__', '_');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string[]} identifierNames
|
||||
* @returns {string[]}
|
||||
*/
|
||||
private getInitialIdentifierNames (identifierNames: string[]): string[] {
|
||||
const formattedIdentifierNames: string[] = identifierNames
|
||||
.filter(Boolean)
|
||||
.map((identifierName: string) => identifierName.toLowerCase());
|
||||
|
||||
return this.arrayUtils.shuffle(formattedIdentifierNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string[]} identifierNames
|
||||
* @returns {string[]}
|
||||
*/
|
||||
private getIncrementedIdentifierNames (identifierNames: string[]): string[] {
|
||||
const formattedIdentifierNames: string[] = [];
|
||||
|
||||
for (const identifierName of identifierNames) {
|
||||
const newIdentifierName: string | null = DictionaryIdentifierNamesGenerator
|
||||
.incrementIdentifierName(identifierName);
|
||||
|
||||
if (newIdentifierName) {
|
||||
formattedIdentifierNames.push(newIdentifierName);
|
||||
}
|
||||
}
|
||||
|
||||
return this.arrayUtils.shuffle(formattedIdentifierNames);
|
||||
}
|
||||
}
|
||||
Vendored
+1
@@ -15,6 +15,7 @@ export interface IOptions {
|
||||
readonly disableConsoleOutput: boolean;
|
||||
readonly domainLock: string[];
|
||||
readonly identifierNamesGenerator: IdentifierNamesGenerator;
|
||||
readonly identifiersDictionary: string[];
|
||||
readonly identifiersPrefix: string;
|
||||
readonly inputFileName: string;
|
||||
readonly log: boolean;
|
||||
|
||||
@@ -2,6 +2,7 @@ import { inject, injectable } from 'inversify';
|
||||
import { ServiceIdentifiers } from '../container/ServiceIdentifiers';
|
||||
|
||||
import {
|
||||
ArrayNotEmpty,
|
||||
ArrayUnique,
|
||||
IsArray,
|
||||
IsBoolean,
|
||||
@@ -107,6 +108,7 @@ export class Options implements IOptions {
|
||||
* @type {IdentifierNamesGenerator}
|
||||
*/
|
||||
@IsIn([
|
||||
IdentifierNamesGenerator.DictionaryIdentifierNamesGenerator,
|
||||
IdentifierNamesGenerator.HexadecimalIdentifierNamesGenerator,
|
||||
IdentifierNamesGenerator.MangledIdentifierNamesGenerator
|
||||
])
|
||||
@@ -118,6 +120,17 @@ export class Options implements IOptions {
|
||||
@IsString()
|
||||
public readonly identifiersPrefix!: string;
|
||||
|
||||
@IsArray()
|
||||
@ArrayUnique()
|
||||
@IsString({
|
||||
each: true
|
||||
})
|
||||
@ValidateIf((options: IOptions) =>
|
||||
options.identifierNamesGenerator === IdentifierNamesGenerator.DictionaryIdentifierNamesGenerator
|
||||
)
|
||||
@ArrayNotEmpty()
|
||||
public readonly identifiersDictionary!: string[];
|
||||
|
||||
/**
|
||||
* @type {string}
|
||||
*/
|
||||
|
||||
@@ -18,6 +18,7 @@ export const DEFAULT_PRESET: TInputOptions = Object.freeze({
|
||||
exclude: [],
|
||||
identifierNamesGenerator: IdentifierNamesGenerator.HexadecimalIdentifierNamesGenerator,
|
||||
identifiersPrefix: '',
|
||||
identifiersDictionary: [],
|
||||
inputFileName: '',
|
||||
log: false,
|
||||
renameGlobals: false,
|
||||
|
||||
@@ -17,6 +17,7 @@ export const NO_ADDITIONAL_NODES_PRESET: TInputOptions = Object.freeze({
|
||||
exclude: [],
|
||||
identifierNamesGenerator: IdentifierNamesGenerator.HexadecimalIdentifierNamesGenerator,
|
||||
identifiersPrefix: '',
|
||||
identifiersDictionary: [],
|
||||
inputFileName: '',
|
||||
log: false,
|
||||
renameGlobals: false,
|
||||
|
||||
@@ -50,6 +50,10 @@ export class StringArrayStorage extends ArrayStorage <string> {
|
||||
public initialize (): void {
|
||||
super.initialize();
|
||||
|
||||
if (!this.options.stringArray) {
|
||||
return;
|
||||
}
|
||||
|
||||
const baseStringArrayName: string = this.identifierNamesGenerator
|
||||
.generate(StringArrayStorage.stringArrayNameLength);
|
||||
const baseStringArrayCallsWrapperName: string = this.identifierNamesGenerator
|
||||
|
||||
+5
-6
@@ -6,16 +6,15 @@ import { NO_ADDITIONAL_NODES_PRESET } from '../../src/options/presets/NoCustomNo
|
||||
|
||||
let obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
|
||||
`
|
||||
var s = {
|
||||
'abcdefg': 'abcdefg'
|
||||
};
|
||||
var abc = 1;
|
||||
var cde = 1;
|
||||
var fg = 1;
|
||||
var sss = 1;
|
||||
`,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
compact: false,
|
||||
splitStrings: true,
|
||||
splitStringsChunkLength: 4,
|
||||
transformObjectKeys: true
|
||||
renameGlobals: true
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
|
||||
|
||||
@@ -569,6 +569,29 @@ describe('JavaScriptObfuscator', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('dictionary identifier names generator', () => {
|
||||
const regExp: RegExp = /var *[ab] *= *0x1; *var *[ab] *= *0x2; *var *[AB] *= *0x3;/;
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
beforeEach(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/dictionary-identifiers.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
identifierNamesGenerator: IdentifierNamesGenerator.DictionaryIdentifierNamesGenerator,
|
||||
identifiersDictionary: ['a', 'b']
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('should generate identifier based on the dictionary', () => {
|
||||
assert.match(obfuscatedCode, regExp);
|
||||
});
|
||||
});
|
||||
|
||||
describe('parse module', () => {
|
||||
describe('Variant #1: import', () => {
|
||||
const importRegExp: RegExp = /import *{foo} *from *'.\/foo';/;
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
(function () {
|
||||
var test1 = 1;
|
||||
var test2 = 2;
|
||||
var test3 = 3;
|
||||
})();
|
||||
+2
-2
@@ -121,8 +121,8 @@ describe('ClassDeclarationTransformer', () => {
|
||||
});
|
||||
|
||||
describe('Variant #3: already renamed identifiers shouldn\'t be renamed twice', () => {
|
||||
const classDeclarationRegExp: RegExp = /class *d *{/;
|
||||
const variableDeclarationsRegExp: RegExp = /let *e, *f, *g, *h;/;
|
||||
const classDeclarationRegExp: RegExp = /class *b *{/;
|
||||
const variableDeclarationsRegExp: RegExp = /let *c, *d, *e, *f;/;
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
|
||||
+2
-2
@@ -145,8 +145,8 @@ describe('FunctionDeclarationTransformer', () => {
|
||||
|
||||
describe('Variant #5: already renamed identifiers shouldn\'t be renamed twice', () => {
|
||||
describe('Variant #1', () => {
|
||||
const functionDeclarationRegExp: RegExp = /function *d\(\) *{/;
|
||||
const variableDeclarationsRegExp: RegExp = /let *e, *f, *g, *h;/;
|
||||
const functionDeclarationRegExp: RegExp = /function *b\(\) *{/;
|
||||
const variableDeclarationsRegExp: RegExp = /let *c, *d, *e, *f;/;
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
|
||||
+9
-9
@@ -426,11 +426,11 @@ describe('VariableDeclarationTransformer', () => {
|
||||
|
||||
describe('Variant #13: already renamed identifiers shouldn\'t be renamed twice', () => {
|
||||
describe('Variant #1', () => {
|
||||
const variableDeclarationRegExp: RegExp = /var *d *= *0x1;/;
|
||||
const functionDeclarationRegExp1: RegExp = /function *e *\(\) *{}/;
|
||||
const functionDeclarationRegExp2: RegExp = /function *f *\(\) *{}/;
|
||||
const functionDeclarationRegExp3: RegExp = /function *g *\(\) *{}/;
|
||||
const functionDeclarationRegExp4: RegExp = /function *h *\(\) *{}/;
|
||||
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 *\(\) *{}/;
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
@@ -468,10 +468,10 @@ describe('VariableDeclarationTransformer', () => {
|
||||
});
|
||||
|
||||
describe('Variant #2', () => {
|
||||
const variableDeclarationRegExp1: RegExp = /var *d *= *0x1;/;
|
||||
const variableDeclarationRegExp2: RegExp = /var *e;/;
|
||||
const functionDeclarationRegExp: RegExp = /function *f *\(\) *{/;
|
||||
const variableDeclarationRegExp3: RegExp = /var *f *= *function *\(\) *{}/;
|
||||
const variableDeclarationRegExp1: RegExp = /var *b *= *0x1;/;
|
||||
const variableDeclarationRegExp2: RegExp = /var *c;/;
|
||||
const functionDeclarationRegExp: RegExp = /function *d *\(\) *{/;
|
||||
const variableDeclarationRegExp3: RegExp = /var *d *= *function *\(\) *{}/;
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ import './unit-tests/cli/sanitizers/StringArrayEncodingSanitizer.spec';
|
||||
import './unit-tests/cli/utils/CLIUtils.spec';
|
||||
import './unit-tests/cli/utils/SourceCodeReader.spec';
|
||||
import './unit-tests/decorators/initializable/Initializable.spec';
|
||||
import './unit-tests/generators/identifier-names-generators/DictionarylIdentifierNamesGenerator.spec';
|
||||
import './unit-tests/generators/identifier-names-generators/HexadecimalIdentifierNamesGenerator.spec';
|
||||
import './unit-tests/generators/identifier-names-generators/MangledlIdentifierNamesGenerator.spec';
|
||||
import './unit-tests/javascript-obfuscator/EspreeFacade.spec';
|
||||
|
||||
+227
@@ -0,0 +1,227 @@
|
||||
import 'reflect-metadata';
|
||||
|
||||
import { assert } from 'chai';
|
||||
|
||||
import { ServiceIdentifiers } from '../../../../src/container/ServiceIdentifiers';
|
||||
|
||||
import { IIdentifierNamesGenerator } from '../../../../src/interfaces/generators/identifier-names-generators/IIdentifierNamesGenerator';
|
||||
import { IInversifyContainerFacade } from '../../../../src/interfaces/container/IInversifyContainerFacade';
|
||||
|
||||
import { IdentifierNamesGenerator } from '../../../../src/enums/generators/identifier-names-generators/IdentifierNamesGenerator';
|
||||
|
||||
import { InversifyContainerFacade } from '../../../../src/container/InversifyContainerFacade';
|
||||
|
||||
describe('DictionaryIdentifierNamesGenerator', () => {
|
||||
describe('generate', () => {
|
||||
let identifierNamesGenerator: IIdentifierNamesGenerator,
|
||||
dictionaryIdentifierName: string;
|
||||
|
||||
describe('Base behaviour', () => {
|
||||
before(() => {
|
||||
const inversifyContainerFacade: IInversifyContainerFacade = new InversifyContainerFacade();
|
||||
|
||||
inversifyContainerFacade.load('', '', {
|
||||
identifiersDictionary: ['a', 'b']
|
||||
});
|
||||
identifierNamesGenerator = inversifyContainerFacade.getNamed<IIdentifierNamesGenerator>(
|
||||
ServiceIdentifiers.IIdentifierNamesGenerator,
|
||||
IdentifierNamesGenerator.DictionaryIdentifierNamesGenerator
|
||||
);
|
||||
});
|
||||
|
||||
describe('Variant #1: first dictionary iteration', () => {
|
||||
const expectedDictionaryIdentifierNameRegExp: RegExp = /[a|b]/;
|
||||
|
||||
beforeEach(() => {
|
||||
dictionaryIdentifierName = identifierNamesGenerator.generate();
|
||||
});
|
||||
|
||||
it('Match #1: should return first identifier name', () => {
|
||||
assert.match(dictionaryIdentifierName, expectedDictionaryIdentifierNameRegExp);
|
||||
});
|
||||
|
||||
it('Match #2: should return second identifier name', () => {
|
||||
assert.match(dictionaryIdentifierName, expectedDictionaryIdentifierNameRegExp);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #2: second dictionary iteration', () => {
|
||||
const expectedDictionaryIdentifierNameRegExp: RegExp = /[A|B]/;
|
||||
|
||||
beforeEach(() => {
|
||||
dictionaryIdentifierName = identifierNamesGenerator.generate();
|
||||
});
|
||||
|
||||
it('Match #1: should return third identifier name', () => {
|
||||
assert.match(dictionaryIdentifierName, expectedDictionaryIdentifierNameRegExp);
|
||||
});
|
||||
|
||||
it('Match #2: should return fourth identifier name', () => {
|
||||
assert.match(dictionaryIdentifierName, expectedDictionaryIdentifierNameRegExp);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Empty string as dictionary value', () => {
|
||||
before(() => {
|
||||
const inversifyContainerFacade: IInversifyContainerFacade = new InversifyContainerFacade();
|
||||
|
||||
inversifyContainerFacade.load('', '', {
|
||||
identifiersDictionary: ['', 'a']
|
||||
});
|
||||
identifierNamesGenerator = inversifyContainerFacade.getNamed<IIdentifierNamesGenerator>(
|
||||
ServiceIdentifiers.IIdentifierNamesGenerator,
|
||||
IdentifierNamesGenerator.DictionaryIdentifierNamesGenerator
|
||||
);
|
||||
});
|
||||
|
||||
describe('Variant #1: Should ignore empty strings from dictionary', () => {
|
||||
const expectedDictionaryIdentifierNameRegExp: RegExp = /[a|A]/;
|
||||
|
||||
beforeEach(() => {
|
||||
dictionaryIdentifierName = identifierNamesGenerator.generate();
|
||||
});
|
||||
|
||||
it('Match #1: should return first identifier name', () => {
|
||||
assert.match(dictionaryIdentifierName, expectedDictionaryIdentifierNameRegExp);
|
||||
});
|
||||
|
||||
it('Match #2: should return second identifier name', () => {
|
||||
assert.match(dictionaryIdentifierName, expectedDictionaryIdentifierNameRegExp);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Multi-character string as dictionary value', () => {
|
||||
before(() => {
|
||||
const inversifyContainerFacade: IInversifyContainerFacade = new InversifyContainerFacade();
|
||||
|
||||
inversifyContainerFacade.load('', '', {
|
||||
identifiersDictionary: ['aa']
|
||||
});
|
||||
identifierNamesGenerator = inversifyContainerFacade.getNamed<IIdentifierNamesGenerator>(
|
||||
ServiceIdentifiers.IIdentifierNamesGenerator,
|
||||
IdentifierNamesGenerator.DictionaryIdentifierNamesGenerator
|
||||
);
|
||||
});
|
||||
|
||||
describe('Variant #1: Should generate identifier names based on all variants of word from dictionary', () => {
|
||||
const expectedFirstIterationIdentifierName: string = 'aa';
|
||||
const expectedSecondIterationIdentifierName: string = 'Aa';
|
||||
const expectedThirdIterationIdentifierName: string = 'aA';
|
||||
const expectedFourthIterationIdentifierName: string = 'AA';
|
||||
|
||||
beforeEach(() => {
|
||||
dictionaryIdentifierName = identifierNamesGenerator.generate();
|
||||
});
|
||||
|
||||
it('Match #1: should return first identifier name', () => {
|
||||
assert.equal(dictionaryIdentifierName, expectedFirstIterationIdentifierName);
|
||||
});
|
||||
|
||||
it('Match #2: should return second identifier name', () => {
|
||||
assert.equal(dictionaryIdentifierName, expectedSecondIterationIdentifierName);
|
||||
});
|
||||
|
||||
it('Match #3: should return third identifier name', () => {
|
||||
assert.equal(dictionaryIdentifierName, expectedThirdIterationIdentifierName);
|
||||
});
|
||||
|
||||
it('Match #4: should return fourth identifier name', () => {
|
||||
assert.equal(dictionaryIdentifierName, expectedFourthIterationIdentifierName);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Generate with prefix', () => {
|
||||
before(() => {
|
||||
const inversifyContainerFacade: IInversifyContainerFacade = new InversifyContainerFacade();
|
||||
|
||||
inversifyContainerFacade.load('', '', {
|
||||
identifiersDictionary: ['a'],
|
||||
identifiersPrefix: 'foo'
|
||||
});
|
||||
identifierNamesGenerator = inversifyContainerFacade.getNamed<IIdentifierNamesGenerator>(
|
||||
ServiceIdentifiers.IIdentifierNamesGenerator,
|
||||
IdentifierNamesGenerator.DictionaryIdentifierNamesGenerator
|
||||
);
|
||||
});
|
||||
|
||||
describe('Variant #1: Should generate identifier names with prefix', () => {
|
||||
const expectedDictionaryIdentifierNameRegExp: RegExp = /foo_[a|A]/;
|
||||
|
||||
beforeEach(() => {
|
||||
dictionaryIdentifierName = identifierNamesGenerator.generateWithPrefix();
|
||||
});
|
||||
|
||||
it('Match #1: should return first identifier name', () => {
|
||||
assert.match(dictionaryIdentifierName, expectedDictionaryIdentifierNameRegExp);
|
||||
});
|
||||
|
||||
it('Match #2: should return second identifier name', () => {
|
||||
assert.match(dictionaryIdentifierName, expectedDictionaryIdentifierNameRegExp);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Errors', () => {
|
||||
let inversifyContainerFacade: IInversifyContainerFacade = new InversifyContainerFacade();
|
||||
|
||||
beforeEach(() => {
|
||||
inversifyContainerFacade = new InversifyContainerFacade();
|
||||
});
|
||||
|
||||
describe('Variant #1: No more identifier variants for generation', () => {
|
||||
const expectedDictionaryIdentifierNameRegExp: RegExp = /[a|A]/;
|
||||
|
||||
let testFunc: () => string;
|
||||
|
||||
before(() => {
|
||||
inversifyContainerFacade.load('', '', {
|
||||
identifiersDictionary: ['a']
|
||||
});
|
||||
identifierNamesGenerator = inversifyContainerFacade.getNamed<IIdentifierNamesGenerator>(
|
||||
ServiceIdentifiers.IIdentifierNamesGenerator,
|
||||
IdentifierNamesGenerator.DictionaryIdentifierNamesGenerator
|
||||
);
|
||||
|
||||
testFunc = () => identifierNamesGenerator.generate();
|
||||
});
|
||||
|
||||
it('Match #1: should return first identifier name', () => {
|
||||
dictionaryIdentifierName = testFunc();
|
||||
assert.match(dictionaryIdentifierName, expectedDictionaryIdentifierNameRegExp);
|
||||
});
|
||||
|
||||
it('Match #2: should return second identifier name', () => {
|
||||
dictionaryIdentifierName = testFunc();
|
||||
assert.match(dictionaryIdentifierName, expectedDictionaryIdentifierNameRegExp);
|
||||
});
|
||||
|
||||
it('Should throw an error when all identifier variants are used', () => {
|
||||
assert.throws(testFunc, Error);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #2: Empty identifiers dictionary', () => {
|
||||
let testFunc: () => string;
|
||||
|
||||
before(() => {
|
||||
inversifyContainerFacade.load('', '', {
|
||||
identifiersDictionary: []
|
||||
});
|
||||
identifierNamesGenerator = inversifyContainerFacade.getNamed<IIdentifierNamesGenerator>(
|
||||
ServiceIdentifiers.IIdentifierNamesGenerator,
|
||||
IdentifierNamesGenerator.DictionaryIdentifierNamesGenerator
|
||||
);
|
||||
|
||||
testFunc = () => identifierNamesGenerator.generate();
|
||||
});
|
||||
|
||||
it('Should throw an error when identifiers dictionary is empty', () => {
|
||||
assert.throws(testFunc, Error);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user