Skip to content

Commit 41f2f88

Browse files
authored
Merge pull request #503 from plotly/C#-refactor
C# refactor
2 parents bca20de + 13941d4 commit 41f2f88

186 files changed

Lines changed: 12262 additions & 8073 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.claude/settings.local.json‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"permissions": {
3+
"allow": [
4+
"Bash(dotnet fsi *)",
5+
"Bash(./build.cmd RunCSharpTestsFast)",
6+
"Bash(./build.cmd Build)"
7+
]
8+
}
9+
}
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
---
2+
name: chart-baseline-generation
3+
description: Use when working in Plotly.NET tests and you need to generate or refresh expected chart output values from real chart rendering instead of inventing assertion strings. This skill helps produce candidate data/layout/html baselines, extract stable segments, and convert investigated output into test expectations.
4+
---
5+
6+
# Chart Baseline Generation
7+
8+
Use this skill when a Plotly.NET test needs an expected string derived from actual chart output.
9+
10+
## Goal
11+
12+
Generate the real chart output first, inspect it, then copy only the stable part into the test as the expected value.
13+
14+
Do not hand-write large expected strings from memory.
15+
16+
## Prerequisites: build the dependency first
17+
18+
The script loads Plotly.NET assemblies from `tests/ConsoleApps/CSharpConsole/bin/Debug/net10.0/`. Before running the script, verify that directory contains `Plotly.NET.dll` and `Plotly.NET.CSharp.dll`. If it is empty or the DLLs are missing, build them first via the FAKE pipeline:
19+
20+
```powershell
21+
./build.cmd Build
22+
```
23+
24+
Any of the `Run*TestsFast` targets also produce these assemblies as a side effect, so if you are about to run tests anyway you can skip the explicit build step.
25+
26+
If you edit sources in `src/Plotly.NET` or `src/Plotly.NET.CSharp` during the investigation, rebuild before re-running the script — `dotnet fsi` caches nothing for you here and stale DLLs silently produce wrong baselines.
27+
28+
## Default workflow
29+
30+
1. Ensure the dependency DLLs exist (see Prerequisites above); build them if missing.
31+
2. Identify the chart fixture or chart-construction expression you want to validate.
32+
3. Prefer an existing fixture from `tests/Common/FSharpTestBase/TestCharts/`.
33+
4. If there is no suitable fixture, put a temporary focused chart expression into `tools/chart-baseline-generation/generate-chart-markup.fsx`.
34+
5. Always use that script for both F# tests and C# tests.
35+
6. For C# wrapper baselines, call `Plotly.NET.CSharp.Chart...` inside the F# script.
36+
7. Keep `UseDefaults = false` on the chart to avoid noisy default template output.
37+
8. Generate output with the same renderer the test uses:
38+
- `GenericChart.toChartHTML` for shared chart html
39+
- `GenericChart.toEmbeddedHTML` when the test is specifically about embedded output
40+
9. Let the script print the stable sections you care about directly: `data`, `layout`, `config`, or `plotly-call`.
41+
10. Inspect the generated section output and decide which part is stable enough to assert.
42+
11. Copy the investigated value into the test.
43+
12. Delete any temporary helper code before finishing.
44+
45+
## Where to generate output
46+
47+
Always use `tools/chart-baseline-generation/generate-chart-markup.fsx` as the investigation harness. Do not create or edit console app projects for this workflow.
48+
49+
Edit `createChart()` in `tools/chart-baseline-generation/generate-chart-markup.fsx`, run the script for the section you need, inspect the generated output, then revert the temporary chart expression when finished.
50+
51+
## How to run the script
52+
53+
Examples:
54+
55+
```powershell
56+
dotnet fsi tools/chart-baseline-generation/generate-chart-markup.fsx
57+
dotnet fsi tools/chart-baseline-generation/generate-chart-markup.fsx -- data
58+
dotnet fsi tools/chart-baseline-generation/generate-chart-markup.fsx -- layout
59+
dotnet fsi tools/chart-baseline-generation/generate-chart-markup.fsx -- html
60+
dotnet fsi tools/chart-baseline-generation/generate-chart-markup.fsx -- data --write-html temp/chart.html
61+
```
62+
63+
By default, the script prints extracted stable sections to stdout and does not create temporary files.
64+
65+
Use `--write-html <output-path>` only when you explicitly want the full generated html on disk.
66+
67+
Pick the smallest local loop that matches the test you are editing:
68+
69+
- C# wrapper tests: `./build.cmd RunCSharpTestsFast`
70+
- Core F# tests: `./build.cmd RunTestsCoreFast`
71+
- Extension library tests: `./build.cmd RunTestsExtensionLibsFast`
72+
73+
Use the full `./build.cmd runTestsAll` before committing.
74+
75+
## Recommended temporary pattern
76+
77+
For a one-off investigation, edit `tools/chart-baseline-generation/generate-chart-markup.fsx` so it generates the chart you need, then run the script with the section you want to inspect.
78+
79+
Prefer temporary F# script code like:
80+
81+
```fsharp
82+
let html = GenericChart.toChartHTML chart
83+
```
84+
85+
For C# wrapper baselines, still use the same script and create the chart with `Plotly.NET.CSharp.Chart...`, then render it with:
86+
87+
```fsharp
88+
let html = GenericChart.toChartHTML chart
89+
```
90+
91+
Do not leave exploratory printouts or file dumps in committed script code.
92+
93+
Do not create extra helper files for this workflow unless there is a strong reason. Prefer modifying `tools/chart-baseline-generation/generate-chart-markup.fsx` directly and then reverting the temporary code.
94+
95+
## What to assert
96+
97+
Prefer the smallest stable assertion that proves the behavior:
98+
99+
- full `var data = ...;` block when validating trace serialization
100+
- full `var layout = ...;` block when validating layout generation
101+
- a small but meaningful substring only when the full block is too brittle
102+
103+
Avoid asserting volatile values such as generated DOM ids.
104+
105+
The unified script can print sections by label:
106+
107+
- `data`
108+
- `layout`
109+
- `config`
110+
- `plotly-call`
111+
112+
## Investigation rules
113+
114+
- Treat generated output as a candidate baseline, not automatically correct truth.
115+
- Compare the output with the API intent and nearby F# tests before adopting it.
116+
- If the output looks surprising, stop and investigate the chart construction rather than locking in a wrong baseline.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
#load "../../../../tools/chart-baseline-generation/generate-chart-markup.fsx"
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
---
2+
name: chart-baseline-generation
3+
description: Use when working in Plotly.NET tests and you need to generate or refresh expected chart output values from real chart rendering instead of inventing assertion strings. This skill helps agents produce candidate data/layout/html baselines, extract stable segments, and convert investigated output into test expectations.
4+
---
5+
6+
# Chart Baseline Generation
7+
8+
Use this skill when a Plotly.NET test needs an expected string derived from actual chart output.
9+
10+
## Goal
11+
12+
Generate the real chart output first, inspect it, then copy only the stable part into the test as the expected value.
13+
14+
Do not hand-write large expected strings from memory.
15+
16+
## Prerequisites: build the dependency first
17+
18+
The script loads Plotly.NET assemblies from `tests/ConsoleApps/CSharpConsole/bin/Debug/net10.0/`. Before running the script, verify that directory contains `Plotly.NET.dll` and `Plotly.NET.CSharp.dll`. If it is empty or the DLLs are missing, build them first via the FAKE pipeline:
19+
20+
```powershell
21+
./build.cmd Build
22+
```
23+
24+
Any of the `Run*TestsFast` targets also produce these assemblies as a side effect, so if you are about to run tests anyway you can skip the explicit build step.
25+
26+
If you edit sources in `src/Plotly.NET` or `src/Plotly.NET.CSharp` during the investigation, rebuild before re-running the script — `dotnet fsi` caches nothing for you here and stale DLLs silently produce wrong baselines.
27+
28+
## Default workflow
29+
30+
1. Ensure the dependency DLLs exist (see Prerequisites above); build them if missing.
31+
2. Identify the chart fixture or chart-construction expression you want to validate.
32+
3. Prefer an existing fixture from `tests/Common/FSharpTestBase/TestCharts/`.
33+
4. If there is no suitable fixture, put a temporary focused chart expression into `tools/chart-baseline-generation/generate-chart-markup.fsx`.
34+
5. Always use that script for both F# tests and C# tests.
35+
6. For C# wrapper baselines, call `Plotly.NET.CSharp.Chart...` inside the F# script.
36+
7. Keep `UseDefaults = false` on the chart to avoid noisy default template output.
37+
8. Generate output with the same renderer the test uses:
38+
- `GenericChart.toChartHTML` for shared chart html
39+
- `GenericChart.toEmbeddedHTML` when the test is specifically about embedded output
40+
9. Let the script print the stable sections you care about directly: `data`, `layout`, `config`, or `plotly-call`.
41+
10. Inspect the generated section output and decide which part is stable enough to assert.
42+
11. Copy the investigated value into the test.
43+
12. Delete any temporary helper code before finishing.
44+
45+
## Where to generate output
46+
47+
Always use `tools/chart-baseline-generation/generate-chart-markup.fsx` as the investigation harness. Do not create or edit console app projects for this workflow.
48+
49+
Edit `createChart()` in `tools/chart-baseline-generation/generate-chart-markup.fsx`, run the script for the section you need, inspect the generated output, then revert the temporary chart expression when finished.
50+
51+
## How to run the script
52+
53+
Examples:
54+
55+
```powershell
56+
dotnet fsi tools/chart-baseline-generation/generate-chart-markup.fsx
57+
dotnet fsi tools/chart-baseline-generation/generate-chart-markup.fsx -- data
58+
dotnet fsi tools/chart-baseline-generation/generate-chart-markup.fsx -- layout
59+
dotnet fsi tools/chart-baseline-generation/generate-chart-markup.fsx -- html
60+
dotnet fsi tools/chart-baseline-generation/generate-chart-markup.fsx -- data --write-html temp/chart.html
61+
```
62+
63+
By default, the script prints extracted stable sections to stdout and does not create temporary files.
64+
65+
Use `--write-html <output-path>` only when you explicitly want the full generated html on disk.
66+
67+
Pick the smallest local loop that matches the test you are editing:
68+
69+
- C# wrapper tests: `./build.cmd RunCSharpTestsFast`
70+
- Core F# tests: `./build.cmd RunTestsCoreFast`
71+
- Extension library tests: `./build.cmd RunTestsExtensionLibsFast`
72+
73+
Use the full `./build.cmd runTestsAll` before committing.
74+
75+
## Recommended temporary pattern
76+
77+
For a one-off investigation, edit `tools/chart-baseline-generation/generate-chart-markup.fsx` so it generates the chart you need, then run the script with the section you want to inspect.
78+
79+
Prefer temporary F# script code like:
80+
81+
```fsharp
82+
let html = GenericChart.toChartHTML chart
83+
```
84+
85+
For C# wrapper baselines, still use the same script and create the chart with `Plotly.NET.CSharp.Chart...`, then render it with:
86+
87+
```fsharp
88+
let html = GenericChart.toChartHTML chart
89+
```
90+
91+
Do not leave exploratory printouts or file dumps in committed script code.
92+
93+
Do not create extra helper files for this workflow unless there is a strong reason. Prefer modifying `tools/chart-baseline-generation/generate-chart-markup.fsx` directly and then reverting the temporary code.
94+
95+
## What to assert
96+
97+
Prefer the smallest stable assertion that proves the behavior:
98+
99+
- full `var data = ...;` block when validating trace serialization
100+
- full `var layout = ...;` block when validating layout generation
101+
- a small but meaningful substring only when the full block is too brittle
102+
103+
Avoid asserting volatile values such as generated DOM ids.
104+
105+
The unified script can print sections by label:
106+
107+
- `data`
108+
- `layout`
109+
- `config`
110+
- `plotly-call`
111+
112+
## Investigation rules
113+
114+
- Treat generated output as a candidate baseline, not automatically correct truth.
115+
- Compare the output with the API intent and nearby F# tests before adopting it.
116+
- If the output looks surprising, stop and investigate the chart construction rather than locking in a wrong baseline.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
#load "../../../../tools/chart-baseline-generation/generate-chart-markup.fsx"

