TOML (Tom's Obvious, Minimal Language)

repository·main·Indexed 12 days ago

https://github.com/toml-lang/toml

A minimal, human-readable configuration file format designed to map unambiguously to hash tables. TOML supports data types including strings, integers, floats, booleans, dates/times, arrays, and tables, providing a standardized alternative to JSON, YAML, and INI for configuration purposes.

Tokens
4.5K
Snippets
15
Records
19
Agent score
48%

What's inside TOML

  1. What is TOML?

    main
    TOML (Tom's Obvious, Minimal Language) is a minimal configuration file format designed to be easy to read due to obvious semantics. Its primary goal is to map unambiguously to a hash table and be easily parsed into data structures across a wide variety of programming languages.
  2. Format integers in TOML

    main

    Integers are whole numbers. They can be positive (prefixed with +) or negative (prefixed with -).

    Readability

    You can use underscores (_) between digits to enhance readability, provided each underscore is surrounded by at least one digit.

    Bases

    • Hexadecimal: Prefix with 0x (case-insensitive).
    • Octal: Prefix with 0o.
    • Binary: Prefix with 0b.

    Constraints

    • Leading zeros are not allowed in decimal integers.
    • In non-decimal formats (hex, octal, binary), leading zeros are allowed after the prefix.
    • Implementations should ideally support at least 64-bit signed integers.
    int1 = +99
    int2 = 42
    int3 = 0
    int4 = -17
    
    # Using underscores
    int5 = 1_000
    int6 = 5_349_221
    
    # Hexadecimal, Octal, and Binary
    hex1 = 0xDEADBEEF
    oct1 = 0o01234567
    bin1 = 0b11010110
  3. Use Arrays in TOML

    main

    Arrays are ordered values surrounded by square brackets []. They can contain values of the same type or mixed types. Whitespace is ignored, and elements are separated by commas. Arrays can span multiple lines and support trailing commas. Indentation is treated as whitespace and ignored.

    integers = [ 1, 2, 3 ]
    colors = [ "red", "yellow", "green" ]
    nested_arrays_of_ints = [ [ 1, 2 ], [3, 4, 5] ]
    nested_mixed_array = [ [ 1, 2 ], ["a", "b", "c"] ]
    string_array = [ "all", 'strings', """are the same""", '''type''' ]
    
    # Mixed-type arrays are allowed
    numbers = [ 0.1, 0.2, 0.5, 1, 2, 5 ]
    contributors = [
      "Foo Bar <foo@example.com>",
      { name = "Baz Qux", email = "bazqux@example.com", url = "https://example.com/bazqux" }
    ]
    
    # Multi-line arrays with trailing commas
    integers2 = [
      1, 2, 3
    ]
    
    integers3 = [
      1,
      2, # this is ok
    ]
  4. Represent dates and times in TOML

    main

    TOML provides several ways to represent temporal data, primarily based on RFC 3339.

    Offset Date-Time

    Represents a specific instant in time with an offset. Format: YYYY-MM-DDTHH:MM:SSZ or YYYY-MM-DDTHH:MM:SS-HH:MM.

    Local Date-Time

    Represents a date and time without any relation to an offset or timezone.

    Local Date

    Represents an entire day without any relation to an offset or timezone.

    Local Time

    Represents a time of day without any relation to a specific day or offset.

    Common Rules

    • Precision: Implementations must support at least millisecond precision. Extra digits should be truncated, not rounded.
    • Omitted Seconds: If seconds are omitted, :00 is assumed.
    • Delimiters: The T delimiter between date and time can be replaced by a space for readability.
    # Offset Date-Time
    o dt1 = 1979-05-27T07:32:00Z
    o dt2 = 1979-05-27 07:32:00-07:00
    
    # Local Date-Time
    ldt1 = 1979-05-27T07:32:00
    
    # Local Date
    ld1 = 1979-05-27
    
    # Local Time
    lt1 = 07:32:00
  5. Use Inline Tables for compact data

    main

    Inline tables provide a compact syntax for expressing tables using curly braces {}. They are useful for grouping nested data.

    Constraints:

    • Inline tables are fully self-contained. You cannot add keys or sub-tables to an inline table from outside its braces.
    • You cannot use an inline table to add keys to an already-defined standard table.
    name = { first = "Tom", last = "Preston-Werner" }
    point = {x=1, y=2}
    
    # Nested inline tables
    contact = {
        personal = {
            name = "Donald Duck",
            email = "donald@duckburg.com",
        },
        work = {
            name = "Coin cleaner",
            email = "donald@ScroogeCorp.com",
        },
    }
  6. Use Arrays of Tables

    main

    Arrays of tables are defined using double brackets [[header]]. The first instance defines the array and its first element; subsequent instances create new elements in the array. This is the TOML equivalent of a JSON array of objects.

    Rules:

    • Any reference to an array of tables points to the most recently defined element.
    • You can define sub-tables or sub-arrays of tables inside the most recent element.
    • Error Conditions:
      • You cannot define a sub-table for a parent that hasn't been defined yet.
      • You cannot append to a statically defined array (e.g., fruits = [] followed by [[fruits]] is invalid).
      • You cannot redefine a table as an array or vice versa.
    [[product]]
    name = "Hammer"
    sku = 738594937
    
    [[product]]  # empty table within the array
    
    [[product]]
    name = "Nail"
    sku = 284758393
    color = "gray"
    
    # Nested array of tables within an array of tables
    [[fruits]]
    name = "apple"
    
    [fruits.physical]
    color = "red"
    shape = "round"
    
    [[fruits.varieties]]
    name = "red delicious"
    
    [[fruits.varieties]]
    name = "granny smith"
  7. Express strings in TOML

    main

    TOML supports four types of strings. All strings must contain only Unicode characters. For binary data, use external encoding like Base64 instead of escape codes.

    1. Basic Strings

    Surrounded by double quotes ("). They allow escape sequences for special characters.

    2. Multi-line Basic Strings

    Surrounded by triple double quotes ("""). They allow newlines. A newline immediately following the opening delimiter is trimmed. You can use a "line ending backslash" (\) to break long strings across lines without introducing extra whitespace.

    3. Literal Strings

    Surrounded by single quotes ('). They do not allow any escaping; what you see is what you get. This is ideal for Windows paths or regular expressions. They must be on a single line.

    4. Multi-line Literal Strings

    Surrounded by triple single quotes ('''). They allow newlines and do not allow escaping. A newline immediately following the opening delimiter is trimmed. You can use up to two single quotes inside these strings, but sequences of three or more are not permitted.

    # Basic string
    str = "I'm a string. \"You can quote me\"."
    
    # Multi-line basic string
    str1 = """
    Roses are red
    Violets are blue"""
    
    # Multi-line basic string with line-ending backslash
    str2 = """
    The quick brown \
    \n  fox jumps over \\n    the lazy dog."""
    
    # Literal string (no escaping)
    winpath = 'C:\Users\nodejs\templates'
    
    # Multi-line literal string
    lines = '''
    The first newline is
    trimmed in literal strings.
    '''
  8. Manage Nested Tables with Dotted Keys

    main

    Dotted keys allow you to build nested structures. When you use a dotted key, you are effectively defining a table.

    Rules for nesting:

    • You can add to a table as long as the key hasn't been directly defined as a non-table value.
    • Invalid Pattern: You cannot turn an existing value (like an integer) into a table. If fruit.apple = 1 is defined, you cannot later define fruit.apple.smooth = true.
    • Best Practice: Define dotted keys in an organized manner. It is recommended to define all properties for a specific branch before moving to the next to avoid confusion.

    Warning on Numeric Dotted Keys: If you use a dotted key that looks like a float (e.g., 3.14159), it will be interpreted as a 2-part dotted key (a nested structure) rather than a float value.

    # Valid: Creating a table via dotted keys
    fruit.apple.smooth = true
    fruit.orange = 2
    
    # INVALID: Trying to turn an integer into a table
    fruit.apple = 1
    fruit.apple.smooth = true
    
    # WARNING: This is a nested structure, NOT a float
    3.14159 = "pi" 
    # Maps to: { "3": { "14159": "pi" } }
  9. Use Bare, Quoted, and Dotted Keys

    main

    TOML supports three types of keys:

    1. Bare keys: Contain only ASCII letters, digits, underscores, and dashes (A-Za-z0-9_-). They are interpreted as strings even if they consist only of digits.
    2. Quoted keys: Follow the rules of basic or literal strings. Use these when you need special characters or spaces. Best practice is to use bare keys whenever possible.
    3. Dotted keys: A sequence of bare or quoted keys joined by dots. This creates a nested structure (tables) similar to JSON objects.

    Important Notes:

    • An empty quoted key ("" = "blank") is valid but discouraged.
    • You cannot use multi-line strings to define quoted keys.
    • Defining a key multiple times is invalid.
    • Dotted keys can be used to define tables implicitly.
    # Bare keys
    key = "value"
    bare_key = "value"
    bare-key = "value"
    1234 = "value"
    
    # Quoted keys
    "127.0.0.1" = "value"
    "character encoding" = "value"
    'key2' = "value"
    
    # Dotted keys (creates nested structure)
    name = "Orange"
    physical.color = "orange"
    physical.shape = "round"
    site."google.com" = true
  10. Compare TOML with JSON, YAML, and INI

    main

    Understanding how TOML relates to other formats can help determine if it is the right choice for your use case:

    • vs. JSON: Like JSON, TOML is simple and uses ubiquitous data types, making it easy to parse. However, unlike JSON, TOML allows comments.
    • vs. YAML: Like YAML, TOML emphasizes human readability and supports comments. However, TOML maintains a higher level of simplicity compared to YAML.
    • vs. INI: While similar in syntax and use case, TOML is a standardized format that handles deep nesting gracefully, whereas INI lacks a standard and struggles with more than one or two levels of nesting.

    Important Limitations: TOML is intended for configuration, not for serializing arbitrary data structures. It always requires a hash table at the top level and does not permit top-level arrays or floats. Additionally, there is no standard identifier for the start or end of a file, so streaming TOML requires application-layer negotiation.

  11. Understand TOML Preliminaries

    main

    Before writing TOML, be aware of these fundamental rules:

    • Case-sensitivity: TOML is case-sensitive.
    • Whitespace: Whitespace consists of tabs (U+0009) and spaces (U+0020).
    • Newlines: Newlines are LF (U+000A) or CRLF (U+000D U+000A).
    • Encoding: A TOML file must be a valid UTF-8 encoded Unicode document.
  12. Format floats in TOML

    main

    A float consists of an integer part followed by a fractional part and/or an exponent part.

    Syntax

    • Fractional part: A decimal point followed by one or more digits.
    • Exponent part: An E or e followed by an integer part.
    • Underscores: Allowed between digits for readability.

    Special Values

    Special float values must be lowercase:

    • inf or +inf: positive infinity
    • -inf: negative infinity
    • nan: not a number
    • +nan: same as nan
    • -nan: negative NaN

    Invalid Floats

    Decimal points must be surrounded by digits. The following are invalid:

    • .7 (missing leading digit)
    • 7. (missing trailing digit)
    • 3.e+20 (missing fractional digits before exponent)

    Implementations should ideally support at least IEEE 754 binary64 values.

    flt1 = +1.0
    flt2 = 3.1415
    flt4 = 5e+22
    flt7 = 6.626e-34
    
    # Underscores
    flt8 = 224_617.445_991_228
    
    # Special values
    sf1 = inf
    sf4 = nan