metar-taf-parser 1.2.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. package/README.md +85 -12
  2. package/dist/command/common.js +13 -10
  3. package/dist/command/metar/AltimeterCommand.d.ts +7 -0
  4. package/dist/command/metar/AltimeterCommand.js +26 -0
  5. package/dist/command/metar/AltimeterMercuryCommand.d.ts +7 -0
  6. package/dist/command/metar/AltimeterMercuryCommand.js +51 -0
  7. package/dist/command/metar/RunwayCommand.d.ts +7 -0
  8. package/dist/command/metar/RunwayCommand.js +60 -0
  9. package/dist/command/metar/TemperatureCommand.d.ts +7 -0
  10. package/dist/command/metar/TemperatureCommand.js +51 -0
  11. package/dist/command/metar.d.ts +1 -22
  12. package/dist/command/metar.js +10 -113
  13. package/dist/command/remark/CeilingHeightCommand.d.ts +18 -0
  14. package/dist/command/remark/CeilingHeightCommand.js +40 -0
  15. package/dist/command/remark/CeilingSecondLocationCommand.d.ts +12 -0
  16. package/dist/command/remark/CeilingSecondLocationCommand.js +40 -0
  17. package/dist/command/remark/Command.d.ts +8 -0
  18. package/dist/command/remark/Command.js +9 -0
  19. package/dist/command/remark/DefaultCommand.d.ts +11 -0
  20. package/dist/command/remark/DefaultCommand.js +38 -0
  21. package/dist/command/remark/HailSizeCommand.d.ts +11 -0
  22. package/dist/command/remark/HailSizeCommand.js +37 -0
  23. package/dist/command/remark/HourlyMaximumMinimumTemperatureCommand.d.ts +18 -0
  24. package/dist/command/remark/HourlyMaximumMinimumTemperatureCommand.js +39 -0
  25. package/dist/command/remark/HourlyMaximumTemperatureCommand.d.ts +14 -0
  26. package/dist/command/remark/HourlyMaximumTemperatureCommand.js +38 -0
  27. package/dist/command/remark/HourlyMinimumTemperatureCommand.d.ts +14 -0
  28. package/dist/command/remark/HourlyMinimumTemperatureCommand.js +38 -0
  29. package/dist/command/remark/HourlyPrecipitationAmountCommand.d.ts +14 -0
  30. package/dist/command/remark/HourlyPrecipitationAmountCommand.js +38 -0
  31. package/dist/command/remark/HourlyPressureCommand.d.ts +32 -0
  32. package/dist/command/remark/HourlyPressureCommand.js +40 -0
  33. package/dist/command/remark/HourlyTemperatureDewPointCommand.d.ts +18 -0
  34. package/dist/command/remark/HourlyTemperatureDewPointCommand.js +52 -0
  35. package/dist/command/remark/IceAccretionCommand.d.ts +15 -0
  36. package/dist/command/remark/IceAccretionCommand.js +38 -0
  37. package/dist/command/remark/ObscurationCommand.d.ts +14 -0
  38. package/dist/command/remark/ObscurationCommand.js +44 -0
  39. package/dist/command/remark/PrecipitationAmount24HourCommand.d.ts +14 -0
  40. package/dist/command/remark/PrecipitationAmount24HourCommand.js +39 -0
  41. package/dist/command/remark/PrecipitationAmount36HourCommand.d.ts +15 -0
  42. package/dist/command/remark/PrecipitationAmount36HourCommand.js +41 -0
  43. package/dist/command/remark/PrecipitationBegCommand.d.ts +15 -0
  44. package/dist/command/remark/PrecipitationBegCommand.js +45 -0
  45. package/dist/command/remark/PrecipitationBegEndCommand.d.ts +17 -0
  46. package/dist/command/remark/PrecipitationBegEndCommand.js +46 -0
  47. package/dist/command/remark/PrecipitationEndCommand.d.ts +15 -0
  48. package/dist/command/remark/PrecipitationEndCommand.js +45 -0
  49. package/dist/command/remark/PrevailingVisibilityCommand.d.ts +12 -0
  50. package/dist/command/remark/PrevailingVisibilityCommand.js +40 -0
  51. package/dist/command/remark/SeaLevelPressureCommand.d.ts +11 -0
  52. package/dist/command/remark/SeaLevelPressureCommand.js +39 -0
  53. package/dist/command/remark/SecondLocationVisibilityCommand.d.ts +12 -0
  54. package/dist/command/remark/SecondLocationVisibilityCommand.js +40 -0
  55. package/dist/command/remark/SectorVisibilityCommand.d.ts +13 -0
  56. package/dist/command/remark/SectorVisibilityCommand.js +41 -0
  57. package/dist/command/remark/SmallHailSizeCommand.d.ts +11 -0
  58. package/dist/command/remark/SmallHailSizeCommand.js +37 -0
  59. package/dist/command/remark/SnowDepthCommand.d.ts +11 -0
  60. package/dist/command/remark/SnowDepthCommand.js +38 -0
  61. package/dist/command/remark/SnowIncreaseCommand.d.ts +12 -0
  62. package/dist/command/remark/SnowIncreaseCommand.js +40 -0
  63. package/dist/command/remark/SnowPelletsCommand.d.ts +11 -0
  64. package/dist/command/remark/SnowPelletsCommand.js +37 -0
  65. package/dist/command/remark/SunshineDurationCommand.d.ts +11 -0
  66. package/dist/command/remark/SunshineDurationCommand.js +38 -0
  67. package/dist/command/remark/SurfaceVisibilityCommand.d.ts +11 -0
  68. package/dist/command/remark/SurfaceVisibilityCommand.js +38 -0
  69. package/dist/command/remark/ThunderStormLocationCommand.d.ts +12 -0
  70. package/dist/command/remark/ThunderStormLocationCommand.js +40 -0
  71. package/dist/command/remark/ThunderStormLocationMovingCommand.d.ts +19 -0
  72. package/dist/command/remark/ThunderStormLocationMovingCommand.js +42 -0
  73. package/dist/command/remark/TornadicActivityBegCommand.d.ts +16 -0
  74. package/dist/command/remark/TornadicActivityBegCommand.js +44 -0
  75. package/dist/command/remark/TornadicActivityBegEndCommand.d.ts +18 -0
  76. package/dist/command/remark/TornadicActivityBegEndCommand.js +46 -0
  77. package/dist/command/remark/TornadicActivityEndCommand.d.ts +16 -0
  78. package/dist/command/remark/TornadicActivityEndCommand.js +44 -0
  79. package/dist/command/remark/TowerVisibilityCommand.d.ts +11 -0
  80. package/dist/command/remark/TowerVisibilityCommand.js +38 -0
  81. package/dist/command/remark/VariableSkyCommand.d.ts +12 -0
  82. package/dist/command/remark/VariableSkyCommand.js +41 -0
  83. package/dist/command/remark/VariableSkyHeightCommand.d.ts +13 -0
  84. package/dist/command/remark/VariableSkyHeightCommand.js +43 -0
  85. package/dist/command/remark/VirgaDirectionCommand.d.ts +12 -0
  86. package/dist/command/remark/VirgaDirectionCommand.js +40 -0
  87. package/dist/command/remark/WaterEquivalentSnowCommand.d.ts +11 -0
  88. package/dist/command/remark/WaterEquivalentSnowCommand.js +38 -0
  89. package/dist/command/remark/WindPeakCommandCommand.d.ts +17 -0
  90. package/dist/command/remark/WindPeakCommandCommand.js +42 -0
  91. package/dist/command/remark/WindShiftCommand.d.ts +12 -0
  92. package/dist/command/remark/WindShiftCommand.js +38 -0
  93. package/dist/command/remark/WindShiftFropaCommand.d.ts +12 -0
  94. package/dist/command/remark/WindShiftFropaCommand.js +38 -0
  95. package/dist/command/remark.d.ts +100 -194
  96. package/dist/command/remark.js +135 -753
  97. package/dist/commons/converter.d.ts +14 -2
  98. package/dist/commons/converter.js +53 -5
  99. package/dist/commons/errors.d.ts +6 -2
  100. package/dist/commons/errors.js +15 -8
  101. package/dist/commons/i18n.d.ts +2 -2
  102. package/dist/commons/i18n.js +9 -3
  103. package/dist/dates/metar.d.ts +5 -0
  104. package/dist/dates/metar.js +8 -0
  105. package/dist/dates/taf.d.ts +28 -0
  106. package/dist/dates/taf.js +17 -0
  107. package/dist/forecast/forecast.d.ts +36 -0
  108. package/dist/forecast/forecast.js +73 -0
  109. package/dist/helpers/date.d.ts +11 -0
  110. package/dist/helpers/date.js +56 -0
  111. package/dist/helpers/helpers.d.ts +7 -0
  112. package/dist/helpers/helpers.js +14 -1
  113. package/dist/index.d.ts +23 -2
  114. package/dist/index.js +24 -7
  115. package/dist/model/enum.d.ts +44 -0
  116. package/dist/model/enum.js +50 -1
  117. package/dist/model/model.d.ts +84 -19
  118. package/dist/model/model.js +3 -1
  119. package/dist/parser/parser.d.ts +13 -6
  120. package/dist/parser/parser.js +63 -29
  121. package/package.json +3 -3
