When a $defs entry that is not an object (e.g. an enum, an array, or an array of enum) is referenced from more than one place, the generator creates a fresh C++ type for every reference instead of reusing the definition.
Relevant code in contrib/schemagen/weaseljson_schemagen.py:
Lines 226-232 (build_def): only returns a cached value for entries found in self._building.
Line 317 (_build_object): self._building is only populated for object definitions while their fields are being built, so object refs are implicitly cached.
Lines 291-297 (enum branch of build_type) and the array branch at lines 304-309: always call self.unique_name(...) and create a new EnumType / TArr, even when defname is the same definition seen before.
enumclassRole:int{admin,user};enumclassRole2:int{admin,user};// duplicate of Role
structRoot{std::optional<Role>role1;// "role1"
std::optional<Role2>role2;// "role2"
std::optional<std::vector<Role>>roles1;// "roles1"
std::optional<std::vector<Role2>>roles2;// "roles2"
};
Expected output: a single Role enum and a single Roles / std::vector<Role> type, referenced by all four fields.
Impact:
Generated headers grow unnecessarily when schemas reuse enum/array definitions.
Fields that refer to the same logical enum get different C++ types, so user code cannot assign or compare them directly (r.role1 = r.role2 fails to compile).
Arrays-of-enum references also generate duplicate Arr* kinds and matching code in the builder, compounding the bloat.
This only affects non-object $defs entries; object refs already reuse the cached TObj via self._building.
When a `$defs` entry that is not an object (e.g. an enum, an array, or an array of enum) is referenced from more than one place, the generator creates a fresh C++ type for every reference instead of reusing the definition.
**Relevant code in `contrib/schemagen/weaseljson_schemagen.py`:**
- Lines 226-232 (`build_def`): only returns a cached value for entries found in `self._building`.
- Line 317 (`_build_object`): `self._building` is only populated for object definitions while their fields are being built, so object refs are implicitly cached.
- Lines 291-297 (enum branch of `build_type`) and the array branch at lines 304-309: always call `self.unique_name(...)` and create a new `EnumType` / `TArr`, even when `defname` is the same definition seen before.
**Reproduction schema:**
```json
{
"type": "object",
"properties": {
"role1": { "$ref": "#/$defs/Role" },
"role2": { "$ref": "#/$defs/Role" },
"roles1": { "$ref": "#/$defs/Roles" },
"roles2": { "$ref": "#/$defs/Roles" }
},
"$defs": {
"Role": { "enum": ["admin", "user"] },
"Roles": { "type": "array", "items": { "$ref": "#/$defs/Role" } }
}
}
```
Actual generated output (abridged):
```cpp
enum class Role : int { admin, user };
enum class Role2 : int { admin, user }; // duplicate of Role
struct Root {
std::optional<Role> role1; // "role1"
std::optional<Role2> role2; // "role2"
std::optional<std::vector<Role>> roles1; // "roles1"
std::optional<std::vector<Role2>> roles2; // "roles2"
};
```
Expected output: a single `Role` enum and a single `Roles` / `std::vector<Role>` type, referenced by all four fields.
**Impact:**
- Generated headers grow unnecessarily when schemas reuse enum/array definitions.
- Fields that refer to the same logical enum get *different* C++ types, so user code cannot assign or compare them directly (`r.role1 = r.role2` fails to compile).
- Arrays-of-enum references also generate duplicate `Arr*` kinds and matching code in the builder, compounding the bloat.
This only affects non-object `$defs` entries; object refs already reuse the cached `TObj` via `self._building`.
weaselbot
was assigned by andrew2026-06-24 00:46:11 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
When a
$defsentry that is not an object (e.g. an enum, an array, or an array of enum) is referenced from more than one place, the generator creates a fresh C++ type for every reference instead of reusing the definition.Relevant code in
contrib/schemagen/weaseljson_schemagen.py:build_def): only returns a cached value for entries found inself._building._build_object):self._buildingis only populated for object definitions while their fields are being built, so object refs are implicitly cached.build_type) and the array branch at lines 304-309: always callself.unique_name(...)and create a newEnumType/TArr, even whendefnameis the same definition seen before.Reproduction schema:
Actual generated output (abridged):
Expected output: a single
Roleenum and a singleRoles/std::vector<Role>type, referenced by all four fields.Impact:
r.role1 = r.role2fails to compile).Arr*kinds and matching code in the builder, compounding the bloat.This only affects non-object
$defsentries; object refs already reuse the cachedTObjviaself._building.