SYMBOL INDEX (173 symbols across 7 files) FILE: website/build.py function group_categories (line 14) | def group_categories( class Entry (line 33) | class Entry(TypedDict): class StarData (line 44) | class StarData(TypedDict): function extract_github_repo (line 54) | def extract_github_repo(url: str) -> str | None: function load_stars (line 60) | def load_stars(path: Path) -> dict[str, StarData]: function sort_entries (line 70) | def sort_entries(entries: list[dict]) -> list[dict]: function extract_entries (line 83) | def extract_entries( function build (line 126) | def build(repo_root: str) -> None: FILE: website/fetch_github_stars.py function extract_github_repos (line 23) | def extract_github_repos(text: str) -> set[str]: function save_cache (line 33) | def save_cache(cache: dict) -> None: function build_graphql_query (line 42) | def build_graphql_query(repos: list[str]) -> str: function parse_graphql_response (line 60) | def parse_graphql_response( function fetch_batch (line 80) | def fetch_batch( function main (line 97) | def main() -> None: FILE: website/readme_parser.py class AlsoSee (line 13) | class AlsoSee(TypedDict): class ParsedEntry (line 18) | class ParsedEntry(TypedDict): class ParsedSection (line 25) | class ParsedSection(TypedDict): class ParsedGroup (line 35) | class ParsedGroup(TypedDict): function slugify (line 48) | def slugify(name: str) -> str: function render_inline_html (line 60) | def render_inline_html(children: list[SyntaxTreeNode]) -> str: function render_inline_text (line 86) | def render_inline_text(children: list[SyntaxTreeNode]) -> str: function _heading_text (line 105) | def _heading_text(node: SyntaxTreeNode) -> str: function _extract_description (line 113) | def _extract_description(nodes: list[SyntaxTreeNode]) -> str: function _find_child (line 136) | def _find_child(node: SyntaxTreeNode, child_type: str) -> SyntaxTreeNode... function _find_inline (line 144) | def _find_inline(node: SyntaxTreeNode) -> SyntaxTreeNode | None: function _find_first_link (line 152) | def _find_first_link(inline: SyntaxTreeNode) -> SyntaxTreeNode | None: function _is_leading_link (line 160) | def _is_leading_link(inline: SyntaxTreeNode, link: SyntaxTreeNode) -> bool: function _extract_description_html (line 165) | def _extract_description_html(inline: SyntaxTreeNode, first_link: Syntax... function _parse_list_entries (line 181) | def _parse_list_entries(bullet_list: SyntaxTreeNode) -> list[ParsedEntry]: function _parse_section_entries (line 239) | def _parse_section_entries(content_nodes: list[SyntaxTreeNode]) -> list[... function _render_bullet_list_html (line 251) | def _render_bullet_list_html( function _render_section_html (line 302) | def _render_section_html(content_nodes: list[SyntaxTreeNode]) -> str: function _build_section (line 314) | def _build_section(name: str, body: list[SyntaxTreeNode]) -> ParsedSection: function _group_by_h2 (line 333) | def _group_by_h2( function _is_bold_marker (line 360) | def _is_bold_marker(node: SyntaxTreeNode) -> str | None: function _parse_grouped_sections (line 379) | def _parse_grouped_sections( function parse_readme (line 435) | def parse_readme(text: str) -> tuple[list[ParsedGroup], list[ParsedSecti... FILE: website/static/main.js function relativeTime (line 14) | function relativeTime(isoStr) { function collapseAll (line 42) | function collapseAll() { function applyFilters (line 50) | function applyFilters() { function updateURL (line 113) | function updateURL() { function getSortValue (line 128) | function getSortValue(row, col) { function sortRows (line 144) | function sortRows() { function updateSortIndicators (line 172) | function updateSortIndicators() { FILE: website/tests/test_build.py class TestSlugify (line 22) | class TestSlugify: method test_simple (line 23) | def test_simple(self): method test_uppercase_acronym (line 26) | def test_uppercase_acronym(self): method test_all_caps (line 29) | def test_all_caps(self): method test_hyphenated_input (line 32) | def test_hyphenated_input(self): method test_special_chars (line 35) | def test_special_chars(self): method test_single_word (line 38) | def test_single_word(self): method test_extra_spaces (line 41) | def test_extra_spaces(self): class TestGroupCategories (line 50) | class TestGroupCategories: method test_appends_resources (line 51) | def test_appends_resources(self): method test_no_resources_no_extra_group (line 61) | def test_no_resources_no_extra_group(self): method test_preserves_group_order (line 69) | def test_preserves_group_order(self): class TestBuild (line 84) | class TestBuild: method _make_repo (line 85) | def _make_repo(self, tmp_path, readme): method test_build_creates_single_page (line 114) | def test_build_creates_single_page(self, tmp_path): method test_build_cleans_stale_output (line 156) | def test_build_cleans_stale_output(self, tmp_path): method test_index_contains_category_names (line 180) | def test_index_contains_category_names(self, tmp_path): method test_index_contains_preview_text (line 211) | def test_index_contains_preview_text(self, tmp_path): method test_build_with_stars_sorts_by_stars (line 233) | def test_build_with_stars_sorts_by_stars(self, tmp_path): class TestExtractGithubRepo (line 283) | class TestExtractGithubRepo: method test_github_url (line 284) | def test_github_url(self): method test_non_github_url (line 287) | def test_non_github_url(self): method test_github_io_url (line 290) | def test_github_io_url(self): method test_trailing_slash (line 293) | def test_trailing_slash(self): method test_deep_path (line 296) | def test_deep_path(self): method test_dot_git_suffix (line 299) | def test_dot_git_suffix(self): method test_org_only (line 302) | def test_org_only(self): class TestLoadStars (line 311) | class TestLoadStars: method test_returns_empty_when_missing (line 312) | def test_returns_empty_when_missing(self, tmp_path): method test_loads_valid_json (line 316) | def test_loads_valid_json(self, tmp_path): method test_returns_empty_on_corrupt_json (line 323) | def test_returns_empty_on_corrupt_json(self, tmp_path): class TestSortEntries (line 335) | class TestSortEntries: method test_sorts_by_stars_descending (line 336) | def test_sorts_by_stars_descending(self): method test_equal_stars_sorted_alphabetically (line 345) | def test_equal_stars_sorted_alphabetically(self): method test_no_stars_go_to_bottom (line 353) | def test_no_stars_go_to_bottom(self): method test_no_stars_sorted_alphabetically (line 361) | def test_no_stars_sorted_alphabetically(self): FILE: website/tests/test_fetch_github_stars.py class TestExtractGithubRepos (line 16) | class TestExtractGithubRepos: method test_extracts_owner_repo_from_github_url (line 17) | def test_extracts_owner_repo_from_github_url(self): method test_multiple_repos (line 22) | def test_multiple_repos(self): method test_ignores_non_github_urls (line 30) | def test_ignores_non_github_urls(self): method test_ignores_github_io_urls (line 35) | def test_ignores_github_io_urls(self): method test_ignores_github_wiki_and_blob_urls (line 40) | def test_ignores_github_wiki_and_blob_urls(self): method test_handles_trailing_slash (line 48) | def test_handles_trailing_slash(self): method test_deduplicates (line 53) | def test_deduplicates(self): method test_strips_fragment (line 61) | def test_strips_fragment(self): class TestSaveCache (line 67) | class TestSaveCache: method test_creates_directory_and_writes_json (line 68) | def test_creates_directory_and_writes_json(self, tmp_path, monkeypatch): class TestBuildGraphqlQuery (line 78) | class TestBuildGraphqlQuery: method test_single_repo (line 79) | def test_single_repo(self): method test_multiple_repos_use_aliases (line 86) | def test_multiple_repos_use_aliases(self): method test_empty_list (line 91) | def test_empty_list(self): method test_skips_repos_with_quotes_in_name (line 95) | def test_skips_repos_with_quotes_in_name(self): method test_skips_only_bad_repos (line 99) | def test_skips_only_bad_repos(self): class TestParseGraphqlResponse (line 105) | class TestParseGraphqlResponse: method test_parses_star_count_and_owner (line 106) | def test_parses_star_count_and_owner(self): method test_skips_null_repos (line 118) | def test_skips_null_repos(self): method test_handles_missing_owner (line 124) | def test_handles_missing_owner(self): method test_multiple_repos (line 130) | def test_multiple_repos(self): class TestMainSkipsFreshCache (line 142) | class TestMainSkipsFreshCache: method test_skips_fetch_when_cache_is_fresh (line 145) | def test_skips_fetch_when_cache_is_fresh(self, tmp_path, monkeypatch, ... method test_fetches_when_cache_is_stale (line 179) | def test_fetches_when_cache_is_stale(self, tmp_path, monkeypatch, caps... FILE: website/tests/test_readme_parser.py function _parse_inline (line 20) | def _parse_inline(md_text: str) -> list[SyntaxTreeNode]: class TestRenderInlineHtml (line 28) | class TestRenderInlineHtml: method test_plain_text_escapes_html (line 29) | def test_plain_text_escapes_html(self): method test_link_with_target (line 33) | def test_link_with_target(self): method test_emphasis (line 41) | def test_emphasis(self): method test_strong (line 45) | def test_strong(self): method test_code_inline (line 49) | def test_code_inline(self): method test_mixed_link_and_text (line 53) | def test_mixed_link_and_text(self): class TestRenderInlineText (line 61) | class TestRenderInlineText: method test_plain_text (line 62) | def test_plain_text(self): method test_link_becomes_text (line 66) | def test_link_becomes_text(self): method test_emphasis_stripped (line 70) | def test_emphasis_stripped(self): method test_code_inline_kept (line 74) | def test_code_inline_kept(self): class TestParseReadmeSections (line 160) | class TestParseReadmeSections: method test_ungrouped_categories_go_to_other (line 161) | def test_ungrouped_categories_go_to_other(self): method test_ungrouped_category_names (line 167) | def test_ungrouped_category_names(self): method test_resource_count (line 173) | def test_resource_count(self): method test_category_slugs (line 177) | def test_category_slugs(self): method test_category_description (line 183) | def test_category_description(self): method test_resource_names (line 189) | def test_resource_names(self): method test_contributing_skipped (line 194) | def test_contributing_skipped(self): method test_no_separator (line 202) | def test_no_separator(self): method test_no_description (line 207) | def test_no_description(self): method test_description_with_link_stripped (line 232) | def test_description_with_link_stripped(self): class TestParseGroupedReadme (line 253) | class TestParseGroupedReadme: method test_group_count (line 254) | def test_group_count(self): method test_group_names (line 258) | def test_group_names(self): method test_group_slugs (line 263) | def test_group_slugs(self): method test_group_one_has_one_category (line 268) | def test_group_one_has_one_category(self): method test_group_two_has_two_categories (line 273) | def test_group_two_has_two_categories(self): method test_resources_still_parsed (line 279) | def test_resources_still_parsed(self): method test_empty_group_skipped (line 284) | def test_empty_group_skipped(self): method test_bold_with_extra_text_not_group_marker (line 306) | def test_bold_with_extra_text_not_group_marker(self): method test_categories_before_any_group_marker (line 328) | def test_categories_before_any_group_marker(self): function _content_nodes (line 356) | def _content_nodes(md_text: str) -> list[SyntaxTreeNode]: class TestParseSectionEntries (line 363) | class TestParseSectionEntries: method test_flat_entries (line 364) | def test_flat_entries(self): method test_link_only_entry (line 377) | def test_link_only_entry(self): method test_subcategorized_entries (line 384) | def test_subcategorized_entries(self): method test_text_before_link_is_subcategory (line 397) | def test_text_before_link_is_subcategory(self): method test_also_see_sub_entries (line 411) | def test_also_see_sub_entries(self): method test_entry_count_includes_also_see (line 425) | def test_entry_count_includes_also_see(self): method test_preview_first_four_names (line 446) | def test_preview_first_four_names(self): method test_description_html_escapes_xss (line 468) | def test_description_html_escapes_xss(self): class TestRenderSectionHtml (line 475) | class TestRenderSectionHtml: method test_basic_entry (line 476) | def test_basic_entry(self): method test_subcategory_label (line 484) | def test_subcategory_label(self): method test_sub_entry (line 493) | def test_sub_entry(self): method test_link_only_entry (line 502) | def test_link_only_entry(self): method test_xss_escaped_in_name (line 509) | def test_xss_escaped_in_name(self): method test_xss_escaped_in_subcat (line 514) | def test_xss_escaped_in_subcat(self): class TestParseRealReadme (line 520) | class TestParseRealReadme: method load_readme (line 522) | def load_readme(self): method test_at_least_11_groups (line 529) | def test_at_least_11_groups(self): method test_first_group_is_ai_ml (line 532) | def test_first_group_is_ai_ml(self): method test_at_least_76_categories (line 535) | def test_at_least_76_categories(self): method test_resources_has_newsletters_and_podcasts (line 538) | def test_resources_has_newsletters_and_podcasts(self): method test_contributing_not_in_results (line 543) | def test_contributing_not_in_results(self): method test_first_category_is_ai_and_agents (line 547) | def test_first_category_is_ai_and_agents(self): method test_web_apis_slug (line 551) | def test_web_apis_slug(self): method test_descriptions_extracted (line 555) | def test_descriptions_extracted(self): method test_entry_counts_nonzero (line 559) | def test_entry_counts_nonzero(self): method test_previews_nonempty (line 563) | def test_previews_nonempty(self): method test_content_html_nonempty (line 567) | def test_content_html_nonempty(self): method test_algorithms_has_subcategories (line 571) | def test_algorithms_has_subcategories(self): method test_async_has_also_see (line 575) | def test_async_has_also_see(self): method test_description_links_stripped_to_text (line 581) | def test_description_links_stripped_to_text(self): method test_miscellaneous_in_own_group (line 586) | def test_miscellaneous_in_own_group(self):