ObfuscatedCodeFileUtils.ts 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. import * as fs from 'fs';
  2. import * as mkdirp from 'mkdirp';
  3. import * as path from 'path';
  4. import { TInputCLIOptions } from '../../types/options/TInputCLIOptions';
  5. import { StringSeparator } from '../../enums/StringSeparator';
  6. import { JavaScriptObfuscatorCLI } from '../JavaScriptObfuscatorCLI';
  7. export class ObfuscatedCodeFileUtils {
  8. /**
  9. * @type {string}
  10. */
  11. private readonly inputPath: string;
  12. /**
  13. * @type {TInputCLIOptions}
  14. */
  15. private readonly options: TInputCLIOptions;
  16. /**
  17. * @param {string} inputPath
  18. * @param {TInputCLIOptions} options
  19. */
  20. public constructor (
  21. inputPath: string,
  22. options: TInputCLIOptions
  23. ) {
  24. this.inputPath = path.normalize(inputPath);
  25. this.options = options;
  26. }
  27. /**
  28. * @param {string} filePath
  29. * @returns {string}
  30. */
  31. public getOutputCodePath (filePath: string): string {
  32. const normalizedFilePath: string = path.normalize(filePath);
  33. const normalizedRawOutputPath: string | null = this.options.output
  34. ? path.normalize(this.options.output)
  35. : null;
  36. if (!normalizedRawOutputPath) {
  37. return normalizedFilePath
  38. .split(StringSeparator.Dot)
  39. .map((value: string, index: number) => {
  40. return index === 0 ? `${value}${JavaScriptObfuscatorCLI.obfuscatedFilePrefix}` : value;
  41. })
  42. .join(StringSeparator.Dot);
  43. }
  44. const rawInputPathStats: fs.Stats = fs.lstatSync(this.inputPath);
  45. const outputPathExtName: string = path.extname(normalizedRawOutputPath);
  46. const isDirectoryRawInputPath: boolean = rawInputPathStats.isDirectory();
  47. const isDirectoryRawOutputPath: boolean = !JavaScriptObfuscatorCLI
  48. .availableInputExtensions
  49. .includes(outputPathExtName);
  50. if (isDirectoryRawInputPath) {
  51. if (isDirectoryRawOutputPath) {
  52. const parsedNormalizedFilePath: path.ParsedPath = path.parse(normalizedFilePath);
  53. // Make ending with "/" consistent
  54. if (!parsedNormalizedFilePath.dir.endsWith('/') && this.inputPath.endsWith('/')) {
  55. parsedNormalizedFilePath.dir += '/';
  56. }
  57. const baseOutputPath: string = path.join(
  58. parsedNormalizedFilePath.dir.replace(this.inputPath, ''),
  59. parsedNormalizedFilePath.base
  60. );
  61. return path.join(normalizedRawOutputPath, baseOutputPath);
  62. } else {
  63. throw new Error('Output path for directory obfuscation should be a directory path');
  64. }
  65. } else {
  66. if (isDirectoryRawOutputPath) {
  67. return path.join(normalizedRawOutputPath, path.basename(filePath));
  68. } else {
  69. return normalizedRawOutputPath;
  70. }
  71. }
  72. }
  73. /**
  74. * @param {string} outputCodePath
  75. * @param {string} sourceMapFileName
  76. * @returns {string}
  77. */
  78. public getOutputSourceMapPath (outputCodePath: string, sourceMapFileName: string = ''): string {
  79. if (!outputCodePath) {
  80. throw new Error('Output code path is empty');
  81. }
  82. let normalizedOutputCodePath: string = path.normalize(outputCodePath);
  83. let parsedOutputCodePath: path.ParsedPath = path.parse(normalizedOutputCodePath);
  84. if (!parsedOutputCodePath.ext && !sourceMapFileName) {
  85. throw new Error('Source map file name should be set when output code path is a directory path');
  86. }
  87. if (sourceMapFileName) {
  88. const indexOfLastSeparator: number = normalizedOutputCodePath.lastIndexOf(path.sep);
  89. let sourceMapPath: string;
  90. if (parsedOutputCodePath.ext) {
  91. // File path with directory, like: `foo/bar.js`, or without, like: `bar.js`
  92. const isFilePathWithDirectory: boolean = indexOfLastSeparator > 0;
  93. sourceMapPath = isFilePathWithDirectory
  94. ? normalizedOutputCodePath.slice(0, indexOfLastSeparator)
  95. : '';
  96. } else {
  97. sourceMapPath = normalizedOutputCodePath;
  98. }
  99. // remove possible drive letter for win32 environment
  100. const normalizedSourceMapFilePath: string = sourceMapFileName.replace(/^[a-zA-Z]:\\*/, '');
  101. normalizedOutputCodePath = path.join(sourceMapPath, normalizedSourceMapFilePath);
  102. }
  103. if (!/\.js\.map$/.test(normalizedOutputCodePath)) {
  104. parsedOutputCodePath = path.parse(normalizedOutputCodePath);
  105. const outputCodePathWithoutExtension: string = path.join(parsedOutputCodePath.dir, parsedOutputCodePath.name);
  106. normalizedOutputCodePath = `${outputCodePathWithoutExtension}.js.map`;
  107. } else if (/\.js$/.test(normalizedOutputCodePath)) {
  108. normalizedOutputCodePath += '.map';
  109. }
  110. return normalizedOutputCodePath;
  111. }
  112. /**
  113. * @param {string} outputPath
  114. * @param {string} data
  115. */
  116. public writeFile (outputPath: string, data: string): void {
  117. mkdirp.sync(path.dirname(outputPath));
  118. fs.writeFileSync(outputPath, data, {
  119. encoding: JavaScriptObfuscatorCLI.encoding
  120. });
  121. }
  122. }