v1.0.0
Publicado em 4/3/2020 – Versão de texto

TOML v1.0.0-rc.1

Tom's Obvious, Minimal Language.

Por Tom Preston-Werner, Pradyun Gedam, et al.

Objetivos

TOML visa ser um formato de arquivo de configuração mínimo que seja fácil de ler devido à semântica óbvia. O TOML foi projetado para mapear inequivocamente para uma tabela de hash. O TOML deve ser fácil de analisar em estruturas de dados em uma ampla variedade de idiomas.

Exemplo

# Este é um documento TOML.

título = "Exemplo do TOML"

[dono]
nome = "Tom Preston-Werner"
dtnasc = 1979-05-27T07:32:00-0800 # Datas da primeira classe

[banco-de-dados]
servidor = "192.168.1.1"
portas = [ 8001, 8001, 8002 ]
max_conexoes = 5000
habilitado = true

[servidores]

  # Recuo (tabulações e/ou espaços) é permitido, mas não necessário
  [servidores.alfa]
  ip = "10.0.0.1"
  dc = "eqdc10"

  [servidores.beta]
  ip = "10.0.0.2"
  dc = "eqdc10"

[clientes]
dados = [ ["gama", "delta"], [1, 2] ]

# Quebras de linha são aceitas dentro de arrays
hosts = [
  "alfa",
  "omega"
]

Especificação

  • TOML é case-sensitive, ou seja, diferencia maiúsculo de minúsculo.
  • Um arquivo TOML deve ser um documento Unicode válido codificado em UTF-8.
  • Espaço em branco significa tabulação (0x09) ou espaço (0x20).
  • Nova linha significa LF (0x0A) ou CRLF (0x0D 0x0A).

Comentário

Um símbolo de cerquilha marca o resto da linha como um comentário, exceto quando dentro de uma string.

# Este é um comentário de linha completa
chave = "valor"  # Este é um comentário ao final de uma linha
outro = "# Este não é um comentário"

Caracteres de controle diferentes de tabulação (U+0000 a U+0008, U+000A a U+001F, U+007F) não são permitidos nos comentários.

Par chave/valor

O bloco de construção fundamental de um documento TOML é o par chave/valor.

As chaves estão à esquerda do sinal de igual e os valores à direita. O espaço em branco é ignorado em torno de nomes e valores de chave. A chave, o sinal de igual e o valor devem estar na mesma linha (embora alguns valores possam ser divididos em várias linhas).

chave = "valor"

Os valores devem ter um dos tipos a seguir.

Valores não especificados são inválidos.

chave = # INVÁLIDO

Deve haver uma nova linha após um par chave/valor. (Consulte Tabela inline para ver as exceções.)

nome = "Tom" sobrenome = "Preston-Werner" # INVÁLIDO

Chaves

Uma chave pode ser simples, entre aspas ou pontilhada.

Chaves simples podem conter apenas letras ASCII, dígitos ASCII, underscores e traços (A-Za-z0-9_-). Observe que as chaves simples podem ser compostas apenas por dígitos ASCII, por exemplo 1234, mas são sempre interpretados como strings.

chave = "valor"
chave_simples = "valor"
chave-simples = "valor"
1234 = "valor"

Chaves entre aspas seguem exatamente as mesmas regras de strings básicas ou strings literais, e permitem que você use um conjunto muito mais amplo de nomes de chaves. A melhor prática é usar chaves simples, exceto quando absolutamente necessário.

"127.0.0.1" = "valor"
"codificação de caracteres" = "valor"
"ǝʌɐɥɔ" = "valor"
'chave2' = "valor"
'"valor" entre aspas' = "valor"

Uma chave simples não deve estar vazia, mas uma chave entre aspas vazia é permitida (embora desencorajada).

= "sem nome de chave"  # INVÁLIDO
"" = "vazio"     # VÁLIDO, mas desencorajado
'' = 'vazio'     # VÁLIDO, mas desencorajado

Chaves pontilhadas são uma sequência de chaves simples ou entre aspas unidas por um ponto. Isso permite agrupar propriedades semelhantes:

nome = "Laranja"
fisico.cor = "laranja"
fisico.forma = "redonda"
site."google.com" = true

Na terra do JSON, isso resultaria na seguinte estrutura:

