Skip to content

Commit e790387

Browse files
committed
Add ReDoS-safe regex & unit tests for ColorCode.Core
- Introduced ColorCode.Core.Tests (MSTest) with full coverage for Markdown, CSharp, JavaScript, and HTML parsing, including ReDoS prevention tests with large malformed inputs and timeouts. - Added LanguageParsingTestBase for shared test logic and reflection-based access to internal components. - Updated LanguageCompiler to use a 5-second regex timeout for all language rules, preventing catastrophic backtracking. - Fixed ReDoS-prone regexes in Markdown, CSharp, JavaScript, and Html language definitions. - Bumped BuildSite.csproj version to 2.2.0 and updated release notes. - Added detailed test README, favicon, and copilot-instructions.md. - Minor blog and sitemap content updates; fixed build.ps1 project path.
1 parent ab51db7 commit e790387

22 files changed

Lines changed: 1280 additions & 44 deletions

.github/copilot-instructions.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Copilot Instructions
2+
3+
## General Guidelines
4+
5+
## Project-Specific Rules
6+
- EasyDocs 项目 - 除非用户明确要求,否则不要自动生成任何报告、总结、交付说明等文档。只在用户明确指示时才创建这类文档。

WebApp/blogs.html

Lines changed: 9 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,7 @@
3939
</div>
4040
<div class="absolute z-10 mt-2 w-56 origin-top-right rounded-md bg-card dropdown-content hidden" tabindex="-1">
4141
<div class="py-1" role="none">
42-
<a href="/docs/EasyDoc.html" class="block px-4 py-2 text">EasyDoc</a>
43-
42+
4443
</div>
4544
</div>
4645
</div>
@@ -66,24 +65,12 @@
6665
<div class="w-full card-border rounded-md my-2">
6766
<div class="px-6 py-3">
6867
<div class="font-bold text-xl mb-2">
69-
<a href = "/blogs/作者的官方博客.html" target="_blank" class="block text-xl py-2 text-neutral-600 hover:text-neutral-800 dark:text-neutral-300 dark:hover:text-neutral-100">📑 作者的官方博客</a>
70-
</div>
71-
<p class="text-neutral-700 text-base dark:text-neutral-300">
72-
👨‍💻 NilTor
73-
&nbsp;&nbsp;
74-
📆 <span class="publish-time" data-time="2025-12-30T15:18:32+08:00"></span>
75-
</p>
76-
</div>
77-
</div>
78-
<div class="w-full card-border rounded-md my-2">
79-
<div class="px-6 py-3">
80-
<div class="font-bold text-xl mb-2">
81-
<a href = "/blogs/markdown/markdown渲染测试.html" target="_blank" class="block text-xl py-2 text-neutral-600 hover:text-neutral-800 dark:text-neutral-300 dark:hover:text-neutral-100">📑 markdown渲染测试</a>
68+
<a href = "/blogs/.NET/2026-Make-Dotnet-Great-Again.html" target="_blank" class="block text-xl py-2 text-neutral-600 hover:text-neutral-800 dark:text-neutral-300 dark:hover:text-neutral-100">📑 2026-Make-Dotnet-Great-Again</a>
8269
</div>
8370
<p class="text-neutral-700 text-base dark:text-neutral-300">
8471
👨‍💻 NilTor
8572
&nbsp;&nbsp;
86-
📆 <span class="publish-time" data-time="2025-12-30T15:18:32+08:00"></span>
73+
📆 <span class="publish-time" data-time="2026-01-01T10:59:03+08:00"></span>
8774
</p>
8875
</div>
8976
</div>
@@ -96,19 +83,19 @@
9683
<div id="catalog-list" class="card-border rounded-lg shadow-md p-4 dark:bg-neutral-800">
9784
<div class="text-xl font-semibold dark:text-neutral-300">分类</div>
9885
<span data-catalog="all" class="filter-item text-lg block py-2 text-neutral-600 hover:text-neutral-800 dark:text-neutral-300 dark:hover:text-neutral-100">
99-
全部 [2]
86+
全部 [1]
10087
</span>
101-
<span data-catalog="markdown" class="filter-item text-lg block py-2 text-neutral-600 hover:text-neutral-800 dark:text-neutral-300 dark:hover:text-neutral-100">
102-
markdown [1]
88+
<span data-catalog=".NET" class="filter-item text-lg block py-2 text-neutral-600 hover:text-neutral-800 dark:text-neutral-300 dark:hover:text-neutral-100">
89+
.NET [1]
10390
</span>
10491
</div>
10592
<div id="date-list" class="card-border rounded-lg shadow-md p-4 dark:bg-neutral-800 mt-3">
10693
<div class="text-xl font-semibold dark:text-neutral-300">存档</div>
10794
<span data-date="all" class="filter-item text-lg block py-2 text-neutral-600 hover:text-neutral-800 dark:text-neutral-300 dark:hover:text-neutral-100">
108-
全部 [2]
95+
全部 [1]
10996
</span>
110-
<span data-date="2025-12" class="filter-item text-lg block py-2 text-neutral-600 hover:text-neutral-800 dark:text-neutral-300 dark:hover:text-neutral-100">
111-
2025-12 [2]
97+
<span data-date="2026-01" class="filter-item text-lg block py-2 text-neutral-600 hover:text-neutral-800 dark:text-neutral-300 dark:hover:text-neutral-100">
98+
2026-01 [1]
11299
</span>
113100
</div>
114101

