import { getFullProject , sortProjectsByFunction } from "selectors" ; import { paginateItemList } from "components/core/pagination" ; export function findProjects ( projects , tagsById , auth , { tags , query , page = 1 , selector , direction , limit } ) { const filterByTag = ( project ) => tags . every ( ( tagId ) => project . tags . includes ( tagId ) ) ; const filteredProjects = projects . filter ( ( project ) => { if ( tags . length > 0 ) { if ( ! filterByTag ( project ) ) return false ; } return true ; } ) ; const foundProjects = query ? filterProjectsByQuery ( filteredProjects , query ) : filteredProjects ; const sortedProjects = sortProjectsByFunction ( foundProjects , selector , direction ) ; const relevantTags = ( tags . length > 0 || query ) && getResultRelevantTags ( sortedProjects , tags ) ; const paginatedProjects = paginateItemList ( sortedProjects , page , { limit } ) ; const results = paginatedProjects . map ( getFullProject ( tagsById , auth ) ) ; return { results , relevantTags , total : foundProjects . length , } ; } export function filterProjectsByQuery ( projects , query ) { return projects . map ( ( project ) => ( { ... project , rank : rank ( project , query ) } ) ) . filter ( ( project ) => project . rank > 0 ) ; } function rank ( project , query ) { const escapedQuery = escapeRegExp ( query ) ; const equals = new RegExp ( "^" + escapedQuery + "$" , "i" ) ; const startsWith = new RegExp ( "^" + escapedQuery , "i" ) ; const contains = new RegExp ( escapedQuery . replace ( / /g , ".+" ) , "i" ) ; if ( equals . test ( project . name ) ) { return 7 ; } if ( startsWith . test ( project . name ) ) { return 6 ; } if ( project . packageName && startsWith . test ( project . packageName ) ) { return 5 ; } if ( query . length > 1 ) { if ( contains . test ( project . name ) ) { return 4 ; } } if ( query . length > 2 ) { if ( contains . test ( project . description ) ) { return 3 ; } if ( contains . test ( project . full_name ) ) { return 2 ; } if ( contains . test ( project . url ) ) { return 1 ; } } return 0 ; } function getResultRelevantTags ( projects , excludedTags = [ ] ) { const projectCountByTag = getTagsFromProjects ( projects , excludedTags ) ; return orderBy ( Array . from ( projectCountByTag . entries ( ) ) , ( [ tagId , count ] ) => count ) ; } function orderBy ( items , fn ) { return items . sort ( ( a , b ) => fn ( b ) - fn ( a ) ) ; } function getTagsFromProjects ( projects , excludedTagIds = [ ] ) { const result = new Map ( ) ; projects . forEach ( ( project ) => { project . tags . filter ( ( tagId ) => ! excludedTagIds . includes ( tagId ) ) . forEach ( ( tagId ) => { if ( result . has ( tagId ) ) { result . set ( tagId , result . get ( tagId ) + 1 ) ; } else { result . set ( tagId , 1 ) ; } } ) ; } ) ; return result ; } function escapeRegExp ( string ) { return string . replace ( /[.*+?^${}()|[\]\\]/g , "\\$&" ) ; }