{
  "nome": "Laranja",
  "fisico": {
    "cor": "laranja",
    "forma": "redonda"
  },
  "site": {
    "google.com": true
  }
}

Os espaços em branco ao redor das partes separadas por pontos são ignorados. No entanto, a melhor prática é não usar nenhum espaço em branco estranho.

A definição de uma chave várias vezes é inválido.

# NÃO FAÇA ISSO
nome = "Tom"
nome = "Pradyun"

Como as chaves simples podem ser compostas apenas por inteiros ASCII, é possível escrever chaves pontilhadas que se parecem com pontos flutuantes, mas são chaves pontilhadas de 2 partes. Não faça isso a menos que tenha um bom motivo para isso (provavelmente não há).

3.14159 = "pi"

O TOML acima é mapeado para o seguinte JSON.

{ "3": { "14159": "pi" } }

Desde que uma chave não tenha sido definida diretamente, você ainda pode escrever nela e nos nomes dentro dela.

# Isso torna a chave "fruta" uma tabela.
fruta.uva.suave = true

# Então, você pode adicionar à tabela "fruta" desta forma:
fruta.laranja = 2
# O EXEMPLO A SEGUIR É INVÁLIDO

# Isso define o valor de fruta.uva como um inteiro.
fruta.uva = 1

# Mas então isso trata a fruta.uva como se fosse uma tabela.
# Você não pode transformar um número inteiro em uma tabela.
fruta.uva.suave = true

A definição de chaves pontilhadas fora de ordem é desencorajada.

# VÁLIDO, MAS DESENCORAJADO

uva.tipo = "fruta"
laranja.tipo = "fruta"

uva.casca = "fina"
laranja.casca = "espessa"

uva.cor = "roxa"
laranja.cor = "laranja"
# RECOMENDADO

uva.tipo = "fruta"
uva.casca = "fina"
uva.cor = "roxa"

laranja.tipo = "fruta"
laranja.casca = "espessa"
laranja.cor = "laranja"

String

Há quatro maneiras de expressar strings: básica, básica multilinha, literal e literal multilinha. Todas as strings devem conter apenas caracteres UTF-8 válidos.

Strings básicas são delimitadas por aspas. Qualquer caractere Unicode pode ser usado, exceto aqueles que devem ter escape: aspas, barra invertida e os caracteres de controle que não sejam tabulação (U+0000 a U+0008, U+000A a U+001F, U+007F).

str = "Sou uma string. \"Você me colocar entre aspas\". Nome\tJos\u00E9\nLocal\tSF."

Por conveniência, alguns caracteres populares têm uma sequência de escape compacta.

\b         - backspace         (U+0008)
\t         - tabulações        (U+0009)
\n         - linefeed          (U+000A)
\f         - form feed         (U+000C)
\r         - carriage return   (U+000D)
\"         - aspas             (U+0022)
\\         - barra invertida   (U+005C)
\uXXXX     - unicode           (U+XXXX)
\UXXXXXXXX - unicode           (U+XXXXXXXX)

Qualquer caractere Unicode pode ter escape com as formas \uXXXX ou \UXXXXXXXX. Os códigos de escape devem ser valores escalares em Unicode válido.

Todas as outras sequências de escape não listadas acima são reservadas e, se forem usadas, TOML deve produzir um erro.

Às vezes, você precisa expressar passagens de texto (por exemplo, arquivos de tradução) ou deseja dividir uma string muito longa em várias linhas. O TOML torna isso fácil.

Strings básicas multilinha são delimitadas por três aspas em cada lado e permitem novas linhas. Uma nova linha imediatamente após o delimitador de abertura será cortada. Todos os outros espaços em branco e caracteres de nova linha permanecem intactos.

str1 = """
Rosas são vermelhas
Violetas são azuis"""

Os analisadores TOML devem se sentir à vontade para normalizar a nova linha para o que fizer sentido para sua plataforma.

# Em um sistema Unix, a string multilinha acima provavelmente será a mesma que:
str2 = "Rosas são vermelhas\nVioletas são azuis"

# Em um sistema Windows, provavelmente será equivalente a:
str3 = "Rosas são vermelhas\r\nVioletas são azuis"