WebApp/favicon.png

4.01 KB
Loading

WebApp/sitemap.xml

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,8 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
33
<url>
4-
<loc>https://aterdev.github.io/blogs/作者的官方博客.html</loc>
5-
<lastmod>2025-12-30</lastmod>
6-
<changefreq>daily</changefreq>
7-
<priority>0.9</priority>
8-
</url>
9-
<url>
10-
<loc>https://aterdev.github.io/blogs/markdown/markdown渲染测试.html</loc>
11-
<lastmod>2025-12-30</lastmod>
4+
<loc>https://aterdev.github.io/blogs/.NET/2026-Make-Dotnet-Great-Again.html</loc>
5+
<lastmod>2026-01-01</lastmod>
126
<changefreq>daily</changefreq>
137
<priority>0.9</priority>
148
</url>

build.ps1

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
# 生成内容
2-
dotnet run --project ./src/BuildSite build ./webinfo.json
2+
dotnet run --project ./src/BuildSite/BuildSite.csproj build ./webinfo.json
33

src/BuildSite/BuildSite.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<ToolCommandName>ezdoc</ToolCommandName>
99
<PackageOutputPath>./nupkg</PackageOutputPath>
1010
<PackageId>Ater.EasyDocs</PackageId>
11-
<Version>2.1.6</Version>
11+
<Version>2.2.0</Version>
1212
<Description>Fast and lightweight static website generation tool!</Description>
1313
<Authors>NilTor</Authors>
1414
<Company>Atersoft</Company>
@@ -19,7 +19,7 @@
1919
<RepositoryType>git</RepositoryType>
2020
<RepositoryUrl>https://github.com/AterDev/EasyDocs</RepositoryUrl>
2121
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
22-
<PackageReleaseNotes>fix related md doc link in the a href</PackageReleaseNotes>
22+
<PackageReleaseNotes>1. fix regex stuck issue</PackageReleaseNotes>
2323
<ImplicitUsings>enable</ImplicitUsings>
2424
<AssemblyName>$(MSBuildProjectName)</AssemblyName>
2525
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>

