@squawk/flightplan 0.10.1 → 0.11.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 CHANGED
@@ -120,8 +120,8 @@ Each element has a `type` discriminant and a `raw` field with the original token
120
120
  | Type | Description | Key fields |
121
121
  | --------------- | ----------------------------------------- | ---------------------------------------------------------------------------- |
122
122
  | `airport` | Resolved airport (ICAO or FAA ID) | `airport` |
123
- | `sid` | Standard Instrument Departure | `procedure`, `legs`, `transition` |
124
- | `star` | Standard Terminal Arrival Route | `procedure`, `legs`, `transition` |
123
+ | `sid` | Standard Instrument Departure | `procedure`, `legs`, `transition`, `airportMismatch` |
124
+ | `star` | Standard Terminal Arrival Route | `procedure`, `legs`, `transition`, `airportMismatch` |
125
125
  | `airway` | Airway segment between entry and exit fix | `airway`, `entryFix`, `exitFix`, `waypoints`, `gaps`, `unusable`, `reversed` |
126
126
  | `direct` | DCT (direct) indicator | - |
127
127
  | `waypoint` | Resolved fix or navaid | `fix` and/or `navaid`, `lat`, `lon` |
@@ -192,6 +192,17 @@ which is how routes are usually filed (`KJFK DEEZZ6 CANDR`). Otherwise the
192
192
  common route alone is expanded. The `sid` or `star` element records the merged
193
193
  transition in `transition`.
194
194
 
195
+ Many procedure identifiers are published as a separate adaptation at each of
196
+ several airports, and the adaptations' legs differ (PANGG7 has seven common
197
+ legs at 05C and five at KMDW). A SID is matched to the route's departure
198
+ airport, the last airport before it, and a STAR to the arrival airport, the
199
+ first airport after it. When no adaptation serves that airport the first one
200
+ published is expanded, so the route still draws, and the element carries the
201
+ airport in `airportMismatch`: the route files the procedure at an airport it
202
+ does not serve, so it is not valid as filed. A STAR with no airport after it,
203
+ or a SID with none before it, is expanded from the first adaptation without a
204
+ flag.
205
+
195
206
  A procedure that cannot be expanded is marked `unresolved`: either the dotted
196
207
  transition is not one of its transitions, or the procedure has no common route
197
208
  (some SIDs and STARs are published as transitions only) and no adjacent fix
@@ -203,10 +214,18 @@ When a token could match multiple entity types (e.g. a 3-letter code matching
203
214
  both an airport and a navaid), the resolver uses this priority order:
204
215
 
205
216
  1. Airway (if previous waypoint context exists and next token available)
206
- 2. Airport (ICAO or FAA ID)
207
- 3. Procedure (SID/STAR)
208
- 4. Fix
209
- 5. Navaid
217
+ 2. Navaid, when the token is an airport's FAA ID, names a navaid, and is
218
+ directly followed by an airway that lists it as a waypoint
219
+ 3. Airport (ICAO or FAA ID)
220
+ 4. Procedure (SID/STAR)
221
+ 5. Fix
222
+ 6. Navaid
223
+
224
+ Rule 2 covers the hundreds of airports that share their FAA ID with a navaid,
225
+ sometimes miles apart: ahead of an airway, `SAT` in `SAT Q24 LSU` is the SAT
226
+ VORTAC the airway is joined at, 6.6 nm from San Antonio's airport. Anywhere
227
+ else the token is the airport, and an ICAO code (`KSAT`) always names the
228
+ airport.
210
229
 
211
230
  The same fix or navaid identifier is sometimes published in more than one
212
231
  region. When the `fixes` or `navaids` provider exposes `byIdentAtPosition`, the
@@ -100,6 +100,14 @@ export interface SidRouteElement {
100
100
  procedure: Procedure;
101
101
  /** Name of the transition merged into `legs`: the one named in a dotted token (`DEEZZ6.CANDR`), or the fix following the SID when it names one of the procedure's transitions. Absent when only the common route was expanded. */
102
102
  transition?: string;
103
+ /**
104
+ * Identifier of the route's departure airport (the last airport before the
105
+ * SID) when no published adaptation of the procedure serves it. The SID is
106
+ * still expanded, from the first adaptation published, so the route can be
107
+ * drawn and measured, but it is not valid as filed. Absent when an
108
+ * adaptation serves the departure airport or the route names none.
109
+ */
110
+ airportMismatch?: string;
103
111
  /** Ordered legs for the procedure expansion. */
104
112
  legs: ProcedureLeg[];
105
113
  }
