Skip to content

Commit ed5855c

Browse files
Add tests and refine API
1 parent 2c9501a commit ed5855c

14 files changed

+289
-32
lines changed

Modules/Minification/Concern/MinifyBuilder.cs

+9-1
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,16 @@ public sealed class MinifyBuilder : IConcernBuilder
1414
{
1515
private readonly List<IMinificationPlugin> _Plugins = new();
1616

17+
private MinificationErrors _ErrorHandling = MinificationErrors.Ignore;
18+
1719
#region Functionality
1820

21+
public MinifyBuilder ErrorHandling(MinificationErrors strategy)
22+
{
23+
_ErrorHandling = strategy;
24+
return this;
25+
}
26+
1927
public MinifyBuilder AddJS() => Add(new JSPlugin());
2028

2129
public MinifyBuilder AddCss() => Add(new CssPlugin());
@@ -30,7 +38,7 @@ public MinifyBuilder Add(IMinificationPlugin plugin)
3038

3139
public IConcern Build(IHandler parent, Func<IHandler, IHandler> contentFactory)
3240
{
33-
throw new NotImplementedException();
41+
return new MinifyConcern(parent, contentFactory, _Plugins, _ErrorHandling);
3442
}
3543

3644
#endregion

Modules/Minification/Concern/MinifyConcern.cs

+21-11
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,19 @@ public sealed class MinifyConcern : IConcern
1919

2020
public IReadOnlyList<IMinificationPlugin> Plugins { get; }
2121

22+
public MinificationErrors ErrorHandling { get; }
23+
2224
#endregion
2325

2426
#region Initialization
2527

26-
public MinifyConcern(IHandler parent, Func<IHandler, IHandler> contentFactory, IReadOnlyList<IMinificationPlugin> plugins)
28+
public MinifyConcern(IHandler parent, Func<IHandler, IHandler> contentFactory, IReadOnlyList<IMinificationPlugin> plugins, MinificationErrors errorHandling)
2729
{
2830
Parent = parent;
2931
Content = contentFactory(this);
3032

3133
Plugins = plugins;
34+
ErrorHandling = errorHandling;
3235
}
3336

3437
#endregion
@@ -41,21 +44,28 @@ public MinifyConcern(IHandler parent, Func<IHandler, IHandler> contentFactory, I
4144

4245
public async ValueTask<IResponse?> HandleAsync(IRequest request)
4346
{
44-
var response = await Content.HandleAsync(request);
45-
46-
if (response != null)
47+
if (!request.Server.Development)
4748
{
48-
foreach (var plugin in Plugins)
49-
{
50-
if (plugin.Supports(response))
49+
var response = await Content.HandleAsync(request);
50+
51+
if (response != null)
52+
{
53+
foreach (var plugin in Plugins)
5154
{
52-
plugin.Process(response);
53-
break;
55+
if (plugin.Supports(response))
56+
{
57+
plugin.Process(response, ErrorHandling);
58+
break;
59+
}
5460
}
5561
}
56-
}
5762

58-
return response;
63+
return response;
64+
}
65+
else
66+
{
67+
return await Content.HandleAsync(request);
68+
}
5969
}
6070

6171
#endregion

Modules/Minification/Extensions.cs

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using GenHTTP.Api.Content;
2+
3+
namespace GenHTTP.Modules.Minification
4+
{
5+
public static class Extensions
6+
{
7+
8+
public static T Minification<T>(this T builder) where T : IHandlerBuilder<T>
9+
{
10+
builder.Add(Minify.Default());
11+
return builder;
12+
}
13+
14+
}
15+
}

Modules/Minification/IMinificationPlugin.cs

+2-1
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,12 @@ public interface IMinificationPlugin
2323
/// Process the given response by replacing it's content with a minified version.
2424
/// </summary>
2525
/// <param name="response">The response to be minified</param>
26+
/// <param name="errorHandling">The error handling strategy to be applied by this plugin</param>
2627
/// <remarks>
2728
/// Please ensure that your plugin properly sets the content length on the response
2829
/// (e.g. by setting it to null).
2930
/// </remarks>
30-
void Process(IResponse response);
31+
void Process(IResponse response, MinificationErrors errorHandling);
3132

3233
}
3334

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+

2+
namespace GenHTTP.Modules.Minification
3+
{
4+
5+
/// <summary>
6+
/// Defines the error handling strategy to be respected by a plugin.
7+
/// </summary>
8+
public enum MinificationErrors
9+
{
10+
11+
/// <summary>
12+
/// Ignores errors raised by the plugin and serves the generated
13+
/// content anyway.
14+
/// </summary>
15+
/// <remarks>
16+
/// For plugins where this is not possible this should behave like
17+
/// <see cref="ServeOriginal" />.
18+
/// </remarks>
19+
Ignore,
20+
21+
/// <summary>
22+
/// Serves the original, not minified content in case of an error.
23+
/// </summary>
24+
ServeOriginal,
25+
26+
/// <summary>
27+
/// Throws an exception, resulting in a HTTP 500 error message being
28+
/// rendered.
29+
/// </summary>
30+
Throw
31+
32+
}
33+
34+
}

Modules/Minification/Plugins/CSS/CssPlugin.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ public bool Supports(IResponse response)
1515
return (contentType == ContentType.TextCss);
1616
}
1717