src/BuildSite/Properties/launchSettings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{
1+
{
22
"profiles": {
33
"BuildSite": {
44
"commandName": "Project",
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
using ColorCode.Core;
2+
using ColorCode.Core.Compilation.Languages;
3+
using Microsoft.VisualStudio.TestTools.UnitTesting;
4+
5+
namespace ColorCode.Core.Tests;
6+
7+
/// <summary>
8+
/// Test cases for C# language parsing
9+
/// </summary>
10+
[TestClass]
11+
public class CSharpParsingTests : LanguageParsingTestBase
12+
{
13+
private CSharp? _csharp;
14+
15+
[TestInitialize]
16+
public new void Initialize()
17+
{
18+
base.Initialize();
19+
_csharp = new CSharp();
20+
}
21+
22+
[TestMethod]
23+
public void ParseSimpleClass()
24+
{
25+
var sourceCode = @"public class MyClass
26+
{
27+
public void MyMethod()
28+
{
29+
var x = 10;
30+
}
31+
}";
32+
VerifyParsingCompletes(sourceCode, _csharp!);
33+
34+
var result = Parse(sourceCode, _csharp!);
35+
Assert.IsNotNull(result);
36+
}
37+
38+
[TestMethod]
39+
public void ParseSingleLineComment()
40+
{
41+
var sourceCode = "// This is a comment\nvar x = 10; // inline comment";
42+
VerifyParsingCompletes(sourceCode, _csharp!);
43+
44+
var result = Parse(sourceCode, _csharp!);
45+
Assert.IsNotNull(result);
46+
}
47+
48+
[TestMethod]
49+
public void ParseMultiLineComment()
50+
{
51+
var sourceCode = @"/* This is a
52+
multiline
53+
comment */
54+
var x = 10;";
55+
VerifyParsingCompletes(sourceCode, _csharp!);
56+
57+
var result = Parse(sourceCode, _csharp!);
58+
Assert.IsNotNull(result);
59+
}
60+
61+
[TestMethod]
62+
public void ParseUnclosedMultiLineComment_DoesNotHang()
63+
{
64+
// This is critical for ReDoS prevention
65+
var sourceCode = @"/* This comment is not closed
66+
var x = 10;
67+
" + new string('x', 10000); // Large content
68+
69+
VerifyParsingCompletes(sourceCode, _csharp!, timeoutMs: 2000);
70+
}
71+
72+
[TestMethod]
73+
public void ParseXmlDocComment()
74+
{
75+
var sourceCode = @"/// <summary>
76+
/// This is a method
77+
/// </summary>
78+
/// <param name=""value"">A value</param>
79+
public void MyMethod(int value)
80+
{
81+
}";
82+
VerifyParsingCompletes(sourceCode, _csharp!);
83+
84+
var result = Parse(sourceCode, _csharp!);
85+
Assert.IsNotNull(result);
86+
}
87+
88+
[TestMethod]
89+
public void ParseStrings()
90+
{
91+
var sourceCode = @"var str1 = ""Normal string"";
92+
var str2 = @""Verbatim string"";
93+
var str3 = ""String with \""escaped quotes\"""";";
94+
VerifyParsingCompletes(sourceCode, _csharp!);
95+
96+
var result = Parse(sourceCode, _csharp!);
97+
Assert.IsNotNull(result);
98+
}
99+
100+
[TestMethod]
101+
public void ParseNamespaceAndUsings()
102+
{
103+
var sourceCode = @"using System;
104+
using System.Collections.Generic;
105+
106+
namespace MyNamespace
107+
{
108+
public class MyClass { }
109+
}";
110+
VerifyParsingCompletes(sourceCode, _csharp!);
111+
112+
var result = Parse(sourceCode, _csharp!);
113+
Assert.IsNotNull(result);
114+
}
115+
116+
[TestMethod]
117+
public void ParseGenericTypes()
118+
{
119+
var sourceCode = @"var list = new List<string>();
120+
var dict = new Dictionary<string, int>();
121+
public void Method<T>(T value) { }";
122+
VerifyParsingCompletes(sourceCode, _csharp!);
123+
124+
var result = Parse(sourceCode, _csharp!);
125+
Assert.IsNotNull(result);
126+
}
127+
128+
[TestMethod]
129+
public void ParseComplexCSharpCode()
130+
{
131+
var sourceCode = @"using System;
132+
133+
namespace EasyDocs.Core
134+
{
135+
/// <summary>
136+
/// Main application class
137+
/// </summary>
138+
public class Application
139+
{
140+
/* Initialize the application */
141+
public Application()
142+
{
143+
// Constructor code
144+
}
145+
146+
/// <param name=""args"">Command line arguments</param>
147+
public void Run(string[] args)
148+
{
149+
foreach (var arg in args)
150+
{
151+
Console.WriteLine(arg);
152+
}
153+
}
154+
}
155+
}";
156+
VerifyParsingCompletes(sourceCode, _csharp!);
157+
158+
var result = Parse(sourceCode, _csharp!);
159+
Assert.IsNotNull(result);
160+
}
161+
162+
[TestMethod]
163+
public void HasCorrectAlias()
164+
{
165+
Assert.IsTrue(_csharp!.HasAlias("cs"));
166+
Assert.IsTrue(_csharp!.HasAlias("c#"));
167+
Assert.IsTrue(_csharp!.HasAlias("csharp"));
168+
Assert.IsTrue(_csharp!.HasAlias("cake"));
169+
Assert.IsFalse(_csharp!.HasAlias("java"));
170+
}
171+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project Sdk="Microsoft.NET.Sdk">
3+
<PropertyGroup>
4+
<TargetFramework>net10.0</TargetFramework>
5+
<IsTestProject>true</IsTestProject>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
</PropertyGroup>
9+
10+
<ItemGroup>
11+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.1" />
12+
<PackageReference Include="MSTest.TestAdapter" Version="3.1.1" />
13+
<PackageReference Include="MSTest.TestFramework" Version="3.1.1" />
14+
</ItemGroup>
15+
16+
<ItemGroup>
17+
<ProjectReference Include="..\ColorCode.Core\ColorCode.Core.csproj" />
18+
</ItemGroup>
19+
20+
</Project>

0 commit comments

Comments
 (0)