Modelina

repository·master·Indexed 19 days ago

https://github.com/asyncapi/modelina

A library for generating accurate and well-tested data models (classes, interfaces, enums, etc.) from schema definitions such as AsyncAPI, OpenAPI, JSON Schema, XSD, or Avro documents. Modelina supports multiple target programming languages including TypeScript, Java, Python, Go, C#, and others, providing customizable constraint behavior, type mapping, and a preset system for generator customization.

Tokens
70.2K
Snippets
279
Records
438
Agent score
64%

What's inside @asyncapi/modelina

  1. What is the Modelina Meta Model (MMM)?

    master

    The Modelina Meta Model (MMM), also known as the MetaModel or Raw Meta Model, is a common intermediate structure used to represent data models from various input formats (such as Protobuf, JSON Schema, GraphQL, etc.).

    Developers can use the MetaModel as an input to Modelina to create their own custom input processors. The model is divided into two distinct stages: the Meta Model (the raw representation of the input) and the Constrained Meta Model (the representation adjusted to meet the specific requirements of an output language).

  2. Serialization and deserialization support for Scala

    master
    Modelina can generate Scala models that include serialization and deserialization functionality for various payload formats. However, as of the current version, specific presets for JSON, XML, and binary formats are not yet supported for Scala.
  3. Handle camel case naming changes

    master

    Modelina v4 fixed an edge case where object properties using camel case containing a number followed by an underscore and a letter (e.g., aa_00_testAttribute) were incorrectly formatted. This fix may cause existing property or model names to change in your generated code.

    Example of the change:

    Old (v3):

    interface AnonymousSchema_1 {
      aa_00TestAttribute?: string;
    }

    New (v4):

    interface AnonymousSchema_1 {
      aa_00_testAttribute?: string;
    }
  4. Supported XSD Features

    master

    Modelina supports several XSD constructs during conversion:

    Simple Types

    • Enumerations: xs:restriction with xs:enumeration values are converted to enum models.
    • Restrictions: Patterns, length constraints, and numeric ranges are recognized (though constraint information is preserved in the input rather than enforced in all generated models).

    Complex Types

    • Sequences: xs:sequence elements become object properties in the defined order.
    • Choices: xs:choice elements are converted to optional object properties.
    • Attributes: Converted to object properties. use="required" results in required properties, while use="optional" results in optional properties.

    Advanced Features

    • Complex Content (Inheritance): Using xs:complexContent with xs:extension results in properties from the base type being merged into the extending type.
    • Simple Content: Text content combined with attributes is converted to an object with a value property.
    • Arrays: Triggered by maxOccurs="unbounded" or maxOccurs > 1.
    • Optional Elements: Triggered by minOccurs="0".
    • Wildcards: xs:any elements are mapped to the any type. They are generated as properties with names like additionalProperty, additionalProperty1, etc., and support cardinality via minOccurs and maxOccurs.
  5. Understand Modelina's versioning and breaking change policy

    master

    Modelina follows a strict versioning policy to ensure stability for consumers of generated models. Any change that alters the generated output is considered a breaking change and requires a major version bump.

    Non-breaking changes include:

    • Adding new features (e.g., new generators, presets, or input processors) that do not affect existing output.
    • Modifying existing features via new options that default to the current behavior.
    • Bug fixes that resolve unusable generated code (e.g., syntax errors).

    Maintenance Note: Only the most recent major version is maintained. Major version releases typically follow a 3-month cadence in January, April, June, and September.

  6. How the Constrained Meta Model works

    master

    Before a MetaModel reaches a generator, it must be constrained to the target output language. Constraints ensure that the model adheres to the naming conventions and syntax rules of the specific output (e.g., Java, TypeScript, etc.).

    Example: Enum Key Constraint If an input EnumModel has a key named something% something:

    • In the Meta Model, the EnumValueModel.key remains something% something.
    • In the Java Constrained Meta Model, the ConstrainedEnumValueModel.key is transformed to a compliant identifier like SOMETHING_PERCENT_SOMETHING.

    Each output language has unique constraints. The specific behavior for each language can be found in the constraints documentation.

  7. How `oneOf` interacts with `allOf` and `properties`

    master

    Modelina uses specific patterns to handle combinations of schema keywords:

    oneOf with allOf

    If both oneOf and allOf are present, each model defined in allOf is merged into every model within the oneOf array.

    oneOf with properties

    If both oneOf and properties are present at the same level, the behavior is identical to the oneOf with allOf pattern. All properties defined on the root object are merged into each of the models defined within the oneOf array.

    Example of oneOf with allOf pattern:

    {
      "allOf":[
        {
          "title":"Animal",
          "type":"object",
          "properties":{
            "animalType":{
              "title":"Animal Type",
              "type":"string"
            },
            "age":{
              "type":"integer",
              "min":0
            }
          }
        }
      ],
      "oneOf":[
        {
          "title":"Cat",
          "type":"object",
          "properties":{
            "animalType":{
              "const":"Cat"
            },
            "huntingSkill":{
              "title":"Hunting Skill",
              "type":"string",
              "enum":[
                "clueless",
                "lazy"
              ]
            }
          }
        },
        {
          "title":"Dog",
          "type":"object",
          "additionalProperties":false,
          "properties":{
            "animalType":{
              "const":"Dog"
            },
            "breed":{
              "title":"Dog Breed",
              "type":"string",
              "enum":[
                "bulldog",
                "bichons frise"
              ]
            }
          }
        }
      ]
    }
  8. How XSD is transformed into MetaModels

    master

    Modelina transforms XSD (XML Schema Definition) into internal MetaModel representations through a four-step pipeline:

    1. XML Parsing: The XSD string is parsed into a JavaScript object using fast-xml-parser.
    2. XSD Schema Model: The parsed XML is converted into a structured XsdSchema model.
    3. MetaModel Conversion: XSD types are mapped to Modelina's internal MetaModel representation.
    4. Model Generation: The resulting MetaModels are processed by generators to produce the final output code (e.g., TypeScript, JSON Schema, etc.).
  9. How presets work in Modelina

    master

    Modelina uses presets to extend or modify the rendered model. You can think of presets as layers added on top of each other. Each generator starts with a default preset that provides a minimal model. Subsequent presets can either add new code to the rendered output or completely overwrite existing generated code.

    Generators render models by calling preset hooks (callbacks) for specific parts of a model (e.g., properties, constructors, getters). These hooks can be extended or overwritten by the presets you provide in the generator's configuration.

    // Example of the layering concept
    const generator = new TypeScriptGenerator({
      presets: [
        {
          class: {
            property({ content }) {
              // This prepends a comment to the existing content rendered by the default preset
              return `// My Comment\n${content}`;
            }
          }
        }
      ]
    });
  10. Security best practices for Modelina integrations

    master

    To prevent arbitrary code execution on your webserver, do not allow end-users to provide their own option callbacks. This includes preset hooks and constraint rules.

    Recommended approach: Only allow users to select from a predefined list of internal options and presets, similar to the implementation used in the Modelina Playground.