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 + + + + + + Tableau vX.Y.Z — Release Notes + + + + + + + + + + + + + + + + + + +``` + +### Key generation rules + +**Nav** — always version-specific: +- Left: logo (22px) + "Tableau" bold + version badge (grey pill) +- Right: nav links matching the sections present + GitHub icon SVG link to the release tag + +**Hero** — five animated elements: +1. `hero-anim-0`: brand row (logo 28px + "Tableau" + `|` + version badge + `|` + green released-pill with pulse dot) +2. `hero-anim-1`: "RELEASE NOTES" eyebrow (JetBrains Mono, 10.5px, 0.3em letter-spacing, `#9ca3af`) +3. `hero-anim-2`: giant version `vX.Y.Z` using `.hero-version` +4. `hero-anim-3`: descriptive subtitle (list the top 3–4 headline features, muted `#6b7280`, max-width 580px) +5. `hero-anim-4`: stat chips row (`.stat-chip .chip-green/blue/amber/violet`) + `|` + tech tags + +Background: CSS grid (`::before`) + ghosted watermark version text + `deco-sheet-wrap` (3D spreadsheet table, absolute positioned bottom-right). + +**Section structure** — each major section. The `sec-num` and the `sec-title` MUST share the section's accent colour (the same colour as the section's tag style). This colour pairing is non-negotiable — never leave the title at the default dark. + +```html +
+
+
+ 01 +

New Features

+
+ +
+
+``` + +**Section accent colour matrix** (identical to `tag-*` colours — see `references/design-system.md` for the full matrix): + +| Section | `sec-num` + `sec-title` colour | Matching tag | +|---------|--------------------------------|--------------| +| New Features | `#16a34a` (green) | `tag-new`, `tag-option` | +| Bug Fixes | `#1d4ed8` (blue, deep) — pair with section background `sec-fix` | `tag-tooling` | +| Breaking Changes | `#dc2626` (red) | `tag-breaking` | +| Deprecated | `#d97706` (amber) | `tag-arch` | +| Dependencies | `#6b7280` (slate) — body title may use `#374151` for contrast | n/a | +| Examples | `#7c3aed` (violet) | `tag-enhanced` | + +**Feature cards** — grid layout, `border-t-2` accent: +```html +
+
+
+ NEW + TOOLING +
+

Feature Title

+

Description…

+ +
+
+``` + +**Bug fix rows** — inside a `.card-base rounded-2xl`: +```html +
+
+ +
+

Fix title

+

Brief description.

+
+ PARSER +
+ +
+``` + +**Breaking change cards** — `.breaking-card` with red top border: +```html +
+
BREAKING
+

Change title

+

Description…

+ +
+``` + +**Before/after panels**: +```html +
+
+
✗ Before (vOLD)
+
...old code...
+
+
+
✓ After (vNEW)
+
...new code...
+
+
+``` + +**Code blocks** — GitHub light style. **Always wrap the body in `
` 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
+
+ + + + + + + ... + ... + ... + ... + ... + +
ABC
1FieldName
2map<uint32,Msg>
3Note text
41
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 +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ABCDEFG
1IDNameLevelHPAttackTypeValidate
2map<uint32,Hero>stringint32int32int32enum<HeroType>string|{validate:...
3Hero IDHero nameHero levelMax HPBase attackHero classCEL rule
41Arthur50500120warrior
52Merlin4538090mage
63Lancelot55620150knight
+
+``` + +--- + +## 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 + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ABCDEF
1FruitTypeIDPriceNameTagStock
2map<int32,Fruit>map<int32,Item>int32stringstringint32
3Outer keyInner keyIndexed fieldDisplayTagStock
4110099Applefresh120
5110179Pearfresh80
6220099Berryfrozen40
+
+ +
+ + +
+
+ Tableau + 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 +
+
+
+
+ + +
+
+
+ 03 +

+ Toolchain & Dependencies +

+
+ +

+ The biggest non-feature change in v0.6.0 is build-system + modernization. The bundled + third_party/_submodules/protobuf + submodule was removed in favor of vcpkg-managed + protobuf with a quarterly-pinned + VCPKG_BASELINE_COMMIT. Two variants ship + out of the box: +

+ +
+
+

+ DEFAULT_VARIANT=modern +

+

+ protobuf 6.33.4 +

+

+ vcpkg snapshot pinned to + 56bb2411… (tip of + 2026.04.27). +

+
+
+

+ DEFAULT_VARIANT=legacy_v3 +

+

+ protobuf 3.21.12 (Linux-only smoke) +

+

+ vcpkg snapshot from 2023-01-15 (6245ce44…). +

+
+
+ +
+ + vcpkg-managed protobuf + - third_party/_submodules/protobuf (removed) + + go-udiff (extracted to pkg/udiff) + - pmezard/go-difflib (replaced) + + buf v1.67.0 (CI proto generation) + + Editions 2023 / 2024 + + Go 1.24 (devcontainer) · Go 1.26 build tag + + .NET 8.0 SDK + + tableau v0.16.0 + + submodule recursive checkout in CI +
+ +
+ Migration note. If you + previously cloned with --recurse-submodules for the + bundled protobuf, drop that flag and run + python3 make.py setup --lang all (or open the repo in the + devcontainer). The script bootstraps vcpkg at + VCPKG_BASELINE_COMMIT, installs Go / buf / .NET pinned to + .devcontainer/versions.env, and is idempotent. +
+ +
+ Heads-up. + init.bat, init.sh, and the original + prepare.bat were deleted. If your CI or local scripts + call them, switch to python3 make.py. +
+
+
+ + +
+
+
+ 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

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ABC
1FruitTypeIDPrice
2map<int32,Fruit>[Item]int32
3Outer map keyList of items (vertical)Indexed by Price<ID>
4199
5179
6299
+
+ +
+
+
✗ 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
+
+
+
+
+ + + + + + +