Para escrever strings longas sem introduzir espaços em branco estranhos, use uma "barra invertida de final de linha". Quando o último caractere diferente de espaço em branco em uma linha for um \, ele será cortado junto com todos os espaços em branco (incluindo novas linhas) até o próximo caractere diferente de espaço em branco ou delimitador de fechamento. Todas as sequências de escape que são válidas para strings básicas também são válidas para strings básicas multilinha.

# As seguintes strings são equivalentes byte a byte:
str1 = "A rápida raposa marrom pula sobre o cachorro preguiçoso."

str2 = """
A rápida raposa \


  marrom pula sobre o \
    cachorro preguiçoso."""

str3 = """\
       A rápida raposa \
       marrom pula sobre o \
       cachorro preguiçoso.\
       """

Qualquer caractere Unicode pode ser usado, exceto aqueles que devem ser escapados: barra invertida e os caracteres de controle diferentes de tabulação, line feed e carriage return (U+0000 a U+0008, U+000B, U+000C, U+000E a U+001F, U+007F).

Você pode escrever uma aspa, ou duas aspas adjacentes, em qualquer lugar dentro de uma string básica de várias linhas. Eles também podem ser escritos apenas dentro dos delimitadores.

str4 = """Aqui estão duas aspas: "". Simples o suficiente."""
# str5 = """Aqui estão três aspas: """."""  # INVÁLIDO
str5 = """Aqui estão três aspas: ""\"."""
str6 = """Aqui estão quinze aspas: ""\"""\"""\"""\"""\"."""

# "Esta," disse ela, "é apenas uma declaração sem sentido."
str7 = """"Esta," disse ela, "é apenas uma declaração sem sentido.""""

Se você com frequência especifica caminhos do Windows ou expressões regulares, ter que fazer escape de barras invertidas rapidamente se torna tedioso e sujeito a erros. Para ajudar, o TOML oferece suporte a strings literais que não permitem escape.

Strings literais são delimitadas entre aspas simples. Como strings básicas, elas devem aparecer em uma única linha:

# O que você vê é o que você obtém.
winpath  = 'C:\Users\nodejs\templates'
winpath2 = '\\ServerX\admin$\system32\'
com_aspas = 'Tom "Dubs" Preston-Werner'
regex    = '<\i\c*\s*>'

Como não há escape, não há como escrever uma aspa simples dentro de uma string literal entre aspas simples. Felizmente, o TOML oferece suporte a uma versão multilinha de strings literais que resolve esse problema.

Strings literais multilinha são delimitadas por três aspas simples de cada lado e permitem novas linhas. Como strings literais, não há como fazer escape. Uma nova linha imediatamente após o delimitador de abertura será apagada. Todos os outros conteúdos entre os delimitadores são interpretados como estão, sem modificação.

regex2 = '''Eu( não)? preciso de \d{2} maçãs'''
linhas = '''
A primeira nova linha é
cortada em strings brutas.
   Todos os outros espaços
   em branco são preservados.
'''

Você pode escrever 1 ou 2 aspas simples em qualquer lugar dentro de uma string literal multilinha, mas sequências de três ou mais aspas simples não são permitidas.

aspas15 = '''Aqui estão quinze aspas: """""""""""""""'''

# apos15 = '''Aqui estão quinze apóstrofos: ''''''''''''''''''  # INVÁLIDO
apos15 = "Aqui estão quinze apóstrofos: '''''''''''''''"

# 'Isso,' disse ela, 'ainda não tem sentido.'
str = ''''Isso,' disse ela, 'ainda não tem sentido.''''

Caracteres de controle diferentes de tabulação não são permitidos em uma string literal. Portanto, para dados binários, é recomendável usar Base64 ou outra codificação ASCII ou UTF-8 adequada. A manipulação dessa codificação será específica do aplicativo.

Inteiro

Inteiros são números inteiros. Números positivos podem ser prefixados com um sinal de mais. Números negativos são prefixados com um sinal de menos.

int1 = +99
int2 = 42
int3 = 0
int4 = -17

Para números grandes, você pode usar underscores entre os dígitos para melhorar a legibilidade. Cada underscore deve ser envolto por pelo menos um dígito.

int5 = 1_000
int6 = 5_349_221
int7 = 1_2_3_4_5     # VÁLIDO, mas desencorajado

