📦 deps(tsl): sync tsl-playbook from f90faa10

Source-Commit: f90faa10c3
This commit is contained in:
ci[bot]
2026-08-13 15:37:54 +08:00
parent 85a9d8ee40
commit 2c38c5fc06
21 changed files with 721 additions and 1825 deletions
+13 -12
View File
@@ -41,6 +41,7 @@ STRUCTURAL_METADATA_RE = re.compile(
r"<!--\s*(?:section-id|quickstart-rule)\s*:.*?-->",
re.DOTALL | re.IGNORECASE,
)
HTML_COMMENT_RE = re.compile(r"<!--.*?-->", re.DOTALL)
IDENTITY_PREFIX = "代码块身份:"
BLOCK_DESCRIPTION_PREFIX = "代码块说明:"
ALLOWED_IDENTITIES = {
@@ -156,7 +157,6 @@ CHINESE_QUERY_PARTICLES = ("的", "是", "吗", "呢", "吧")
ASCII_FILTER_STOP_TOKENS = {
"debug",
"please",
"program",
"tinysoft",
"tsl",
"tsf",
@@ -480,7 +480,7 @@ def load_sections(references_dir: Path = DEFAULT_REFERENCES_DIR) -> list[Section
raise ReferenceStructureError(f"重复 section ID{base_id}")
seen_ids.add(base_id)
tags = _section_tags(local_body)
searchable_body = STRUCTURAL_METADATA_RE.sub(" ", local_body)
searchable_body = HTML_COMMENT_RE.sub(" ", local_body)
searchable_text = normalize(
"\n".join((page.stem, page_title, *heading_path, *tags, searchable_body))
)
@@ -1122,9 +1122,9 @@ def _text_contains_exact_query(text: str, query: str) -> bool:
def _intent_score(section: Section, query: str) -> int:
aliases = PAGE_INTENT_ALIASES.get(section.page.name, ())
return PAGE_INTENT_SCORE * sum(
return PAGE_INTENT_SCORE if any(
_query_contains_phrase(query, alias) for alias in aliases
)
) else 0
def _has_chinese_context(section: Section, query: str) -> bool:
@@ -1161,7 +1161,9 @@ def _tag_matched_tokens(tags: tuple[str, ...], query_token_set: set[str]) -> int
def _code_text(body: str) -> str:
inline = INLINE_CODE_RE.findall(body)
fenced = FENCED_CODE_RE.findall(body)
return normalize("\n".join((*inline, *fenced)))
# 标识符信号只来自 ASCII 代码术语。中文散文会走标题、tag 和正文得分;
# 若把围栏里的“下标数组”等输出标签也当标识符,中文查询会被样例值劫持。
return normalize("\n".join(ASCII_TOKEN_RE.findall("\n".join((*inline, *fenced)))))
def _score_section(section: Section, query: str, mode: str) -> ScoreBreakdown:
@@ -1169,8 +1171,7 @@ def _score_section(section: Section, query: str, mode: str) -> ScoreBreakdown:
tokens = query_tokens(query)
heading_text = normalize("\n".join(section.heading_path))
page_title_text = normalize(section.page_title)
body_without_metadata = STRUCTURAL_METADATA_RE.sub(" ", section.local_body)
body_text = normalize(SECTION_TAG_RE.sub(" ", body_without_metadata))
body_text = normalize(HTML_COMMENT_RE.sub(" ", section.local_body))
tag_text = normalize("\n".join(section.tags))
term_text = _code_text(section.local_body)
expanded_only_tokens = _synonym_tokens(query) - _base_query_tokens(query)
@@ -1356,6 +1357,7 @@ def query_sections(
)
ranked.sort(
key=lambda match: (
match.weak,
-match.score,
*(-value for value in match.priority),
match.section.page.as_posix(),
@@ -1400,10 +1402,9 @@ def _safe_json_string(value: str) -> str:
def _plain_text_summary(body: str, limit: int = 180) -> str:
# 标签是检索元数据,不是事实正文;不能泄进候选摘要。
without_metadata = STRUCTURAL_METADATA_RE.sub(" ", body)
without_tags = SECTION_TAG_RE.sub(" ", without_metadata)
without_fences = FENCED_CODE_RE.sub(" ", without_tags)
# HTML 注释都是维护元数据,不是事实正文;不能泄进候选摘要。
without_comments = HTML_COMMENT_RE.sub(" ", body)
without_fences = FENCED_CODE_RE.sub(" ", without_comments)
without_links = re.sub(
r"!?\[([^\]]*)\]\([^)]+\)", lambda match: match.group(1), without_fences
)
@@ -1464,7 +1465,7 @@ def render_candidates(result: QueryResult) -> str:
def render_section(section: Section) -> str:
body = STRUCTURAL_METADATA_RE.sub("", section.body)
body = HTML_COMMENT_RE.sub("", section.body)
body = re.sub(r"\n{3,}", "\n\n", body).rstrip()
lines = [
"# TSL Syntax Section",