mirror of
https://github.com/wilsonfreitas/awesome-quant.git
synced 2026-08-24 01:08:05 +00:00
Update site/generate.py: support category-first structure with inline language tags
Changes: - Update parse_readme() to extract languages from backtick tags - Extract languages from inline tags instead of h2 headings - Add languages column to project data - Update build_tags_html() to support multiple language tags per entry - Update generate_html() to use data-languages attribute (space-separated) - Update languages counting logic to extract from inline tags Site now correctly displays multi-language projects with proper filtering support for all languages in the new category-first README structure.
This commit is contained in:
+54
-35
@@ -26,42 +26,45 @@ def slugify(text: str) -> str:
|
|||||||
def parse_readme(path: str) -> list[dict]:
|
def parse_readme(path: str) -> list[dict]:
|
||||||
"""Parse README.md and return a list of project entries (no API data)."""
|
"""Parse README.md and return a list of project entries (no API data)."""
|
||||||
entries = []
|
entries = []
|
||||||
current_language = ""
|
|
||||||
current_category = ""
|
current_category = ""
|
||||||
|
|
||||||
re_h2 = re.compile(r"^## (.+)$")
|
re_h2 = re.compile(r"^## (.+)$")
|
||||||
re_h3 = re.compile(r"^### (.+)$")
|
|
||||||
re_entry = re.compile(r"^\s*- \[(.+?)\]\((.+?)\) - (.+)$")
|
re_entry = re.compile(r"^\s*- \[(.+?)\]\((.+?)\) - (.+)$")
|
||||||
re_github = re.compile(r"\[GitHub\]\((https://github\.com/[\w-]+/[-\w\.]+)\)")
|
re_github = re.compile(r"\[GitHub\]\((https://github\.com/[\w-]+/[-\w\.]+)\)")
|
||||||
|
|
||||||
skip_sections = {"Languages"}
|
|
||||||
|
|
||||||
# Strip markdown badge images before parsing
|
|
||||||
re_badge = re.compile(r"\s*!\[[^\]]*\]\([^)]*\)\s*")
|
re_badge = re.compile(r"\s*!\[[^\]]*\]\([^)]*\)\s*")
|
||||||
|
re_langs = re.compile(r'^((?:`[^`]+`\s*)+)-\s*(.*)$')
|
||||||
|
|
||||||
|
skip_sections = {"Contents"}
|
||||||
|
|
||||||
with open(path, "r", encoding="utf-8") as f:
|
with open(path, "r", encoding="utf-8") as f:
|
||||||
for line in f:
|
for line in f:
|
||||||
line = re_badge.sub(" ", line).rstrip("\n")
|
line = re_badge.sub(" ", line).rstrip("\n")
|
||||||
|
|
||||||
m = re_h2.match(line)
|
m = re_h2.match(line)
|
||||||
if m:
|
|
||||||
current_language = m.group(1).strip()
|
|
||||||
current_category = ""
|
|
||||||
continue
|
|
||||||
|
|
||||||
m = re_h3.match(line)
|
|
||||||
if m:
|
if m:
|
||||||
current_category = m.group(1).strip()
|
current_category = m.group(1).strip()
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if current_language in skip_sections:
|
if current_category in skip_sections:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
m = re_entry.match(line)
|
m = re_entry.match(line)
|
||||||
if m:
|
if m:
|
||||||
name = m.group(1).strip()
|
name = m.group(1).strip()
|
||||||
url = m.group(2).strip()
|
url = m.group(2).strip()
|
||||||
desc = m.group(3).strip()
|
raw_desc = m.group(3).strip()
|
||||||
|
|
||||||
|
# Extract inline language tags
|
||||||
|
m_lang = re_langs.match(raw_desc)
|
||||||
|
if m_lang:
|
||||||
|
lang_str = m_lang.group(1)
|
||||||
|
desc = m_lang.group(2)
|
||||||
|
languages = re.findall(r'`([^`]+)`', lang_str)
|
||||||
|
else:
|
||||||
|
desc = raw_desc
|
||||||
|
languages = []
|
||||||
|
|
||||||
|
primary_language = languages[0] if languages else ""
|
||||||
|
|
||||||
github_url = ""
|
github_url = ""
|
||||||
gh_match = re_github.search(desc)
|
gh_match = re_github.search(desc)
|
||||||
@@ -81,15 +84,15 @@ def parse_readme(path: str) -> list[dict]:
|
|||||||
|
|
||||||
is_cran = "cran.r-project.org" in url
|
is_cran = "cran.r-project.org" in url
|
||||||
is_pypi = "pypi.org" in url or "pypi.python.org" in url
|
is_pypi = "pypi.org" in url or "pypi.python.org" in url
|
||||||
is_commercial = current_language == "Commercial & Proprietary Services"
|
is_commercial = current_category == "Commercial & Proprietary Services"
|
||||||
category = current_category or current_language
|
section_slug = slugify(current_category)
|
||||||
section_slug = slugify(category)
|
|
||||||
|
|
||||||
entries.append(
|
entries.append(
|
||||||
{
|
{
|
||||||
"project": name,
|
"project": name,
|
||||||
"language": current_language,
|
"language": primary_language,
|
||||||
"category": category,
|
"languages": ",".join(languages),
|
||||||
|
"category": current_category,
|
||||||
"section_slug": section_slug,
|
"section_slug": section_slug,
|
||||||
"url": url,
|
"url": url,
|
||||||
"description": desc,
|
"description": desc,
|
||||||
@@ -121,6 +124,8 @@ def load_csv(path: str) -> list[dict]:
|
|||||||
# Extract github_url and repo from CSV data
|
# Extract github_url and repo from CSV data
|
||||||
repo = row.get("repo", "")
|
repo = row.get("repo", "")
|
||||||
row["github_url"] = f"https://github.com/{repo}" if repo else ""
|
row["github_url"] = f"https://github.com/{repo}" if repo else ""
|
||||||
|
# Ensure languages column exists
|
||||||
|
row["languages"] = row.get("languages", row.get("language", ""))
|
||||||
# Clean description: strip [GitHub](url) if present
|
# Clean description: strip [GitHub](url) if present
|
||||||
desc = row.get("description", "")
|
desc = row.get("description", "")
|
||||||
desc = re.sub(
|
desc = re.sub(
|
||||||
@@ -148,25 +153,28 @@ def build_tags_html(e: dict) -> str:
|
|||||||
esc = html.escape
|
esc = html.escape
|
||||||
tags = []
|
tags = []
|
||||||
|
|
||||||
# Language tag
|
# Language tags (from inline backtick tags)
|
||||||
lang = e.get("language", "")
|
languages_str = e.get("languages", e.get("language", ""))
|
||||||
if lang and lang != "Commercial & Proprietary Services" and lang != "Related Lists":
|
languages = [l.strip() for l in languages_str.split(",") if l.strip()]
|
||||||
lang_slug = slugify(lang)
|
skip_langs = {"Commercial & Proprietary Services", "Related Lists",
|
||||||
tags.append(
|
"Reproducing Works, Training & Books", "Cross-Language Frameworks"}
|
||||||
f'<button class="tag tag-lang" data-filter-type="language" '
|
for lang in languages:
|
||||||
f'data-filter-value="{esc(lang)}">{esc(lang_slug)}</button>'
|
if lang and lang not in skip_langs:
|
||||||
)
|
tags.append(
|
||||||
|
f'<button class="tag tag-lang" data-filter-type="language" '
|
||||||
|
f'data-filter-value="{esc(lang)}">{esc(lang.lower())}</button>'
|
||||||
|
)
|
||||||
|
|
||||||
# Section tag
|
# Category tag
|
||||||
section_slug = e.get("section_slug", "")
|
|
||||||
category = e.get("category", "")
|
category = e.get("category", "")
|
||||||
if section_slug and section_slug != slugify(lang):
|
section_slug = e.get("section_slug", "")
|
||||||
|
if section_slug:
|
||||||
tags.append(
|
tags.append(
|
||||||
f'<button class="tag tag-section" data-filter-type="category" '
|
f'<button class="tag tag-section" data-filter-type="category" '
|
||||||
f'data-filter-value="{esc(category)}">{esc(section_slug)}</button>'
|
f'data-filter-value="{esc(category)}">{esc(section_slug)}</button>'
|
||||||
)
|
)
|
||||||
|
|
||||||
# Source tags
|
# Source tags (unchanged)
|
||||||
if e.get("github"):
|
if e.get("github"):
|
||||||
tags.append(
|
tags.append(
|
||||||
'<button class="tag tag-source tag-github" '
|
'<button class="tag tag-source tag-github" '
|
||||||
@@ -195,9 +203,16 @@ def generate_html(entries: list[dict]) -> str:
|
|||||||
"""Generate the full HTML page from project entries."""
|
"""Generate the full HTML page from project entries."""
|
||||||
languages = sorted(
|
languages = sorted(
|
||||||
set(
|
set(
|
||||||
e["language"]
|
lang.strip()
|
||||||
for e in entries
|
for e in entries
|
||||||
if e.get("language") and e["language"] != "Languages"
|
for lang in e.get("languages", e.get("language", "")).split(",")
|
||||||
|
if lang.strip()
|
||||||
|
and lang.strip() not in {
|
||||||
|
"Commercial & Proprietary Services",
|
||||||
|
"Related Lists",
|
||||||
|
"Reproducing Works, Training & Books",
|
||||||
|
"Cross-Language Frameworks",
|
||||||
|
}
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -208,7 +223,6 @@ def generate_html(entries: list[dict]) -> str:
|
|||||||
name = esc(e["project"])
|
name = esc(e["project"])
|
||||||
url = esc(e["url"])
|
url = esc(e["url"])
|
||||||
desc = esc(e["description"])
|
desc = esc(e["description"])
|
||||||
language = esc(e.get("language", ""))
|
|
||||||
category = esc(e.get("category", ""))
|
category = esc(e.get("category", ""))
|
||||||
github_url = esc(e.get("github_url", ""))
|
github_url = esc(e.get("github_url", ""))
|
||||||
repo = esc(e.get("repo", ""))
|
repo = esc(e.get("repo", ""))
|
||||||
@@ -219,6 +233,11 @@ def generate_html(entries: list[dict]) -> str:
|
|||||||
is_pypi = e.get("pypi", False)
|
is_pypi = e.get("pypi", False)
|
||||||
is_commercial = e.get("commercial", False)
|
is_commercial = e.get("commercial", False)
|
||||||
|
|
||||||
|
# Languages attribute (space-separated)
|
||||||
|
languages_attr = esc(" ".join(
|
||||||
|
l.strip() for l in e.get("languages", e.get("language", "")).split(",") if l.strip()
|
||||||
|
))
|
||||||
|
|
||||||
# Stars display
|
# Stars display
|
||||||
stars_html = (
|
stars_html = (
|
||||||
f'<span class="stars" title="{stars:,} stars">'
|
f'<span class="stars" title="{stars:,} stars">'
|
||||||
@@ -250,7 +269,7 @@ def generate_html(entries: list[dict]) -> str:
|
|||||||
tags_html = build_tags_html(e)
|
tags_html = build_tags_html(e)
|
||||||
|
|
||||||
rows.append(
|
rows.append(
|
||||||
f""" <tr class="row" data-language="{language}" data-category="{category}" data-sources="{sources_attr}" data-stars="{stars}">
|
f""" <tr class="row" data-languages="{languages_attr}" data-category="{category}" data-sources="{sources_attr}" data-stars="{stars}">
|
||||||
<td class="col-num">{i}</td>
|
<td class="col-num">{i}</td>
|
||||||
<td class="col-name">
|
<td class="col-name">
|
||||||
<a href="{url}" target="_blank" rel="noopener">{name}</a>
|
<a href="{url}" target="_blank" rel="noopener">{name}</a>
|
||||||
|
|||||||
+9307
-9154
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user