Zeros à esquerda não são permitidos. Valores inteiros -0 e +0 são válidos e idênticos a um zero sem prefixo.

Valores inteiros não negativos também podem ser expressos em hexadecimal, octal ou binário. Nesses formatos, + à esquerda não é permitido e zeros à esquerda são permitidos (após o prefixo). Os valores hexadecimais não diferenciam maiúsculas de minúsculas. Underscores são permitidos entre dígitos (mas não entre o prefixo e o valor).

# hexadecimal com prefixo `0x`
hex1 = 0xDEADBEEF
hex2 = 0xdeadbeef
hex3 = 0xdead_beef

# octal com prefixo `0o`
oct1 = 0o01234567
oct2 = 0o755 # útil para permissões de arquivos do Unix

# binário com prefixo `0b`
bin1 = 0b11010110

Intervalos de 64 bits (longo com sinal) são esperados (−9,223,372,036,854,775,808 to 9,223,372,036,854,775,807).

Ponto flutuante

Os pontos flutuantes, ou floats, devem ser implementados como valores IEEE 754 binary64.

Um ponto flutuante consiste em uma parte inteira (que segue as mesmas regras dos valores inteiros decimais) seguida por uma parte fracionária e/ou uma parte expoente. Se uma parte fracionária e uma parte expoente estiverem presentes, a parte fracionária deve preceder a parte expoente.

# fracionário
flt1 = +1.0
flt2 = 3.1415
flt3 = -0.01

# expoente
flt4 = 5e+22
flt5 = 1e06
flt6 = -2E-2

# ambos
flt7 = 6.626e-34

Uma parte fracionária é um ponto decimal seguido por um ou mais dígitos.

Uma parte expoente é um E (maiúsculo ou minúsculo) seguido por uma parte inteira (que segue as mesmas regras dos valores inteiros decimais, mas pode incluir zeros à esquerda).

Como inteiros, você pode usar underscores para melhorar a legibilidade. Cada underscore deve ser envolto por pelo menos um dígito.

flt8 = 224_617.445_991_228

Os valores de pontos flutuantes -0.0 e +0.0 são válidos e devem ser mapeados de acordo com o IEEE 754.

Valores de pontos flutuantes especiais também podem ser expressos. Eles são sempre minúsculos.

# infinito
sf1 = inf  # infinito positivo
sf2 = +inf # infinito positivo
sf3 = -inf # infinito negativo

# não um número (not a number)
sf4 = nan  # a codificação sNaN/qNaN real é específica da implementação
sf5 = +nan # mesmo que `nan`
sf6 = -nan # válida, a codificação real é específica da implementação

Booleano

Booleanos são apenas os tokens com os quais você está acostumado. Sempre minúsculos.

bool1 = true
bool2 = false

Data e hora com deslocamento

Para representar inequivocamente um instante específico no tempo, você pode usar uma data hora formatada em RFC 3339 com deslocamento.

odt1 = 1979-05-27T07:32:00Z
odt2 = 1979-05-27T00:32:00-07:00
odt3 = 1979-05-27T00:32:00.999999-07:00

Para facilitar a leitura, você pode substituir o delimitador T entre data e hora por um caractere de espaço (conforme permitido pela RFC 3339 seção 5.6).

odt4 = 1979-05-27 07:32:00Z

A precisão de segundos fracionários é específica da implementação, mas a precisão de milissegundos é esperada. Se o valor contiver uma precisão maior do que a implementação pode suportar, a precisão adicional deverá ser truncada, não arredondada.

Data e hora local

Se você omitir o deslocamento de uma data/hora formatada em RFC 3339, ele representará a data/hora fornecida sem qualquer relação com um deslocamento ou fuso horário. Não pode ser convertido para um instante no tempo sem informações adicionais. A conversão para um instante, se necessário, é específica da implementação.

ldt1 = 1979-05-27T07:32:00
ldt2 = 1979-05-27T00:32:00.999999

A precisão de segundos fracionários é específica da implementação, mas a precisão de milissegundos é esperada. Se o valor contiver uma precisão maior do que a implementação pode suportar, a precisão adicional deverá ser truncada, não arredondada.

Data local

Se você incluir apenas a parte da data de uma data/hora formatada em RFC 3339, ela representará o dia inteiro sem qualquer relação com um deslocamento ou fuso horário.

