Repository navigation
Expand file tree
/
Copy pathProgram.cs
More file actions
130 lines (121 loc) · 5.64 KB
/
Copy pathProgram.cs
File metadata and controls
130 lines (121 loc) · 5.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
using CommandLine;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
namespace JavascriptSourceExtractor
{
class Program
{
static void Main(string[] args) => Parser.Default.ParseArguments<FileOptions, DirOptions>(args).WithParsed(o =>
{
try
{
int ret = 0;
if (o is FileOptions f)
{
l($"Starting conversion from file: {f.InputFile}");
doCommon(f);
ret = doFile(f);
}
if (o is DirOptions d)
{
l($"Starting conversion from directory: {d.InputFile}");
doCommon(d);
ret = doDirectory(d);
}
l($"Operation success! {ret} source files were extracted!");
}
catch(Exception e)
{
l($"Operation failed! Details:\r\n{e}", true);
Environment.Exit(1);
}
});
static void l(string msg, bool error = false)
{
if (error)
Console.Error.WriteLine(msg);
else Console.WriteLine(msg);
}
static void doCommon(Options options)
{
l($"Output directory: {options.OutputDir}. Creating if necessary");
Directory.CreateDirectory(options.OutputDir);
}
static int doFile(FileOptions options) => _processFile(options.InputFile, options.OutputDir, options);
static int doDirectory(DirOptions options)
{
l("Enumerating input directory contents");
var files = Directory.GetFiles(options.InputFile, "*", options.AllFiles ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);
var jsMapFiles = files.Where(e => e.EndsWith(".js.map", StringComparison.CurrentCultureIgnoreCase)).ToList();
jsMapFiles.RemoveAll(f => f.EndsWith(".min.js.map", StringComparison.CurrentCultureIgnoreCase) && jsMapFiles.Any(m => m == f.Replace(".min.js.map", ".js.map", StringComparison.CurrentCultureIgnoreCase)));
var singleJsFiles = files.Where(e => e.EndsWith(".js", StringComparison.CurrentCultureIgnoreCase) && !jsMapFiles.Contains($"{e}.map", StringComparer.CurrentCultureIgnoreCase)).ToList();
l($"{jsMapFiles.Count} js map files found!");
var ret = 0;
foreach (var map in jsMapFiles)
ret += _processFile(map, options.DifferentDirs? Path.Combine(options.OutputDir, Path.GetFileName(map).Replace(".js.map", "", StringComparison.CurrentCultureIgnoreCase)) : options.OutputDir, options);
l("Map files extracted!");
if (options.ExtractJsWithoutMap)
{
l($"{singleJsFiles.Count} single js files found. Copying them to output");
foreach (var j in singleJsFiles)
File.Copy(j, Path.Combine(options.OutputDir, Path.GetFileName(j)), true);
}
return ret;
}
static int _processFile(string filePath, string outputDir, Options options)
{
l($"\tExtracting files from source file: {filePath}");
var fileContent = _doOp("\tFailed to read file", ()=> File.ReadAllText(filePath));
var jsonContent = _doOp("\tFailed to parse file to JSON", () => JsonConvert.DeserializeObject<MapSchema>(fileContent));
if (jsonContent.sources.Length == 0)
{
l($"\tSourceMap file has no content. Skipping");
return 0;
}
if (jsonContent.sources.Length != jsonContent.sourcesContent.Length)
throw new Exception("SourceMap file invalid. Not the same number of sources and sourcecontents are provided");
int ret = 0;
for (int sourceIndex = 0;sourceIndex < jsonContent.sources.Length; sourceIndex++)
{
var sourcePath = jsonContent.sources[sourceIndex];
if (sourcePath.StartsWith("webpack:///external") || sourcePath.StartsWith("webpack:///(webpack)"))
continue;
var sourceFilePath = Path.Combine(new string[] { outputDir }.Concat(getWebpackFilePath(sourcePath)).ToArray());
if (sourceFilePath.EndsWith(".js", StringComparison.CurrentCultureIgnoreCase) && options.SkipJs)
continue;
if (sourceFilePath.EndsWith(".ts", StringComparison.CurrentCultureIgnoreCase) && options.SkipTs)
continue;
Directory.CreateDirectory(Path.GetDirectoryName(sourceFilePath));
File.WriteAllText(sourceFilePath, jsonContent.sourcesContent[sourceIndex]);
ret++;
}
return ret;
}
static T _doOp<T>(string error, Func<T> op)
{
try
{
return op();
}
catch(Exception ex)
{
throw new Exception(error, ex);
}
}
static string[] getWebpackFilePath(string path)
{
var regex = Regex.Match(path, @"^(?>webpack:\/\/)*[.|\/~]*([a-zA-Z(@].*)$");
if (!regex.Success || !regex.Groups[1].Success)
throw new Exception($"Webpack file path: '{path}' is not of valid format");
var val = regex.Groups[1].Value;
foreach (var c in Path.GetInvalidFileNameChars())
if (c != '/')
val = val.Replace(c, '_');
return val.Split('/').Where(e=> !e.All(c=>c == '.')).ToArray();
}
}
}