Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
196 changes: 196 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
# AngleSharp.Diffing - HTML Comparison Library

AngleSharp.Diffing is a .NET library for comparing AngleSharp control nodes and test nodes to identify differences between HTML DOM trees. This library targets .NET Standard 2.0 and provides a fluent API for HTML comparison and diffing.

**Always reference these instructions first and fallback to search or bash commands only when you encounter unexpected information that does not match the info here.**

## Working Effectively

### Prerequisites and Setup
- Install .NET 8.0+ SDK (already available in GitHub Actions environments)
- Mono is NOT required for standard development (only for legacy Cake build system)

### Bootstrap, Build, and Test
Execute these commands in order from the repository root:

```bash
cd src
dotnet restore # ~11 seconds - restores NuGet packages
dotnet build # ~15 seconds - compiles library and tests
dotnet test # ~5 seconds - runs 521 tests. NEVER CANCEL.
```

**CRITICAL TIMING EXPECTATIONS:**
- `dotnet restore`: 11 seconds - NEVER CANCEL. Set timeout to 60+ seconds minimum.
- `dotnet build`: 15 seconds - NEVER CANCEL. Set timeout to 60+ seconds minimum.
- `dotnet test`: 5 seconds - runs 521 tests. NEVER CANCEL. Set timeout to 30+ seconds minimum.
- Complete clean rebuild: ~20 seconds - NEVER CANCEL. Set timeout to 60+ seconds minimum.

### Alternative Build Methods
**PRIMARY METHOD (Recommended):** Use dotnet CLI commands as shown above.

**LEGACY METHOD (Not Recommended):** The repository includes Cake build scripts (`build.sh`/`build.ps1`) but they require Mono and may fail. Only use if specifically needed:
```bash
# Install Mono first (if needed)
sudo apt-get update && sudo apt-get install -y mono-complete
./build.sh # May fail - use dotnet commands instead
```

### Release Builds and Packaging
```bash
cd src
dotnet build --configuration Release # ~15 seconds
dotnet pack --configuration Release # ~8 seconds - creates NuGet packages
```

**Package Output:** Creates `.nupkg` and `.snupkg` files in `src/AngleSharp.Diffing/bin/Release/`

## Validation and Testing

### Manual Validation Requirements
**ALWAYS** validate changes by creating and running a test program to exercise the library:

```csharp
using AngleSharp.Diffing;

// Test basic HTML diffing functionality
var control = @"<p attr=""foo"">hello <em>world</em></p>";
var test = @"<p attr=""bar"">hello <strong>world</strong></p>";

var diffs = DiffBuilder
.Compare(control)
.WithTest(test)
.Build()
.ToList();

Console.WriteLine($"Found {diffs.Count} differences:");
foreach (var diff in diffs)
{
Console.WriteLine($"- {diff.GetType().Name}: {diff.Result} {diff.Target}");
}
```

### Code Quality and Standards
- **Code Analysis:** Project has strict analysis rules enabled (`EnforceCodeStyleInBuild=true`)
- **EditorConfig:** Follow the existing `.editorconfig` settings (4-space indentation, CRLF line endings)
- **Nullable References:** Enabled - handle null values appropriately
- **Build Warnings:** Zero warnings expected - treat warnings as errors for critical types

### Test Suite Information
- **Test Framework:** xUnit with Shouldly assertions
- **Test Count:** 521 tests covering core diffing functionality
- **Test Runtime:** ~5 seconds total
- **Test Files Location:** `src/AngleSharp.Diffing.Tests/`

## Navigation and Architecture

### Key Directories and Files
```
src/
├── AngleSharp.Diffing/ # Main library project
│ ├── Core/ # Core diffing engine and interfaces
│ ├── Extensions/ # Extension methods
│ ├── Strategies/ # Diffing strategy implementations
│ └── DiffBuilder.cs # Main fluent API entry point
├── AngleSharp.Diffing.Tests/ # Test project
│ ├── Core/ # Core functionality tests
│ └── Strategies/ # Strategy-specific tests
└── AngleSharp.Diffing.sln # Solution file
```

### Important Classes and APIs
- **`DiffBuilder`**: Main entry point with fluent API (`DiffBuilder.Compare(control).WithTest(test).Build()`)
- **`IDiff`**: Base interface for all difference types
- **`HtmlDifferenceEngine`**: Core comparison engine
- **Diff Types**: `AttrDiff`, `NodeDiff`, `MissingNodeDiff`, `UnexpectedNodeDiff`, etc.

### Dependencies
- **AngleSharp 1.1.2**: Core HTML parsing library
- **AngleSharp.Css 1.0.0-beta.144**: CSS support
- **Target Framework**: .NET Standard 2.0 (library), .NET 8.0 (tests)

## Common Development Tasks

### Making Code Changes
1. **Always build and test first** to establish baseline: `dotnet build && dotnet test`
2. Make your changes to source files in `src/AngleSharp.Diffing/`
3. **Immediately test after changes**: `dotnet build && dotnet test`
4. **Manual validation**: Create a test program to exercise your changes
5. **Pre-commit validation**: Ensure no build warnings or test failures

### Debugging and Investigation
- **Test filtering**: `dotnet test --filter "TestMethodName"` to run specific tests
- **Verbose builds**: `dotnet build --verbosity normal` to see detailed output
- **Key test files**: `DiffBuilderTest.cs` shows basic API usage patterns

### CI/Build Requirements
- **GitHub Actions**: Runs on both Linux and Windows
- **Zero warnings policy**: Build must complete without warnings
- **All tests must pass**: 521/521 tests required
- **Code formatting**: Enforced via EditorConfig and analyzers

