1+ import logging
12import os
23import re
34
45from application .defs .cheatsheet_defs import CheatsheetRecord
56
67PARSER_VERSION = "v1"
7- FALLBACK_USED = "false"
88
99CANONICAL_BASE_URL = "https://cheatsheetseries.owasp.org/cheatsheets/"
1010
@@ -41,28 +41,44 @@ def _extract_body_after_heading(markdown: str, heading_match: re.Match) -> str:
4141
4242
4343def _extract_summary (markdown : str ) -> str :
44- """Extract a summary section from cheatsheet markdown."""
44+ """Extract summary from Introduction section in cheatsheet markdown."""
4545
46- all_heading_matches = list (_ANY_HEADING_RE .finditer (markdown ))
47-
48- for match in all_heading_matches :
49- heading_text = match .group ().lstrip ("#" ).strip ()
50-
51- if heading_text .lower () == "introduction" :
46+ for match in _ANY_HEADING_RE .finditer (markdown ):
47+ if match .group ().lstrip ("#" ).strip ().lower () == "introduction" :
5248 body = _extract_body_after_heading (markdown , match )
53-
5449 if body :
5550 return body
5651
57- break
52+ raise ValueError (
53+ "_extract_summary: no suitable summary section could be extracted from markdown."
54+ )
55+
5856
59- for match in all_heading_matches :
60- body = _extract_body_after_heading (markdown , match )
57+ def _extract_title (markdown : str ) -> str :
58+ """Extract H1 title from cheatsheet markdown."""
59+
60+ match = _TITLE_RE .search (markdown )
61+ if not match :
62+ raise ValueError ("_extract_title: no title found in markdown." )
63+
64+ return match .group ("title" ).strip ()
6165
66+
67+ def _fallback_title () -> str :
68+ """Return fallback title for malformed markdown."""
69+
70+ return "No title found."
71+
72+
73+ def _fallback_summary (markdown : str ) -> str :
74+ """Return first non-empty paragraph after any heading, or 'No summary found.'"""
75+
76+ for match in _ANY_HEADING_RE .finditer (markdown ):
77+ body = _extract_body_after_heading (markdown , match )
6278 if body :
6379 return body
6480
65- raise ValueError ( "_extract_summary: no summary could be extracted from markdown." )
81+ return "No summary found."
6682
6783
6884def extract_cheatsheet_record (
@@ -71,12 +87,24 @@ def extract_cheatsheet_record(
7187) -> CheatsheetRecord :
7288 """Extract a structured CheatsheetRecord from markdown content."""
7389
74- title_match = _TITLE_RE .search (markdown )
75- title = title_match .group ("title" ).strip ()
90+ fallback_used = "false"
91+
92+ try :
93+ title = _extract_title (markdown )
94+ except ValueError as e :
95+ logging .warning (str (e ))
96+ title = _fallback_title ()
97+ fallback_used = "true"
7698
99+ # Headings can be empty.
77100 headings = [m .group ("heading" ).strip () for m in _HEADING_RE .finditer (markdown )]
78101
79- summary = _extract_summary (markdown )
102+ try :
103+ summary = _extract_summary (markdown )
104+ except ValueError as e :
105+ logging .warning (str (e ))
106+ summary = _fallback_summary (markdown )
107+ fallback_used = "true"
80108
81109 source_id = _derive_source_id (source_path )
82110 hyperlink = _derive_hyperlink (source_path )
@@ -91,6 +119,6 @@ def extract_cheatsheet_record(
91119 category_hints = [],
92120 metadata = {
93121 "parser_version" : PARSER_VERSION ,
94- "fallback_used" : FALLBACK_USED ,
122+ "fallback_used" : fallback_used ,
95123 },
96124 )
0 commit comments