Skip to content

Keep dotted keys separate from table headers - #103

Closed
jonathangreen wants to merge 1 commit into
pappasam:mainfrom
jonathangreen:pr/1-dotted-keys
Closed

jonathangreen wants to merge 1 commit into
pappasam:mainfrom
jonathangreen:pr/1-dotted-keys

Conversation

@jonathangreen

Copy link
Copy Markdown
Contributor

tomlkit models a dotted key such as b.c = 1 as a table, and the sorter grouped it with the [header] tables of the same parent. That corrupted two kinds of document:

  1. A dotted key was rendered after a header and captured by it. Any header that sorted before the dotted key moved ahead of it in the output, so the key line landed inside that header's scope.

    top.key = 1
    
    [tbl]
    a = 2

    came out as

    [tbl]
    a = 2
    top.key = 1
  2. A dotted key and a header with the same name were coalesced into one table. tomlkit renders a dotted-key table without its parent prefix, so the merged header lost its prefix.

    [a]
    b.c = 1
    
    [a.b.e]
    x = 1

    came out as

    [a]
    b.c = 1
    
    [b.e]
    x = 1

Fix

Dotted keys are key/value lines, so sorted_children_table now groups and sorts them with the keys instead of the headers. They always render ahead of the headers of their table, and a dotted key is never merged with a header of the same name. Sibling dotted keys (a.b = 1 and a.c = 2), which tomlkit stores as separate entries, are still coalesced so their children sort together.

Behaviour change

With key sorting enabled, dotted keys now interleave alphabetically with the plain keys of their table. Previously they were always placed after the plain keys. For example:

[project]
version = "1.0"
urls.homepage = "https://example.com"
name = "demo"
urls.docs = "https://example.com/docs"

used to sort to

[project]
name = "demo"
version = "1.0"
urls.docs = "https://example.com/docs"
urls.homepage = "https://example.com"

and now sorts to

[project]
name = "demo"
urls.docs = "https://example.com/docs"
urls.homepage = "https://example.com"
version = "1.0"

Tests

Two new example files under tests/examples, wired into the existing fixture test:

  • dotted-key-header.toml: a dotted key beside a header of the same name at the top level, inside a table, and as an array of tables. Output must equal input.
  • dotted-key-order.toml: dotted keys at the top level, in a table, and in array-of-tables elements, each followed by headers. Checked with key sorting on and off.

tomlkit models a dotted key such as b.c = 1 as a table, so
sorted_children_table grouped it with the [header] tables. That caused
two corruptions. A dotted key was rendered after any header that sorted
before it, and the header captured it: top.key = 1 followed by [tbl]
came out as tbl.top.key. And a dotted key and a header with the same
name were coalesced into one table, which tomlkit renders without its
parent prefix: [a] containing b.c = 1 followed by [a.b.e] came out as a
top-level [b.e].

Dotted keys are key/value lines. Group and sort them with the keys, so
they always render ahead of the headers and are never merged with one.
Found by running the toml-lang/toml-test suite.
@dimbleby

Copy link
Copy Markdown
Contributor

#102 also fixes this.

The only behaviour difference shown by your testcases is that in dotted-key-order-no-sort-keys, tomlrt preserves the input order z, b.y, a, b.x. That seems more correct: the test is "no sort keys".

@pappasam

Copy link
Copy Markdown
Owner

resolved separately by 0.25.0

@pappasam pappasam closed this Sep 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants