DictionaryIdentifierNamesGenerator.ts 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. import { inject, injectable } from 'inversify';
  2. import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
  3. import { IArrayUtils } from '../../interfaces/utils/IArrayUtils';
  4. import { IOptions } from '../../interfaces/options/IOptions';
  5. import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
  6. import { AbstractIdentifierNamesGenerator } from './AbstractIdentifierNamesGenerator';
  7. import { TNodeWithLexicalScope } from '../../types/node/TNodeWithLexicalScope';
  8. import { NodeLexicalScopeUtils } from '../../node/NodeLexicalScopeUtils';
  9. @injectable()
  10. export class DictionaryIdentifierNamesGenerator extends AbstractIdentifierNamesGenerator {
  11. /**
  12. * @type {IArrayUtils}
  13. */
  14. private readonly arrayUtils: IArrayUtils;
  15. /**
  16. * @type {Set<string>}
  17. */
  18. private identifierNamesSet: Set<string>;
  19. /**
  20. * @type {IterableIterator<string>}
  21. */
  22. private identifiersIterator: IterableIterator<string>;
  23. /**
  24. * @param {IRandomGenerator} randomGenerator
  25. * @param {IOptions} options
  26. * @param {IArrayUtils} arrayUtils
  27. */
  28. public constructor (
  29. @inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
  30. @inject(ServiceIdentifiers.IOptions) options: IOptions,
  31. @inject(ServiceIdentifiers.IArrayUtils) arrayUtils: IArrayUtils,
  32. ) {
  33. super(randomGenerator, options);
  34. this.arrayUtils = arrayUtils;
  35. this.identifierNamesSet = new Set(this.getInitialIdentifierNames(this.options.identifiersDictionary));
  36. this.identifiersIterator = this.identifierNamesSet.values();
  37. }
  38. /**
  39. * @param {string} identifierName
  40. * @returns {string | null}
  41. */
  42. private static incrementIdentifierName (identifierName: string): string | null {
  43. let newIdentifierName: string = '';
  44. let isSuccess: boolean = false;
  45. for (const character of identifierName) {
  46. if (!isSuccess && character === character.toUpperCase()) {
  47. newIdentifierName += character.toLowerCase();
  48. } else if (!isSuccess && character === character.toLowerCase()) {
  49. newIdentifierName += character.toUpperCase();
  50. isSuccess = true;
  51. } else {
  52. newIdentifierName += character;
  53. }
  54. }
  55. if (isSuccess) {
  56. return newIdentifierName;
  57. }
  58. return null;
  59. }
  60. public generate (): string {
  61. const identifierName: string = this.generateNewDictionaryName();
  62. this.preserveName(identifierName);
  63. return identifierName;
  64. }
  65. /**
  66. * @param {TNodeWithLexicalScope} lexicalScopeNode
  67. * @returns {string}
  68. */
  69. public generateForLexicalScope (lexicalScopeNode: TNodeWithLexicalScope): string {
  70. const lexicalScopes: TNodeWithLexicalScope[] = [
  71. lexicalScopeNode,
  72. ...NodeLexicalScopeUtils.getLexicalScopes(lexicalScopeNode)
  73. ];
  74. const identifierName: string = this.generateNewDictionaryName();
  75. if (!this.isValidIdentifierNameInLexicalScopes(identifierName, lexicalScopes)) {
  76. return this.generateForLexicalScope(lexicalScopeNode);
  77. }
  78. this.preserveNameForLexicalScope(identifierName, lexicalScopeNode);
  79. return identifierName;
  80. }
  81. /**
  82. * @returns {string}
  83. */
  84. public generateWithPrefix (): string {
  85. const prefix: string = this.options.identifiersPrefix ?
  86. `${this.options.identifiersPrefix}`
  87. : '';
  88. const identifierName: string = this.generateNewDictionaryName();
  89. const identifierNameWithPrefix: string = `${prefix}${identifierName}`;
  90. if (!this.isValidIdentifierName(identifierNameWithPrefix)) {
  91. return this.generateWithPrefix();
  92. }
  93. this.preserveName(identifierNameWithPrefix);
  94. return identifierNameWithPrefix;
  95. }
  96. /**
  97. * @returns {string}
  98. */
  99. private generateNewDictionaryName (): string {
  100. if (!this.identifierNamesSet.size) {
  101. throw new Error('Too many identifiers in the code, add more words to identifiers dictionary');
  102. }
  103. const iteratorResult: IteratorResult<string> = this.identifiersIterator.next();
  104. if (!iteratorResult.done) {
  105. const identifierName: string =iteratorResult.value;
  106. if (!this.isValidIdentifierName(identifierName)) {
  107. return this.generateNewDictionaryName();
  108. }
  109. return iteratorResult.value;
  110. }
  111. this.identifierNamesSet = new Set(this.getIncrementedIdentifierNames([...this.identifierNamesSet]));
  112. this.identifiersIterator = this.identifierNamesSet.values();
  113. return this.generateNewDictionaryName();
  114. }
  115. /**
  116. * @param {string[]} identifierNames
  117. * @returns {string[]}
  118. */
  119. private getInitialIdentifierNames (identifierNames: string[]): string[] {
  120. const formattedIdentifierNames: string[] = identifierNames
  121. .filter(Boolean)
  122. .map((identifierName: string) => identifierName.toLowerCase());
  123. return this.arrayUtils.shuffle(formattedIdentifierNames);
  124. }
  125. /**
  126. * @param {string[]} identifierNames
  127. * @returns {string[]}
  128. */
  129. private getIncrementedIdentifierNames (identifierNames: string[]): string[] {
  130. const formattedIdentifierNames: string[] = [];
  131. for (const identifierName of identifierNames) {
  132. const newIdentifierName: string | null = DictionaryIdentifierNamesGenerator
  133. .incrementIdentifierName(identifierName);
  134. if (newIdentifierName) {
  135. formattedIdentifierNames.push(newIdentifierName);
  136. }
  137. }
  138. return this.arrayUtils.shuffle(formattedIdentifierNames);
  139. }
  140. }