metar-taf-parser 1.2.0 → 2.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.
Files changed (121) hide show
  1. package/README.md +85 -12
  2. package/dist/command/common.js +13 -10
  3. package/dist/command/metar/AltimeterCommand.d.ts +7 -0
  4. package/dist/command/metar/AltimeterCommand.js +26 -0
  5. package/dist/command/metar/AltimeterMercuryCommand.d.ts +7 -0
  6. package/dist/command/metar/AltimeterMercuryCommand.js +51 -0
  7. package/dist/command/metar/RunwayCommand.d.ts +7 -0
  8. package/dist/command/metar/RunwayCommand.js +60 -0
  9. package/dist/command/metar/TemperatureCommand.d.ts +7 -0
  10. package/dist/command/metar/TemperatureCommand.js +51 -0
  11. package/dist/command/metar.d.ts +1 -22
  12. package/dist/command/metar.js +10 -113
  13. package/dist/command/remark/CeilingHeightCommand.d.ts +18 -0
  14. package/dist/command/remark/CeilingHeightCommand.js +40 -0
  15. package/dist/command/remark/CeilingSecondLocationCommand.d.ts +12 -0
  16. package/dist/command/remark/CeilingSecondLocationCommand.js +40 -0
  17. package/dist/command/remark/Command.d.ts +8 -0
  18. package/dist/command/remark/Command.js +9 -0
  19. package/dist/command/remark/DefaultCommand.d.ts +11 -0
  20. package/dist/command/remark/DefaultCommand.js +38 -0
  21. package/dist/command/remark/HailSizeCommand.d.ts +11 -0
  22. package/dist/command/remark/HailSizeCommand.js +37 -0
  23. package/dist/command/remark/HourlyMaximumMinimumTemperatureCommand.d.ts +18 -0
  24. package/dist/command/remark/HourlyMaximumMinimumTemperatureCommand.js +39 -0
  25. package/dist/command/remark/HourlyMaximumTemperatureCommand.d.ts +14 -0
  26. package/dist/command/remark/HourlyMaximumTemperatureCommand.js +38 -0
  27. package/dist/command/remark/HourlyMinimumTemperatureCommand.d.ts +14 -0
  28. package/dist/command/remark/HourlyMinimumTemperatureCommand.js +38 -0
  29. package/dist/command/remark/HourlyPrecipitationAmountCommand.d.ts +14 -0
  30. package/dist/command/remark/HourlyPrecipitationAmountCommand.js +38 -0
  31. package/dist/command/remark/HourlyPressureCommand.d.ts +32 -0
  32. package/dist/command/remark/HourlyPressureCommand.js +40 -0
  33. package/dist/command/remark/HourlyTemperatureDewPointCommand.d.ts +18 -0
  34. package/dist/command/remark/HourlyTemperatureDewPointCommand.js +52 -0
  35. package/dist/command/remark/IceAccretionCommand.d.ts +15 -0
  36. package/dist/command/remark/IceAccretionCommand.js +38 -0
  37. package/dist/command/remark/ObscurationCommand.d.ts +14 -0
  38. package/dist/command/remark/ObscurationCommand.js +44 -0
  39. package/dist/command/remark/PrecipitationAmount24HourCommand.d.ts +14 -0
  40. package/dist/command/remark/PrecipitationAmount24HourCommand.js +39 -0
  41. package/dist/command/remark/PrecipitationAmount36HourCommand.d.ts +15 -0
  42. package/dist/command/remark/PrecipitationAmount36HourCommand.js +41 -0
  43. package/dist/command/remark/PrecipitationBegCommand.d.ts +15 -0
  44. package/dist/command/remark/PrecipitationBegCommand.js +45 -0
  45. package/dist/command/remark/PrecipitationBegEndCommand.d.ts +17 -0
  46. package/dist/command/remark/PrecipitationBegEndCommand.js +46 -0
  47. package/dist/command/remark/PrecipitationEndCommand.d.ts +15 -0
  48. package/dist/command/remark/PrecipitationEndCommand.js +45 -0
  49. package/dist/command/remark/PrevailingVisibilityCommand.d.ts +12 -0
  50. package/dist/command/remark/PrevailingVisibilityCommand.js +40 -0
  51. package/dist/command/remark/SeaLevelPressureCommand.d.ts +11 -0
  52. package/dist/command/remark/SeaLevelPressureCommand.js +39 -0
  53. package/dist/command/remark/SecondLocationVisibilityCommand.d.ts +12 -0
  54. package/dist/command/remark/SecondLocationVisibilityCommand.js +40 -0
  55. package/dist/command/remark/SectorVisibilityCommand.d.ts +13 -0
  56. package/dist/command/remark/SectorVisibilityCommand.js +41 -0
  57. package/dist/command/remark/SmallHailSizeCommand.d.ts +11 -0
  58. package/dist/command/remark/SmallHailSizeCommand.js +37 -0
  59. package/dist/command/remark/SnowDepthCommand.d.ts +11 -0
  60. package/dist/command/remark/SnowDepthCommand.js +38 -0
  61. package/dist/command/remark/SnowIncreaseCommand.d.ts +12 -0
  62. package/dist/command/remark/SnowIncreaseCommand.js +40 -0
  63. package/dist/command/remark/SnowPelletsCommand.d.ts +11 -0
  64. package/dist/command/remark/SnowPelletsCommand.js +37 -0
  65. package/dist/command/remark/SunshineDurationCommand.d.ts +11 -0
  66. package/dist/command/remark/SunshineDurationCommand.js +38 -0
  67. package/dist/command/remark/SurfaceVisibilityCommand.d.ts +11 -0
  68. package/dist/command/remark/SurfaceVisibilityCommand.js +38 -0
  69. package/dist/command/remark/ThunderStormLocationCommand.d.ts +12 -0
  70. package/dist/command/remark/ThunderStormLocationCommand.js +40 -0
  71. package/dist/command/remark/ThunderStormLocationMovingCommand.d.ts +19 -0
  72. package/dist/command/remark/ThunderStormLocationMovingCommand.js +42 -0
  73. package/dist/command/remark/TornadicActivityBegCommand.d.ts +16 -0
  74. package/dist/command/remark/TornadicActivityBegCommand.js +44 -0
  75. package/dist/command/remark/TornadicActivityBegEndCommand.d.ts +18 -0
  76. package/dist/command/remark/TornadicActivityBegEndCommand.js +46 -0
  77. package/dist/command/remark/TornadicActivityEndCommand.d.ts +16 -0
  78. package/dist/command/remark/TornadicActivityEndCommand.js +44 -0
  79. package/dist/command/remark/TowerVisibilityCommand.d.ts +11 -0
  80. package/dist/command/remark/TowerVisibilityCommand.js +38 -0
  81. package/dist/command/remark/VariableSkyCommand.d.ts +12 -0
  82. package/dist/command/remark/VariableSkyCommand.js +41 -0
  83. package/dist/command/remark/VariableSkyHeightCommand.d.ts +13 -0
  84. package/dist/command/remark/VariableSkyHeightCommand.js +43 -0
  85. package/dist/command/remark/VirgaDirectionCommand.d.ts +12 -0
  86. package/dist/command/remark/VirgaDirectionCommand.js +40 -0
  87. package/dist/command/remark/WaterEquivalentSnowCommand.d.ts +11 -0
  88. package/dist/command/remark/WaterEquivalentSnowCommand.js +38 -0
  89. package/dist/command/remark/WindPeakCommandCommand.d.ts +17 -0
  90. package/dist/command/remark/WindPeakCommandCommand.js +42 -0
  91. package/dist/command/remark/WindShiftCommand.d.ts +12 -0
  92. package/dist/command/remark/WindShiftCommand.js +38 -0
  93. package/dist/command/remark/WindShiftFropaCommand.d.ts +12 -0
  94. package/dist/command/remark/WindShiftFropaCommand.js +38 -0
  95. package/dist/command/remark.d.ts +100 -194
  96. package/dist/command/remark.js +135 -753
  97. package/dist/commons/converter.d.ts +14 -2
  98. package/dist/commons/converter.js +53 -5
  99. package/dist/commons/errors.d.ts +6 -2
  100. package/dist/commons/errors.js +15 -8
  101. package/dist/commons/i18n.d.ts +2 -2
  102. package/dist/commons/i18n.js +9 -3
  103. package/dist/dates/metar.d.ts +5 -0
  104. package/dist/dates/metar.js +8 -0
  105. package/dist/dates/taf.d.ts +28 -0
  106. package/dist/dates/taf.js +17 -0
  107. package/dist/forecast/forecast.d.ts +36 -0
  108. package/dist/forecast/forecast.js +73 -0
  109. package/dist/helpers/date.d.ts +11 -0
  110. package/dist/helpers/date.js +56 -0
  111. package/dist/helpers/helpers.d.ts +7 -0
  112. package/dist/helpers/helpers.js +14 -1
  113. package/dist/index.d.ts +23 -2
  114. package/dist/index.js +24 -7
  115. package/dist/model/enum.d.ts +44 -0
  116. package/dist/model/enum.js +50 -1
  117. package/dist/model/model.d.ts +84 -19
  118. package/dist/model/model.js +3 -1
  119. package/dist/parser/parser.d.ts +13 -6
  120. package/dist/parser/parser.js +63 -29
  121. package/package.json +3 -3
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.WeatherChangeType = exports.TimeIndicator = exports.Phenomenon = exports.Descriptive = exports.Intensity = exports.CloudType = exports.CloudQuantity = void 0;
3
+ exports.RunwayInfoUnit = exports.RunwayInfoTrend = exports.ValueIndicator = exports.DistanceUnit = exports.Direction = exports.WeatherChangeType = exports.TimeIndicator = exports.Phenomenon = exports.Descriptive = exports.Intensity = exports.CloudType = exports.CloudQuantity = void 0;
4
4
  var CloudQuantity;