## Getting Started Examples

### Basic HTML Comparison
```csharp
var control = "<p>Expected content</p>";
var test = "<p>Actual content</p>";

var diffs = DiffBuilder
.Compare(control)
.WithTest(test)
.Build();
```

### Advanced Configuration
```csharp
var diffs = DiffBuilder
.Compare(control)
.WithTest(test)
.WithOptions(options => {
// Configure diffing strategies
})
.Build();
```

### Working with Results
```csharp
foreach (var diff in diffs)
{
switch (diff.Result)
{
case DiffResult.Different:
case DiffResult.Missing:
case DiffResult.Unexpected:
// Handle different types of differences
break;
}
}
```

## Troubleshooting

### Common Issues
- **Build failures**: Ensure you're in the `src/` directory
- **Cake build failures**: Use `dotnet` commands instead of `build.sh`/`build.ps1`
- **Test failures**: Check for environment-specific issues or recent changes
- **Package restore issues**: Clear NuGet caches with `dotnet nuget locals all --clear`

### Quick Reset Commands
```bash
# Clean and rebuild everything
cd src
dotnet clean
rm -rf */bin */obj
dotnet restore
dotnet build
dotnet test
```

## Performance Expectations
- **Development builds**: ~15 seconds
- **Test execution**: ~5 seconds for full suite
- **Package creation**: ~8 seconds
- **CI builds**: Allow 60+ seconds timeout minimum for each step

**CRITICAL**: NEVER CANCEL builds or tests that appear slow. Wait at least 60 seconds for builds and 30 seconds for tests before considering alternatives.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4

- name: Build
run: ./build.sh
Expand All @@ -20,7 +20,7 @@ jobs:
runs-on: windows-latest

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4

- name: Build
run: |
Expand Down
9 changes: 8 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ PublishScripts/

# NuGet Packages
*.nupkg
nupkgs/
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
Expand Down Expand Up @@ -346,4 +347,10 @@ ASALocalRun/
# BeatPulse healthcheck temp database
healthchecksdb

*.ncrunchsolution
*.ncrunchsolution

# Nuke build artifacts
.nuke/temp/
bin/
nuke/bin/
nuke/obj/
134 changes: 134 additions & 0 deletions .nuke/build.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"definitions": {
"Host": {
"type": "string",
"enum": [
"AppVeyor",
"AzurePipelines",
"Bamboo",
"Bitbucket",
"Bitrise",
"GitHubActions",
"GitLab",
"Jenkins",
"Rider",
"SpaceAutomation",
"TeamCity",
"Terminal",
"TravisCI",
"VisualStudio",
"VSCode"
]
},
"ExecutableTarget": {
"type": "string",
"enum": [
"Clean",
"Compile",
"CreatePackage",
"Default",
"Package",
"PrePublish",
"Publish",
"PublishPackage",
"PublishPreRelease",
"PublishRelease",
"Restore",
"RunUnitTests"
]
},
"Verbosity": {
"type": "string",
"description": "",
"enum": [
"Verbose",
"Normal",
"Minimal",
"Quiet"
]
},
"NukeBuild": {
"properties": {
"Continue": {
"type": "boolean",
"description": "Indicates to continue a previously failed build attempt"
},
"Help": {
"type": "boolean",
"description": "Shows the help text for this build assembly"
},
"Host": {
"description": "Host for execution. Default is 'automatic'",
"$ref": "#/definitions/Host"
},
"NoLogo": {
"type": "boolean",
"description": "Disables displaying the NUKE logo"
},
"Partition": {
"type": "string",
"description": "Partition to use on CI"
},
"Plan": {
"type": "boolean",
"description": "Shows the execution plan (HTML)"
},
"Profile": {
"type": "array",
"description": "Defines the profiles to load",
"items": {
"type": "string"
}
},
"Root": {
"type": "string",
"description": "Root directory during build execution"
},
"Skip": {
"type": "array",
"description": "List of targets to be skipped. Empty list skips all dependencies",
"items": {
"$ref": "#/definitions/ExecutableTarget"
}
},
"Target": {
"type": "array",
"description": "List of targets to be invoked. Default is '{default_target}'",
"items": {
"$ref": "#/definitions/ExecutableTarget"
}
},
"Verbosity": {
"description": "Logging verbosity during build execution. Default is 'Normal'",
"$ref": "#/definitions/Verbosity"
}
}
}
},
"allOf": [
{
"properties": {
"Configuration": {
"type": "string",
"description": "Configuration to build - Default is 'Debug' (local) or 'Release' (server)",
"enum": [
"Debug",
"Release"
]
},
"ReleaseNotesFilePath": {
"type": "string",
"description": "ReleaseNotesFilePath - To determine the SemanticVersion"
},
"Solution": {
"type": "string",
"description": "Path to a solution file that is automatically loaded"
}
}
},
{
"$ref": "#/definitions/NukeBuild"
}
]
}
4 changes: 4 additions & 0 deletions .nuke/parameters.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"$schema": "./build.schema.json",
"Solution": "src/AngleSharp.Diffing.sln"
}
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# 1.1.0

- An ':ignore' marked attributes will no longer show up as a diff if the ignored attribute was NOT found in the test html. By [@RiRiSharp](https://github.com/RiRiSharp).

# 1.0.0

- Enabled using `diff:ignoreAttributes` and `diff:ignoreChildren` together on the same element.
Expand Down
11 changes: 0 additions & 11 deletions build.cake

This file was deleted.

Loading
Loading