mirror of
https://github.com/github/awesome-copilot.git
synced 2026-02-20 02:15:12 +00:00
fix: make FuzzySearch generic to support typed items
- Add SearchableItem base interface for minimum required fields - Make FuzzySearch class generic with type parameter - Update all page scripts to use typed FuzzySearch instances - Fix type casting in calculateScore method
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"generated": "2026-01-28T22:44:20.356Z",
|
||||
"generated": "2026-01-28T22:56:09.687Z",
|
||||
"counts": {
|
||||
"agents": 140,
|
||||
"prompts": 134,
|
||||
|
||||
@@ -25,7 +25,7 @@ interface AgentsData {
|
||||
|
||||
const resourceType = 'agent';
|
||||
let allItems: Agent[] = [];
|
||||
let search = new FuzzySearch();
|
||||
let search = new FuzzySearch<Agent>();
|
||||
let modelSelect: Choices;
|
||||
let toolSelect: Choices;
|
||||
|
||||
|
||||
@@ -2,13 +2,14 @@
|
||||
* Collections page functionality
|
||||
*/
|
||||
import { createChoices, getChoicesValues, type Choices } from '../choices';
|
||||
import { FuzzySearch, type SearchItem } from '../search';
|
||||
import { FuzzySearch } from '../search';
|
||||
import { fetchData, debounce, escapeHtml, getGitHubUrl } from '../utils';
|
||||
import { setupModal, openFileModal } from '../modal';
|
||||
|
||||
interface Collection {
|
||||
id: string;
|
||||
name: string;
|
||||
title: string;
|
||||
description?: string;
|
||||
path: string;
|
||||
tags?: string[];
|
||||
@@ -25,7 +26,7 @@ interface CollectionsData {
|
||||
|
||||
const resourceType = 'collection';
|
||||
let allItems: Collection[] = [];
|
||||
let search = new FuzzySearch();
|
||||
let search = new FuzzySearch<Collection>();
|
||||
let tagSelect: Choices;
|
||||
let currentFilters = {
|
||||
tags: [] as string[],
|
||||
|
||||
@@ -48,7 +48,7 @@ export async function initHomepage(): Promise<void> {
|
||||
// Load search index
|
||||
const searchIndex = await fetchData<SearchItem[]>('search-index.json');
|
||||
if (searchIndex) {
|
||||
const search = new FuzzySearch();
|
||||
const search = new FuzzySearch<SearchItem>();
|
||||
search.setItems(searchIndex);
|
||||
|
||||
const searchInput = document.getElementById('global-search') as HTMLInputElement;
|
||||
|
||||
@@ -23,7 +23,7 @@ interface InstructionsData {
|
||||
|
||||
const resourceType = 'instruction';
|
||||
let allItems: Instruction[] = [];
|
||||
let search = new FuzzySearch();
|
||||
let search = new FuzzySearch<Instruction>();
|
||||
let extensionSelect: Choices;
|
||||
let currentFilters = { extensions: [] as string[] };
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ interface PromptsData {
|
||||
|
||||
const resourceType = 'prompt';
|
||||
let allItems: Prompt[] = [];
|
||||
let search = new FuzzySearch();
|
||||
let search = new FuzzySearch<Prompt>();
|
||||
let toolSelect: Choices;
|
||||
let currentFilters = { tools: [] as string[] };
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ interface SkillsData {
|
||||
|
||||
const resourceType = 'skill';
|
||||
let allItems: Skill[] = [];
|
||||
let search = new FuzzySearch();
|
||||
let search = new FuzzySearch<Skill>();
|
||||
let categorySelect: Choices;
|
||||
let currentFilters = {
|
||||
categories: [] as string[],
|
||||
|
||||
@@ -14,30 +14,36 @@ export interface SearchItem {
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export interface SearchableItem {
|
||||
title: string;
|
||||
description?: string;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export interface SearchOptions {
|
||||
fields?: string[];
|
||||
limit?: number;
|
||||
minScore?: number;
|
||||
}
|
||||
|
||||
export class FuzzySearch {
|
||||
private items: SearchItem[] = [];
|
||||
export class FuzzySearch<T extends SearchableItem = SearchItem> {
|
||||
private items: T[] = [];
|
||||
|
||||
constructor(items: SearchItem[] = []) {
|
||||
constructor(items: T[] = []) {
|
||||
this.items = items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the items to search
|
||||
*/
|
||||
setItems(items: SearchItem[]): void {
|
||||
setItems(items: T[]): void {
|
||||
this.items = items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search items with fuzzy matching
|
||||
*/
|
||||
search(query: string, options: SearchOptions = {}): SearchItem[] {
|
||||
search(query: string, options: SearchOptions = {}): T[] {
|
||||
const {
|
||||
fields = ['title', 'description', 'searchText'],
|
||||
limit = 50,
|
||||
@@ -50,7 +56,7 @@ export class FuzzySearch {
|
||||
|
||||
const normalizedQuery = query.toLowerCase().trim();
|
||||
const queryWords = normalizedQuery.split(/\s+/);
|
||||
const results: Array<{ item: SearchItem; score: number }> = [];
|
||||
const results: Array<{ item: T; score: number }> = [];
|
||||
|
||||
for (const item of this.items) {
|
||||
const score = this.calculateScore(item, queryWords, fields);
|
||||
@@ -68,14 +74,14 @@ export class FuzzySearch {
|
||||
/**
|
||||
* Calculate match score for an item
|
||||
*/
|
||||
private calculateScore(item: SearchItem, queryWords: string[], fields: string[]): number {
|
||||
private calculateScore(item: T, queryWords: string[], fields: string[]): number {
|
||||
let totalScore = 0;
|
||||
|
||||
for (const word of queryWords) {
|
||||
let wordScore = 0;
|
||||
|
||||
for (const field of fields) {
|
||||
const value = item[field];
|
||||
const value = (item as Record<string, unknown>)[field];
|
||||
if (!value) continue;
|
||||
|
||||
const normalizedValue = String(value).toLowerCase();
|
||||
@@ -108,7 +114,7 @@ export class FuzzySearch {
|
||||
// Bonus for matching all words
|
||||
const matchesAllWords = queryWords.every(word =>
|
||||
fields.some(field => {
|
||||
const value = item[field];
|
||||
const value = (item as Record<string, unknown>)[field];
|
||||
return value && String(value).toLowerCase().includes(word);
|
||||
})
|
||||
);
|
||||
@@ -140,13 +146,13 @@ export class FuzzySearch {
|
||||
}
|
||||
}
|
||||
|
||||
// Global search instance
|
||||
export const globalSearch = new FuzzySearch();
|
||||
// Global search instance (uses SearchItem for the global search index)
|
||||
export const globalSearch = new FuzzySearch<SearchItem>();
|
||||
|
||||
/**
|
||||
* Initialize global search with search index
|
||||
*/
|
||||
export async function initGlobalSearch(): Promise<FuzzySearch> {
|
||||
export async function initGlobalSearch(): Promise<FuzzySearch<SearchItem>> {
|
||||
const searchIndex = await fetchData<SearchItem[]>('search-index.json');
|
||||
if (searchIndex) {
|
||||
globalSearch.setItems(searchIndex);
|
||||
|
||||
Reference in New Issue
Block a user