Skip to content

BRP improve json schema support #19786

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 76 commits into
base: main
Choose a base branch
from

Conversation

Leinnan
Copy link
Contributor

@Leinnan Leinnan commented Jun 23, 2025

Objective

Currently implemented JSON Schema export is often producing invalid schemas for types resulting in that json that would be a valid value for schema generated for type cannot be deserialized to that type by Bevy deserializer.

Solution

This PR tries to reimagine how the schema is constructed. It follows Draft 2020 of JSON schema, as definied here: https://json-schema.org/draft/2020-12/schema
It is possible to use schemas generated by new system as validation data for assets in various editors. Once there would be a support for getting information about supported extensions with reflection system I could write example. Related task: #19399
Main additions and change to previous behaviour would be:

  • f32 generates {"type": "number", "shortPath": "f32", "typePath": "f32"} instead of {"$ref": "#/$defs/f32"}
  • primitive types also are getting proper support for minimum and maximum values- from type itself and also from reflection range data, if provided.
  • CustomInternalSchemaData enables providing custom schemas for reflected types
  • Particularly useful for types like Vec3 that serialize as 3-element arrays despite being structs with 3 fields
  • ExternalSchemaSource trait allows referencing external schema sources
  • Automatic registration for math types (Vec2, Vec3, Vec4, quaternions, matrices) to serialize as arrays
  • Types with ReflectDefault implementation automatically include a default field in their schema
  • Type and field descriptions are read from documentation attributes and included in schemas
  • Range attributes (#[reflect(@min..=max)]) are properly handled
  • Option<T> is now treated as a required field with possible values of T or null. This approach ensures compatibility with JSON Schema validation while maintaining type safety. Information about whether field is required should be provided by bevy reflection system, until that is the case we cannot guarantee that data with missing optional field is would be parsed correctly. Related task: Access serde attributes with reflection #19557
  • New field rustFieldsInfo- It is provided when type is serialized as array, but the type is not an array. It is done to provide additional information about the fields in the schema.

Example schema:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "shortPath": "DAffine3",
  "typePath": "glam::DAffine3",
  "modulePath": "glam",
  "crateName": "glam",
  "reflectTypeData": [
    "Deserialize",
    "Serialize",
    "Default"
  ],
  "kind": "Struct",
  "rustFieldsInfo": {
    "translation": {
      "$ref": "#/$defs/glam%3A%3ADVec3",
      "title": "translation",
      "typePath": "glam::DVec3",
      "kind": "Struct"
    },
    "matrix3": {
      "$ref": "#/$defs/glam%3A%3ADMat3",
      "title": "matrix3",
      "typePath": "glam::DMat3",
      "kind": "Struct"
    }
  },
  "type": "array",
  "prefixItems": [
    {
      "title": "matrix3.x_axis.x",
      "typePath": "f64",
      "kind": "Value",
      "type": "number"
    },
    {
      "title": "matrix3.x_axis.y",
      "typePath": "f64",
      "kind": "Value",
      "type": "number"
    },
    {
      "title": "matrix3.x_axis.z",
      "typePath": "f64",
      "kind": "Value",
      "type": "number"
    },
    {
      "title": "matrix3.y_axis.x",
      "typePath": "f64",
      "kind": "Value",
      "type": "number"
    },
    {
      "title": "matrix3.y_axis.y",
      "typePath": "f64",
      "kind": "Value",
      "type": "number"
    },
    {
      "title": "matrix3.y_axis.z",
      "typePath": "f64",
      "kind": "Value",
      "type": "number"
    },
    {
      "title": "matrix3.z_axis.x",
      "typePath": "f64",
      "kind": "Value",
      "type": "number"
    },
    {
      "title": "matrix3.z_axis.y",
      "typePath": "f64",
      "kind": "Value",
      "type": "number"
    },
    {
      "title": "matrix3.z_axis.z",
      "typePath": "f64",
      "kind": "Value",
      "type": "number"
    },
    {
      "title": "translation.x",
      "typePath": "f64",
      "kind": "Value",
      "type": "number"
    },
    {
      "title": "translation.y",
      "typePath": "f64",
      "kind": "Value",
      "type": "number"
    },
    {
      "title": "translation.z",
      "typePath": "f64",
      "kind": "Value",
      "type": "number"
    }
  ],
  "minItems": 12,
  "maxItems": 12,
  "$defs": {
    "glam::DMat3": {
      "shortPath": "DMat3",
      "typePath": "glam::DMat3",
      "modulePath": "glam",
      "crateName": "glam",
      "reflectTypeData": [
        "Deserialize",
        "Serialize",
        "Default"
      ],
      "kind": "Struct",
      "rustFieldsInfo": {
        "x_axis": {
          "$ref": "#/$defs/glam%3A%3ADVec3",
          "title": "x_axis",
          "typePath": "glam::DVec3",
          "kind": "Struct"
        },
        "y_axis": {
          "$ref": "#/$defs/glam%3A%3ADVec3",
          "title": "y_axis",
          "typePath": "glam::DVec3",
          "kind": "Struct"
        },
        "z_axis": {
          "$ref": "#/$defs/glam%3A%3ADVec3",
          "title": "z_axis",
          "typePath": "glam::DVec3",
          "kind": "Struct"
        }
      },
      "type": "array",
      "prefixItems": [
        {
          "title": "x_axis.x",
          "typePath": "f64",
          "kind": "Value",
          "type": "number"
        },
        {
          "title": "x_axis.y",
          "typePath": "f64",
          "kind": "Value",
          "type": "number"
        },
        {
          "title": "x_axis.z",
          "typePath": "f64",
          "kind": "Value",
          "type": "number"
        },
        {
          "title": "y_axis.x",
          "typePath": "f64",
          "kind": "Value",
          "type": "number"
        },
        {
          "title": "y_axis.y",
          "typePath": "f64",
          "kind": "Value",
          "type": "number"
        },
        {
          "title": "y_axis.z",
          "typePath": "f64",
          "kind": "Value",
          "type": "number"
        },
        {
          "title": "z_axis.x",
          "typePath": "f64",
          "kind": "Value",
          "type": "number"
        },
        {
          "title": "z_axis.y",
          "typePath": "f64",
          "kind": "Value",
          "type": "number"
        },
        {
          "title": "z_axis.z",
          "typePath": "f64",
          "kind": "Value",
          "type": "number"
        }
      ],
      "minItems": 9,
      "maxItems": 9
    },
    "glam::DVec3": {
      "shortPath": "DVec3",
      "typePath": "glam::DVec3",
      "modulePath": "glam",
      "crateName": "glam",
      "reflectTypeData": [
        "Deserialize",
        "Serialize",
        "Default"
      ],
      "kind": "Struct",
      "rustFieldsInfo": {
        "x": {
          "title": "x",
          "typePath": "f64",
          "kind": "Value",
          "type": "number"
        },
        "y": {
          "title": "y",
          "typePath": "f64",
          "kind": "Value",
          "type": "number"
        },
        "z": {
          "title": "z",
          "typePath": "f64",
          "kind": "Value",
          "type": "number"
        }
      },
      "type": "array",
      "prefixItems": [
        {
          "title": "x",
          "typePath": "f64",
          "kind": "Value",
          "type": "number"
        },
        {
          "title": "y",
          "typePath": "f64",
          "kind": "Value",
          "type": "number"
        },
        {
          "title": "z",
          "typePath": "f64",
          "kind": "Value",
          "type": "number"
        }
      ],
      "minItems": 3,
      "maxItems": 3
    }
  }
}