@@ -1,9 +1,21 @@
1
+ import { Distance } from "../model/model";
1
2
  export declare function degreesToCardinal(input: number | string): string;
2
- export declare function convertVisibility(input: string): string;
3
+ export declare function convertVisibility(input: string): Distance;
4
+ /**
5
+ * @param input May start with P or M, and must end with SM
6
+ * @returns Distance
7
+ */
8
+ export declare function convertNauticalMilesVisibility(input: string): Distance;
9
+ /**
10
+ * Converts fractional and/or whole amounts
11
+ *
12
+ * Example "1/3", "1 1/3" and "1"
13
+ */
14
+ export declare function convertFractionalAmount(input: string): number;
3
15
  export declare function convertTemperature(input: string): number;
4
16
  export declare function convertInchesMercuryToPascal(input: number): number;
5
17
  /**
6
18
  * Converts number `.toFixed(1)` before outputting to match python implementation
7
19
  */
8
- export declare function convertTemperatureRemarks(sign: string, temperature: string): string;
20
+ export declare function convertTemperatureRemarks(sign: string, temperature: string): number;
9
21
  export declare function convertPrecipitationAmount(amount: string): number;
@@ -1,7 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.convertPrecipitationAmount = exports.convertTemperatureRemarks = exports.convertInchesMercuryToPascal = exports.convertTemperature = exports.convertVisibility = exports.degreesToCardinal = void 0;
3
+ exports.convertPrecipitationAmount = exports.convertTemperatureRemarks = exports.convertInchesMercuryToPascal = exports.convertTemperature = exports.convertFractionalAmount = exports.convertNauticalMilesVisibility = exports.convertVisibility = exports.degreesToCardinal = void 0;
4
4
  const helpers_1 = require("../helpers/helpers");
