├── .gitattributes ├── .pre-commit-config.yaml ├── .prettierrc.toml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── docs └── README.md ├── logos ├── toml-100.png ├── toml-200.png ├── toml-400.png ├── toml.ai └── toml.svg ├── scripts └── release.py ├── toml.abnf └── toml.md /.gitattributes: -------------------------------------------------------------------------------- 1 | toml.abnf text eol=crlf 2 | /scripts/* linguist-detectable=false 3 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/mirrors-prettier 3 | rev: v4.0.0-alpha.8 4 | hooks: 5 | - id: prettier 6 | 7 | - repo: https://github.com/pre-commit/pre-commit-hooks 8 | rev: v5.0.0 9 | hooks: 10 | - id: check-added-large-files 11 | - id: check-case-conflict 12 | - id: end-of-file-fixer 13 | - id: forbid-new-submodules 14 | - id: trailing-whitespace 15 | exclude: .*/toml\.ai 16 | args: [--markdown-linebreak-ext=md] 17 | -------------------------------------------------------------------------------- /.prettierrc.toml: -------------------------------------------------------------------------------- 1 | proseWrap = "always" 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # TOML Changelog 2 | 3 | ## unreleased 4 | 5 | - Allow newlines and trailing commas in inline tables ([#904]). 6 | 7 | Previously an inline table had to be on a single line and couldn't end with a 8 | trailing comma. This is now relaxed so that the following is valid: 9 | 10 | tbl = { 11 | key = "a string", 12 | moar-tbl = { 13 | key = 1, 14 | }, 15 | } 16 | 17 | - Add `\xHH` notation to basic strings for codepoints <255 ([#796]): 18 | 19 | null = "null byte: \x00; letter a: \x61" 20 | 21 | - Add `\e` escape for the escape character ([#790]): 22 | 23 | csi = "\e[" 24 | 25 | - Seconds in datetime and time values are now optional ([#894]). The following 26 | are now valid: 27 | 28 | dt = 2010-02-03 14:15 29 | t = 14:15 30 | 31 | - Clarify that comments never affect the tables produced by parsers ([#950]). 32 | 33 | - Clarify Unicode and UTF-8 references ([#929]). 34 | 35 | - Clarify where and how dotted keys define tables ([#859]). 36 | 37 | - Clarify newline normalization in multi-line literal strings ([#842]). 38 | 39 | - Clarify sub-millisecond precision is allowed ([#805]). 40 | 41 | [#790]: https://github.com/toml-lang/toml/pull/790 42 | [#796]: https://github.com/toml-lang/toml/pull/796 43 | [#805]: https://github.com/toml-lang/toml/pull/805 44 | [#842]: https://github.com/toml-lang/toml/pull/842 45 | [#859]: https://github.com/toml-lang/toml/pull/859 46 | [#894]: https://github.com/toml-lang/toml/pull/894 47 | [#904]: https://github.com/toml-lang/toml/pull/904 48 | [#929]: https://github.com/toml-lang/toml/pull/929 49 | [#950]: https://github.com/toml-lang/toml/pull/950 50 | 51 | ## 1.0.0 / 2021-01-11 52 | 53 | - Clarify how tables are created and defined. 54 | - Clarify and describe the top-level table. 55 | - Clarify that indentation before keys is ignored. 56 | - Clarify that indentation before table headers is ignored. 57 | - Clarify that indentation between array values is ignored. 58 | 59 | ## 1.0.0-rc.3 / 2020-10-07 60 | 61 | - Clarify that comments and newlines are allowed before commas in arrays. 62 | - Mark the ABNF as canonical, and reference it from the text specification. 63 | 64 | ## 1.0.0-rc.2 / 2020-08-09 65 | 66 | - Create https://toml.io as the new primary location to read the TOML spec. 67 | - Clarify meaning of "quotation marks". 68 | - Clarify meaning of "expected" value ranges. 69 | - Clarify that EOF is allowed after key/value pair. 70 | - Clarify that the various styles for writing keys are equivalent. 71 | - Clarify that line-ending backslashes must be unescaped in multi-line strings. 72 | - Add examples for invalid float values. 73 | 74 | ## 1.0.0-rc.1 / 2020-04-01 75 | 76 | - Clarify in ABNF how quotes in multi-line basic and multi-line literal strings 77 | are allowed to be used. 78 | - Leading zeroes in exponent parts of floats are permitted. 79 | - Clarify that control characters are not permitted in comments. 80 | - Clarify behavior of tables defined implicitly by dotted keys. 81 | - Clarify that inline tables are immutable. 82 | - Clarify that trailing commas are not allowed in inline tables. 83 | - Clarify in ABNF that UTF-16 surrogate code points (U+D800 - U+DFFF) are not 84 | allowed in strings or comments. 85 | - Allow raw tab characters in basic strings and multi-line basic strings. 86 | - Allow heterogenous values in arrays. 87 | 88 | ## 0.5.0 / 2018-07-11 89 | 90 | - Add dotted keys. 91 | - Add hex, octal, and binary integer formats. 92 | - Add special float values (inf, nan). 93 | - Rename Datetime to Offset Date-Time. 94 | - Add Local Date-Time. 95 | - Add Local Date. 96 | - Add Local Time. 97 | - Add ABNF specification. 98 | - Allow space (instead of T) to separate date and time in Date-Time. 99 | - Allow accidental whitespace between backslash and newline in the line 100 | continuation operator in multi-line basic strings. 101 | - Specify that the standard file extension is `.toml`. 102 | - Specify that MIME type is `application/toml` 103 | - Clarify that U+007F is an escape character. 104 | - Clarify that keys are always strings. 105 | - Clarify that you cannot use array-of-table to append to a static array. 106 | - Clarify that a TOML file must be a valid UTF-8 document. 107 | - Clarify valid Array values. 108 | - Clarify that literal strings can be table keys. 109 | - Clarify that at least millisecond precision expected for Date-Time and Time. 110 | - Clarify that comments are OK in multiline arrays. 111 | - Clarify that +0, -0, +0.0, and -0.0 are valid and what they mean. 112 | - TOML has a logo! 113 | 114 | ## 0.4.0 / 2015-02-12 115 | 116 | - Add Inline Table syntax. 117 | - Allow underscores in numbers. 118 | - Remove forward slash as an escapable character. 119 | - Unicode escapes must be scalar values. 120 | - Newline is now defined as LF or CRLF. 121 | 122 | ## 0.3.1 / 2014-11-11 123 | 124 | - Fix incorrect datetime examples. 125 | 126 | ## 0.3.0 / 2014-11-10 127 | 128 | - Add scientific notation for floats. 129 | - Allow optional + prefix on integers. 130 | - Switch to RFC 3339 for datetimes (allowing offsets and fractional seconds). 131 | - Add multiline and literal strings. 132 | - Clarify what characters valid keys can contain. 133 | 134 | ## 0.2.0 / 2013-09-24 135 | 136 | - Use "table" instead of "key group" terminology. 137 | - Add the ability to define nestable arrays of tables. 138 | 139 | ## 0.1.0 / 2013-03-17 140 | 141 | - From Twitter rage to reality; TOML is now a thing. 142 | - First proper release. 143 | - TOML adheres to the SemVer standard for version numbers. 144 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) Tom Preston-Werner 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | TOML logo 2 | 3 | # TOML 4 | 5 | Tom's Obvious, Minimal Language. 6 | 7 | By Tom Preston-Werner, Pradyun Gedam, et al. 8 | 9 | > This repository contains the in-development version of the TOML specification. 10 | > You can find the released versions at https://toml.io. 11 | 12 | ## Objectives 13 | 14 | TOML aims to be a minimal configuration file format that's easy to read due to 15 | obvious semantics. TOML is designed to map unambiguously to a hash table. TOML 16 | should be easy to parse into data structures in a wide variety of languages. 17 | 18 | ## Example 19 | 20 | ```toml 21 | # This is a TOML document. 22 | 23 | title = "TOML Example" 24 | 25 | [owner] 26 | name = "Tom Preston-Werner" 27 | dob = 1979-05-27T07:32:00-08:00 # First class dates 28 | 29 | [database] 30 | server = "192.168.1.1" 31 | ports = [ 8000, 8001, 8002 ] 32 | connection_max = 5000 33 | enabled = true 34 | 35 | [servers] 36 | 37 | # Indentation (tabs and/or spaces) is allowed but not required 38 | [servers.alpha] 39 | ip = "10.0.0.1" 40 | dc = "eqdc10" 41 | 42 | [servers.beta] 43 | ip = "10.0.0.2" 44 | dc = "eqdc10" 45 | 46 | [clients] 47 | data = [ ["gamma", "delta"], [1, 2] ] 48 | 49 | # Line breaks are OK when inside arrays 50 | hosts = [ 51 | "alpha", 52 | "omega" 53 | ] 54 | ``` 55 | 56 | ## Comparison with Other Formats 57 | 58 | TOML shares traits with other file formats used for application configuration 59 | and data serialization, such as YAML and JSON. TOML and JSON both are simple and 60 | use ubiquitous data types, making them easy to code for or parse with machines. 61 | TOML and YAML both emphasize human readability features, like comments that make 62 | it easier to understand the purpose of a given line. TOML differs in combining 63 | these, allowing comments (unlike JSON) but preserving simplicity (unlike YAML). 64 | 65 | Because TOML is explicitly intended as a configuration file format, parsing it 66 | is easy, but it is not intended for serializing arbitrary data structures. TOML 67 | always has a hash table at the top level of the file, which can easily have data 68 | nested inside its keys, but it doesn't permit top-level arrays or floats, so it 69 | cannot directly serialize some data. There is also no standard identifying the 70 | start or end of a TOML file, which can complicate sending it through a stream. 71 | These details must be negotiated on the application layer. 72 | 73 | INI files are frequently compared to TOML for their similarities in syntax and 74 | use as configuration files. However, there is no standardized format for INI and 75 | they do not gracefully handle more than one or two levels of nesting. 76 | 77 | Further reading: 78 | 79 | - YAML spec: https://yaml.org/spec/1.2/spec.html 80 | - JSON spec: https://tools.ietf.org/html/rfc8259 81 | - Wikipedia on INI files: https://en.wikipedia.org/wiki/INI_file 82 | 83 | ## Get Involved 84 | 85 | Documentation, bug reports, pull requests, and all other contributions are 86 | welcome! 87 | 88 | ## Wiki 89 | 90 | We have an [Official TOML Wiki](https://github.com/toml-lang/toml/wiki) that 91 | catalogs the following: 92 | 93 | - Projects using TOML 94 | - Implementations 95 | - Validators 96 | - Language-agnostic test suite for TOML decoders and encoders 97 | - Editor support 98 | - Encoders 99 | - Converters 100 | 101 | Please take a look if you'd like to view or add to that list. Thanks for being a 102 | part of the TOML community! 103 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Maintainer documentation 2 | 3 | This section of the repository contains documentation for TOML's maintainers. 4 | 5 | ## Release Process 6 | 7 | - Set up local repos of [toml-lang/toml] and [toml-lang/toml.io], as described 8 | in [scripts/release.py](../scripts/release.py). 9 | - In the root of the toml-lang/toml clone, run 10 | `python3.8 scripts/release.py `. 11 | - Done! ✨ 12 | 13 | [toml-lang/toml]: https://github.com/toml-lang/toml 14 | [toml-lang/toml.io]: https://github.com/toml-lang/toml.io 15 | -------------------------------------------------------------------------------- /logos/toml-100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toml-lang/toml/d0c77ee8a76f506c8fddbec6d5eef282f96efa90/logos/toml-100.png -------------------------------------------------------------------------------- /logos/toml-200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toml-lang/toml/d0c77ee8a76f506c8fddbec6d5eef282f96efa90/logos/toml-200.png -------------------------------------------------------------------------------- /logos/toml-400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toml-lang/toml/d0c77ee8a76f506c8fddbec6d5eef282f96efa90/logos/toml-400.png -------------------------------------------------------------------------------- /logos/toml.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toml-lang/toml/d0c77ee8a76f506c8fddbec6d5eef282f96efa90/logos/toml.ai -------------------------------------------------------------------------------- /logos/toml.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /scripts/release.py: -------------------------------------------------------------------------------- 1 | """Release Automation! 2 | 3 | Baked assumptions: 4 | 5 | - CWD is the root of the toml repository (this one) 6 | - The toml.io repository is available at "../toml.io" 7 | - Changelog file: 8 | - is `CHANGELOG.md` 9 | - has a "## unreleased" heading line. 10 | - Markdown file: 11 | - is `toml.md` 12 | - goes to `specs/en/v{version}` in the website repo 13 | - lines "TOML" and "====" are the main heading. 14 | - ABNF file: 15 | - is `toml.abnf` 16 | 17 | Checked assumptions: 18 | 19 | - Both this and the toml.io repository have an "upstream" remote 20 | - "upstream" remotes point to "github.com/toml-lang/{repo}" 21 | - Current branch is the default branch 22 | - Current branch is up to date with remote 23 | - Working directory is clean 24 | 25 | """ 26 | 27 | import fileinput 28 | import os 29 | import re 30 | import shutil 31 | import subprocess 32 | import sys 33 | import tempfile 34 | import textwrap 35 | from contextlib import contextmanager 36 | from datetime import datetime 37 | from pathlib import Path 38 | from typing import Callable, List, Tuple 39 | 40 | # Copied from semver.org and broken up for readability + line length. 41 | SEMVER_REGEX = re.compile( 42 | r""" 43 | ^ 44 | (?P0|[1-9]\d*) 45 | \. 46 | (?P0|[1-9]\d*) 47 | \. 48 | (?P0|[1-9]\d*) 49 | (?: 50 | - 51 | (?P 52 | (?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*) 53 | (?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))* 54 | ) 55 | )? 56 | (?: 57 | \+ 58 | (?P[0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*) 59 | )? 60 | $ 61 | """, 62 | re.VERBOSE, 63 | ) 64 | 65 | 66 | # 67 | # Helpers 68 | # 69 | @contextmanager 70 | def task(message: str): 71 | """A little thing to allow for nicer code organization.""" 72 | global _INDENT 73 | 74 | log(f"{message}...") 75 | _INDENT += 1 76 | try: 77 | yield 78 | except AssertionError as e: 79 | log(f"ERROR: {e}", error=True) 80 | sys.exit(1) 81 | finally: 82 | _INDENT -= 1 83 | 84 | 85 | def log(message: str, *, error=False) -> None: 86 | output = textwrap.indent(message, " " * _INDENT) 87 | 88 | if error: 89 | file = sys.stderr 90 | # A dash of red 91 | if sys.stdout.isatty(): 92 | output = f"\033[31m{output}\033[0m" 93 | else: 94 | file = sys.stdout 95 | 96 | print(output, file=file) 97 | 98 | 99 | _INDENT = 0 100 | 101 | 102 | def run(*args, cwd: Path): 103 | """Runs a command, while also pretty-printing it.""" 104 | result = subprocess.run(args, cwd=cwd, capture_output=True) 105 | if result.returncode == 0: 106 | return result.stdout.decode().rstrip("\n") 107 | 108 | # Print information about the failed command. 109 | log(" ".join(["$", *args])) 110 | log(" stdout ".center(80, "-")) 111 | log(result.stdout.decode() or "") 112 | log(" stderr ".center(80, "-")) 113 | log(result.stderr.decode() or "") 114 | 115 | assert False, f"Exited with non-zero exit code: {result.returncode}" 116 | 117 | 118 | @contextmanager 119 | def replacement_file(path: Path): 120 | fh, tmp_path = tempfile.mkstemp() 121 | with os.fdopen(fh, "w") as dest: 122 | with path.open() as source: 123 | yield source, dest 124 | 125 | # Replace current file with rewritten file 126 | shutil.copymode(path, tmp_path) 127 | path.unlink() 128 | shutil.move(tmp_path, path) 129 | 130 | 131 | def matches(line): 132 | return (line + "\n").__eq__ 133 | 134 | 135 | def contains(fragment): 136 | def marker(line): 137 | return fragment in line 138 | 139 | return marker 140 | 141 | 142 | def change_line(path: Path, *, marker: Callable[[str], bool], to: List[str]) -> None: 143 | with replacement_file(path) as (source, dest): 144 | for line in source: 145 | # not-to-be-replaced lines 146 | if not marker(line): 147 | dest.write(line) 148 | continue 149 | # replacement lines 150 | for replacement in to: 151 | dest.write(replacement + "\n") 152 | 153 | 154 | def git_commit(message: str, *, files: List[str], repo: Path): 155 | run("git", "add", *files, cwd=repo) 156 | run("git", "commit", "-m", message, cwd=repo) 157 | 158 | 159 | # 160 | # Actual automation 161 | # 162 | def get_version() -> str: 163 | assert len(sys.argv) == 2, "Got wrong number of arguments, expected 1." 164 | 165 | version = sys.argv[1] 166 | 167 | match = SEMVER_REGEX.match(version) 168 | assert match is not None, "Given version is not a valid semver." 169 | assert not match.group("buildmetadata"), "Shouldn't have build metadata in version." 170 | 171 | return version 172 | 173 | 174 | def check_repo_state(repo: Path, *, name: str): 175 | # Check upstream remote is configured correctly 176 | upstream = run("git", "config", "--get", "remote.upstream.url", cwd=repo) 177 | assert ( 178 | upstream == f"git@github.com:toml-lang/{name}.git" 179 | ), f"Got incorrect upstream repo: {upstream}" 180 | 181 | # Check current branch is correct 182 | current_branch = run("git", "branch", "--show-current", cwd=repo) 183 | assert current_branch in ("main", "master"), current_branch 184 | 185 | # Check working directory is clean 186 | working_directory_state = run("git", "status", "--porcelain", cwd=repo) 187 | assert ( 188 | working_directory_state == "" 189 | ), f"Dirty working directory\n{working_directory_state}" 190 | 191 | # Check up-to-date with remote 192 | with task("Checking against remote"): 193 | run("git", "remote", "update", "upstream", cwd=repo) 194 | 195 | deviation = run( 196 | "git", 197 | "rev-list", 198 | f"{current_branch}..upstream/{current_branch}", 199 | "--left-right", 200 | cwd=repo, 201 | ) 202 | assert not deviation, f"Local branch deviates from upstream\n{deviation}" 203 | 204 | 205 | def get_repositories() -> Tuple[Path, Path]: 206 | spec_repo = Path(".").resolve() 207 | website_repo = spec_repo.parent / "toml.io" 208 | 209 | with task("Checking repositories"): 210 | with task("toml"): 211 | check_repo_state(spec_repo, name="toml") 212 | with task("toml.io"): 213 | check_repo_state(website_repo, name="toml.io") 214 | 215 | return website_repo, spec_repo 216 | 217 | 218 | def prepare_release(version: str, spec_repo: Path, website_repo: Path) -> None: 219 | # Make "backup" tags 220 | backup_tag = "backup/{now}".format(now=str(int(datetime.now().timestamp()))) 221 | run("git", "tag", "-m", "backup", backup_tag, cwd=spec_repo) 222 | run("git", "tag", "-m", "backup", backup_tag, cwd=website_repo) 223 | 224 | date = datetime.today().strftime("%Y-%m-%d") 225 | release_heading = f"## {version} / {date}" 226 | release_message = f"Release v{version}" 227 | 228 | with task("Updating changelog for release"): 229 | unreleased_heading = "## unreleased" 230 | changelog = spec_repo / "CHANGELOG.md" 231 | 232 | change_line(changelog, marker=matches(unreleased_heading), to=[release_heading]) 233 | git_commit(release_message, files=[str(changelog)], repo=spec_repo) 234 | 235 | with task("Creating release tag"): 236 | run("git", "tag", "-m", release_message, version, cwd=spec_repo) 237 | 238 | with task("Updating changelog for development"): 239 | change_line( 240 | changelog, 241 | marker=matches(release_heading), 242 | to=[unreleased_heading, "", "Nothing.", "", release_heading], 243 | ) 244 | git_commit("Bump for development", files=[str(changelog)], repo=spec_repo) 245 | 246 | with task("Copy to website"): 247 | source_md = spec_repo / "toml.md" 248 | destination_md = website_repo / "specs" / "en" / f"v{version}.md" 249 | 250 | shutil.copyfile(source_md, destination_md) 251 | 252 | new_heading = f"TOML v{version}" 253 | new_abnf_link = f"https://github.com/toml-lang/toml/blob/{version}/toml.abnf" 254 | 255 | with task("Updating spec for release"): 256 | change_line(destination_md, marker=matches("TOML"), to=[new_heading]) 257 | change_line(destination_md, marker=matches("===="), to=["=" * len(new_heading)]) 258 | change_line( 259 | destination_md, 260 | marker=matches("[abnf]: ./toml.abnf"), 261 | to=[f"[abnf]: {new_abnf_link}"], 262 | ) 263 | 264 | netlify_toml = website_repo / "netlify.toml" 265 | 266 | with task("Update latest redirect"): 267 | marker = "RELEASE AUTOMATION MARKER: version" 268 | new_line = f' to = "/en/v{version}" # {marker}' 269 | 270 | change_line(netlify_toml, marker=contains(marker), to=[new_line]) 271 | 272 | with task("Commit new version"): 273 | git_commit( 274 | release_message, 275 | files=[str(destination_md), str(netlify_toml)], 276 | repo=website_repo, 277 | ) 278 | 279 | 280 | def push_release(version: str, spec_repo: Path, website_repo: Path) -> None: 281 | print("Publishing changes...") 282 | with task("specs repository"): 283 | run("git", "push", "origin", "HEAD", version, cwd=spec_repo) 284 | run("git", "push", "upstream", "HEAD", version, cwd=spec_repo) 285 | 286 | with task("website repository"): 287 | run("git", "push", "origin", "HEAD", cwd=website_repo) 288 | run("git", "push", "upstream", "HEAD", cwd=website_repo) 289 | 290 | 291 | def main() -> None: 292 | version = get_version() 293 | website_repo, spec_repo = get_repositories() 294 | 295 | with task("Preparing release"): 296 | prepare_release(version, spec_repo, website_repo) 297 | 298 | input("Press enter when ready.") # a chance to stop/pause before publishing 299 | 300 | with task("Publishing release"): 301 | push_release(version, spec_repo, website_repo) 302 | 303 | 304 | if __name__ == "__main__": 305 | main() 306 | -------------------------------------------------------------------------------- /toml.abnf: -------------------------------------------------------------------------------- 1 | ;; This document describes TOML's syntax, using the ABNF format (defined in 2 | ;; RFC 5234 -- https://www.ietf.org/rfc/rfc5234.txt). 3 | ;; 4 | ;; Although a TOML document must be valid UTF-8, this grammar refers to the 5 | ;; Unicode Code Points you get after you decode the UTF-8 input. 6 | ;; 7 | ;; All valid TOML documents will match this description, however certain 8 | ;; invalid documents would need to be rejected as per the semantics described 9 | ;; in the supporting text description. 10 | 11 | ;; It is possible to try this grammar interactively, using instaparse. 12 | ;; http://instaparse.mojombo.com/ 13 | ;; 14 | ;; To do so, in the lower right, click on Options and change `:input-format` to 15 | ;; ':abnf'. Then paste this entire ABNF document into the grammar entry box 16 | ;; (above the options). Then you can type or paste a sample TOML document into 17 | ;; the beige box on the left. Tada! 18 | 19 | ;; Overall Structure 20 | 21 | toml = expression *( newline expression ) 22 | 23 | expression = ws [ comment ] 24 | expression =/ ws keyval ws [ comment ] 25 | expression =/ ws table ws [ comment ] 26 | 27 | ;; Whitespace 28 | 29 | ws = *wschar 30 | wschar = %x20 ; Space 31 | wschar =/ %x09 ; Horizontal tab 32 | 33 | ;; Newline 34 | 35 | newline = %x0A ; LF 36 | newline =/ %x0D.0A ; CRLF 37 | 38 | ;; Comment 39 | 40 | comment-start-symbol = %x23 ; # 41 | non-ascii = %x80-D7FF / %xE000-10FFFF 42 | non-eol = %x09 / %x20-7E / non-ascii 43 | 44 | comment = comment-start-symbol *non-eol 45 | 46 | ;; Key-Value pairs 47 | 48 | keyval = key keyval-sep val 49 | key = simple-key / dotted-key 50 | val = string / boolean / array / inline-table / date-time / float / integer 51 | 52 | simple-key = quoted-key / unquoted-key 53 | unquoted-key = 1*( ALPHA / DIGIT / %x2D / %x5F ) ; A-Z / a-z / 0-9 / - / _ 54 | 55 | ;; Quoted and dotted key 56 | 57 | quoted-key = basic-string / literal-string 58 | dotted-key = simple-key 1*( dot-sep simple-key ) 59 | 60 | dot-sep = ws %x2E ws ; . Period 61 | keyval-sep = ws %x3D ws ; = 62 | 63 | ;; String 64 | 65 | string = ml-basic-string / basic-string / ml-literal-string / literal-string 66 | 67 | ;; Basic String 68 | 69 | basic-string = quotation-mark *basic-char quotation-mark 70 | 71 | quotation-mark = %x22 ; " 72 | 73 | basic-char = basic-unescaped / escaped 74 | basic-unescaped = wschar / %x21 / %x23-5B / %x5D-7E / non-ascii 75 | escaped = escape escape-seq-char 76 | 77 | escape = %x5C ; \ 78 | escape-seq-char = %x22 ; " quotation mark U+0022 79 | escape-seq-char =/ %x5C ; \ reverse solidus U+005C 80 | escape-seq-char =/ %x62 ; b backspace U+0008 81 | escape-seq-char =/ %x65 ; e escape U+001B 82 | escape-seq-char =/ %x66 ; f form feed U+000C 83 | escape-seq-char =/ %x6E ; n line feed U+000A 84 | escape-seq-char =/ %x72 ; r carriage return U+000D 85 | escape-seq-char =/ %x74 ; t tab U+0009 86 | escape-seq-char =/ %x78 2HEXDIG ; xHH U+00HH 87 | escape-seq-char =/ %x75 4HEXDIG ; uHHHH U+HHHH 88 | escape-seq-char =/ %x55 8HEXDIG ; UHHHHHHHH U+HHHHHHHH 89 | 90 | ;; Multiline Basic String 91 | 92 | ml-basic-string = ml-basic-string-delim [ newline ] ml-basic-body 93 | ml-basic-string-delim 94 | ml-basic-string-delim = 3quotation-mark 95 | ml-basic-body = *mlb-content *( mlb-quotes 1*mlb-content ) [ mlb-quotes ] 96 | 97 | mlb-content = basic-char / newline / mlb-escaped-nl 98 | mlb-quotes = 1*2quotation-mark 99 | mlb-escaped-nl = escape ws newline *( wschar / newline ) 100 | 101 | ;; Literal String 102 | 103 | literal-string = apostrophe *literal-char apostrophe 104 | 105 | apostrophe = %x27 ; ' apostrophe 106 | 107 | literal-char = %x09 / %x20-26 / %x28-7E / non-ascii 108 | 109 | ;; Multiline Literal String 110 | 111 | ml-literal-string = ml-literal-string-delim [ newline ] ml-literal-body 112 | ml-literal-string-delim 113 | ml-literal-string-delim = 3apostrophe 114 | ml-literal-body = *mll-content *( mll-quotes 1*mll-content ) [ mll-quotes ] 115 | 116 | mll-content = literal-char / newline 117 | mll-quotes = 1*2apostrophe 118 | 119 | ;; Integer 120 | 121 | integer = dec-int / hex-int / oct-int / bin-int 122 | 123 | minus = %x2D ; - 124 | plus = %x2B ; + 125 | underscore = %x5F ; _ 126 | digit1-9 = %x31-39 ; 1-9 127 | digit0-7 = %x30-37 ; 0-7 128 | digit0-1 = %x30-31 ; 0-1 129 | 130 | hex-prefix = %x30.78 ; 0x 131 | oct-prefix = %x30.6F ; 0o 132 | bin-prefix = %x30.62 ; 0b 133 | 134 | dec-int = [ minus / plus ] unsigned-dec-int 135 | unsigned-dec-int = DIGIT / digit1-9 1*( DIGIT / underscore DIGIT ) 136 | 137 | hex-int = hex-prefix HEXDIG *( HEXDIG / underscore HEXDIG ) 138 | oct-int = oct-prefix digit0-7 *( digit0-7 / underscore digit0-7 ) 139 | bin-int = bin-prefix digit0-1 *( digit0-1 / underscore digit0-1 ) 140 | 141 | ;; Float 142 | 143 | float = float-int-part ( exp / frac [ exp ] ) 144 | float =/ special-float 145 | 146 | float-int-part = dec-int 147 | frac = decimal-point zero-prefixable-int 148 | decimal-point = %x2E ; . 149 | zero-prefixable-int = DIGIT *( DIGIT / underscore DIGIT ) 150 | 151 | exp = "e" float-exp-part 152 | float-exp-part = [ minus / plus ] zero-prefixable-int 153 | 154 | special-float = [ minus / plus ] ( inf / nan ) 155 | inf = %x69.6E.66 ; inf 156 | nan = %x6E.61.6E ; nan 157 | 158 | ;; Boolean 159 | 160 | boolean = true / false 161 | 162 | true = %x74.72.75.65 ; true 163 | false = %x66.61.6C.73.65 ; false 164 | 165 | ;; Date and Time (as defined in RFC 3339) 166 | 167 | date-time = offset-date-time / local-date-time / local-date / local-time 168 | 169 | date-fullyear = 4DIGIT 170 | date-month = 2DIGIT ; 01-12 171 | date-mday = 2DIGIT ; 01-28, 01-29, 01-30, 01-31 based on month/year 172 | time-delim = "T" / %x20 ; T, t, or space 173 | time-hour = 2DIGIT ; 00-23 174 | time-minute = 2DIGIT ; 00-59 175 | time-second = 2DIGIT ; 00-58, 00-59, 00-60 based on leap second rules 176 | time-secfrac = "." 1*DIGIT 177 | time-numoffset = ( "+" / "-" ) time-hour ":" time-minute 178 | time-offset = "Z" / time-numoffset 179 | 180 | partial-time = time-hour ":" time-minute [ ":" time-second [ time-secfrac ] ] 181 | full-date = date-fullyear "-" date-month "-" date-mday 182 | full-time = partial-time time-offset 183 | 184 | ;; Offset Date-Time 185 | 186 | offset-date-time = full-date time-delim full-time 187 | 188 | ;; Local Date-Time 189 | 190 | local-date-time = full-date time-delim partial-time 191 | 192 | ;; Local Date 193 | 194 | local-date = full-date 195 | 196 | ;; Local Time 197 | 198 | local-time = partial-time 199 | 200 | ;; Array 201 | 202 | array = array-open [ array-values ] ws-comment-newline array-close 203 | 204 | array-open = %x5B ; [ 205 | array-close = %x5D ; ] 206 | 207 | array-values = ws-comment-newline val ws-comment-newline array-sep array-values 208 | array-values =/ ws-comment-newline val ws-comment-newline [ array-sep ] 209 | 210 | array-sep = %x2C ; , Comma 211 | 212 | ws-comment-newline = *( wschar / [ comment ] newline ) 213 | 214 | ;; Table 215 | 216 | table = std-table / array-table 217 | 218 | ;; Standard Table 219 | 220 | std-table = std-table-open key std-table-close 221 | 222 | std-table-open = %x5B ws ; [ Left square bracket 223 | std-table-close = ws %x5D ; ] Right square bracket 224 | 225 | ;; Inline Table 226 | 227 | inline-table = inline-table-open [ inline-table-keyvals ] ws-comment-newline inline-table-close 228 | 229 | inline-table-open = %x7B ; { 230 | inline-table-close = %x7D ; } 231 | inline-table-sep = %x2C ; , Comma 232 | 233 | inline-table-keyvals = ws-comment-newline keyval ws-comment-newline inline-table-sep inline-table-keyvals 234 | inline-table-keyvals =/ ws-comment-newline keyval ws-comment-newline [ inline-table-sep ] 235 | 236 | ;; Array Table 237 | 238 | array-table = array-table-open key array-table-close 239 | 240 | array-table-open = %x5B.5B ws ; [[ Double left square bracket 241 | array-table-close = ws %x5D.5D ; ]] Double right square bracket 242 | 243 | ;; Built-in ABNF terms, reproduced here for clarity 244 | 245 | ALPHA = %x41-5A / %x61-7A ; A-Z / a-z 246 | DIGIT = %x30-39 ; 0-9 247 | HEXDIG = DIGIT / "A" / "B" / "C" / "D" / "E" / "F" 248 | -------------------------------------------------------------------------------- /toml.md: -------------------------------------------------------------------------------- 1 | ![TOML Logo](logos/toml-200.png) 2 | 3 | # TOML 4 | 5 | Tom's Obvious, Minimal Language. 6 | 7 | By Tom Preston-Werner, Pradyun Gedam, et al. 8 | 9 | ## Objectives 10 | 11 | TOML aims to be a minimal configuration file format that's easy to read due to 12 | obvious semantics. TOML is designed to map unambiguously to a hash table. TOML 13 | should be easy to parse into data structures in a wide variety of languages. 14 | 15 | ## Table of contents 16 | 17 | - [Preliminaries](#user-content-preliminaries) 18 | - [Comment](#user-content-comment) 19 | - [Key/Value Pair](#user-content-keyvalue-pair) 20 | - [Keys](#user-content-keys) 21 | - [String](#user-content-string) 22 | - [Integer](#user-content-integer) 23 | - [Float](#user-content-float) 24 | - [Boolean](#user-content-boolean) 25 | - [Offset Date-Time](#user-content-offset-date-time) 26 | - [Local Date-Time](#user-content-local-date-time) 27 | - [Local Date](#user-content-local-date) 28 | - [Local Time](#user-content-local-time) 29 | - [Array](#user-content-array) 30 | - [Table](#user-content-table) 31 | - [Inline Table](#user-content-inline-table) 32 | - [Array of Tables](#user-content-array-of-tables) 33 | - [Filename Extension](#user-content-filename-extension) 34 | - [MIME Type](#user-content-mime-type) 35 | - [ABNF Grammar](#user-content-abnf-grammar) 36 | 37 | ## Preliminaries 38 | 39 | - TOML is case-sensitive. 40 | - Whitespace means tab (U+0009) or space (U+0020). 41 | - Newline means LF (U+000A) or CRLF (U+000D U+000A). 42 | - A TOML file must be a valid UTF-8 encoded Unicode document. 43 | 44 | Specifically this means that a file _as a whole_ must form a 45 | [well-formed code-unit sequence](https://unicode.org/glossary/#well_formed_code_unit_sequence). 46 | Otherwise, it must be rejected (preferably) or have ill-formed byte sequences 47 | replaced with U+FFFD, as per the Unicode specification. 48 | 49 | ## Comment 50 | 51 | A hash symbol marks the rest of the line as a comment, except when inside a 52 | string. 53 | 54 | ```toml 55 | # This is a full-line comment 56 | key = "value" # This is a comment at the end of a line 57 | another = "# This is not a comment" 58 | ``` 59 | 60 | Control characters other than tab (U+0000 to U+0008, U+000A to U+001F, U+007F) 61 | are not permitted in comments. 62 | 63 | Comments should be used to communicate between the human readers of a file. 64 | Parsers must not modify keys or values, based on the presence (or contents) of a 65 | comment. 66 | 67 | ## Key/Value Pair 68 | 69 | The primary building block of a TOML document is the key/value pair. 70 | 71 | Keys are on the left of the equals sign and values are on the right. Whitespace 72 | is ignored around key names and values. The key, equals sign, and value must be 73 | on the same line (though some values can be broken over multiple lines). 74 | 75 | ```toml 76 | key = "value" 77 | ``` 78 | 79 | Values must have one of the following types. 80 | 81 | - [String](#user-content-string) 82 | - [Integer](#user-content-integer) 83 | - [Float](#user-content-float) 84 | - [Boolean](#user-content-boolean) 85 | - [Offset Date-Time](#user-content-offset-date-time) 86 | - [Local Date-Time](#user-content-local-date-time) 87 | - [Local Date](#user-content-local-date) 88 | - [Local Time](#user-content-local-time) 89 | - [Array](#user-content-array) 90 | - [Inline Table](#user-content-inline-table) 91 | 92 | Unspecified values are invalid. 93 | 94 | ```toml 95 | key = # INVALID 96 | ``` 97 | 98 | There must be a newline (or EOF) after a key/value pair. (See 99 | [Inline Table](#user-content-inline-table) for exceptions.) 100 | 101 | ``` 102 | first = "Tom" last = "Preston-Werner" # INVALID 103 | ``` 104 | 105 | ## Keys 106 | 107 | A key may be either bare, quoted, or dotted. 108 | 109 | **Bare keys** may only contain ASCII letters, ASCII digits, underscores, and 110 | dashes (`A-Za-z0-9_-`). Note that bare keys are allowed to be composed of only 111 | ASCII digits, e.g. `1234`, but are always interpreted as strings. 112 | 113 | ℹ️ The exact ranges of allowed code points can be found in the 114 | [ABNF grammar file][abnf]. 115 | 116 | ```toml 117 | key = "value" 118 | bare_key = "value" 119 | bare-key = "value" 120 | 1234 = "value" 121 | ``` 122 | 123 | **Quoted keys** follow the exact same rules as either basic strings or literal 124 | strings and allow you to use a much broader set of key names. Best practice is 125 | to use bare keys except when absolutely necessary. 126 | 127 | ```toml 128 | "127.0.0.1" = "value" 129 | "character encoding" = "value" 130 | "ʎǝʞ" = "value" 131 | 'key2' = "value" 132 | 'quoted "value"' = "value" 133 | ``` 134 | 135 | A bare key must be non-empty, but an empty quoted key is allowed (though 136 | discouraged). You cannot use multi-line strings to define quoted keys. 137 | 138 | ```toml 139 | = "no key name" # INVALID 140 | """key""" = "not allowed" # INVALID 141 | "" = "blank" # VALID but discouraged 142 | '' = 'blank' # VALID but discouraged 143 | ``` 144 | 145 | **Dotted keys** are a sequence of bare or quoted keys joined with a dot. This 146 | allows for grouping similar properties together: 147 | 148 | ```toml 149 | name = "Orange" 150 | physical.color = "orange" 151 | physical.shape = "round" 152 | site."google.com" = true 153 | ``` 154 | 155 | In JSON land, that would give you the following structure: 156 | 157 | ```json 158 | { 159 | "name": "Orange", 160 | "physical": { 161 | "color": "orange", 162 | "shape": "round" 163 | }, 164 | "site": { 165 | "google.com": true 166 | } 167 | } 168 | ``` 169 | 170 | For details regarding the tables that dotted keys define, refer to the 171 | [Table](#user-content-table) section below. 172 | 173 | Whitespace around dot-separated parts is ignored. However, best practice is to 174 | not use any extraneous whitespace. 175 | 176 | ```toml 177 | fruit.name = "banana" # this is best practice 178 | fruit. color = "yellow" # same as fruit.color 179 | fruit . flavor = "banana" # same as fruit.flavor 180 | ``` 181 | 182 | Indentation is treated as whitespace and ignored. 183 | 184 | Defining a key multiple times is invalid. 185 | 186 | ``` 187 | # DO NOT DO THIS 188 | name = "Tom" 189 | name = "Pradyun" 190 | ``` 191 | 192 | Note that bare keys and quoted keys are equivalent: 193 | 194 | ``` 195 | # THIS WILL NOT WORK 196 | spelling = "favorite" 197 | "spelling" = "favourite" 198 | ``` 199 | 200 | As long as a key hasn't been directly defined, you may still write to it and to 201 | names within it. 202 | 203 | ```toml 204 | # This makes the key "fruit" into a table. 205 | fruit.apple.smooth = true 206 | 207 | # So then you can add to the table "fruit" like so: 208 | fruit.orange = 2 209 | ``` 210 | 211 | ``` 212 | # THE FOLLOWING IS INVALID 213 | 214 | # This defines the value of fruit.apple to be an integer. 215 | fruit.apple = 1 216 | 217 | # But then this treats fruit.apple like it's a table. 218 | # You can't turn an integer into a table. 219 | fruit.apple.smooth = true 220 | ``` 221 | 222 | Defining dotted keys out-of-order is discouraged. 223 | 224 | ```toml 225 | # VALID BUT DISCOURAGED 226 | 227 | apple.type = "fruit" 228 | orange.type = "fruit" 229 | 230 | apple.skin = "thin" 231 | orange.skin = "thick" 232 | 233 | apple.color = "red" 234 | orange.color = "orange" 235 | ``` 236 | 237 | ```toml 238 | # RECOMMENDED 239 | 240 | apple.type = "fruit" 241 | apple.skin = "thin" 242 | apple.color = "red" 243 | 244 | orange.type = "fruit" 245 | orange.skin = "thick" 246 | orange.color = "orange" 247 | ``` 248 | 249 | Since bare keys can be composed of only ASCII integers, it is possible to write 250 | dotted keys that look like floats but are 2-part dotted keys. Don't do this 251 | unless you have a good reason to (you probably don't). 252 | 253 | ```toml 254 | 3.14159 = "pi" 255 | ``` 256 | 257 | The above TOML maps to the following JSON. 258 | 259 | ```json 260 | { "3": { "14159": "pi" } } 261 | ``` 262 | 263 | ## String 264 | 265 | There are four ways to express strings: basic, multi-line basic, literal, and 266 | multi-line literal. All strings must contain only Unicode characters. 267 | 268 | **Basic strings** are surrounded by quotation marks (`"`). Any Unicode character 269 | may be used except those that must be escaped: quotation mark, backslash, and 270 | the control characters other than tab (U+0000 to U+0008, U+000A to U+001F, 271 | U+007F). 272 | 273 | ```toml 274 | str = "I'm a string. \"You can quote me\". Name\tJos\xE9\nLocation\tSF." 275 | ``` 276 | 277 | For convenience, some popular characters have a compact escape sequence. 278 | 279 | ``` 280 | \b - backspace (U+0008) 281 | \t - tab (U+0009) 282 | \n - linefeed (U+000A) 283 | \f - form feed (U+000C) 284 | \r - carriage return (U+000D) 285 | \e - escape (U+001B) 286 | \" - quote (U+0022) 287 | \\ - backslash (U+005C) 288 | \xHH - unicode (U+00HH) 289 | \uHHHH - unicode (U+HHHH) 290 | \UHHHHHHHH - unicode (U+HHHHHHHH) 291 | ``` 292 | 293 | Any Unicode character may be escaped with the `\xHH`, `\uHHHH`, or `\UHHHHHHHH` 294 | forms. The escape codes must be Unicode 295 | [scalar values](https://unicode.org/glossary/#unicode_scalar_value). 296 | 297 | Keep in mind that all TOML strings are sequences of Unicode characters, _not_ 298 | byte sequences. For binary data, avoid using these escape codes. Instead, 299 | external binary-to-text encoding strategies, like hexadecimal sequences or 300 | [Base64](https://www.base64decode.org/), are recommended for converting between 301 | bytes and strings. 302 | 303 | All other escape sequences not listed above are reserved; if they are used, TOML 304 | should produce an error. 305 | 306 | Sometimes you need to express passages of text (e.g. translation files) or would 307 | like to break up a very long string into multiple lines. TOML makes this easy. 308 | 309 | **Multi-line basic strings** are surrounded by three quotation marks on each 310 | side and allow newlines. A newline immediately following the opening delimiter 311 | will be trimmed. All other whitespace and newline characters remain intact. 312 | 313 | ```toml 314 | str1 = """ 315 | Roses are red 316 | Violets are blue""" 317 | ``` 318 | 319 | TOML parsers should feel free to normalize newline to whatever makes sense for 320 | their platform. 321 | 322 | ```toml 323 | # On a Unix system, the above multi-line string will most likely be the same as: 324 | str2 = "Roses are red\nViolets are blue" 325 | 326 | # On a Windows system, it will most likely be equivalent to: 327 | str3 = "Roses are red\r\nViolets are blue" 328 | ``` 329 | 330 | For writing long strings without introducing extraneous whitespace, use a "line 331 | ending backslash". When the last non-whitespace character on a line is an 332 | unescaped `\`, it will be trimmed along with all whitespace (including newlines) 333 | up to the next non-whitespace character or closing delimiter. All of the escape 334 | sequences that are valid for basic strings are also valid for multi-line basic 335 | strings. 336 | 337 | ```toml 338 | # The following strings are byte-for-byte equivalent: 339 | str1 = "The quick brown fox jumps over the lazy dog." 340 | 341 | str2 = """ 342 | The quick brown \ 343 | 344 | 345 | fox jumps over \ 346 | the lazy dog.""" 347 | 348 | str3 = """\ 349 | The quick brown \ 350 | fox jumps over \ 351 | the lazy dog.\ 352 | """ 353 | ``` 354 | 355 | Any Unicode character may be used except those that must be escaped: backslash 356 | and the control characters other than tab, line feed, and carriage return 357 | (U+0000 to U+0008, U+000B, U+000C, U+000E to U+001F, U+007F). Carriage returns 358 | (U+000D) are only allowed as part of a newline sequence. 359 | 360 | You can write a quotation mark, or two adjacent quotation marks, anywhere inside 361 | a multi-line basic string. They can also be written just inside the delimiters. 362 | 363 | ```toml 364 | str4 = """Here are two quotation marks: "". Simple enough.""" 365 | # str5 = """Here are three quotation marks: """.""" # INVALID 366 | str5 = """Here are three quotation marks: ""\".""" 367 | str6 = """Here are fifteen quotation marks: ""\"""\"""\"""\"""\".""" 368 | 369 | # "This," she said, "is just a pointless statement." 370 | str7 = """"This," she said, "is just a pointless statement."""" 371 | ``` 372 | 373 | If you're a frequent specifier of Windows paths or regular expressions, then 374 | having to escape backslashes quickly becomes tedious and error-prone. To help, 375 | TOML supports literal strings which do not allow escaping at all. 376 | 377 | **Literal strings** are surrounded by single quotes. Like basic strings, they 378 | must appear on a single line: 379 | 380 | ```toml 381 | # What you see is what you get. 382 | winpath = 'C:\Users\nodejs\templates' 383 | winpath2 = '\\ServerX\admin$\system32\' 384 | quoted = 'Tom "Dubs" Preston-Werner' 385 | regex = '<\i\c*\s*>' 386 | ``` 387 | 388 | Since there is no escaping, there is no way to write a single quote inside a 389 | literal string enclosed by single quotes. Luckily, TOML supports a multi-line 390 | version of literal strings that solves this problem. 391 | 392 | **Multi-line literal strings** are surrounded by three single quotes on each 393 | side and allow newlines. Like literal strings, there is no escaping whatsoever. 394 | A newline immediately following the opening delimiter will be trimmed. TOML 395 | parsers must normalize newlines in the same manner as multi-line basic strings. 396 | 397 | All other content between the delimiters is interpreted as-is without 398 | modification. 399 | 400 | ```toml 401 | regex2 = '''I [dw]on't need \d{2} apples''' 402 | lines = ''' 403 | The first newline is 404 | trimmed in literal strings. 405 | All other whitespace 406 | is preserved. 407 | ''' 408 | ``` 409 | 410 | You can write 1 or 2 single quotes anywhere within a multi-line literal string, 411 | but sequences of three or more single quotes are not permitted. 412 | 413 | ```toml 414 | quot15 = '''Here are fifteen quotation marks: """""""""""""""''' 415 | 416 | # apos15 = '''Here are fifteen apostrophes: '''''''''''''''''' # INVALID 417 | apos15 = "Here are fifteen apostrophes: '''''''''''''''" 418 | 419 | # 'That,' she said, 'is still pointless.' 420 | str = ''''That,' she said, 'is still pointless.'''' 421 | ``` 422 | 423 | Control characters other than tab are not permitted in a literal string. 424 | 425 | ## Integer 426 | 427 | Integers are whole numbers. Positive numbers may be prefixed with a plus sign. 428 | Negative numbers are prefixed with a minus sign. 429 | 430 | ```toml 431 | int1 = +99 432 | int2 = 42 433 | int3 = 0 434 | int4 = -17 435 | ``` 436 | 437 | For large numbers, you may use underscores between digits to enhance 438 | readability. Each underscore must be surrounded by at least one digit on each 439 | side. 440 | 441 | ```toml 442 | int5 = 1_000 443 | int6 = 5_349_221 444 | int7 = 53_49_221 # Indian number system grouping 445 | int8 = 1_2_3_4_5 # VALID but discouraged 446 | ``` 447 | 448 | Leading zeros are not allowed. Integer values `-0` and `+0` are valid and 449 | identical to an unprefixed zero. 450 | 451 | Non-negative integer values may also be expressed in hexadecimal, octal, or 452 | binary. In these formats, leading `+` is not allowed and leading zeros are 453 | allowed (after the prefix). Hex values are case-insensitive. Underscores are 454 | allowed between digits (but not between the prefix and the value). 455 | 456 | ```toml 457 | # hexadecimal with prefix `0x` 458 | hex1 = 0xDEADBEEF 459 | hex2 = 0xdeadbeef 460 | hex3 = 0xdead_beef 461 | 462 | # octal with prefix `0o` 463 | oct1 = 0o01234567 464 | oct2 = 0o755 # useful for Unix file permissions 465 | 466 | # binary with prefix `0b` 467 | bin1 = 0b11010110 468 | ``` 469 | 470 | Arbitrary 64-bit signed integers (from −2^63 to 2^63−1) should be accepted and 471 | handled losslessly. If an integer cannot be represented losslessly, an error 472 | must be thrown. 473 | 474 | ## Float 475 | 476 | Floats should be implemented as IEEE 754 binary64 values. 477 | 478 | A float consists of an integer part (which follows the same rules as decimal 479 | integer values) followed by a fractional part and/or an exponent part. If both a 480 | fractional part and exponent part are present, the fractional part must precede 481 | the exponent part. 482 | 483 | ```toml 484 | # fractional 485 | flt1 = +1.0 486 | flt2 = 3.1415 487 | flt3 = -0.01 488 | 489 | # exponent 490 | flt4 = 5e+22 491 | flt5 = 1e06 492 | flt6 = -2E-2 493 | 494 | # both 495 | flt7 = 6.626e-34 496 | ``` 497 | 498 | A fractional part is a decimal point followed by one or more digits. 499 | 500 | An exponent part is an E (upper or lower case) followed by an integer part 501 | (which follows the same rules as decimal integer values but may include leading 502 | zeros). 503 | 504 | The decimal point, if used, must be surrounded by at least one digit on each 505 | side. 506 | 507 | ``` 508 | # INVALID FLOATS 509 | invalid_float_1 = .7 510 | invalid_float_2 = 7. 511 | invalid_float_3 = 3.e+20 512 | ``` 513 | 514 | Similar to integers, you may use underscores to enhance readability. Each 515 | underscore must be surrounded by at least one digit. 516 | 517 | ```toml 518 | flt8 = 224_617.445_991_228 519 | ``` 520 | 521 | Float values `-0.0` and `+0.0` are valid and should map according to IEEE 754. 522 | 523 | Special float values can also be expressed. They are always lowercase. 524 | 525 | ```toml 526 | # infinity 527 | sf1 = inf # positive infinity 528 | sf2 = +inf # positive infinity 529 | sf3 = -inf # negative infinity 530 | 531 | # not a number 532 | sf4 = nan # actual sNaN/qNaN encoding is implementation-specific 533 | sf5 = +nan # same as `nan` 534 | sf6 = -nan # valid, actual encoding is implementation-specific 535 | ``` 536 | 537 | ## Boolean 538 | 539 | Booleans are just the tokens you're used to. Always lowercase. 540 | 541 | ```toml 542 | bool1 = true 543 | bool2 = false 544 | ``` 545 | 546 | ## Offset Date-Time 547 | 548 | To unambiguously represent a specific instant in time, you may use an 549 | [RFC 3339](https://tools.ietf.org/html/rfc3339) formatted date-time with offset. 550 | 551 | ```toml 552 | odt1 = 1979-05-27T07:32:00Z 553 | odt2 = 1979-05-27T00:32:00-07:00 554 | odt3 = 1979-05-27T00:32:00.5-07:00 555 | odt4 = 1979-05-27T00:32:00.999999-07:00 556 | ``` 557 | 558 | For the sake of readability, you may replace the T delimiter between date and 559 | time with a space character (as permitted by RFC 3339 section 5.6). 560 | 561 | ```toml 562 | odt4 = 1979-05-27 07:32:00Z 563 | ``` 564 | 565 | One exception to RFC 3339 is permitted: seconds may be omitted, in which case 566 | `:00` will be assumed. The offset immediately follows the minutes. 567 | 568 | ```toml 569 | odt5 = 1979-05-27 07:32Z 570 | odt6 = 1979-05-27 07:32-07:00 571 | ``` 572 | 573 | Implementations are required to support at least millisecond precision. 574 | Additional digits of precision may be specified, but if they exceed the 575 | supported precision then the extra digits must be truncated, not rounded. 576 | 577 | ## Local Date-Time 578 | 579 | If you omit the offset from an [RFC 3339](https://tools.ietf.org/html/rfc3339) 580 | formatted date-time, it will represent the given date-time without any relation 581 | to an offset or timezone. It cannot be converted to an instant in time without 582 | additional information. Conversion to an instant, if required, is 583 | implementation-specific. 584 | 585 | ```toml 586 | ldt1 = 1979-05-27T07:32:00 587 | ldt2 = 1979-05-27T07:32:00.5 588 | ldt3 = 1979-05-27T00:32:00.999999 589 | ``` 590 | 591 | Seconds may be omitted, in which case `:00` will be assumed. 592 | 593 | ```toml 594 | ldt3 = 1979-05-27T07:32 595 | ``` 596 | 597 | Millisecond precision is required. Further precision of fractional seconds is 598 | implementation-specific. If the value contains greater precision than the 599 | implementation can support, the additional precision must be truncated, not 600 | rounded. 601 | 602 | Implementations are required to support at least millisecond precision. 603 | Additional digits of precision may be specified, but if they exceed the 604 | supported precision then the extra digits must be truncated, not rounded. 605 | 606 | ## Local Date 607 | 608 | If you include only the date portion of an 609 | [RFC 3339](https://tools.ietf.org/html/rfc3339) formatted date-time, it will 610 | represent that entire day without any relation to an offset or timezone. 611 | 612 | ```toml 613 | ld1 = 1979-05-27 614 | ``` 615 | 616 | ## Local Time 617 | 618 | If you include only the time portion of an 619 | [RFC 3339](https://tools.ietf.org/html/rfc3339) formatted date-time, it will 620 | represent that time of day without any relation to a specific day or any offset 621 | or timezone. 622 | 623 | ```toml 624 | lt1 = 07:32:00 625 | lt2 = 00:32:00.5 626 | lt3 = 00:32:00.999999 627 | ``` 628 | 629 | Seconds may be omitted, in which case `:00` will be assumed. 630 | 631 | ```toml 632 | lt3 = 07:32 633 | ``` 634 | 635 | Millisecond precision is required. Further precision of fractional seconds is 636 | implementation-specific. If the value contains greater precision than the 637 | implementation can support, the additional precision must be truncated, not 638 | rounded. 639 | 640 | Implementations are required to support at least millisecond precision. 641 | Additional digits of precision may be specified, but if they exceed the 642 | supported precision then the extra digits must be truncated, not rounded. 643 | 644 | ## Array 645 | 646 | Arrays are ordered values surrounded by square brackets. Whitespace is ignored. 647 | Elements are separated by commas. Arrays can contain values of the same data 648 | types as allowed in key/value pairs. Values of different types may be mixed. 649 | 650 | ```toml 651 | integers = [ 1, 2, 3 ] 652 | colors = [ "red", "yellow", "green" ] 653 | nested_arrays_of_ints = [ [ 1, 2 ], [3, 4, 5] ] 654 | nested_mixed_array = [ [ 1, 2 ], ["a", "b", "c"] ] 655 | string_array = [ "all", 'strings', """are the same""", '''type''' ] 656 | 657 | # Mixed-type arrays are allowed 658 | numbers = [ 0.1, 0.2, 0.5, 1, 2, 5 ] 659 | contributors = [ 660 | "Foo Bar ", 661 | { name = "Baz Qux", email = "bazqux@example.com", url = "https://example.com/bazqux" } 662 | ] 663 | ``` 664 | 665 | Arrays can span multiple lines. A terminating comma (also called a trailing 666 | comma) is permitted after the last value of the array. Any number of newlines 667 | and comments may precede values, commas, and the closing bracket. Indentation 668 | between array values and commas is treated as whitespace and ignored. 669 | 670 | ```toml 671 | integers2 = [ 672 | 1, 2, 3 673 | ] 674 | 675 | integers3 = [ 676 | 1, 677 | 2, # this is ok 678 | ] 679 | ``` 680 | 681 | ## Table 682 | 683 | Tables (also known as hash tables or dictionaries) are collections of key/value 684 | pairs. They are defined by headers, with square brackets on a line by 685 | themselves. You can tell headers apart from arrays because arrays are only ever 686 | values. 687 | 688 | ```toml 689 | [table] 690 | ``` 691 | 692 | Under that, and until the next header or EOF, are the key/values of that table. 693 | Key/value pairs within tables are not guaranteed to be in any specific order. 694 | 695 | ```toml 696 | [table-1] 697 | key1 = "some string" 698 | key2 = 123 699 | 700 | [table-2] 701 | key1 = "another string" 702 | key2 = 456 703 | ``` 704 | 705 | Naming rules for tables are the same as for keys (see definition of 706 | [Keys](#user-content-keys) above). 707 | 708 | ```toml 709 | [dog."tater.man"] 710 | type.name = "pug" 711 | ``` 712 | 713 | In JSON land, that would give you the following structure: 714 | 715 | ```json 716 | { "dog": { "tater.man": { "type": { "name": "pug" } } } } 717 | ``` 718 | 719 | Whitespace around the key is ignored. However, best practice is to not use any 720 | extraneous whitespace. 721 | 722 | ```toml 723 | [a.b.c] # this is best practice 724 | [ d.e.f ] # same as [d.e.f] 725 | [ g . h . i ] # same as [g.h.i] 726 | [ j . "ʞ" . 'l' ] # same as [j."ʞ".'l'] 727 | ``` 728 | 729 | Indentation is treated as whitespace and ignored. 730 | 731 | You don't need to specify all the super-tables if you don't want to. TOML knows 732 | how to do it for you. 733 | 734 | ```toml 735 | # [x] you 736 | # [x.y] don't 737 | # [x.y.z] need these 738 | [x.y.z.w] # for this to work 739 | 740 | [x] # defining a super-table afterward is ok 741 | ``` 742 | 743 | Empty tables are allowed and simply have no key/value pairs within them. 744 | 745 | Like keys, you cannot define a table more than once. Doing so is invalid. 746 | 747 | ``` 748 | # DO NOT DO THIS 749 | 750 | [fruit] 751 | apple = "red" 752 | 753 | [fruit] 754 | orange = "orange" 755 | ``` 756 | 757 | ``` 758 | # DO NOT DO THIS EITHER 759 | 760 | [fruit] 761 | apple = "red" 762 | 763 | [fruit.apple] 764 | texture = "smooth" 765 | ``` 766 | 767 | Defining tables out-of-order is discouraged. 768 | 769 | ```toml 770 | # VALID BUT DISCOURAGED 771 | [fruit.apple] 772 | [animal] 773 | [fruit.orange] 774 | ``` 775 | 776 | ```toml 777 | # RECOMMENDED 778 | [fruit.apple] 779 | [fruit.orange] 780 | [animal] 781 | ``` 782 | 783 | The top-level table, also called the root table, starts at the beginning of the 784 | document and ends just before the first table header (or EOF). Unlike other 785 | tables, it is nameless and cannot be relocated. 786 | 787 | ```toml 788 | # Top-level table begins. 789 | name = "Fido" 790 | breed = "pug" 791 | 792 | # Top-level table ends. 793 | [owner] 794 | name = "Regina Dogman" 795 | member_since = 1999-08-04 796 | ``` 797 | 798 | Dotted keys create and define a table for each key part before the last one. Any 799 | such table must have all its key/value pairs defined under the current `[table]` 800 | header, or in the root table if defined before all headers, or in one inline 801 | table. 802 | 803 | ```toml 804 | fruit.apple.color = "red" 805 | # Defines a table named fruit 806 | # Defines a table named fruit.apple 807 | 808 | fruit.apple.taste.sweet = true 809 | # Defines a table named fruit.apple.taste 810 | # fruit and fruit.apple were already created 811 | ``` 812 | 813 | Since tables cannot be defined more than once, redefining such tables using a 814 | `[table]` header is not allowed. Likewise, using dotted keys to redefine tables 815 | already defined in `[table]` form is not allowed. The `[table]` form can, 816 | however, be used to define sub-tables within tables defined via dotted keys. 817 | 818 | ```toml 819 | [fruit] 820 | apple.color = "red" 821 | apple.taste.sweet = true 822 | 823 | # [fruit.apple] # INVALID 824 | # [fruit.apple.taste] # INVALID 825 | 826 | [fruit.apple.texture] # you can add sub-tables 827 | smooth = true 828 | ``` 829 | 830 | ## Inline Table 831 | 832 | Inline tables provide a more compact syntax for expressing tables. They are 833 | especially useful for grouped nested data that can otherwise quickly become 834 | verbose. 835 | 836 | Inline tables are fully defined within curly braces: `{` and `}`. Within the 837 | braces, zero or more comma-separated key/value pairs may appear. Key/value pairs 838 | take the same form as key/value pairs in standard tables. All value types are 839 | allowed, including inline tables. 840 | 841 | Inline tables can have multiple key/value pairs on the same line, or they can be 842 | put on different lines. A terminating comma (also called trailing comma) is 843 | permitted after the last key/value pair. 844 | 845 | ```toml 846 | name = { first = "Tom", last = "Preston-Werner" } 847 | point = {x=1, y=2} 848 | animal = { type.name = "pug" } 849 | contact = { 850 | personal = { 851 | name = "Donald Duck", 852 | email = "donald@duckburg.com", 853 | }, 854 | work = { 855 | name = "Coin cleaner", 856 | email = "donald@ScroogeCorp.com", 857 | }, 858 | } 859 | ``` 860 | 861 | The inline tables above are identical to the following standard table 862 | definitions: 863 | 864 | ```toml 865 | [name] 866 | first = "Tom" 867 | last = "Preston-Werner" 868 | 869 | [point] 870 | x = 1 871 | y = 2 872 | 873 | [animal] 874 | type.name = "pug" 875 | 876 | [contact.personal] 877 | name = "Donald Duck" 878 | email = "donald@duckburg.com" 879 | 880 | [contact.work] 881 | name = "Coin cleaner" 882 | email = "donald@ScroogeCorp.com" 883 | ``` 884 | 885 | Inline tables are fully self-contained and define all keys and sub-tables within 886 | them. Keys and sub-tables cannot be added outside the braces. 887 | 888 | ```toml 889 | [product] 890 | type = { name = "Nail" } 891 | # type.edible = false # INVALID 892 | ``` 893 | 894 | Similarly, inline tables cannot be used to add keys or sub-tables to an 895 | already-defined table. 896 | 897 | ```toml 898 | [product] 899 | type.name = "Nail" 900 | # type = { edible = false } # INVALID 901 | ``` 902 | 903 | ## Array of Tables 904 | 905 | The last syntax that has not yet been described allows writing arrays of tables. 906 | These can be expressed by using a header with a name in double brackets. The 907 | first instance of that header defines the array and its first table element, and 908 | each subsequent instance creates and defines a new table element in that array. 909 | The tables are inserted into the array in the order encountered. 910 | 911 | ```toml 912 | [[product]] 913 | name = "Hammer" 914 | sku = 738594937 915 | 916 | [[product]] # empty table within the array 917 | 918 | [[product]] 919 | name = "Nail" 920 | sku = 284758393 921 | 922 | color = "gray" 923 | ``` 924 | 925 | In JSON land, that would give you the following structure. 926 | 927 | ```json 928 | { 929 | "product": [ 930 | { "name": "Hammer", "sku": 738594937 }, 931 | {}, 932 | { "name": "Nail", "sku": 284758393, "color": "gray" } 933 | ] 934 | } 935 | ``` 936 | 937 | Any reference to an array of tables points to the most recently defined table 938 | element of the array. This allows you to define sub-tables, and even sub-arrays 939 | of tables, inside the most recent table. 940 | 941 | ```toml 942 | [[fruits]] 943 | name = "apple" 944 | 945 | [fruits.physical] # subtable 946 | color = "red" 947 | shape = "round" 948 | 949 | [[fruits.varieties]] # nested array of tables 950 | name = "red delicious" 951 | 952 | [[fruits.varieties]] 953 | name = "granny smith" 954 | 955 | 956 | [[fruits]] 957 | name = "banana" 958 | 959 | [[fruits.varieties]] 960 | name = "plantain" 961 | ``` 962 | 963 | The above TOML maps to the following JSON. 964 | 965 | ```json 966 | { 967 | "fruits": [ 968 | { 969 | "name": "apple", 970 | "physical": { 971 | "color": "red", 972 | "shape": "round" 973 | }, 974 | "varieties": [{ "name": "red delicious" }, { "name": "granny smith" }] 975 | }, 976 | { 977 | "name": "banana", 978 | "varieties": [{ "name": "plantain" }] 979 | } 980 | ] 981 | } 982 | ``` 983 | 984 | If the parent of a table or array of tables is an array element, that element 985 | must already have been defined before the child can be defined. Attempts to 986 | reverse that ordering must produce an error at parse time. 987 | 988 | ``` 989 | # INVALID TOML DOC 990 | [fruit.physical] # subtable, but to which parent element should it belong? 991 | color = "red" 992 | shape = "round" 993 | 994 | [[fruit]] # parser must throw an error upon discovering that "fruit" is 995 | # an array rather than a table 996 | name = "apple" 997 | ``` 998 | 999 | Attempting to append to a statically defined array, even if that array is empty, 1000 | must produce an error at parse time. 1001 | 1002 | ``` 1003 | # INVALID TOML DOC 1004 | fruits = [] 1005 | 1006 | [[fruits]] # Not allowed 1007 | ``` 1008 | 1009 | Attempting to define a normal table with the same name as an already established 1010 | array must produce an error at parse time. Attempting to redefine a normal table 1011 | as an array must likewise produce a parse-time error. 1012 | 1013 | ``` 1014 | # INVALID TOML DOC 1015 | [[fruits]] 1016 | name = "apple" 1017 | 1018 | [[fruits.varieties]] 1019 | name = "red delicious" 1020 | 1021 | # INVALID: This table conflicts with the previous array of tables 1022 | [fruits.varieties] 1023 | name = "granny smith" 1024 | 1025 | [fruits.physical] 1026 | color = "red" 1027 | shape = "round" 1028 | 1029 | # INVALID: This array of tables conflicts with the previous table 1030 | [[fruits.physical]] 1031 | color = "green" 1032 | ``` 1033 | 1034 | You may also use inline tables where appropriate: 1035 | 1036 | ```toml 1037 | points = [ { x = 1, y = 2, z = 3 }, 1038 | { x = 7, y = 8, z = 9 }, 1039 | { x = 2, y = 4, z = 8 } ] 1040 | ``` 1041 | 1042 | ## Filename Extension 1043 | 1044 | TOML files should use the extension `.toml`. 1045 | 1046 | ## MIME Type 1047 | 1048 | When transferring TOML files over the internet, the appropriate MIME type is 1049 | `application/toml`. 1050 | 1051 | ## ABNF Grammar 1052 | 1053 | A formal description of TOML's syntax is available, as a separate [ABNF 1054 | file][abnf]. 1055 | 1056 | [abnf]: ./toml.abnf 1057 | --------------------------------------------------------------------------------