metar-taf-parser 2.0.0 → 3.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,9 +1,21 @@
1
1
  # ✈️ [metar-taf-parser](https://aeharding.github.io/metar-taf-parser)
2
2
 
3
- Parser for METeorological Aerodrome Reports (METARs) and Terminal Aerodrome Forecasts (TAFs). This is a port of [python-metar-taf-parser](https://github.com/mivek/python-metar-taf-parser) to Typescript. It's dependency-free, fully typed, tested, has i18n support, and can run on Node or in the browser.
3
+ Parser for METeorological Aerodrome Reports (METARs) and Terminal Aerodrome Forecasts (TAFs). This is a port of [python-metar-taf-parser](https://github.com/mivek/python-metar-taf-parser) to Typescript with some additional features.
4
4
 
5
5
  [Check out the demo here](https://aeharding.github.io/metar-taf-parser)
6
6
 
7
+ Features:
8
+
9
+ - ✈️ Complete METAR and TAF parsing
10
+ - 🛠 Fully typed
11
+ - 🪶 Dependency free
12
+ - 🧪 Full test suite
13
+ - ✅ Runs anywhere: Web browser or Node
14
+ - 🌎 i18n: Translations
15
+ - 🌏 i18n: Handling international TAF & METAR report format differences
16
+ - 🌪 Remark parsing to human and machine readable formats
17
+ - 🗓 [`Forecast` abstraction](https://aeharding.github.io/metar-taf-parser/forecast) to easily query TAF reports by `Date`
18
+
7
19
  ## Installation
8
20
 
9
21
  ```sh
@@ -114,6 +126,33 @@ const metarResult = parseMetar(rawMetarReport, {
114
126
  console.log(metarReport.remarks[0].description);
115
127
  ```
116
128
 
129
+ ## Handling remarks
130
+
131
+ Remarks may be found on base TAF and METARs, along with TAF trends.
132
+
133
+ Each Remark will have a `description` (if translated), `type` and `raw` properties. There are additional properties for each unique remark, depending on the remark's `type`. We can type guard on `type` to access these unique properties.
134
+
135
+ If the remark is not understood, it will have `type` as `RemarkType.Unknown`, with `raw` containing everything until the next understood remark.
136
+
137
+ ### Example
138
+
139
+ ```ts
140
+ import { Remark, RemarkType } from "metar-taf-parser";
141
+
142
+ /**
143
+ * Find the sea level pressure given remarks, if defined
144
+ */
145
+ function findSeaLevelPressure(remarks: Remark[]): number | undefined {
146
+ for (const remark of remarks) {
147
+ switch (remark.type) {
148
+ case RemarkType.SeaLevelPressure:
149
+ // can now access remark.pressure
150
+ return remark.pressure;
151
+ }
152
+ }
153
+ }
154
+ ```
155
+
117
156
  ## Development
118
157
 
119
158
  ### Example site
@@ -233,8 +233,7 @@ class CommandSupplier {
233
233
  ]);
234
234
  }
235
235
  get(input) {
236
- for (let i = 0; i < __classPrivateFieldGet(this, _CommandSupplier_commands, "f").length; i++) {
237
- const command = __classPrivateFieldGet(this, _CommandSupplier_commands, "f")[i];
236
+ for (const command of __classPrivateFieldGet(this, _CommandSupplier_commands, "f")) {
238
237
  if (command.canParse(input))
239
238
  return command;
240
239
  }
@@ -21,8 +21,7 @@ class CommandSupplier {
21
21
  ]);
22
22
  }
23
23
  get(input) {
24
- for (let i = 0; i < __classPrivateFieldGet(this, _CommandSupplier_commands, "f").length; i++) {
25
- const command = __classPrivateFieldGet(this, _CommandSupplier_commands, "f")[i];
24
+ for (const command of __classPrivateFieldGet(this, _CommandSupplier_commands, "f")) {
26
25
  if (command.canParse(input))
27
26
  return command;
28
27
  }
@@ -2,7 +2,7 @@ import { IBaseRemark, RemarkType, Remark } from "../remark";
2
2
  import { Command } from "./Command";
3
3
  export interface IHailSizeRemark extends IBaseRemark {
4
4
  type: RemarkType.HailSize;
5
- size: string;
5
+ size: number;
6
6
  }
7
7
  export declare class HailSizeCommand extends Command {
8
8
  #private;
@@ -11,6 +11,7 @@ const i18n_1 = require("../../commons/i18n");
11
11
  const errors_1 = require("../../commons/errors");
12
12
  const remark_1 = require("../remark");
13
13
  const Command_1 = require("./Command");
14
+ const converter_1 = require("../../commons/converter");
14
15
  class HailSizeCommand extends Command_1.Command {
15
16
  constructor() {
16
17
  super(...arguments);
@@ -28,7 +29,7 @@ class HailSizeCommand extends Command_1.Command {
28
29
  type: remark_1.RemarkType.HailSize,
29
30
  description,
30
31
  raw: matches[0],
31
- size: matches[1],
32
+ size: (0, converter_1.convertFractionalAmount)(matches[1]),
32
33
  });
33
34
  return [code.replace(__classPrivateFieldGet(this, _HailSizeCommand_regex, "f"), "").trim(), remark];
34
35
  }
@@ -2,8 +2,8 @@ import { IBaseRemark, RemarkType, Remark } from "../remark";
2
2
  import { Command } from "./Command";
3
3
  export interface IPrevailingVisibilityRemark extends IBaseRemark {
4
4
  type: RemarkType.PrevailingVisibility;
5
- minVisibility: string;
6
- maxVisibility: string;
5
+ minVisibility: number;
6
+ maxVisibility: number;
7
7
  }
8
8
  export declare class PrevailingVisibilityCommand extends Command {
9
9
  #private;
@@ -11,6 +11,7 @@ const i18n_1 = require("../../commons/i18n");
11
11
  const errors_1 = require("../../commons/errors");
12
12
  const remark_1 = require("../remark");
13
13
  const Command_1 = require("./Command");
14
+ const converter_1 = require("../../commons/converter");
14
15
  class PrevailingVisibilityCommand extends Command_1.Command {
15
16
  constructor() {
16
17
  super(...arguments);
@@ -30,8 +31,8 @@ class PrevailingVisibilityCommand extends Command_1.Command {
30
31
  type: remark_1.RemarkType.PrevailingVisibility,
31
32
  description,
32
33
  raw: matches[0],
33
- minVisibility,
34
- maxVisibility,
34
+ minVisibility: (0, converter_1.convertFractionalAmount)(minVisibility),
35
+ maxVisibility: (0, converter_1.convertFractionalAmount)(maxVisibility),
35
36
  });
36
37
  return [code.replace(__classPrivateFieldGet(this, _PrevailingVisibilityCommand_regex, "f"), "").trim(), remark];
37
38
  }
@@ -2,7 +2,7 @@ import { IBaseRemark, RemarkType, Remark } from "../remark";
2
2
  import { Command } from "./Command";
3
3
  export interface ISecondLocationVisibilityRemark extends IBaseRemark {
4
4
  type: RemarkType.SecondLocationVisibility;
5
- distance: string;
5
+ distance: number;
6
6
  location: string;
7
7
  }
8
8
  export declare class SecondLocationVisibilityCommand extends Command {
@@ -11,6 +11,7 @@ const i18n_1 = require("../../commons/i18n");
11
11
  const errors_1 = require("../../commons/errors");
12
12
  const remark_1 = require("../remark");
13
13
  const Command_1 = require("./Command");
14
+ const converter_1 = require("../../commons/converter");
14
15
  class SecondLocationVisibilityCommand extends Command_1.Command {
15
16
  constructor() {
16
17
  super(...arguments);
@@ -30,7 +31,7 @@ class SecondLocationVisibilityCommand extends Command_1.Command {
30
31
  type: remark_1.RemarkType.SecondLocationVisibility,
31
32
  description,
32
33
  raw: matches[0],
33
- distance,
34
+ distance: (0, converter_1.convertFractionalAmount)(distance),
34
35
  location,
35
36
  });
36
37
  return [code.replace(__classPrivateFieldGet(this, _SecondLocationVisibilityCommand_regex, "f"), "").trim(), remark];
@@ -4,7 +4,7 @@ import { Command } from "./Command";
4
4
  export interface ISectorVisibilityRemark extends IBaseRemark {
5
5
  type: RemarkType.SectorVisibility;
6
6
  direction: Direction;
7
- distance: string;
7
+ distance: number;
8
8
  }
9
9
  export declare class SectorVisibilityCommand extends Command {
10
10
  #private;
@@ -13,6 +13,7 @@ const errors_1 = require("../../commons/errors");
13
13
  const enum_1 = require("../../model/enum");
14
14
  const remark_1 = require("../remark");
15
15
  const Command_1 = require("./Command");
16
+ const converter_1 = require("../../commons/converter");
16
17
  class SectorVisibilityCommand extends Command_1.Command {
17
18
  constructor() {
18
19
  super(...arguments);
@@ -32,7 +33,7 @@ class SectorVisibilityCommand extends Command_1.Command {
32
33
  description,
33
34
  raw: matches[0],
34
35
  direction,
35
- distance: matches[2],
36
+ distance: (0, converter_1.convertFractionalAmount)(matches[2]),
36
37
  });
37
38
  return [code.replace(__classPrivateFieldGet(this, _SectorVisibilityCommand_regex, "f"), "").trim(), remark];
38
39
  }
@@ -2,7 +2,7 @@ import { IBaseRemark, RemarkType, Remark } from "../remark";
2
2
  import { Command } from "./Command";
3
3
  export interface ISmallHailSizeRemark extends IBaseRemark {
4
4
  type: RemarkType.SmallHailSize;
5
- size: string;
5
+ size: number;
6
6
  }
7
7
  export declare class SmallHailSizeCommand extends Command {
8
8
  #private;
@@ -11,6 +11,7 @@ const i18n_1 = require("../../commons/i18n");
11
11
  const errors_1 = require("../../commons/errors");
12
12
  const remark_1 = require("../remark");
13
13
  const Command_1 = require("./Command");
14
+ const converter_1 = require("../../commons/converter");
14
15
  class SmallHailSizeCommand extends Command_1.Command {
15
16
  constructor() {
16
17
  super(...arguments);
@@ -28,7 +29,7 @@ class SmallHailSizeCommand extends Command_1.Command {
28
29
  type: remark_1.RemarkType.SmallHailSize,
29
30
  description,
30
31
  raw: matches[0],
31
- size: matches[1],
32
+ size: (0, converter_1.convertFractionalAmount)(matches[1]),
32
33
  });
33
34
  return [code.replace(__classPrivateFieldGet(this, _SmallHailSizeCommand_regex, "f"), "").trim(), remark];
34
35
  }
@@ -2,7 +2,7 @@ import { IBaseRemark, RemarkType, Remark } from "../remark";
2
2
  import { Command } from "./Command";
3
3
  export interface ISurfaceVisibilityRemark extends IBaseRemark {
4
4
  type: RemarkType.SurfaceVisibility;
5
- distance: string;
5
+ distance: number;
6
6
  }
7
7
  export declare class SurfaceVisibilityCommand extends Command {
8
8
  #private;
@@ -11,6 +11,7 @@ const i18n_1 = require("../../commons/i18n");
11
11
  const errors_1 = require("../../commons/errors");
12
12
  const remark_1 = require("../remark");
13
13
  const Command_1 = require("./Command");
14
+ const converter_1 = require("../../commons/converter");
14
15
  class SurfaceVisibilityCommand extends Command_1.Command {
15
16
  constructor() {
16
17
  super(...arguments);
@@ -29,7 +30,7 @@ class SurfaceVisibilityCommand extends Command_1.Command {
29
30
  type: remark_1.RemarkType.SurfaceVisibility,
30
31
  description,
31
32
  raw: matches[0],
32
- distance,
33
+ distance: (0, converter_1.convertFractionalAmount)(distance),
33
34
  });
34
35
  return [code.replace(__classPrivateFieldGet(this, _SurfaceVisibilityCommand_regex, "f"), "").trim(), remark];
35
36
  }
@@ -2,7 +2,7 @@ import { IBaseRemark, RemarkType, Remark } from "../remark";
2
2
  import { Command } from "./Command";
3
3
  export interface ITowerVisibilityRemark extends IBaseRemark {
4
4
  type: RemarkType.TowerVisibility;
5
- distance: string;
5
+ distance: number;
6
6
  }
7
7
  export declare class TowerVisibilityCommand extends Command {
8
8
  #private;
@@ -11,6 +11,7 @@ const i18n_1 = require("../../commons/i18n");
11
11
  const errors_1 = require("../../commons/errors");
12
12
  const remark_1 = require("../remark");
13
13
  const Command_1 = require("./Command");
14
+ const converter_1 = require("../../commons/converter");
14
15
  class TowerVisibilityCommand extends Command_1.Command {
15
16
  constructor() {
16
17
  super(...arguments);
@@ -29,7 +30,7 @@ class TowerVisibilityCommand extends Command_1.Command {
29
30
  type: remark_1.RemarkType.TowerVisibility,
30
31
  description,
31
32
  raw: matches[0],
32
- distance,
33
+ distance: (0, converter_1.convertFractionalAmount)(distance),
33
34
  });
34
35
  return [code.replace(__classPrivateFieldGet(this, _TowerVisibilityCommand_regex, "f"), "").trim(), remark];
35
36
  }
@@ -88,8 +88,7 @@ class RemarkCommandSupplier {
88
88
  ];
89
89
  }
90
90
  get(code) {
91
- for (let i = 0; i < this.commandList.length; i++) {
92
- const command = this.commandList[i];
91
+ for (const command of this.commandList) {
93
92
  if (command.canParse(code))
94
93
  return command;
95
94
  }
@@ -18,8 +18,8 @@ function format(message, ...args) {
18
18
  if (!message)
19
19
  return;
20
20
  // All arguments must be defined, otherwise nothing is returned
21
- for (let i = 0; i < args.length; i++) {
22
- if (args[i] === undefined)
21
+ for (const arg of args) {
22
+ if (arg === undefined)
23
23
  return;
24
24
  }
25
25
  return message.replace(/{\d+}/g, (match) => {
@@ -52,8 +52,7 @@ function getCompositeForecastForDate(date, forecastContainer) {
52
52
  throw new TimestampOutOfBoundsError("Provided timestamp is outside the report validity period");
53
53
  let base;
54
54
  let additional = [];
55
- for (let i = 0; i < forecastContainer.forecast.length; i++) {
56
- const forecast = forecastContainer.forecast[i];
55
+ for (const forecast of forecastContainer.forecast) {
57
56
  if (!forecast.validity.end &&
58
57
  forecast.validity.start.getTime() <= date.getTime()) {
59
58
  // Is FM or initial forecast
@@ -311,9 +311,9 @@ class TAFParser extends AbstractParser {
311
311
  parse(input) {
312
312
  let amendment;
313
313
  const lines = this.extractLinesTokens(input);
314
- if (lines[0][0] !== this.TAF)
315
- throw new errors_1.InvalidWeatherStatementError('TAF report must begin with "TAF"');
316
- let index = 1;
314
+ let index = 0;
315
+ if (lines[0][0] === this.TAF)
316
+ index = 1;
317
317
  if (lines[0][1] === this.TAF)
318
318
  index = 2;
319
319
  if (lines[0][index] === "AMD") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "metar-taf-parser",
3
- "version": "2.0.0",
3
+ "version": "3.1.1",
4
4
  "description": "Parse METAR and TAF reports",
5
5
  "homepage": "https://aeharding.github.io/metar-taf-parser",
6
6
  "keywords": [