@@ -25,15 +25,15 @@ export function score(target: string, query: IPreparedQuery, fuzzy: boolean): Sc
2525 return scoreMultiple ( target , query . values , fuzzy ) ;
2626 }
2727
28- return scoreSingle ( target , query . value , query . valueLowercase , fuzzy ) ;
28+ return scoreSingle ( target , query . normalized , query . normalizedLowercase , fuzzy ) ;
2929}
3030
3131function scoreMultiple ( target : string , query : IPreparedQueryPiece [ ] , fuzzy : boolean ) : Score {
3232 let totalScore = NO_MATCH ;
3333 const totalPositions : number [ ] = [ ] ;
3434
35- for ( const { value , valueLowercase } of query ) {
36- const [ scoreValue , positions ] = scoreSingle ( target , value , valueLowercase , fuzzy ) ;
35+ for ( const { normalized , normalizedLowercase } of query ) {
36+ const [ scoreValue , positions ] = scoreSingle ( target , normalized , normalizedLowercase , fuzzy ) ;
3737 if ( scoreValue === NO_MATCH ) {
3838 // if a single query value does not match, return with
3939 // no score entirely, we require all queries to match
@@ -338,11 +338,26 @@ const LABEL_CAMELCASE_SCORE = 1 << 16;
338338const LABEL_SCORE_THRESHOLD = 1 << 15 ;
339339
340340export interface IPreparedQueryPiece {
341+
342+ /**
343+ * The original query as provided as input.
344+ */
341345 original : string ;
342346 originalLowercase : string ;
343347
344- value : string ;
345- valueLowercase : string ;
348+ /**
349+ * Original normalized to platform separators:
350+ * - Windows: \
351+ * - Posix: /
352+ */
353+ pathNormalized : string ;
354+
355+ /**
356+ * In addition to the normalized path, will have
357+ * whitespace and wildcards removed.
358+ */
359+ normalized : string ;
360+ normalizedLowercase : string ;
346361}
347362
348363export interface IPreparedQuery extends IPreparedQueryPiece {
@@ -364,47 +379,58 @@ export function prepareQuery(original: string): IPreparedQuery {
364379 }
365380
366381 const originalLowercase = original . toLowerCase ( ) ;
367- const value = prepareQueryValue ( original ) ;
368- const valueLowercase = value . toLowerCase ( ) ;
369- const containsPathSeparator = value . indexOf ( sep ) >= 0 ;
382+ const { pathNormalized, normalized, normalizedLowercase } = normalizeQuery ( original ) ;
383+ const containsPathSeparator = pathNormalized . indexOf ( sep ) >= 0 ;
370384
371385 let values : IPreparedQueryPiece [ ] | undefined = undefined ;
372386
373387 const originalSplit = original . split ( MULTIPL_QUERY_VALUES_SEPARATOR ) ;
374388 if ( originalSplit . length > 1 ) {
375389 for ( const originalPiece of originalSplit ) {
376- const valuePiece = prepareQueryValue ( originalPiece ) ;
377- if ( valuePiece ) {
390+ const {
391+ pathNormalized : pathNormalizedPiece ,
392+ normalized : normalizedPiece ,
393+ normalizedLowercase : normalizedLowercasePiece
394+ } = normalizeQuery ( originalPiece ) ;
395+
396+ if ( normalizedPiece ) {
378397 if ( ! values ) {
379398 values = [ ] ;
380399 }
381400
382401 values . push ( {
383402 original : originalPiece ,
384403 originalLowercase : originalPiece . toLowerCase ( ) ,
385- value : valuePiece ,
386- valueLowercase : valuePiece . toLowerCase ( )
404+ pathNormalized : pathNormalizedPiece ,
405+ normalized : normalizedPiece ,
406+ normalizedLowercase : normalizedLowercasePiece
387407 } ) ;
388408 }
389409 }
390410 }
391411
392- return { original, originalLowercase, value , valueLowercase , values, containsPathSeparator } ;
412+ return { original, originalLowercase, pathNormalized , normalized , normalizedLowercase , values, containsPathSeparator } ;
393413}
394414
395- function prepareQueryValue ( original : string ) : string {
396- let value = stripWildcards ( original ) . replace ( / \s / g , '' ) ; // get rid of all wildcards and whitespace
415+ function normalizeQuery ( original : string ) : { pathNormalized : string , normalized : string , normalizedLowercase : string } {
416+ let pathNormalized : string ;
397417 if ( isWindows ) {
398- value = value . replace ( / \/ / g, sep ) ; // Help Windows users to search for paths when using slash
418+ pathNormalized = original . replace ( / \/ / g, sep ) ; // Help Windows users to search for paths when using slash
399419 } else {
400- value = value . replace ( / \\ / g, sep ) ; // Help macOS/Linux users to search for paths when using backslash
420+ pathNormalized = original . replace ( / \\ / g, sep ) ; // Help macOS/Linux users to search for paths when using backslash
401421 }
402422
403- return value ;
423+ const normalized = stripWildcards ( pathNormalized ) . replace ( / \s / g, '' ) ;
424+
425+ return {
426+ pathNormalized,
427+ normalized,
428+ normalizedLowercase : normalized . toLowerCase ( )
429+ } ;
404430}
405431
406432export function scoreItem < T > ( item : T , query : IPreparedQuery , fuzzy : boolean , accessor : IItemAccessor < T > , cache : ScorerCache ) : IItemScore {
407- if ( ! item || ! query . value ) {
433+ if ( ! item || ! query . normalized ) {
408434 return NO_ITEM_SCORE ; // we need an item and query to score on at least
409435 }
410436
@@ -417,9 +443,9 @@ export function scoreItem<T>(item: T, query: IPreparedQuery, fuzzy: boolean, acc
417443
418444 let cacheHash : string ;
419445 if ( description ) {
420- cacheHash = `${ label } ${ description } ${ query . value } ${ fuzzy } ` ;
446+ cacheHash = `${ label } ${ description } ${ query . normalized } ${ fuzzy } ` ;
421447 } else {
422- cacheHash = `${ label } ${ query . value } ${ fuzzy } ` ;
448+ cacheHash = `${ label } ${ query . normalized } ${ fuzzy } ` ;
423449 }
424450
425451 const cached = cache [ cacheHash ] ;
@@ -455,7 +481,7 @@ function createMatches(offsets: undefined | number[]): IMatch[] {
455481function doScoreItem ( label : string , description : string | undefined , path : string | undefined , query : IPreparedQuery , fuzzy : boolean ) : IItemScore {
456482
457483 // 1.) treat identity matches on full path highest
458- if ( path && ( isLinux ? query . original === path : equalsIgnoreCase ( query . original , path ) ) ) {
484+ if ( path && ( isLinux ? query . pathNormalized === path : equalsIgnoreCase ( query . pathNormalized , path ) ) ) {
459485 return { score : PATH_IDENTITY_SCORE , labelMatch : [ { start : 0 , end : label . length } ] , descriptionMatch : description ? [ { start : 0 , end : description . length } ] : undefined } ;
460486 }
461487
@@ -464,13 +490,13 @@ function doScoreItem(label: string, description: string | undefined, path: strin
464490 if ( preferLabelMatches ) {
465491
466492 // 2.) treat prefix matches on the label second highest
467- const prefixLabelMatch = matchesPrefix ( query . value , label ) ;
493+ const prefixLabelMatch = matchesPrefix ( query . normalized , label ) ;
468494 if ( prefixLabelMatch ) {
469495 return { score : LABEL_PREFIX_SCORE , labelMatch : prefixLabelMatch } ;
470496 }
471497
472498 // 3.) treat camelcase matches on the label third highest
473- const camelcaseLabelMatch = matchesCamelCase ( query . value , label ) ;
499+ const camelcaseLabelMatch = matchesCamelCase ( query . normalized , label ) ;
474500 if ( camelcaseLabelMatch ) {
475501 return { score : LABEL_CAMELCASE_SCORE , labelMatch : camelcaseLabelMatch } ;
476502 }
@@ -702,17 +728,17 @@ function fallbackCompare<T>(itemA: T, itemB: T, query: IPreparedQuery, accessor:
702728
703729 // compare by label
704730 if ( labelA !== labelB ) {
705- return compareAnything ( labelA , labelB , query . value ) ;
731+ return compareAnything ( labelA , labelB , query . normalized ) ;
706732 }
707733
708734 // compare by description
709735 if ( descriptionA && descriptionB && descriptionA !== descriptionB ) {
710- return compareAnything ( descriptionA , descriptionB , query . value ) ;
736+ return compareAnything ( descriptionA , descriptionB , query . normalized ) ;
711737 }
712738
713739 // compare by path
714740 if ( pathA && pathB && pathA !== pathB ) {
715- return compareAnything ( pathA , pathB , query . value ) ;
741+ return compareAnything ( pathA , pathB , query . normalized ) ;
716742 }
717743
718744 // equal
0 commit comments