metar-taf-parser 4.0.1 → 5.0.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 +7 -8
- package/locale/en.js +1 -1
- package/metar-taf-parser.d.ts +30 -13
- package/metar-taf-parser.js +35 -16
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -39,9 +39,8 @@ const metar = parseMetar(rawMetarString);
|
|
|
39
39
|
|
|
40
40
|
// -or-
|
|
41
41
|
|
|
42
|
-
// Optionally pass
|
|
43
|
-
|
|
44
|
-
const datedMetar = parseMetar(rawMetarString, { date: new Date() });
|
|
42
|
+
// Optionally pass the date issued to add it to the report
|
|
43
|
+
const datedMetar = parseMetar(rawMetarString, { issued });
|
|
45
44
|
```
|
|
46
45
|
|
|
47
46
|
#### `parseTAF`
|
|
@@ -55,9 +54,9 @@ const taf = parseTAF(rawTAFString);
|
|
|
55
54
|
|
|
56
55
|
// -or-
|
|
57
56
|
|
|
58
|
-
// Optionally pass
|
|
59
|
-
//
|
|
60
|
-
const datedTAF = parseTAF(rawTAFString, {
|
|
57
|
+
// Optionally pass the date issued to get the report issued and
|
|
58
|
+
// trend validity dates (start/end) on the report:
|
|
59
|
+
const datedTAF = parseTAF(rawTAFString, { issued });
|
|
61
60
|
```
|
|
62
61
|
|
|
63
62
|
### Higher level parsing: The Forecast abstraction
|
|
@@ -72,7 +71,7 @@ Returns a more normalized TAF report. Most notably: while the `parseTAF` functio
|
|
|
72
71
|
import { parseTAFAsForecast } from "metar-taf-parser";
|
|
73
72
|
|
|
74
73
|
// You must provide an issued date to use the Forecast abstraction
|
|
75
|
-
const report = parseTAFAsForecast(rawTAFString, {
|
|
74
|
+
const report = parseTAFAsForecast(rawTAFString, { issued: tafIssuedDate });
|
|
76
75
|
|
|
77
76
|
console.log(report.forecast);
|
|
78
77
|
```
|
|
@@ -98,7 +97,7 @@ import {
|
|
|
98
97
|
getCompositeForecastForDate,
|
|
99
98
|
} from "metar-taf-parser";
|
|
100
99
|
|
|
101
|
-
const report = parseTAFAsForecast(rawTAFString, {
|
|
100
|
+
const report = parseTAFAsForecast(rawTAFString, { issued: tafIssuedDate });
|
|
102
101
|
|
|
103
102
|
const forecastPerHour = eachHourOfInterval({
|
|
104
103
|
start: report.start,
|
package/locale/en.js
CHANGED
|
@@ -207,7 +207,7 @@ var en = {
|
|
|
207
207
|
Hourly: "{0}/100 of an inch of precipitation fell in the last hour",
|
|
208
208
|
},
|
|
209
209
|
Beg: {
|
|
210
|
-
"0": "{0} {1} beginning at {2}:{3}
|
|
210
|
+
"0": "{0} {1} beginning at {2}:{3}",
|
|
211
211
|
End: "{0} {1} beginning at {2}:{3} ending at {4}:{5}",
|
|
212
212
|
},
|
|
213
213
|
End: "{0} {1} ending at {2}:{3}",
|
package/metar-taf-parser.d.ts
CHANGED
|
@@ -1101,7 +1101,29 @@ interface ICloud {
|
|
|
1101
1101
|
quantity: CloudQuantity;
|
|
1102
1102
|
type?: CloudType;
|
|
1103
1103
|
}
|
|
1104
|
-
interface
|
|
1104
|
+
interface IFlags {
|
|
1105
|
+
/**
|
|
1106
|
+
* Amended TAF
|
|
1107
|
+
*/
|
|
1108
|
+
amendment?: true;
|
|
1109
|
+
/**
|
|
1110
|
+
* Amended METAR
|
|
1111
|
+
*/
|
|
1112
|
+
auto?: true;
|
|
1113
|
+
/**
|
|
1114
|
+
* Canceled TAF
|
|
1115
|
+
*/
|
|
1116
|
+
canceled?: true;
|
|
1117
|
+
/**
|
|
1118
|
+
* Corrected METAR/TAF
|
|
1119
|
+
*/
|
|
1120
|
+
corrected?: true;
|
|
1121
|
+
/**
|
|
1122
|
+
* No data
|
|
1123
|
+
*/
|
|
1124
|
+
nil?: true;
|
|
1125
|
+
}
|
|
1126
|
+
interface IAbstractWeatherContainer extends IFlags {
|
|
1105
1127
|
wind?: IWind;
|
|
1106
1128
|
visibility?: Visibility;
|
|
1107
1129
|
verticalVisibility?: number;
|
|
@@ -1120,11 +1142,11 @@ interface IAbstractValidity {
|
|
|
1120
1142
|
* Exclusive for the TS port (because python has `time()` and js does not)
|
|
1121
1143
|
*/
|
|
1122
1144
|
interface ITime {
|
|
1123
|
-
hour
|
|
1124
|
-
minute
|
|
1145
|
+
hour?: number;
|
|
1146
|
+
minute?: number;
|
|
1125
1147
|
}
|
|
1126
1148
|
interface IAbstractWeatherCode extends IAbstractWeatherContainer, ITime {
|
|
1127
|
-
day
|
|
1149
|
+
day?: number;
|
|
1128
1150
|
airport?: IAirport;
|
|
1129
1151
|
message: string;
|
|
1130
1152
|
station: string;
|
|
@@ -1138,7 +1160,6 @@ interface IMetar extends IAbstractWeatherCode {
|
|
|
1138
1160
|
dewPoint?: number;
|
|
1139
1161
|
altimeter?: number;
|
|
1140
1162
|
nosig?: true;
|
|
1141
|
-
auto?: true;
|
|
1142
1163
|
runwaysInfo: IRunwayInfo[];
|
|
1143
1164
|
/**
|
|
1144
1165
|
* Not used in North America
|
|
@@ -1149,7 +1170,6 @@ interface ITAF extends IAbstractWeatherCode {
|
|
|
1149
1170
|
validity: IValidity;
|
|
1150
1171
|
maxTemperature?: ITemperatureDated;
|
|
1151
1172
|
minTemperature?: ITemperatureDated;
|
|
1152
|
-
amendment?: true;
|
|
1153
1173
|
trends: TAFTrend[];
|
|
1154
1174
|
}
|
|
1155
1175
|
interface IAbstractTrend extends IAbstractWeatherContainer {
|
|
@@ -1306,15 +1326,12 @@ interface IMetarTAFParserOptions {
|
|
|
1306
1326
|
}
|
|
1307
1327
|
interface IMetarTAFParserOptionsDated extends IMetarTAFParserOptions {
|
|
1308
1328
|
/**
|
|
1309
|
-
* This date should
|
|
1310
|
-
* can be be +/- one week of the actual report date and work properly.
|
|
1311
|
-
*
|
|
1312
|
-
* So if you know the report was recently issued, you can pass `new Date()`
|
|
1329
|
+
* This date should be the date the report was issued.
|
|
1313
1330
|
*
|
|
1314
1331
|
* This date is needed to create actual timestamps since the report only has
|
|
1315
|
-
* day of month, hour, and minute.
|
|
1332
|
+
* day of month, hour, and minute (and sometimes not even that).
|
|
1316
1333
|
*/
|
|
1317
|
-
|
|
1334
|
+
issued: Date;
|
|
1318
1335
|
}
|
|
1319
1336
|
declare function parseMetar(rawMetar: string, options?: IMetarTAFParserOptions): IMetar;
|
|
1320
1337
|
declare function parseMetar(rawMetar: string, options?: IMetarTAFParserOptionsDated): IMetarDated;
|
|
@@ -1322,4 +1339,4 @@ declare function parseTAF(rawTAF: string, options?: IMetarTAFParserOptions): ITA
|
|
|
1322
1339
|
declare function parseTAF(rawTAF: string, options?: IMetarTAFParserOptionsDated): ITAFDated;
|
|
1323
1340
|
declare function parseTAFAsForecast(rawTAF: string, options: IMetarTAFParserOptionsDated): IForecastContainer;
|
|
1324
1341
|
|
|
1325
|
-
export { CloudQuantity, CloudType, CommandExecutionError, Descriptive, Direction, Distance, DistanceUnit, Forecast, IAbstractTrend, IAbstractValidity, IAbstractWeatherCode, IAbstractWeatherCodeDated, IAbstractWeatherContainer, IAirport, IBaseRemark, IBaseTAFTrend, ICeilingHeightRemark, ICeilingSecondLocationRemark, ICloud, ICompositeForecast, ICountry, IEndValidity, IFMValidity, IForecastContainer, IHourlyMaximumMinimumTemperatureRemark, IHourlyMaximumTemperatureRemark, IHourlyMinimumTemperatureRemark, IHourlyPrecipitationAmountRemark, IHourlyPressureRemark, IHourlyTemperatureDewPointRemark, IIceAccretionRemark, IMetar, IMetarTAFParserOptions, IMetarTAFParserOptionsDated, IMetarTrend, IMetarTrendTime, IObscurationRemark, IPrecipitationAmount24HourRemark, IPrecipitationAmount36HourRemark, IPrecipitationBegEndRemark, IPrevailingVisibilityRemark, IRunwayInfo, ISeaLevelPressureRemark, ISecondLocationVisibilityRemark, ISectorVisibilityRemark, ISmallHailSizeRemark, ISnowIncreaseRemark, ISnowPelletsRemark, ISunshineDurationRemark, ISurfaceVisibilityRemark, ITAF, ITAFDated, ITemperatureDated, IThunderStormLocationMovingRemark, IThunderStormLocationRemark, ITime, ITornadicActivityBegEndRemark, ITornadicActivityBegRemark, ITornadicActivityEndRemark, ITowerVisibilityRemark, IUnknownRemark, IValidity, IValidityDated, IVariableSkyHeightRemark, IVariableSkyRemark, IVirgaDirectionRemark, IWaterEquivalentSnowRemark, IWeatherCondition, IWind, IWindPeakCommandRemark, IWindShear, IWindShiftFropaRemark, Intensity, InvalidWeatherStatementError, Locale, ParseError, Phenomenon, Remark, RemarkType, RunwayInfoTrend, RunwayInfoUnit, TAFTrend, TAFTrendDated, TimeIndicator, TimestampOutOfBoundsError, UnexpectedParseError, ValueIndicator, Visibility, WeatherChangeType, getCompositeForecastForDate, isWeatherConditionValid, parseMetar, parseTAF, parseTAFAsForecast };
|
|
1342
|
+
export { CloudQuantity, CloudType, CommandExecutionError, Descriptive, Direction, Distance, DistanceUnit, Forecast, IAbstractTrend, IAbstractValidity, IAbstractWeatherCode, IAbstractWeatherCodeDated, IAbstractWeatherContainer, IAirport, IBaseRemark, IBaseTAFTrend, ICeilingHeightRemark, ICeilingSecondLocationRemark, ICloud, ICompositeForecast, ICountry, IEndValidity, IFMValidity, IFlags, IForecastContainer, IHourlyMaximumMinimumTemperatureRemark, IHourlyMaximumTemperatureRemark, IHourlyMinimumTemperatureRemark, IHourlyPrecipitationAmountRemark, IHourlyPressureRemark, IHourlyTemperatureDewPointRemark, IIceAccretionRemark, IMetar, IMetarTAFParserOptions, IMetarTAFParserOptionsDated, IMetarTrend, IMetarTrendTime, IObscurationRemark, IPrecipitationAmount24HourRemark, IPrecipitationAmount36HourRemark, IPrecipitationBegEndRemark, IPrevailingVisibilityRemark, IRunwayInfo, ISeaLevelPressureRemark, ISecondLocationVisibilityRemark, ISectorVisibilityRemark, ISmallHailSizeRemark, ISnowIncreaseRemark, ISnowPelletsRemark, ISunshineDurationRemark, ISurfaceVisibilityRemark, ITAF, ITAFDated, ITemperatureDated, IThunderStormLocationMovingRemark, IThunderStormLocationRemark, ITime, ITornadicActivityBegEndRemark, ITornadicActivityBegRemark, ITornadicActivityEndRemark, ITowerVisibilityRemark, IUnknownRemark, IValidity, IValidityDated, IVariableSkyHeightRemark, IVariableSkyRemark, IVirgaDirectionRemark, IWaterEquivalentSnowRemark, IWeatherCondition, IWind, IWindPeakCommandRemark, IWindShear, IWindShiftFropaRemark, Intensity, InvalidWeatherStatementError, Locale, ParseError, Phenomenon, Remark, RemarkType, RunwayInfoTrend, RunwayInfoUnit, TAFTrend, TAFTrendDated, TimeIndicator, TimestampOutOfBoundsError, UnexpectedParseError, ValueIndicator, Visibility, WeatherChangeType, getCompositeForecastForDate, isWeatherConditionValid, parseMetar, parseTAF, parseTAFAsForecast };
|
package/metar-taf-parser.js
CHANGED
|
@@ -2064,13 +2064,31 @@ function parseDeliveryTime(timeString) {
|
|
|
2064
2064
|
const hour = +timeString.slice(2, 4);
|
|
2065
2065
|
const minute = +timeString.slice(4, 6);
|
|
2066
2066
|
if (isNaN(day) || isNaN(hour) || isNaN(minute))
|
|
2067
|
-
|
|
2067
|
+
return;
|
|
2068
2068
|
return {
|
|
2069
2069
|
day,
|
|
2070
2070
|
hour,
|
|
2071
2071
|
minute,
|
|
2072
2072
|
};
|
|
2073
2073
|
}
|
|
2074
|
+
function parseFlags(abstractWeatherCode, flag) {
|
|
2075
|
+
const flags = findFlags(flag);
|
|
2076
|
+
if (flags)
|
|
2077
|
+
Object.assign(abstractWeatherCode, flags);
|
|
2078
|
+
return !!flags;
|
|
2079
|
+
}
|
|
2080
|
+
var FlagMap;
|
|
2081
|
+
(function (FlagMap) {
|
|
2082
|
+
FlagMap["AMD"] = "amendment";
|
|
2083
|
+
FlagMap["AUTO"] = "auto";
|
|
2084
|
+
FlagMap["CNL"] = "canceled";
|
|
2085
|
+
FlagMap["COR"] = "corrected";
|
|
2086
|
+
FlagMap["NIL"] = "nil";
|
|
2087
|
+
})(FlagMap || (FlagMap = {}));
|
|
2088
|
+
function findFlags(flag) {
|
|
2089
|
+
if (flag in FlagMap)
|
|
2090
|
+
return { [FlagMap[flag]]: true };
|
|
2091
|
+
}
|
|
2074
2092
|
/**
|
|
2075
2093
|
* This function parses the array containing the remark and concat the array into a string
|
|
2076
2094
|
* @param container the metar, taf or taf trend to update
|
|
@@ -2102,7 +2120,7 @@ function parseTemperature(input) {
|
|
|
2102
2120
|
* @param input the string containing the validity
|
|
2103
2121
|
* @returns Validity object
|
|
2104
2122
|
*/
|
|
2105
|
-
function parseValidity(input
|
|
2123
|
+
function parseValidity(input) {
|
|
2106
2124
|
const parts = pySplit(input, "/");
|
|
2107
2125
|
return {
|
|
2108
2126
|
startDay: +parts[0].slice(0, 2),
|
|
@@ -2184,7 +2202,6 @@ class AbstractParser {
|
|
|
2184
2202
|
if (digitRegex.test(splitted[i])) {
|
|
2185
2203
|
if (splitted[i + 1] && smRegex.test(splitted[i + 1])) {
|
|
2186
2204
|
splitted.splice(i, 2, `${splitted[i]} ${splitted[i + 1]}`);
|
|
2187
|
-
i--;
|
|
2188
2205
|
}
|
|
2189
2206
|
}
|
|
2190
2207
|
}
|
|
@@ -2274,13 +2291,11 @@ class MetarParser extends AbstractParser {
|
|
|
2274
2291
|
};
|
|
2275
2292
|
let index = 2;
|
|
2276
2293
|
while (index < metarTab.length) {
|
|
2277
|
-
if (!super.generalParse(metar, metarTab[index])
|
|
2294
|
+
if (!super.generalParse(metar, metarTab[index]) &&
|
|
2295
|
+
!parseFlags(metar, metarTab[index])) {
|
|
2278
2296
|
if (metarTab[index] === "NOSIG") {
|
|
2279
2297
|
metar.nosig = true;
|
|
2280
2298
|
}
|
|
2281
|
-
else if (metarTab[index] === "AUTO") {
|
|
2282
|
-
metar.auto = true;
|
|
2283
|
-
}
|
|
2284
2299
|
else if (metarTab[index] === this.TEMPO ||
|
|
2285
2300
|
metarTab[index] === this.BECMG) {
|
|
2286
2301
|
const trend = {
|
|
@@ -2328,25 +2343,25 @@ class TAFParser extends AbstractParser {
|
|
|
2328
2343
|
* @throws ParseError if the message is invalid
|
|
2329
2344
|
*/
|
|
2330
2345
|
parse(input) {
|
|
2331
|
-
let amendment;
|
|
2332
2346
|
const lines = this.extractLinesTokens(input);
|
|
2333
2347
|
let index = 0;
|
|
2334
2348
|
if (lines[0][0] === this.TAF)
|
|
2335
2349
|
index = 1;
|
|
2336
2350
|
if (lines[0][1] === this.TAF)
|
|
2337
2351
|
index = 2;
|
|
2338
|
-
|
|
2339
|
-
|
|
2352
|
+
const flags = findFlags(lines[0][index]);
|
|
2353
|
+
if (flags) {
|
|
2340
2354
|
index += 1;
|
|
2341
2355
|
}
|
|
2342
2356
|
const station = lines[0][index];
|
|
2343
2357
|
index += 1;
|
|
2344
2358
|
const time = parseDeliveryTime(lines[0][index]);
|
|
2345
|
-
|
|
2359
|
+
if (time)
|
|
2360
|
+
index += 1;
|
|
2346
2361
|
const validity = parseValidity(lines[0][index]);
|
|
2347
2362
|
const taf = {
|
|
2348
2363
|
station,
|
|
2349
|
-
|
|
2364
|
+
...flags,
|
|
2350
2365
|
...time,
|
|
2351
2366
|
validity,
|
|
2352
2367
|
message: input,
|
|
@@ -2365,8 +2380,10 @@ class TAFParser extends AbstractParser {
|
|
|
2365
2380
|
taf.maxTemperature = parseTemperature(token);
|
|
2366
2381
|
else if (token.startsWith(this.TN))
|
|
2367
2382
|
taf.minTemperature = parseTemperature(token);
|
|
2368
|
-
else
|
|
2383
|
+
else {
|
|
2384
|
+
parseFlags(taf, token);
|
|
2369
2385
|
this.generalParse(taf, token);
|
|
2386
|
+
}
|
|
2370
2387
|
}
|
|
2371
2388
|
// Handle the other lines
|
|
2372
2389
|
for (let i = 1; i < lines.length; i++) {
|
|
@@ -2390,7 +2407,6 @@ class TAFParser extends AbstractParser {
|
|
|
2390
2407
|
for (let i = 0; i < ls.length; i++) {
|
|
2391
2408
|
if (/^PROB\d{2}$/.test(ls[i]) && /^TEMPO/.test(ls[i + 1])) {
|
|
2392
2409
|
ls.splice(i, 2, `${ls[i]} ${ls[i + 1]}`);
|
|
2393
|
-
i--;
|
|
2394
2410
|
}
|
|
2395
2411
|
}
|
|
2396
2412
|
return ls;
|
|
@@ -2531,6 +2547,9 @@ _RemarkParser_supplier = new WeakMap();
|
|
|
2531
2547
|
* @returns
|
|
2532
2548
|
*/
|
|
2533
2549
|
function determineReportIssuedDate(date, day, hour, minute) {
|
|
2550
|
+
// Some TAF reports do not include a delivery time
|
|
2551
|
+
if (day == null || hour == null)
|
|
2552
|
+
return date;
|
|
2534
2553
|
const months = [
|
|
2535
2554
|
setDateComponents(addMonthsUTC(date, -1), day, hour, minute),
|
|
2536
2555
|
setDateComponents(new Date(date), day, hour, minute),
|
|
@@ -2690,8 +2709,8 @@ function parse(rawReport, options, parser, datesHydrator) {
|
|
|
2690
2709
|
const lang = options?.locale || en;
|
|
2691
2710
|
try {
|
|
2692
2711
|
const report = new parser(lang).parse(rawReport);
|
|
2693
|
-
if (options && "
|
|
2694
|
-
return datesHydrator(report, options.
|
|
2712
|
+
if (options && "issued" in options) {
|
|
2713
|
+
return datesHydrator(report, options.issued);
|
|
2695
2714
|
}
|
|
2696
2715
|
return report;
|
|
2697
2716
|
}
|