@squawk/airports
Advanced tools
+2
-1
@@ -5,4 +5,5 @@ /** | ||
| */ | ||
| export type { MatchRange } from '@squawk/search'; | ||
| export { createAirportResolver } from './resolver.js'; | ||
| export type { AirportResolver, AirportResolverOptions, NearestAirportQuery, NearestAirportResult, AirportSearchQuery, } from './resolver.js'; | ||
| export type { AirportResolver, AirportResolverOptions, NearestAirportQuery, NearestAirportResult, AirportSearchQuery, AirportSearchField, AirportSearchResult, } from './resolver.js'; | ||
| //# sourceMappingURL=index.d.ts.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACtD,YAAY,EACV,eAAe,EACf,sBAAsB,EACtB,mBAAmB,EACnB,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,eAAe,CAAC"} | ||
| {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,YAAY,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACtD,YAAY,EACV,eAAe,EACf,sBAAsB,EACtB,mBAAmB,EACnB,oBAAoB,EACpB,kBAAkB,EAClB,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,eAAe,CAAC"} |
+0
-4
@@ -1,5 +0,1 @@ | ||
| /** | ||
| * @packageDocumentation | ||
| * Pure logic library for querying US airport data. | ||
| */ | ||
| export { createAirportResolver } from './resolver.js'; |
+27
-5
@@ -0,1 +1,2 @@ | ||
| import type { MatchRange } from '@squawk/search'; | ||
| import type { Airport, FacilityType } from '@squawk/types'; | ||
@@ -36,6 +37,11 @@ /** | ||
| /** | ||
| * Options for a text search query against airport names and cities. | ||
| * The searchable fields an airport {@link AirportSearchResult} can match on. | ||
| */ | ||
| export type AirportSearchField = 'faaId' | 'icao' | 'name' | 'city'; | ||
| /** | ||
| * Options for a fuzzy text search query against airport identifiers, names, and | ||
| * cities. | ||
| */ | ||
| export interface AirportSearchQuery { | ||
| /** Case-insensitive substring to match against airport name or city. */ | ||
| /** Search text, matched fuzzily and case-insensitively against each airport's FAA ID, ICAO code, name, and city. */ | ||
| text: string; | ||
@@ -46,4 +52,19 @@ /** Maximum number of results to return. Defaults to 20. */ | ||
| types?: ReadonlySet<FacilityType>; | ||
| /** Minimum match score (exclusive) in `[0, 1]` a result must reach. Defaults to 0, which keeps every match. Raise it to drop weak fuzzy matches. */ | ||
| minScore?: number; | ||
| } | ||
| /** | ||
| * A scored airport result from a fuzzy {@link AirportResolver.search}. | ||
| */ | ||
| export interface AirportSearchResult { | ||
| /** The matched airport record. */ | ||
| airport: Airport; | ||
| /** Match strength in `[0, 1]`, where 1 is an exact identifier or name match. */ | ||
| score: number; | ||
| /** Which field produced the best match, identifying what {@link AirportSearchResult.ranges} index into. */ | ||
| matchedField: AirportSearchField; | ||
| /** Matched character ranges within the best-matching field's text, for highlighting. */ | ||
| ranges: MatchRange[]; | ||
| } | ||
| /** | ||
| * A stateless resolver providing airport lookup methods. | ||
@@ -68,6 +89,7 @@ */ | ||
| /** | ||
| * Searches airports by name or city using case-insensitive substring matching. | ||
| * Results are returned in alphabetical order by name. | ||
| * Fuzzy-searches airports across FAA ID, ICAO code, name, and city. Results | ||
| * are scored and returned best-match first, each carrying the matched field | ||
| * and character ranges for highlighting. | ||
| */ | ||
| search(query: AirportSearchQuery): Airport[]; | ||
| search(query: AirportSearchQuery): AirportSearchResult[]; | ||
| } | ||
@@ -74,0 +96,0 @@ /** |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../src/resolver.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE3D;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,qDAAqD;IACrD,IAAI,EAAE,OAAO,EAAE,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,2CAA2C;IAC3C,GAAG,EAAE,MAAM,CAAC;IACZ,4CAA4C;IAC5C,GAAG,EAAE,MAAM,CAAC;IACZ,0DAA0D;IAC1D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,2DAA2D;IAC3D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uFAAuF;IACvF,KAAK,CAAC,EAAE,WAAW,CAAC,YAAY,CAAC,CAAC;IAClC,wHAAwH;IACxH,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,kCAAkC;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,0DAA0D;IAC1D,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC;IACb,2DAA2D;IAC3D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uFAAuF;IACvF,KAAK,CAAC,EAAE,WAAW,CAAC,YAAY,CAAC,CAAC;CACnC;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;IAE5C;;;OAGG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;IAE1C;;;OAGG;IACH,OAAO,CAAC,KAAK,EAAE,mBAAmB,GAAG,oBAAoB,EAAE,CAAC;IAE5D;;;OAGG;IACH,MAAM,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,EAAE,CAAC;CAC9C;AAiBD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,sBAAsB,GAAG,eAAe,CA8EtF"} | ||
| {"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../src/resolver.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAsB,UAAU,EAAe,MAAM,gBAAgB,CAAC;AAClF,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE3D;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,qDAAqD;IACrD,IAAI,EAAE,OAAO,EAAE,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,2CAA2C;IAC3C,GAAG,EAAE,MAAM,CAAC;IACZ,4CAA4C;IAC5C,GAAG,EAAE,MAAM,CAAC;IACZ,0DAA0D;IAC1D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,2DAA2D;IAC3D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uFAAuF;IACvF,KAAK,CAAC,EAAE,WAAW,CAAC,YAAY,CAAC,CAAC;IAClC,wHAAwH;IACxH,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,kCAAkC;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,0DAA0D;IAC1D,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAEpE;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,oHAAoH;IACpH,IAAI,EAAE,MAAM,CAAC;IACb,2DAA2D;IAC3D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uFAAuF;IACvF,KAAK,CAAC,EAAE,WAAW,CAAC,YAAY,CAAC,CAAC;IAClC,oJAAoJ;IACpJ,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,kCAAkC;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,gFAAgF;IAChF,KAAK,EAAE,MAAM,CAAC;IACd,2GAA2G;IAC3G,YAAY,EAAE,kBAAkB,CAAC;IACjC,wFAAwF;IACxF,MAAM,EAAE,UAAU,EAAE,CAAC;CACtB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;;OAGG;IACH,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;IAE5C;;;OAGG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC;IAE1C;;;OAGG;IACH,OAAO,CAAC,KAAK,EAAE,mBAAmB,GAAG,oBAAoB,EAAE,CAAC;IAE5D;;;;OAIG;IACH,MAAM,CAAC,KAAK,EAAE,kBAAkB,GAAG,mBAAmB,EAAE,CAAC;CAC1D;AAiBD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,sBAAsB,GAAG,eAAe,CAiFtF"} |
+25
-16
| import { greatCircle } from '@squawk/geo'; | ||
| import { fuzzySearch } from '@squawk/search'; | ||
| /** | ||
@@ -73,21 +74,29 @@ * Default maximum distance in nautical miles for nearest-airport queries. | ||
| search(query) { | ||
| const limit = query.limit ?? DEFAULT_SEARCH_LIMIT; | ||
| const needle = query.text.toLowerCase(); | ||
| if (needle.length === 0) { | ||
| return []; | ||
| const options = { | ||
| keys: (airport) => { | ||
| const fields = [ | ||
| { name: 'faaId', text: airport.faaId }, | ||
| { name: 'name', text: airport.name }, | ||
| { name: 'city', text: airport.city }, | ||
| ]; | ||
| if (airport.icao) { | ||
| fields.push({ name: 'icao', text: airport.icao }); | ||
| } | ||
| return fields; | ||
| }, | ||
| limit: query.limit ?? DEFAULT_SEARCH_LIMIT, | ||
| minScore: query.minScore ?? 0, | ||
| }; | ||
| const types = query.types; | ||
| if (types) { | ||
| options.filter = (airport) => types.has(airport.facilityType); | ||
| } | ||
| const results = []; | ||
| for (const airport of airports) { | ||
| if (query.types && !query.types.has(airport.facilityType)) { | ||
| continue; | ||
| } | ||
| if (airport.name.toLowerCase().includes(needle) || | ||
| airport.city.toLowerCase().includes(needle)) { | ||
| results.push(airport); | ||
| } | ||
| } | ||
| results.sort((a, b) => a.name.localeCompare(b.name)); | ||
| return results.slice(0, limit); | ||
| return fuzzySearch(airports, query.text, options).map((match) => ({ | ||
| airport: match.item, | ||
| score: match.score, | ||
| matchedField: match.field, | ||
| ranges: match.ranges, | ||
| })); | ||
| }, | ||
| }; | ||
| } |
+2
-1
| { | ||
| "name": "@squawk/airports", | ||
| "version": "0.6.7", | ||
| "version": "0.7.0", | ||
| "type": "module", | ||
@@ -45,2 +45,3 @@ "description": "Pure logic library for querying US airport data by identifier, location, or name", | ||
| "@squawk/geo": "^0.4.3", | ||
| "@squawk/search": "^0.1.0", | ||
| "@squawk/types": "^0.8.0" | ||
@@ -47,0 +48,0 @@ }, |
+24
-10
@@ -6,3 +6,3 @@ <h1><img src="../../../assets/squawk-logo.svg" alt="squawk logo" width="48" height="48" style="vertical-align: middle"> @squawk/airports</h1> | ||
| Pure logic library for querying US airport data. Look up airports by FAA ID, ICAO code, | ||
| geographic proximity, or name/city search. Contains no bundled data - accepts an array of | ||
| geographic proximity, or fuzzy text search. Contains no bundled data - accepts an array of | ||
| Airport records at initialization. For zero-config use, pair with `@squawk/airport-data`. | ||
@@ -32,4 +32,5 @@ | ||
| // Search by name or city | ||
| // Fuzzy-search across FAA ID, ICAO, name, and city (scored, best match first) | ||
| const results = resolver.search({ text: 'chicago' }); | ||
| console.log(results[0]?.airport.name, results[0]?.score); | ||
| ``` | ||
@@ -117,15 +118,28 @@ | ||
| Searches airports by name or city using case-insensitive substring matching. | ||
| Results are returned in alphabetical order by name. | ||
| Fuzzy-searches airports across FAA ID, ICAO code, name, and city. Matching is | ||
| case-insensitive and tolerant of prefixes, substrings, subsequences, and small typos. | ||
| Results are scored and returned best-match first. | ||
| | Property | Type | Description | | ||
| | -------- | -------------------------- | -------------------------------------------------------------------- | | ||
| | `text` | string | Case-insensitive substring to match against name or city | | ||
| | `limit` | number | Optional. Maximum number of results. Defaults to 20 | | ||
| | `types` | ReadonlySet\<FacilityType> | Optional. When provided, only facilities of these types are returned | | ||
| | Property | Type | Description | | ||
| | ---------- | -------------------------- | ---------------------------------------------------------------------------------------- | | ||
| | `text` | string | Search text, matched fuzzily against each airport's FAA ID, ICAO code, name, and city | | ||
| | `limit` | number | Optional. Maximum number of results. Defaults to 20 | | ||
| | `types` | ReadonlySet\<FacilityType> | Optional. When provided, only facilities of these types are returned | | ||
| | `minScore` | number | Optional. Minimum match score (exclusive) in `[0, 1]` a result must reach. Defaults to 0 | | ||
| Returns `Airport[]`. | ||
| Returns `AirportSearchResult[]`, sorted by descending score, each containing: | ||
| - `airport` - the matched Airport record | ||
| - `score` - match strength in `[0, 1]`, where 1 is an exact identifier or name match | ||
| - `matchedField` - which field produced the best match: `'faaId'`, `'icao'`, `'name'`, or `'city'` | ||
| - `ranges` - matched character ranges within the best-matching field's text, for highlighting | ||
| ```typescript | ||
| const results = resolver.search({ text: 'san francisco', limit: 10 }); | ||
| for (const { airport, score, matchedField } of results) { | ||
| console.log(airport.faaId, score, `(matched ${matchedField})`); | ||
| } | ||
| // Raise minScore to drop weak fuzzy matches | ||
| const strong = resolver.search({ text: 'kennedy', minScore: 0.5 }); | ||
| ``` | ||
@@ -132,0 +146,0 @@ |
19371
18.23%223
14.36%165
9.27%3
50%+ Added
+ Added