5
5
  (function (CloudQuantity) {
6
6
  /**
@@ -119,6 +119,7 @@ var Phenomenon;
119
119
  Phenomenon["SPRAY"] = "PY";
120
120
  Phenomenon["SQUALL"] = "SQ";
121
121
  Phenomenon["SAND_WHIRLS"] = "PO";
122
+ Phenomenon["THUNDERSTORM"] = "TS";
122
123
  Phenomenon["DUSTSTORM"] = "DS";
123
124
  Phenomenon["SANDSTORM"] = "SS";
124
125
  Phenomenon["FUNNEL_CLOUD"] = "FC";
@@ -229,3 +230,51 @@ var WeatherChangeType;
229
230
  */
230
231
  WeatherChangeType["PROB"] = "PROB";
231
232
  })(WeatherChangeType = exports.WeatherChangeType || (exports.WeatherChangeType = {}));
233
+ var Direction;
234
+ (function (Direction) {
235
+ Direction["E"] = "E";
236
+ Direction["ENE"] = "ENE";
237
+ Direction["ESE"] = "ESE";
238
+ Direction["N"] = "N";
239
+ Direction["NE"] = "NE";
240
+ Direction["NNE"] = "NNE";
241
+ Direction["NNW"] = "NNW";
242
+ Direction["NW"] = "NW";
243
+ Direction["S"] = "S";
244
+ Direction["SE"] = "SE";
245
+ Direction["SSE"] = "SSE";
246
+ Direction["SSW"] = "SSW";
247
+ Direction["SW"] = "SW";
248
+ Direction["W"] = "W";
249
+ Direction["WNW"] = "WNW";
250
+ Direction["WSW"] = "WSW";
251
+ })(Direction = exports.Direction || (exports.Direction = {}));
252
+ var DistanceUnit;
253
+ (function (DistanceUnit) {
254
+ DistanceUnit["Meters"] = "m";
255
+ DistanceUnit["StatuteMiles"] = "SM";
256
+ })(DistanceUnit = exports.DistanceUnit || (exports.DistanceUnit = {}));
257
+ /**
258
+ * Used to indicate the actual value is greater than or less than the value written
259
+ *
260
+ * For example,
261
+ *
262
+ * 1. `P6SM` = visibility greater than 6 statute miles
263
+ * 2. `M1/4SM` = visibility less than 1/4 statute mile
264
+ */
265
+ var ValueIndicator;
266
+ (function (ValueIndicator) {
267
+ ValueIndicator["GreaterThan"] = "P";
268
+ ValueIndicator["LessThan"] = "M";
269
+ })(ValueIndicator = exports.ValueIndicator || (exports.ValueIndicator = {}));
270
+ var RunwayInfoTrend;
271
+ (function (RunwayInfoTrend) {
272
+ RunwayInfoTrend["Uprising"] = "U";
273
+ RunwayInfoTrend["Decreasing"] = "D";
274
+ RunwayInfoTrend["NoSignificantChange"] = "N";
275
+ })(RunwayInfoTrend = exports.RunwayInfoTrend || (exports.RunwayInfoTrend = {}));
276
+ var RunwayInfoUnit;
277
+ (function (RunwayInfoUnit) {
278
+ RunwayInfoUnit["Feet"] = "FT";
279
+ RunwayInfoUnit["Meters"] = "m";
280
+ })(RunwayInfoUnit = exports.RunwayInfoUnit || (exports.RunwayInfoUnit = {}));
@@ -1,4 +1,5 @@
1
- import { CloudQuantity, CloudType, Descriptive, Phenomenon, TimeIndicator, WeatherChangeType } from "../model/enum";
1
+ import { CloudQuantity, CloudType, Descriptive, ValueIndicator, Phenomenon, TimeIndicator, WeatherChangeType, DistanceUnit, RunwayInfoTrend, RunwayInfoUnit, Intensity } from "../model/enum";
2
+ import { Remark } from "../command/remark";
2
3
  export interface ICountry {
3
4
  name: string;
4
5
  }