5
+ const enum_1 = require("../model/enum");
5
6
  function degreesToCardinal(input) {
6
7
  const degrees = +input;
7
8
  if (isNaN(degrees))
@@ -30,10 +31,57 @@ function degreesToCardinal(input) {
30
31
  exports.degreesToCardinal = degreesToCardinal;
31
32
  function convertVisibility(input) {
32
33
  if (input === "9999")
33
- return "> 10km";
34
- return `${+input}m`;
34
+ return {
35
+ indicator: enum_1.ValueIndicator.GreaterThan,
36
+ value: +input,
37
+ unit: enum_1.DistanceUnit.Meters,
38
+ };
39
+ return {
40
+ value: +input,
41
+ unit: enum_1.DistanceUnit.Meters,
42
+ };
35
43
  }
36
44
  exports.convertVisibility = convertVisibility;
45
+ /**
46
+ * @param input May start with P or M, and must end with SM
47
+ * @returns Distance
48
+ */
49
+ function convertNauticalMilesVisibility(input) {
50
+ let indicator;
51
+ let index = 0;
52
+ if (input.startsWith("P")) {
53
+ indicator = enum_1.ValueIndicator.GreaterThan;
54
+ index = 1;
55
+ }
56
+ else if (input.startsWith("M")) {
57
+ indicator = enum_1.ValueIndicator.LessThan;
58
+ index = 1;
59
+ }
60
+ return {
61
+ indicator,
62
+ value: convertFractionalAmount(input.slice(index, -2)),
63
+ unit: enum_1.DistanceUnit.StatuteMiles,
64
+ };
65
+ }
66
+ exports.convertNauticalMilesVisibility = convertNauticalMilesVisibility;
67
+ /**
68
+ * Converts fractional and/or whole amounts
69
+ *
70
+ * Example "1/3", "1 1/3" and "1"
71
+ */
72
+ function convertFractionalAmount(input) {
73
+ const [whole, fraction] = input.split(" ");
74
+ if (!fraction)
75
+ return parseFraction(whole);
76
+ return +whole + parseFraction(fraction);
77
+ }
78
+ exports.convertFractionalAmount = convertFractionalAmount;
79
+ function parseFraction(input) {
80
+ const [top, bottom] = input.split("/");
81
+ if (!bottom)
82
+ return +top;
83
+ return Math.round((+top / +bottom) * 100) / 100;
84
+ }
37
85
  function convertTemperature(input) {
38
86
  if (input.startsWith("M"))
39
87
  return -(0, helpers_1.pySplit)(input, "M")[1];
@@ -50,8 +98,8 @@ exports.convertInchesMercuryToPascal = convertInchesMercuryToPascal;
50
98
  function convertTemperatureRemarks(sign, temperature) {
51
99
  const temp = +temperature / 10;
52
100
  if (sign === "0")
53
- return temp.toFixed(1);
54
- return (-temp).toFixed(1);
101
+ return temp;
102
+ return -temp;
55
103
  }
56
104
  exports.convertTemperatureRemarks = convertTemperatureRemarks;
57
105
  function convertPrecipitationAmount(amount) {
@@ -7,9 +7,13 @@ export declare class InvalidWeatherStatementError extends ParseError {
7
7
  cause?: unknown;
8
8
  constructor(cause?: unknown);
9
9
  }
10
- export declare class TranslationError extends ParseError {
10
+ /**
11
+ * Thrown when command marked as canParse, but couldn't parse when
12
+ * executing (for example, an invalid CloudQuantity)
13
+ */
14
+ export declare class CommandExecutionError extends ParseError {
11
15
  name: string;
12
- constructor(missingLocale: string);
16
+ constructor(message: string);
13
17
  }
14
18
  /**
15
19
  * Should never occur
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.UnexpectedParseError = exports.TranslationError = exports.InvalidWeatherStatementError = exports.ParseError = void 0;
3
+ exports.UnexpectedParseError = exports.CommandExecutionError = exports.InvalidWeatherStatementError = exports.ParseError = void 0;
4
4
  class ParseError extends Error {
5
5
  constructor(message) {
6
6
  super(message);
@@ -11,21 +11,28 @@ class ParseError extends Error {
11
11
  exports.ParseError = ParseError;
12
12
  class InvalidWeatherStatementError extends ParseError {
13
13
  constructor(cause) {
14
- super(`Invalid weather string.`);
14
+ super(typeof cause === "string"
15
+ ? `Invalid weather string: ${cause}`
16
+ : "Invalid weather string");
15
17
  this.name = "InvalidWeatherStatementError";
16
18
  Object.setPrototypeOf(this, new.target.prototype);
17
- this.cause = cause;
19
+ if (typeof cause !== "string")
20
+ this.cause = cause;
18
21
  }
19
22
  }
20
23
  exports.InvalidWeatherStatementError = InvalidWeatherStatementError;
21
- class TranslationError extends ParseError {
22
- constructor(missingLocale) {
23
- super(`Missing translation "${missingLocale}"`);
24
- this.name = "TranslationError";
24
+ /**
25
+ * Thrown when command marked as canParse, but couldn't parse when
26
+ * executing (for example, an invalid CloudQuantity)
27
+ */
28
+ class CommandExecutionError extends ParseError {
29
+ constructor(message) {
30
+ super(message);
31
+ this.name = "CommandExecutionError";
25
32
  Object.setPrototypeOf(this, new.target.prototype);
26
33
  }
27
34
  }
28
- exports.TranslationError = TranslationError;
35
+ exports.CommandExecutionError = CommandExecutionError;
29
36
  /**
30
37
  * Should never occur
31
38
  */
@@ -8,5 +8,5 @@ declare type PathsToStringProps<T> = T extends string ? [] : {
8
8
  [K in Extract<keyof T, string>]: [K, ...PathsToStringProps<T[K]>];
9
9
  }[Extract<keyof T, string>];
10
10
  declare type Join<T extends string[], D extends string> = T extends [] ? never : T extends [infer F] ? F : T extends [infer F, ...infer R] ? F extends string ? `${F}${D}${Join<Extract<R, string[]>, D>}` : never : string;
11
- export declare function _(path: Join<PathsToStringProps<typeof en>, ".">, lang: Locale): string;
12
- export declare function format(message: string, ...args: unknown[]): string;
11
+ export declare function _(path: Join<PathsToStringProps<typeof en>, ".">, lang: Locale): string | undefined;
12
+ export declare function format(message: string | undefined, ...args: unknown[]): string | undefined;
@@ -6,19 +6,25 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.format = exports._ = void 0;
7
7
  const en_1 = __importDefault(require("../locale/en"));
8
8
  const helpers_1 = require("../helpers/helpers");
9
- const errors_1 = require("./errors");
10
9
  exports.default = en_1.default;
11
10
  function _(path, lang) {
12
11
  const translation = (0, helpers_1.resolve)(lang, path);
13
12
  if (!translation || typeof translation !== "string")
14
- throw new errors_1.TranslationError(path);
13
+ return undefined;
15
14
  return translation;
16
15
  }
17
16
  exports._ = _;
18
17
  function format(message, ...args) {
18
+ if (!message)
19
+ return;
20
+ // All arguments must be defined, otherwise nothing is returned
21
+ for (let i = 0; i < args.length; i++) {
22
+ if (args[i] === undefined)
23
+ return;
24
+ }
19
25
  return message.replace(/{\d+}/g, (match) => {
20
26
  const index = +match.slice(1, -1);
21
- return args[index] !== undefined ? `${args[index]}` : "";
27
+ return `${args[index]}`;
22
28
  });
23
29
  }
24
30
  exports.format = format;
@@ -0,0 +1,5 @@
1
+ import { IMetar } from "../model/model";
2
+ export interface IMetarDated extends IMetar {
3
+ issued: Date;
4
+ }
5
+ export declare function metarDatesHydrator(report: IMetar, date: Date): IMetarDated;
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.metarDatesHydrator = void 0;
4
+ const date_1 = require("../helpers/date");
5
+ function metarDatesHydrator(report, date) {
6
+ return Object.assign(Object.assign({}, report), { issued: (0, date_1.determineReportIssuedDate)(date, report.day, report.hour, report.minute) });
7
+ }
8
+ exports.metarDatesHydrator = metarDatesHydrator;
@@ -0,0 +1,28 @@
1
+ import { WeatherChangeType } from "../model/enum";
2
+ import { IAbstractTrend, IFMValidity, ITAF, IBaseTAFTrend, IValidity } from "../model/model";
3
+ export declare type TAFTrendDated = IAbstractTrend & IBaseTAFTrend & {
4
+ validity: IBaseTAFTrend["validity"] & {
5
+ start: Date;
6
+ end?: Date;
7
+ };
8
+ } & ({
9
+ type: WeatherChangeType.FM;
10
+ validity: IFMValidity & {
11
+ start: Date;
12
+ };
13
+ } | {
14
+ type: WeatherChangeType;
15
+ validity: IValidity & {
16
+ start: Date;
17
+ end: Date;
18
+ };
19
+ });
20
+ export interface ITAFDated extends ITAF {
21
+ issued: Date;
22
+ validity: ITAF["validity"] & {
23
+ start: Date;
24
+ end: Date;
25
+ };
26
+ trends: TAFTrendDated[];
27
+ }
28
+ export declare function tafDatesHydrator(report: ITAF, date: Date): ITAFDated;
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.tafDatesHydrator = void 0;
4
+ const enum_1 = require("../model/enum");
5
+ const date_1 = require("../helpers/date");
6
+ function tafDatesHydrator(report, date) {
7
+ const issued = (0, date_1.determineReportIssuedDate)(date, report.day, report.hour, report.minute);
8
+ return Object.assign(Object.assign({}, report), { issued, validity: Object.assign(Object.assign({}, report.validity), { start: (0, date_1.getReportDate)(issued, report.validity.startDay, report.validity.startHour), end: (0, date_1.getReportDate)(issued, report.validity.endDay, report.validity.endHour) }), trends: report.trends.map((trend) => (Object.assign(Object.assign({}, trend), { validity: (() => {
9
+ switch (trend.type) {
10
+ case enum_1.WeatherChangeType.FM:
11
+ return Object.assign(Object.assign({}, trend.validity), { start: (0, date_1.getReportDate)(issued, trend.validity.startDay, trend.validity.startHour, trend.validity.startMinutes) });
12
+ default:
13
+ return Object.assign(Object.assign({}, trend.validity), { start: (0, date_1.getReportDate)(issued, trend.validity.startDay, trend.validity.startHour), end: (0, date_1.getReportDate)(issued, trend.validity.endDay, trend.validity.endHour) });
14
+ }
15
+ })() }))) });
16
+ }
17
+ exports.tafDatesHydrator = tafDatesHydrator;
@@ -0,0 +1,36 @@
1
+ import { TAFTrendDated } from "../dates/taf";
2
+ import { ITAFDated } from "../dates/taf";
3
+ import { ParseError } from "../commons/errors";
4
+ /**
5
+ * The initial forecast, extracted from the first line of the TAF, does not have
6
+ * a trend type (FM, BECMG, etc)
7
+ */
8
+ export declare type Forecast = Omit<TAFTrendDated, "type"> & Partial<Pick<TAFTrendDated, "type">>;
9
+ export interface IForecastContainer {
10
+ station: string;
11
+ issued: Date;
12
+ start: Date;
13
+ end: Date;
14
+ message: string;
15
+ forecast: Forecast[];
16
+ }
17
+ export declare function getForecastFromTAF(taf: ITAFDated): IForecastContainer;
18
+ export interface ICompositeForecast {
19
+ /**
20
+ * The base forecast (type is `FM` or initial group)
21
+ */
22
+ base: Forecast;
23
+ /**
24
+ * Any forecast here should pre-empt the base forecast. These forecasts may
25
+ * have probabilities of occuring, be temporary, or otherwise notable
26
+ * precipitation events
27
+ *
28
+ * `type` is (`BECMG`, `TEMPO` or `PROB`)
29
+ */
30
+ additional: Forecast[];
31
+ }
32
+ export declare class TimestampOutOfBoundsError extends ParseError {
33
+ name: string;
34
+ constructor(message?: string);
35
+ }
36
+ export declare function getCompositeForecastForDate(date: Date, forecastContainer: IForecastContainer): ICompositeForecast;
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getCompositeForecastForDate = exports.TimestampOutOfBoundsError = exports.getForecastFromTAF = void 0;
4
+ const date_1 = require("../helpers/date");
5
+ const errors_1 = require("../commons/errors");
6
+ function getForecastFromTAF(taf) {
7
+ return {
8
+ issued: taf.issued,
9
+ station: taf.station,
10
+ message: taf.message,
11
+ start: (0, date_1.getReportDate)(taf.issued, taf.validity.startDay, taf.validity.startHour),
12
+ end: (0, date_1.getReportDate)(taf.issued, taf.validity.endDay, taf.validity.endHour),
13
+ forecast: [makeInitialForecast(taf), ...taf.trends],
14
+ };
15
+ }
16
+ exports.getForecastFromTAF = getForecastFromTAF;
17
+ /**
18
+ * Treat the base of the TAF as a FM
19
+ */
20
+ function makeInitialForecast(taf) {
21
+ return {
22
+ wind: taf.wind,
23
+ visibility: taf.visibility,
24
+ verticalVisibility: taf.verticalVisibility,
25
+ windShear: taf.windShear,
26
+ cavok: taf.cavok,
27
+ remark: taf.remark,
28
+ remarks: taf.remarks,
29
+ clouds: taf.clouds,
30
+ weatherConditions: taf.weatherConditions,
31
+ validity: {
32
+ // End day/hour are for end of the entire TAF
33
+ startDay: taf.validity.startDay,
34
+ startHour: taf.validity.startHour,
35
+ startMinutes: 0,
36
+ start: taf.validity.start,
37
+ },
38
+ };
39
+ }
40
+ class TimestampOutOfBoundsError extends errors_1.ParseError {
41
+ constructor(message) {
42
+ super(message);
43
+ this.name = "TimestampOutOfBoundsError";
44
+ Object.setPrototypeOf(this, new.target.prototype);
45
+ }
46
+ }
47
+ exports.TimestampOutOfBoundsError = TimestampOutOfBoundsError;
48
+ function getCompositeForecastForDate(date, forecastContainer) {
49
+ // Validity bounds check
50
+ if (date.getTime() > forecastContainer.end.getTime() ||
51
+ date.getTime() < forecastContainer.start.getTime())
52
+ throw new TimestampOutOfBoundsError("Provided timestamp is outside the report validity period");
53
+ let base;
54
+ let additional = [];
55
+ for (let i = 0; i < forecastContainer.forecast.length; i++) {
56
+ const forecast = forecastContainer.forecast[i];
57
+ if (!forecast.validity.end &&
58
+ forecast.validity.start.getTime() <= date.getTime()) {
59
+ // Is FM or initial forecast
60
+ base = forecast;
61
+ }
62
+ if (forecast.validity.end &&
63
+ forecast.validity.end.getTime() - date.getTime() > 0 &&
64
+ forecast.validity.start.getTime() - date.getTime() <= 0) {
65
+ // Is BECMG or TEMPO
66
+ additional.push(forecast);
67
+ }
68
+ }
69
+ if (!base)
70
+ throw new errors_1.UnexpectedParseError("Unable to find trend for date");
71
+ return { base, additional };
72
+ }
73
+ exports.getCompositeForecastForDate = getCompositeForecastForDate;
@@ -0,0 +1,11 @@
1
+ /**
2
+ *
3
+ * @param date Ideally the date the report was issued. However, any date within
4
+ * ~14 days of the report will work.
5
+ * @param day Day of the month (from the report)
6
+ * @param hour Hour (from the report)
7
+ * @param minute Minute (from the report)
8
+ * @returns
9
+ */
10
+ export declare function determineReportIssuedDate(date: Date, day: number, hour: number, minute?: number): Date;
11
+ export declare function getReportDate(issued: Date, day: number, hour: number, minute?: number): Date;
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getReportDate = exports.determineReportIssuedDate = void 0;
4
+ /**
5
+ *
6
+ * @param date Ideally the date the report was issued. However, any date within
7
+ * ~14 days of the report will work.
8
+ * @param day Day of the month (from the report)
9
+ * @param hour Hour (from the report)
10
+ * @param minute Minute (from the report)
11
+ * @returns
12
+ */
13
+ function determineReportIssuedDate(date, day, hour, minute) {
14
+ const months = [
15
+ setDateComponents(addMonthsUTC(date, -1), day, hour, minute),
16
+ setDateComponents(new Date(date), day, hour, minute),
17
+ setDateComponents(addMonthsUTC(date, 1), day, hour, minute),
18
+ ];
19
+ return months
20
+ .map((d) => ({
21
+ date: d,
22
+ difference: Math.abs(d.getTime() - date.getTime()),
23
+ }))
24
+ .sort((a, b) => a.difference - b.difference)[0].date;
25
+ }
26
+ exports.determineReportIssuedDate = determineReportIssuedDate;
27
+ function getReportDate(issued, day, hour, minute = 0) {
28
+ let date = new Date(issued);
29
+ if (day < date.getUTCDate()) {
30
+ date = addMonthsUTC(date, 1);
31
+ }
32
+ date.setUTCDate(day);
33
+ date.setUTCHours(hour);
34
+ if (minute != null)
35
+ date.setUTCMinutes(minute);
36
+ return date;
37
+ }
38
+ exports.getReportDate = getReportDate;
39
+ function setDateComponents(date, day, hour, minute) {
40
+ date.setUTCDate(day);
41
+ date.setUTCHours(hour);
42
+ if (minute != null)
43
+ date.setUTCMinutes(minute);
44
+ return date;
45
+ }
46
+ function addMonthsUTC(date, count) {
47
+ if (date && count) {
48
+ let m, d = (date = new Date(+date)).getUTCDate();
49
+ date.setUTCMonth(date.getUTCMonth() + count, 1);
50
+ m = date.getUTCMonth();
51
+ date.setUTCDate(d);
52
+ if (date.getUTCMonth() !== m)
53
+ date.setUTCDate(0);
54
+ }
55
+ return date;
56
+ }
@@ -8,3 +8,10 @@ export declare function pySplit(string: string, separator: string, n?: number):
8
8
  * https://stackoverflow.com/a/22129960
9
9
  */
10
10
  export declare function resolve(obj: any, path: string | string[], separator?: string): unknown;
11
+ /**
12
+ * For safely casting input values
13
+ * @param input String that is expected to be in the snum
14
+ * @param enumExpected The enum to cast the input value to
15
+ * @throws RemarkExecutionError when input is not a key of enum
16
+ */
17
+ export declare function as<T extends Record<string, unknown>>(input: string, enumExpected: T): T[keyof T];
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.resolve = exports.pySplit = void 0;
3
+ exports.as = exports.resolve = exports.pySplit = void 0;
4
+ const errors_1 = require("../commons/errors");
4
5
  /**
5
6
  * Split behaving similar to Python's implementation
6
7
  */
@@ -31,3 +32,15 @@ function resolve(obj, path, separator = ".") {
31
32
  return properties.reduce((prev, curr) => prev === null || prev === void 0 ? void 0 : prev[curr], obj);
32
33
  }
33
34
  exports.resolve = resolve;
35
+ /**
36
+ * For safely casting input values
37
+ * @param input String that is expected to be in the snum
38
+ * @param enumExpected The enum to cast the input value to
39
+ * @throws RemarkExecutionError when input is not a key of enum
40
+ */
41
+ function as(input, enumExpected) {
42
+ if (!Object.values(enumExpected).includes(input))
43
+ throw new errors_1.CommandExecutionError(`${input} not found in ${Object.values(enumExpected)}`);
44
+ return input;
45
+ }
46
+ exports.as = as;
package/dist/index.d.ts CHANGED
@@ -1,11 +1,32 @@
1
1
  import { IMetar, ITAF } from "./model/model";
2
2
  import { Locale } from "./commons/i18n";
3
+ import { IMetarDated } from "./dates/metar";
4
+ import { ITAFDated } from "./dates/taf";
5
+ import { IForecastContainer } from "./forecast/forecast";
3
6
  export { Locale } from "./commons/i18n";
4
7
  export * from "./commons/errors";
5
8
  export * from "./model/model";
6
9
  export * from "./model/enum";
10
+ export { RemarkType, IBaseRemark, IUnknownRemark, Remark, ICeilingHeightRemark, ICeilingSecondLocationRemark, IHourlyMaximumMinimumTemperatureRemark, IHourlyMaximumTemperatureRemark, IHourlyMinimumTemperatureRemark, IHourlyPrecipitationAmountRemark, IHourlyPressureRemark, IHourlyTemperatureDewPointRemark, IIceAccretionRemark, IObscurationRemark, IPrecipitationAmount24HourRemark, IPrecipitationAmount36HourRemark, IPrecipitationBegEndRemark, IPrevailingVisibilityRemark, ISeaLevelPressureRemark, ISecondLocationVisibilityRemark, ISectorVisibilityRemark, ISmallHailSizeRemark, ISnowIncreaseRemark, ISnowPelletsRemark, ISunshineDurationRemark, ISurfaceVisibilityRemark, IThunderStormLocationRemark, IThunderStormLocationMovingRemark, ITornadicActivityBegRemark, ITornadicActivityBegEndRemark, ITornadicActivityEndRemark, ITowerVisibilityRemark, IVariableSkyRemark, IVariableSkyHeightRemark, IVirgaDirectionRemark, IWaterEquivalentSnowRemark, IWindPeakCommandRemark, IWindShiftFropaRemark, } from "./command/remark";
11
+ export { getCompositeForecastForDate, IForecastContainer, ICompositeForecast, Forecast, TimestampOutOfBoundsError, } from "./forecast/forecast";
12
+ export { TAFTrendDated } from "./dates/taf";
7
13
  export interface IMetarTAFParserOptions {
8
14
  locale?: Locale;
9
15
  }
10
- export declare function parseMetar(metar: string, options?: IMetarTAFParserOptions): IMetar;
11
- export declare function parseTAF(taf: string, options?: IMetarTAFParserOptions): ITAF;
16
+ export interface IMetarTAFParserOptionsDated extends IMetarTAFParserOptions {
17
+ /**
18
+ * This date should ideally be the date the report was issued. Otherwise, it
19
+ * can be be +/- one week of the actual report date and work properly.
20
+ *
21
+ * So if you know the report was recently issued, you can pass `new Date()`
22
+ *
23
+ * This date is needed to create actual timestamps since the report only has
24
+ * day of month, hour, and minute.
25
+ */
26
+ date: Date;
27
+ }
28
+ export declare function parseMetar(rawMetar: string, options?: IMetarTAFParserOptions): IMetar;
29
+ export declare function parseMetar(rawMetar: string, options?: IMetarTAFParserOptionsDated): IMetarDated;
30
+ export declare function parseTAF(rawTAF: string, options?: IMetarTAFParserOptions): ITAF;
31
+ export declare function parseTAF(rawTAF: string, options?: IMetarTAFParserOptionsDated): ITAFDated;
32
+ export declare function parseTAFAsForecast(rawTAF: string, options: IMetarTAFParserOptionsDated): IForecastContainer;
package/dist/index.js CHANGED
@@ -17,25 +17,42 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
17
17
  return (mod && mod.__esModule) ? mod : { "default": mod };
18
18
  };
19
19
  Object.defineProperty(exports, "__esModule", { value: true });
20
- exports.parseTAF = exports.parseMetar = void 0;
20
+ exports.parseTAFAsForecast = exports.parseTAF = exports.parseMetar = exports.TimestampOutOfBoundsError = exports.getCompositeForecastForDate = exports.RemarkType = void 0;
21
21
  const parser_1 = require("./parser/parser");
22
22
  const errors_1 = require("./commons/errors");
23
23
  const en_1 = __importDefault(require("./locale/en"));
24
+ const metar_1 = require("./dates/metar");
25
+ const taf_1 = require("./dates/taf");
26
+ const forecast_1 = require("./forecast/forecast");
24
27
  __exportStar(require("./commons/errors"), exports);
25
28
  __exportStar(require("./model/model"), exports);
26
29
  __exportStar(require("./model/enum"), exports);
27
- function parseMetar(metar, options) {
28
- return parse(metar, options, parser_1.MetarParser);
30
+ var remark_1 = require("./command/remark");
31
+ Object.defineProperty(exports, "RemarkType", { enumerable: true, get: function () { return remark_1.RemarkType; } });
32
+ var forecast_2 = require("./forecast/forecast");
33
+ Object.defineProperty(exports, "getCompositeForecastForDate", { enumerable: true, get: function () { return forecast_2.getCompositeForecastForDate; } });
34
+ Object.defineProperty(exports, "TimestampOutOfBoundsError", { enumerable: true, get: function () { return forecast_2.TimestampOutOfBoundsError; } });
35
+ function parseMetar(rawMetar, options) {
36
+ return parse(rawMetar, options, parser_1.MetarParser, metar_1.metarDatesHydrator);
29
37
  }
30
38
  exports.parseMetar = parseMetar;
31
- function parseTAF(taf, options) {
32
- return parse(taf, options, parser_1.TAFParser);
39
+ function parseTAF(rawTAF, options) {
40
+ return parse(rawTAF, options, parser_1.TAFParser, taf_1.tafDatesHydrator);
33
41
  }
34
42
  exports.parseTAF = parseTAF;
35
- function parse(report, options, parser) {
43
+ function parseTAFAsForecast(rawTAF, options) {
44
+ const taf = parseTAF(rawTAF, options);
45
+ return (0, forecast_1.getForecastFromTAF)(taf);
46
+ }
47
+ exports.parseTAFAsForecast = parseTAFAsForecast;
48
+ function parse(rawReport, options, parser, datesHydrator) {
36
49
  const lang = (options === null || options === void 0 ? void 0 : options.locale) || en_1.default;
37
50
  try {
38
- return new parser(lang).parse(report);
51
+ const report = new parser(lang).parse(rawReport);
52
+ if (options && "date" in options) {
53
+ return datesHydrator(report, options.date);
54
+ }
55
+ return report;
39
56
  }
40
57
  catch (e) {
41
58
  if (e instanceof errors_1.ParseError)
@@ -111,6 +111,7 @@ export declare enum Phenomenon {
111
111
  SPRAY = "PY",
112
112
  SQUALL = "SQ",
113
113
  SAND_WHIRLS = "PO",
114
+ THUNDERSTORM = "TS",
114
115
  DUSTSTORM = "DS",
115
116
  SANDSTORM = "SS",
116
117
  FUNNEL_CLOUD = "FC"
@@ -219,3 +220,46 @@ export declare enum WeatherChangeType {
219
220
  */
220
221
  PROB = "PROB"
221
222
  }
223
+ export declare enum Direction {
224
+ E = "E",
225
+ ENE = "ENE",
226
+ ESE = "ESE",
227
+ N = "N",
228
+ NE = "NE",
229
+ NNE = "NNE",
230
+ NNW = "NNW",
231
+ NW = "NW",
232
+ S = "S",
233
+ SE = "SE",
234
+ SSE = "SSE",
235
+ SSW = "SSW",
236
+ SW = "SW",
237
+ W = "W",
238
+ WNW = "WNW",
239
+ WSW = "WSW"
240
+ }
241
+ export declare enum DistanceUnit {
242
+ Meters = "m",
243
+ StatuteMiles = "SM"
244
+ }
245
+ /**
246
+ * Used to indicate the actual value is greater than or less than the value written
247
+ *
248
+ * For example,
249
+ *
250
+ * 1. `P6SM` = visibility greater than 6 statute miles
251
+ * 2. `M1/4SM` = visibility less than 1/4 statute mile
252
+ */
253
+ export declare enum ValueIndicator {
254
+ GreaterThan = "P",
255
+ LessThan = "M"
256
+ }
257
+ export declare enum RunwayInfoTrend {
258
+ Uprising = "U",
259
+ Decreasing = "D",
260
+ NoSignificantChange = "N"
261
+ }
262
+ export declare enum RunwayInfoUnit {
263
+ Feet = "FT",
264
+ Meters = "m"
265
+ }