@@ -115,6 +123,14 @@ export interface StarRouteElement {
115
123
  procedure: Procedure;
116
124
  /** Name of the transition merged into `legs`: the one named in a dotted token (`AALLE4.BBOTL`), or the waypoint preceding the STAR when it names one of the procedure's transitions. Absent when only the common route was expanded. */
117
125
  transition?: string;
126
+ /**
127
+ * Identifier of the route's arrival airport (the first airport after the
128
+ * STAR) when no published adaptation of the procedure serves it. The STAR
129
+ * is still expanded, from the first adaptation published, so the route can
130
+ * be drawn and measured, but it is not valid as filed. Absent when an
131
+ * adaptation serves the arrival airport or the route names none.
132
+ */
133
+ airportMismatch?: string;
118
134
  /** Ordered legs for the procedure expansion. */
119
135
  legs: ProcedureLeg[];
120
136
  }
@@ -1 +1 @@
1
- {"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../src/resolver.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../src/resolver.ts"],"names":[],"mappings":"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"}
package/dist/resolver.js CHANGED
@@ -100,9 +100,13 @@ function tryAirport(token, airports) {
100
100
  /**
101
101
  * Attempts to resolve a token as a SID or STAR procedure at a given
102
102
  * airport context. The airport context is the identifier of the most
103
- * recently seen airport (for SIDs, the departure airport; for STARs,
104
- * the arrival airport - but since the route is parsed left-to-right,
105
- * the most recent airport is the best available hint).
103
+ * route's departure airport for a SID (the last airport before the token)
104
+ * and its arrival airport for a STAR (the first airport after it), since
105
+ * one identifier is often published as a separate adaptation at each of
106
+ * several airports, and the adaptations' legs differ. When no adaptation
107
+ * serves that airport, the first one published is expanded and the element
108
+ * carries `airportMismatch`; when the route names no such airport, the
109
+ * first one is expanded without a flag.
106
110
  *
107
111
  * Accepts both the bare CIFP identifier (e.g. `DEEZZ6`) and the dotted
108
112
  * identifier-with-transition form (e.g. `DEEZZ6.CANDR`). A dotted
@@ -118,7 +122,7 @@ function tryAirport(token, airports) {
118
122
  * expanded: the dotted transition is not one of its transitions, or it
119
123
  * has no common route and no adjacent fix names a transition.
120
124
  */
121
- function tryProcedure(token, procedures, airportContext, previousWaypoint, nextToken) {
125
+ function tryProcedure(token, procedures, previousAirport, resolveNextAirport, previousWaypoint, nextToken) {
122
126
  if (!procedures) {
123
127
  return undefined;
124
128
  }
@@ -132,14 +136,20 @@ function tryProcedure(token, procedures, airportContext, previousWaypoint, nextT
132
136
  if (candidates.length === 0) {
133
137
  return undefined;
134
138
  }
135
- let proc;
136
- if (airportContext !== undefined) {
137
- const upperAirport = airportContext.toUpperCase();
138
- proc = candidates.find((c) => c.airports.some((a) => a.toUpperCase() === upperAirport));
139
- }
140
- if (proc === undefined) {
141
- proc = candidates[0];
139
+ // The arrival airport is only looked up when a STAR candidate needs it.
140
+ let nextAirport;
141
+ let nextAirportResolved = false;
142
+ function routeAirportFor(candidate) {
143
+ if (candidate.type !== 'STAR') {
144
+ return previousAirport;
145
+ }
146
+ if (!nextAirportResolved) {
147
+ nextAirport = resolveNextAirport();
148
+ nextAirportResolved = true;
149
+ }
150
+ return nextAirport;
142
151
  }
152
+ const proc = candidates.find((c) => servesAirport(c, routeAirportFor(c))) ?? candidates[0];
143
153
  if (proc === undefined || proc.type === 'IAP') {
144
154
  return undefined;
145
155
  }
@@ -159,8 +169,23 @@ function tryProcedure(token, procedures, airportContext, previousWaypoint, nextT
159
169
  if (transitionName !== undefined) {
160
170
  element.transition = transitionName;
161
171
  }
172
+ const routeAirport = routeAirportFor(proc);
173
+ if (routeAirport !== undefined && !servesAirport(proc, routeAirport)) {
174
+ element.airportMismatch = routeAirport;
175
+ }
162
176
  return element;
163
177
  }
178
+ /**
179
+ * Whether a procedure adaptation is published for the given airport
180
+ * identifier. An undefined airport is served by nothing.
181
+ */
182
+ function servesAirport(procedure, airport) {
183
+ if (airport === undefined) {
184
+ return false;
185
+ }
186
+ const upper = airport.toUpperCase();
187
+ return procedure.airports.some((a) => a.toUpperCase() === upper);
188
+ }
164
189
  /**
165
190
  * Returns the procedure's transition whose name matches the adjacent fix
166
191
  * token, in the procedure's own spelling, or `undefined` when there is
@@ -207,6 +232,55 @@ function tryNavaid(token, navaids, anchor) {
207
232
  }
208
233
  return undefined;
209
234
  }
235
+ /**
236
+ * Resolves a token as the navaid where the following airway is entered, when
237
+ * the token matches an airport by its FAA identifier and also names a navaid
238
+ * that is a waypoint of that airway (`SAT Q24 LSU`, `SJN J108 INK`). Hundreds
239
+ * of airports share their FAA identifier with a navaid, sometimes miles away
240
+ * (San Antonio's airport is 6.6 nm from the SAT VORTAC), and a token directly
241
+ * ahead of an airway names the point the airway is joined at. The navaid is
242
+ * chosen by proximity to that airway waypoint.
243
+ *
244
+ * Returns `undefined`, leaving the token to resolve as the airport, when it
245
+ * matches an airport by ICAO code (an ICAO code always names the airport),
246
+ * matches no airport, is not followed by an airway that lists it, or names no
247
+ * navaid there.
248
+ */
249
+ function tryAirwayEntryNavaid(token, nextToken, airports, navaids, airways) {
250
+ if (!airports || !navaids || !airways || nextToken === undefined) {
251
+ return undefined;
252
+ }
253
+ if (airports.byIcao(token) !== undefined || airports.byFaaId(token) === undefined) {
254
+ return undefined;
255
+ }
256
+ for (const airway of airways.byDesignation(nextToken)) {
257
+ const entry = airway.waypoints.find((w) => w.identifier?.toUpperCase() === token);
258
+ if (entry !== undefined) {
259
+ return tryNavaid(token, navaids, { lat: entry.lat, lon: entry.lon });
260
+ }
261
+ }
262
+ return undefined;
263
+ }
264
+ /**
265
+ * Identifier of the first airport among the tokens from `start` on, by the
266
+ * same rules the parse applies (a token that resolves as an airway-entry
267
+ * navaid is not an airport), as the airport's ICAO code when it has one and
268
+ * its FAA identifier otherwise. Returns `undefined` when none follows. Used
269
+ * as the arrival airport of a STAR.
270
+ */
271
+ function findNextAirport(tokens, start, airports, navaids, airways) {
272
+ for (let j = start; j < tokens.length; j++) {
273
+ const token = tokens[j].toUpperCase();
274
+ if (tryAirwayEntryNavaid(token, tokens[j + 1]?.toUpperCase(), airports, navaids, airways)) {
275
+ continue;
276
+ }
277
+ const airportElement = tryAirport(token, airports);
278
+ if (airportElement) {
279
+ return airportElement.airport.icao ?? airportElement.airport.faaId;
280
+ }
281
+ }
282
+ return undefined;
283
+ }
210
284
  // ---------------------------------------------------------------------------
211
285
  // Main parse implementation
212
286
  // ---------------------------------------------------------------------------
@@ -334,13 +408,23 @@ export function createFlightplanResolver(options) {
334
408
  i++;
335
409
  continue;
336
410
  }
411
+ // An FAA airport identifier that also names a navaid on the airway
412
+ // that follows is where the airway is joined, not the airport.
413
+ const entryNavaid = tryAirwayEntryNavaid(token, tokens[i + 1]?.toUpperCase(), airports, navaids, airways);
414
+ if (entryNavaid) {
415
+ elements.push(entryNavaid);
416
+ lastWaypointIdent = token;
417
+ lastPosition = { lat: entryNavaid.lat, lon: entryNavaid.lon };
418
+ i++;
419
+ continue;
420
+ }
337
421
  // Try airport
338
422
  const airportElement = tryAirport(token, airports);
339
423
  if (airportElement) {
340
424
  elements.push(airportElement);
341
425
  // Preserve the token as lastWaypointIdent so a following airway can
342
- // use it as the entry fix (e.g. "BOS V16 CCC" where BOS is both an
343
- // airport and a navaid on V16).
426
+ // still use it as the entry fix when no navaid lookup resolved it
427
+ // above.
344
428
  lastWaypointIdent = token;
345
429
  lastAirportIdent = airportElement.airport.icao ?? airportElement.airport.faaId;
346
430
  lastPosition = { lat: airportElement.airport.lat, lon: airportElement.airport.lon };
@@ -349,7 +433,8 @@ export function createFlightplanResolver(options) {
349
433
  }
350
434
  // Try procedure (SID/STAR). The fix after a SID or before a STAR may
351
435
  // name the transition when the token itself does not.
352
- const procElement = tryProcedure(token, procedures, lastAirportIdent, lastWaypointIdent, tokens[i + 1]?.toUpperCase());
436
+ const nextIndex = i + 1;
437
+ const procElement = tryProcedure(token, procedures, lastAirportIdent, () => findNextAirport(tokens, nextIndex, airports, navaids, airways), lastWaypointIdent, tokens[i + 1]?.toUpperCase());
353
438
  if (procElement) {
354
439
  elements.push(procElement);
355
440
  if (procElement.type === 'unresolved') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@squawk/flightplan",
3
- "version": "0.10.1",
3
+ "version": "0.11.0",
4
4
  "type": "module",
5
5
  "description": "Flight plan route string parsing and resolution using composed navigation resolvers",
6
6
  "author": "Neil Cochran",