mirror of
https://github.com/zensical/zensical.git
synced 2026-09-23 23:05:34 +00:00
performance: faster autorefs URL membership check
Signed-off-by: Timothée Mazzucotelli <dev@pawamoy.fr>
This commit is contained in:
+33
-7
@@ -117,6 +117,34 @@ class TestStore:
|
||||
"external": "https://example.com/external"
|
||||
}
|
||||
|
||||
def test_urls_are_ordered_and_unique(self) -> None:
|
||||
"""Candidate URLs preserve registration order without duplicates."""
|
||||
store = get_autorefs_store()
|
||||
page = Page("page", "page.html")
|
||||
|
||||
store.register_anchor(page, "identifier", "first")
|
||||
store.register_anchor(page, "identifier", "second")
|
||||
store.register_anchor(page, "identifier", "first")
|
||||
|
||||
assert get_autorefs_page_data("page")["primary"] == {
|
||||
"identifier": ["page#first", "page#second"]
|
||||
}
|
||||
|
||||
def test_page_registrations_remove_urls(self) -> None:
|
||||
"""Reprocessing a page removes its previously registered URLs."""
|
||||
store = get_autorefs_store()
|
||||
first_page = Page("first", "first.html")
|
||||
second_page = Page("second", "second.html")
|
||||
store.register_anchor(first_page, "identifier", "anchor")
|
||||
store.register_anchor(second_page, "identifier", "anchor")
|
||||
|
||||
store.set_page(first_page)
|
||||
|
||||
assert get_autorefs_page_data("first")["primary"] == {}
|
||||
assert get_autorefs_page_data("second")["primary"] == {
|
||||
"identifier": ["second#anchor"]
|
||||
}
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Inline processor
|
||||
@@ -415,8 +443,7 @@ class TestAnchorsTreeprocessor:
|
||||
[](){#alias10}
|
||||
"""),
|
||||
)
|
||||
store = get_autorefs_store()
|
||||
assert store._primary_url_map == {
|
||||
assert get_autorefs_page_data("page")["primary"] == {
|
||||
"foo": ["page#heading-foo"],
|
||||
"heading-foo": ["page#heading-foo"],
|
||||
"bar": ["page#bar"],
|
||||
@@ -474,8 +501,7 @@ class TestAnchorsTreeprocessor:
|
||||
## Heading baz
|
||||
"""),
|
||||
)
|
||||
store = get_autorefs_store()
|
||||
assert store._primary_url_map == {
|
||||
assert get_autorefs_page_data("page")["primary"] == {
|
||||
"heading-foo": ["page#heading-foo"],
|
||||
"heading-bar": ["page#heading-bar"],
|
||||
"heading-baz": ["page#heading-baz"],
|
||||
@@ -510,9 +536,9 @@ class TestHeadingsTreeprocessor:
|
||||
def test_register_heading(self, md: Markdown) -> None:
|
||||
"""A single heading is registered under its toc-generated slug."""
|
||||
md.convert("## Foo")
|
||||
store = get_autorefs_store()
|
||||
assert "foo" in store._primary_url_map
|
||||
assert store._primary_url_map["foo"] == ["page#foo"]
|
||||
assert get_autorefs_page_data("page")["primary"]["foo"] == [
|
||||
"page#foo"
|
||||
]
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"md",
|
||||
|
||||
@@ -27,7 +27,7 @@ import re
|
||||
from abc import ABC, abstractmethod
|
||||
from dataclasses import dataclass
|
||||
from html import escape
|
||||
from typing import TYPE_CHECKING, Any
|
||||
from typing import TYPE_CHECKING, Any, TypeAlias
|
||||
from xml.etree.ElementTree import Element
|
||||
|
||||
from markdown.core import Markdown
|
||||
@@ -59,6 +59,11 @@ if TYPE_CHECKING:
|
||||
|
||||
HTAGS = {"h1", "h2", "h3", "h4", "h5", "h6"}
|
||||
|
||||
# URL order determines which target wins when several are equally
|
||||
# suitable. Dict keys give us that order plus constant-time lookups.
|
||||
OrderedSet: TypeAlias = dict[str, None]
|
||||
URLMap: TypeAlias = dict[str, OrderedSet]
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Globals
|
||||
@@ -81,8 +86,8 @@ class AutorefsStore:
|
||||
self.scan_toc: bool = True
|
||||
self.record_backlinks: bool = False
|
||||
|
||||
self._primary_url_map: dict[str, list[str]] = {}
|
||||
self._secondary_url_map: dict[str, list[str]] = {}
|
||||
self._primary_url_map: URLMap = {}
|
||||
self._secondary_url_map: URLMap = {}
|
||||
self._abs_url_map: dict[str, str] = {}
|
||||
self._title_map: dict[str, str] = {}
|
||||
self._page_registrations: dict[str, set[tuple[bool, str, str]]] = {}
|
||||
@@ -118,7 +123,7 @@ class AutorefsStore:
|
||||
|
||||
@staticmethod
|
||||
def _pop_urls(
|
||||
url_map: dict[str, list[str]],
|
||||
url_map: URLMap,
|
||||
registrations: set[tuple[bool, str, str]],
|
||||
primary: bool,
|
||||
) -> dict[str, list[str]]:
|
||||
@@ -130,12 +135,11 @@ class AutorefsStore:
|
||||
|
||||
result: dict[str, list[str]] = {}
|
||||
for identifier, selected_urls in selected.items():
|
||||
urls = url_map.get(identifier, [])
|
||||
urls = url_map.get(identifier, {})
|
||||
result[identifier] = [url for url in urls if url in selected_urls]
|
||||
remaining = [url for url in urls if url not in selected_urls]
|
||||
if remaining:
|
||||
url_map[identifier] = remaining
|
||||
else:
|
||||
for url in selected_urls:
|
||||
urls.pop(url, None)
|
||||
if not urls:
|
||||
url_map.pop(identifier, None)
|
||||
return result
|
||||
|
||||
@@ -150,11 +154,7 @@ class AutorefsStore:
|
||||
) -> None:
|
||||
url = f"{page.url}#{anchor or identifier}"
|
||||
url_map = self._primary_url_map if primary else self._secondary_url_map
|
||||
if identifier in url_map:
|
||||
if url not in url_map[identifier]:
|
||||
url_map[identifier].append(url)
|
||||
else:
|
||||
url_map[identifier] = [url]
|
||||
url_map.setdefault(identifier, {})[url] = None
|
||||
self._page_registrations.setdefault(page.url, set()).add(
|
||||
(primary, identifier, url)
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user