Define datatypes once, get polyglot results
datatypetool docs datatypetool_type_files.md
4.3 kB · 110 lines
Markdown
at main

*.type Files #

Data Types with in *.type files can be one of four options:

  • An alias:

    • A simple "Treat this as something else" type
    • ex.: Point = (Float, Float)
  • An enum:

    • A category of type "variants" that are part of the named type.
    • ex.: Answers = Yes | No | Unsure
  • A model:

    • A dataclass/object/record-like collection of named fields/attributes.
    • ex.: Response = { data: Str, error: Str }
  • A constant:

    • A value that is always the same, and should be across languages.
      • THIS SHOULD NOT BE USED FOR SENSITIVE ITEMS LIKE PASSWORDS.
      • If you need something for sensitive things, maybe consider a dotenv vault or HashiCorp's Vault or something.
    • ex.: Meaning_Of_Life = 42

Type names in *.type files should be in Capitalized_Snake_Case. This is probably a weird choice at first glance, but we'll explain why it makes sense. It's all about name conversion when we generate files:

  • Converting from quiet_snake_case to camelCase or PascalCase, it's simple:
    • Remove the underscore and capitalize the following letter
    • BUT: What if you have a name like api_versions? That would become ApiVersions, which maybe you prefer the semantics of an entirely-capitalized "API".
  • Converting from camelCase or PascalCase to quiet_snake_case, it seems easy:
    • Add an underscore before capitalized letters (except the first one, for PascalCase), and lowercase all of them.
    • BUT: What if you have a name like APIVersions? That would become a_p_i_versions, which is gross, albeit understandable.
  • Capitalized_Snake_Case allows us to preserve capitalization and semantics, so it makes the most sense for creating types in any language's preferred casing. We want to make the cross-language types, and not make arguments over each language's preferred casing.

The basic structure of a *.type file is just a list of types. No header or module declarations needed, usually no imports (we'll get to those cases later), just types.

Comments are denoted with a #.

There is a strict constraint of indentation at the moment, and it must be the spacing set in datatypetool.toml |> spacing. If omitted, it will be 4 spaces.

To define a type, first define which type you need: alias, enum, model, or constant. Then, give it a Capitalized_Snake_Case name and a colon. Like YAML, colons open up an indented block below it for nested fields.

All types can have a meta field. This is for things specific to that type, that aren't a core part of the type. Things like doc strings, or lang-uage settings, or a ref-erence to another *.type file. The meta field is optional, if you don't need any of that.

Then, you need to do the actual type-defining.

If you are making an alias:

  • There must be a type field.
    • This is just the type that the alias is equivalent to.

Example:

alias Point:
    type:
        Tuple2 Float Float

If you are making an enum:

  • There must be a members field.
    • This contains the names of the enum variants.

Example:

enum Cardinal_Directions:
    members:
        North
        South
        East
        West

If you are making a model:

  • There must be a fields field.
    • This is each attribute of the datamodel.
    • Each field should contain a field with just the field's name, in Uppercase_Snake_Case, for conversion.
    • Each model-field must contain a field named type.
      • This contains the type intended for the field.

Example:

model Important_Data:
    fields:
        This:
            type:
                Str
        That:
            type:
                Nullable Int
        Where:
            type:
                Cardinal_Directions

If you are making a constant:

  • There must be a type field.
    • This is the type of the constant.
  • There must be a value field.
    • This is the value of the constant

Example:

constant Life:
    type:
        Int
    value:
        42