(raw string)
| 752 | } |
| 753 | |
| 754 | func simplifyRepoList(raw string) (string, error) { |
| 755 | var repos []map[string]interface{} |
| 756 | |
| 757 | // Search API returns {items: [...]} wrapper |
| 758 | var searchResult map[string]interface{} |
| 759 | if err := json.Unmarshal([]byte(raw), &searchResult); err == nil { |
| 760 | if items, ok := searchResult["items"].([]interface{}); ok { |
| 761 | for _, item := range items { |
| 762 | if m, ok := item.(map[string]interface{}); ok { |
| 763 | repos = append(repos, m) |
| 764 | } |
| 765 | } |
| 766 | } |
| 767 | } |
| 768 | |
| 769 | // Fallback: direct array (user/repos endpoint) |
| 770 | if len(repos) == 0 { |
| 771 | if err := json.Unmarshal([]byte(raw), &repos); err != nil { |
| 772 | return raw, nil |
| 773 | } |
| 774 | } |
| 775 | |
| 776 | // Filter junk repos — awesome-lists, collections, non-code repos |
| 777 | filtered := make([]map[string]interface{}, 0, len(repos)) |
| 778 | for _, r := range repos { |
| 779 | name := strings.ToLower(fmt.Sprintf("%v", r["name"])) |
| 780 | desc := strings.ToLower(fmt.Sprintf("%v", r["description"])) |
| 781 | fullName := strings.ToLower(fmt.Sprintf("%v", r["full_name"])) |
| 782 | |
| 783 | // Skip awesome-lists and curated collections |
| 784 | if strings.HasPrefix(name, "awesome") || strings.Contains(desc, "curated list") || |
| 785 | strings.Contains(desc, "cheatsheet") || strings.Contains(desc, "collection of") || |
| 786 | strings.Contains(desc, "list of") || strings.Contains(name, "awesome") { |
| 787 | continue |
| 788 | } |
| 789 | |
| 790 | // Skip if it's clearly a learning resource, not a library/framework |
| 791 | if strings.Contains(desc, "tutorial") || strings.Contains(desc, "interview question") || |
| 792 | strings.Contains(desc, "roadmap") || strings.Contains(name, "learn-") { |
| 793 | continue |
| 794 | } |
| 795 | |
| 796 | _ = fullName |
| 797 | filtered = append(filtered, r) |
| 798 | } |
| 799 | repos = filtered |
| 800 | |
| 801 | // Sort by stars descending (in case API didn't sort correctly) |
| 802 | for i := 1; i < len(repos); i++ { |
| 803 | for j := i; j > 0; j-- { |
| 804 | starsJ := toFloat(repos[j]["stargazers_count"]) |
| 805 | starsJm1 := toFloat(repos[j-1]["stargazers_count"]) |
| 806 | if starsJ > starsJm1 { |
| 807 | repos[j], repos[j-1] = repos[j-1], repos[j] |
| 808 | } |
| 809 | } |
| 810 | } |
| 811 |
no test coverage detected