UNPKG

@wordpress/block-editor

Version:
8 lines (7 loc) 9.07 kB
{ "version": 3, "sources": ["../../../src/components/inserter/search-items.js"], "sourcesContent": ["/**\n * External dependencies\n */\nimport removeAccents from 'remove-accents';\nimport { noCase } from 'change-case';\n\n// Default search helpers.\nconst defaultGetName = ( item ) => item.name || '';\nconst defaultGetTitle = ( item ) => item.title;\nconst defaultGetDescription = ( item ) => item.description || '';\nconst defaultGetKeywords = ( item ) => item.keywords || [];\nconst defaultGetCategory = ( item ) => item.category;\nconst defaultGetCollection = () => null;\n\n// Normalization regexes\nconst splitRegexp = [\n\t/([\\p{Ll}\\p{Lo}\\p{N}])([\\p{Lu}\\p{Lt}])/gu, // One lowercase or digit, followed by one uppercase.\n\t/([\\p{Lu}\\p{Lt}])([\\p{Lu}\\p{Lt}][\\p{Ll}\\p{Lo}])/gu, // One uppercase followed by one uppercase and one lowercase.\n];\nconst stripRegexp = /(\\p{C}|\\p{P}|\\p{S})+/giu; // Anything that's not a punctuation, symbol or control/format character.\n\n// Normalization cache\nconst extractedWords = new Map();\nconst normalizedStrings = new Map();\n\n/**\n * Extracts words from an input string.\n *\n * @param {string} input The input string.\n *\n * @return {Array} Words, extracted from the input string.\n */\nexport function extractWords( input = '' ) {\n\tif ( extractedWords.has( input ) ) {\n\t\treturn extractedWords.get( input );\n\t}\n\n\tconst result = noCase( input, {\n\t\tsplitRegexp,\n\t\tstripRegexp,\n\t} )\n\t\t.split( ' ' )\n\t\t.filter( Boolean );\n\n\textractedWords.set( input, result );\n\n\treturn result;\n}\n\n/**\n * Sanitizes the search input string.\n *\n * @param {string} input The search input to normalize.\n *\n * @return {string} The normalized search input.\n */\nexport function normalizeString( input = '' ) {\n\tif ( normalizedStrings.has( input ) ) {\n\t\treturn normalizedStrings.get( input );\n\t}\n\n\t// Disregard diacritics.\n\t// Input: \"m\u00E9dia\"\n\tlet result = removeAccents( input );\n\n\t// Accommodate leading slash, matching autocomplete expectations.\n\t// Input: \"/media\"\n\tresult = result.replace( /^\\//, '' );\n\n\t// Lowercase.\n\t// Input: \"MEDIA\"\n\tresult = result.toLowerCase();\n\n\tnormalizedStrings.set( input, result );\n\n\treturn result;\n}\n\n/**\n * Converts the search term into a list of normalized terms.\n *\n * @param {string} input The search term to normalize.\n *\n * @return {string[]} The normalized list of search terms.\n */\nexport const getNormalizedSearchTerms = ( input = '' ) => {\n\treturn extractWords( normalizeString( input ) );\n};\n\nconst removeMatchingTerms = ( unmatchedTerms, unprocessedTerms ) => {\n\treturn unmatchedTerms.filter(\n\t\t( term ) =>\n\t\t\t! getNormalizedSearchTerms( unprocessedTerms ).some(\n\t\t\t\t( unprocessedTerm ) => unprocessedTerm.includes( term )\n\t\t\t)\n\t);\n};\n\nexport const searchBlockItems = (\n\titems,\n\tcategories,\n\tcollections,\n\tsearchInput\n) => {\n\tconst normalizedSearchTerms = getNormalizedSearchTerms( searchInput );\n\tif ( normalizedSearchTerms.length === 0 ) {\n\t\treturn items;\n\t}\n\n\tconst config = {\n\t\tgetCategory: ( item ) =>\n\t\t\tcategories.find( ( { slug } ) => slug === item.category )?.title,\n\t\tgetCollection: ( item ) =>\n\t\t\tcollections[ item.name.split( '/' )[ 0 ] ]?.title,\n\t};\n\n\treturn searchItems( items, searchInput, config );\n};\n\n/**\n * Filters an item list given a search term.\n *\n * @param {Array} items Item list\n * @param {string} searchInput Search input.\n * @param {Object} config Search Config.\n *\n * @return {Array} Filtered item list.\n */\nexport const searchItems = ( items = [], searchInput = '', config = {} ) => {\n\tconst normalizedSearchTerms = getNormalizedSearchTerms( searchInput );\n\tif ( normalizedSearchTerms.length === 0 ) {\n\t\treturn items;\n\t}\n\n\tconst rankedItems = items\n\t\t.map( ( item ) => {\n\t\t\treturn [ item, getItemSearchRank( item, searchInput, config ) ];\n\t\t} )\n\t\t.filter( ( [ , rank ] ) => rank > 0 );\n\n\trankedItems.sort( ( [ , rank1 ], [ , rank2 ] ) => rank2 - rank1 );\n\treturn rankedItems.map( ( [ item ] ) => item );\n};\n\n/**\n * Get the search rank for a given item and a specific search term.\n * The better the match, the higher the rank.\n * If the rank equals 0, it should be excluded from the results.\n *\n * @param {Object} item Item to filter.\n * @param {string} searchTerm Search term.\n * @param {Object} config Search Config.\n *\n * @return {number} Search Rank.\n */\nexport function getItemSearchRank( item, searchTerm, config = {} ) {\n\tconst {\n\t\tgetName = defaultGetName,\n\t\tgetTitle = defaultGetTitle,\n\t\tgetDescription = defaultGetDescription,\n\t\tgetKeywords = defaultGetKeywords,\n\t\tgetCategory = defaultGetCategory,\n\t\tgetCollection = defaultGetCollection,\n\t} = config;\n\n\tconst name = getName( item );\n\tconst title = getTitle( item );\n\tconst description = getDescription( item );\n\tconst keywords = getKeywords( item );\n\tconst category = getCategory( item );\n\tconst collection = getCollection( item );\n\n\tconst normalizedSearchInput = normalizeString( searchTerm );\n\tconst normalizedTitle = normalizeString( title );\n\n\tlet rank = 0;\n\n\t// Prefers exact matches\n\t// Then prefers if the beginning of the title matches the search term\n\t// name, keywords, categories, collection, variations match come later.\n\tif ( normalizedSearchInput === normalizedTitle ) {\n\t\trank += 30;\n\t} else if ( normalizedTitle.startsWith( normalizedSearchInput ) ) {\n\t\trank += 20;\n\t} else {\n\t\tconst terms = [\n\t\t\tname,\n\t\t\ttitle,\n\t\t\tdescription,\n\t\t\t...keywords,\n\t\t\tcategory,\n\t\t\tcollection,\n\t\t].join( ' ' );\n\t\tconst normalizedSearchTerms = extractWords( normalizedSearchInput );\n\t\tconst unmatchedTerms = removeMatchingTerms(\n\t\t\tnormalizedSearchTerms,\n\t\t\tterms\n\t\t);\n\n\t\tif ( unmatchedTerms.length === 0 ) {\n\t\t\trank += 10;\n\t\t}\n\t}\n\n\t// Give a better rank to \"core\" namespaced items.\n\tif ( rank !== 0 && name.startsWith( 'core/' ) ) {\n\t\tconst isCoreBlockVariation = name !== item.id;\n\t\t// Give a bit better rank to \"core\" blocks over \"core\" block variations.\n\t\trank += isCoreBlockVariation ? 1 : 2;\n\t}\n\n\treturn rank;\n}\n"], "mappings": "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", "names": ["removeAccents"] }