DictionaryIdentifierNamesGenerator.ts 5.0 KB

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