ld1 = 1979-05-27

Hora local

Se você incluir apenas a parte da hora de uma data/hora formatada em RFC 3339, ela representará essa hora do dia sem qualquer relação com um dia específico ou qualquer deslocamento ou fuso horário.

lt1 = 07:32:00
lt2 = 00:32:00.999999

A precisão de segundos fracionários é específica da implementação, mas a precisão de milissegundos é esperada. Se o valor contiver uma precisão maior do que a implementação pode suportar, a precisão adicional deverá ser truncada, não arredondada.

Array

Arrays são colchetes com valores dentro. O espaço em branco é ignorado. Os elementos são separados por vírgulas. Os arrays podem conter valores dos mesmos tipos de dados permitidos em pares chave/valor. Valores de tipos diferentes podem ser misturados.

inteiros = [ 1, 2, 3 ]
cores = [ "vermelho", "amarelo", "verde" ]
arrays_aninhados_de_ints = [ [ 1, 2 ], [3, 4, 5] ]
array_aninhado_misturado = [ [ 1, 2 ], ["a", "b", "c"] ]
array_de_strings = [ "todas", 'strings', """são do mesmo""", '''tipo''' ]

# Arrays com tipo misturado são permitidos
numeros = [ 0.1, 0.2, 0.5, 1, 2, 5 ]
contribuidores = [
  "Foo Bar <foo@example.com>",
  { nome = "Baz Qux", email = "bazqux@example.com", url = "https://example.com/bazqux" }
]

Arrays podem abranger várias linhas. Uma vírgula de terminação (também chamada de vírgula à direita) é permitida após o último valor do array. Pode haver uma quantidade arbitrária de novas linhas e comentários antes de um valor e antes de colchete de fechamento.

inteiros2 = [
  1, 2, 3
]

inteiros3 = [
  1,
  2, # tudo bem
]

Tabela

Tabelas (também conhecidas como tabelas hash ou dicionários) são coleções de pares chave/valor. Elas aparecem entre colchetes em uma linha própria. Você pode diferenciá-las de arrays porque os arrays são apenas valores.

[tabela]

Abaixo disso, e até o próximo cabeçalho ou EOF, estão as chaves/valores dessa tabela. Não há garantia de que os pares chave/valor nas tabelas estejam em uma ordem específica.

[tabela-1]
chave1 = "mesma string"
chave2 = 123

[tabela-2]
chave1 = "outra string"
chave2 = 456

As regras de nomenclatura para tabelas são as mesmas que para chaves (consulte a definição de Chaves acima).

[cachorro."homem.batatinha"]
tipo.nome = "pug"

Na terra do JSON, isso resultaria na seguinte estrutura:

{ "cachorro": { "homem.batatinha": { "tipo": { "nome": "pug" } } } }

O espaço em branco ao redor da chave é ignorado. No entanto, a melhor prática é não usar nenhum espaço em branco estranho.

[a.b.c]            # esta é a melhor prática
[ d.e.f ]          # mesmo que [d.e.f]
[ g .  h  . i ]    # mesmo que [g.h.i]
[ j . "ʞ" . 'l' ]  # mesmo que [j."ʞ".'l']

Você não precisa especificar todas as supertabelas se não quiser. TOML sabe como fazer isso para você.

# [x] você
# [x.y] não
# [x.y.z] precisa disso
[x.y.z.w] # para que isso funcione

[x] # não tem problema definir uma supertabela posteriormente

Tabelas vazias são permitidas e simplesmente não possuem pares chave/valor dentro delas.

Assim como as chaves, você não pode definir uma tabela mais de uma vez. Fazer isso é inválido.

# NÃO FAÇA ISSO

[fruta]
uva = "roxa"

[fruta]
laranja = "laranja"
# TAMBÉM NÃO FAÇA ISSO

[fruta]
uva = "roxa"

[fruta.uva]
textura = "suave"

A definição de tabelas fora de ordem é desencorajado.

# VÁLIDO, MAS DESENCORAJADO
[fruta.uva]
[animal]
[fruta.laranja]
# RECOMENDADO
[fruta.uva]
[fruta.laranja]
[animal]