Testing

  • New tests are added
  • I use this code for generating schemas for my assets with configurations for Zed and VSCode editor

@janhohenheim janhohenheim added the S-Needs-Review Needs reviewer attention (from anyone!) to move forward label Jun 23, 2025
@Leinnan
Copy link
Contributor Author

Leinnan commented Jun 23, 2025

@mweatherley @splo @MrGVSV Could be interested in this :) It still requires some cleanup for sure before merging, but I wanted to make sure if that is something that others find useful enough to justify changes.

@Leinnan
Copy link
Contributor Author

Leinnan commented Jun 23, 2025

I also was wondering about adding dev dependency: https://github.com/GREsau/schemars
It would help out with validation whether generated schemas are valid and test out more scenarios that should pass/fail for given type. Is that a justified use case?

@alice-i-cecile alice-i-cecile added the C-Feature A new feature, making something new possible label Jun 23, 2025
@Leinnan
Copy link
Contributor Author

Leinnan commented Jul 9, 2025

I was trying out this as solution, but https://github.com/Stranger6667/jsonschema was claiming that it is not a valid schema, so I did revert this change to the one currently existing in the PR. But I am open to improve it.

After testing with this library, the following is a valid schema:

{
  "$ref": "#/$defs/%28foo%3A%3Abar%2C%20baz%3A%3Aqux%29",
  "$defs": {
    "(foo::bar, baz::qux)": {
      "type": "number"
    }
  }
}

