metar-taf-parser 3.1.2 → 4.0.2

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 (136) hide show
  1. package/README.md +1 -1
  2. package/{dist/locale → locale}/de.d.ts +0 -0
  3. package/{dist/locale → locale}/de.js +3 -3
  4. package/{dist/locale → locale}/en.d.ts +0 -0
  5. package/{dist/locale → locale}/en.js +3 -3
  6. package/{dist/locale → locale}/fr.d.ts +0 -0
  7. package/{dist/locale → locale}/fr.js +3 -3
  8. package/{dist/locale → locale}/it.d.ts +0 -0
  9. package/{dist/locale → locale}/it.js +3 -3
  10. package/{dist/locale → locale}/pl.d.ts +0 -0
  11. package/{dist/locale → locale}/pl.js +3 -3
  12. package/{dist/locale → locale}/zh-CN.d.ts +0 -0
  13. package/{dist/locale → locale}/zh-CN.js +3 -3
  14. package/metar-taf-parser.d.ts +1325 -0
  15. package/metar-taf-parser.js +2703 -0
  16. package/package.json +23 -16
  17. package/dist/command/common.d.ts +0 -54
  18. package/dist/command/common.js +0 -243
  19. package/dist/command/metar/AltimeterCommand.d.ts +0 -7
  20. package/dist/command/metar/AltimeterCommand.js +0 -26
  21. package/dist/command/metar/AltimeterMercuryCommand.d.ts +0 -7
  22. package/dist/command/metar/AltimeterMercuryCommand.js +0 -51
  23. package/dist/command/metar/RunwayCommand.d.ts +0 -7
  24. package/dist/command/metar/RunwayCommand.js +0 -60
  25. package/dist/command/metar/TemperatureCommand.d.ts +0 -7
  26. package/dist/command/metar/TemperatureCommand.js +0 -51
  27. package/dist/command/metar.d.ts +0 -9
  28. package/dist/command/metar.js +0 -31
  29. package/dist/command/remark/CeilingHeightCommand.d.ts +0 -18
  30. package/dist/command/remark/CeilingHeightCommand.js +0 -40
  31. package/dist/command/remark/CeilingSecondLocationCommand.d.ts +0 -12
  32. package/dist/command/remark/CeilingSecondLocationCommand.js +0 -40
  33. package/dist/command/remark/Command.d.ts +0 -8
  34. package/dist/command/remark/Command.js +0 -9
  35. package/dist/command/remark/DefaultCommand.d.ts +0 -11
  36. package/dist/command/remark/DefaultCommand.js +0 -38
  37. package/dist/command/remark/HailSizeCommand.d.ts +0 -11
  38. package/dist/command/remark/HailSizeCommand.js +0 -38
  39. package/dist/command/remark/HourlyMaximumMinimumTemperatureCommand.d.ts +0 -18
  40. package/dist/command/remark/HourlyMaximumMinimumTemperatureCommand.js +0 -39
  41. package/dist/command/remark/HourlyMaximumTemperatureCommand.d.ts +0 -14
  42. package/dist/command/remark/HourlyMaximumTemperatureCommand.js +0 -38
  43. package/dist/command/remark/HourlyMinimumTemperatureCommand.d.ts +0 -14
  44. package/dist/command/remark/HourlyMinimumTemperatureCommand.js +0 -38
  45. package/dist/command/remark/HourlyPrecipitationAmountCommand.d.ts +0 -14
  46. package/dist/command/remark/HourlyPrecipitationAmountCommand.js +0 -38
  47. package/dist/command/remark/HourlyPressureCommand.d.ts +0 -32
  48. package/dist/command/remark/HourlyPressureCommand.js +0 -40
  49. package/dist/command/remark/HourlyTemperatureDewPointCommand.d.ts +0 -18
  50. package/dist/command/remark/HourlyTemperatureDewPointCommand.js +0 -52
  51. package/dist/command/remark/IceAccretionCommand.d.ts +0 -15
  52. package/dist/command/remark/IceAccretionCommand.js +0 -38
  53. package/dist/command/remark/ObscurationCommand.d.ts +0 -14
  54. package/dist/command/remark/ObscurationCommand.js +0 -44
  55. package/dist/command/remark/PrecipitationAmount24HourCommand.d.ts +0 -14
  56. package/dist/command/remark/PrecipitationAmount24HourCommand.js +0 -39
  57. package/dist/command/remark/PrecipitationAmount36HourCommand.d.ts +0 -15
  58. package/dist/command/remark/PrecipitationAmount36HourCommand.js +0 -41
  59. package/dist/command/remark/PrecipitationBegCommand.d.ts +0 -15
  60. package/dist/command/remark/PrecipitationBegCommand.js +0 -45
  61. package/dist/command/remark/PrecipitationBegEndCommand.d.ts +0 -17
  62. package/dist/command/remark/PrecipitationBegEndCommand.js +0 -46
  63. package/dist/command/remark/PrecipitationEndCommand.d.ts +0 -15
  64. package/dist/command/remark/PrecipitationEndCommand.js +0 -45
  65. package/dist/command/remark/PrevailingVisibilityCommand.d.ts +0 -12
  66. package/dist/command/remark/PrevailingVisibilityCommand.js +0 -41
  67. package/dist/command/remark/SeaLevelPressureCommand.d.ts +0 -11
  68. package/dist/command/remark/SeaLevelPressureCommand.js +0 -39
  69. package/dist/command/remark/SecondLocationVisibilityCommand.d.ts +0 -12
  70. package/dist/command/remark/SecondLocationVisibilityCommand.js +0 -41
  71. package/dist/command/remark/SectorVisibilityCommand.d.ts +0 -13
  72. package/dist/command/remark/SectorVisibilityCommand.js +0 -42
  73. package/dist/command/remark/SmallHailSizeCommand.d.ts +0 -11
  74. package/dist/command/remark/SmallHailSizeCommand.js +0 -38
  75. package/dist/command/remark/SnowDepthCommand.d.ts +0 -11
  76. package/dist/command/remark/SnowDepthCommand.js +0 -38
  77. package/dist/command/remark/SnowIncreaseCommand.d.ts +0 -12
  78. package/dist/command/remark/SnowIncreaseCommand.js +0 -40
  79. package/dist/command/remark/SnowPelletsCommand.d.ts +0 -11
  80. package/dist/command/remark/SnowPelletsCommand.js +0 -37
  81. package/dist/command/remark/SunshineDurationCommand.d.ts +0 -11
  82. package/dist/command/remark/SunshineDurationCommand.js +0 -38
  83. package/dist/command/remark/SurfaceVisibilityCommand.d.ts +0 -11
  84. package/dist/command/remark/SurfaceVisibilityCommand.js +0 -39
  85. package/dist/command/remark/ThunderStormLocationCommand.d.ts +0 -12
  86. package/dist/command/remark/ThunderStormLocationCommand.js +0 -40
  87. package/dist/command/remark/ThunderStormLocationMovingCommand.d.ts +0 -19
  88. package/dist/command/remark/ThunderStormLocationMovingCommand.js +0 -42
  89. package/dist/command/remark/TornadicActivityBegCommand.d.ts +0 -16
  90. package/dist/command/remark/TornadicActivityBegCommand.js +0 -44
  91. package/dist/command/remark/TornadicActivityBegEndCommand.d.ts +0 -18
  92. package/dist/command/remark/TornadicActivityBegEndCommand.js +0 -46
  93. package/dist/command/remark/TornadicActivityEndCommand.d.ts +0 -16
  94. package/dist/command/remark/TornadicActivityEndCommand.js +0 -44
  95. package/dist/command/remark/TowerVisibilityCommand.d.ts +0 -11
  96. package/dist/command/remark/TowerVisibilityCommand.js +0 -39
  97. package/dist/command/remark/VariableSkyCommand.d.ts +0 -12
  98. package/dist/command/remark/VariableSkyCommand.js +0 -41
  99. package/dist/command/remark/VariableSkyHeightCommand.d.ts +0 -13
  100. package/dist/command/remark/VariableSkyHeightCommand.js +0 -43
  101. package/dist/command/remark/VirgaDirectionCommand.d.ts +0 -12
  102. package/dist/command/remark/VirgaDirectionCommand.js +0 -40
  103. package/dist/command/remark/WaterEquivalentSnowCommand.d.ts +0 -11
  104. package/dist/command/remark/WaterEquivalentSnowCommand.js +0 -38
  105. package/dist/command/remark/WindPeakCommandCommand.d.ts +0 -17
  106. package/dist/command/remark/WindPeakCommandCommand.js +0 -42
  107. package/dist/command/remark/WindShiftCommand.d.ts +0 -12
  108. package/dist/command/remark/WindShiftCommand.js +0 -38
  109. package/dist/command/remark/WindShiftFropaCommand.d.ts +0 -12
  110. package/dist/command/remark/WindShiftFropaCommand.js +0 -38
  111. package/dist/command/remark.d.ts +0 -109
  112. package/dist/command/remark.js +0 -152
  113. package/dist/commons/converter.d.ts +0 -21
  114. package/dist/commons/converter.js +0 -108
  115. package/dist/commons/errors.d.ts +0 -24
  116. package/dist/commons/errors.js +0 -46
  117. package/dist/commons/i18n.d.ts +0 -12
  118. package/dist/commons/i18n.js +0 -30
  119. package/dist/dates/metar.d.ts +0 -5
  120. package/dist/dates/metar.js +0 -8
  121. package/dist/dates/taf.d.ts +0 -28
  122. package/dist/dates/taf.js +0 -17
  123. package/dist/forecast/forecast.d.ts +0 -36
  124. package/dist/forecast/forecast.js +0 -72
  125. package/dist/helpers/date.d.ts +0 -11
  126. package/dist/helpers/date.js +0 -56
  127. package/dist/helpers/helpers.d.ts +0 -17
  128. package/dist/helpers/helpers.js +0 -46
  129. package/dist/index.d.ts +0 -32
  130. package/dist/index.js +0 -62
  131. package/dist/model/enum.d.ts +0 -265
  132. package/dist/model/enum.js +0 -280
  133. package/dist/model/model.d.ts +0 -188
  134. package/dist/model/model.js +0 -11
  135. package/dist/parser/parser.d.ts +0 -111
  136. package/dist/parser/parser.js +0 -480
