UNPKG

metar-decoder

Version:

Convert METAR weather reports to JavaScript objects

146 lines (145 loc) 5.58 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.decode = void 0; const axios_1 = require("axios"); const constants_1 = require("./constants"); const utils_1 = require("./utils"); function decode(metar) { const data = {}; const sections = metar.split(' '); if (sections.length === 0) return null; data.rvr = []; data.clouds = []; data.weather = []; data.auto = sections[1] === 'AUTO'; data.cavok = metar.includes('CAVOK'); if (data.cavok) { data.visibility = 9999; sections.splice(sections.indexOf('CAVOK'), 1); } // WEATHER for (let i = sections.length - 1; i >= 0; i--) { if (constants_1.weather[sections[i]]) { const uncodedWeather = sections[i]; data.weather.push({ abbreviation: uncodedWeather, meaning: constants_1.weather[uncodedWeather], }); sections.splice(i, 1); } } // AIRPORT data.airport = sections.shift(); // TIME const timeSection = sections.shift(); const now = new Date(); data.recorded_at = new Date(Date.UTC(now.getFullYear(), now.getMonth(), Number(timeSection.slice(0, 2)), Number(timeSection.slice(2, 4)), Number(timeSection.slice(4, 6)))); // WIND const windSection = sections.shift(); data.wind = {}; data.wind.direction = windSection.slice(0, 3); data.wind.speed = Number(windSection.slice(3, 5)); if (windSection[5] === 'G') { data.wind.guest = Number(windSection.slice(5, 7)); data.wind.unit = windSection.slice(7, 9); } else { data.wind.guest = null; data.wind.unit = windSection.slice(5, 7); } // VARIATION if (/(\d){3}V(\d){3}/g.test(sections[0])) { const [min, max] = sections.shift().split('V').map(Number); data.wind.variation = { min, max, }; } // VISIBILITY if (!data.cavok) { data.visibility = Number(sections.shift()); // MIN VISIBILITY if ((0, utils_1.matchExact)(/(\d){4}(W|E|N|S|(NE)|(NW)|(SE)|(SW))?/, sections[0])) { const min_visibility = sections.shift(); data.min_visibility = { visibility: Number(min_visibility.slice(0, 4)), direction: min_visibility.slice(4, min_visibility.length), }; } } // RVR while (sections[0].startsWith('R')) { const [runway, visibility] = sections.shift().substring(1).split('/'); const isVariable = visibility.includes('V'); data.rvr.push({ runway, visibility: !isVariable ? visibility.slice(0, visibility.length - 1) : { min: visibility.slice(0, 4), max: visibility.slice(5, 9), }, trend: constants_1.rvrTrend[visibility.slice(-1)], }); } // CLOUDS if (/((SCT)|(BKN)|(FEW)|(OVC))(\d{3})((CB)|(TCB))?/.test(sections[0])) { while (constants_1.clouds.map((c) => c.code).includes(sections[0].slice(0, 3))) { const uncodedCloud = sections.shift(); const cloud = constants_1.clouds.find((c) => c.code === uncodedCloud.slice(0, 3)); if (!cloud) continue; data.clouds.push(Object.assign(Object.assign({}, cloud), { cumulonimbus: uncodedCloud.includes('CB'), altitude: Number(uncodedCloud.slice(3, 6)) * 100 })); } } if (sections[0].startsWith('VV')) { const vv = sections.shift(); data.vertical_visibility = vv.substring(2); } // TEMP if (/(\d){2}\/(\d){2}/.test(sections[0])) { const [temperature, dewpoint] = sections.shift().split('/').map(Number); data.dewpoint = dewpoint, data.temperature = temperature; } // BARO if ((0, utils_1.matchExact)(/(Q|A)(\d){4}/, sections[0])) { const baro = sections.shift(); data.qnh = baro.startsWith('A') ? (0, utils_1.inHgtoHpa)(Number(`${baro.slice(1, 3)}.${baro.slice(2, 5)}`)) : Number(baro.slice(1, 5)); } // TREND if (constants_1.trends[sections[0]]) { data.trend = { type: constants_1.trends[sections[0]], full: sections.join(' '), }; } data.fetchAirport = () => __awaiter(this, void 0, void 0, function* () { if (typeof data.airport === 'object') return data.airport; try { const { data: json } = yield axios_1.default.get(`https://airports.larrrssss.workers.dev/${data.airport}`); if (json.status && json.status === 404) return null; data.airport = json; return data.airport; } catch (e) { return null; } }); return data; } exports.decode = decode;