@@ -27,13 +28,25 @@ export interface IWind {
27
28
  export interface IWindShear extends IWind {
28
29
  height: number;
29
30
  }
30
- export interface Visibility {
31
- distance: string;
32
- minDistance?: number;
33
- minDirection?: string;
34
- }
31
+ export interface Distance {
32
+ indicator?: ValueIndicator;
33
+ value: number;
34
+ unit: DistanceUnit;
35
+ /** No Directional Visibility */
36
+ ndv?: true;
37
+ }
38
+ export declare type Visibility = Distance & {
39
+ /**
40
+ * Never in North American METARs
41
+ */
42
+ min?: {
43
+ /** Always in meters */
44
+ value: number;
45
+ direction: string;
46
+ };
47
+ };
35
48
  export interface IWeatherCondition {
36
- intensity?: string;
49
+ intensity?: Intensity;
37
50
  descriptive?: Descriptive;
38
51
  phenomenons: Phenomenon[];
39
52
  }
@@ -47,7 +60,15 @@ export interface IRunwayInfo {
47
60
  name: string;
48
61
  minRange: number;
49
62
  maxRange?: number;
50
- trend: unknown;
63
+ /**
64
+ * Only used in North American runway ranges (feet unit of measurement)
65
+ */
66
+ indicator?: ValueIndicator;
67
+ /**
68
+ * Only used in IACO runway ranges (meters unit of measurement)
69
+ */
70
+ trend?: RunwayInfoTrend;
71
+ unit: RunwayInfoUnit;
51
72
  }
52
73
  export interface ICloud {
53
74
  height?: number;
@@ -59,9 +80,9 @@ export interface IAbstractWeatherContainer {
59
80
  visibility?: Visibility;
60
81
  verticalVisibility?: number;
61
82
  windShear?: IWindShear;
62
- cavok?: boolean;
83
+ cavok?: true;
63
84
  remark?: string;
64
- remarks: string[];
85
+ remarks: Remark[];
65
86
  clouds: ICloud[];
66
87
  weatherConditions: IWeatherCondition[];
67
88
  }
@@ -83,21 +104,27 @@ export interface IAbstractWeatherCode extends IAbstractWeatherContainer, ITime {
83
104
  station: string;
84
105
  trends: IAbstractTrend[];
85
106
  }
107
+ export interface IAbstractWeatherCodeDated extends IAbstractWeatherCode {
108
+ issued: Date;
109
+ }
86
110
  export interface IMetar extends IAbstractWeatherCode {
87
111
  temperature?: number;
88
112
  dewPoint?: number;
89
113
  altimeter?: number;
90
- nosig?: boolean;
91
- auto?: boolean;
114
+ nosig?: true;
115
+ auto?: true;
92
116
  runwaysInfo: IRunwayInfo[];
117
+ /**
118
+ * Not used in North America
119
+ */
93
120
  trends: IMetarTrend[];
94
121
  }
95
122
  export interface ITAF extends IAbstractWeatherCode {
96
123
  validity: IValidity;
97
124
  maxTemperature?: ITemperatureDated;
98
125
  minTemperature?: ITemperatureDated;
99
- amendment?: boolean;
100
- trends: ITAFTrend[];
126
+ amendment?: true;
127
+ trends: TAFTrend[];
101
128
  }
102
129
  export interface IAbstractTrend extends IAbstractWeatherContainer {
103
130
  type: WeatherChangeType;
@@ -108,16 +135,54 @@ export interface IMetarTrendTime extends ITime {
108
135
  export interface IMetarTrend extends IAbstractTrend {
109
136
  times: IMetarTrendTime[];
110
137
  }
111
- export interface ITAFTrend extends IAbstractTrend {
138
+ export interface IBaseTAFTrend extends IAbstractTrend {
139
+ /**
140
+ * Will not be found on FM trends. May exist on others.
141
+ *
142
+ * If does not exist, probability is > 40%
143
+ */
112
144
  probability?: number;
113
- validity?: IFMValidity;
114
- }
145
+ /**
146
+ * All trends have `startDay` and `startHour` defined. Additionally:
147
+ *
148
+ * - FM trends also have `startMinutes`. They **DO NOT** have an explicit end
149
+ * validity (it is implied by the following FM).
150
+ * - All others (PROB, TEMPO, BECMG) have `endDay` and `endHour`.
151
+ *
152
+ * All properties are allowed to be accessed (as optionals), but if you want
153
+ * type guarantees, you can check the trend type. For example:
154
+ *
155
+ * ```ts
156
+ * switch (trend.type) {
157
+ * case WeatherChangeType.FM:
158
+ * // trend.validity now has startMinutes defined
159
+ * break;
160
+ * case WeatherChangeType.PROB:
161
+ * case WeatherChangeType.BECMG:
162
+ * case WeatherChangeType.TEMPO:
163
+ * // trend.validity now has endHour, endDay defined
164
+ * }
165
+ * ```
166
+ */
167
+ validity: IAbstractValidity & Partial<IFMValidity> & Partial<IValidity>;
168
+ }
169
+ export declare type TAFTrend = IBaseTAFTrend & ({
170
+ type: WeatherChangeType.FM;
171
+ validity: IFMValidity;
172
+ } | {
173
+ type: WeatherChangeType;
174
+ validity: IValidity;
175
+ });
115
176
  export interface IEndValidity {
116
177
  endHour: number;
117
178
  endDay: number;
118
179
  }
119
180
  export interface IValidity extends IAbstractValidity, IEndValidity {
120
181
  }
121
- export interface IFMValidity extends IAbstractValidity, Partial<IEndValidity> {
122
- startMinutes?: number;
182
+ export interface IValidityDated extends IAbstractValidity, IEndValidity {
183
+ start: Date;
184
+ end: Date;
185
+ }
186
+ export interface IFMValidity extends IAbstractValidity {
187
+ startMinutes: number;
123
188
  }
@@ -4,6 +4,8 @@ exports.isWeatherConditionValid = void 0;
4
4
  const enum_1 = require("../model/enum");
5
5
  function isWeatherConditionValid(weather) {
6
6
  return (weather.phenomenons.length !== 0 ||
7
- weather.descriptive == enum_1.Descriptive.THUNDERSTORM);
7
+ weather.descriptive == enum_1.Descriptive.THUNDERSTORM ||
8
+ (weather.intensity === enum_1.Intensity.IN_VICINITY &&
9
+ weather.descriptive == enum_1.Descriptive.SHOWERS));
8
10
  }
9
11
  exports.isWeatherConditionValid = isWeatherConditionValid;
@@ -1,5 +1,5 @@
1
- import { IAbstractWeatherContainer, IMetar, IMetarTrend, ITAF, ITAFTrend, ITemperatureDated, IValidity, IWeatherCondition } from "../model/model";
2
- import { WeatherChangeType } from "../model/enum";
1
+ import { Remark } from "../command/remark";
2
+ import { IAbstractWeatherContainer, IMetar, IMetarTrend, ITAF, TAFTrend, ITemperatureDated, IValidity, IWeatherCondition, IValidityDated } from "../model/model";
3
3
  import { Locale } from "../commons/i18n";
4
4
  /**
5
5
  * Parses the temperature in a TAF
@@ -12,7 +12,7 @@ export declare function parseTemperature(input: string): ITemperatureDated;
12
12
  * @param input the string containing the validity
13
13
  * @returns Validity object
14
14
  */
15
- export declare function parseValidity(input: string): IValidity;
15
+ export declare function parseValidity(input: string, date?: Date): IValidityDated | IValidity;
16
16
  /**
17
17
  * Abstract class.
18
18
  * Base parser.
@@ -87,18 +87,25 @@ export declare class TAFParser extends AbstractParser {
87
87
  * @param lineTokens the array of tokens representing a line
88
88
  */
89
89
  parseLine(taf: ITAF, lineTokens: string[]): void;
90
+ /**
91
+ * Finds a non-FM validity in a line
92
+ * @param index the index at which the array should be parsed
93
+ * @param line The array of string containing the line
94
+ * @param trend The trend object to update
95
+ */
96
+ findLineValidity(index: number, line: string[]): IValidity | undefined;
90
97
  /**
91
98
  * Parses a trend of the TAF
92
99
  * @param index the index at which the array should be parsed
93
100
  * @param line The array of string containing the line
94
101
  * @param trend The trend object to update
95
102
  */
96
- parseTrend(index: number, line: string[], trend: ITAFTrend): void;
97
- makeEmptyTAFTrend(type: WeatherChangeType): ITAFTrend;
103
+ parseTrend(index: number, line: string[], trend: TAFTrend): void;
104
+ makeEmptyTAFTrend(): Omit<TAFTrend, "type" | "validity">;
98
105
  }
99
106
  export declare class RemarkParser {
100
107
  #private;
101
108
  private locale;
102
109
  constructor(locale: Locale);
103
- parse(code: string): string[];
110
+ parse(code: string): Remark[];
104
111
  }
@@ -32,10 +32,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
32
32
  exports.RemarkParser = exports.TAFParser = exports.MetarParser = exports.AbstractParser = exports.parseValidity = exports.parseTemperature = void 0;
33
33
  const remark_1 = require("../command/remark");
34
34
  const model_1 = require("../model/model");
35
+ const enum_1 = require("../model/enum");
35
36
  const converter = __importStar(require("../commons/converter"));
36
37
  const helpers_1 = require("../helpers/helpers");
37
38
  const common_1 = require("../command/common");
38
- const enum_1 = require("../model/enum");
39
+ const enum_2 = require("../model/enum");
39
40
  const metar_1 = require("../command/metar");
40
41
  const errors_1 = require("../commons/errors");
41
42
  /**
@@ -44,10 +45,15 @@ const errors_1 = require("../commons/errors");
44
45
  * @param timeString The string representing the delivery time
45
46
  */
46
47
  function parseDeliveryTime(timeString) {
48
+ const day = +timeString.slice(0, 2);
49
+ const hour = +timeString.slice(2, 4);
50
+ const minute = +timeString.slice(4, 6);
51
+ if (isNaN(day) || isNaN(hour) || isNaN(minute))
52
+ throw new errors_1.InvalidWeatherStatementError("Report time is invalid");
47
53
  return {
48
- day: +timeString.slice(0, 2),
49
- hour: +timeString.slice(2, 4),
50
- minute: +timeString.slice(4, 6),
54
+ day,
55
+ hour,
56
+ minute,
51
57
  };
52
58
  }
53
59
  /**
@@ -59,7 +65,9 @@ function parseDeliveryTime(timeString) {
59
65
  function parseRemark(container, line, index, locale) {
60
66
  const remarks = new RemarkParser(locale).parse(line.slice(index + 1).join(" "));
61
67
  container.remarks = remarks;
62
- container.remark = remarks.join(" ");
68
+ container.remark = remarks
69
+ .map(({ description, raw }) => description || raw)
70
+ .join(" ");
63
71
  }
64
72
  /**
65
73
  * Parses the temperature in a TAF
@@ -80,7 +88,7 @@ exports.parseTemperature = parseTemperature;
80
88
  * @param input the string containing the validity
81
89
  * @returns Validity object
82
90
  */
83
- function parseValidity(input) {
91
+ function parseValidity(input, date) {
84
92
  const parts = (0, helpers_1.pySplit)(input, "/");
85
93
  return {
86
94
  startDay: +parts[0].slice(0, 2),
@@ -128,7 +136,7 @@ class AbstractParser {
128
136
  intensity = match;
129
137
  }
130
138
  let descriptive;
131
- for (const key of Object.values(enum_1.Descriptive)) {
139
+ for (const key of Object.values(enum_2.Descriptive)) {
132
140
  if (input.includes(key))
133
141
  descriptive = key;
134
142
  }
@@ -137,7 +145,10 @@ class AbstractParser {
137
145
  descriptive,
138
146
  phenomenons: [],
139
147
  };
140
- for (const key of Object.values(enum_1.Phenomenon)) {
148
+ for (const key of Object.values(enum_2.Phenomenon)) {
149
+ // Thunderstorm as descriptive should not be added as a phenomenon
150
+ if (descriptive === key)
151
+ continue;
141
152
  if (input.includes(key))
142
153
  weatherCondition.phenomenons.push(key);
143
154
  }
@@ -154,7 +165,7 @@ class AbstractParser {
154
165
  // Hack for safari below...
155
166
  const splitRegex = /\s|=/;
156
167
  const smRegex = /^\d\/\dSM$/;
157
- const digitRegex = /^\d$/;
168
+ const digitRegex = /^(P|M)?\d$/;
158
169
  // return input.split(this.#TOKENIZE_REGEX).filter((v) => v);
159
170
  const splitted = input.split(splitRegex);
160
171
  for (let i = 0; i < splitted.length; i++) {
@@ -176,12 +187,11 @@ class AbstractParser {
176
187
  generalParse(abstractWeatherContainer, input) {
177
188
  if (input === __classPrivateFieldGet(this, _AbstractParser_CAVOK, "f")) {
178
189
  abstractWeatherContainer.cavok = true;
179
- const distance = "> 10km";
180
- if (!abstractWeatherContainer.visibility)
181
- abstractWeatherContainer.visibility = {
182
- distance,
183
- };
184
- abstractWeatherContainer.visibility.distance = distance;
190
+ abstractWeatherContainer.visibility = {
191
+ indicator: enum_1.ValueIndicator.GreaterThan,
192
+ value: 9999,
193
+ unit: enum_1.DistanceUnit.Meters,
194
+ };
185
195
  return true;
186
196
  }
187
197
  const command = __classPrivateFieldGet(this, _AbstractParser_commonSupplier, "f").get(input);
@@ -221,7 +231,7 @@ class MetarParser extends AbstractParser {
221
231
  trendParts[i].startsWith(this.TL) ||
222
232
  trendParts[i].startsWith(this.AT)) {
223
233
  const trendTime = {
224
- type: enum_1.TimeIndicator[trendParts[i].slice(0, 2)],
234
+ type: enum_2.TimeIndicator[trendParts[i].slice(0, 2)],
225
235
  hour: +trendParts[i].slice(2, 4),
226
236
  minute: +trendParts[i].slice(4, 6),
227
237
  };
@@ -241,7 +251,7 @@ class MetarParser extends AbstractParser {
241
251
  */
242
252
  parse(input) {
243
253
  const metarTab = this.tokenize(input);
244
- const metar = Object.assign(Object.assign({}, parseDeliveryTime(metarTab[1])), { station: metarTab[0], message: input, remark: "", remarks: [], clouds: [], weatherConditions: [], trends: [], runwaysInfo: [] });
254
+ const metar = Object.assign(Object.assign({}, parseDeliveryTime(metarTab[1])), { station: metarTab[0], message: input, remarks: [], clouds: [], weatherConditions: [], trends: [], runwaysInfo: [] });
245
255
  let index = 2;
246
256
  while (index < metarTab.length) {
247
257
  if (!super.generalParse(metar, metarTab[index])) {
@@ -254,7 +264,7 @@ class MetarParser extends AbstractParser {
254
264
  else if (metarTab[index] === this.TEMPO ||
255
265
  metarTab[index] === this.BECMG) {
256
266
  const trend = {
257
- type: enum_1.WeatherChangeType[metarTab[index]],
267
+ type: enum_2.WeatherChangeType[metarTab[index]],
258
268
  weatherConditions: [],
259
269
  clouds: [],
260
270
  times: [],
@@ -302,7 +312,7 @@ class TAFParser extends AbstractParser {
302
312
  let amendment;
303
313
  const lines = this.extractLinesTokens(input);
304
314
  if (lines[0][0] !== this.TAF)
305
- throw new errors_1.InvalidWeatherStatementError('TAF report must begin with string "TAF"');
315
+ throw new errors_1.InvalidWeatherStatementError('TAF report must begin with "TAF"');
306
316
  let index = 1;
307
317
  if (lines[0][1] === this.TAF)
308
318
  index = 2;
@@ -319,8 +329,10 @@ class TAFParser extends AbstractParser {
319
329
  amendment }, time), { validity, message: input, trends: [], remarks: [], clouds: [], weatherConditions: [] });
320
330
  for (let i = index + 1; i < lines[0].length; i++) {
321
331
  const token = lines[0][i];
322
- if (token == this.RMK)
332
+ if (token == this.RMK) {
323
333
  parseRemark(taf, lines[0], i, this.locale);
334
+ break;
335
+ }
324
336
  else if (token.startsWith(this.TX))
325
337
  taf.maxTemperature = parseTemperature(token);
326
338
  else if (token.startsWith(this.TN))
@@ -375,22 +387,42 @@ class TAFParser extends AbstractParser {
375
387
  let index = 1;
376
388
  let trend;
377
389
  if (lineTokens[0].startsWith(this.FM)) {
378
- trend = Object.assign(Object.assign({}, this.makeEmptyTAFTrend(enum_1.WeatherChangeType.FM)), { validity: parseFromValidity(lineTokens[0]) });
390
+ trend = Object.assign(Object.assign({}, this.makeEmptyTAFTrend()), { type: enum_2.WeatherChangeType.FM, validity: parseFromValidity(lineTokens[0]) });
379
391
  }
380
392
  else if (lineTokens[0].startsWith(this.PROB)) {
381
- trend = this.makeEmptyTAFTrend(enum_1.WeatherChangeType.PROB);
393
+ const validity = this.findLineValidity(index, lineTokens);
394
+ if (!validity)
395
+ return;
396
+ trend = Object.assign(Object.assign({}, this.makeEmptyTAFTrend()), { type: enum_2.WeatherChangeType.PROB, validity });
382
397
  if (lineTokens.length > 1 && lineTokens[1] === this.TEMPO) {
383
- trend = this.makeEmptyTAFTrend(enum_1.WeatherChangeType[lineTokens[1]]);
398
+ trend = Object.assign(Object.assign({}, this.makeEmptyTAFTrend()), { type: enum_2.WeatherChangeType[lineTokens[1]], validity });
384
399
  index = 2;
385
400
  }
386
401
  trend.probability = +lineTokens[0].slice(4);
387
402
  }
388
403
  else {
389
- trend = this.makeEmptyTAFTrend(enum_1.WeatherChangeType[lineTokens[0]]);
404
+ const validity = this.findLineValidity(index, lineTokens);
405
+ if (!validity)
406
+ return;
407
+ trend = Object.assign(Object.assign({}, this.makeEmptyTAFTrend()), { type: enum_2.WeatherChangeType[lineTokens[0]], validity });
390
408
  }
391
409
  this.parseTrend(index, lineTokens, trend);
392
410
  taf.trends.push(trend);
393
411
  }
412
+ /**
413
+ * Finds a non-FM validity in a line
414
+ * @param index the index at which the array should be parsed
415
+ * @param line The array of string containing the line
416
+ * @param trend The trend object to update
417
+ */
418
+ findLineValidity(index, line) {
419
+ let validity;
420
+ for (let i = index; i < line.length; i++) {
421
+ if (__classPrivateFieldGet(this, _TAFParser_validityPattern, "f").test(line[i]))
422
+ validity = parseValidity(line[i]);
423
+ }
424
+ return validity;
425
+ }
394
426
  /**
395
427
  * Parses a trend of the TAF
396
428
  * @param index the index at which the array should be parsed
@@ -399,17 +431,19 @@ class TAFParser extends AbstractParser {
399
431
  */
400
432
  parseTrend(index, line, trend) {
401
433
  for (let i = index; i < line.length; i++) {
402
- if (line[i] === this.RMK)
434
+ if (line[i] === this.RMK) {
403
435
  parseRemark(trend, line, i, this.locale);
436
+ break;
437
+ }
438
+ // already parsed
404
439
  else if (__classPrivateFieldGet(this, _TAFParser_validityPattern, "f").test(line[i]))
405
- trend.validity = parseValidity(line[i]);
440
+ continue;
406
441
  else
407
442
  super.generalParse(trend, line[i]);
408
443
  }
409
444
  }
410
- makeEmptyTAFTrend(type) {
445
+ makeEmptyTAFTrend() {
411
446
  return {
412
- type,
413
447
  remarks: [],
414
448
  clouds: [],
415
449
  weatherConditions: [],
@@ -431,7 +465,7 @@ class RemarkParser {
431
465
  [rmkStr, rmkList] = __classPrivateFieldGet(this, _RemarkParser_supplier, "f").get(rmkStr).execute(rmkStr, rmkList);
432
466
  }
433
467
  catch (e) {
434
- if (e instanceof errors_1.TranslationError) {
468
+ if (e instanceof errors_1.CommandExecutionError) {
435
469
  [rmkStr, rmkList] = __classPrivateFieldGet(this, _RemarkParser_supplier, "f").defaultCommand.execute(rmkStr, rmkList);
436
470
  }
437
471
  else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "metar-taf-parser",
3
- "version": "1.2.0",
3
+ "version": "2.0.0",
4
4
  "description": "Parse METAR and TAF reports",
5
5
  "homepage": "https://aeharding.github.io/metar-taf-parser",
6
6
  "keywords": [
@@ -21,7 +21,7 @@
21
21
  "url": "https://github.com/aeharding/metar-taf-parser.git"
22
22
  },
23
23
  "scripts": {
24
- "build": "yarn clean; tsc --project tsconfig.build.json && tsc-alias",
24
+ "build": "tsc --project tsconfig.build.json && tsc-alias",
25
25
  "clean": "rm -rf ./dist",
26
26
  "start": "node --experimental-specifier-resolution=node --loader ts-node/esm lib",
27
27
  "check-types": "tsc --noEmit",
@@ -29,7 +29,7 @@
29
29
  "watch": "watch 'yarn build' src",
30
30
  "test": "jest --coverage",
31
31
  "test-watch": "jest --watch --coverage",
32
- "prepublishOnly": "yarn build"
32
+ "prepublishOnly": "yarn clean && yarn build"
33
33
  },
34
34
  "files": [
35
35
  "dist",