That is, the percent encoding part should only be in the reference, not at the definition key. The only thing to care is not to convert spaces with + but with %20, meaning valid percent encoding and not URL encoding.

Then we could satisfy @ChristopherBiscardi: having valid references and keep type paths as keys.

Sounds great, I will check it out tomorrow/today.

Edit@ Just did it, it works! Great :D

@alice-i-cecile alice-i-cecile added the X-Controversial There is active debate or serious implications around merging this PR label Jul 9, 2025
@splo
Copy link
Contributor

splo commented Jul 10, 2025

When running the example server, it panics with the following error:

thread 'main' panicked at crates/bevy_remote/src/schemas/mod.rs:151:14:
SHOULD NOT HAPPENED
stack backtrace:
   5: <bevy_reflect::type_registry::TypeRegistry as bevy_remote::schemas::RegisterReflectJsonSchemas>::register_data_type_by_value
             at ./crates/bevy_remote/src/schemas/mod.rs:150:9
   6: <bevy_app::app::App as bevy_remote::schemas::RegisterReflectJsonSchemas>::register_data_type_by_value
             at ./crates/bevy_remote/src/schemas/mod.rs:181:9
   7: bevy_remote::schemas::RegisterReflectJsonSchemas::register_force_as_array
             at ./crates/bevy_remote/src/schemas/mod.rs:122:9
   8: bevy_remote::schemas::RegisterReflectJsonSchemas::register_schema_base_types
             at ./crates/bevy_remote/src/schemas/mod.rs:62:13
   9: <bevy_remote::RemotePlugin as bevy_app::plugin::Plugin>::build
             at ./crates/bevy_remote/src/lib.rs:658:9
  10: bevy_app::app::App::add_boxed_plugin::{{closure}}
             at ./crates/bevy_app/src/app.rs:484:37

It seems it fails calling this at RegisterReflectJsonSchemas::register_schema_base_types:

            self.register_force_as_array::<bevy_math::I8Vec2>();

@Leinnan
Copy link
Contributor Author

Leinnan commented Jul 10, 2025

@splo I've updated the registration process, it should be fine now.

