From a304ac5e46757edc494e08cf99ca6577194ef258 Mon Sep 17 00:00:00 2001 From: Tom Softreck Date: Mon, 19 Oct 2026 19:24:42 +0200 Subject: [PATCH 1/3] koru(PLF-226): verified patch run_id: 8d9e64b2eff8 Co-authored-by: Koru Agent --- repatch/scope.py | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/repatch/scope.py b/repatch/scope.py index d763da7..d309c1d 100644 --- a/repatch/scope.py +++ b/repatch/scope.py @@ -2,6 +2,7 @@ from __future__ import annotations +from dataclasses import dataclass, field import re from ._scope_css import ( @@ -136,6 +137,13 @@ def _splice_replacements(text: str, matched_ranges: list[tuple[int, int, str]]) return "".join(spliced_segments) +@dataclass +class _AnnotationContext: + text: str + wanted: set[str] + seen_elements: set[str] = field(default_factory=set) + + def _bind_annotations_to_html( html: str, keep_ids: list[str] | None, @@ -147,14 +155,13 @@ def _bind_annotations_to_html( if not marked_ids: return html - wanted = set(marked_ids) binding_html = str(html or "") + ctx = _AnnotationContext(text=binding_html, wanted=set(marked_ids)) matched_ranges: list[tuple[int, int, str]] = [] - seen_elements: set[str] = set() for match in _TAG_OPEN_RE.finditer(binding_html): - target_range = _annotation_target(binding_html, match, wanted, seen_elements) + target_range = _annotation_target(ctx, match) if target_range: matched_ranges.append(target_range) @@ -164,35 +171,32 @@ def _bind_annotations_to_html( def _find_matched_id( - text: str, + ctx: _AnnotationContext, match: "re.Match[str]", tag: str, attr_map: dict[str, str], - wanted: set[str], ) -> str | None: """Find the target id matching the element among wanted ids.""" element_keys, raw_id, nexu_attr = _element_candidates(tag, attr_map) - hit = wanted & element_keys + hit = ctx.wanted & element_keys if not hit and not raw_id and not nexu_attr: - hit = _label_probe_hit(text, match, tag, attr_map, wanted) + hit = _label_probe_hit(ctx.text, match, tag, attr_map, ctx.wanted) if not hit: return None return list(hit)[0] def _claim_annotation_target( - text: str, + ctx: _AnnotationContext, match: "re.Match[str]", tag: str, attr_map: dict[str, str], - wanted: set[str], - seen_elements: set[str], ) -> str | None: """Resolve and claim an unused target id for the element.""" - matched_id = _find_matched_id(text, match, tag, attr_map, wanted) - if not matched_id or matched_id in seen_elements: + matched_id = _find_matched_id(ctx, match, tag, attr_map) + if not matched_id or matched_id in ctx.seen_elements: return None - seen_elements.add(matched_id) + ctx.seen_elements.add(matched_id) if "data-nexu-target" in attr_map: return None return matched_id @@ -205,17 +209,15 @@ def _format_annotated_tag(match: "re.Match[str]", matched_id: str) -> tuple[int, def _annotation_target( - text: str, + ctx: _AnnotationContext, match: "re.Match[str]", - wanted: set[str], - seen_elements: set[str], ) -> tuple[int, int, str] | None: """Return the replacement range for a matched element, or None to skip.""" tag = match.group(1).lower() if tag in _SKIP_TAGS: return None attr_map = _parse_attrs(match.group(2)) - matched_id = _claim_annotation_target(text, match, tag, attr_map, wanted, seen_elements) + matched_id = _claim_annotation_target(ctx, match, tag, attr_map) if not matched_id: return None return _format_annotated_tag(match, matched_id) From ca2ac8ad7746f9d54dd0aac82c6a2be9911e31d8 Mon Sep 17 00:00:00 2001 From: Tom Softreck Date: Mon, 19 Oct 2026 20:05:18 +0200 Subject: [PATCH 2/3] koru(PLF-239): verified patch run_id: 266769bd4249 Co-authored-by: Koru Agent --- repatch/scope.py | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/repatch/scope.py b/repatch/scope.py index d309c1d..4a5b914 100644 --- a/repatch/scope.py +++ b/repatch/scope.py @@ -144,26 +144,41 @@ class _AnnotationContext: seen_elements: set[str] = field(default_factory=set) -def _bind_annotations_to_html( - html: str, +def _collect_marked_ids( keep_ids: list[str] | None, delete_ids: list[str] | None, -) -> str: +) -> list[str]: + """Normalize keep/delete marks into one ordered, de-duplicated list.""" marked_keep_ids = [str(x).strip() for x in (keep_ids or []) if str(x).strip()] marked_delete_ids = [str(x).strip() for x in (delete_ids or []) if str(x).strip()] - marked_ids = marked_keep_ids + [x for x in marked_delete_ids if x not in marked_keep_ids] - if not marked_ids: - return html + return marked_keep_ids + [x for x in marked_delete_ids if x not in marked_keep_ids] - binding_html = str(html or "") - ctx = _AnnotationContext(text=binding_html, wanted=set(marked_ids)) +def _scan_annotation_targets( + binding_html: str, + wanted: set[str], +) -> list[tuple[int, int, str]]: + """Scan tag opens and collect annotated replacement ranges.""" + ctx = _AnnotationContext(text=binding_html, wanted=wanted) matched_ranges: list[tuple[int, int, str]] = [] - for match in _TAG_OPEN_RE.finditer(binding_html): target_range = _annotation_target(ctx, match) if target_range: matched_ranges.append(target_range) + return matched_ranges + + +def _bind_annotations_to_html( + html: str, + keep_ids: list[str] | None, + delete_ids: list[str] | None, +) -> str: + marked_ids = _collect_marked_ids(keep_ids, delete_ids) + if not marked_ids: + return html + + binding_html = str(html or "") + matched_ranges = _scan_annotation_targets(binding_html, set(marked_ids)) if not matched_ranges: return html From 67f6886b103a07ed9d3477ec3e2633b3d3925ded Mon Sep 17 00:00:00 2001 From: Tom Softreck Date: Mon, 19 Oct 2026 20:03:24 +0200 Subject: [PATCH 3/3] koru(PLF-238): verified patch run_id: 89e53d68bffe Co-authored-by: Koru Agent --- repatch/scope.py | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/repatch/scope.py b/repatch/scope.py index 4a5b914..136fa5d 100644 --- a/repatch/scope.py +++ b/repatch/scope.py @@ -185,34 +185,32 @@ def _bind_annotations_to_html( return _splice_replacements(binding_html, matched_ranges) -def _find_matched_id( - ctx: _AnnotationContext, - match: "re.Match[str]", - tag: str, - attr_map: dict[str, str], -) -> str | None: +@dataclass +class _TagProbe: + ctx: _AnnotationContext + match: "re.Match[str]" + tag: str + attr_map: dict[str, str] + + +def _find_matched_id(probe: _TagProbe) -> str | None: """Find the target id matching the element among wanted ids.""" - element_keys, raw_id, nexu_attr = _element_candidates(tag, attr_map) - hit = ctx.wanted & element_keys + element_keys, raw_id, nexu_attr = _element_candidates(probe.tag, probe.attr_map) + hit = probe.ctx.wanted & element_keys if not hit and not raw_id and not nexu_attr: - hit = _label_probe_hit(ctx.text, match, tag, attr_map, ctx.wanted) + hit = _label_probe_hit(probe.ctx.text, probe.match, probe.tag, probe.attr_map, probe.ctx.wanted) if not hit: return None return list(hit)[0] -def _claim_annotation_target( - ctx: _AnnotationContext, - match: "re.Match[str]", - tag: str, - attr_map: dict[str, str], -) -> str | None: +def _claim_annotation_target(probe: _TagProbe) -> str | None: """Resolve and claim an unused target id for the element.""" - matched_id = _find_matched_id(ctx, match, tag, attr_map) - if not matched_id or matched_id in ctx.seen_elements: + matched_id = _find_matched_id(probe) + if not matched_id or matched_id in probe.ctx.seen_elements: return None - ctx.seen_elements.add(matched_id) - if "data-nexu-target" in attr_map: + probe.ctx.seen_elements.add(matched_id) + if "data-nexu-target" in probe.attr_map: return None return matched_id @@ -232,7 +230,7 @@ def _annotation_target( if tag in _SKIP_TAGS: return None attr_map = _parse_attrs(match.group(2)) - matched_id = _claim_annotation_target(ctx, match, tag, attr_map) + matched_id = _claim_annotation_target(_TagProbe(ctx, match, tag, attr_map)) if not matched_id: return None return _format_annotated_tag(match, matched_id)