feat: Add decoding and scoring for vertical visibility (VV)

Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
This commit is contained in:
2026-02-14 18:24:16 -07:00
parent 822a2237de
commit e3b9c7901b
+12 -3
View File
@@ -147,9 +147,10 @@
} }
// Clouds // Clouds
if (part.match(/^(BKN|OVC)/)) { if (part.match(/^(BKN|OVC|VV)/)) {
score += 1; score += 1;
const ceilingAlt = parseInt(part.substring(3, 6)); const altCode = part.startsWith('VV') ? part.substring(2, 5) : part.substring(3, 6);
const ceilingAlt = parseInt(altCode);
if (!isNaN(ceilingAlt)) { if (!isNaN(ceilingAlt)) {
const ceilingFt = ceilingAlt * 100; const ceilingFt = ceilingAlt * 100;
if (ceilingFt < 500) score += 8; if (ceilingFt < 500) score += 8;
@@ -285,6 +286,14 @@
} }
function decodeClouds(code, metarString) { function decodeClouds(code, metarString) {
if (code.startsWith('VV')) {
const height = code.substring(2, 5);
if (height === '///') {
return `${code}: Vertical visibility sensor inoperative`;
}
const alt = parseInt(height) * 100;
return `${code}: Vertical visibility ${alt.toLocaleString()} feet`;
}
const coverMap = { const coverMap = {
'SKC': 'Sky clear', 'SKC': 'Sky clear',
'CLR': 'Sky clear', 'CLR': 'Sky clear',
@@ -791,7 +800,7 @@
sections.push({ raw: part, decoded: decodeVisibility(part) }); sections.push({ raw: part, decoded: decodeVisibility(part) });
} else if (part.match(/^([+-]|VC)?(MI|PR|BC|DR|BL|SH|TS|FZ|DZ|RA|SN|SG|IC|PL|GR|GS|UP|BR|FG|FU|VA|DU|SA|HZ|PY|PO|SQ|FC|SS|DS|TR)+$/)) { } else if (part.match(/^([+-]|VC)?(MI|PR|BC|DR|BL|SH|TS|FZ|DZ|RA|SN|SG|IC|PL|GR|GS|UP|BR|FG|FU|VA|DU|SA|HZ|PY|PO|SQ|FC|SS|DS|TR)+$/)) {
sections.push({ raw: part, decoded: decodeWeather(part, metarString) }); sections.push({ raw: part, decoded: decodeWeather(part, metarString) });
} else if (part.match(/^(SKC|CLR|FEW|SCT|BKN|OVC)/)) { } else if (part.match(/^(VV|SKC|CLR|FEW|SCT|BKN|OVC)/)) {
sections.push({ raw: part, decoded: decodeClouds(part, metarString) }); sections.push({ raw: part, decoded: decodeClouds(part, metarString) });
} else if (part.match(/^(M?\d{2})\/(M?\d{2})$/)) { } else if (part.match(/^(M?\d{2})\/(M?\d{2})$/)) {
sections.push({ raw: part, decoded: decodeTempDew(part) }); sections.push({ raw: part, decoded: decodeTempDew(part) });