@ChristopherBiscardi I still want to adress your concern about loosing field informations. What do you think about introducing additional field rustFieldsInfo that will be in the same format as properties and will be provided for types that are serialized as arrays, but are reallly structs on Rust side? Besides that, for the fields where we are forcing serialization as arrays there will be used title field in format like that: matrix3.x_axis.x.
To give you example, schema of glam::DAffine3(here with added definitions used by type):

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "shortPath": "DAffine3",
  "typePath": "glam::DAffine3",
  "modulePath": "glam",
  "crateName": "glam",
  "reflectTypeData": [
    "Deserialize",
    "Serialize",
    "Default"
  ],
  "kind": "Struct",
  "rustFieldsInfo": {
    "translation": {
      "$ref": "#/$defs/glam%3A%3ADVec3",
      "title": "translation",
      "typePath": "glam::DVec3",
      "kind": "Struct"
    },
    "matrix3": {
      "$ref": "#/$defs/glam%3A%3ADMat3",
      "title": "matrix3",
      "typePath": "glam::DMat3",
      "kind": "Struct"
    }
  },
  "type": "array",
  "prefixItems": [
    {
      "title": "matrix3.x_axis.x",
      "typePath": "f64",
      "kind": "Value",
      "type": "number"
    },
    {
      "title": "matrix3.x_axis.y",
      "typePath": "f64",
      "kind": "Value",
      "type": "number"
    },
    {
      "title": "matrix3.x_axis.z",
      "typePath": "f64",
      "kind": "Value",
      "type": "number"
    },
    {
      "title": "matrix3.y_axis.x",
      "typePath": "f64",
      "kind": "Value",
      "type": "number"
    },
    {
      "title": "matrix3.y_axis.y",
      "typePath": "f64",
      "kind": "Value",
      "type": "number"
    },
    {
      "title": "matrix3.y_axis.z",
      "typePath": "f64",
      "kind": "Value",
      "type": "number"
    },
    {
      "title": "matrix3.z_axis.x",
      "typePath": "f64",
      "kind": "Value",
      "type": "number"
    },
    {
      "title": "matrix3.z_axis.y",
      "typePath": "f64",
      "kind": "Value",
      "type": "number"
    },
    {
      "title": "matrix3.z_axis.z",
      "typePath": "f64",
      "kind": "Value",
      "type": "number"
    },
    {
      "title": "translation.x",
      "typePath": "f64",
      "kind": "Value",
      "type": "number"
    },
    {
      "title": "translation.y",
      "typePath": "f64",
      "kind": "Value",
      "type": "number"
    },
    {
      "title": "translation.z",
      "typePath": "f64",
      "kind": "Value",
      "type": "number"
    }
  ],
  "minItems": 12,
  "maxItems": 12,
  "$defs": {
    "glam::DMat3": {
      "shortPath": "DMat3",
      "typePath": "glam::DMat3",
      "modulePath": "glam",
      "crateName": "glam",
      "reflectTypeData": [
        "Deserialize",
        "Serialize",
        "Default"
      ],
      "kind": "Struct",
      "rustFieldsInfo": {
        "x_axis": {
          "$ref": "#/$defs/glam%3A%3ADVec3",
          "title": "x_axis",
          "typePath": "glam::DVec3",
          "kind": "Struct"
        },
        "y_axis": {
          "$ref": "#/$defs/glam%3A%3ADVec3",
          "title": "y_axis",
          "typePath": "glam::DVec3",
          "kind": "Struct"
        },
        "z_axis": {
          "$ref": "#/$defs/glam%3A%3ADVec3",
          "title": "z_axis",
          "typePath": "glam::DVec3",
          "kind": "Struct"
        }
      },
      "type": "array",
      "prefixItems": [
        {
          "title": "x_axis.x",
          "typePath": "f64",
          "kind": "Value",
          "type": "number"
        },
        {
          "title": "x_axis.y",
          "typePath": "f64",
          "kind": "Value",
          "type": "number"
        },
        {
          "title": "x_axis.z",
          "typePath": "f64",
          "kind": "Value",
          "type": "number"
        },
        {
          "title": "y_axis.x",
          "typePath": "f64",
          "kind": "Value",
          "type": "number"
        },
        {
          "title": "y_axis.y",
          "typePath": "f64",
          "kind": "Value",
          "type": "number"
        },
        {
          "title": "y_axis.z",
          "typePath": "f64",
          "kind": "Value",
          "type": "number"
        },
        {
          "title": "z_axis.x",
          "typePath": "f64",
          "kind": "Value",
          "type": "number"
        },
        {
          "title": "z_axis.y",
          "typePath": "f64",
          "kind": "Value",
          "type": "number"
        },
        {
          "title": "z_axis.z",
          "typePath": "f64",
          "kind": "Value",
          "type": "number"
        }
      ],
      "minItems": 9,
      "maxItems": 9
    },
    "glam::DVec3": {
      "shortPath": "DVec3",
      "typePath": "glam::DVec3",
      "modulePath": "glam",
      "crateName": "glam",
      "reflectTypeData": [
        "Deserialize",
        "Serialize",
        "Default"
      ],
      "kind": "Struct",
      "rustFieldsInfo": {
        "x": {
          "title": "x",
          "typePath": "f64",
          "kind": "Value",
          "type": "number"
        },
        "y": {
          "title": "y",
          "typePath": "f64",
          "kind": "Value",
          "type": "number"
        },
        "z": {
          "title": "z",
          "typePath": "f64",
          "kind": "Value",
          "type": "number"
        }
      },
      "type": "array",
      "prefixItems": [
        {
          "title": "x",
          "typePath": "f64",
          "kind": "Value",
          "type": "number"
        },
        {
          "title": "y",
          "typePath": "f64",
          "kind": "Value",
          "type": "number"
        },
        {
          "title": "z",
          "typePath": "f64",
          "kind": "Value",
          "type": "number"
        }
      ],
      "minItems": 3,
      "maxItems": 3
    }
  }
}

What do you think? Same question to the @splo

@splo
Copy link
Contributor

splo commented Jul 10, 2025

Before this PR, the registry query lied about some of its types. For instance, in my VS Code extension, I have code like this:

