*.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
- A value that is always the same, and should be across languages.
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
typefield.- 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
membersfield.- 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
fieldsfield.- 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
typefield.- This is the type of the constant.
- There must be a
valuefield.- This is the value of the constant
Example:
constant Life:
type:
Int
value:
42