@squawk/airspace 0.8.6 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +42 -4
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -4
- package/dist/resolver.d.ts +40 -0
- package/dist/resolver.d.ts.map +1 -1
- package/dist/resolver.js +26 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
[](../../../LICENSE.md) [](https://www.npmjs.com/package/@squawk/airspace) 
|
|
4
4
|
|
|
5
5
|
Pure logic library for querying US airspace geometry. Given a position and altitude,
|
|
6
|
-
returns all applicable airspace designations
|
|
7
|
-
|
|
6
|
+
returns all applicable airspace designations, or look up and fuzzy-search features by
|
|
7
|
+
identifier and name. Contains no bundled data - accepts a GeoJSON dataset at
|
|
8
|
+
initialization. For zero-config use, pair with `@squawk/airspace-data`.
|
|
8
9
|
|
|
9
10
|
Part of the [@squawk](https://www.npmjs.com/org/squawk) aviation library suite. See all packages on npm.
|
|
10
11
|
|
|
@@ -40,6 +41,10 @@ const laxShells = resolver.byAirport('LAX');
|
|
|
40
41
|
|
|
41
42
|
// Get every ARTCC center boundary (one feature per stratum)
|
|
42
43
|
const ny = resolver.byArtcc('ZNY');
|
|
44
|
+
|
|
45
|
+
// Fuzzy-search features by identifier and name (scored, best match first)
|
|
46
|
+
const matches = resolver.search({ text: 'LAX' });
|
|
47
|
+
console.log(matches[0]?.feature.identifier, matches[0]?.score);
|
|
43
48
|
```
|
|
44
49
|
|
|
45
50
|
Consumers who have their own GeoJSON airspace data can use this package standalone:
|
|
@@ -82,6 +87,9 @@ returns a resolver object with the following methods:
|
|
|
82
87
|
- `byIdentifier(identifier, options?)` - type-agnostic identifier lookup that
|
|
83
88
|
spans both partitions in one call, with an optional `types` inclusion
|
|
84
89
|
filter and `includeArtcc` toggle.
|
|
90
|
+
- `search(AirspaceSearchQuery)` - fuzzy-searches features by identifier and
|
|
91
|
+
name, returning scored results best-match first with the matched field and
|
|
92
|
+
highlight ranges, optionally filtered by type.
|
|
85
93
|
- `byCentroid({ lon, lat, toleranceDeg? })` - returns features whose polygon
|
|
86
94
|
centroid lies within tolerance of the query coordinates. Useful for
|
|
87
95
|
resolving features whose `identifier` is empty (some Class E5 surfaces),
|
|
@@ -130,8 +138,8 @@ Creates a resolver from a GeoJSON dataset.
|
|
|
130
138
|
|
|
131
139
|
**Returns:** `AirspaceResolver` - an object exposing `query(AirspaceQuery)`,
|
|
132
140
|
`byAirport(identifier, types?)`, `byArtcc(identifier, stratum?)`,
|
|
133
|
-
`byIdentifier(identifier, options?)`, `
|
|
134
|
-
and `forEachIndexed(callback)` methods.
|
|
141
|
+
`byIdentifier(identifier, options?)`, `search(query)`, `byCentroid(query)`,
|
|
142
|
+
`withinBbox(bbox)`, and `forEachIndexed(callback)` methods.
|
|
135
143
|
|
|
136
144
|
### `AirspaceQuery`
|
|
137
145
|
|
|
@@ -259,6 +267,36 @@ resolver.forEachIndexed((feature, ring, boundingBox) => {
|
|
|
259
267
|
});
|
|
260
268
|
```
|
|
261
269
|
|
|
270
|
+
### `resolver.search(query)`
|
|
271
|
+
|
|
272
|
+
Fuzzy-searches airspace features across identifier and name. Matching is
|
|
273
|
+
case-insensitive and tolerant of prefixes, substrings, subsequences, and small
|
|
274
|
+
typos. Results are scored and returned best-match first.
|
|
275
|
+
|
|
276
|
+
| Property | Type | Description |
|
|
277
|
+
| ---------- | -------------------------- | ---------------------------------------------------------------------------------------- |
|
|
278
|
+
| `text` | string | Search text, matched fuzzily against each feature's identifier and name |
|
|
279
|
+
| `limit` | number | Optional. Maximum number of results. Defaults to 20 |
|
|
280
|
+
| `types` | ReadonlySet\<AirspaceType> | Optional. When provided, only features of these types are returned |
|
|
281
|
+
| `minScore` | number | Optional. Minimum match score (exclusive) in `[0, 1]` a result must reach. Defaults to 0 |
|
|
282
|
+
|
|
283
|
+
Returns `AirspaceSearchResult[]`, sorted by descending score, each containing:
|
|
284
|
+
|
|
285
|
+
- `feature` - the matched `AirspaceFeature` record
|
|
286
|
+
- `score` - match strength in `[0, 1]`, where 1 is an exact identifier or name match
|
|
287
|
+
- `matchedField` - which field produced the best match: `'identifier'` or `'name'`
|
|
288
|
+
- `ranges` - matched character ranges within the best-matching field's text, for highlighting
|
|
289
|
+
|
|
290
|
+
Features with an empty identifier and name (some Class E5 surfaces) never match a
|
|
291
|
+
non-empty query and are simply absent from results.
|
|
292
|
+
|
|
293
|
+
```typescript
|
|
294
|
+
const results = resolver.search({ text: 'LAX', limit: 10 });
|
|
295
|
+
for (const { feature, score, matchedField } of results) {
|
|
296
|
+
console.log(feature.identifier, score, `(matched ${matchedField})`);
|
|
297
|
+
}
|
|
298
|
+
```
|
|
299
|
+
|
|
262
300
|
### ARTCC altitude bounds
|
|
263
301
|
|
|
264
302
|
ARTCC features carry stratum-aligned floor/ceiling values for use with
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* @packageDocumentation
|
|
3
3
|
* Pure logic library for point-in-airspace queries against US airspace polygons.
|
|
4
4
|
*/
|
|
5
|
+
export type { MatchRange } from '@squawk/search';
|
|
5
6
|
export { createAirspaceResolver } from './resolver.js';
|
|
6
|
-
export type { AirspaceResolver, AirspaceResolverOptions, AirspaceQuery, AirspaceCentroidQuery, AirspaceByIdentifierOptions, } from './resolver.js';
|
|
7
|
+
export type { AirspaceResolver, AirspaceResolverOptions, AirspaceQuery, AirspaceCentroidQuery, AirspaceByIdentifierOptions, AirspaceSearchField, AirspaceSearchQuery, AirspaceSearchResult, } from './resolver.js';
|
|
7
8
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AACvD,YAAY,EACV,gBAAgB,EAChB,uBAAuB,EACvB,aAAa,EACb,qBAAqB,EACrB,2BAA2B,
|
|
1
|
+
{"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,sBAAsB,EAAE,MAAM,eAAe,CAAC;AACvD,YAAY,EACV,gBAAgB,EAChB,uBAAuB,EACvB,aAAa,EACb,qBAAqB,EACrB,2BAA2B,EAC3B,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,eAAe,CAAC"}
|
package/dist/index.js
CHANGED
package/dist/resolver.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { FeatureCollection } from 'geojson';
|
|
2
2
|
import { type BoundingBox } from '@squawk/geo';
|
|
3
|
+
import type { MatchRange } from '@squawk/search';
|
|
3
4
|
import type { AirspaceFeature, AirspaceType, ArtccStratum } from '@squawk/types';
|
|
4
5
|
/**
|
|
5
6
|
* A query describing a geographic position and altitude to resolve
|
|
@@ -64,6 +65,36 @@ export interface AirspaceByIdentifierOptions {
|
|
|
64
65
|
*/
|
|
65
66
|
includeArtcc?: boolean;
|
|
66
67
|
}
|
|
68
|
+
/**
|
|
69
|
+
* The searchable fields an airspace {@link AirspaceSearchResult} can match on.
|
|
70
|
+
*/
|
|
71
|
+
export type AirspaceSearchField = 'identifier' | 'name';
|
|
72
|
+
/**
|
|
73
|
+
* Options for a fuzzy text search query against airspace identifiers and names.
|
|
74
|
+
*/
|
|
75
|
+
export interface AirspaceSearchQuery {
|
|
76
|
+
/** Search text, matched fuzzily and case-insensitively against each feature's identifier and name. */
|
|
77
|
+
text: string;
|
|
78
|
+
/** Maximum number of results to return. Defaults to 20. */
|
|
79
|
+
limit?: number;
|
|
80
|
+
/** Optional set of airspace types to include. When omitted, all types are included. */
|
|
81
|
+
types?: ReadonlySet<AirspaceType>;
|
|
82
|
+
/** 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. */
|
|
83
|
+
minScore?: number;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* A scored airspace result from a fuzzy {@link AirspaceResolver.search}.
|
|
87
|
+
*/
|
|
88
|
+
export interface AirspaceSearchResult {
|
|
89
|
+
/** The matched airspace feature. */
|
|
90
|
+
feature: AirspaceFeature;
|
|
91
|
+
/** Match strength in `[0, 1]`, where 1 is an exact identifier or name match. */
|
|
92
|
+
score: number;
|
|
93
|
+
/** Which field produced the best match, identifying what {@link AirspaceSearchResult.ranges} index into. */
|
|
94
|
+
matchedField: AirspaceSearchField;
|
|
95
|
+
/** Matched character ranges within the best-matching field's text, for highlighting. */
|
|
96
|
+
ranges: MatchRange[];
|
|
97
|
+
}
|
|
67
98
|
/**
|
|
68
99
|
* Options for creating an airspace resolver.
|
|
69
100
|
*/
|
|
@@ -159,6 +190,15 @@ export interface AirspaceResolver {
|
|
|
159
190
|
* @returns All matching features, or an empty array.
|
|
160
191
|
*/
|
|
161
192
|
byIdentifier(identifier: string, options?: AirspaceByIdentifierOptions): AirspaceFeature[];
|
|
193
|
+
/**
|
|
194
|
+
* Fuzzy-searches airspace features across identifier and name. Results are
|
|
195
|
+
* scored and returned best-match first, each carrying the matched field and
|
|
196
|
+
* character ranges for highlighting.
|
|
197
|
+
*
|
|
198
|
+
* Features with an empty identifier and name (some Class E5 surfaces) never
|
|
199
|
+
* match a non-empty query and are simply absent from results.
|
|
200
|
+
*/
|
|
201
|
+
search(query: AirspaceSearchQuery): AirspaceSearchResult[];
|
|
162
202
|
/**
|
|
163
203
|
* Returns every airspace feature whose pre-indexed bounding box overlaps
|
|
164
204
|
* the given bounding box. Reuses the bounding box computed once at
|
package/dist/resolver.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../src/resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAW,MAAM,SAAS,CAAC;AAE1D,OAAO,EAA2B,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../src/resolver.ts"],"names":[],"mappings":"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"}
|
package/dist/resolver.js
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { polygon, polygonGeoJson } from '@squawk/geo';
|
|
2
|
+
import { fuzzySearch } from '@squawk/search';
|
|
2
3
|
import { altitudeMatches } from './vertical-filter.js';
|
|
4
|
+
/**
|
|
5
|
+
* Default maximum number of results for text search queries.
|
|
6
|
+
*/
|
|
7
|
+
const DEFAULT_SEARCH_LIMIT = 20;
|
|
3
8
|
/**
|
|
4
9
|
* Parses a GeoJSON Feature into an IndexedFeature, extracting the
|
|
5
10
|
* AirspaceFeature properties and polygon ring. Returns null if the
|
|
@@ -81,6 +86,7 @@ export function createAirspaceResolver(options) {
|
|
|
81
86
|
}
|
|
82
87
|
}
|
|
83
88
|
}
|
|
89
|
+
const searchableFeatures = indexed.map((entry) => entry.feature);
|
|
84
90
|
return {
|
|
85
91
|
query(query) {
|
|
86
92
|
const results = [];
|
|
@@ -153,6 +159,26 @@ export function createAirspaceResolver(options) {
|
|
|
153
159
|
}
|
|
154
160
|
return bucket.filter((f) => f.type !== 'ARTCC');
|
|
155
161
|
},
|
|
162
|
+
search(query) {
|
|
163
|
+
const options = {
|
|
164
|
+
keys: (feature) => [
|
|
165
|
+
{ name: 'identifier', text: feature.identifier },
|
|
166
|
+
{ name: 'name', text: feature.name },
|
|
167
|
+
],
|
|
168
|
+
limit: query.limit ?? DEFAULT_SEARCH_LIMIT,
|
|
169
|
+
minScore: query.minScore ?? 0,
|
|
170
|
+
};
|
|
171
|
+
const types = query.types;
|
|
172
|
+
if (types) {
|
|
173
|
+
options.filter = (feature) => types.has(feature.type);
|
|
174
|
+
}
|
|
175
|
+
return fuzzySearch(searchableFeatures, query.text, options).map((match) => ({
|
|
176
|
+
feature: match.item,
|
|
177
|
+
score: match.score,
|
|
178
|
+
matchedField: match.field,
|
|
179
|
+
ranges: match.ranges,
|
|
180
|
+
}));
|
|
181
|
+
},
|
|
156
182
|
withinBbox(bbox) {
|
|
157
183
|
const results = [];
|
|
158
184
|
for (const { feature, boundingBox } of indexed) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@squawk/airspace",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Pure logic library for querying US airspace geometry by position and altitude",
|
|
6
6
|
"author": "Neil Cochran",
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"@squawk/geo": "^0.4.3",
|
|
45
|
+
"@squawk/search": "^0.1.0",
|
|
45
46
|
"@squawk/types": "^0.8.0",
|
|
46
47
|
"@types/geojson": "^7946.0.16"
|
|
47
48
|
},
|