Chaves pontilhadas definem tudo à esquerda de cada ponto como uma tabela. Como as tabelas não podem ser definidas mais de uma vez, não é permitido redefinir tais tabelas usando um cabeçalho [tabela]. Da mesma forma, não é permitido usar chaves pontilhadas para redefinir tabelas já definidas na forma [tabela].

A forma [tabela] pode, no entanto, ser usada para definir subtabelas dentro de tabelas definidas por meio de chaves pontilhadas.

[fruta]
uva.cor = "roxa"
uva.sabor.doce = true

# [fruta.uva]  # INVÁLIDO
# [fruta.uva.sabor]  # INVÁLIDO

[fruta.uva.textura]  # você pode adicionar subtabelas
suave = true

Tabela inline

As tabelas inline fornecem uma sintaxe mais compacta para expressar tabelas. Elas são especialmente úteis para dados agrupados que, de outra forma, podem rapidamente se tornar detalhadas. As tabelas inline são definidas entre chaves: { e }. Dentro das chaves, zero ou mais pares chave/valor separados por vírgulas podem aparecer. Os pares chave/valor assumem o mesmo formato que os pares chave/valor nas tabelas padrão. Todos os tipos de valor são permitidos, incluindo tabelas inline.

As tabelas inline devem aparecer em uma única linha. Uma vírgula de terminação (também chamada de vírgula à direita) não é permitida após o último par chave/valor em uma tabela inline. Nenhuma nova linha é permitida entre as chaves, a menos que sejam válidas dentro de um valor. Mesmo assim, é altamente desencorajado quebrar uma tabela inline em várias linhas. Se você se sentir dominado por esse desejo, isso significa que você deve usar tabelas padrão.

nome = { nome = "Tom", sobrenome = "Preston-Werner" }
ponto = { x = 1, y = 2 }
animal = { tipo.nome = "pug" }

As tabelas inline acima são idênticas às seguintes definições de tabela padrão:

[nome]
nome = "Tom"
sobrenome = "Preston-Werner"

[ponto]
x = 1
y = 2

[animal]
tipo.nome = "pug"

As tabelas inline definem todas as chaves e subtabelas dentro delas. Chaves e subtabelas não podem ser adicionadas fora das chaves.

[produto]
tipo = { nome = "Prego" }
# tipo.comestivel = false  # INVÁLIDO

Da mesma forma, as tabelas inline não podem ser usadas para adicionar chaves ou subtabelas a uma tabela já definida.

[produto]
tipo.nome = "Prego"
# tipo = { comestivel = false }  # INVÁLIDO

Array de tabelas

O último tipo que ainda não foi expressado é um array de tabelas. Eles podem ser expressos usando um nome de tabela entre colchetes duplos. Abaixo disso, e até a próxima tabela ou EOF, estão as chaves/valores dessa tabela. Cada tabela com o mesmo nome entre colchetes duplos será um elemento no array de tabelas. As tabelas são inseridas na ordem encontrada. Uma tabela com colchetes duplos sem nenhum par chave/valor será considerada uma tabela vazia.

[[produtos]]
nome = "Martelo"
sku = 738594937

[[produtos]]

[[produtos]]
nome = "Prego"
sku = 284758393

cor = "cinza"

Na terra do JSON, isso resultaria na seguinte estrutura.

{
  "produtos": [
    { "nome": "Martelo", "sku": 738594937 },
    { },
    { "nome": "Prego", "sku": 284758393, "color": "cinza" }
  ]
}

Você também pode criar arrays aninhados de tabelas. Basta usar a mesma sintaxe de colchetes duplos nas subtabelas. Cada subtabela entre colchetes pertencerá ao elemento de tabela definido mais recentemente. Da mesma forma, subtabelas normais (não arrays) pertencem ao elemento de tabela definido mais recentemente.

[[fruta]]
  nome = "uva"

  [fruta.fisico]  # subtabela
    cor = "roxa"
    forma = "redonda"

  [[fruta.variedade]]  # arrays aninhados de tabelas
    nome = "roxa deliciosa"

  [[fruta.variedade]]
    nome = "cabernet sauvignon"

[[fruta]]
  nome = "banana"

  [[fruta.variedade]]
    nome = "banana-da-terra"

O TOML acima é mapeado para o seguinte JSON.