if (typePath === 'glam::Vec3`) {
  // Ignore that this pretends to be an object with x, y, z properties.
  // Instead treat it as an array with 3 elements.
}

I reported this issue earlier in this PR and I thought we concluded that we'd tackle it later. Indeed, the issue is not only with bevy_math types but (I think) for every type that has a custom serde implementation (for instance core::time::Duration).

The current state of this PR tries to manually fix the bevy_math types by hard-coding them while I hoped the fix would be more general and cover all such cases. I understand this is a tricky issue.

So first question: is it ok to have a temporary and incomplete workaround in this PR?

If so and we naively fix bevy_math types by reporting their serialized type, then indeed we lose some of the underlying internal Rust type information. We still have the most important though: the type path.

Second question: is it that important? What is the use case for reporting the internal Rust type information in the registry query?

I feel that is an actual controversial change. I think most BRP users only need to know the actual types they are supposed to work with. Is it about code generation? Like read type info from BRP and generate Rust code that should be compiled with Bevy types?

If we decide to somehow report the internal Rust type information, then yes, I guess we could include that in a custom field.

In the current format, is it possible to map the internal Rust field to its associated JSON Schema field? I mean for DAffine3, JSON schema value [2] maps to Rust value matrix3.x_axis.z. Is this what you're doing with the title field? If so, I'm not sure title is supposed to be used algorithmically, as it is more of a human-readable label. Then what alternatives do we have? It is a bit clunky.


Anyway, how about concentrating all custom fields (such as typePath, shortPath, kind, etc) that are not part of the JSON Schema standard under a single field? Something like rustType or bevyType or just bevy?

"glam::Vec3": {
  "type": "array",
  "maxItems": 3,
  "minItems": 3,
  "prefixItems": [
    {
      "title": "x",
      "type": "number",
      "bevyType": {
        "kind": "Value",
        "typePath": "f32"
      }
    },
    {
      "title": "y",
      "type": "number",
      "bevyType": {
        "kind": "Value",
        "typePath": "f32"
      }
    },
    {
      "title": "z",
      "type": "number",
      "bevyType": {
        "kind": "Value",
        "typePath": "f32"
      }
    }
  ],
  "bevyType": {
    "crateName": "glam",
    "kind": "Struct",
    "modulePath": "glam",
    "reflectTypeData": ["Default", "Serialize", "Deserialize"],
    "shortPath": "Vec3",
    "typePath": "glam::Vec3",
    "fields": {
      "x": {
        "kind": "Value",
        "typePath": "f32"
      },
      "y": {
        "kind": "Value",
        "typePath": "f32"
      },
      "z": {
        "kind": "Value",
        "typePath": "f32"
      }
    }
  }
}

It would isolate non-standard fields and make it easier to parse the JSON Schema. It would also allow us to add more custom fields in the future without cluttering the main schema structure.

@Leinnan
Copy link
Contributor Author

Leinnan commented Jul 10, 2025

The current state of this PR tries to manually fix the bevy_math types by hard-coding them while I hoped the fix would be more general and cover all such cases. I understand this is a tricky issue.
So first question: is it ok to have a temporary and incomplete workaround in this PR?

@splo I think that yes, given that Bevy Registry does not give us information that we could use to detect and handle those cases. One other thing that this does not cover is serde attributes, but support for that must wait for #19557 .

Second question: is it that important? What is the use case for reporting the internal Rust type information in the registry query?

I think that not loosing information that we can provide is useful, but maybe it should all be in separate field like you described later?

In the current format, is it possible to map the internal Rust field to its associated JSON Schema field? I mean for DAffine3, JSON schema value [2] maps to Rust value matrix3.x_axis.z. Is this what you're doing with the title field? If so, I'm not sure title is supposed to be used algorithmically, as it is more of a human-readable label. Then what alternatives do we have? It is a bit clunky.

For this format I was thinking about what format for title would be useful to cover cases like the one here: https://github.com/rust-adventure/skein/blob/main/extension/object_to_form.py

I really like the idea of putting bevy specific fields into one field, but I don't know if that should be part of this PR tbh.

@Leinnan
Copy link
Contributor Author

Leinnan commented Jul 10, 2025

@mweatherley @MrGVSV How do you feel about the current state of the PR?

@splo
Copy link
Contributor

splo commented Jul 10, 2025

For this format I was thinking about what format for title would be useful to cover cases like the one here: https://github.com/rust-adventure/skein/blob/main/extension/object_to_form.py

