A lone link's preview is looked up where the server filed it

The server unfurls what detect_urls finds, trailing .,;:!? trimmed, and files the
preview under that. The web and Android cards looked a lone link's preview up
under body.trim(), punctuation included, so a note reading
"https://example.com/a." never showed its card.

- grammar.json gains a urls section: what the server finds in a body, and the
  link a lone-link note is filed under.
- The web's rule moves out of NoteCard into notes/links.ts loneUrl(); Android's
  LinkPreviewRow gets the same loneUrl(); both trim like the server.
- The server and web suites run the cases; Android's JVM test pins them by hand,
  as it does the tint.

Fixes #5399. DRY pass #2, batch 3 (#5372).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-08 14:30:32 -04:00
co-authored by Claude Opus 5.5
parent 3766d59b2e
commit 1c4bf56058
7 changed files with 99 additions and 13 deletions
+6
View File
@@ -17,6 +17,7 @@ from inkwell.notes.checklist import parse_items, render_item
from inkwell.notes.helpers import derive_display_title
from inkwell.notes.recurrence import REMINDER_RECURRENCES
from inkwell.notes.tags import parse_tags, split_body_tags
from inkwell.unfurl_queue import detect_urls
FIXTURE = json.loads(
(Path(__file__).resolve().parents[1] / "core" / "testdata" / "grammar.json").read_text(encoding="utf-8")
@@ -59,3 +60,8 @@ def test_palette_keys():
"""The palette the server accepts is the fixture's hues plus `default`, the key
unrecognised input lands on. The web checks the same hues (DERIVED_TINT_KEYS)."""
assert NOTE_COLORS == {"default", *FIXTURE["tint"]["keys"]}
@pytest.mark.parametrize("case", FIXTURE["urls"], ids=lambda c: repr(c["body"]))
def test_urls(case):
assert detect_urls(case["body"]) == case["found"]