123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175 |
- 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';
- import { TNodeWithLexicalScope } from '../../types/node/TNodeWithLexicalScope';
- import { NodeLexicalScopeUtils } from '../../node/NodeLexicalScopeUtils';
- @injectable()
- export class DictionaryIdentifierNamesGenerator extends AbstractIdentifierNamesGenerator {
- /**
- * @type {IArrayUtils}
- */
- private readonly arrayUtils: IArrayUtils;
- /**
- * @type {Set<string>}
- */
- private identifierNamesSet: Set<string>;
-
- /**
- * @type {IterableIterator<string>}
- */
- private identifiersIterator: IterableIterator<string>;
- /**
- * @param {IRandomGenerator} randomGenerator
- * @param {IOptions} options
- * @param {IArrayUtils} arrayUtils
- */
- public constructor (
- @inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
- @inject(ServiceIdentifiers.IOptions) options: IOptions,
- @inject(ServiceIdentifiers.IArrayUtils) arrayUtils: IArrayUtils,
- ) {
- super(randomGenerator, options);
- this.arrayUtils = arrayUtils;
- this.identifierNamesSet = new Set(this.getInitialIdentifierNames(this.options.identifiersDictionary));
- this.identifiersIterator = this.identifierNamesSet.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 generateNext (): string {
- const identifierName: string = this.generateNewDictionaryName();
- this.preserveName(identifierName);
- return identifierName;
- }
- /**
- * @returns {string}
- */
- public generateForGlobalScope (): string {
- const prefix: string = this.options.identifiersPrefix ?
- `${this.options.identifiersPrefix}`
- : '';
- const identifierName: string = this.generateNewDictionaryName();
- const identifierNameWithPrefix: string = `${prefix}${identifierName}`;
- if (!this.isValidIdentifierName(identifierNameWithPrefix)) {
- return this.generateForGlobalScope();
- }
- this.preserveName(identifierNameWithPrefix);
- return identifierNameWithPrefix;
- }
- /**
- * @param {TNodeWithLexicalScope} lexicalScopeNode
- * @returns {string}
- */
- public generateForLexicalScope (lexicalScopeNode: TNodeWithLexicalScope): string {
- const lexicalScopes: TNodeWithLexicalScope[] = [
- lexicalScopeNode,
- ...NodeLexicalScopeUtils.getLexicalScopes(lexicalScopeNode)
- ];
- const identifierName: string = this.generateNewDictionaryName();
- if (!this.isValidIdentifierNameInLexicalScopes(identifierName, lexicalScopes)) {
- return this.generateForLexicalScope(lexicalScopeNode);
- }
- this.preserveNameForLexicalScope(identifierName, lexicalScopeNode);
- return identifierName;
- }
- /**
- * @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[]}
- */
- 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);
- }
- }
|