I need more context information to understand exactly why the Rust internal structure is needed in this Python code. But fine, if there's demand for this feature, we can add it.

I really like the idea of putting bevy specific fields into one field, but I don't know if that should be part of this PR tbh.

It could be in another PR of course. I just fear a PR with only cosmetic schema-breaking changes would be de-prioritized to hell. Like "too late, we can't change anything anymore, the API is frozen forever". I've seen that in a professional context so many times.

@Leinnan
Copy link
Contributor Author

Leinnan commented Jul 12, 2025

It could be in another PR of course. I just fear a PR with only cosmetic schema-breaking changes would be de-prioritized to hell. Like "too late, we can't change anything anymore, the API is frozen forever". I've seen that in a professional context so many times.

Yeah, I get that :< I agree with you, but I am already a bit worried if that wouldn't make this PR too big. It already did have a long discussion and I would love to make it to the finish line before 0.17.

Right now I would love to have some feedback from the team to know if that can make into it and/or what would need to be changed or fixed.

@Leinnan Leinnan requested a review from splo July 18, 2025 15:55
}

/// Helper trait
pub(crate) trait RegisterReflectJsonSchemas {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this need to be a trait with blanket implementations as opposed to simple functions?

Copy link
Contributor Author

@Leinnan Leinnan Jul 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That way it is implemented for both App and TypeRegistry, making it easier to use.

fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
ReferenceLocation::Definitions => write!(f, "#/$defs/"),
ReferenceLocation::Components => write!(f, "#/components/"),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fact that components and $defs are hard-coded here is pragmatic and fine. But don't you think in an ideal situation, these should be somehow passed as parameters by the calling code (which is json_schema or open_rpc)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree, but I that could be a separate improvement.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add a comment for this? I don't know Bevy maintainers stance on TODO comments but there could be an indication on how it should be improved in the future.

}
}

/// JSON Schema type for Bevy Registry Types
/// It tries to follow this standard: <https://json-schema.org/specification>
///
/// To take the full advantage from info provided by Bevy registry it provides extra fields
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default)]
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Default, Reflect)]
#[serde(rename_all = "camelCase")]
pub struct JsonSchemaBevyType {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a thought: if we used a third-party library schema type (jsonschema), we would have a standard to rely on. We could include custom Bevy types with a struct that flattens the official fields:

pub struct BevyJsonSchema {
    #[serde(flatten)]
    pub schema: Schema, // Third-party schema.
    // Bevy extensions:
    pub short_path: Cow<'static, str>,
    pub type_path: Cow<'static, str>,
    // etc.
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall this file is very well documented, congratulations! It is very long though. Once we take the time to read it, it's not too complicated.
Do you think a third-party library would help here to lower the line count and ease future maintenance?

@Leinnan
Copy link
Contributor Author

Leinnan commented Jul 21, 2025

@splo thanks for the feedback! About the last two pieces- I think maybe it would make sense to move the schema stuff to separate crate inside bevy repo since it depends so much on bevy reflection.

@Leinnan
Copy link
Contributor Author

Leinnan commented Jul 21, 2025

@MrGVSV I've tried to update first message in PR as well, do you have any opinions on the PR?

@splo
Copy link
Contributor

splo commented Jul 22, 2025

@splo thanks for the feedback! About the last two pieces- I think maybe it would make sense to move the schema stuff to separate crate inside bevy repo since it depends so much on bevy reflection.

I understand much of the code rely on bevy_reflect but I was commenting on 2 different matter:

  • The long reflect info file where I was asking if you (or anyone) knew any lib that could simplify the code. I don't know how to express, it seems very "type info" stuff that could live in bevy_reflect or even maybe some non-reflect part could be extracted out?
  • The JSON Schema file comment is not about bevy_reflect stuff. The point is to more easily understand and maintain where Bevy is actually using the JSON Schema standards, and where it diverges to add its extensions. Also to reduce responsibilities and number of lines of code Bevy maintainers will have to handle.

Copy link
Contributor

@splo splo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A migration guide is needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Dev-Tools Tools used to debug Bevy applications. C-Feature A new feature, making something new possible M-Needs-Migration-Guide A breaking change to Bevy's public API that needs to be noted in a migration guide S-Needs-Review Needs reviewer attention (from anyone!) to move forward X-Controversial There is active debate or serious implications around merging this PR
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants