MangledIdentifierNameGenerator.ts 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. import { inject, injectable } from 'inversify';
  2. import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
  3. import { IOptions } from '../../interfaces/options/IOptions';
  4. import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
  5. import { AbstractIdentifierNameGenerator } from './AbstractIdentifierNameGenerator';
  6. @injectable()
  7. export class MangledIdentifierNameGenerator extends AbstractIdentifierNameGenerator {
  8. /**
  9. * @type {string}
  10. */
  11. private static initMangledNameCharacter: string = '9';
  12. /**
  13. * @type {string[]}
  14. */
  15. private static nameSequence: string[] = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
  16. /**
  17. * Reserved JS words with length of 2-4 symbols that can be possible generated with this replacer
  18. *
  19. * @type {string[]}
  20. */
  21. private static reservedNames: string[] = [
  22. 'byte', 'case', 'char', 'do', 'else', 'enum', 'eval', 'for', 'goto',
  23. 'if', 'in', 'int', 'let', 'long', 'new', 'null', 'this', 'true', 'try',
  24. 'var', 'void', 'with'
  25. ];
  26. /**
  27. * @type {string}
  28. */
  29. private previousMangledName: string = MangledIdentifierNameGenerator.initMangledNameCharacter;
  30. /**
  31. * @param {IRandomGenerator} randomGenerator
  32. * @param {IOptions} options
  33. */
  34. constructor (
  35. @inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
  36. @inject(ServiceIdentifiers.IOptions) options: IOptions
  37. ) {
  38. super(randomGenerator, options);
  39. }
  40. /**
  41. * @param {string} previousMangledName
  42. * @returns {string}
  43. */
  44. private static generateNewMangledName (previousMangledName: string): string {
  45. const generateNewMangledName: (name: string) => string = (name: string): string => {
  46. const nameSequence: string[] = MangledIdentifierNameGenerator.nameSequence;
  47. const zeroSequenceCache: string[] = [];
  48. const zeroSequence: (num: number) => string = (num: number): string => {
  49. let result: string = zeroSequenceCache[num];
  50. if (result !== undefined) {
  51. return result;
  52. }
  53. result = '0'.repeat(num);
  54. zeroSequenceCache[num] = result;
  55. return result;
  56. };
  57. let cur: number = name.length - 1;
  58. do {
  59. let character: string, index: number;
  60. character = name.charAt(cur);
  61. index = nameSequence.indexOf(character);
  62. if (index !== (nameSequence.length - 1)) {
  63. return name.substring(0, cur) + nameSequence[index + 1] + zeroSequence(name.length - (cur + 1));
  64. }
  65. --cur;
  66. } while (cur >= 0);
  67. return `a${zeroSequence(name.length)}`;
  68. };
  69. let newMangledName: string = generateNewMangledName(previousMangledName);
  70. if (!MangledIdentifierNameGenerator.validateMangledName(newMangledName)) {
  71. newMangledName = MangledIdentifierNameGenerator.generateNewMangledName(newMangledName);
  72. }
  73. return newMangledName;
  74. }
  75. /**
  76. * @param {string} mangledName
  77. * @returns {boolean}
  78. */
  79. private static validateMangledName (mangledName: string): boolean {
  80. return !MangledIdentifierNameGenerator.reservedNames.includes(mangledName);
  81. }
  82. /**
  83. * @param {number} length
  84. * @returns {string}
  85. */
  86. public generate (length: number): string {
  87. const newName: string = MangledIdentifierNameGenerator.generateNewMangledName(this.previousMangledName);
  88. this.previousMangledName = newName;
  89. return newName;
  90. }
  91. }