-
Notifications
You must be signed in to change notification settings - Fork 1
/
Minifier.cs
159 lines (144 loc) · 5.99 KB
/
Minifier.cs
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
namespace DotStd
{
/// <summary>
/// Minify some client site script file that has comments etc.
/// https://docs.microsoft.com/en-us/aspnet/core/client-side/bundling-and-minification?view=aspnetcore-3.1
/// use for: CSS, HTML, JavaScript
/// </summary>
public static class Minifier
{
public const string kMin = ".min."; // is minified version ?
public const string kMin2 = "-min."; // alternate minified naming style.
public const string kExtJs = ".js";
public const string kExtCss = ".css";
/// <summary>
/// Does this seem to be the name of a minified file name?
/// </summary>
/// <param name="n"></param>
/// <returns></returns>
public static bool IsMinName(string n)
{
if (n == null)
return false;
return n.Contains(kMin) || n.Contains(kMin2);
}
public static string GetNonMinName(string n)
{
// make the NON-minified version of the file name.
return n.Replace(kMin, ".").Replace(kMin2, ".").Replace("/min/", UrlUtil.kSep);
}
public static readonly string[] extensions =
{
kExtCss,
FileUtil.kExtHtm,
FileUtil.kExtHtml,
kExtJs,
};
const string kCommentClose = "*/";
/// <summary>
/// create a minified version of a file. CSS, JS or HTML.
/// </summary>
/// <param name="srcPath"></param>
/// <param name="dstMinPath"></param>
/// <returns></returns>
public static async Task<bool> CreateMinified(string srcPath, string dstMinPath)
{
try
{
var contents = await FileUtil.ReadAllLinesAsync(srcPath);
// Filter the contents to make the minified file.
using (var wr = File.CreateText(dstMinPath))
{
bool commentOpen = false;
foreach (string line in contents)
{
// remove extra whitespace at start and end of lines.
string line2 = line.Trim();
if (commentOpen)
{
// Look for close of comment.
int j = line2.IndexOf(kCommentClose);
if (j < 0)
continue;
line2 = line2.Substring(j + kCommentClose.Length).Trim();
commentOpen = false;
}
// remove blank lines.
if (string.IsNullOrWhiteSpace(line2))
continue;
// remove whole line comments.
if (line2.StartsWith("//"))
continue;
do_retest:
// remove /* Block Comment */
int i = line2.IndexOf("/*");
if (i >= 0)
{
string lineStart = line2.Substring(0, i).Trim();
int j = line2.IndexOf(kCommentClose, i);
if (j < 0)
{
// to next line.
commentOpen = true;
line2 = lineStart;
}
else
{
commentOpen = false;
line2 = lineStart + line2.Substring(j + kCommentClose.Length).Trim();
goto do_retest;
}
}
// ?? remove end line // comments
if (string.IsNullOrWhiteSpace(line2))
continue;
await wr.WriteLineAsync(line2);
}
}
return true;
}
catch (Exception ex)
{
LoggerUtil.DebugError("CreateMinified", ex);
return false;
}
}
/// <summary>
/// make minified versions of all the files in this directory if they don't already exist.
/// </summary>
/// <param name="dirPath"></param>
/// <param name="searchPattern"></param>
/// <returns></returns>
public static async Task UpdateDirectory(string dirPath, string? searchPattern = null)
{
var dir = new DirectoryInfo(dirPath);
var files1 = ((searchPattern == null) ? dir.GetFiles() : dir.GetFiles(searchPattern)).Where(x => extensions.Contains(x.Extension));
foreach (FileInfo info in files1)
{
string name = info.Name;
if (IsMinName(name))
continue;
// does the non min file have a valid minified version? must be ~newer
string dstMinPath;
FileInfo? infoMin = files1.FirstOrDefault(x => GetNonMinName(x.Name) == name && x.Name != name);
if (infoMin != null)
{
// Min file exists.
if ((infoMin.LastWriteTimeUtc - info.LastWriteTimeUtc).Minutes >= -2) // minified must be newer or close enough.
continue;
dstMinPath = infoMin.FullName;
}
else
{
dstMinPath = Path.Combine(Path.GetDirectoryName(info.FullName) ?? string.Empty, Path.GetFileNameWithoutExtension(name) + ".min" + Path.GetExtension(name)); // kMin
}
LoggerUtil.DebugEntry($"Update minified file '{dstMinPath}'");
await CreateMinified(info.FullName, dstMinPath);
}
}
}
}