Skip to content

Releases: cjmworks/cxx-json-codegen

v0.5.2 - Recursive Schema and Runtime Foundation

Choose a tag to compare

@lmingzhi618 lmingzhi618 released this 04 Aug 03:26

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 through anyOf with schema(T)
    and null
  • 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> and std::array<T, N> using recursive schema(T)
  • std::optional<T> using anyOf with recursive schema(T) and null
  • std::map<std::string, T> and std::unordered_map<std::string, T> when T
    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::variant
  • std::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-failure

Expected 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

Choose a tag to compare

@lmingzhi618 lmingzhi618 released this 03 Aug 03:00

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-failure

Expected result:

100% tests passed, 0 tests failed out of 30

Tag

Release tag:

v0.5.1

CJM v0.5.0

Choose a tag to compare

@lmingzhi618 lmingzhi618 released this 02 Aug 16:58
b4f6bc7

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 generate and default CMake header generation compatible

CLI Workflow

Generate the normal C++ integration header:

cjm generate \
  --input user.hpp \
  --output user.cjm.hpp

Generate a JSON Schema artifact:

cjm generate-schema \
  --input user.hpp \
  --output user.schema.json

Both 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> and std::array<T, N> when T is a scalar or string mapping
  • std::optional<T> when T is a scalar or string mapping
  • std::map<std::string, T> and std::unordered_map<std::string, T> when T
    is a scalar or string mapping
  • enum and enum class fields as JSON string enums
  • direct generated-struct fields through $ref and $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> when T is 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::variant
  • std::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-failure

Expected 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

Choose a tag to compare

@lmingzhi618 lmingzhi618 released this 31 Jul 01:06
90f06b3

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 enum and enum class fields 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 --input headers
  • 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.hpp

Repeating --input remains supported:

cjm generate \
  --input address.hpp \
  --input user.hpp \
  --output model.cjm.hpp

Generated Model Contract

Generated headers include experimental model-contract metadata through:

cjm::contract::model_traits<T>::model

The 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::variant
  • std::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-failure

Tag

Release tag:

v0.4.0

CJM v0.3.6

Choose a tag to compare

@lmingzhi618 lmingzhi618 released this 26 Jul 22:04
4e59acf

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 SourceFileSyntax boundary 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-failure

Expected 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::variant
  • std::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

Choose a tag to compare

@lmingzhi618 lmingzhi618 released this 22 Jul 02:38

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> where T is 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_t
  • std::int16_t
  • std::int32_t
  • std::int64_t
  • std::uint8_t
  • std::uint16_t
  • std::uint32_t
  • std::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::model

Map 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-failure

Expected 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-failure

Expected 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/frontends

These searches produced no architecture violations.

Known Limitations

v0.3.0 remains a documented practical subset.

Not yet supported:

  • arbitrary JSON values
  • std::variant
  • std::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.