mirror of
https://github.com/upstash/context7.git
synced 2025-06-26 23:50:04 +00:00
128 lines
4.7 KiB
JavaScript
128 lines
4.7 KiB
JavaScript
/**
|
|
* Format a project into a string representation
|
|
* @param project Project to format
|
|
* @returns Formatted project string
|
|
*/
|
|
export function formatProject(project) {
|
|
return `Title: ${project.settings.title}\nContext7-compatible library ID: ${project.settings.project}\n`;
|
|
}
|
|
/**
|
|
* Format a list of projects into a string representation
|
|
* @param projects Projects to format
|
|
* @returns Formatted projects string
|
|
*/
|
|
export function formatProjectsList(projects) {
|
|
const formattedProjects = projects.map(formatProject);
|
|
return (formattedProjects.length +
|
|
" available documentation libraries:\n\n" +
|
|
formattedProjects.join("\n"));
|
|
}
|
|
/**
|
|
* Rerank projects based on a search term
|
|
* @param projects Projects to rerank
|
|
* @param searchTerm Search term to rerank by
|
|
* @returns Reranked projects
|
|
*/
|
|
export function rerankProjects(projects, searchTerm) {
|
|
if (!searchTerm)
|
|
return projects;
|
|
// Normalize the search term - remove special characters and convert to lowercase
|
|
const normalizedSearchTerm = searchTerm.toLowerCase().replace(/[^\w\s]/g, "");
|
|
return [...projects].sort((a, b) => {
|
|
const aTitle = a.settings.title.toLowerCase();
|
|
const aProject = a.settings.project.toLowerCase();
|
|
const aProjectName = aProject.split("/").pop() || "";
|
|
const aProjectPath = aProject.split("/").slice(0, -1).join("/");
|
|
const bTitle = b.settings.title.toLowerCase();
|
|
const bProject = b.settings.project.toLowerCase();
|
|
const bProjectName = bProject.split("/").pop() || "";
|
|
const bProjectPath = bProject.split("/").slice(0, -1).join("/");
|
|
// Normalize project names for better matching - remove special characters
|
|
const normalizedATitle = aTitle.replace(/[^\w\s]/g, "");
|
|
const normalizedAProject = aProject.replace(/[^\w\s]/g, "");
|
|
const normalizedAProjectName = aProjectName.replace(/[^\w\s]/g, "");
|
|
const normalizedBTitle = bTitle.replace(/[^\w\s]/g, "");
|
|
const normalizedBProject = bProject.replace(/[^\w\s]/g, "");
|
|
const normalizedBProjectName = bProjectName.replace(/[^\w\s]/g, "");
|
|
// Calculate match scores for better ranking
|
|
const aScore = calculateMatchScore(normalizedSearchTerm, {
|
|
original: {
|
|
title: aTitle,
|
|
project: aProject,
|
|
projectName: aProjectName,
|
|
projectPath: aProjectPath,
|
|
},
|
|
normalized: {
|
|
title: normalizedATitle,
|
|
project: normalizedAProject,
|
|
projectName: normalizedAProjectName,
|
|
},
|
|
});
|
|
const bScore = calculateMatchScore(normalizedSearchTerm, {
|
|
original: {
|
|
title: bTitle,
|
|
project: bProject,
|
|
projectName: bProjectName,
|
|
projectPath: bProjectPath,
|
|
},
|
|
normalized: {
|
|
title: normalizedBTitle,
|
|
project: normalizedBProject,
|
|
projectName: normalizedBProjectName,
|
|
},
|
|
});
|
|
// Higher score first
|
|
if (aScore !== bScore) {
|
|
return bScore - aScore;
|
|
}
|
|
// Default to alphabetical by project name
|
|
return aProject.localeCompare(bProject);
|
|
});
|
|
}
|
|
/**
|
|
* Calculate a match score for ranking
|
|
* Higher score means better match
|
|
*/
|
|
function calculateMatchScore(searchTerm, projectData) {
|
|
const { original, normalized } = projectData;
|
|
let score = 0;
|
|
// Exact matches (highest priority)
|
|
if (original.project === searchTerm ||
|
|
original.title === searchTerm ||
|
|
original.projectName === searchTerm) {
|
|
score += 100;
|
|
}
|
|
// Normalized exact matches
|
|
if (normalized.project === searchTerm ||
|
|
normalized.title === searchTerm ||
|
|
normalized.projectName === searchTerm) {
|
|
score += 90;
|
|
}
|
|
// Starts with matches
|
|
if (original.project.startsWith(searchTerm) ||
|
|
original.title.startsWith(searchTerm) ||
|
|
original.projectName.startsWith(searchTerm)) {
|
|
score += 80;
|
|
}
|
|
// Normalized starts with matches
|
|
if (normalized.project.startsWith(searchTerm) ||
|
|
normalized.title.startsWith(searchTerm) ||
|
|
normalized.projectName.startsWith(searchTerm)) {
|
|
score += 70;
|
|
}
|
|
// Contains matches
|
|
if (original.project.includes(searchTerm) ||
|
|
original.title.includes(searchTerm) ||
|
|
original.projectName.includes(searchTerm) ||
|
|
original.projectPath.includes(searchTerm)) {
|
|
score += 60;
|
|
}
|
|
// Normalized contains matches
|
|
if (normalized.project.includes(searchTerm) ||
|
|
normalized.title.includes(searchTerm) ||
|
|
normalized.projectName.includes(searchTerm)) {
|
|
score += 50;
|
|
}
|
|
return score;
|
|
}
|