18-
public void Process(IResponse response)
18+
public void Process(IResponse response, MinificationErrors errorHandling)
1919
{
20-
response.Content = new MinifiedCss(response.Content ?? throw new InvalidOperationException("Response has not content to be minified"));
20+
response.Content = new MinifiedCss(response.Content ?? throw new InvalidOperationException("Response has not content to be minified"), errorHandling);
2121
response.ContentLength = null;
2222
}
2323

Modules/Minification/Plugins/CSS/MinifiedCss.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@ namespace GenHTTP.Modules.Minification.Plugins.CSS
88
public sealed class MinifiedCss : TextBasedMinificationResult
99
{
1010

11-
public MinifiedCss(IResponseContent original) : base(original) { }
11+
public MinifiedCss(IResponseContent original, MinificationErrors errorHandling) : base(original, errorHandling) { }
1212

13-
protected override string Transform(string input)
13+
protected override string Transform(string input, bool ignoreErrors)
1414
{
1515
var minified = Uglify.Css(input);
1616

17-
if (minified.HasErrors)
17+
if (minified.HasErrors && !ignoreErrors)
1818
{
1919
throw new UglifyException("Failed to minify CSS", minified.Errors);
2020
}

Modules/Minification/Plugins/Html/HtmlPlugin.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ public bool Supports(IResponse response)
1515
return (contentType == ContentType.TextHtml);
1616
}
1717

18-
public void Process(IResponse response)
18+
public void Process(IResponse response, MinificationErrors errorHandling)
1919
{
20-
response.Content = new MinifiedHtml(response.Content ?? throw new InvalidOperationException("Response has not content to be minified"));
20+
response.Content = new MinifiedHtml(response.Content ?? throw new InvalidOperationException("Response has not content to be minified"), errorHandling);
2121
response.ContentLength = null;
2222
}
2323

Modules/Minification/Plugins/Html/MinifiedHtml.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@ namespace GenHTTP.Modules.Minification.Plugins.Html
88
public sealed class MinifiedHtml : TextBasedMinificationResult
99
{
1010

11-
public MinifiedHtml(IResponseContent original) : base(original) { }
11+
public MinifiedHtml(IResponseContent original, MinificationErrors errorHandling) : base(original, errorHandling) { }
1212

13-
protected override string Transform(string input)
13+
protected override string Transform(string input, bool ignoreErrors)
1414
{
1515
var minified = Uglify.Html(input);
1616

17-
if (minified.HasErrors)
17+
if (minified.HasErrors && !ignoreErrors)
1818
{
1919
throw new UglifyException("Failed to minify HTML", minified.Errors);
2020
}

Modules/Minification/Plugins/JS/JSPlugin.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ public bool Supports(IResponse response)
1515
return (contentType == ContentType.ApplicationJavaScript) || (contentType == ContentType.TextJavaScript);
1616
}
1717

18-
public void Process(IResponse response)
18+
public void Process(IResponse response, MinificationErrors errorHandling)
1919
{
20-
response.Content = new MinifiedJS(response.Content ?? throw new InvalidOperationException("Response has not content to be minified"));
20+
response.Content = new MinifiedJS(response.Content ?? throw new InvalidOperationException("Response has not content to be minified"), errorHandling);
2121
response.ContentLength = null;
2222
}
2323

Modules/Minification/Plugins/JS/MinifiedJS.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@ namespace GenHTTP.Modules.Minification.Plugins.JS
88
public sealed class MinifiedJS : TextBasedMinificationResult
99
{
1010

11-
public MinifiedJS(IResponseContent original) : base(original) { }
11+
public MinifiedJS(IResponseContent original, MinificationErrors errorHandling) : base(original, errorHandling) { }
1212

13-
protected override string Transform(string input)
13+
protected override string Transform(string input, bool ignoreErrors)
1414
{
1515
var minified = Uglify.Js(input);
1616

17-
if (minified.HasErrors)
17+
if (minified.HasErrors && !ignoreErrors)
1818
{
1919
throw new UglifyException("Failed to minify JS", minified.Errors);
2020
}

Modules/Minification/Plugins/TextBasedMinificationResult.cs

+22-3
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,16 @@ public abstract class TextBasedMinificationResult : IResponseContent
1515

1616
protected IResponseContent Original { get; }
1717

18+
protected MinificationErrors ErrorHandling { get; }
19+
1820
#endregion
1921

2022
#region Initialization
2123

22-
public TextBasedMinificationResult(IResponseContent original)
24+
public TextBasedMinificationResult(IResponseContent original, MinificationErrors errorHandling)
2325
{
2426
Original = original;
27+
ErrorHandling = errorHandling;
2528
}
2629

2730
#endregion
@@ -42,14 +45,30 @@ public async ValueTask WriteAsync(Stream target, uint bufferSize)
4245

4346
var content = await reader.ReadToEndAsync();
4447

45-
var transformed = Transform(content);
48+
string transformed;
49+
50+
try
51+
{
52+
transformed = Transform(content, ErrorHandling == MinificationErrors.Ignore);
53+
}
54+
catch
55+
{
56+
if (ErrorHandling == MinificationErrors.ServeOriginal)
57+
{
58+
transformed = content;
59+
}
60+
else
61+
{
62+
throw;
63+
}
64+
}
4665

4766
using var writer = new StreamWriter(target, bufferSize: (int)bufferSize, leaveOpen: true);
4867

4968
await writer.WriteAsync(transformed);
5069
}
5170

52-
protected abstract string Transform(string input);
71+
protected abstract string Transform(string input, bool ignoreErrors);
5372

5473
#endregion
5574

Testing/Acceptance/GenHTTP.Testing.Acceptance.csproj

+2-1
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,12 @@
6969
<ProjectReference Include="..\..\Modules\Conversion\GenHTTP.Modules.Conversion.csproj" />
7070
<ProjectReference Include="..\..\Modules\DirectoryBrowsing\GenHTTP.Modules.DirectoryBrowsing.csproj" />
7171
<ProjectReference Include="..\..\Modules\ErrorHandling\GenHTTP.Modules.ErrorHandling.csproj" />
72-
<ProjectReference Include="..\..\Modules\Functional\GenHTTP.Modules.Functional.csproj" />
72+
<ProjectReference Include="..\..\Modules\Functional\GenHTTP.Modules.Functional.csproj" />
7373
<ProjectReference Include="..\..\Modules\IO\GenHTTP.Modules.IO.csproj" />
7474
<ProjectReference Include="..\..\Modules\Layouting\GenHTTP.Modules.Layouting.csproj" />
7575
<ProjectReference Include="..\..\Modules\LoadBalancing\GenHTTP.Modules.LoadBalancing.csproj" />
7676
<ProjectReference Include="..\..\Modules\Markdown\GenHTTP.Modules.Markdown.csproj" />
77+
<ProjectReference Include="..\..\Modules\Minification\GenHTTP.Modules.Minification.csproj" />
7778
<ProjectReference Include="..\..\Modules\Placeholders\GenHTTP.Modules.Placeholders.csproj" />
7879
<ProjectReference Include="..\..\Modules\Practices\GenHTTP.Modules.Practices.csproj" />
7980
<ProjectReference Include="..\..\Modules\Protobuf\GenHTTP.Modules.Protobuf.csproj" />

0 commit comments

Comments
 (0)