Files
inkwell/core/testdata/grammar.json
T
bvandeusenandClaude Opus 5.5 0ecff7eeb9 Core: tag names fold every letter, as the server does (#5385)
SQLite's lower() folds ASCII only, so a device could hold "Café" and
"CAFÉ" as two tags while the server held one. derive::fold (to_lowercase)
is now the one comparison. It is registered as the deterministic SQL function
fold() on every connection (schema::migrate), and find_or_create, the rename
clash, the pull clash and the unique index all use it. derive's push_unique
used eq_ignore_ascii_case and now folds the same way.

v14 merges pairs a device already holds before rebuilding the index. The
older row survives, as in rename_label. Memberships move with via_tag kept,
affected notes go dirty, and the merged-away row is a pending delete. It is
written out rather than calling store::merge_labels so the migration doesn't
depend on store code that later versions may change.

rusqlite gains its "functions" feature (operator-approved, 2026-10-08).
grammar.json gains "#café and #CAFÉ" -> ["café"], which all three
implementations run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 17:01:42 -04:00

123 lines
7.8 KiB
JSON

{
"_about": [
"The cases every implementation of the note grammar is tested against.",
"One file, read by four test suites: core (derive.rs), the server (checklist.py, tags.py, helpers.py), the web (markdown.ts, colors.ts) and, for the tint, Android (DerivedTint.kt, which pins the same values by hand).",
"A difference between any two implementations is a note that changes shape when it syncs. Add a case here, not to one suite.",
"Lives under core/ because core is the definition, and because core/ is in the desktop, Android and server file sets, so changing a case reruns every suite that reads it.",
"display_titles: a note's name is its first line that says anything once a task marker is stripped, cut to 200 characters (not bytes). Lines split on \\n alone, as the grammar does everywhere.",
"urls: the links in a body the server unfurls (found), and the one a note that is nothing but a link files its preview under (lone). Trailing .,;:!? is the sentence's, not the link's, on every surface.",
"recurrences: the repeat rules a reminder can carry, as stored. The server, the core and the web's editor each hold the list; Android's picker pins it by hand, as it does the tint.",
"Tag cases are plain text on purpose. The web's renderer lets `code` and **bold** claim a `#` first, which the derivers do not; that is a rendering choice, not grammar, and is tested where it lives."
],
"task_lines": [
{ "line": "- [ ] milk", "item": { "checked": false, "text": "milk" } },
{ "line": "- [x] milk", "item": { "checked": true, "text": "milk" } },
{ "line": "- [X] milk", "item": { "checked": true, "text": "milk" } },
{ "line": "* [ ] star bullet", "item": { "checked": false, "text": "star bullet" } },
{ "line": " - [ ] indented", "item": { "checked": false, "text": "indented" } },
{ "line": "\t- [ ] tab indent", "item": { "checked": false, "text": "tab indent" } },
{ "line": "- [ ] two spaces after the bullet", "item": { "checked": false, "text": "two spaces after the bullet" } },
{ "line": "- [ ]", "item": { "checked": false, "text": "" } },
{ "line": "- [ ] ", "item": { "checked": false, "text": "" } },
{ "line": "- [ ] trailing space kept ", "item": { "checked": false, "text": "trailing space kept " } },
{ "line": "- [ ]x", "item": null },
{ "line": "-[ ] x", "item": null },
{ "line": "+ [ ] plus bullet", "item": null },
{ "line": "- [y] x", "item": null },
{ "line": "- [ ] x", "item": null },
{ "line": "- [] empty brackets", "item": null },
{ "line": "[ ] no bullet at all", "item": null },
{ "line": "text - [ ] x", "item": null },
{ "line": "- milk", "item": null },
{ "line": "", "item": null }
],
"rendered_items": [
{ "text": "milk", "checked": false, "line": "- [ ] milk" },
{ "text": "milk", "checked": true, "line": "- [x] milk" },
{ "text": "", "checked": false, "line": "- [ ]" },
{ "text": "", "checked": true, "line": "- [x]" }
],
"tags": [
{ "body": "#todo buy milk", "tags": ["todo"] },
{ "body": "buy #milk and #eggs", "tags": ["milk", "eggs"] },
{ "body": "#Todo and #todo", "tags": ["Todo"] },
{ "body": "#café and #CAFÉ", "tags": ["café"] },
{ "body": "line one\n#two", "tags": ["two"] },
{ "body": "#tag, and #more.", "tags": ["tag", "more"] },
{ "body": "#x-y_z9", "tags": ["x-y_z9"] },
{ "body": "#café #über", "tags": ["café", "über"] },
{ "body": "(#todo)", "tags": [] },
{ "body": "end.#tag", "tags": [] },
{ "body": "https://x.com/#section", "tags": [] },
{ "body": "#tag#more", "tags": ["tag"] },
{ "body": "a#b", "tags": [] },
{ "body": "x-#tag", "tags": [] },
{ "body": "##x", "tags": [] },
{ "body": "#1st", "tags": [] },
{ "body": "#2024", "tags": [] },
{ "body": "#_x", "tags": [] },
{ "body": "# heading", "tags": [] },
{ "body": "see https://x.com/page#frag", "tags": [] },
{ "body": "", "tags": [] }
],
"lifts": [
{ "body": "#todo\nreorganize the homepage", "standalone": ["todo"], "inline": [], "lifted": "reorganize the homepage" },
{ "body": "buy milk #grocery", "standalone": [], "inline": ["grocery"], "lifted": "buy milk #grocery" },
{ "body": "first\n\n#todo\n\nsecond", "standalone": ["todo"], "inline": [], "lifted": "first\n\nsecond" },
{ "body": "#todo\ncall #todo later", "standalone": [], "inline": ["todo"], "lifted": "call #todo later" },
{ "body": "#a #b", "standalone": [], "inline": ["a", "b"], "lifted": "#a #b" },
{ "body": "```\n# comment #todo\n```", "standalone": [], "inline": ["todo"], "lifted": "```\n# comment #todo\n```" },
{ "body": "(#todo)\nnotes", "standalone": [], "inline": [], "lifted": "(#todo)\nnotes" }
],
"display_titles": [
{ "body": "", "title": "" },
{ "body": "\n\n Shopping \nmilk", "title": "Shopping" },
{ "body": "- [ ] milk\n- [x] eggs", "title": "milk" },
{ "body": "- [ ]\n- [ ] bread", "title": "bread" },
{ "body": " \n\t\nlate start", "title": "late start" },
{ "body": "one\r\ntwo", "title": "one" },
{ "body": "a\rb\nc", "title": "a\rb" },
{ "body": "a\u2028b\nc", "title": "a\u2028b" },
{ "body": "ééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééé", "title": "éééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééééé" }
],
"urls": [
{ "body": "https://example.com/a", "found": ["https://example.com/a"], "lone": "https://example.com/a" },
{ "body": " https://example.com/a \n", "found": ["https://example.com/a"], "lone": "https://example.com/a" },
{ "body": "https://example.com/a.", "found": ["https://example.com/a"], "lone": "https://example.com/a" },
{ "body": "https://example.com/a?q=1!", "found": ["https://example.com/a?q=1"], "lone": "https://example.com/a?q=1" },
{ "body": "see https://example.com/a, then https://example.com/b.", "found": ["https://example.com/a", "https://example.com/b"], "lone": null },
{ "body": "<https://example.com/a>", "found": ["https://example.com/a"], "lone": null },
{ "body": "https://example.com/a)", "found": ["https://example.com/a"], "lone": null },
{ "body": "https://example.com/a https://example.com/a", "found": ["https://example.com/a"], "lone": null },
{ "body": "ftp://example.com/a", "found": [], "lone": null },
{ "body": "", "found": [], "lone": null }
],
"recurrences": ["daily", "weekly", "monthly", "yearly"],
"tint": {
"keys": ["red", "orange", "yellow", "green", "teal", "blue", "purple", "pink", "gray"],
"hashes": [
{ "id": "00000000-0000-0000-0000-000000000000", "hash": 3192360657, "color": "purple" },
{ "id": "11111111-1111-1111-1111-111111111111", "hash": 1031130113, "color": "blue" },
{ "id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8", "hash": 4043892016, "color": "orange" },
{ "id": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "hash": 1533351232, "color": "orange" }
],
"names": [
{ "name": "todo", "color": "pink" },
{ "name": "grocery", "color": "blue" },
{ "name": "work", "color": "green" },
{ "name": "home", "color": "gray" },
{ "name": "ideas", "color": "green" },
{ "name": "reading", "color": "gray" },
{ "name": "urgent", "color": "red" }
]
}
}