Releases: cjmworks/cxx-json-codegen
Release list
v0.5.2 - Recursive Schema and Runtime Foundation
CJM v0.5.2 Release Notes
CJM v0.5.2 is the Recursive Schema and Runtime Foundation release.
This release extends the JSON Schema backend over recursive Metadata IR type
shapes and completes the design/test foundation needed before high-performance
runtime backend implementation begins.
It remains part of the v0.5 line because it does not add a new JSON runtime
backend. The next runtime implementation work can now start from documented
semantics, conformance shape, and static backend selection rules.
Highlights
- Adds recursive JSON Schema fragment generation for supported
schema(T)
combinations - Represents
std::optional<T>in JSON Schema throughanyOfwithschema(T)
andnull - Verifies recursive type closure across Metadata IR, nlohmann generated
mappings, generated model-contract descriptors, and JSON Schema output - Verifies supported multiline field declarations through the Tree-sitter
frontend and semantic pipeline - Adds the runtime JSON semantic profile for future runtime backends
- Adds the decode error and structured path model
- Sketches the runtime conformance fixture layout
- Adds static backend selection design for future CLI/CMake runtime backend
selection
Schema Coverage
JSON Schema output now supports recursive schema fragments for the existing
supported type surface:
std::vector<T>andstd::array<T, N>using recursiveschema(T)std::optional<T>usinganyOfwith recursiveschema(T)andnullstd::map<std::string, T>andstd::unordered_map<std::string, T>whenT
has a supported recursive schema mapping- enum and enum class fields nested inside supported containers
- generated struct fields nested inside supported containers
- optional enum, generated struct, and container fields
This keeps JSON Schema generation aligned with Metadata IR instead of treating
containers, optionals, enums, and generated structs as isolated one-level cases.
Runtime Foundation
The release adds design contracts for future runtime backends:
- runtime JSON semantic profile
- decode error and structured path model
- conformance fixture layout
- static backend selection
The key backend-selection decision is static selection:
generation time or build time
not dynamic runtime plugin dispatch.
Future runtime C++ backend selection should use a dedicated JSON backend concept
such as:
cjm_generate(
TARGET app
HEADERS user.hpp
JSON_BACKEND simdjson
)Artifact requests such as JSON Schema generation remain separate from runtime
backend selection.
Known Limitations
Not yet supported:
- simdjson, Glaze, yyjson, or other high-performance runtime backends
- runtime JSON Schema validation
- automatic header discovery
- arbitrary dynamic JSON values
std::variantstd::any- pointer fields
- polymorphism
- custom converters
- custom enum string mapping policies
- default-value metadata
- time and datetime mappings
- private fields
- native JSON backend
- install/package distribution
Verification
The v0.5.2 release was verified locally with:
ctest --test-dir build --output-on-failureExpected result:
100% tests passed, 0 tests failed out of 32
Coverage includes:
- recursive schema backend golden tests
- recursive nlohmann generated compile tests
- recursive generated model-contract tests
- multiline Tree-sitter frontend and semantic tests
- runtime conformance fixture skeleton checks
- existing CLI, CMake, parser, semantic, schema, contract, and generated compile
tests
Tag
Release tag:
v0.5.2
v0.5.1 - Default Field Mapping
CJM v0.5.1 Release Notes
CJM v0.5.1 is the Default Field Mapping release.
This release makes the normal model-authoring path less repetitive: fields in
CJM-managed structs now default to their exact C++ field names. Explicit JSON
metadata remains available for renames, omitempty, and ignored fields.
The release is intentionally still part of the v0.5 line. It strengthens the
shared field semantics that future runtime backends must consume; it does not
add a new JSON runtime backend.
Highlights
- Defaults untagged managed fields to their C++ field names
- Supports
json:",omitempty"for default-name optional fields - Preserves
json:"-"fields in Metadata IR with explicit ignored semantics - Diagnoses duplicate effective JSON field names
- Keeps explicit
json:"name"tags as rename overrides - Validates normalized field semantics across semantic, nlohmann, contract,
schema, CLI, CMake, parser, and Tree-sitter fixture tests - Updates the basic example to show tag-free same-name fields
Mapping Semantics
For a managed field:
struct User {
std::string name;
std::optional<std::string> nickname; // json:",omitempty"
std::string display_name; // json:"displayName"
int internal_id; // json:"-"
};CJM computes:
name -> "name"
nickname -> "nickname", omit_empty = true
display_name -> "displayName"
internal_id -> ignored
No case conversion is included in this release. CJM uses exact C++ field names
unless an explicit rename tag is present.
Backend Impact
All backends consume normalized Metadata IR facts:
- the nlohmann backend emits the same JSON keys whether the field name came from
a default or an explicit same-name tag - the JSON Schema backend uses effective field names and omits ignored fields
- generated model-contract metadata exposes JSON names,
omit_empty, and
ignored-field status consistently - CLI and CMake generation paths use the same semantic pipeline
Backends do not inspect C++ comments or decide default field names themselves.
Known Limitations
Not yet supported:
- automatic snake_case, camelCase, PascalCase, or acronym conversion
- type-level opt-in metadata syntax
- custom converters
- custom enum string mapping policies
- runtime JSON Schema validation
- native JSON backend
- high-performance runtime backends such as simdjson, Glaze, or yyjson
- automatic header discovery
- install/package distribution
Verification
The v0.5.1 release branch was verified locally with:
cmake --build build
ctest --test-dir build --output-on-failureExpected result:
100% tests passed, 0 tests failed out of 30
Tag
Release tag:
v0.5.1
CJM v0.5.0
CJM v0.5.0 Release Notes
CJM v0.5.0 adds the first JSON Schema backend.
The release keeps C++ models as the source of truth. Users still write ordinary
C++ headers with CJM JSON metadata; CJM builds Metadata IR and can now emit both
generated nlohmann/json C++ integration and JSON Schema artifacts for the
supported mapping surface.
This release does not make CJM a schema-first generator, OpenAPI framework,
runtime validator, or cross-language code generator.
Highlights
- Adds a JSON Schema Draft 2020-12 backend that consumes Metadata IR
- Adds golden tests for primitive, array, optional, map, enum, nested object, and
composed schema output - Preserves
std::array<T, N>extent in Metadata IR for schema generation - Adds
cjm generate-schema --input <header> --output <file> - Wires schema generation into
cjm_generate(...)through opt-in
GENERATE_SCHEMAS - Keeps C++ headers under
generated/cjm - Keeps schema artifacts under
generated/schemas - Exposes generated schema paths through
GENERATED_SCHEMAS_VAR - Keeps existing
cjm generateand default CMake header generation compatible
CLI Workflow
Generate the normal C++ integration header:
cjm generate \
--input user.hpp \
--output user.cjm.hppGenerate a JSON Schema artifact:
cjm generate-schema \
--input user.hpp \
--output user.schema.jsonBoth commands use the same parser and Semantic Analysis pipeline. Schema output
is generated from validated Metadata IR.
CMake Workflow
Existing CMake calls continue to generate only C++ headers:
cjm_generate(
TARGET app
HEADERS user.hpp
)Schema generation is opt-in:
cjm_generate(
TARGET app
HEADERS user.hpp
GENERATED_TARGET app_cjm_generated
GENERATE_SCHEMAS
GENERATED_SCHEMAS_VAR app_cjm_schemas
)For user.hpp, the current CMake layout is:
<build-dir>/generated/cjm/user.cjm.hpp
<build-dir>/generated/schemas/user.schema.json
Schema files are build artifacts. They are tracked by the generated target, but
they are not added as C++ sources and are not added to the generated include
directory.
Schema Coverage
Implemented schema mappings:
- object schemas for supported generated structs
bool- signed and unsigned integers
- common fixed-width integer spellings
- floating-point types
std::string- unsigned integers with
minimum: 0 std::vector<T>andstd::array<T, N>whenTis a scalar or string mappingstd::optional<T>whenTis a scalar or string mappingstd::map<std::string, T>andstd::unordered_map<std::string, T>whenT
is a scalar or string mapping- enum and enum class fields as JSON string enums
- direct generated-struct fields through
$refand$defs json:"-"fields omitted from schema properties- non-optional supported fields listed in
required
Known Limitations
Not yet supported:
- schema output for nested containers
- schema output for containers whose element or value type is an enum or
generated struct - schema output for
std::optional<T>whenTis an enum, generated struct, or
container - custom enum string mapping policies
- custom converters
- default-value metadata
- time and datetime schema formats
- OpenAPI route generation
- HTTP endpoint policy
- runtime JSON Schema validation
- arbitrary JSON values
std::variantstd::any- pointer fields
- polymorphism
- automatic header discovery
- full C++ grammar support at the CJM product level
- multiline managed field declarations are not yet documented as supported
- private fields
- native JSON backend
- install/package distribution
Verification
The v0.5 branch was verified locally with:
cmake --build build
ctest --test-dir build --output-on-failureExpected result:
100% tests passed, 0 tests failed out of 30
Coverage includes:
- schema backend golden tests
- CLI schema generation tests
- CMake schema artifact tests
- existing nlohmann backend tests
- contract backend tests
- parser and semantic tests
- generated compile tests
- basic example build/run tests
Tag
Release tag:
v0.5.0
CJM v0.4.0
CJM v0.4.0 Release Notes
CJM v0.4.0 expands the practical mapping surface and introduces the first
generated model-contract metadata for downstream tools.
This release keeps CJM focused on strongly typed, structured, modelable JSON.
It does not add arbitrary dynamic JSON support, custom converters, native JSON
runtime code, or automatic header discovery.
Highlights
- Adds
std::array<T, N>support for supported element types - Serializes supported
enumandenum classfields as JSON strings - Generates enum string conversion helpers in the nlohmann backend
- Exposes enum value metadata through generated model-contract descriptors
- Adds generated model-contract type descriptors for arrays, maps, optionals,
vectors, objects, enums, and scalar categories - Improves CLI ergonomics for grouped explicit
--inputheaders - Clarifies downstream generated artifact handles through
cjm_generate - Documents custom converter boundaries without implementing converters
- Documents high-performance backend strategy and keeps native JSON engine work
outside the CJM v1.0 critical path
Mapping Additions
std::array<T, N> maps to a JSON array when T is already supported.
Supported enum fields map to JSON strings by default:
enum class Status {
Active,
Disabled,
};
struct User {
Status status; // json:"status"
};The generated nlohmann backend writes:
{"status":"Active"}Unknown enum strings fail through the generated conversion helper.
Custom enum rename policies, enum aliases, case conversion policies, and
numeric enum mode are not implemented in v0.4.
Downstream Workflow
The recommended CMake workflow remains:
cjm_generate(
TARGET app
HEADERS user.hpp
)For multiple explicit model headers:
cjm_generate(
TARGET app
HEADERS
address.hpp
user.hpp
)The current CMake integration generates one *.cjm.hpp per listed header under
the build directory's generated/cjm include directory.
CJM does not automatically discover #include dependencies yet. Pass each
model header explicitly.
Manual CLI users can group related inputs into one generated output:
cjm generate \
--input address.hpp user.hpp \
--output model.cjm.hppRepeating --input remains supported:
cjm generate \
--input address.hpp \
--input user.hpp \
--output model.cjm.hppGenerated Model Contract
Generated headers include experimental model-contract metadata through:
cjm::contract::model_traits<T>::modelThe v0.4 contract exposes:
- model names
- field names
- JSON names
- ignored fields
omitempty- source locations
- type categories
- container type arguments
- enum string values
This contract is intended for downstream experiments such as schema generation,
typed endpoint tooling, documentation, and CLI/RPC binders. It may still change
before v1.0.
Custom Converter Boundary
v0.4 documents custom converter boundaries but does not implement converters.
Domain-specific scalar types such as UUID, decimal, path, duration, and
project-specific identifiers should eventually use explicit converter metadata
instead of becoming unlimited built-in mappings.
Converters are not a dynamic JSON escape hatch. std::any, arbitrary dynamic
JSON documents, pointer ownership policies, polymorphism, and std::variant
without a discriminator policy remain out of scope.
Known Limitations
Not yet supported:
- arbitrary JSON values
std::variantstd::any- pointer fields
- polymorphism
- custom converters
- custom enum string mapping policies
- time and datetime mappings
- automatic header discovery
- full C++ grammar support at the CJM product level
- multiline managed field declarations are not yet documented as supported
- private fields
- native JSON backend
- install/package distribution
Verification
The release branch should be verified with:
cmake --build build
ctest --test-dir build --output-on-failureTag
Release tag:
v0.4.0
CJM v0.3.6
CJM v0.3.6 Release Notes
CJM v0.3.6 promotes the Tree-sitter C++ frontend from research spike to the
default production parser path for the current practical syntax surface.
This release does not expand the Metadata IR or generated JSON behavior. Its
purpose is to make the parser foundation stronger while preserving the v0.3
public workflow.
Highlights
- Uses a Tree-sitter-backed C++ frontend by default for CLI and CMake generation
- Preserves the existing
SourceFileSyntaxboundary into Semantic Analysis - Keeps Tree-sitter implementation details inside the C++ frontend layer
- Adds parser parity coverage for the supported v0.3 syntax surface
- Fails closed for unsupported managed declarations that Tree-sitter can parse
but CJM does not yet support semantically - Registers Tree-sitter smoke and adapter tests in the normal test suite
- Keeps generated output compatible with existing golden tests
What Changed For Users
The user-facing workflow remains the same:
cjm generate --input model.hpp --output model.cjm.hpp
and:
cjm_generate(
TARGET app
HEADERS model.hpp
)Users do not need the Tree-sitter CLI, Node.js, Rust, npm, Cargo, or Python to
build or use CJM.
Parser Behavior
CJM still accepts only its documented practical subset. Tree-sitter can parse
far more C++ than CJM supports, so the adapter is intentionally strict.
Supported managed fields continue to use same-line JSON metadata:
struct User {
std::string name; // json:"name"
};Unsupported managed forms are rejected instead of being silently misread.
Ordinary C++ members without CJM json:"..." metadata remain outside CJM's
managed model surface and are ignored by the adapter when they are not needed
for metadata extraction.
Verification
The release branch was verified with:
cmake --build build
ctest --test-dir build --output-on-failureExpected result:
100% tests passed, 0 tests failed out of 21
Coverage includes:
- Tree-sitter adapter tests
- Tree-sitter smoke tests
- parser tests
- semantic tests
- generator golden tests
- CLI tests
- generated compile tests
- basic example build/run tests
Known Limitations
v0.3.6 remains a practical subset release.
Not yet supported:
- arbitrary JSON values
std::variantstd::any- pointer fields
- polymorphism
- custom converters
- enum string mapping policies
- time and datetime mappings
- automatic header discovery
- full C++ grammar support
- multiline managed field declarations are not yet documented as supported
- private fields
- native JSON backend
- install/package distribution
Tag
Release tag:
v0.3.6
CJM v0.3.0
CJM v0.3.0 Release Notes
CJM v0.3.0 is the Practical Type Coverage release.
This release extends the v0.2 Practical Models surface with common JSON object
shapes, fixed-width numeric spellings, and stronger end-to-end verification.
Highlights
- Adds language-neutral Metadata IR support for string-keyed map fields
- Supports
std::map<std::string, T>and
std::unordered_map<std::string, T>whereTis already in the supported
practical mapping surface - Rejects unsupported map key types before generation
- Preserves backend independence: the nlohmann backend consumes Metadata IR
only and does not inspect C++ parser syntax - Covers common fixed-width numeric spellings from
<cstdint> - Adds generated-code compile/run tests for expanded practical types
- Adds pipeline golden coverage for parser -> semantic -> Metadata IR ->
nlohmann generation - Adds CLI golden coverage for the v0.3 practical fixture
Supported v0.3 Additions
v0.3 builds on the v0.2 model surface.
Newly covered in v0.3:
std::map<std::string, T>std::unordered_map<std::string, T>- nested supported map value types
std::int8_tstd::int16_tstd::int32_tstd::int64_tstd::uint8_tstd::uint16_tstd::uint32_tstd::uint64_t- composed supported practical types across maps, vectors, optionals, enums,
aliases, and generated structs
Example:
namespace company::model {
using Sequence = std::uint64_t;
struct Detail {
std::string source; // json:"source"
std::uint32_t shard; // json:"shard"
};
struct Event {
Sequence sequence; // json:"sequence"
std::int64_t timestamp_ns; // json:"timestamp_ns"
Detail detail; // json:"detail"
std::vector<std::string> tags; // json:"tags"
std::map<std::string, std::vector<std::uint64_t>> buckets; // json:"buckets"
std::optional<std::unordered_map<std::string, std::string>> attributes; // json:"attributes,omitempty"
};
} // namespace company::modelMap Semantics
CJM maps supported string-keyed C++ maps to JSON objects with dynamic string
keys.
Supported:
std::map<std::string, int>
std::unordered_map<std::string, std::string>
std::map<std::string, std::vector<std::uint64_t>>
std::optional<std::map<std::string, int>>Unsupported map key types fail during semantic analysis:
std::map<int, std::string>Map values must still be part of the documented practical mapping subset.
Verification
v0.3.0 was verified with both the normal build directory and a clean build
directory.
Normal test run:
ctest --test-dir build --output-on-failureExpected result:
100% tests passed, 0 tests failed out of 19
Clean verification:
cmake -S . -B build-v03-verify
cmake --build build-v03-verify
ctest --test-dir build-v03-verify --output-on-failureExpected result:
100% tests passed, 0 tests failed out of 19
Architecture dependency checks were also run:
rg -n "frontends/|backends/" src/core
rg -n "frontends/cxx" src/backends
rg -n "backends/nlohmann" src/frontendsThese searches produced no architecture violations.
Known Limitations
v0.3.0 remains a documented practical subset.
Not yet supported:
- arbitrary JSON values
std::variantstd::any- pointer fields
- polymorphism
- custom converters
- enum string mapping policies
- time and datetime mappings
- automatic header discovery
- full C++ grammar support
- multiline field declarations in the current handwritten parser
- production parser replacement
- install/package distribution
- cross-platform CI release gates
Frontend parser research, including Tree-sitter evaluation, is planned for
v0.3.5.
Dogfooding and adoption documentation are planned after v0.3.0 so that
downstream projects can consume a real release tag.
Tag
Release tag:
v0.3.0
The tag should point to the v0.3.0 release commit on main.