@@ -13,8 +13,42 @@ const matchGroups = matchGroupsJSON.matchGroups;
1313const trees = treesJSON . trees ;
1414
1515
16+ type Vec2 = [ number , number ] ;
17+ type Vec3 = [ number , number , number ] ;
18+ type Location = Vec2 | Vec3 | string | number ;
19+
20+ interface LocationSet {
21+ include ?: Array < Location > ,
22+ exclude ?: Array < Location >
23+ } ;
24+
25+ interface LocationConflation {
26+ validateLocation : ( a : Location ) => unknown ;
27+ resolveLocation : ( a : Location ) => unknown ;
28+ validateLocationSet : ( a : LocationSet ) => unknown ;
29+ resolveLocationSet : ( a : LocationSet ) => unknown ;
30+ } ;
31+
32+ type HitType = 'primary' | 'alternate' | 'excludeGeneric' | 'excludeNamed' ;
33+ interface Hit {
34+ match : HitType ;
35+ itemID ?: string ;
36+ area ?: number ;
37+ kv ?: string ;
38+ nsimple ?: string ;
39+ pattern ?: string ;
40+ } ;
41+
42+
1643export class Matcher {
17- //
44+ private matchIndex ;
45+ private genericWords = new Map ( ) ;
46+ private itemLocation ;
47+ private locationSets ;
48+ private locationIndex ;
49+ private warnings : Array < string > = [ ] ;
50+
51+
1852 // `constructor`
1953 // initialize the genericWords regexes
2054 constructor ( ) {
@@ -105,7 +139,7 @@ export class Matcher {
105139 // …
106140 // }
107141 //
108- buildMatchIndex ( data ) {
142+ buildMatchIndex ( data : Record < string , any > ) : void {
109143 const that = this ;
110144 if ( that . matchIndex ) return ; // it was built already
111145 that . matchIndex = new Map ( ) ;
@@ -248,7 +282,7 @@ export class Matcher {
248282
249283
250284 // Insert this item into the matchIndex
251- function insertName ( which , t , kv , nsimple , itemID ) {
285+ function insertName ( which : string , t : string , kv : string , nsimple : string , itemID : string ) {
252286 if ( ! nsimple ) {
253287 that . warnings . push ( `Warning: skipping empty ${ which } name for item ${ t } /${ kv } : ${ itemID } ` ) ;
254288 return ;
@@ -287,7 +321,7 @@ export class Matcher {
287321 }
288322
289323 // For certain categories we do not want to match generic KV pairs like `building/yes` or `amenity/yes`
290- function skipGenericKVMatches ( t , k , v ) {
324+ function skipGenericKVMatches ( t : string , k : string , v : string ) : boolean {
291325 return (
292326 t === 'flags' ||
293327 t === 'transit' ||
@@ -324,7 +358,7 @@ export class Matcher {
324358 // …
325359 // }
326360 //
327- buildLocationIndex ( data , loco ) {
361+ buildLocationIndex ( data : Record < string , any > , loco : LocationConflation ) : void {
328362 const that = this ;
329363 if ( that . locationIndex ) return ; // it was built already
330364
@@ -341,8 +375,9 @@ export class Matcher {
341375 let resolved ;
342376 try {
343377 resolved = loco . resolveLocationSet ( item . locationSet ) ; // resolve a feature for this locationSet
344- } catch ( err ) {
345- console . warn ( `buildLocationIndex: ${ err . message } ` ) ; // couldn't resolve
378+ } catch ( err : unknown ) {
379+ const message = ( err instanceof Error ) ? err . message : err ;
380+ console . warn ( `buildLocationIndex: ${ message } ` ) ; // couldn't resolve
346381 }
347382 if ( ! resolved || ! resolved . id ) return ;
348383
@@ -420,7 +455,7 @@ export class Matcher {
420455 // 3. If the [k,v,n] tuple matches nothing of any kind, return `null`
421456 //
422457 //
423- match ( k , v , n , loc ) {
458+ match ( k : string , v : string , n : string , loc ?: Vec2 ) : Array < Hit > | null {
424459 const that = this ;
425460 if ( ! that . matchIndex ) {
426461 throw new Error ( 'match: matchIndex not built.' ) ;
@@ -436,8 +471,8 @@ export class Matcher {
436471
437472 const nsimple = simplify ( n ) ;
438473
439- let seen = new Set ( ) ;
440- let results = [ ] ;
474+ const seen = new Set ( ) ;
475+ const results : Array < Hit > = [ ] ;
441476 gatherResults ( 'primary' ) ;
442477 gatherResults ( 'alternate' ) ;
443478 if ( results . length ) return results ;
@@ -446,14 +481,14 @@ export class Matcher {
446481 return results . length ? results : null ;
447482
448483
449- function gatherResults ( which ) {
484+ function gatherResults ( which : string ) : void {
450485 // First try an exact match on k/v
451486 const kv = `${ k } /${ v } ` ;
452487 let didMatch = tryMatch ( which , kv ) ;
453488 if ( didMatch ) return ;
454489
455490 // If that didn't work, look in match groups for other pairs considered equivalent to k/v..
456- for ( let mg in matchGroups ) {
491+ for ( const mg in matchGroups ) {
457492 const matchGroup = matchGroups [ mg ] ;
458493 const inGroup = matchGroup . some ( otherkv => otherkv === kv ) ;
459494 if ( ! inGroup ) continue ;
@@ -476,38 +511,39 @@ export class Matcher {
476511 }
477512 }
478513
479-
480- function tryMatch ( which , kv ) {
514+ function tryMatch ( which : string , kv : string ) : boolean {
481515 const branch = that . matchIndex . get ( kv ) ;
482- if ( ! branch ) return ;
516+ if ( ! branch ) return false ;
483517
484518 if ( which === 'exclude' ) { // Test name `n` against named and generic exclude patterns
485519 let regex = [ ...branch . excludeNamed . values ( ) ] . find ( regex => regex . test ( n ) ) ;
486520 if ( regex ) {
487521 results . push ( { match : 'excludeNamed' , pattern : String ( regex ) , kv : kv } ) ;
488- return ;
522+ return false ;
489523 }
490524 regex = [ ...branch . excludeGeneric . values ( ) ] . find ( regex => regex . test ( n ) ) ;
491525 if ( regex ) {
492526 results . push ( { match : 'excludeGeneric' , pattern : String ( regex ) , kv : kv } ) ;
493- return ;
527+ return false ;
494528 }
495- return ;
529+ return false ;
496530 }
497531
498532 const leaf = branch [ which ] . get ( nsimple ) ;
499- if ( ! leaf || ! leaf . size ) return ;
533+ if ( ! leaf || ! leaf . size ) return false ;
534+ if ( ! ( which === 'primary' || which === 'alternate' ) ) return false ;
500535
501536 // If we get here, we matched something..
502537 // Prepare the results, calculate areas (if location index was set up)
503- let hits = Array . from ( leaf ) . map ( itemID => {
538+ let hits : Array < Hit > = [ ] ;
539+ for ( const itemID of [ ...leaf ] ) {
504540 let area = Infinity ;
505541 if ( that . itemLocation && that . locationSets ) {
506542 const location = that . locationSets . get ( that . itemLocation . get ( itemID ) ) ;
507543 area = ( location && location . properties . area ) || Infinity ;
508544 }
509- return { match : which , itemID : itemID , area : area , kv : kv , nsimple : nsimple } ;
510- } ) ;
545+ hits . push ( { match : which , itemID : itemID , area : area , kv : kv , nsimple : nsimple } ) ;
546+ }
511547
512548 let sortFn = byAreaDescending ;
513549
@@ -517,7 +553,7 @@ export class Matcher {
517553 sortFn = byAreaAscending ;
518554 }
519555
520- if ( ! hits . length ) return ;
556+ if ( ! hits . length ) return false ;
521557
522558 // push results
523559 hits . sort ( sortFn ) . forEach ( hit => {
@@ -529,17 +565,21 @@ export class Matcher {
529565 return true ;
530566
531567
532- function isValidLocation ( hit ) {
568+ function isValidLocation ( hit : Hit ) : boolean {
533569 if ( ! that . itemLocation ) return true ;
534570 return matchLocations . find ( props => props . id === that . itemLocation . get ( hit . itemID ) ) ;
535571 }
536572 // Sort smaller (more local) locations first.
537- function byAreaAscending ( hitA , hitB ) {
538- return hitA . area - hitB . area ;
573+ function byAreaAscending ( hitA : Hit , hitB : Hit ) : number {
574+ const areaA = hitA . area || 0 ;
575+ const areaB = hitB . area || 0 ;
576+ return areaA - areaB ;
539577 }
540578 // Sort larger (more worldwide) locations first.
541- function byAreaDescending ( hitA , hitB ) {
542- return hitB . area - hitA . area ;
579+ function byAreaDescending ( hitA : Hit , hitB : Hit ) : number {
580+ const areaA = hitA . area || 0 ;
581+ const areaB = hitB . area || 0 ;
582+ return areaB - areaA ;
543583 }
544584 }
545585 }
@@ -550,7 +590,7 @@ export class Matcher {
550590 // Return any warnings discovered when buiding the index.
551591 // (currently this does nothing)
552592 //
553- getWarnings ( ) {
593+ getWarnings ( ) : Array < string > {
554594 return this . warnings ;
555595 }
556596}
0 commit comments