{
  "fruta": [
    {
      "nome": "uva",
      "fisico": {
        "cor": "roxa",
        "forma": "redonda"
      },
      "variedade": [
        { "nome": "roxa deliciosa" },
        { "nome": "cabernet sauvignon" }
      ]
    },
    {
      "nome": "banana",
      "variedade": [
        { "nome": "banana-da-terra" }
      ]
    }
  ]
}

Se o pai de uma tabela ou array de tabelas for um elemento array, esse elemento já deve ter sido definido antes que o filho possa ser definido. As tentativas de inverter essa ordem devem produzir um erro no momento da análise.

# DOCUMENTO TOML INVÁLIDO
[fruta.fisico]  # subtabela, mas a qual elemento pai ela pertence?
  cor = "roxa"
  forma = "redonda"

[[fruta]]  # o analisador sintático deve lançar um erro ao descobrir
           # que "fruta" é um array em vez de uma tabela
  nome = "uva"

A tentativa de anexar a um array definido estaticamente, mesmo que esse array esteja vazio ou seja de tipo compatível, deve produzir um erro no momento da análise.

# DOCUMENTO TOML INVÁLIDO
fruta = []

[[fruta]] # Não permitido

A tentativa de definir uma tabela normal com o mesmo nome de um array já estabelecido deve produzir um erro no momento da análise. A tentativa de redefinir uma tabela normal como um array também deve produzir um erro de tempo de análise.

# DOCUMENTO TOML INVÁLIDO
[[fruta]]
  nome = "uva"

  [[fruta.variedade]]
    nome = "roxa deliciosa"

  # INVÁLIDO: Esta tabela conflita com o array de tabelas anterior
  [fruta.variedade]
    nome = "cabernet sauvignon"

  [fruta.fisico]
    cor = "roxa"
    forma = "redonda"

  # INVÁLIDO: Este array de tabelas conflita com a tabela anterior
  [[fruta.fisico]]
    cor = "verde"

Você também pode usar tabelas inline quando apropriado:

pontos = [ { x = 1, y = 2, z = 3 },
           { x = 7, y = 8, z = 9 },
           { x = 2, y = 4, z = 8 } ]

Extensão de nome de arquivo

Os arquivos TOML devem usar a extensão .toml.

Tipo MIME

Ao transferir arquivos TOML pela Internet, o tipo MIME apropriado é application/toml.

Comparação com outros formatos

O TOML compartilha características com outros formatos de arquivo usados para configuração de aplicativos e serialização de dados, como YAML e JSON. TOML e JSON são simples e usam tipos de dados onipresentes, tornando-os fáceis de codificar ou analisar com máquinas. TOML e YAML enfatizam recursos de legibilidade humana, como comentários que facilitam a compreensão do propósito de uma determinada linha. O TOML difere em combiná-los, permitindo comentários (ao contrário do JSON), mas preservando a simplicidade (ao contrário do YAML).

Como o TOML é explicitamente planejado como um formato de arquivo de configuração, sua análise é fácil, mas não se destina à serialização de estruturas de dados arbitrárias. TOML sempre tem uma tabela hash no nível superior do arquivo, que pode facilmente ter dados aninhados dentro de suas chaves, mas não permite arrays ou pontos flutuantes de topo de nível, portanto, não pode serializar diretamente alguns dados. Também não há um padrão que identifique o início ou o fim de um arquivo TOML, o que pode complicar o envio por meio de um fluxo. Esses detalhes devem ser negociados na camada de aplicação.

Os arquivos INI são frequentemente comparados ao TOML por suas semelhanças na sintaxe e uso como arquivos de configuração. No entanto, não há formato padronizado para INI e eles não lidam normalmente com mais de um ou dois níveis de aninhamento.

Leitura adicional:

Participe

Documentação, relatórios de erros, pull requests e outras contribuições são bem-vindas!

Wiki

Temos uma wiki oficial do TOML que cataloga o seguinte:

  • Projetos usando TOML
  • Implementações
  • Validadores
  • Conjunto de testes agnósticos de linguagem para codificadores e decodificadores TOML
  • Suporte em editores
  • Codificadores
  • Conversores

Por favor, dê uma olhada se você gostaria de ver ou adicionar a essa lista. Obrigado por fazer parte da comunidade TOML!