@@ -0,0 +1,2703 @@
1
+ import en from './locale/en.js';
2
+
3
+ /******************************************************************************
4
+ Copyright (c) Microsoft Corporation.
5
+
6
+ Permission to use, copy, modify, and/or distribute this software for any
7
+ purpose with or without fee is hereby granted.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
10
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
12
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
14
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15
+ PERFORMANCE OF THIS SOFTWARE.
16
+ ***************************************************************************** */
17
+
18
+ function __classPrivateFieldGet(receiver, state, kind, f) {
19
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
20
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
21
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
22
+ }
23
+
24
+ class ParseError extends Error {
25
+ constructor(message) {
26
+ super(message);
27
+ this.name = "ParseError";
28
+ Object.setPrototypeOf(this, new.target.prototype);
29
+ }
30
+ }
31
+ class InvalidWeatherStatementError extends ParseError {
32
+ constructor(cause) {
33
+ super(typeof cause === "string"
34
+ ? `Invalid weather string: ${cause}`
35
+ : "Invalid weather string");
36
+ this.name = "InvalidWeatherStatementError";
37
+ Object.setPrototypeOf(this, new.target.prototype);
38
+ if (typeof cause !== "string")
39
+ this.cause = cause;
40
+ }
41
+ }
42
+ /**
43
+ * Thrown when command marked as canParse, but couldn't parse when
44
+ * executing (for example, an invalid CloudQuantity)
45
+ */
46
+ class CommandExecutionError extends ParseError {
47
+ constructor(message) {
48
+ super(message);
49
+ this.name = "CommandExecutionError";
50
+ Object.setPrototypeOf(this, new.target.prototype);
51
+ }
52
+ }
53
+ /**
54
+ * Should never occur
55
+ */
56
+ class UnexpectedParseError extends ParseError {
57
+ constructor(message) {
58
+ super(message);
59
+ this.name = "UnexpectedParseError";
60
+ Object.setPrototypeOf(this, new.target.prototype);
61
+ }
62
+ }
63
+
64
+ /**
65
+ * Split behaving similar to Python's implementation
66
+ */
67
+ function pySplit(string, separator, n) {
68
+ let split = string.split(separator);
69
+ // Note: Python implementation will automatically trim empty values if
70
+ // separator is undefined. Since this function is kinda meh, we'll just do it
71
+ // for any spaces (pretty close to their implementation, since a space is the
72
+ // default character to split on)
73
+ //
74
+ // https://docs.python.org/3/library/stdtypes.html?highlight=split#str.split
75
+ if (separator === " ")
76
+ split = split.filter((n) => n);
77
+ if (n == null || split.length <= n)
78
+ return split;
79
+ const out = split.slice(0, n);
80
+ out.push(split.slice(n).join(separator));
81
+ return out;
82
+ }
83
+ /**
84
+ * Access nested object properties by string path
85
+ *
86
+ * https://stackoverflow.com/a/22129960
87
+ */
88
+ function resolve(obj, path, separator = ".") {
89
+ const properties = Array.isArray(path) ? path : path.split(separator);
90
+ return properties.reduce((prev, curr) => prev?.[curr], obj);
91
+ }
92
+ /**
93
+ * For safely casting input values
94
+ * @param input String that is expected to be in the snum
95
+ * @param enumExpected The enum to cast the input value to
96
+ * @throws RemarkExecutionError when input is not a key of enum
97
+ */
98
+ function as(input, enumExpected) {
99
+ if (!Object.values(enumExpected).includes(input))
100
+ throw new CommandExecutionError(`${input} not found in ${Object.values(enumExpected)}`);
101
+ return input;
102
+ }
103
+
104
+ function _(path, lang) {
105
+ const translation = resolve(lang, path);
106
+ if (!translation || typeof translation !== "string")
107
+ return undefined;
108
+ return translation;
109
+ }
110
+ function format(message, ...args) {
111
+ if (!message)
112
+ return;
113
+ // All arguments must be defined, otherwise nothing is returned
114
+ for (const arg of args) {
115
+ if (arg === undefined)
116
+ return;
117
+ }
118
+ return message.replace(/{\d+}/g, (match) => {
119
+ const index = +match.slice(1, -1);
120
+ return `${args[index]}`;
121
+ });
122
+ }
123
+
124
+ class Command {
125
+ constructor(locale) {
126
+ this.locale = locale;
127
+ }
128
+ }
129
+
130
+ var _CeilingHeightCommand_regex;
131
+ class CeilingHeightCommand extends Command {
132
+ constructor() {
133
+ super(...arguments);
134
+ _CeilingHeightCommand_regex.set(this, /^CIG (\d{3})V(\d{3})\b/);
135
+ }
136
+ canParse(code) {
137
+ return __classPrivateFieldGet(this, _CeilingHeightCommand_regex, "f").test(code);
138
+ }
139
+ execute(code, remark) {
140
+ const matches = code.match(__classPrivateFieldGet(this, _CeilingHeightCommand_regex, "f"));
141
+ if (!matches)
142
+ throw new UnexpectedParseError("Match not found");
143
+ const min = +matches[1] * 100;
144
+ const max = +matches[2] * 100;
145
+ const description = format(_("Remark.Ceiling.Height", this.locale), min, max);
146
+ remark.push({
147
+ type: RemarkType.CeilingHeight,
148
+ description,
149
+ raw: matches[0],
150
+ min,
151
+ max,
152
+ });
153
+ return [code.replace(__classPrivateFieldGet(this, _CeilingHeightCommand_regex, "f"), "").trim(), remark];
154
+ }
155
+ }
156
+ _CeilingHeightCommand_regex = new WeakMap();
157
+
158
+ var _CeilingSecondLocationCommand_regex;
159
+ class CeilingSecondLocationCommand extends Command {
160
+ constructor() {
161
+ super(...arguments);
162
+ _CeilingSecondLocationCommand_regex.set(this, /^CIG (\d{3}) (\w+)\b/);
163
+ }
164
+ canParse(code) {
165
+ return __classPrivateFieldGet(this, _CeilingSecondLocationCommand_regex, "f").test(code);
166
+ }
167
+ execute(code, remark) {
168
+ const matches = code.match(__classPrivateFieldGet(this, _CeilingSecondLocationCommand_regex, "f"));
169
+ if (!matches)
170
+ throw new UnexpectedParseError("Match not found");
171
+ const height = +matches[1] * 100;
172
+ const location = matches[2];
173
+ const description = format(_("Remark.Ceiling.Second.Location", this.locale), height, location);
174
+ remark.push({
175
+ type: RemarkType.CeilingSecondLocation,
176
+ description,
177
+ raw: matches[0],
178
+ height,
179
+ location,
180
+ });
181
+ return [code.replace(__classPrivateFieldGet(this, _CeilingSecondLocationCommand_regex, "f"), "").trim(), remark];
182
+ }
183
+ }
184
+ _CeilingSecondLocationCommand_regex = new WeakMap();
185
+
186
+ var CloudQuantity;
187
+ (function (CloudQuantity) {
188
+ /**
189
+ * Sky clear
190
+ */
191
+ CloudQuantity["SKC"] = "SKC";
192
+ /**
193
+ * Few
194
+ */
195
+ CloudQuantity["FEW"] = "FEW";
196
+ /**
197
+ * Broken
198
+ */
199
+ CloudQuantity["BKN"] = "BKN";
200
+ /**
201
+ * Scattered
202
+ */
203
+ CloudQuantity["SCT"] = "SCT";
204
+ /**
205
+ * Overcast
206
+ */
207
+ CloudQuantity["OVC"] = "OVC";
208
+ /**
209
+ * No significant cloud
210
+ */
211
+ CloudQuantity["NSC"] = "NSC";
212
+ })(CloudQuantity || (CloudQuantity = {}));
213
+ var CloudType;
214
+ (function (CloudType) {
215
+ /**
216
+ * Cumulonimbus
217
+ */
218
+ CloudType["CB"] = "CB";
219
+ /**
220
+ * Towering cumulus, cumulus congestus
221
+ */
222
+ CloudType["TCU"] = "TCU";
223
+ /**
224
+ * Cirrus
225
+ */
226
+ CloudType["CI"] = "CI";
227
+ /**
228
+ * Cirrocumulus
229
+ */
230
+ CloudType["CC"] = "CC";
231
+ /**
232
+ * Cirrostratus
233
+ */
234
+ CloudType["CS"] = "CS";
235
+ /**
236
+ * Altocumulus
237
+ */
238
+ CloudType["AC"] = "AC";
239
+ /**
240
+ * Stratus
241
+ */
242
+ CloudType["ST"] = "ST";
243
+ /**
244
+ * Cumulus
245
+ */
246
+ CloudType["CU"] = "CU";
247
+ /**
248
+ * Astrostratus
249
+ */
250
+ CloudType["AS"] = "AS";
251
+ /**
252
+ * Nimbostratus
253
+ */
254
+ CloudType["NS"] = "NS";
255
+ /**
256
+ * Stratocumulus
257
+ */
258
+ CloudType["SC"] = "SC";
259
+ })(CloudType || (CloudType = {}));
260
+ /**
261
+ * Moderate has no qualifier.
262
+ */
263
+ var Intensity;
264
+ (function (Intensity) {
265
+ Intensity["LIGHT"] = "-";
266
+ /**
267
+ * Heavy or well-developed
268
+ */
269
+ Intensity["HEAVY"] = "+";
270
+ Intensity["IN_VICINITY"] = "VC";
271
+ })(Intensity || (Intensity = {}));
272
+ var Descriptive;
273
+ (function (Descriptive) {
274
+ Descriptive["SHOWERS"] = "SH";
275
+ Descriptive["SHALLOW"] = "MI";
276
+ Descriptive["PATCHES"] = "BC";
277
+ Descriptive["PARTIAL"] = "PR";
278
+ Descriptive["DRIFTING"] = "DR";
279
+ Descriptive["THUNDERSTORM"] = "TS";
280
+ Descriptive["BLOWING"] = "BL";
281
+ Descriptive["FREEZING"] = "FZ";
282
+ })(Descriptive || (Descriptive = {}));
283
+ var Phenomenon;
284
+ (function (Phenomenon) {
285
+ Phenomenon["RAIN"] = "RA";
286
+ Phenomenon["DRIZZLE"] = "DZ";
287
+ Phenomenon["SNOW"] = "SN";
288
+ Phenomenon["SNOW_GRAINS"] = "SG";
289
+ Phenomenon["ICE_PELLETS"] = "PL";
290
+ Phenomenon["ICE_CRYSTALS"] = "IC";
291
+ Phenomenon["HAIL"] = "GR";
292
+ Phenomenon["SMALL_HAIL"] = "GS";
293
+ Phenomenon["UNKNOW_PRECIPITATION"] = "UP";
294
+ Phenomenon["FOG"] = "FG";
295
+ Phenomenon["VOLCANIC_ASH"] = "VA";
296
+ Phenomenon["MIST"] = "BR";
297
+ Phenomenon["HAZE"] = "HZ";
298
+ Phenomenon["WIDESPREAD_DUST"] = "DU";
299
+ Phenomenon["SMOKE"] = "FU";
300
+ Phenomenon["SAND"] = "SA";
301
+ Phenomenon["SPRAY"] = "PY";
302
+ Phenomenon["SQUALL"] = "SQ";
303
+ Phenomenon["SAND_WHIRLS"] = "PO";
304
+ Phenomenon["THUNDERSTORM"] = "TS";
305
+ Phenomenon["DUSTSTORM"] = "DS";
306
+ Phenomenon["SANDSTORM"] = "SS";
307
+ Phenomenon["FUNNEL_CLOUD"] = "FC";
308
+ })(Phenomenon || (Phenomenon = {}));
309
+ var TimeIndicator;
310
+ (function (TimeIndicator) {
311
+ TimeIndicator["AT"] = "AT";
312
+ TimeIndicator["FM"] = "FM";
313
+ TimeIndicator["TL"] = "TL";
314
+ })(TimeIndicator || (TimeIndicator = {}));
315
+ /**
316
+ * https://www.aviationweather.gov/taf/decoder
317
+ */
318
+ var WeatherChangeType;
319
+ (function (WeatherChangeType) {
320
+ /**
321
+ * FROM Group
322
+ *
323
+ * ie. `FM1600`
324
+ *
325
+ * The FM group is used when a rapid change, usually occuring in less than one
326
+ * hour, in prevailing conditions is expected. Typically, a rapid change of
327
+ * prevailing conditions to more or less a completely new set of prevailing
328
+ * conditions is associated with a synoptic feature passing through the
329
+ * terminal area (cold or warm frontal passage). Appended to the FM indicator
330
+ * is the four-digit hour and minute the change is expected to begin and
331
+ * continues until the next change group or until the end of the current
332
+ * forecast.
333
+ *
334
+ * A FM group will mark the beginning of a new line in a TAF report. Each FM
335
+ * group contains all the required elements -- wind, visibility, weather, and
336
+ * sky condition. Weather will be omitted in FM groups when it is not
337
+ * significant to aviation. FM groups will not include the contraction NSW.
338
+ *
339
+ * Examples:
340
+ *
341
+ * 1. `FM0100 SKC` - After 0100Z sky clear
342
+ * 2. `FM1430 OVC020` - After 1430Z ceiling two thousand overcast
343
+ */
344
+ WeatherChangeType["FM"] = "FM";
345
+ /**
346
+ * BECOMING Group
347
+ *
348
+ * ie. `BECMG 2224`
349
+ *
350
+ * The BECMG group is used when a gradual change in conditions is expected
351
+ * over a longer time period, usually two hours. The time period when the
352
+ * change is expected is a four-digit group with the beginning hour and ending
353
+ * hour of the change period which follows the BECMG indicator. The gradual
354
+ * change will occur at an unspecified time within this time period. Only the
355
+ * conditions are carried over from the previous time group.
356
+ *
357
+ * Example:
358
+ *
359
+ * 1. `OVC012 BECMG 1416 BKN020` - Ceiling one thousand two hundred overcast.
360
+ * Then a gradual change to ceiling two thousand broken between 1400Z and
361
+ * 1600Z.
362
+ */
363
+ WeatherChangeType["BECMG"] = "BECMG";
364
+ /**
365
+ * TEMPORARY Group
366
+ *
367
+ * ie. `TEMPO 1316`
368
+ *
369
+ * The TEMPO group is used for any conditions in wind, visibility, weather, or
370
+ * sky condition which are expected to last for generally less than an hour at
371
+ * a time (occasional), and are expected to occur during less than half the
372
+ * time period. The TEMPO indicator is followed by a four-digit group giving
373
+ * the beginning hour and ending hour of the time period during which the
374
+ * temporary conditions are expected. Only the changing forecast
375
+ * meteorological conditions are included in TEMPO groups. The omitted
376
+ * conditions are carried over from the previous time group.
377
+ *
378
+ * Examples:
379
+ *
380
+ * 1. `SCT030 TEMPO 1923 BKN030` - Three thousand scattered with occasional
381
+ * ceilings three thousand broken between 1900Z and 2300Z.
382
+ * 2. `4SM HZ TEMPO 0006 2SM BR HZ` - Visibility four in haze with occasional
383
+ * visibility two in mist and haze between 0000Z and 0600Z.
384
+ */
385
+ WeatherChangeType["TEMPO"] = "TEMPO";
386
+ /**
387
+ * Probability Forecast
388
+ *
389
+ * ie. `PROB40 0006`
390
+ *
391
+ * The probability or chance of thunderstorms or other precipitation events
392
+ * occuring, along with associated weather conditions (wind, visibility, and
393
+ * sky conditions).
394
+ *
395
+ * The PROB40 group is used when the occurrence of thunderstorms or
396
+ * precipitation is in the 30% to less than 50% range, thus the probability
397
+ * value 40 is appended to the PROB contraction. This is followed by a
398
+ * four-digit group giving the beginning hour and ending hour of the time
399
+ * period during which the thunderstorms or precipitation is expected.
400
+ *
401
+ * Note: PROB40 will not be shown during the first six hours of a forecast.
402
+ *
403
+ * Examples:
404
+ *
405
+ * 1. `PROB40 2102 1/2SM +TSRA` - Chance between 2100Z and 0200Z of
406
+ * visibility one-half thunderstorm, heavy rain.
407
+ * 2. `PROB40 1014 1SM RASN` - Chance between 1000Z and 1400Z of visibility
408
+ * one rain and snow.
409
+ * 3. `PROB40 2024 2SM FZRA` - Chance between 2000Z and 0000Z of visibility
410
+ * two freezing rain.
411
+
412
+ */
413
+ WeatherChangeType["PROB"] = "PROB";
414
+ })(WeatherChangeType || (WeatherChangeType = {}));
415
+ var Direction;
416
+ (function (Direction) {
417
+ Direction["E"] = "E";
418
+ Direction["ENE"] = "ENE";
419
+ Direction["ESE"] = "ESE";
420
+ Direction["N"] = "N";
421
+ Direction["NE"] = "NE";
422
+ Direction["NNE"] = "NNE";
423
+ Direction["NNW"] = "NNW";
424
+ Direction["NW"] = "NW";
425
+ Direction["S"] = "S";
426
+ Direction["SE"] = "SE";
427
+ Direction["SSE"] = "SSE";
428
+ Direction["SSW"] = "SSW";
429
+ Direction["SW"] = "SW";
430
+ Direction["W"] = "W";
431
+ Direction["WNW"] = "WNW";
432
+ Direction["WSW"] = "WSW";
433
+ })(Direction || (Direction = {}));
434
+ var DistanceUnit;
435
+ (function (DistanceUnit) {
436
+ DistanceUnit["Meters"] = "m";
437
+ DistanceUnit["StatuteMiles"] = "SM";
438
+ })(DistanceUnit || (DistanceUnit = {}));
439
+ /**
440
+ * Used to indicate the actual value is greater than or less than the value written
441
+ *
442
+ * For example,
443
+ *
444
+ * 1. `P6SM` = visibility greater than 6 statute miles
445
+ * 2. `M1/4SM` = visibility less than 1/4 statute mile
446
+ */
447
+ var ValueIndicator;
448
+ (function (ValueIndicator) {
449
+ ValueIndicator["GreaterThan"] = "P";
450
+ ValueIndicator["LessThan"] = "M";
451
+ })(ValueIndicator || (ValueIndicator = {}));
452
+ var RunwayInfoTrend;
453
+ (function (RunwayInfoTrend) {
454
+ RunwayInfoTrend["Uprising"] = "U";
455
+ RunwayInfoTrend["Decreasing"] = "D";
456
+ RunwayInfoTrend["NoSignificantChange"] = "N";
457
+ })(RunwayInfoTrend || (RunwayInfoTrend = {}));
458
+ var RunwayInfoUnit;
459
+ (function (RunwayInfoUnit) {
460
+ RunwayInfoUnit["Feet"] = "FT";
461
+ RunwayInfoUnit["Meters"] = "m";
462
+ })(RunwayInfoUnit || (RunwayInfoUnit = {}));
463
+
464
+ function degreesToCardinal(input) {
465
+ const degrees = +input;
466
+ if (isNaN(degrees))
467
+ return "VRB";
468
+ const dirs = [
469
+ "N",
470
+ "NNE",
471
+ "NE",
472
+ "ENE",
473
+ "E",
474
+ "ESE",
475
+ "SE",
476
+ "SSE",
477
+ "S",
478
+ "SSW",
479
+ "SW",
480
+ "WSW",
481
+ "W",
482
+ "WNW",
483
+ "NW",
484
+ "NNW",
485
+ ];
486
+ const ix = Math.floor((degrees + 11.25) / 22.5);
487
+ return dirs[ix % 16];
488
+ }
489
+ function convertVisibility(input) {
490
+ if (input === "9999")
491
+ return {
492
+ indicator: ValueIndicator.GreaterThan,
493
+ value: +input,
494
+ unit: DistanceUnit.Meters,
495
+ };
496
+ return {
497
+ value: +input,
498
+ unit: DistanceUnit.Meters,
499
+ };
500
+ }
501
+ /**
502
+ * @param input May start with P or M, and must end with SM
503
+ * @returns Distance
504
+ */
505
+ function convertNauticalMilesVisibility(input) {
506
+ let indicator;
507
+ let index = 0;
508
+ if (input.startsWith("P")) {
509
+ indicator = ValueIndicator.GreaterThan;
510
+ index = 1;
511
+ }
512
+ else if (input.startsWith("M")) {
513
+ indicator = ValueIndicator.LessThan;
514
+ index = 1;
515
+ }
516
+ return {
517
+ indicator,
518
+ value: convertFractionalAmount(input.slice(index, -2)),
519
+ unit: DistanceUnit.StatuteMiles,
520
+ };
521
+ }
522
+ /**
523
+ * Converts fractional and/or whole amounts
524
+ *
525
+ * Example "1/3", "1 1/3" and "1"
526
+ */
527
+ function convertFractionalAmount(input) {
528
+ const [whole, fraction] = input.split(" ");
529
+ if (!fraction)
530
+ return parseFraction(whole);
531
+ return +whole + parseFraction(fraction);
532
+ }
533
+ function parseFraction(input) {
534
+ const [top, bottom] = input.split("/");
535
+ if (!bottom)
536
+ return +top;
537
+ return Math.round((+top / +bottom) * 100) / 100;
538
+ }
539
+ function convertTemperature(input) {
540
+ if (input.startsWith("M"))
541
+ return -pySplit(input, "M")[1];
542
+ return +input;
543
+ }
544
+ function convertInchesMercuryToPascal(input) {
545
+ return 33.8639 * input;
546
+ }
547
+ /**
548
+ * Converts number `.toFixed(1)` before outputting to match python implementation
549
+ */
550
+ function convertTemperatureRemarks(sign, temperature) {
551
+ const temp = +temperature / 10;
552
+ if (sign === "0")
553
+ return temp;
554
+ return -temp;
555
+ }
556
+ function convertPrecipitationAmount(amount) {
557
+ return +amount / 100;
558
+ }
559
+
560
+ var _HailSizeCommand_regex;
561
+ class HailSizeCommand extends Command {
562
+ constructor() {
563
+ super(...arguments);
564
+ _HailSizeCommand_regex.set(this, /^GR ((\d\/\d)|((\d) ?(\d\/\d)?))/);
565
+ }
566
+ canParse(code) {
567
+ return __classPrivateFieldGet(this, _HailSizeCommand_regex, "f").test(code);
568
+ }
569
+ execute(code, remark) {
570
+ const matches = code.match(__classPrivateFieldGet(this, _HailSizeCommand_regex, "f"));
571
+ if (!matches)
572
+ throw new UnexpectedParseError("Match not found");
573
+ const description = format(_("Remark.Hail.0", this.locale), matches[1]);
574
+ remark.push({
575
+ type: RemarkType.HailSize,
576
+ description,
577
+ raw: matches[0],
578
+ size: convertFractionalAmount(matches[1]),
579
+ });
580
+ return [code.replace(__classPrivateFieldGet(this, _HailSizeCommand_regex, "f"), "").trim(), remark];
581
+ }
582
+ }
583
+ _HailSizeCommand_regex = new WeakMap();
584
+
585
+ var _HourlyMaximumMinimumTemperatureCommand_regex;
586
+ class HourlyMaximumMinimumTemperatureCommand extends Command {
587
+ constructor() {
588
+ super(...arguments);
589
+ _HourlyMaximumMinimumTemperatureCommand_regex.set(this, /^4([01])(\d{3})([01])(\d{3})\b/);
590
+ }
591
+ canParse(code) {
592
+ return __classPrivateFieldGet(this, _HourlyMaximumMinimumTemperatureCommand_regex, "f").test(code);
593
+ }
594
+ execute(code, remark) {
595
+ const matches = code.match(__classPrivateFieldGet(this, _HourlyMaximumMinimumTemperatureCommand_regex, "f"));
596
+ if (!matches)
597
+ throw new UnexpectedParseError("Match not found");
598
+ const description = format(_("Remark.Hourly.Maximum.Minimum.Temperature", this.locale), convertTemperatureRemarks(matches[1], matches[2]).toFixed(1), convertTemperatureRemarks(matches[3], matches[4]).toFixed(1));
599
+ remark.push({
600
+ type: RemarkType.HourlyMaximumMinimumTemperature,
601
+ description: description,
602
+ raw: matches[0],
603
+ max: convertTemperatureRemarks(matches[1], matches[2]),
604
+ min: convertTemperatureRemarks(matches[3], matches[4]),
605
+ });
606
+ return [code.replace(__classPrivateFieldGet(this, _HourlyMaximumMinimumTemperatureCommand_regex, "f"), "").trim(), remark];
607
+ }
608
+ }
609
+ _HourlyMaximumMinimumTemperatureCommand_regex = new WeakMap();
610
+
611
+ var _HourlyMaximumTemperatureCommand_regex;
612
+ class HourlyMaximumTemperatureCommand extends Command {
613
+ constructor() {
614
+ super(...arguments);
615
+ _HourlyMaximumTemperatureCommand_regex.set(this, /^1([01])(\d{3})\b/);
616
+ }
617
+ canParse(code) {
618
+ return __classPrivateFieldGet(this, _HourlyMaximumTemperatureCommand_regex, "f").test(code);
619
+ }
620
+ execute(code, remark) {
621
+ const matches = code.match(__classPrivateFieldGet(this, _HourlyMaximumTemperatureCommand_regex, "f"));
622
+ if (!matches)
623
+ throw new UnexpectedParseError("Match not found");
624
+ const description = format(_("Remark.Hourly.Maximum.Temperature", this.locale), convertTemperatureRemarks(matches[1], matches[2]).toFixed(1));
625
+ remark.push({
626
+ type: RemarkType.HourlyMaximumTemperature,
627
+ description: description,
628
+ raw: matches[0],
629
+ max: convertTemperatureRemarks(matches[1], matches[2]),
630
+ });
631
+ return [code.replace(__classPrivateFieldGet(this, _HourlyMaximumTemperatureCommand_regex, "f"), "").trim(), remark];
632
+ }
633
+ }
634
+ _HourlyMaximumTemperatureCommand_regex = new WeakMap();
635
+
636
+ var _HourlyMinimumTemperatureCommand_regex;
637
+ class HourlyMinimumTemperatureCommand extends Command {
638
+ constructor() {
639
+ super(...arguments);
640
+ _HourlyMinimumTemperatureCommand_regex.set(this, /^2([01])(\d{3})\b/);
641
+ }
642
+ canParse(code) {
643
+ return __classPrivateFieldGet(this, _HourlyMinimumTemperatureCommand_regex, "f").test(code);
644
+ }
645
+ execute(code, remark) {
646
+ const matches = code.match(__classPrivateFieldGet(this, _HourlyMinimumTemperatureCommand_regex, "f"));
647
+ if (!matches)
648
+ throw new UnexpectedParseError("Match not found");
649
+ const description = format(_("Remark.Hourly.Minimum.Temperature", this.locale), convertTemperatureRemarks(matches[1], matches[2]).toFixed(1));
650
+ remark.push({
651
+ type: RemarkType.HourlyMinimumTemperature,
652
+ description,
653
+ raw: matches[0],
654
+ min: convertTemperatureRemarks(matches[1], matches[2]),
655
+ });
656
+ return [code.replace(__classPrivateFieldGet(this, _HourlyMinimumTemperatureCommand_regex, "f"), "").trim(), remark];
657
+ }
658
+ }
659
+ _HourlyMinimumTemperatureCommand_regex = new WeakMap();
660
+
661
+ var _HourlyPrecipitationAmountCommand_regex;
662
+ class HourlyPrecipitationAmountCommand extends Command {
663
+ constructor() {
664
+ super(...arguments);
665
+ _HourlyPrecipitationAmountCommand_regex.set(this, /^P(\d{4})\b/);
666
+ }
667
+ canParse(code) {
668
+ return __classPrivateFieldGet(this, _HourlyPrecipitationAmountCommand_regex, "f").test(code);
669
+ }
670
+ execute(code, remark) {
671
+ const matches = code.match(__classPrivateFieldGet(this, _HourlyPrecipitationAmountCommand_regex, "f"));
672
+ if (!matches)
673
+ throw new UnexpectedParseError("Match not found");
674
+ const amount = +matches[1];
675
+ const description = format(_("Remark.Precipitation.Amount.Hourly", this.locale), amount);
676
+ remark.push({
677
+ type: RemarkType.HourlyPrecipitationAmount,
678
+ description,
679
+ raw: matches[0],
680
+ amount: amount / 100,
681
+ });
682
+ return [code.replace(__classPrivateFieldGet(this, _HourlyPrecipitationAmountCommand_regex, "f"), "").trim(), remark];
683
+ }
684
+ }
685
+ _HourlyPrecipitationAmountCommand_regex = new WeakMap();
686
+
687
+ var _HourlyPressureCommand_regex;
688
+ class HourlyPressureCommand extends Command {
689
+ constructor() {
690
+ super(...arguments);
691
+ _HourlyPressureCommand_regex.set(this, /^5(\d)(\d{3})\b/);
692
+ }
693
+ canParse(code) {
694
+ return __classPrivateFieldGet(this, _HourlyPressureCommand_regex, "f").test(code);
695
+ }
696
+ execute(code, remark) {
697
+ const matches = code.match(__classPrivateFieldGet(this, _HourlyPressureCommand_regex, "f"));
698
+ if (!matches)
699
+ throw new UnexpectedParseError("Match not found");
700
+ const part1 = _(`Remark.Barometer.${+matches[1]}`, this.locale);
701
+ const part2 = format(_("Remark.Pressure.Tendency", this.locale), +matches[2] / 10);
702
+ const description = part1 != null && part2 != null ? `${part1} ${part2}` : undefined;
703
+ remark.push({
704
+ type: RemarkType.HourlyPressure,
705
+ description,
706
+ raw: matches[0],
707
+ code: +matches[1],
708
+ pressureChange: +matches[2] / 10,
709
+ });
710
+ return [code.replace(__classPrivateFieldGet(this, _HourlyPressureCommand_regex, "f"), "").trim(), remark];
711
+ }
712
+ }
713
+ _HourlyPressureCommand_regex = new WeakMap();
714
+
715
+ var _HourlyTemperatureDewPointCommand_regex;
716
+ class HourlyTemperatureDewPointCommand extends Command {
717
+ constructor() {
718
+ super(...arguments);
719
+ _HourlyTemperatureDewPointCommand_regex.set(this, /^T([01])(\d{3})(([01])(\d{3}))?/);
720
+ }
721
+ canParse(code) {
722
+ return __classPrivateFieldGet(this, _HourlyTemperatureDewPointCommand_regex, "f").test(code);
723
+ }
724
+ execute(code, remark) {
725
+ const matches = code.match(__classPrivateFieldGet(this, _HourlyTemperatureDewPointCommand_regex, "f"));
726
+ if (!matches)
727
+ throw new UnexpectedParseError("Match not found");
728
+ const temperature = convertTemperatureRemarks(matches[1], matches[2]);
729
+ if (!matches[3]) {
730
+ const description = format(_("Remark.Hourly.Temperature.0", this.locale), temperature.toFixed(1));
731
+ remark.push({
732
+ type: RemarkType.HourlyTemperatureDewPoint,
733
+ description,
734
+ raw: matches[0],
735
+ temperature,
736
+ });
737
+ }
738
+ else {
739
+ const dewPoint = convertTemperatureRemarks(matches[4], matches[5]);
740
+ const description = format(_("Remark.Hourly.Temperature.Dew.Point", this.locale), temperature.toFixed(1), dewPoint.toFixed(1));
741
+ remark.push({
742
+ type: RemarkType.HourlyTemperatureDewPoint,
743
+ description,
744
+ raw: matches[0],
745
+ temperature,
746
+ dewPoint,
747
+ });
748
+ }
749
+ return [code.replace(__classPrivateFieldGet(this, _HourlyTemperatureDewPointCommand_regex, "f"), "").trim(), remark];
750
+ }
751
+ }
752
+ _HourlyTemperatureDewPointCommand_regex = new WeakMap();
753
+
754
+ var _IceAccretionCommand_regex;
755
+ class IceAccretionCommand extends Command {
756
+ constructor() {
757
+ super(...arguments);
758
+ _IceAccretionCommand_regex.set(this, /^l(\d)(\d{3})\b/);
759
+ }
760
+ canParse(code) {
761
+ return __classPrivateFieldGet(this, _IceAccretionCommand_regex, "f").test(code);
762
+ }
763
+ execute(code, remark) {
764
+ const matches = code.match(__classPrivateFieldGet(this, _IceAccretionCommand_regex, "f"));
765
+ if (!matches)
766
+ throw new UnexpectedParseError("Match not found");
767
+ const description = format(_("Remark.Ice.Accretion.Amount", this.locale), +matches[2], +matches[1]);
768
+ remark.push({
769
+ type: RemarkType.IceAccretion,
770
+ description,
771
+ raw: matches[0],
772
+ amount: +matches[2] / 100,
773
+ periodInHours: +matches[1],
774
+ });
775
+ return [code.replace(__classPrivateFieldGet(this, _IceAccretionCommand_regex, "f"), "").trim(), remark];
776
+ }
777
+ }
778
+ _IceAccretionCommand_regex = new WeakMap();
779
+
780
+ var _ObscurationCommand_regex;
781
+ class ObscurationCommand extends Command {
782
+ constructor() {
783
+ super(...arguments);
784
+ _ObscurationCommand_regex.set(this, /^([A-Z]{2}) ([A-Z]{3})(\d{3})/);
785
+ }
786
+ canParse(code) {
787
+ return __classPrivateFieldGet(this, _ObscurationCommand_regex, "f").test(code);
788
+ }
789
+ execute(code, remark) {
790
+ const matches = code.match(__classPrivateFieldGet(this, _ObscurationCommand_regex, "f"));
791
+ if (!matches)
792
+ throw new UnexpectedParseError("Match not found");
793
+ const quantity = as(matches[2], CloudQuantity);
794
+ const height = 100 * +matches[3];
795
+ const phenomenon = as(matches[1], Phenomenon);
796
+ const description = format(_("Remark.Obscuration", this.locale), _(`CloudQuantity.${quantity}`, this.locale), height, _(`Phenomenon.${phenomenon}`, this.locale));
797
+ remark.push({
798
+ type: RemarkType.Obscuration,
799
+ description,
800
+ raw: matches[0],
801
+ quantity,
802
+ height,
803
+ phenomenon,
804
+ });
805
+ return [code.replace(__classPrivateFieldGet(this, _ObscurationCommand_regex, "f"), "").trim(), remark];
806
+ }
807
+ }
808
+ _ObscurationCommand_regex = new WeakMap();
809
+
810
+ var _PrecipitationAmount24HourCommand_regex;
811
+ class PrecipitationAmount24HourCommand extends Command {
812
+ constructor() {
813
+ super(...arguments);
814
+ _PrecipitationAmount24HourCommand_regex.set(this, /^7(\d{4})\b/);
815
+ }
816
+ canParse(code) {
817
+ return __classPrivateFieldGet(this, _PrecipitationAmount24HourCommand_regex, "f").test(code);
818
+ }
819
+ execute(code, remark) {
820
+ const matches = code.match(__classPrivateFieldGet(this, _PrecipitationAmount24HourCommand_regex, "f"));
821
+ if (!matches)
822
+ throw new UnexpectedParseError("Match not found");
823
+ const amount = convertPrecipitationAmount(matches[1]);
824
+ const description = format(_("Remark.Precipitation.Amount.24", this.locale), amount);
825
+ remark.push({
826
+ type: RemarkType.PrecipitationAmount24Hour,
827
+ description,
828
+ raw: matches[0],
829
+ amount,
830
+ });
831
+ return [code.replace(__classPrivateFieldGet(this, _PrecipitationAmount24HourCommand_regex, "f"), "").trim(), remark];
832
+ }
833
+ }
834
+ _PrecipitationAmount24HourCommand_regex = new WeakMap();
835
+
836
+ var _PrecipitationAmount36HourCommand_regex;
837
+ class PrecipitationAmount36HourCommand extends Command {
838
+ constructor() {
839
+ super(...arguments);
840
+ _PrecipitationAmount36HourCommand_regex.set(this, /^([36])(\d{4})\b/);
841
+ }
842
+ canParse(code) {
843
+ return __classPrivateFieldGet(this, _PrecipitationAmount36HourCommand_regex, "f").test(code);
844
+ }
845
+ execute(code, remark) {
846
+ const matches = code.match(__classPrivateFieldGet(this, _PrecipitationAmount36HourCommand_regex, "f"));
847
+ if (!matches)
848
+ throw new UnexpectedParseError("Match not found");
849
+ const periodInHours = +matches[1];
850
+ const amount = convertPrecipitationAmount(matches[2]);
851
+ const description = format(_("Remark.Precipitation.Amount.3.6", this.locale), periodInHours, amount);
852
+ remark.push({
853
+ type: RemarkType.PrecipitationAmount36Hour,
854
+ description,
855
+ raw: matches[0],
856
+ periodInHours,
857
+ amount,
858
+ });
859
+ return [code.replace(__classPrivateFieldGet(this, _PrecipitationAmount36HourCommand_regex, "f"), "").trim(), remark];
860
+ }
861
+ }
862
+ _PrecipitationAmount36HourCommand_regex = new WeakMap();
863
+
864
+ var _PrecipitationBegEndCommand_regex;
865
+ class PrecipitationBegEndCommand extends Command {
866
+ constructor() {
867
+ super(...arguments);
868
+ _PrecipitationBegEndCommand_regex.set(this, /^(([A-Z]{2})?([A-Z]{2})B(\d{2})?(\d{2})E(\d{2})?(\d{2}))/);
869
+ }
870
+ canParse(code) {
871
+ return __classPrivateFieldGet(this, _PrecipitationBegEndCommand_regex, "f").test(code);
872
+ }
873
+ execute(code, remark) {
874
+ const matches = code.match(__classPrivateFieldGet(this, _PrecipitationBegEndCommand_regex, "f"));
875
+ if (!matches)
876
+ throw new UnexpectedParseError("Match not found");
877
+ const descriptive = matches[2] ? as(matches[2], Descriptive) : undefined;
878
+ const phenomenon = as(matches[3], Phenomenon);
879
+ const description = format(_("Remark.Precipitation.Beg.End", this.locale), descriptive ? _(`Descriptive.${descriptive}`, this.locale) : "", _(`Phenomenon.${phenomenon}`, this.locale), matches[4] || "", matches[5], matches[6] || "", matches[7]);
880
+ remark.push({
881
+ type: RemarkType.PrecipitationBegEnd,
882
+ description,
883
+ raw: matches[0],
884
+ descriptive,
885
+ phenomenon,
886
+ startHour: matches[4] ? +matches[4] : undefined,
887
+ startMin: +matches[5],
888
+ endHour: matches[6] ? +matches[6] : undefined,
889
+ endMin: +matches[7],
890
+ });
891
+ return [code.replace(__classPrivateFieldGet(this, _PrecipitationBegEndCommand_regex, "f"), "").trim(), remark];
892
+ }
893
+ }
894
+ _PrecipitationBegEndCommand_regex = new WeakMap();
895
+
896
+ var _PrevailingVisibilityCommand_regex;
897
+ class PrevailingVisibilityCommand extends Command {
898
+ constructor() {
899
+ super(...arguments);
900
+ _PrevailingVisibilityCommand_regex.set(this, /^VIS ((\d)*( )?(\d?\/?\d))V((\d)*( )?(\d?\/?\d))/);
901
+ }
902
+ canParse(code) {
903
+ return __classPrivateFieldGet(this, _PrevailingVisibilityCommand_regex, "f").test(code);
904
+ }
905
+ execute(code, remark) {
906
+ const matches = code.match(__classPrivateFieldGet(this, _PrevailingVisibilityCommand_regex, "f"));
907
+ if (!matches)
908
+ throw new UnexpectedParseError("Match not found");
909
+ const minVisibility = matches[1];
910
+ const maxVisibility = matches[5];
911
+ const description = format(_("Remark.Variable.Prevailing.Visibility", this.locale), minVisibility, maxVisibility);
912
+ remark.push({
913
+ type: RemarkType.PrevailingVisibility,
914
+ description,
915
+ raw: matches[0],
916
+ minVisibility: convertFractionalAmount(minVisibility),
917
+ maxVisibility: convertFractionalAmount(maxVisibility),
918
+ });
919
+ return [code.replace(__classPrivateFieldGet(this, _PrevailingVisibilityCommand_regex, "f"), "").trim(), remark];
920
+ }
921
+ }
922
+ _PrevailingVisibilityCommand_regex = new WeakMap();
923
+
924
+ var _SeaLevelPressureCommand_regex;
925
+ class SeaLevelPressureCommand extends Command {
926
+ constructor() {
927
+ super(...arguments);
928
+ _SeaLevelPressureCommand_regex.set(this, /^SLP(\d{2})(\d)/);
929
+ }
930
+ canParse(code) {
931
+ return __classPrivateFieldGet(this, _SeaLevelPressureCommand_regex, "f").test(code);
932
+ }
933
+ execute(code, remark) {
934
+ const matches = code.match(__classPrivateFieldGet(this, _SeaLevelPressureCommand_regex, "f"));
935
+ if (!matches)
936
+ throw new UnexpectedParseError("Match not found");
937
+ let pressure = matches[1].startsWith("9") ? "9" : "10";
938
+ pressure += matches[1] + "." + matches[2];
939
+ const description = format(_("Remark.Sea.Level.Pressure", this.locale), pressure);
940
+ remark.push({
941
+ type: RemarkType.SeaLevelPressure,
942
+ description,
943
+ raw: matches[0],
944
+ pressure: +pressure,
945
+ });
946
+ return [code.replace(__classPrivateFieldGet(this, _SeaLevelPressureCommand_regex, "f"), "").trim(), remark];
947
+ }
948
+ }
949
+ _SeaLevelPressureCommand_regex = new WeakMap();
950
+
951
+ var _SecondLocationVisibilityCommand_regex;
952
+ class SecondLocationVisibilityCommand extends Command {
953
+ constructor() {
954
+ super(...arguments);
955
+ _SecondLocationVisibilityCommand_regex.set(this, /^VIS ((\d)*( )?(\d?\/?\d)) (\w+)/);
956
+ }
957
+ canParse(code) {
958
+ return __classPrivateFieldGet(this, _SecondLocationVisibilityCommand_regex, "f").test(code);
959
+ }
960
+ execute(code, remark) {
961
+ const matches = code.match(__classPrivateFieldGet(this, _SecondLocationVisibilityCommand_regex, "f"));
962
+ if (!matches)
963
+ throw new UnexpectedParseError("Match not found");
964
+ const distance = matches[1];
965
+ const location = matches[5];
966
+ const description = format(_("Remark.Second.Location.Visibility", this.locale), distance, location);
967
+ remark.push({
968
+ type: RemarkType.SecondLocationVisibility,
969
+ description,
970
+ raw: matches[0],
971
+ distance: convertFractionalAmount(distance),
972
+ location,
973
+ });
974
+ return [code.replace(__classPrivateFieldGet(this, _SecondLocationVisibilityCommand_regex, "f"), "").trim(), remark];
975
+ }
976
+ }
977
+ _SecondLocationVisibilityCommand_regex = new WeakMap();
978
+
979
+ var _SectorVisibilityCommand_regex;
980
+ class SectorVisibilityCommand extends Command {
981
+ constructor() {
982
+ super(...arguments);
983
+ _SectorVisibilityCommand_regex.set(this, /^VIS ([A-Z]{1,2}) ((\d)*( )?(\d?\/?\d))/);
984
+ }
985
+ canParse(code) {
986
+ return __classPrivateFieldGet(this, _SectorVisibilityCommand_regex, "f").test(code);
987
+ }
988
+ execute(code, remark) {
989
+ const matches = code.match(__classPrivateFieldGet(this, _SectorVisibilityCommand_regex, "f"));
990
+ if (!matches)
991
+ throw new UnexpectedParseError("Match not found");
992
+ const direction = as(matches[1], Direction);
993
+ const description = format(_("Remark.Sector.Visibility", this.locale), _(`Converter.${direction}`, this.locale), matches[2]);
994
+ remark.push({
995
+ type: RemarkType.SectorVisibility,
996
+ description,
997
+ raw: matches[0],
998
+ direction,
999
+ distance: convertFractionalAmount(matches[2]),
1000
+ });
1001
+ return [code.replace(__classPrivateFieldGet(this, _SectorVisibilityCommand_regex, "f"), "").trim(), remark];
1002
+ }
1003
+ }
1004
+ _SectorVisibilityCommand_regex = new WeakMap();
1005
+
1006
+ var _SmallHailSizeCommand_regex;
1007
+ class SmallHailSizeCommand extends Command {
1008
+ constructor() {
1009
+ super(...arguments);
1010
+ _SmallHailSizeCommand_regex.set(this, /^GR LESS THAN ((\d )?(\d\/\d)?)/);
1011
+ }
1012
+ canParse(code) {
1013
+ return __classPrivateFieldGet(this, _SmallHailSizeCommand_regex, "f").test(code);
1014
+ }
1015
+ execute(code, remark) {
1016
+ const matches = code.match(__classPrivateFieldGet(this, _SmallHailSizeCommand_regex, "f"));
1017
+ if (!matches)
1018
+ throw new UnexpectedParseError("Match not found");
1019
+ const description = format(_("Remark.Hail.LesserThan", this.locale), matches[1]);
1020
+ remark.push({
1021
+ type: RemarkType.SmallHailSize,
1022
+ description,
1023
+ raw: matches[0],
1024
+ size: convertFractionalAmount(matches[1]),
1025
+ });
1026
+ return [code.replace(__classPrivateFieldGet(this, _SmallHailSizeCommand_regex, "f"), "").trim(), remark];
1027
+ }
1028
+ }
1029
+ _SmallHailSizeCommand_regex = new WeakMap();
1030
+
1031
+ var _SnowDepthCommand_regex;
1032
+ class SnowDepthCommand extends Command {
1033
+ constructor() {
1034
+ super(...arguments);
1035
+ _SnowDepthCommand_regex.set(this, /^4\/(\d{3})/);
1036
+ }
1037
+ canParse(code) {
1038
+ return __classPrivateFieldGet(this, _SnowDepthCommand_regex, "f").test(code);
1039
+ }
1040
+ execute(code, remark) {
1041
+ const matches = code.match(__classPrivateFieldGet(this, _SnowDepthCommand_regex, "f"));
1042
+ if (!matches)
1043
+ throw new UnexpectedParseError("Match not found");
1044
+ const depth = +matches[1];
1045
+ const description = format(_("Remark.Snow.Depth", this.locale), depth);
1046
+ remark.push({
1047
+ type: RemarkType.SnowDepth,
1048
+ description,
1049
+ raw: matches[0],
1050
+ depth,
1051
+ });
1052
+ return [code.replace(__classPrivateFieldGet(this, _SnowDepthCommand_regex, "f"), "").trim(), remark];
1053
+ }
1054
+ }
1055
+ _SnowDepthCommand_regex = new WeakMap();
1056
+
1057
+ var _SnowIncreaseCommand_regex;
1058
+ class SnowIncreaseCommand extends Command {
1059
+ constructor() {
1060
+ super(...arguments);
1061
+ _SnowIncreaseCommand_regex.set(this, /^SNINCR (\d+)\/(\d+)/);
1062
+ }
1063
+ canParse(code) {
1064
+ return __classPrivateFieldGet(this, _SnowIncreaseCommand_regex, "f").test(code);
1065
+ }
1066
+ execute(code, remark) {
1067
+ const matches = code.match(__classPrivateFieldGet(this, _SnowIncreaseCommand_regex, "f"));
1068
+ if (!matches)
1069
+ throw new UnexpectedParseError("Match not found");
1070
+ const inchesLastHour = +matches[1];
1071
+ const totalDepth = +matches[2];
1072
+ const description = format(_("Remark.Snow.Increasing.Rapidly", this.locale), inchesLastHour, totalDepth);
1073
+ remark.push({
1074
+ type: RemarkType.SnowIncrease,
1075
+ description,
1076
+ raw: matches[0],
1077
+ inchesLastHour,
1078
+ totalDepth,
1079
+ });
1080
+ return [code.replace(__classPrivateFieldGet(this, _SnowIncreaseCommand_regex, "f"), "").trim(), remark];
1081
+ }
1082
+ }
1083
+ _SnowIncreaseCommand_regex = new WeakMap();
1084
+
1085
+ var _SnowPelletsCommand_regex;
1086
+ class SnowPelletsCommand extends Command {
1087
+ constructor() {
1088
+ super(...arguments);
1089
+ _SnowPelletsCommand_regex.set(this, /^GS (LGT|MOD|HVY)/);
1090
+ }
1091
+ canParse(code) {
1092
+ return __classPrivateFieldGet(this, _SnowPelletsCommand_regex, "f").test(code);
1093
+ }
1094
+ execute(code, remark) {
1095
+ const matches = code.match(__classPrivateFieldGet(this, _SnowPelletsCommand_regex, "f"));
1096
+ if (!matches)
1097
+ throw new UnexpectedParseError("Match not found");
1098
+ const description = format(_("Remark.Snow.Pellets", this.locale), _(`Remark.${matches[1]}`, this.locale));
1099
+ remark.push({
1100
+ type: RemarkType.SnowPellets,
1101
+ description,
1102
+ raw: matches[0],
1103
+ amount: matches[1],
1104
+ });
1105
+ return [code.replace(__classPrivateFieldGet(this, _SnowPelletsCommand_regex, "f"), "").trim(), remark];
1106
+ }
1107
+ }
1108
+ _SnowPelletsCommand_regex = new WeakMap();
1109
+
1110
+ var _SunshineDurationCommand_regex;
1111
+ class SunshineDurationCommand extends Command {
1112
+ constructor() {
1113
+ super(...arguments);
1114
+ _SunshineDurationCommand_regex.set(this, /^98(\d{3})/);
1115
+ }
1116
+ canParse(code) {
1117
+ return __classPrivateFieldGet(this, _SunshineDurationCommand_regex, "f").test(code);
1118
+ }
1119
+ execute(code, remark) {
1120
+ const matches = code.match(__classPrivateFieldGet(this, _SunshineDurationCommand_regex, "f"));
1121
+ if (!matches)
1122
+ throw new UnexpectedParseError("Match not found");
1123
+ const duration = +matches[1];
1124
+ const description = format(_("Remark.Sunshine.Duration", this.locale), duration);
1125
+ remark.push({
1126
+ type: RemarkType.SunshineDuration,
1127
+ description,
1128
+ raw: matches[0],
1129
+ duration,
1130
+ });
1131
+ return [code.replace(__classPrivateFieldGet(this, _SunshineDurationCommand_regex, "f"), "").trim(), remark];
1132
+ }
1133
+ }
1134
+ _SunshineDurationCommand_regex = new WeakMap();
1135
+
1136
+ var _SurfaceVisibilityCommand_regex;
1137
+ class SurfaceVisibilityCommand extends Command {
1138
+ constructor() {
1139
+ super(...arguments);
1140
+ _SurfaceVisibilityCommand_regex.set(this, /^SFC VIS ((\d)*( )?(\d?\/?\d))/);
1141
+ }
1142
+ canParse(code) {
1143
+ return __classPrivateFieldGet(this, _SurfaceVisibilityCommand_regex, "f").test(code);
1144
+ }
1145
+ execute(code, remark) {
1146
+ const matches = code.match(__classPrivateFieldGet(this, _SurfaceVisibilityCommand_regex, "f"));
1147
+ if (!matches)
1148
+ throw new UnexpectedParseError("Match not found");
1149
+ const distance = matches[1];
1150
+ const description = format(_("Remark.Surface.Visibility", this.locale), distance);
1151
+ remark.push({
1152
+ type: RemarkType.SurfaceVisibility,
1153
+ description,
1154
+ raw: matches[0],
1155
+ distance: convertFractionalAmount(distance),
1156
+ });
1157
+ return [code.replace(__classPrivateFieldGet(this, _SurfaceVisibilityCommand_regex, "f"), "").trim(), remark];
1158
+ }
1159
+ }
1160
+ _SurfaceVisibilityCommand_regex = new WeakMap();
1161
+
1162
+ var _ThunderStormLocationCommand_regex;
1163
+ class ThunderStormLocationCommand extends Command {
1164
+ constructor() {
1165
+ super(...arguments);
1166
+ _ThunderStormLocationCommand_regex.set(this, /^TS ([A-Z]{2})/);
1167
+ }
1168
+ canParse(code) {
1169
+ return __classPrivateFieldGet(this, _ThunderStormLocationCommand_regex, "f").test(code);
1170
+ }
1171
+ execute(code, remark) {
1172
+ const matches = code.match(__classPrivateFieldGet(this, _ThunderStormLocationCommand_regex, "f"));
1173
+ if (!matches)
1174
+ throw new UnexpectedParseError("Match not found");
1175
+ const location = as(matches[1], Direction);
1176
+ const description = format(_("Remark.Thunderstorm.Location.0", this.locale), _(`Converter.${location}`, this.locale));
1177
+ remark.push({
1178
+ type: RemarkType.ThunderStormLocation,
1179
+ description,
1180
+ raw: matches[0],
1181
+ location,
1182
+ });
1183
+ return [code.replace(__classPrivateFieldGet(this, _ThunderStormLocationCommand_regex, "f"), "").trim(), remark];
1184
+ }
1185
+ }
1186
+ _ThunderStormLocationCommand_regex = new WeakMap();
1187
+
1188
+ var _ThunderStormLocationMovingCommand_regex;
1189
+ class ThunderStormLocationMovingCommand extends Command {
1190
+ constructor() {
1191
+ super(...arguments);
1192
+ _ThunderStormLocationMovingCommand_regex.set(this, /^TS ([A-Z]{2}) MOV ([A-Z]{2})/);
1193
+ }
1194
+ canParse(code) {
1195
+ return __classPrivateFieldGet(this, _ThunderStormLocationMovingCommand_regex, "f").test(code);
1196
+ }
1197
+ execute(code, remark) {
1198
+ const matches = code.match(__classPrivateFieldGet(this, _ThunderStormLocationMovingCommand_regex, "f"));
1199
+ if (!matches)
1200
+ throw new UnexpectedParseError("Match not found");
1201
+ const location = as(matches[1], Direction);
1202
+ const moving = as(matches[2], Direction);
1203
+ const description = format(_("Remark.Thunderstorm.Location.Moving", this.locale), _(`Converter.${location}`, this.locale), _(`Converter.${moving}`, this.locale));
1204
+ remark.push({
1205
+ type: RemarkType.ThunderStormLocationMoving,
1206
+ description,
1207
+ raw: matches[0],
1208
+ location,
1209
+ moving,
1210
+ });
1211
+ return [code.replace(__classPrivateFieldGet(this, _ThunderStormLocationMovingCommand_regex, "f"), "").trim(), remark];
1212
+ }
1213
+ }
1214
+ _ThunderStormLocationMovingCommand_regex = new WeakMap();
1215
+
1216
+ var _TornadicActivityBegCommand_regex;
1217
+ class TornadicActivityBegCommand extends Command {
1218
+ constructor() {
1219
+ super(...arguments);
1220
+ _TornadicActivityBegCommand_regex.set(this, /^(TORNADO|FUNNEL CLOUD|WATERSPOUT) (B(\d{2})?(\d{2}))( (\d+)? ([A-Z]{1,2})?)?/);
1221
+ }
1222
+ canParse(code) {
1223
+ return __classPrivateFieldGet(this, _TornadicActivityBegCommand_regex, "f").test(code);
1224
+ }
1225
+ execute(code, remark) {
1226
+ const matches = code.match(__classPrivateFieldGet(this, _TornadicActivityBegCommand_regex, "f"));
1227
+ if (!matches)
1228
+ throw new UnexpectedParseError("Match not found");
1229
+ const direction = as(matches[7], Direction);
1230
+ const description = format(_("Remark.Tornadic.Activity.Beginning", this.locale), _(`Remark.${matches[1].replace(" ", "")}`, this.locale), matches[3] || "", matches[4], matches[6], _(`Converter.${direction}`, this.locale));
1231
+ remark.push({
1232
+ type: RemarkType.TornadicActivityBeg,
1233
+ description,
1234
+ raw: matches[0],
1235
+ tornadicType: matches[1],
1236
+ startHour: matches[3] ? +matches[3] : undefined,
1237
+ startMinute: +matches[4],
1238
+ distance: +matches[6],
1239
+ direction,
1240
+ });
1241
+ return [code.replace(__classPrivateFieldGet(this, _TornadicActivityBegCommand_regex, "f"), "").trim(), remark];
1242
+ }
1243
+ }
1244
+ _TornadicActivityBegCommand_regex = new WeakMap();
1245
+
1246
+ var _TornadicActivityBegEndCommand_regex;
1247
+ class TornadicActivityBegEndCommand extends Command {
1248
+ constructor() {
1249
+ super(...arguments);
1250
+ _TornadicActivityBegEndCommand_regex.set(this, /^(TORNADO|FUNNEL CLOUD|WATERSPOUT) (B(\d{2})?(\d{2}))(E(\d{2})?(\d{2}))( (\d+)? ([A-Z]{1,2})?)?/);
1251
+ }
1252
+ canParse(code) {
1253
+ return __classPrivateFieldGet(this, _TornadicActivityBegEndCommand_regex, "f").test(code);
1254
+ }
1255
+ execute(code, remark) {
1256
+ const matches = code.match(__classPrivateFieldGet(this, _TornadicActivityBegEndCommand_regex, "f"));
1257
+ if (!matches)
1258
+ throw new UnexpectedParseError("Match not found");
1259
+ const direction = as(matches[10], Direction);
1260
+ const description = format(_("Remark.Tornadic.Activity.BegEnd", this.locale), _(`Remark.${matches[1].replace(" ", "")}`, this.locale), matches[3] || "", matches[4], matches[6] || "", matches[7], matches[9], _(`Converter.${direction}`, this.locale));
1261
+ remark.push({
1262
+ type: RemarkType.TornadicActivityBegEnd,
1263
+ description,
1264
+ raw: matches[0],
1265
+ tornadicType: matches[1],
1266
+ startHour: matches[3] ? +matches[3] : undefined,
1267
+ startMinute: +matches[4],
1268
+ endHour: matches[6] ? +matches[6] : undefined,
1269
+ endMinute: +matches[7],
1270
+ distance: +matches[9],
1271
+ direction,
1272
+ });
1273
+ return [code.replace(__classPrivateFieldGet(this, _TornadicActivityBegEndCommand_regex, "f"), "").trim(), remark];
1274
+ }
1275
+ }
1276
+ _TornadicActivityBegEndCommand_regex = new WeakMap();
1277
+
1278
+ var _TornadicActivityEndCommand_regex;
1279
+ class TornadicActivityEndCommand extends Command {
1280
+ constructor() {
1281
+ super(...arguments);
1282
+ _TornadicActivityEndCommand_regex.set(this, /^(TORNADO|FUNNEL CLOUD|WATERSPOUT) (E(\d{2})?(\d{2}))( (\d+)? ([A-Z]{1,2})?)?/);
1283
+ }
1284
+ canParse(code) {
1285
+ return __classPrivateFieldGet(this, _TornadicActivityEndCommand_regex, "f").test(code);
1286
+ }
1287
+ execute(code, remark) {
1288
+ const matches = code.match(__classPrivateFieldGet(this, _TornadicActivityEndCommand_regex, "f"));
1289
+ if (!matches)
1290
+ throw new UnexpectedParseError("Match not found");
1291
+ const direction = as(matches[7], Direction);
1292
+ const description = format(_("Remark.Tornadic.Activity.Ending", this.locale), _(`Remark.${matches[1].replace(" ", "")}`, this.locale), matches[3] || "", matches[4], matches[6], _(`Converter.${direction}`, this.locale));
1293
+ remark.push({
1294
+ type: RemarkType.TornadicActivityEnd,
1295
+ description,
1296
+ raw: matches[0],
1297
+ tornadicType: matches[1],
1298
+ endHour: matches[3] ? +matches[3] : undefined,
1299
+ endMinute: +matches[4],
1300
+ distance: +matches[6],
1301
+ direction,
1302
+ });
1303
+ return [code.replace(__classPrivateFieldGet(this, _TornadicActivityEndCommand_regex, "f"), "").trim(), remark];
1304
+ }
1305
+ }
1306
+ _TornadicActivityEndCommand_regex = new WeakMap();
1307
+
1308
+ var _TowerVisibilityCommand_regex;
1309
+ class TowerVisibilityCommand extends Command {
1310
+ constructor() {
1311
+ super(...arguments);
1312
+ _TowerVisibilityCommand_regex.set(this, /^TWR VIS ((\d)*( )?(\d?\/?\d))/);
1313
+ }
1314
+ canParse(code) {
1315
+ return __classPrivateFieldGet(this, _TowerVisibilityCommand_regex, "f").test(code);
1316
+ }
1317
+ execute(code, remark) {
1318
+ const matches = code.match(__classPrivateFieldGet(this, _TowerVisibilityCommand_regex, "f"));
1319
+ if (!matches)
1320
+ throw new UnexpectedParseError("Match not found");
1321
+ const distance = matches[1];
1322
+ const description = format(_("Remark.Tower.Visibility", this.locale), distance);
1323
+ remark.push({
1324
+ type: RemarkType.TowerVisibility,
1325
+ description,
1326
+ raw: matches[0],
1327
+ distance: convertFractionalAmount(distance),
1328
+ });
1329
+ return [code.replace(__classPrivateFieldGet(this, _TowerVisibilityCommand_regex, "f"), "").trim(), remark];
1330
+ }
1331
+ }
1332
+ _TowerVisibilityCommand_regex = new WeakMap();
1333
+
1334
+ var _VariableSkyCommand_regex;
1335
+ class VariableSkyCommand extends Command {
1336
+ constructor() {
1337
+ super(...arguments);
1338
+ _VariableSkyCommand_regex.set(this, /^([A-Z]{3}) V ([A-Z]{3})/);
1339
+ }
1340
+ canParse(code) {
1341
+ return __classPrivateFieldGet(this, _VariableSkyCommand_regex, "f").test(code);
1342
+ }
1343
+ execute(code, remark) {
1344
+ const matches = code.match(__classPrivateFieldGet(this, _VariableSkyCommand_regex, "f"));
1345
+ if (!matches)
1346
+ throw new UnexpectedParseError("Match not found");
1347
+ const firstQuantity = as(matches[1], CloudQuantity);
1348
+ const secondQuantity = as(matches[2], CloudQuantity);
1349
+ const description = format(_("Remark.Variable.Sky.Condition.0", this.locale), _(`CloudQuantity.${firstQuantity}`, this.locale), _(`CloudQuantity.${secondQuantity}`, this.locale));
1350
+ remark.push({
1351
+ type: RemarkType.VariableSky,
1352
+ description,
1353
+ raw: matches[0],
1354
+ cloudQuantityRange: [firstQuantity, secondQuantity],
1355
+ });
1356
+ return [code.replace(__classPrivateFieldGet(this, _VariableSkyCommand_regex, "f"), "").trim(), remark];
1357
+ }
1358
+ }
1359
+ _VariableSkyCommand_regex = new WeakMap();
1360
+
1361
+ var _VariableSkyHeightCommand_regex;
1362
+ class VariableSkyHeightCommand extends Command {
1363
+ constructor() {
1364
+ super(...arguments);
1365
+ _VariableSkyHeightCommand_regex.set(this, /^([A-Z]{3})(\d{3}) V ([A-Z]{3})/);
1366
+ }
1367
+ canParse(code) {
1368
+ return __classPrivateFieldGet(this, _VariableSkyHeightCommand_regex, "f").test(code);
1369
+ }
1370
+ execute(code, remark) {
1371
+ const matches = code.match(__classPrivateFieldGet(this, _VariableSkyHeightCommand_regex, "f"));
1372
+ if (!matches)
1373
+ throw new UnexpectedParseError("Match not found");
1374
+ const firstQuantity = as(matches[1], CloudQuantity);
1375
+ const secondQuantity = as(matches[3], CloudQuantity);
1376
+ const height = 100 * +matches[2];
1377
+ const description = format(_("Remark.Variable.Sky.Condition.Height", this.locale), height, _(`CloudQuantity.${firstQuantity}`, this.locale), _(`CloudQuantity.${secondQuantity}`, this.locale));
1378
+ remark.push({
1379
+ type: RemarkType.VariableSkyHeight,
1380
+ description,
1381
+ raw: matches[0],
1382
+ height,
1383
+ cloudQuantityRange: [firstQuantity, secondQuantity],
1384
+ });
1385
+ return [code.replace(__classPrivateFieldGet(this, _VariableSkyHeightCommand_regex, "f"), "").trim(), remark];
1386
+ }
1387
+ }
1388
+ _VariableSkyHeightCommand_regex = new WeakMap();
1389
+
1390
+ var _VirgaDirectionCommand_regex;
1391
+ class VirgaDirectionCommand extends Command {
1392
+ constructor() {
1393
+ super(...arguments);
1394
+ _VirgaDirectionCommand_regex.set(this, /^VIRGA ([A-Z]{2})/);
1395
+ }
1396
+ canParse(code) {
1397
+ return __classPrivateFieldGet(this, _VirgaDirectionCommand_regex, "f").test(code);
1398
+ }
1399
+ execute(code, remark) {
1400
+ const matches = code.match(__classPrivateFieldGet(this, _VirgaDirectionCommand_regex, "f"));
1401
+ if (!matches)
1402
+ throw new UnexpectedParseError("Match not found");
1403
+ const direction = as(matches[1], Direction);
1404
+ const description = format(_("Remark.Virga.Direction", this.locale), _(`Converter.${direction}`, this.locale));
1405
+ remark.push({
1406
+ type: RemarkType.VirgaDirection,
1407
+ description,
1408
+ raw: matches[0],
1409
+ direction,
1410
+ });
1411
+ return [code.replace(__classPrivateFieldGet(this, _VirgaDirectionCommand_regex, "f"), "").trim(), remark];
1412
+ }
1413
+ }
1414
+ _VirgaDirectionCommand_regex = new WeakMap();
1415
+
1416
+ var _WaterEquivalentSnowCommand_regex;
1417
+ class WaterEquivalentSnowCommand extends Command {
1418
+ constructor() {
1419
+ super(...arguments);
1420
+ _WaterEquivalentSnowCommand_regex.set(this, /^933(\d{3})\b/);
1421
+ }
1422
+ canParse(code) {
1423
+ return __classPrivateFieldGet(this, _WaterEquivalentSnowCommand_regex, "f").test(code);
1424
+ }
1425
+ execute(code, remark) {
1426
+ const matches = code.match(__classPrivateFieldGet(this, _WaterEquivalentSnowCommand_regex, "f"));
1427
+ if (!matches)
1428
+ throw new UnexpectedParseError("Match not found");
1429
+ const amount = +matches[1] / 10;
1430
+ const description = format(_("Remark.Water.Equivalent.Snow.Ground", this.locale), amount);
1431
+ remark.push({
1432
+ type: RemarkType.WaterEquivalentSnow,
1433
+ description,
1434
+ raw: matches[0],
1435
+ amount,
1436
+ });
1437
+ return [code.replace(__classPrivateFieldGet(this, _WaterEquivalentSnowCommand_regex, "f"), "").trim(), remark];
1438
+ }
1439
+ }
1440
+ _WaterEquivalentSnowCommand_regex = new WeakMap();
1441
+
1442
+ var _WindPeakCommand_regex;
1443
+ class WindPeakCommand extends Command {
1444
+ constructor() {
1445
+ super(...arguments);
1446
+ _WindPeakCommand_regex.set(this, /^PK WND (\d{3})(\d{2,3})\/(\d{2})?(\d{2})/);
1447
+ }
1448
+ canParse(code) {
1449
+ return __classPrivateFieldGet(this, _WindPeakCommand_regex, "f").test(code);
1450
+ }
1451
+ execute(code, remark) {
1452
+ const matches = code.match(__classPrivateFieldGet(this, _WindPeakCommand_regex, "f"));
1453
+ if (!matches)
1454
+ throw new UnexpectedParseError("Match not found");
1455
+ const degrees = +matches[1];
1456
+ const speed = +matches[2];
1457
+ const description = format(_("Remark.PeakWind", this.locale), degrees, speed, matches[3] || "", matches[4]);
1458
+ remark.push({
1459
+ type: RemarkType.WindPeak,
1460
+ description,
1461
+ raw: matches[0],
1462
+ speed,
1463
+ degrees,
1464
+ startHour: matches[3] ? +matches[3] : undefined,
1465
+ startMinute: +matches[4],
1466
+ });
1467
+ return [code.replace(__classPrivateFieldGet(this, _WindPeakCommand_regex, "f"), "").trim(), remark];
1468
+ }
1469
+ }
1470
+ _WindPeakCommand_regex = new WeakMap();
1471
+
1472
+ var _WindShiftCommand_regex;
1473
+ class WindShiftCommand extends Command {
1474
+ constructor() {
1475
+ super(...arguments);
1476
+ _WindShiftCommand_regex.set(this, /^WSHFT (\d{2})?(\d{2})/);
1477
+ }
1478
+ canParse(code) {
1479
+ return __classPrivateFieldGet(this, _WindShiftCommand_regex, "f").test(code);
1480
+ }
1481
+ execute(code, remark) {
1482
+ const matches = code.match(__classPrivateFieldGet(this, _WindShiftCommand_regex, "f"));
1483
+ if (!matches)
1484
+ throw new UnexpectedParseError("Match not found");
1485
+ const description = format(_("Remark.WindShift.0", this.locale), matches[1] || "", matches[2]);
1486
+ remark.push({
1487
+ type: RemarkType.WindShift,
1488
+ description,
1489
+ raw: matches[0],
1490
+ startHour: matches[1] ? +matches[1] : undefined,
1491
+ startMinute: +matches[2],
1492
+ });
1493
+ return [code.replace(__classPrivateFieldGet(this, _WindShiftCommand_regex, "f"), "").trim(), remark];
1494
+ }
1495
+ }
1496
+ _WindShiftCommand_regex = new WeakMap();
1497
+
1498
+ var _WindShiftFropaCommand_regex;
1499
+ class WindShiftFropaCommand extends Command {
1500
+ constructor() {
1501
+ super(...arguments);
1502
+ _WindShiftFropaCommand_regex.set(this, /^WSHFT (\d{2})?(\d{2}) FROPA/);
1503
+ }
1504
+ canParse(code) {
1505
+ return __classPrivateFieldGet(this, _WindShiftFropaCommand_regex, "f").test(code);
1506
+ }
1507
+ execute(code, remark) {
1508
+ const matches = code.match(__classPrivateFieldGet(this, _WindShiftFropaCommand_regex, "f"));
1509
+ if (!matches)
1510
+ throw new UnexpectedParseError("Match not found");
1511
+ const description = format(_("Remark.WindShift.FROPA", this.locale), matches[1] || "", matches[2]);
1512
+ remark.push({
1513
+ type: RemarkType.WindShiftFropa,
1514
+ description,
1515
+ raw: matches[0],
1516
+ startHour: matches[1] ? +matches[1] : undefined,
1517
+ startMinute: +matches[2],
1518
+ });
1519
+ return [code.replace(__classPrivateFieldGet(this, _WindShiftFropaCommand_regex, "f"), "").trim(), remark];
1520
+ }
1521
+ }
1522
+ _WindShiftFropaCommand_regex = new WeakMap();
1523
+
1524
+ class DefaultCommand extends Command {
1525
+ canParse() {
1526
+ return true;
1527
+ }
1528
+ execute(code, remark) {
1529
+ const rmkSplit = pySplit(code, " ", 1);
1530
+ const rem = _(`Remark.${rmkSplit[0]}`, this.locale);
1531
+ if (RemarkType[rmkSplit[0]]) {
1532
+ remark.push({
1533
+ type: rmkSplit[0],
1534
+ description: rem,
1535
+ raw: rmkSplit[0],
1536
+ });
1537
+ }
1538
+ else {
1539
+ const lastRemark = remark[remark.length - 1];
1540
+ if (lastRemark?.type === RemarkType.Unknown) {
1541
+ // Merge with last unknown value
1542
+ lastRemark.raw = `${lastRemark.raw} ${rmkSplit[0]}`;
1543
+ }
1544
+ else {
1545
+ remark.push({
1546
+ type: RemarkType.Unknown,
1547
+ raw: rmkSplit[0],
1548
+ });
1549
+ }
1550
+ }
1551
+ return [rmkSplit.length === 1 ? "" : rmkSplit[1], remark];
1552
+ }
1553
+ }
1554
+
1555
+ var _PrecipitationBegCommand_regex;
1556
+ class PrecipitationBegCommand extends Command {
1557
+ constructor() {
1558
+ super(...arguments);
1559
+ _PrecipitationBegCommand_regex.set(this, /^(([A-Z]{2})?([A-Z]{2})B(\d{2})?(\d{2}))/);
1560
+ }
1561
+ canParse(code) {
1562
+ return __classPrivateFieldGet(this, _PrecipitationBegCommand_regex, "f").test(code);
1563
+ }
1564
+ execute(code, remark) {
1565
+ const matches = code.match(__classPrivateFieldGet(this, _PrecipitationBegCommand_regex, "f"));
1566
+ if (!matches)
1567
+ throw new UnexpectedParseError("Match not found");
1568
+ const descriptive = matches[2] ? as(matches[2], Descriptive) : undefined;
1569
+ const phenomenon = as(matches[3], Phenomenon);
1570
+ const description = format(_("Remark.Precipitation.Beg.0", this.locale), descriptive ? _(`Descriptive.${descriptive}`, this.locale) : "", _(`Phenomenon.${phenomenon}`, this.locale), matches[4] || "", matches[5])?.trim();
1571
+ remark.push({
1572
+ type: RemarkType.PrecipitationBeg,
1573
+ description,
1574
+ raw: matches[0],
1575
+ descriptive,
1576
+ phenomenon,
1577
+ startHour: matches[4] ? +matches[4] : undefined,
1578
+ startMin: +matches[5],
1579
+ });
1580
+ return [code.replace(__classPrivateFieldGet(this, _PrecipitationBegCommand_regex, "f"), "").trim(), remark];
1581
+ }
1582
+ }
1583
+ _PrecipitationBegCommand_regex = new WeakMap();
1584
+
1585
+ var _PrecipitationEndCommand_regex;
1586
+ class PrecipitationEndCommand extends Command {
1587
+ constructor() {
1588
+ super(...arguments);
1589
+ _PrecipitationEndCommand_regex.set(this, /^(([A-Z]{2})?([A-Z]{2})E(\d{2})?(\d{2}))/);
1590
+ }
1591
+ canParse(code) {
1592
+ return __classPrivateFieldGet(this, _PrecipitationEndCommand_regex, "f").test(code);
1593
+ }
1594
+ execute(code, remark) {
1595
+ const matches = code.match(__classPrivateFieldGet(this, _PrecipitationEndCommand_regex, "f"));
1596
+ if (!matches)
1597
+ throw new UnexpectedParseError("Match not found");
1598
+ const descriptive = matches[2] ? as(matches[2], Descriptive) : undefined;
1599
+ const phenomenon = as(matches[3], Phenomenon);
1600
+ const description = format(_("Remark.Precipitation.End", this.locale), descriptive ? _(`Descriptive.${descriptive}`, this.locale) : "", _(`Phenomenon.${phenomenon}`, this.locale), matches[4] || "", matches[5])?.trim();
1601
+ remark.push({
1602
+ type: RemarkType.PrecipitationEnd,
1603
+ description,
1604
+ raw: matches[0],
1605
+ descriptive,
1606
+ phenomenon,
1607
+ endHour: matches[4] ? +matches[4] : undefined,
1608
+ endMin: +matches[5],
1609
+ });
1610
+ return [code.replace(__classPrivateFieldGet(this, _PrecipitationEndCommand_regex, "f"), "").trim(), remark];
1611
+ }
1612
+ }
1613
+ _PrecipitationEndCommand_regex = new WeakMap();
1614
+
1615
+ class RemarkCommandSupplier {
1616
+ constructor(locale) {
1617
+ this.locale = locale;
1618
+ this.defaultCommand = new DefaultCommand(locale);
1619
+ this.commandList = [
1620
+ new WindPeakCommand(locale),
1621
+ new WindShiftFropaCommand(locale),
1622
+ new WindShiftCommand(locale),
1623
+ new TowerVisibilityCommand(locale),
1624
+ new SurfaceVisibilityCommand(locale),
1625
+ new PrevailingVisibilityCommand(locale),
1626
+ new SecondLocationVisibilityCommand(locale),
1627
+ new SectorVisibilityCommand(locale),
1628
+ new TornadicActivityBegEndCommand(locale),
1629
+ new TornadicActivityBegCommand(locale),
1630
+ new TornadicActivityEndCommand(locale),
1631
+ new PrecipitationBegEndCommand(locale),
1632
+ new PrecipitationBegCommand(locale),
1633
+ new PrecipitationEndCommand(locale),
1634
+ new ThunderStormLocationMovingCommand(locale),
1635
+ new ThunderStormLocationCommand(locale),
1636
+ new SmallHailSizeCommand(locale),
1637
+ new HailSizeCommand(locale),
1638
+ new SnowPelletsCommand(locale),
1639
+ new VirgaDirectionCommand(locale),
1640
+ new CeilingHeightCommand(locale),
1641
+ new ObscurationCommand(locale),
1642
+ new VariableSkyHeightCommand(locale),
1643
+ new VariableSkyCommand(locale),
1644
+ new CeilingSecondLocationCommand(locale),
1645
+ new SeaLevelPressureCommand(locale),
1646
+ new SnowIncreaseCommand(locale),
1647
+ new HourlyMaximumMinimumTemperatureCommand(locale),
1648
+ new HourlyMaximumTemperatureCommand(locale),
1649
+ new HourlyMinimumTemperatureCommand(locale),
1650
+ new HourlyPrecipitationAmountCommand(locale),
1651
+ new HourlyTemperatureDewPointCommand(locale),
1652
+ new HourlyPressureCommand(locale),
1653
+ new IceAccretionCommand(locale),
1654
+ new PrecipitationAmount36HourCommand(locale),
1655
+ new PrecipitationAmount24HourCommand(locale),
1656
+ new SnowDepthCommand(locale),
1657
+ new SunshineDurationCommand(locale),
1658
+ new WaterEquivalentSnowCommand(locale),
1659
+ ];
1660
+ }
1661
+ get(code) {
1662
+ for (const command of this.commandList) {
1663
+ if (command.canParse(code))
1664
+ return command;
1665
+ }
1666
+ return this.defaultCommand;
1667
+ }
1668
+ }
1669
+ var RemarkType;
1670
+ (function (RemarkType) {
1671
+ // Unknown processed with default command
1672
+ RemarkType["Unknown"] = "Unknown";
1673
+ // Processed with default command
1674
+ RemarkType["AO1"] = "AO1";
1675
+ RemarkType["AO2"] = "AO2";
1676
+ RemarkType["PRESFR"] = "PRESFR";
1677
+ RemarkType["PRESRR"] = "PRESRR";
1678
+ RemarkType["TORNADO"] = "TORNADO";
1679
+ RemarkType["FUNNELCLOUD"] = "FUNNELCLOUD";
1680
+ RemarkType["WATERSPOUT"] = "WATERSPOUT";
1681
+ RemarkType["VIRGA"] = "VIRGA";
1682
+ // Regular commands below
1683
+ RemarkType["WindPeak"] = "WindPeak";
1684
+ RemarkType["WindShiftFropa"] = "WindShiftFropa";
1685
+ RemarkType["WindShift"] = "WindShift";
1686
+ RemarkType["TowerVisibility"] = "TowerVisibility";
1687
+ RemarkType["SurfaceVisibility"] = "SurfaceVisibility";
1688
+ RemarkType["PrevailingVisibility"] = "PrevailingVisibility";
1689
+ RemarkType["SecondLocationVisibility"] = "SecondLocationVisibility";
1690
+ RemarkType["SectorVisibility"] = "SectorVisibility";
1691
+ RemarkType["TornadicActivityBegEnd"] = "TornadicActivityBegEnd";
1692
+ RemarkType["TornadicActivityBeg"] = "TornadicActivityBeg";
1693
+ RemarkType["TornadicActivityEnd"] = "TornadicActivityEnd";
1694
+ RemarkType["PrecipitationBeg"] = "PrecipitationBeg";
1695
+ RemarkType["PrecipitationBegEnd"] = "PrecipitationBegEnd";
1696
+ RemarkType["PrecipitationEnd"] = "PrecipitationEnd";
1697
+ RemarkType["ThunderStormLocationMoving"] = "ThunderStormLocationMoving";
1698
+ RemarkType["ThunderStormLocation"] = "ThunderStormLocation";
1699
+ RemarkType["SmallHailSize"] = "SmallHailSize";
1700
+ RemarkType["HailSize"] = "HailSize";
1701
+ RemarkType["SnowPellets"] = "SnowPellets";
1702
+ RemarkType["VirgaDirection"] = "VirgaDirection";
1703
+ RemarkType["CeilingHeight"] = "CeilingHeight";
1704
+ RemarkType["Obscuration"] = "Obscuration";
1705
+ RemarkType["VariableSkyHeight"] = "VariableSkyHeight";
1706
+ RemarkType["VariableSky"] = "VariableSky";
1707
+ RemarkType["CeilingSecondLocation"] = "CeilingSecondLocation";
1708
+ RemarkType["SeaLevelPressure"] = "SeaLevelPressure";
1709
+ RemarkType["SnowIncrease"] = "SnowIncrease";
1710
+ RemarkType["HourlyMaximumMinimumTemperature"] = "HourlyMaximumMinimumTemperature";
1711
+ RemarkType["HourlyMaximumTemperature"] = "HourlyMaximumTemperature";
1712
+ RemarkType["HourlyMinimumTemperature"] = "HourlyMinimumTemperature";
1713
+ RemarkType["HourlyPrecipitationAmount"] = "HourlyPrecipitationAmount";
1714
+ RemarkType["HourlyTemperatureDewPoint"] = "HourlyTemperatureDewPoint";
1715
+ RemarkType["HourlyPressure"] = "HourlyPressure";
1716
+ RemarkType["IceAccretion"] = "IceAccretion";
1717
+ RemarkType["PrecipitationAmount36Hour"] = "PrecipitationAmount36Hour";
1718
+ RemarkType["PrecipitationAmount24Hour"] = "PrecipitationAmount24Hour";
1719
+ RemarkType["SnowDepth"] = "SnowDepth";
1720
+ RemarkType["SunshineDuration"] = "SunshineDuration";
1721
+ RemarkType["WaterEquivalentSnow"] = "WaterEquivalentSnow";
1722
+ })(RemarkType || (RemarkType = {}));
1723
+
1724
+ function isWeatherConditionValid(weather) {
1725
+ return (weather.phenomenons.length !== 0 ||
1726
+ weather.descriptive == Descriptive.THUNDERSTORM ||
1727
+ (weather.intensity === Intensity.IN_VICINITY &&
1728
+ weather.descriptive == Descriptive.SHOWERS));
1729
+ }
1730
+
1731
+ var _CloudCommand_cloudRegex, _MainVisibilityCommand_regex, _WindCommand_regex, _WindVariationCommand_regex, _WindShearCommand_regex, _VerticalVisibilityCommand_regex, _MinimalVisibilityCommand_regex, _MainVisibilityNauticalMilesCommand_regex, _CommandSupplier_commands$1;
1732
+ /**
1733
+ * This function creates a wind element.
1734
+ * @param wind The wind object
1735
+ * @param direction The direction in degrees
1736
+ * @param speed The speed
1737
+ * @param gust The speed of the gust.
1738
+ * @param unit The speed unit
1739
+ */
1740
+ function makeWind(direction, speed, gust, unit) {
1741
+ return {
1742
+ speed: +speed,
1743
+ direction: degreesToCardinal(direction),
1744
+ degrees: direction !== "VRB" ? +direction : undefined,
1745
+ gust: gust ? +gust : undefined,
1746
+ unit: unit || "KT",
1747
+ };
1748
+ }
1749
+ class CloudCommand {
1750
+ constructor() {
1751
+ _CloudCommand_cloudRegex.set(this, /^([A-Z]{3})(\d{3})?([A-Z]{2,3})?$/);
1752
+ }
1753
+ parse(cloudString) {
1754
+ const m = cloudString.match(__classPrivateFieldGet(this, _CloudCommand_cloudRegex, "f"));
1755
+ if (!m)
1756
+ return;
1757
+ const quantity = CloudQuantity[m[1]];
1758
+ const height = 100 * +m[2] || undefined;
1759
+ const type = CloudType[m[3]];
1760
+ if (!quantity)
1761
+ return;
1762
+ return { quantity, height, type };
1763
+ }
1764
+ execute(container, cloudString) {
1765
+ const cloud = this.parse(cloudString);
1766
+ if (cloud) {
1767
+ container.clouds.push(cloud);
1768
+ return true;
1769
+ }
1770
+ return false;
1771
+ }
1772
+ canParse(cloudString) {
1773
+ return __classPrivateFieldGet(this, _CloudCommand_cloudRegex, "f").test(cloudString);
1774
+ }
1775
+ }
1776
+ _CloudCommand_cloudRegex = new WeakMap();
1777
+ class MainVisibilityCommand {
1778
+ constructor() {
1779
+ _MainVisibilityCommand_regex.set(this, /^(\d{4})(|NDV)$/);
1780
+ }
1781
+ canParse(visibilityString) {
1782
+ return __classPrivateFieldGet(this, _MainVisibilityCommand_regex, "f").test(visibilityString);
1783
+ }
1784
+ execute(container, visibilityString) {
1785
+ const matches = visibilityString.match(__classPrivateFieldGet(this, _MainVisibilityCommand_regex, "f"));
1786
+ if (!matches)
1787
+ return false;
1788
+ const distance = convertVisibility(matches[1]);
1789
+ if (!container.visibility)
1790
+ container.visibility = distance;
1791
+ container.visibility = { ...container.visibility, ...distance };
1792
+ if (matches[2] === "NDV")
1793
+ container.visibility.ndv = true;
1794
+ return true;
1795
+ }
1796
+ }
1797
+ _MainVisibilityCommand_regex = new WeakMap();
1798
+ class WindCommand {
1799
+ constructor() {
1800
+ _WindCommand_regex.set(this, /^(VRB|\d{3})(\d{2})G?(\d{2})?(KT|MPS|KM\/H)?/);
1801
+ }
1802
+ canParse(windString) {
1803
+ return __classPrivateFieldGet(this, _WindCommand_regex, "f").test(windString);
1804
+ }
1805
+ parseWind(windString) {
1806
+ const matches = windString.match(__classPrivateFieldGet(this, _WindCommand_regex, "f"));
1807
+ if (!matches)
1808
+ throw new UnexpectedParseError("Wind should be defined");
1809
+ return makeWind(matches[1], matches[2], matches[3], matches[4]);
1810
+ }
1811
+ execute(container, windString) {
1812
+ const wind = this.parseWind(windString);
1813
+ container.wind = wind;
1814
+ return true;
1815
+ }
1816
+ }
1817
+ _WindCommand_regex = new WeakMap();
1818
+ class WindVariationCommand {
1819
+ constructor() {
1820
+ _WindVariationCommand_regex.set(this, /^(\d{3})V(\d{3})/);
1821
+ }
1822
+ canParse(windString) {
1823
+ return __classPrivateFieldGet(this, _WindVariationCommand_regex, "f").test(windString);
1824
+ }
1825
+ parseWindVariation(wind, windString) {
1826
+ const matches = windString.match(__classPrivateFieldGet(this, _WindVariationCommand_regex, "f"));
1827
+ if (!matches)
1828
+ throw new UnexpectedParseError("Wind should be defined");
1829
+ wind.minVariation = +matches[1];
1830
+ wind.maxVariation = +matches[2];
1831
+ }
1832
+ execute(container, windString) {
1833
+ if (!container.wind)
1834
+ throw new UnexpectedParseError();
1835
+ this.parseWindVariation(container.wind, windString);
1836
+ return true;
1837
+ }
1838
+ }
1839
+ _WindVariationCommand_regex = new WeakMap();
1840
+ class WindShearCommand {
1841
+ constructor() {
1842
+ _WindShearCommand_regex.set(this, /^WS(\d{3})\/(\w{3})(\d{2})G?(\d{2})?(KT|MPS|KM\/H)/);
1843
+ }
1844
+ canParse(windString) {
1845
+ return __classPrivateFieldGet(this, _WindShearCommand_regex, "f").test(windString);
1846
+ }
1847
+ parseWindShear(windString) {
1848
+ const matches = windString.match(__classPrivateFieldGet(this, _WindShearCommand_regex, "f"));
1849
+ if (!matches)
1850
+ throw new UnexpectedParseError("Wind shear should be defined");
1851
+ return {
1852
+ ...makeWind(matches[2], matches[3], matches[4], matches[5]),
1853
+ height: 100 * +matches[1],
1854
+ };
1855
+ }
1856
+ execute(container, windString) {
1857
+ container.windShear = this.parseWindShear(windString);
1858
+ return true;
1859
+ }
1860
+ }
1861
+ _WindShearCommand_regex = new WeakMap();
1862
+ class VerticalVisibilityCommand {
1863
+ constructor() {
1864
+ _VerticalVisibilityCommand_regex.set(this, /^VV(\d{3})$/);
1865
+ }
1866
+ execute(container, visibilityString) {
1867
+ const matches = visibilityString.match(__classPrivateFieldGet(this, _VerticalVisibilityCommand_regex, "f"));
1868
+ if (!matches)
1869
+ throw new UnexpectedParseError("Vertical visibility should be defined");
1870
+ container.verticalVisibility = 100 * +matches[1];
1871
+ return true;
1872
+ }
1873
+ canParse(windString) {
1874
+ return __classPrivateFieldGet(this, _VerticalVisibilityCommand_regex, "f").test(windString);
1875
+ }
1876
+ }
1877
+ _VerticalVisibilityCommand_regex = new WeakMap();
1878
+ class MinimalVisibilityCommand {
1879
+ constructor() {
1880
+ _MinimalVisibilityCommand_regex.set(this, /^(\d{4}[a-zA-Z]{1,2})$/);
1881
+ }
1882
+ execute(container, visibilityString) {
1883
+ const matches = visibilityString.match(__classPrivateFieldGet(this, _MinimalVisibilityCommand_regex, "f"));
1884
+ if (!matches)
1885
+ throw new UnexpectedParseError("Vertical visibility should be defined");
1886
+ if (!container.visibility)
1887
+ throw new UnexpectedParseError("container.visibility not instantiated");
1888
+ container.visibility.min = {
1889
+ value: +matches[1].slice(0, 4),
1890
+ direction: matches[1].slice(4),
1891
+ };
1892
+ return true;
1893
+ }
1894
+ canParse(windString) {
1895
+ return __classPrivateFieldGet(this, _MinimalVisibilityCommand_regex, "f").test(windString);
1896
+ }
1897
+ }
1898
+ _MinimalVisibilityCommand_regex = new WeakMap();
1899
+ class MainVisibilityNauticalMilesCommand {
1900
+ constructor() {
1901
+ _MainVisibilityNauticalMilesCommand_regex.set(this, /^(P|M)?(\d)*(\s)?((\d\/\d)?SM)$/);
1902
+ }
1903
+ execute(container, visibilityString) {
1904
+ const distance = convertNauticalMilesVisibility(visibilityString);
1905
+ container.visibility = distance;
1906
+ return true;
1907
+ }
1908
+ canParse(windString) {
1909
+ return __classPrivateFieldGet(this, _MainVisibilityNauticalMilesCommand_regex, "f").test(windString);
1910
+ }
1911
+ }
1912
+ _MainVisibilityNauticalMilesCommand_regex = new WeakMap();
1913
+ class CommandSupplier$1 {
1914
+ constructor() {
1915
+ _CommandSupplier_commands$1.set(this, [
1916
+ new WindShearCommand(),
1917
+ new WindCommand(),
1918
+ new WindVariationCommand(),
1919
+ new MainVisibilityCommand(),
1920
+ new MainVisibilityNauticalMilesCommand(),
1921
+ new MinimalVisibilityCommand(),
1922
+ new VerticalVisibilityCommand(),
1923
+ new CloudCommand(),
1924
+ ]);
1925
+ }
1926
+ get(input) {
1927
+ for (const command of __classPrivateFieldGet(this, _CommandSupplier_commands$1, "f")) {
1928
+ if (command.canParse(input))
1929
+ return command;
1930
+ }
1931
+ }
1932
+ }
1933
+ _CommandSupplier_commands$1 = new WeakMap();
1934
+
1935
+ var _AltimeterCommand_regex;
1936
+ class AltimeterCommand {
1937
+ constructor() {
1938
+ _AltimeterCommand_regex.set(this, /^Q(\d{4})$/);
1939
+ }
1940
+ canParse(input) {
1941
+ return __classPrivateFieldGet(this, _AltimeterCommand_regex, "f").test(input);
1942
+ }
1943
+ execute(metar, input) {
1944
+ const matches = input.match(__classPrivateFieldGet(this, _AltimeterCommand_regex, "f"));
1945
+ if (!matches)
1946
+ throw new UnexpectedParseError("Match not found");
1947
+ metar.altimeter = Math.trunc(+matches[1]);
1948
+ }
1949
+ }
1950
+ _AltimeterCommand_regex = new WeakMap();
1951
+
1952
+ var _AltimeterMercuryCommand_regex;
1953
+ class AltimeterMercuryCommand {
1954
+ constructor() {
1955
+ _AltimeterMercuryCommand_regex.set(this, /^A(\d{4})$/);
1956
+ }
1957
+ canParse(input) {
1958
+ return __classPrivateFieldGet(this, _AltimeterMercuryCommand_regex, "f").test(input);
1959
+ }
1960
+ execute(metar, input) {
1961
+ const matches = input.match(__classPrivateFieldGet(this, _AltimeterMercuryCommand_regex, "f"));
1962
+ if (!matches)
1963
+ throw new UnexpectedParseError("Match not found");
1964
+ const mercury = +matches[1] / 100;
1965
+ metar.altimeter = Math.trunc(convertInchesMercuryToPascal(mercury));
1966
+ }
1967
+ }
1968
+ _AltimeterMercuryCommand_regex = new WeakMap();
1969
+
1970
+ var _RunwayCommand_genericRegex, _RunwayCommand_runwayMaxRangeRegex, _RunwayCommand_runwayRegex;
1971
+ class RunwayCommand {
1972
+ constructor() {
1973
+ _RunwayCommand_genericRegex.set(this, /^(R\d{2}\w?\/)/);
1974
+ _RunwayCommand_runwayMaxRangeRegex.set(this, /^R(\d{2}\w?)\/(\d{4})V(\d{3,4})([UDN])?(FT)?/);
1975
+ _RunwayCommand_runwayRegex.set(this, /^R(\d{2}\w?)\/([MP])?(\d{4})([UDN])?(FT)?$/);
1976
+ }
1977
+ canParse(input) {
1978
+ return __classPrivateFieldGet(this, _RunwayCommand_genericRegex, "f").test(input);
1979
+ }
1980
+ execute(metar, input) {
1981
+ // TODO idk if this matches super well...
1982
+ if (__classPrivateFieldGet(this, _RunwayCommand_runwayRegex, "f").test(input)) {
1983
+ const matches = input.match(__classPrivateFieldGet(this, _RunwayCommand_runwayRegex, "f"));
1984
+ if (!matches)
1985
+ throw new UnexpectedParseError("Should be able to parse");
1986
+ const indicator = matches[2] ? as(matches[2], ValueIndicator) : undefined;
1987
+ const trend = matches[4] ? as(matches[4], RunwayInfoTrend) : undefined;
1988
+ const unit = matches[5]
1989
+ ? as(matches[5], RunwayInfoUnit)
1990
+ : RunwayInfoUnit.Meters;
1991
+ metar.runwaysInfo.push({
1992
+ name: matches[1],
1993
+ indicator,
1994
+ minRange: +matches[3],
1995
+ trend,
1996
+ unit,
1997
+ });
1998
+ }
1999
+ else if (__classPrivateFieldGet(this, _RunwayCommand_runwayMaxRangeRegex, "f").test(input)) {
2000
+ const matches = input.match(__classPrivateFieldGet(this, _RunwayCommand_runwayMaxRangeRegex, "f"));
2001
+ if (!matches)
2002
+ throw new UnexpectedParseError("Should be able to parse");
2003
+ const trend = matches[4] ? as(matches[4], RunwayInfoTrend) : undefined;
2004
+ const unit = matches[5]
2005
+ ? as(matches[5], RunwayInfoUnit)
2006
+ : RunwayInfoUnit.Meters;
2007
+ metar.runwaysInfo.push({
2008
+ name: matches[1],
2009
+ minRange: +matches[2],
2010
+ maxRange: +matches[3],
2011
+ trend,
2012
+ unit,
2013
+ });
2014
+ }
2015
+ }
2016
+ }
2017
+ _RunwayCommand_genericRegex = new WeakMap(), _RunwayCommand_runwayMaxRangeRegex = new WeakMap(), _RunwayCommand_runwayRegex = new WeakMap();
2018
+
2019
+ var _TemperatureCommand_regex;
2020
+ class TemperatureCommand {
2021
+ constructor() {
2022
+ _TemperatureCommand_regex.set(this, /^(M?\d{2})\/(M?\d{2})$/);
2023
+ }
2024
+ canParse(input) {
2025
+ return __classPrivateFieldGet(this, _TemperatureCommand_regex, "f").test(input);
2026
+ }
2027
+ execute(metar, input) {
2028
+ const matches = input.match(__classPrivateFieldGet(this, _TemperatureCommand_regex, "f"));
2029
+ if (!matches)
2030
+ throw new UnexpectedParseError("Match not found");
2031
+ metar.temperature = convertTemperature(matches[1]);
2032
+ metar.dewPoint = convertTemperature(matches[2]);
2033
+ }
2034
+ }
2035
+ _TemperatureCommand_regex = new WeakMap();
2036
+
2037
+ var _CommandSupplier_commands;
2038
+ class CommandSupplier {
2039
+ constructor() {
2040
+ _CommandSupplier_commands.set(this, [
2041
+ new RunwayCommand(),
2042
+ new TemperatureCommand(),
2043
+ new AltimeterCommand(),
2044
+ new AltimeterMercuryCommand(),
2045
+ ]);
2046
+ }
2047
+ get(input) {
2048
+ for (const command of __classPrivateFieldGet(this, _CommandSupplier_commands, "f")) {
2049
+ if (command.canParse(input))
2050
+ return command;
2051
+ }
2052
+ }
2053
+ }
2054
+ _CommandSupplier_commands = new WeakMap();
2055
+
2056
+ var _AbstractParser_INTENSITY_REGEX, _AbstractParser_CAVOK, _AbstractParser_commonSupplier, _MetarParser_commandSupplier, _TAFParser_validityPattern, _RemarkParser_supplier;
2057
+ /**
2058
+ * Parses the delivery time of a METAR/TAF
2059
+ * @param abstractWeatherCode The TAF or METAR object
2060
+ * @param timeString The string representing the delivery time
2061
+ */
2062
+ function parseDeliveryTime(timeString) {
2063
+ const day = +timeString.slice(0, 2);
2064
+ const hour = +timeString.slice(2, 4);
2065
+ const minute = +timeString.slice(4, 6);
2066
+ if (isNaN(day) || isNaN(hour) || isNaN(minute))
2067
+ throw new InvalidWeatherStatementError("Report time is invalid");
2068
+ return {
2069
+ day,
2070
+ hour,
2071
+ minute,
2072
+ };
2073
+ }
2074
+ /**
2075
+ * This function parses the array containing the remark and concat the array into a string
2076
+ * @param container the metar, taf or taf trend to update
2077
+ * @param line The array containing the current line tokens
2078
+ * @param index the index starting the remark ie token RMK
2079
+ */
2080
+ function parseRemark(container, line, index, locale) {
2081
+ const remarks = new RemarkParser(locale).parse(line.slice(index + 1).join(" "));
2082
+ container.remarks = remarks;
2083
+ container.remark = remarks
2084
+ .map(({ description, raw }) => description || raw)
2085
+ .join(" ");
2086
+ }
2087
+ /**
2088
+ * Parses the temperature in a TAF
2089
+ * @param input the string containing the temperature
2090
+ * @returns TemperatureDated object
2091
+ */
2092
+ function parseTemperature(input) {
2093
+ const parts = pySplit(input, "/");
2094
+ return {
2095
+ temperature: convertTemperature(parts[0].slice(2)),
2096
+ day: +parts[1].slice(0, 2),
2097
+ hour: +parts[1].slice(2, 4),
2098
+ };
2099
+ }
2100
+ /**
2101
+ * Parses validity of a TAF or a TAFTrend
2102
+ * @param input the string containing the validity
2103
+ * @returns Validity object
2104
+ */
2105
+ function parseValidity(input, date) {
2106
+ const parts = pySplit(input, "/");
2107
+ return {
2108
+ startDay: +parts[0].slice(0, 2),
2109
+ startHour: +parts[0].slice(2),
2110
+ endDay: +parts[1].slice(0, 2),
2111
+ endHour: +parts[1].slice(2),
2112
+ };
2113
+ }
2114
+ /**
2115
+ * Parses the validity for a FROM taf trend
2116
+ * @param input the string containing the validity
2117
+ * @returns a Validity object
2118
+ */
2119
+ function parseFromValidity(input) {
2120
+ return {
2121
+ startDay: +input.slice(2, 4),
2122
+ startHour: +input.slice(4, 6),
2123
+ startMinutes: +input.slice(6, 8),
2124
+ };
2125
+ }
2126
+ /**
2127
+ * Abstract class.
2128
+ * Base parser.
2129
+ */
2130
+ class AbstractParser {
2131
+ constructor(locale) {
2132
+ this.locale = locale;
2133
+ this.FM = "FM";
2134
+ this.TEMPO = "TEMPO";
2135
+ this.BECMG = "BECMG";
2136
+ this.RMK = "RMK";
2137
+ // Safari does not currently support negative lookbehind
2138
+ // #TOKENIZE_REGEX = /\s((?=\d\/\dSM)(?<!\s\d\s)|(?!\d\/\dSM))|=/;
2139
+ _AbstractParser_INTENSITY_REGEX.set(this, /^(-|\+|VC)/);
2140
+ _AbstractParser_CAVOK.set(this, "CAVOK");
2141
+ _AbstractParser_commonSupplier.set(this, new CommandSupplier$1());
2142
+ }
2143
+ parseWeatherCondition(input) {
2144
+ let intensity;
2145
+ if (input.match(__classPrivateFieldGet(this, _AbstractParser_INTENSITY_REGEX, "f"))) {
2146
+ const match = input.match(__classPrivateFieldGet(this, _AbstractParser_INTENSITY_REGEX, "f"))?.[0];
2147
+ if (match)
2148
+ intensity = match;
2149
+ }
2150
+ let descriptive;
2151
+ for (const key of Object.values(Descriptive)) {
2152
+ if (input.includes(key))
2153
+ descriptive = key;
2154
+ }
2155
+ const weatherCondition = {
2156
+ intensity,
2157
+ descriptive,
2158
+ phenomenons: [],
2159
+ };
2160
+ for (const key of Object.values(Phenomenon)) {
2161
+ // Thunderstorm as descriptive should not be added as a phenomenon
2162
+ if (descriptive === key)
2163
+ continue;
2164
+ if (input.includes(key))
2165
+ weatherCondition.phenomenons.push(key);
2166
+ }
2167
+ return weatherCondition;
2168
+ }
2169
+ /**
2170
+ * Parses the message into different tokens
2171
+ * @param input The metar or TAF as string
2172
+ * @returns List of tokens
2173
+ */
2174
+ tokenize(input) {
2175
+ // Missing safari support. If added in the future, put this back
2176
+ // return input.split(this.#TOKENIZE_REGEX).filter((v) => v);
2177
+ // Hack for safari below...
2178
+ const splitRegex = /\s|=/;
2179
+ const smRegex = /^\d\/\dSM$/;
2180
+ const digitRegex = /^(P|M)?\d$/;
2181
+ // return input.split(this.#TOKENIZE_REGEX).filter((v) => v);
2182
+ const splitted = input.split(splitRegex);
2183
+ for (let i = 0; i < splitted.length; i++) {
2184
+ if (digitRegex.test(splitted[i])) {
2185
+ if (splitted[i + 1] && smRegex.test(splitted[i + 1])) {
2186
+ splitted.splice(i, 2, `${splitted[i]} ${splitted[i + 1]}`);
2187
+ }
2188
+ }
2189
+ }
2190
+ return splitted.filter((t) => t);
2191
+ }
2192
+ /**
2193
+ * Common parse method for METAR, TAF and trends object
2194
+ * @param abstractWeatherCode the object to update
2195
+ * @param input The token to parse
2196
+ * @returns True if the token was parsed false otherwise
2197
+ */
2198
+ generalParse(abstractWeatherContainer, input) {
2199
+ if (input === __classPrivateFieldGet(this, _AbstractParser_CAVOK, "f")) {
2200
+ abstractWeatherContainer.cavok = true;
2201
+ abstractWeatherContainer.visibility = {
2202
+ indicator: ValueIndicator.GreaterThan,
2203
+ value: 9999,
2204
+ unit: DistanceUnit.Meters,
2205
+ };
2206
+ return true;
2207
+ }
2208
+ const command = __classPrivateFieldGet(this, _AbstractParser_commonSupplier, "f").get(input);
2209
+ if (command) {
2210
+ return command.execute(abstractWeatherContainer, input);
2211
+ }
2212
+ const weatherCondition = this.parseWeatherCondition(input);
2213
+ if (isWeatherConditionValid(weatherCondition)) {
2214
+ abstractWeatherContainer.weatherConditions.push(weatherCondition);
2215
+ return true;
2216
+ }
2217
+ return false;
2218
+ }
2219
+ }
2220
+ _AbstractParser_INTENSITY_REGEX = new WeakMap(), _AbstractParser_CAVOK = new WeakMap(), _AbstractParser_commonSupplier = new WeakMap();
2221
+ class MetarParser extends AbstractParser {
2222
+ constructor() {
2223
+ super(...arguments);
2224
+ this.AT = "AT";
2225
+ this.TL = "TL";
2226
+ _MetarParser_commandSupplier.set(this, new CommandSupplier());
2227
+ }
2228
+ /**
2229
+ * Parses a trend of a metar
2230
+ * @param index the index starting the trend in the list
2231
+ * @param trend The trend to update
2232
+ * @param trendParts array of tokens
2233
+ * @returns the last index of the token that was last parsed
2234
+ */
2235
+ parseTrend(index, trend, trendParts) {
2236
+ let i = index + 1;
2237
+ while (i < trendParts.length &&
2238
+ trendParts[i] !== this.TEMPO &&
2239
+ trendParts[i] !== this.BECMG) {
2240
+ if (trendParts[i].startsWith(this.FM) ||
2241
+ trendParts[i].startsWith(this.TL) ||
2242
+ trendParts[i].startsWith(this.AT)) {
2243
+ const trendTime = {
2244
+ type: TimeIndicator[trendParts[i].slice(0, 2)],
2245
+ hour: +trendParts[i].slice(2, 4),
2246
+ minute: +trendParts[i].slice(4, 6),
2247
+ };
2248
+ trend.times.push(trendTime);
2249
+ }
2250
+ else {
2251
+ this.generalParse(trend, trendParts[i]);
2252
+ }
2253
+ i = i + 1;
2254
+ }
2255
+ return i - 1;
2256
+ }
2257
+ /**
2258
+ * Parses an message and returns a METAR
2259
+ * @param input The message to parse
2260
+ * @returns METAR
2261
+ */
2262
+ parse(input) {
2263
+ const metarTab = this.tokenize(input);
2264
+ const metar = {
2265
+ ...parseDeliveryTime(metarTab[1]),
2266
+ station: metarTab[0],
2267
+ message: input,
2268
+ remarks: [],
2269
+ clouds: [],
2270
+ weatherConditions: [],
2271
+ trends: [],
2272
+ runwaysInfo: [],
2273
+ };
2274
+ let index = 2;
2275
+ while (index < metarTab.length) {
2276
+ if (!super.generalParse(metar, metarTab[index])) {
2277
+ if (metarTab[index] === "NOSIG") {
2278
+ metar.nosig = true;
2279
+ }
2280
+ else if (metarTab[index] === "AUTO") {
2281
+ metar.auto = true;
2282
+ }
2283
+ else if (metarTab[index] === this.TEMPO ||
2284
+ metarTab[index] === this.BECMG) {
2285
+ const trend = {
2286
+ type: WeatherChangeType[metarTab[index]],
2287
+ weatherConditions: [],
2288
+ clouds: [],
2289
+ times: [],
2290
+ remarks: [],
2291
+ };
2292
+ index = this.parseTrend(index, trend, metarTab);
2293
+ metar.trends.push(trend);
2294
+ }
2295
+ else if (metarTab[index] === this.RMK) {
2296
+ parseRemark(metar, metarTab, index, this.locale);
2297
+ break;
2298
+ }
2299
+ else {
2300
+ const command = __classPrivateFieldGet(this, _MetarParser_commandSupplier, "f").get(metarTab[index]);
2301
+ if (command)
2302
+ command.execute(metar, metarTab[index]);
2303
+ }
2304
+ }
2305
+ index = index + 1;
2306
+ }
2307
+ return metar;
2308
+ }
2309
+ }
2310
+ _MetarParser_commandSupplier = new WeakMap();
2311
+ /**
2312
+ * Parser for TAF messages
2313
+ */
2314
+ class TAFParser extends AbstractParser {
2315
+ constructor() {
2316
+ super(...arguments);
2317
+ this.TAF = "TAF";
2318
+ this.PROB = "PROB";
2319
+ this.TX = "TX";
2320
+ this.TN = "TN";
2321
+ _TAFParser_validityPattern.set(this, /^\d{4}\/\d{4}$/);
2322
+ }
2323
+ /**
2324
+ * the message to parse
2325
+ * @param input
2326
+ * @returns a TAF object
2327
+ * @throws ParseError if the message is invalid
2328
+ */
2329
+ parse(input) {
2330
+ let amendment;
2331
+ const lines = this.extractLinesTokens(input);
2332
+ let index = 0;
2333
+ if (lines[0][0] === this.TAF)
2334
+ index = 1;
2335
+ if (lines[0][1] === this.TAF)
2336
+ index = 2;
2337
+ if (lines[0][index] === "AMD") {
2338
+ amendment = true;
2339
+ index += 1;
2340
+ }
2341
+ const station = lines[0][index];
2342
+ index += 1;
2343
+ const time = parseDeliveryTime(lines[0][index]);
2344
+ index += 1;
2345
+ const validity = parseValidity(lines[0][index]);
2346
+ const taf = {
2347
+ station,
2348
+ amendment,
2349
+ ...time,
2350
+ validity,
2351
+ message: input,
2352
+ trends: [],
2353
+ remarks: [],
2354
+ clouds: [],
2355
+ weatherConditions: [],
2356
+ };
2357
+ for (let i = index + 1; i < lines[0].length; i++) {
2358
+ const token = lines[0][i];
2359
+ if (token == this.RMK) {
2360
+ parseRemark(taf, lines[0], i, this.locale);
2361
+ break;
2362
+ }
2363
+ else if (token.startsWith(this.TX))
2364
+ taf.maxTemperature = parseTemperature(token);
2365
+ else if (token.startsWith(this.TN))
2366
+ taf.minTemperature = parseTemperature(token);
2367
+ else
2368
+ this.generalParse(taf, token);
2369
+ }
2370
+ // Handle the other lines
2371
+ for (let i = 1; i < lines.length; i++) {
2372
+ this.parseLine(taf, lines[i]);
2373
+ }
2374
+ return taf;
2375
+ }
2376
+ /**
2377
+ * Format the message as a multiple line code so each line can be parsed
2378
+ * @param tafCode The base message
2379
+ * @returns a list of string representing the lines of the message
2380
+ */
2381
+ extractLinesTokens(tafCode) {
2382
+ const singleLine = tafCode.replace(/\n/g, " ");
2383
+ const cleanLine = singleLine.replace(/\s{2,}/g, " ");
2384
+ const lines = joinProbIfNeeded(cleanLine
2385
+ .replace(/\s(?=PROB\d{2}\sTEMPO|TEMPO|BECMG|FM|PROB)/g, "\n")
2386
+ .split(/\n/));
2387
+ // TODO cleanup
2388
+ function joinProbIfNeeded(ls) {
2389
+ for (let i = 0; i < ls.length; i++) {
2390
+ if (/^PROB\d{2}$/.test(ls[i]) && /^TEMPO/.test(ls[i + 1])) {
2391
+ ls.splice(i, 2, `${ls[i]} ${ls[i + 1]}`);
2392
+ }
2393
+ }
2394
+ return ls;
2395
+ }
2396
+ const linesToken = lines.map(this.tokenize);
2397
+ if (linesToken.length > 1) {
2398
+ const lastLine = linesToken[lines.length - 1];
2399
+ const temperatures = lastLine.filter((l) => l.startsWith(this.TX) || l.startsWith(this.TN));
2400
+ if (temperatures.length) {
2401
+ linesToken[0] = linesToken[0].concat(temperatures);
2402
+ linesToken[lines.length - 1] = lastLine.filter((l) => !l.startsWith(this.TX) && !l.startsWith(this.TN));
2403
+ }
2404
+ }
2405
+ return linesToken;
2406
+ }
2407
+ /**
2408
+ * Parses the tokens of the line and updates the TAF object
2409
+ * @param taf TAF object to update
2410
+ * @param lineTokens the array of tokens representing a line
2411
+ */
2412
+ parseLine(taf, lineTokens) {
2413
+ let index = 1;
2414
+ let trend;
2415
+ if (lineTokens[0].startsWith(this.FM)) {
2416
+ trend = {
2417
+ ...this.makeEmptyTAFTrend(),
2418
+ type: WeatherChangeType.FM,
2419
+ validity: parseFromValidity(lineTokens[0]),
2420
+ };
2421
+ }
2422
+ else if (lineTokens[0].startsWith(this.PROB)) {
2423
+ const validity = this.findLineValidity(index, lineTokens);
2424
+ if (!validity)
2425
+ return;
2426
+ trend = {
2427
+ ...this.makeEmptyTAFTrend(),
2428
+ type: WeatherChangeType.PROB,
2429
+ validity,
2430
+ };
2431
+ if (lineTokens.length > 1 && lineTokens[1] === this.TEMPO) {
2432
+ trend = {
2433
+ ...this.makeEmptyTAFTrend(),
2434
+ type: WeatherChangeType[lineTokens[1]],
2435
+ validity,
2436
+ };
2437
+ index = 2;
2438
+ }
2439
+ trend.probability = +lineTokens[0].slice(4);
2440
+ }
2441
+ else {
2442
+ const validity = this.findLineValidity(index, lineTokens);
2443
+ if (!validity)
2444
+ return;
2445
+ trend = {
2446
+ ...this.makeEmptyTAFTrend(),
2447
+ type: WeatherChangeType[lineTokens[0]],
2448
+ validity,
2449
+ };
2450
+ }
2451
+ this.parseTrend(index, lineTokens, trend);
2452
+ taf.trends.push(trend);
2453
+ }
2454
+ /**
2455
+ * Finds a non-FM validity in a line
2456
+ * @param index the index at which the array should be parsed
2457
+ * @param line The array of string containing the line
2458
+ * @param trend The trend object to update
2459
+ */
2460
+ findLineValidity(index, line) {
2461
+ let validity;
2462
+ for (let i = index; i < line.length; i++) {
2463
+ if (__classPrivateFieldGet(this, _TAFParser_validityPattern, "f").test(line[i]))
2464
+ validity = parseValidity(line[i]);
2465
+ }
2466
+ return validity;
2467
+ }
2468
+ /**
2469
+ * Parses a trend of the TAF
2470
+ * @param index the index at which the array should be parsed
2471
+ * @param line The array of string containing the line
2472
+ * @param trend The trend object to update
2473
+ */
2474
+ parseTrend(index, line, trend) {
2475
+ for (let i = index; i < line.length; i++) {
2476
+ if (line[i] === this.RMK) {
2477
+ parseRemark(trend, line, i, this.locale);
2478
+ break;
2479
+ }
2480
+ // already parsed
2481
+ else if (__classPrivateFieldGet(this, _TAFParser_validityPattern, "f").test(line[i]))
2482
+ continue;
2483
+ else
2484
+ super.generalParse(trend, line[i]);
2485
+ }
2486
+ }
2487
+ makeEmptyTAFTrend() {
2488
+ return {
2489
+ remarks: [],
2490
+ clouds: [],
2491
+ weatherConditions: [],
2492
+ };
2493
+ }
2494
+ }
2495
+ _TAFParser_validityPattern = new WeakMap();
2496
+ class RemarkParser {
2497
+ constructor(locale) {
2498
+ this.locale = locale;
2499
+ _RemarkParser_supplier.set(this, new RemarkCommandSupplier(this.locale));
2500
+ }
2501
+ parse(code) {
2502
+ let rmkStr = code;
2503
+ let rmkList = [];
2504
+ while (rmkStr) {
2505
+ try {
2506
+ [rmkStr, rmkList] = __classPrivateFieldGet(this, _RemarkParser_supplier, "f").get(rmkStr).execute(rmkStr, rmkList);
2507
+ }
2508
+ catch (e) {
2509
+ if (e instanceof CommandExecutionError) {
2510
+ [rmkStr, rmkList] = __classPrivateFieldGet(this, _RemarkParser_supplier, "f").defaultCommand.execute(rmkStr, rmkList);
2511
+ }
2512
+ else {
2513
+ throw e;
2514
+ }
2515
+ }
2516
+ }
2517
+ return rmkList;
2518
+ }
2519
+ }
2520
+ _RemarkParser_supplier = new WeakMap();
2521
+
2522
+ /**
2523
+ *
2524
+ * @param date Ideally the date the report was issued. However, any date within
2525
+ * ~14 days of the report will work.
2526
+ * @param day Day of the month (from the report)
2527
+ * @param hour Hour (from the report)
2528
+ * @param minute Minute (from the report)
2529
+ * @returns
2530
+ */
2531
+ function determineReportIssuedDate(date, day, hour, minute) {
2532
+ const months = [
2533
+ setDateComponents(addMonthsUTC(date, -1), day, hour, minute),
2534
+ setDateComponents(new Date(date), day, hour, minute),
2535
+ setDateComponents(addMonthsUTC(date, 1), day, hour, minute),
2536
+ ];
2537
+ return months
2538
+ .map((d) => ({
2539
+ date: d,
2540
+ difference: Math.abs(d.getTime() - date.getTime()),
2541
+ }))
2542
+ .sort((a, b) => a.difference - b.difference)[0].date;
2543
+ }
2544
+ function getReportDate(issued, day, hour, minute = 0) {
2545
+ let date = new Date(issued);
2546
+ if (day < date.getUTCDate()) {
2547
+ date = addMonthsUTC(date, 1);
2548
+ }
2549
+ date.setUTCDate(day);
2550
+ date.setUTCHours(hour);
2551
+ if (minute != null)
2552
+ date.setUTCMinutes(minute);
2553
+ return date;
2554
+ }
2555
+ function setDateComponents(date, day, hour, minute) {
2556
+ date.setUTCDate(day);
2557
+ date.setUTCHours(hour);
2558
+ if (minute != null)
2559
+ date.setUTCMinutes(minute);
2560
+ return date;
2561
+ }
2562
+ function addMonthsUTC(date, count) {
2563
+ if (date && count) {
2564
+ let m, d = (date = new Date(+date)).getUTCDate();
2565
+ date.setUTCMonth(date.getUTCMonth() + count, 1);
2566
+ m = date.getUTCMonth();
2567
+ date.setUTCDate(d);
2568
+ if (date.getUTCMonth() !== m)
2569
+ date.setUTCDate(0);
2570
+ }
2571
+ return date;
2572
+ }
2573
+
2574
+ function metarDatesHydrator(report, date) {
2575
+ return {
2576
+ ...report,
2577
+ issued: determineReportIssuedDate(date, report.day, report.hour, report.minute),
2578
+ };
2579
+ }
2580
+
2581
+ function tafDatesHydrator(report, date) {
2582
+ const issued = determineReportIssuedDate(date, report.day, report.hour, report.minute);
2583
+ return {
2584
+ ...report,
2585
+ issued,
2586
+ validity: {
2587
+ ...report.validity,
2588
+ start: getReportDate(issued, report.validity.startDay, report.validity.startHour),
2589
+ end: getReportDate(issued, report.validity.endDay, report.validity.endHour),
2590
+ },
2591
+ trends: report.trends.map((trend) => ({
2592
+ ...trend,
2593
+ validity: (() => {
2594
+ switch (trend.type) {
2595
+ case WeatherChangeType.FM:
2596
+ return {
2597
+ ...trend.validity,
2598
+ start: getReportDate(issued, trend.validity.startDay, trend.validity.startHour, trend.validity.startMinutes),
2599
+ };
2600
+ default:
2601
+ return {
2602
+ ...trend.validity,
2603
+ start: getReportDate(issued, trend.validity.startDay, trend.validity.startHour),
2604
+ end: getReportDate(issued, trend.validity.endDay, trend.validity.endHour),
2605
+ };
2606
+ }
2607
+ })(),
2608
+ })),
2609
+ };
2610
+ }
2611
+
2612
+ function getForecastFromTAF(taf) {
2613
+ return {
2614
+ issued: taf.issued,
2615
+ station: taf.station,
2616
+ message: taf.message,
2617
+ start: getReportDate(taf.issued, taf.validity.startDay, taf.validity.startHour),
2618
+ end: getReportDate(taf.issued, taf.validity.endDay, taf.validity.endHour),
2619
+ forecast: [makeInitialForecast(taf), ...taf.trends],
2620
+ };
2621
+ }
2622
+ /**
2623
+ * Treat the base of the TAF as a FM
2624
+ */
2625
+ function makeInitialForecast(taf) {
2626
+ return {
2627
+ wind: taf.wind,
2628
+ visibility: taf.visibility,
2629
+ verticalVisibility: taf.verticalVisibility,
2630
+ windShear: taf.windShear,
2631
+ cavok: taf.cavok,
2632
+ remark: taf.remark,
2633
+ remarks: taf.remarks,
2634
+ clouds: taf.clouds,
2635
+ weatherConditions: taf.weatherConditions,
2636
+ validity: {
2637
+ // End day/hour are for end of the entire TAF
2638
+ startDay: taf.validity.startDay,
2639
+ startHour: taf.validity.startHour,
2640
+ startMinutes: 0,
2641
+ start: taf.validity.start,
2642
+ },
2643
+ };
2644
+ }
2645
+ class TimestampOutOfBoundsError extends ParseError {
2646
+ constructor(message) {
2647
+ super(message);
2648
+ this.name = "TimestampOutOfBoundsError";
2649
+ Object.setPrototypeOf(this, new.target.prototype);
2650
+ }
2651
+ }
2652
+ function getCompositeForecastForDate(date, forecastContainer) {
2653
+ // Validity bounds check
2654
+ if (date.getTime() > forecastContainer.end.getTime() ||
2655
+ date.getTime() < forecastContainer.start.getTime())
2656
+ throw new TimestampOutOfBoundsError("Provided timestamp is outside the report validity period");
2657
+ let base;
2658
+ let additional = [];
2659
+ for (const forecast of forecastContainer.forecast) {
2660
+ if (!forecast.validity.end &&
2661
+ forecast.validity.start.getTime() <= date.getTime()) {
2662
+ // Is FM or initial forecast
2663
+ base = forecast;
2664
+ }
2665
+ if (forecast.validity.end &&
2666
+ forecast.validity.end.getTime() - date.getTime() > 0 &&
2667
+ forecast.validity.start.getTime() - date.getTime() <= 0) {
2668
+ // Is BECMG or TEMPO
2669
+ additional.push(forecast);
2670
+ }
2671
+ }
2672
+ if (!base)
2673
+ throw new UnexpectedParseError("Unable to find trend for date");
2674
+ return { base, additional };
2675
+ }
2676
+
2677
+ function parseMetar(rawMetar, options) {
2678
+ return parse(rawMetar, options, MetarParser, metarDatesHydrator);
2679
+ }
2680
+ function parseTAF(rawTAF, options) {
2681
+ return parse(rawTAF, options, TAFParser, tafDatesHydrator);
2682
+ }
2683
+ function parseTAFAsForecast(rawTAF, options) {
2684
+ const taf = parseTAF(rawTAF, options);
2685
+ return getForecastFromTAF(taf);
2686
+ }
2687
+ function parse(rawReport, options, parser, datesHydrator) {
2688
+ const lang = options?.locale || en;
2689
+ try {
2690
+ const report = new parser(lang).parse(rawReport);
2691
+ if (options && "date" in options) {
2692
+ return datesHydrator(report, options.date);
2693
+ }
2694
+ return report;
2695
+ }
2696
+ catch (e) {
2697
+ if (e instanceof ParseError)
2698
+ throw e;
2699
+ throw new InvalidWeatherStatementError(e);
2700
+ }
2701
+ }
2702
+
2703
+ export { CloudQuantity, CloudType, CommandExecutionError, Descriptive, Direction, DistanceUnit, Intensity, InvalidWeatherStatementError, ParseError, Phenomenon, RemarkType, RunwayInfoTrend, RunwayInfoUnit, TimeIndicator, TimestampOutOfBoundsError, UnexpectedParseError, ValueIndicator, WeatherChangeType, getCompositeForecastForDate, isWeatherConditionValid, parseMetar, parseTAF, parseTAFAsForecast };