flight-planner
Version:
Plan and route VFR flights
239 lines (238 loc) • 10.4 kB
TypeScript
import type { WaypointType } from './navigation.types.js';
import { Aerodrome } from './waypoint.types.js';
import type { ICAO } from './constants.js';
/**
* Abstract base class for service implementations that handle entity retrieval.
*
* @template T - The type of entity this service manages
*
* @remarks
* This class provides a standard interface for services that need to find entities
* by ICAO codes or geographic location. All concrete implementations must provide
* their own implementations of the abstract methods.
*
* Users of this library must implement this class to provide data fetching logic
* for their specific data sources (database, API, cache, etc.).
*
* @example
* ```typescript
* class MyAerodromeService extends ServiceBase<Aerodrome> {
* async findByICAO(icao: readonly ICAO[]): Promise<Aerodrome[]> {
* return await database.getAerodromesByICAO(icao);
* }
*
* async findByLocation(location: GeoJSON.Position, radius: number): Promise<Aerodrome[]> {
* return await database.getAerodromesNearLocation(location, radius);
* }
* }
* ```
*/
export declare abstract class ServiceBase<T> {
/**
* Finds entities by their ICAO codes.
*
* @param icao - An array of ICAO codes to search for
* @returns A promise that resolves to an array of entities matching the provided ICAO codes
*
* @example
* ```typescript
* const results = await service.findByICAO(['KJFK', 'KLAX']);
* ```
*/
abstract findByICAO(icao: readonly ICAO[]): Promise<T[]>;
/**
* Finds entities within a specified radius of a geographic location.
*
* @param location - A GeoJSON position [longitude, latitude, altitude?] representing the center point
* @param radius - The search radius in kilometers
* @returns A promise that resolves to an array of entities within the specified radius
*
* @example
* ```typescript
* const results = await service.findByLocation([-74.0060, 40.7128], 50);
* ```
*/
abstract findByLocation(location: GeoJSON.Position, radius: number): Promise<T[]>;
}
/**
* Interface for waypoint resolvers that attempt to resolve a route string part into a waypoint.
* Resolvers are called in sequence until one successfully resolves the waypoint.
*
* @interface WaypointResolver
*/
export interface WaypointResolver {
/**
* Attempts to resolve a route string part into a waypoint.
*
* @param part - The route string part to resolve (e.g., "KJFK", "WP(40.7128,-74.0060)", "VOR123")
* @returns A promise that resolves to a WaypointType if successful, null/undefined if the resolver cannot handle this part
* @throws {Error} May throw an error if the part matches the resolver's pattern but is invalid (e.g., invalid ICAO, malformed coordinates)
*/
resolve(part: string): Promise<WaypointType | null | undefined>;
}
/**
* PlannerService class provides methods to parse and resolve flight route strings into waypoints.
* Uses a configurable chain of resolvers to support various waypoint formats.
*
* @class PlannerService
*
* @remarks
* **Typical Usage**: Use the `createDefaultPlannerService()` factory function to get a pre-configured
* instance with ICAO and coordinate resolvers.
*
* **Advanced Usage**: Use the constructor directly when you need full control over the resolver chain,
* such as when you want to exclude default resolvers or change their order.
*
* @example
* ```typescript
* // Recommended: Use factory function for standard use cases
* const planner = createDefaultPlannerService(aerodromeService);
*
* // Advanced: Direct construction for custom resolver chains
* const planner = new PlannerService([
* new MyCustomResolver(),
* new ICAOResolver(aerodromeService),
* ]);
* ```
*/
export declare class PlannerService {
private resolvers;
/**
* Creates a new instance of the PlannerService class.
*
* @param resolvers - Array of waypoint resolvers that will be tried in sequence to resolve route parts
*
* @remarks
* Resolvers are tried in the order they appear in the array. The first resolver to return a
* non-null/non-undefined value wins. Consider using `createDefaultPlannerService()` instead
* for typical use cases.
*/
constructor(resolvers?: WaypointResolver[]);
/**
* Adds a custom waypoint resolver to the resolver chain.
* The resolver will be added at the end of the chain and will be tried after existing resolvers.
*
* @param resolver - The waypoint resolver to add
* @returns void
*/
addResolver(resolver: WaypointResolver): void;
/**
* Clears all waypoint resolvers from the resolver chain.
*
* @remarks
* WARNING: This removes ALL resolvers including the default ICAO and Coordinate resolvers.
* After calling this method, route parsing will fail unless new resolvers are added.
*
* @returns void
*/
clearResolvers(): void;
/**
* Parses a route string into an array of waypoints.
*
* This method accepts a route string containing various waypoint formats and converts them
* into standardized waypoint objects using a chain of resolvers.
*
* @param routeString - The route string to parse, containing waypoints separated by spaces, semicolons, or newlines
* @returns A promise that resolves to an array of successfully parsed waypoints
*
* @remarks
* Supported waypoint formats depend on the configured resolvers. The default factory function
* (`createDefaultPlannerService`) provides support for:
* - ICAO codes: 4-letter airport identifiers (e.g., "KJFK", "EGLL")
* - Coordinate waypoints: WP(latitude,longitude) format (e.g., "WP(40.7128,-74.0060)")
*
* Custom resolvers can be added to support additional formats such as:
* - IATA codes (e.g., "JFK", "LHR")
* - VOR/NDB navaids (e.g., "VOR123", "NDB456")
* - IFR waypoints (e.g., "BOSOX", "CRISY")
* - VFR reporting points (e.g., "VRP_XX")
*
* Processing steps:
* 1. Returns empty array if routeString is empty or falsy
* 2. Converts input to uppercase for consistency
* 3. Splits the route string by whitespace, semicolons, and newlines
* 4. Filters out empty parts
* 5. For each part, attempts to resolve using the chain of resolvers in order
* 6. Silently skips parts that cannot be resolved by any resolver
*
* **Error Handling**:
* - Parts that don't match any resolver pattern are **silently skipped**
* - Parts that match a resolver's pattern but fail to resolve (e.g., valid ICAO code but
* aerodrome not found in database) **will throw an error**
* - This means the returned array may have fewer waypoints than parts in the input string
*
* For example:
* - "KJFK UNKNOWN EGLL" where UNKNOWN is not a valid ICAO → returns 2 waypoints (KJFK, EGLL)
* - "KJFK XXXX EGLL" where XXXX is a valid ICAO pattern but not found → throws error
*
* @throws {Error} When a resolver matches a pattern but fails to find the entity
*
* @example
* ```typescript
* const waypoints = await planner.parseRouteString("KJFK EGLL WP(51.5,-0.1)");
* // Returns array with resolved waypoints, skipping any unresolvable parts
* ```
*/
parseRouteString(routeString: string): Promise<WaypointType[]>;
/**
* Attempts to resolve multiple route parts into waypoints using the chain of resolvers.
*
* @param parts - An array of route string parts to resolve
* @returns A promise that resolves to an array of successfully resolved waypoints
*
* @remarks
* For each part, resolvers are tried in order until one successfully resolves it.
* Parts that cannot be resolved by any resolver are silently skipped.
* If a resolver throws an error for a matched pattern, that error will propagate and stop processing.
*/
resolveRouteParts(parts: string[]): Promise<WaypointType[]>;
/**
* Attempts to resolve a single route part into a waypoint using the chain of resolvers.
*
* @param part - The route string part to resolve
* @returns A promise that resolves to a WaypointType if any resolver successfully handles it, or null/undefined if no resolver can handle it
*
* @remarks
* Resolvers are tried in the order they exist in the resolvers array.
* Returns the result from the first resolver that returns a non-null/non-undefined value.
* If a resolver throws an error, that error will propagate.
*/
resolveRoutePart(part: string): Promise<WaypointType | null | undefined>;
}
/**
* Creates a PlannerService instance with default waypoint resolvers.
*
* This factory function initializes a PlannerService with a standard resolver chain that includes:
* 1. ICAOResolver - for resolving 4-letter ICAO airport codes (tried first)
* 2. CoordinateResolver - for resolving WP(lat,lng) coordinate waypoints
* 3. Any custom resolvers provided (tried last)
*
* @param aerodromeService - The aerodrome service for looking up airports and aerodromes
* @param customResolvers - Optional array of custom waypoint resolvers that will be tried after the default resolvers
* @returns A configured PlannerService instance with the resolver chain
*
* @remarks
* Custom resolvers are placed at the end of the resolver chain, allowing you to extend
* the default behavior with additional formats. For example, you could add resolvers for
* IATA codes, VOR/NDB navaids, or IFR waypoints that would handle formats not recognized
* by the default resolvers.
*
* @example
* ```typescript
* const planner = createDefaultPlannerService(aerodromeService);
* // Creates a planner with ICAO and coordinate resolvers
* ```
*
* @example
* ```typescript
* const planner = createDefaultPlannerService(
* aerodromeService,
* [new IATAResolver(), new VORResolver()]
* );
* // Creates a planner that tries ICAO first, then coordinates, then custom resolvers
* ```
*/
export declare function createDefaultPlannerService(aerodromeService: ServiceBase<Aerodrome>, options?: {
navaidService?: ServiceBase<Aerodrome>;
customResolvers?: WaypointResolver[];
}): PlannerService;