diff --git a/.claude/skills/tableau-release-html/SKILL.md b/.claude/skills/tableau-release-html/SKILL.md new file mode 100644 index 000000000..4dae5e350 --- /dev/null +++ b/.claude/skills/tableau-release-html/SKILL.md @@ -0,0 +1,287 @@ +--- +name: tableau-release-html +description: > + Generate a complete, beautiful styled HTML release notes page for a Tableau Go library + release (github.com/tableauio/tableau). Produces a self-contained light-theme HTML file + with sticky nav, animated hero, semantic color sections (Features / Bug Fixes / Breaking / + Deprecated / Dependencies / Examples), GitHub-light code blocks, Excel spreadsheet demo + tables, and scroll-reveal animations. Use this skill whenever the user asks to generate, + create, or update a Tableau release page, release notes HTML, or release poster — + even if they just say "make the release page for v0.17.0" or "new release, same style". +--- + +# Tableau Release HTML Generator + +Produce a polished, self-contained HTML release notes page for a Tableau Go library release. +Everything you need is inside this skill — read `references/design-system.md` (bundled here) +for the complete CSS block and all component HTML patterns before writing any code. + +--- + +## Step 1 — Gather release content + +If the user hasn't provided details, ask for (or infer from the GitHub releases page): + +| Field | Example | +|-------|---------| +| Version | `v0.17.0` | +| Release date | `July 15, 2026` | +| Features | List of titles + short descriptions + key proto/YAML snippets | +| Bug fixes | List of short fix descriptions (9–15 typical) | +| Breaking changes | Items requiring migration, with before/after code | +| Deprecated items | Anything deprecated, with notes | +| Dependency updates | Package name + old version → new version | +| Spreadsheet examples | Excel-style demos for key features | + +You can also read the GitHub release tag using `gh release view vX.Y.Z --repo tableauio/tableau` +or inspect commit history to fill in details automatically. + +--- + +## Step 2 — Plan the sections + +Standard section order (omit sections with no content): + +``` +01 New Features green (#16a34a) +02 Bug Fixes blue (#2563eb) +03 Breaking Changes red (#dc2626) +04 Deprecated amber (#d97706) +05 Dependency Updates slate (#6b7280) +06 Spreadsheet Examples violet (#7c3aed) +``` + +--- + +## Step 3 — Generate the HTML + +Output a single self-contained HTML file named `release-vX.Y.Z-light.html`. + +Read `references/design-system.md` now for the complete CSS block and component HTML patterns +before writing any code. This is critical — the classes, colors, and structures must match +exactly for the page to look correct. + +### Page skeleton + +```html + + +
+ + +Description…
+ +Fix title
+Brief description.
+Description…
+ +` with literal newlines** (one source line per line). Do NOT use one inline `` per line — Prettier and other formatters collapse whitespace inside `` flow content but preserve it inside ``, so this is the only formatter-proof pattern. Long lines must scroll horizontally inside the block (CSS already sets `overflow-x: auto` on `.code-blk-bd > pre`); never let long lines wrap or push the surrounding card wider.
+
+```html
+
+ ▸ filename.go
+ // comment
+func Example() error {
+ // highlighted new line
+}
+
+```
+
+The same rule applies to `.demo-out-bd` blocks: wrap content in `...
`.
+
+**Important.** The `` open and close tags MUST sit immediately adjacent to their content — no whitespace between `` and the first character, no whitespace between the last character and ``. The very first character after `` becomes column 0; any leading newline or indent will show up as a blank line in the rendered output.
+Syntax color classes: `c-key` (red `#cf222e`), `c-str` (dark blue `#0a3069`), `c-typ` (brown `#953800`), `c-ann` (purple `#8250df`), `c-num` (blue `#0550ae`), `c-val` (green `#116329`), `c-fld` (default `#24292f`), `c-com` (grey `#6e7781`).
+Highlight classes: `c-hl` (green bg, good), `c-warn` (yellow bg, caution), `c-add` (green line), `c-del` (red line).
+
+**Excel spreadsheet tables** — always use 3-header-row convention:
+```html
+▸ SheetName.xlsx — SheetTab
+
+
+
+
+ A B C
+
+
+ 1 FieldName ...
+ 2 map<uint32,Msg> ...
+ 3 Note text ...
+ 4 1 ...
+ 5 ...
+
+
+
+```
+
+**Footer**:
+```html
+
+```
+
+**Scroll-reveal script** — include verbatim at bottom of ``:
+```html
+
+```
+
+---
+
+## Step 4 — Output
+
+Save the file as `release-vX.Y.Z-light.html` in the current working directory (or wherever
+the user specifies — ask if unclear).
+
+After writing, take a Playwright screenshot to verify the rendered look. Locate `node_modules/playwright`
+in the project directory and adapt the paths accordingly:
+```js
+const {chromium} = require('playwright'); // or path to local node_modules
+(async () => {
+ const browser = await chromium.launch();
+ const page = await browser.newPage();
+ await page.setViewportSize({width:1440, height:900});
+ await page.goto('file://').catch(()=>{});
+ await page.waitForTimeout(2800);
+ await page.screenshot({path:'preview-vX.Y.Z.png', fullPage:false});
+ await browser.close();
+})();
+```
+
+Show the screenshot to the user and ask if any changes are needed.
+
+---
+
+## Design system quick reference
+
+See `references/design-system.md` for:
+- Complete `
+```
+
+---
+
+## Semantic color matrix
+
+### Sections
+
+The `sec-num` AND `sec-title` of every section MUST be set to the accent colour below — the same colour as the section's matching tag. Title left at the default dark is a bug.
+
+| Section | Number | CSS class | `sec-num` + `sec-title` colour |
+|---------|--------|-----------|--------------------------------|
+| New Features | 01 | `sec-feat` | `#16a34a` (green) |
+| Bug Fixes | 02 | `sec-fix` | `#1d4ed8` (deep blue — readable on the light-blue background) |
+| Breaking Changes | 03 | `sec-break` | `#dc2626` (red, or `#b91c1c` for slightly darker) |
+| Deprecated | 04 | `sec-dep` | `#d97706` (amber, or `#92400e` for darker) |
+| Dependencies | 05 | `sec-white-next-gray` | `#6b7280` (slate) — body title may use `#374151` for contrast |
+| Examples | 06 | `sec-gray` | `#7c3aed` (violet) |
+
+### Tags (`.tag` base class)
+| Class | Use |
+|-------|-----|
+| `tag-new` / `tag-option` | New feature, new option — green |
+| `tag-breaking` | Breaking change — red |
+| `tag-tooling` | Tooling / parser / generator — blue |
+| `tag-enhanced` | Enhancement / improvement — violet |
+| `tag-arch` | Architecture / config — amber |
+
+### Stat chips (`.stat-chip` base class)
+| Class | Use |
+|-------|-----|
+| `chip-green` | Feature count |
+| `chip-blue` | Bug fix count |
+| `chip-amber` | Breaking change count (red theme) |
+| `chip-violet` | Deprecated count (amber theme) |
+
+### Demo badges (`.demo-badge` base class)
+| Class | Use |
+|-------|-----|
+| `db-new` | New feature demo — green |
+| `db-fix` | Bug fix demo — blue |
+| `db-breaking` | Breaking change demo — red |
+| `db-dep` | Deprecated demo — amber |
+
+---
+
+## GitHub icon SVG (for nav)
+
+```html
+
+
+
+```
+
+---
+
+## Hero decorative spreadsheet (copy as-is, update cell content for the release)
+
+```html
+
+
+
+
+
+ A B C D E F G
+
+
+
+
+ 1
+ ID Name Level HP Attack Type Validate
+
+
+ 2
+ map<uint32,Hero> string int32 int32 int32 enum<HeroType> string|{validate:...
+
+
+ 3
+ Hero ID Hero name Hero level Max HP Base attack Hero class CEL rule
+
+
+ 4 1 Arthur 50 500 120 warrior
+
+
+ 5 2 Merlin 45 380 90 mage
+
+
+ 6 3 Lancelot 55 620 150 knight
+
+
+
+
+```
+
+---
+
+## Tableau protobuf type system quick reference
+
+Row 2 of every Excel table uses these type strings:
+
+| Type string | Meaning |
+|-------------|---------|
+| `map` | Map keyed by uint32, value is MsgName proto |
+| `[MsgName]` | Repeated/list of MsgName |
+| `[]{.MsgName}` | Horizontal list struct (union) |
+| `string` / `int32` / `bool` / `float` | Scalar proto types |
+| `enum` | Enum reference |
+| `string\|{validate:"rule"}` | Scalar + CEL validation prop |
+| `string\|{validate_complex:"rule"}` | Complex CEL validation |
+| `uint32\|{key:true}` | Primary key field |
+| `uint32\|{optional:true}` | Optional field |
+| `uint32\|{refer:"Sheet.Field"}` | Cross-sheet reference |
diff --git a/CLAUDE.md b/CLAUDE.md
index b603e81b5..7ed30cb97 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -66,3 +66,51 @@ SCSS lives in `assets/scss/` (entry `app.scss`); JS in `assets/js/` (entry `inde
**GitHub Pages** (see `.github/workflows/deploy-github.yml`) — on push to `master`, runs `npm install`, `npm run lint:markdown`, `npm run build`, then publishes `./public` via `peaceiris/actions-gh-pages@v3`. CI pins Node 24.
Treat upstream Doks files (delivered via `node_modules/@hyas/doks`) as read-only; override by creating same-path files in this repo's `layouts/`, `assets/`, etc.
+
+## Adding a release page
+
+The Release section (`/release/`) lists release entries from `content//release/` as Bootstrap cards. Each entry is a `.md` page; the iframe field in front-matter determines whether it renders the markdown body or embeds a standalone HTML report.
+
+### Two flavors
+
+**Markdown release** — author release notes as plain Hugo markdown:
+
+1. Create `content/en/release/.md` and `content/zh/release/.md` with parallel content.
+2. Use the same front-matter shape as `docs/` (`title`, `description`, `lead`, `date`, `lastmod`, `weight`, `toc`, …).
+3. The page renders in the blog-style centered article layout with an optional right-side TOC.
+
+**HTML release** — embed a pre-built standalone HTML report:
+
+1. Place the artifact at `static/release/.html`. It is served as-is at `/release/.html` (no theme wrapping). For multi-repo disambiguation (e.g., the `loader` repo and the `tableau` repo can both reach v0.6.0), prefix the slug with the repo name: `loader-v0-6-0.html`, `tableau-v0-16-0.html`.
+2. Inside the artifact, wrap the brand link with `target="_top"` so navigation escapes the iframe.
+3. Create stub markdown files `content/en/release/.md` and `content/zh/release/.md` with the docs front-matter plus an extra field:
+
+ ```yaml
+ ---
+ title: "Loader v0.6.0"
+ description: "Loader v0.6.0 release report."
+ lead: "One-line summary of the headline features."
+ date: 2026-06-11T04:17:48+00:00
+ lastmod: 2026-06-11T04:17:48+00:00
+ draft: false
+ images: []
+ weight: 1610
+ toc: false
+ iframe: "/release/loader-v0-6-0.html"
+ ---
+ ```
+
+ The body is empty; the iframe renders inside a full-width frame with breadcrumb + open-in-tab + fullscreen-toggle action bar. Reading time on the card is computed by reading the artifact's prose at build time (see `layouts/partials/main/release-meta.html`).
+
+### Generating the HTML report
+
+The `tableau-release-html` skill (in `.claude/skills/tableau-release-html/`) generates the styled standalone HTML for a Tableau-family release from a GitHub release tag. Pipeline:
+
+1. Invoke the skill with the repo + version: `gh release view --repo ` is used internally to fetch the release body.
+2. The skill produces a self-contained HTML file (Inter + JetBrains Mono fonts via Google Fonts CDN, Tailwind via CDN, all CSS inline) following the design system in `.claude/skills/tableau-release-html/references/design-system.md`.
+3. Move the output to `static/release/.html`.
+4. Author the en + zh markdown stubs as above.
+
+### Sort order
+
+The card list uses `weight` ascending — lower weight sorts to the top. Convention: newer releases use lower weights (e.g., v0.16.0 = 1600, v0.15.0 = 1700). For multi-repo entries, choose weights that preserve the desired chronological order across repos.
diff --git a/README.md b/README.md
index abe148a7c..6c27ff94b 100644
--- a/README.md
+++ b/README.md
@@ -46,3 +46,7 @@ assets/js/ # scripts (entry: index.js)
static/ # files served as-is at the URL root
.github/workflows/ # CI: lint + build + GitHub Pages deploy
```
+
+## Skills
+
+- [tableau-release-html](.claude/skills/tableau-release-html)
diff --git a/config/_default/params.toml b/config/_default/params.toml
index be1c379df..07bfef176 100644
--- a/config/_default/params.toml
+++ b/config/_default/params.toml
@@ -10,7 +10,7 @@ description = "Tableau can convert Excel/CSV/XML/YAML to multiple formats: JSON,
# docsVersion = "0.3"
## Tableauc version for download links
-tableaucVersion = "v0.15.1"
+tableaucVersion = "v0.16.0"
## Open Graph
images = ["tableau-logo.svg"]
diff --git a/content/en/docs/basics/enum.md b/content/en/docs/basics/enum.md
index d38d2377a..f64209228 100644
--- a/content/en/docs/basics/enum.md
+++ b/content/en/docs/basics/enum.md
@@ -16,7 +16,7 @@ The tableau parser accepts three enum value forms:
1. enum value **name**.
2. enum value **number**.
- 3. enum value **alias**. It is another name in English, Chinese, or any other language, which can be specified by [tableau.evalue](https://github.com/tableauio/tableau/blob/v0.15.1/proto/tableau/protobuf/tableau.proto#L39) by extending [google.protobuf.EnumValueOptions](https://github.com/protocolbuffers/protobuf/blob/v34.0/src/google/protobuf/descriptor.proto#L904).
+ 3. enum value **alias**. It is another name in English, Chinese, or any other language, which can be specified by [tableau.evalue](https://github.com/tableauio/tableau/blob/v0.16.0/proto/tableau/protobuf/tableau.proto#L39) by extending [google.protobuf.EnumValueOptions](https://github.com/protocolbuffers/protobuf/blob/v34.0/src/google/protobuf/descriptor.proto#L904).
For example, enum type `FruitType` in `common.proto` is defined as:
diff --git a/content/en/release/loader-v0-6-0.md b/content/en/release/loader-v0-6-0.md
new file mode 100644
index 000000000..b5b5138c7
--- /dev/null
+++ b/content/en/release/loader-v0-6-0.md
@@ -0,0 +1,12 @@
+---
+title: "Loader v0.6.0"
+description: "Loader v0.6.0 release report."
+lead: "C# loader plugin, Protobuf Editions (2023/2024) support, cross-language patch system, and a Windows CI overhaul."
+date: 2026-06-11T04:17:48+00:00
+lastmod: 2026-06-11T04:17:48+00:00
+draft: false
+images: []
+weight: 1610
+toc: false
+iframe: "/release/loader-v0-6-0.html"
+---
diff --git a/content/zh/docs/basics/enum.md b/content/zh/docs/basics/enum.md
index 7dd21458c..9265ecc7d 100644
--- a/content/zh/docs/basics/enum.md
+++ b/content/zh/docs/basics/enum.md
@@ -16,7 +16,7 @@ tableau 解析器支持三种枚举值形式:
1. 枚举值**名称**(name)。
2. 枚举值**编号**(number)。
- 3. 枚举值**别名**(alias)。别名可以是英文、中文或其他任意语言,通过 [tableau.evalue](https://github.com/tableauio/tableau/blob/v0.15.1/proto/tableau/protobuf/tableau.proto#L39) 扩展 [google.protobuf.EnumValueOptions](https://github.com/protocolbuffers/protobuf/blob/v34.0/src/google/protobuf/descriptor.proto#L904) 来指定。
+ 3. 枚举值**别名**(alias)。别名可以是英文、中文或其他任意语言,通过 [tableau.evalue](https://github.com/tableauio/tableau/blob/v0.16.0/proto/tableau/protobuf/tableau.proto#L39) 扩展 [google.protobuf.EnumValueOptions](https://github.com/protocolbuffers/protobuf/blob/v34.0/src/google/protobuf/descriptor.proto#L904) 来指定。
例如,`common.proto` 中定义的枚举类型 `FruitType`:
diff --git a/content/zh/release/loader-v0-6-0.md b/content/zh/release/loader-v0-6-0.md
new file mode 100644
index 000000000..e5751f87c
--- /dev/null
+++ b/content/zh/release/loader-v0-6-0.md
@@ -0,0 +1,12 @@
+---
+title: "Loader v0.6.0"
+description: "Loader v0.6.0 发布报告。"
+lead: "C# loader 插件、Protobuf Editions (2023/2024) 支持、跨语言 patch 系统,以及 Windows CI 改造。"
+date: 2026-06-11T04:17:48+00:00
+lastmod: 2026-06-11T04:17:48+00:00
+draft: false
+images: []
+weight: 1610
+toc: false
+iframe: "/release/loader-v0-6-0.html"
+---
diff --git a/package.json b/package.json
index 6062c25a9..03d315539 100644
--- a/package.json
+++ b/package.json
@@ -14,7 +14,7 @@
"init": "shx rm -rf .git && git init -b main",
"create": "exec-bin node_modules/.bin/hugo/hugo new",
"prestart": "npm run clean",
- "start": "exec-bin node_modules/.bin/hugo/hugo server --bind=0.0.0.0 --disableFastRender --poll 700ms --forceSyncStatic --navigateToChanged",
+ "start": "exec-bin node_modules/.bin/hugo/hugo server --bind=0.0.0.0 --disableFastRender --forceSyncStatic --navigateToChanged",
"prebuild": "npm run clean",
"build": "exec-bin node_modules/.bin/hugo/hugo --gc --minify",
"build:preview": "npm run build -D -F",
diff --git a/static/release/loader-v0-6-0.html b/static/release/loader-v0-6-0.html
new file mode 100644
index 000000000..688fd4cbc
--- /dev/null
+++ b/static/release/loader-v0-6-0.html
@@ -0,0 +1,2116 @@
+
+
+
+
+
+ Tableau Loader v0.6.0 — Release Notes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ A
+ B
+ C
+ D
+ E
+ F
+
+
+
+
+ 1
+ FruitType
+ ID
+ Price
+ Name
+ Tag
+ Stock
+
+
+ 2
+ map<int32,Fruit>
+ map<int32,Item>
+ int32
+ string
+ string
+ int32
+
+
+ 3
+ Outer key
+ Inner key
+ Indexed field
+ Display
+ Tag
+ Stock
+
+
+ 4
+ 1
+ 100
+ 99
+ Apple
+ fresh
+ 120
+
+
+ 5
+ 1
+ 101
+ 79
+ Pear
+ fresh
+ 80
+
+
+ 6
+ 2
+ 200
+ 99
+ Berry
+ frozen
+ 40
+
+
+
+
+
+
+
+
+
+
+
+ Tableau Loader
+ |
+ v0.6.0
+ |
+
+
+ Released June 11, 2026
+
+
+
+
+ RELEASE NOTES
+
+
+
+ v0.6.0
+
+
+
+ First-class C# loader plugin, Protobuf Editions 2023/2024 across all
+ three plugins, a unified
+ make.py
+ build pipeline replacing init.bat / init.sh / prepare.bat, and
+ vcpkg-managed protobuf with a quarterly-pinned matrix.
+
+
+
+ + 7 Features
+ ○ 6 Bug Fixes
+ ⟲ 3 Refactors
+ |
+ Go · C++17 · C# (Unity 2022.3 LTS / .NET 8) · Editions 2023/2024
+ · Go 1.26
+
+
+
+
+
+ ↓
+
+
+
+
+
+
+
+ 01
+ New Features
+
+
+
+
+
+ NEW
+ PLUGIN
+
+
+ C# Loader Plugin
+
+
+ New
+ protoc-gen-csharp-tableau-loader
+ plugin. Targets Unity 2022.3 LTS / .NET 8,
+ generates *.pc.cs. Same Hub /
+ Messager / Load API surface as Go & C++, including patch
+ loading, MessagerOptions, custom
+ ReadFunc/LoadFunc, and a thread-safe
+ Atomic<T>-backed Hub.
+
+
+ ▸ Program.cs
+ var hub = new Tableau.Hub();
+var opts = new Tableau.Load.Options {
+ IgnoreUnknownFields = true,
+ PatchDirs = new() { "./patch" },
+};
+hub.Load("./conf", Format.JSON, opts);
+var conf = hub.GetItemConf();
+
+
+
+
+
+ NEW
+ EDITIONS
+
+
+ Protobuf Editions 2023 & 2024
+
+
+ All three plugins (Go / C++ / C#) emit code that compiles cleanly
+ under edition = "2023" and
+ "2024" alongside proto2 / proto3. The
+ build toolchain in init.sh /
+ init.bat was modernized to install a
+ matching protoc.
+
+
+ ▸ schema.proto
+ // proto2 / proto3 still supported
+// new: Editions 2023 & 2024
+edition = "2024";
+package protoconf;
+message ItemConf { ... }
+
+
+
+
+
+ NEW
+ PATCH · TESTS
+
+
+ Cross-Language Patch + Real Test Suites
+
+
+ Three real test suites — Go (testing), C++ (gtest), C# (xUnit) — exercise the same patch scenarios with golden-file parity.
+ Standalone main.go /
+ main.cpp /
+ Program.cs demos were retired.
+
+
+ ▸ patch matrix
+ ✓ go main_test.go::Test_Patch_* PASS
+✓ cpp tests/patch_test.cpp PatchConf_* PASS
+✓ csharp tests/PatchTests.cs PatchConf_* PASS
+// All three load the same testdata/conf + testdata/patchconf
+// and compare to testdata/patchresult/ goldens.
+
+
+
+
+
+ NEW
+ BUILD
+
+
+ Unified make.py Pipeline
+
+
+ One Python 3.10+ stdlib-only entry point replaces
+ init.sh,
+ init.bat, and
+ prepare.bat. Subcommands:
+ setup,
+ generate,
+ build,
+ test,
+ clean,
+ env. CI runs the same script as
+ developers.
+
+
+ ▸ shell
+ $ python3 make.py setup --lang all
+$ python3 make.py test --lang go
+$ python3 make.py test --lang cpp # vcpkg-installed protobuf
+$ python3 make.py test --lang csharp -k HubTests
+$ python3 make.py test --lang cpp --protobuf-version 3.21.12
+
+
+
+
+
+ NEW
+ DEV ENV
+
+
+ Devcontainer & buf Codegen
+
+
+ Reproducible dev environment via
+ .devcontainer/: VS Code → "Reopen in
+ Container" gives the same Go, buf,
+ vcpkg, and protobuf versions used in CI.
+ buf generate replaces the
+ per-language gen.sh /
+ gen.bat scripts in every test
+ workspace.
+
+
+ ▸ .devcontainer/versions.env
+ GO_VERSION=1.24.0
+BUF_VERSION=1.67.0
+DOTNET_VERSION=8.0
+DEFAULT_VARIANT=modern
+MODERN_PROTOBUF_VERSION=6.33.4
+LEGACY_V3_PROTOBUF_VERSION=3.21.12
+
+
+
+
+
+ NEW
+ LOGGING
+
+
+ Dual-Mode Protobuf Log Handler (C++)
+
+
+ The C++ runtime now installs a Tableau log sink on libprotobuf —
+ routing [libprotobuf] messages into
+ the Tableau logger. Compile-time
+ TABLEAU_PB_LOG_LEGACY picks legacy
+ SetLogHandler (protobuf ≤ 3.x) or
+ modern absl::LogSink (protobuf ≥ 4.x
+ with Abseil).
+
+
+ ▸ util.pc.cc
+ #if TABLEAU_PB_LOG_LEGACY
+ // SetLogHandler(ProtobufLogHandler) on protobuf 3.x
+#else
+ // class ProtobufAbslLogSink : public absl::LogSink {
+ // void Send(const absl::LogEntry& entry) override;
+ // };
+#endif
+ATOM_LOGGER_CALL(tableau::log::DefaultLogger(), lvl,
+ "[libprotobuf %s:%d] %s", ...);
+
+
+
+
+
+ NEW
+ GO 1.26
+
+
+ Self-Referential Generics for TreeMap
+
+
+ pkg/treemap/redblacktree now uses
+ self-referential generics on Go ≥ 1.26 (Lesser[T Lesser[T]]), with a
+ //go:build !go1.26 fallback to keep
+ older toolchains compiling. Tightens type safety for
+ FindIter,
+ UpperBound,
+ LowerBound.
+
+
+
+ ▸ pkg/treemap/redblacktree/lesser_go126.go
+
+ //go:build go1.26
+
+package redblacktree
+
+type Lesser[T Lesser[T]] interface {
+ comparable
+ Less(other T) bool
+}
+
+
+
+
+
+
+
+
+
+
+ 02
+ Bug Fixes
+
+
+
+
+ ✓
+
+
+ Index field in a list under upper maps now resolves correctly
+ (#158)
+
+
+ Reworked
+ LevelMessage
+ to track
+ MapDepth
+ + a new
+ LeveledContainerDepth(). List levels under a parent map now generate the correct
+ number of leveled finders (FindItem1,
+ FindItem2, …). Adds Fruit6Conf.json + 543
+ lines of index_test.go.
+
+
+ INDEX
+
+
+
+ ✓
+
+
+ Index parser skips
+ oneof
+ branches when walking levels
+ (#156)
+
+
+ Three-line fix in
+ internal/index/descriptor.go: when iterating a message's fields, descriptors with
+ ContainingOneof() != nil
+ are skipped, removing spurious "field not found" errors caused
+ by oneof name conflicts.
+
+
+ INDEX
+
+
+
+ ✓
+
+
+ Field-name case conversion + cross-platform generation order
+ (#153)
+
+
+ New
+ underscoresToCamelCase
+ helper unifies property naming across all three plugins;
+ introduces
+ internal/xproto.SplitShards
+ so generation order is identical on Linux / macOS / Windows. New
+ StrcaseConf regression suite covers
+ UserID,
+ V2Ray,
+ XCoordinate, etc.
+
+
+ CODEGEN
+
+
+
+ ✓
+
+
+ Windows
+ prepare.bat
+ CMake 3.x install + admin elevation prompt
+ (#152, #154)
+
+
+ Bootstrap script now winget-installs the right CMake major
+ version and re-launches itself elevated when needed. Subsequent
+ commits absorbed it into
+ make.py setup.
+
+
+ WINDOWS
+
+
+
+ ✓
+
+
+ Templated includes use original proto names; OrderedMap
+ accessors adjusted
+ (#151)
+
+
+ Generated C++
+ hub.pc.cc
+ /
+ hub_shard.pc.cc
+ templates emit the original (non-snake-cased) include names, and
+ the OrderedMap accessor in C++ & C# generators only fires
+ when there's a top-level map.
+
+
+ TEMPLATE
+
+
+
+ ✓
+
+
+ C++
+ GetLastLoadedTime
+ no longer marked
+ inline
+ (#146)
+
+
+ The inline keyword on a non-trivial
+ accessor caused ODR violations when the symbol was referenced
+ from multiple translation units; removing it makes the link-time
+ behavior portable.
+
+
+ CPP
+
+
+
+
+
+
+
+
+
+
+
+
+ 04
+ Examples
+
+
+
+ FIX · INDEX (#158)
+
+ Index on a list nested under a parent map
+
+
+ Consider Fruit6Conf: an outer map keyed
+ by
+ FruitType
+ whose values contain a list of items, with the index
+ Price<ID>
+ and ordered index
+ Price<ID>@OrderedFruit. v0.5.0 generated the wrong number of leveled containers because
+ MapDepth
+ alone didn't capture "list under map". v0.6.0 introduces
+ LeveledContainerDepth(), which adds 1 for non-map levels that still need the parent map's
+ container.
+
+
+ ▸ Index.xlsx — Fruit6Conf
+
+
+
+
+
+ A
+ B
+ C
+
+
+
+
+ 1
+ FruitType
+ ID
+ Price
+
+
+ 2
+ map<int32,Fruit>
+ [Item]
+ int32
+
+
+ 3
+ Outer map key
+ List of items (vertical)
+ Indexed by Price<ID>
+
+
+ 4
+ 1
+ —
+ 99
+
+
+ 5
+ 1
+ —
+ 79
+
+
+ 6
+ 2
+ —
+ 99
+
+
+
+
+
+
+
+ ✗ Before (v0.5.0)
+
+ // list under map → 0 leveled finders generated
+ // FindItem1(fruitType, price) absent
+ items := mgr.FindItem(99) // returns only 1 fruit type
+
+
+
+ ✓ After (v0.6.0)
+
+ // LCD = MapDepth + 1 → 1 leveled finder
+ items := mgr.FindItem1(/*fruitType*/
+ 1, 99)
+ // scoped to the parent map key
+
+
+
+
+
+
+ FIX · ONEOF (#156)
+
+ Oneof branches no longer break level walking
+
+
+ When a level message embeds a
+ oneof, the parser previously tried to resolve oneof case fields by name
+ and conflicted with regular fields. The fix skips any descriptor
+ whose
+ ContainingOneof()
+ is non-nil.
+
+
+
+ ▸ internal/index/descriptor.go (parseCols)
+
+ for i := 0; i < md.Fields().Len(); i++ {
+ fd := md.Fields().Get(i)
+ if fd.ContainingOneof() != nil {
+ continue // skip oneof case fields
+ }
+ // ... existing logic
+}
+
+
+
+
+ NEW · MULTI-LANG
+
+ One schema, three loaders, identical patch tests
+
+
+ From a single .proto set, v0.6.0
+ generates idiomatic Go, C++17, and C# loaders — and three real test
+ suites (testing,
+ gtest,
+ xUnit) running the same
+ PatchConf scenarios against shared
+ testdata/ goldens.
+
+
+
+
+ ▸ go: main_test.go
+ func prepareHub(t *testing.T) *hub.MyHub {
+ h := hub.NewMyHub()
+ h.Load("../testdata/conf/",
+ format.JSON,
+ load.IgnoreUnknownFields())
+ return h
+}
+
+
+
+ ▸ cpp: tests/patch_test.cpp
+ TEST_F(PatchTest, RecursivePatchConf) {
+ auto opts = NewOptions();
+ opts->patch_dirs = {
+ test::TestPaths::PatchConf().string()};
+ Hub::Instance().Load(...);
+}
+
+
+
+ ▸ csharp: PatchTests.cs
+ [Fact]
+public void PatchReplaceConf() {
+ var opts = new Load.Options {
+ PatchDirs = new() { TestPaths.PatchConfDir }
+ };
+ var hub = new Hub();
+ hub.Load(...);
+}
+
+
+
+
+
+ NEW · BUILD
+
+ A single Python script for the whole flow
+
+
+ make.py
+ uses Python 3.10 stdlib only. It mounts vcpkg, sources
+ vcvarsall.bat
+ per-subprocess on Windows (your shell PATH/INCLUDE/LIB are never
+ mutated), and is itself unit-tested via
+ test_make.py
+ +
+ testing-make.yml.
+
+
+ ▸ shell — typical contributor flow
+ # one-time host toolchain (no-op inside devcontainer)
+$ python3 make.py setup --lang all
+
+# per-language
+$ python3 make.py test --lang go -k Test_ActivityConf_OrderedMap
+$ python3 make.py test --lang cpp --cxx-std 20 --cxx-compiler clang
+$ python3 make.py test --lang cpp --protobuf-version 3.21.12
+$ python3 make.py test --lang csharp -k HubTests
+
+# diagnostic JSON (paths, versions, env probes)
+$ python3 make.py env
+
+
+
+
+
+
+
+
+
+
+