GET /api/search passa de CC 41 para <= 10. Testes de caracterização (sem rede: fetch e cache JSON temporário) cobrem validação, filtros, ordenação, paginação, modo cache-only e erros. Também: parameter property de NutriScanError virou campo explícito e imports só de tipo usam import type, para o type stripping nativo do Node; o script de teste não usa mais --experimental-transform-types (removida no Node 26).
54 lines
1.3 KiB
TypeScript
54 lines
1.3 KiB
TypeScript
import type { Product } from "./openFoodFactsApi";
|
|
|
|
/**
|
|
* Calcula score de relevância de um produto em relação à query
|
|
*/
|
|
export function calculateRelevanceScore(
|
|
product: Product,
|
|
searchTerm: string
|
|
): number {
|
|
const productName = product.product_name?.toLowerCase() || "";
|
|
const lowerSearchTerm = searchTerm.toLowerCase();
|
|
|
|
// Nome exato = maior prioridade
|
|
if (productName === lowerSearchTerm) {
|
|
return 3;
|
|
}
|
|
|
|
// Nome começa com a query = alta prioridade
|
|
if (productName.startsWith(lowerSearchTerm)) {
|
|
return 2;
|
|
}
|
|
|
|
// Nome contém a query = média prioridade
|
|
if (productName.includes(lowerSearchTerm)) {
|
|
return 1;
|
|
}
|
|
|
|
// Correspondência em marca ou categoria = baixa prioridade
|
|
if (
|
|
product.brands?.toLowerCase().includes(lowerSearchTerm) ||
|
|
product.categories?.toLowerCase().includes(lowerSearchTerm)
|
|
) {
|
|
return 0.5;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Ordena produtos por relevância em relação à query
|
|
*/
|
|
export function sortByRelevance(
|
|
products: Product[],
|
|
searchTerm: string
|
|
): Product[] {
|
|
return products
|
|
.map((product) => ({
|
|
product,
|
|
relevanceScore: calculateRelevanceScore(product, searchTerm),
|
|
}))
|
|
.sort((a, b) => b.relevanceScore - a.relevanceScore)
|
|
.map(({ product }) => product);
|
|
}
|