‎.devcontainer/Dockerfile‎

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Generic devcontainer base; .NET 10 SDK is layered on via the dotnet feature
2+
# in devcontainer.json (the dedicated dotnet:10.0 devcontainer image isn't
3+
# published yet — pinned via global.json rollForward once installed).
4+
FROM mcr.microsoft.com/devcontainers/base:bookworm
5+
6+
# System deps for Plotly.NET.ImageExport tests (PuppeteerSharp downloads its own
7+
# Chromium at runtime, but needs these shared libraries and fonts to launch it).
8+
RUN apt-get update \
9+
&& apt-get install -y --no-install-recommends \
10+
ca-certificates \
11+
fonts-liberation \
12+
libasound2 \
13+
libatk-bridge2.0-0 \
14+
libatk1.0-0 \
15+
libc6 \
16+
libcairo2 \
17+
libcups2 \
18+
libdbus-1-3 \
19+
libdrm2 \
20+
libexpat1 \
21+
libgbm1 \
22+
libglib2.0-0 \
23+
libgtk-3-0 \
24+
libnspr4 \
25+
libnss3 \
26+
libpango-1.0-0 \
27+
libx11-6 \
28+
libx11-xcb1 \
29+
libxcb1 \
30+
libxcomposite1 \
31+
libxdamage1 \
32+
libxext6 \
33+
libxfixes3 \
34+
libxkbcommon0 \
35+
libxrandr2 \
36+
xdg-utils \
37+
&& rm -rf /var/lib/apt/lists/*

‎.devcontainer/devcontainer.json‎

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
{
2+
"name": "Plotly.NET agent sandbox",
3+
"build": {
4+
"dockerfile": "Dockerfile"
5+
},
6+
"features": {
7+
"ghcr.io/devcontainers/features/dotnet:2": {
8+
"version": "10.0",
9+
"installUsingApt": false
10+
},
11+
"ghcr.io/devcontainers/features/node:1": {
12+
"version": "lts"
13+
},
14+
"ghcr.io/devcontainers/features/github-cli:1": {}
15+
},
16+
"remoteUser": "vscode",
17+
"containerEnv": {
18+
"DOTNET_CLI_TELEMETRY_OPTOUT": "1",
19+
"DOTNET_NOLOGO": "1",
20+
"NUGET_XMLDOC_MODE": "skip",
21+
"PUPPETEER_SKIP_CHROMIUM_DOWNLOAD": "true"
22+
},
23+
"postCreateCommand": "bash .devcontainer/postCreate.sh",
24+
"mounts": [
25+
"source=${localEnv:HOME}${localEnv:USERPROFILE}/.claude,target=/home/vscode/.claude,type=bind,consistency=cached",
26+
"source=${localEnv:HOME}${localEnv:USERPROFILE}/.claude.json,target=/home/vscode/.claude.json,type=bind,consistency=cached",
27+
"source=${localEnv:HOME}${localEnv:USERPROFILE}/.codex,target=/home/vscode/.codex,type=bind,consistency=cached"
28+
],
29+
"customizations": {
30+
"vscode": {
31+
"extensions": [
32+
"ms-dotnettools.csdevkit",
33+
"ionide.ionide-fsharp",
34+
"anthropic.claude-code",
35+
"openai.chatgpt"
36+
]
37+
}
38+
}
39+
}

‎.devcontainer/postCreate.sh‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
echo "==> Restoring dotnet local tools (fantomas, fsdocs)"
5+
dotnet tool restore
6+
7+
echo "==> Warming up NuGet restore for the main solution"
8+
dotnet restore Plotly.NET.sln || true
9+
10+
echo "==> Installing agent CLIs globally (Claude Code + Codex)"
11+
npm install -g \
12+
@anthropic-ai/claude-code \
13+
@openai/codex \
14+
opencode-ai@latest
15+
16+
echo "==> Aliasing agent CLIs to skip approvals (sandbox is the devcontainer itself)"
17+
cat >> ~/.bashrc <<'EOF'
18+
19+
# devcontainer: agent CLIs skip approvals since the container IS the sandbox
20+
alias claude='claude --dangerously-skip-permissions'
21+
alias codex='codex --dangerously-bypass-approvals-and-sandbox'
22+
EOF
23+
24+
chmod +x build.sh
25+
26+
echo "==> Done. Verify with:"
27+
echo " ./build.sh # default build target"
28+
echo " ./build.sh RunTestsAllFast"
29+
echo " claude --version"
30+
echo " codex --version"

0 commit comments

Comments
 (0)