feat: Log unknown METAR parts with full string for debugging

Co-authored-by: aider (gemini/gemini-2.5-pro) <aider@aider.chat>
This commit is contained in:
2026-02-14 15:36:20 -07:00
parent cd87f98f18
commit 6f375aed92
+23 -13
View File
@@ -60,8 +60,9 @@
// --- Decoding Functions ---
function decodeAirport(code) {
function decodeAirport(code, metarString) {
if (code === 'CYYC') return "CYYC: Calgary International Airport";
console.log(`Unknown Airport code: ${code} in METAR: ${metarString}`);
return `${code}: Unknown Airport`;
}
@@ -89,7 +90,7 @@
return `${code}: Visibility ${vis} statute miles`;
}
function decodeWeather(code) {
function decodeWeather(code, metarString) {
const originalCode = code;
const intensityMap = {
'-': 'Light ',
@@ -133,6 +134,7 @@
} else if (weatherMap[chunk]) {
decodedChunks.push(weatherMap[chunk]);
} else {
console.log(`Unknown weather chunk: ${chunk} in code: ${code} in METAR: ${metarString}`);
decodedChunks.push(`unknown (${chunk})`);
}
if (precipitationTypes.includes(chunk)) {
@@ -149,7 +151,7 @@
return `${originalCode}: ${decoding.trim()}${vicinity}`;
}
function decodeClouds(code) {
function decodeClouds(code, metarString) {
const coverMap = {
'SKC': 'Sky clear',
'CLR': 'Sky clear',
@@ -160,7 +162,10 @@
};
const coverType = code.substring(0, 3);
const cover = coverMap[coverType];
if (!cover) return `${code}: Unknown cloud information`;
if (!cover) {
console.log(`Unknown cloud information: ${code} in METAR: ${metarString}`);
return `${code}: Unknown cloud information`;
}
if (coverType === 'SKC' || coverType === 'CLR') {
return `${code}: ${cover}`;
@@ -188,7 +193,7 @@
return `SLP${pressure}: Sea-level pressure ${hpa.toFixed(1)} hPa`;
}
function decodeCloudTypesRemark(code) {
function decodeCloudTypesRemark(code, metarString) {
const cloudTypes = {
'CI': 'Cirrus',
'CC': 'Cirrocumulus',
@@ -208,7 +213,11 @@
for (const match of matches) {
const cloudCode = match[1];
const oktas = match[2];
const cloudName = cloudTypes[cloudCode] || `Unknown cloud type (${cloudCode})`;
let cloudName = cloudTypes[cloudCode];
if (!cloudName) {
cloudName = `Unknown cloud type (${cloudCode})`;
console.log(`Unknown cloud type in remark: ${cloudCode} in METAR: ${metarString}`);
}
decodedParts.push(`${oktas}/8 ${cloudName}`);
}
@@ -230,7 +239,7 @@
return `${code}: ${weatherName} obscuring ${oktas}/8 of the sky`;
}
function decodeRemarks(parts) {
function decodeRemarks(parts, metarString) {
let decoded = ["RMK: Remarks"];
const weatherRegex = /^([+-]|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)+$/;
const obscurationRegex = /^(FG|BR|FU|HZ|DU|SA)\d$/;
@@ -263,7 +272,7 @@
} else if (obscurationRegex.test(part)) {
decoded.push(` - ${decodeObscurationRemark(part)}`);
} else if (part.match(/^([A-Z]{2}\d)+$/)) {
decoded.push(` - ${decodeCloudTypesRemark(part)}`);
decoded.push(` - ${decodeCloudTypesRemark(part, metarString)}`);
} else if (part === 'VIRGA' && i + 1 < parts.length && directions[parts[i+1]]) {
const direction = directions[parts[i+1]];
decoded.push(` - VIRGA ${parts[i+1]}: Virga to the ${direction.toLowerCase()}`);
@@ -279,10 +288,11 @@
decoded.push(` - ${part} ${parts[i+1]}: ${cloudName} clouds are translucent (thin)`);
i++; // Consume 'TR' part
} else if (weatherRegex.test(part)) {
decoded.push(` - ${decodeWeather(part)}`);
decoded.push(` - ${decodeWeather(part, metarString)}`);
} else if (part.match(/^(AC|CI|CC)/)) {
decoded.push(` - ${part}: Cloud types and coverage details`);
} else {
console.log(`Other remark: ${part} in METAR: ${metarString}`);
decoded.push(` - ${part}: Other remark`);
}
}
@@ -300,7 +310,7 @@
if (parts[index] && parts[index].length === 4 && parts[index].match(/^[A-Z][A-Z0-9]{3}$/)) {
airportTimeAutoRaw.push(parts[index]);
airportTimeAutoDecoded.push(decodeAirport(parts[index]));
airportTimeAutoDecoded.push(decodeAirport(parts[index], metarString));
index++;
}
if (parts[index] && parts[index].endsWith('Z')) {
@@ -331,9 +341,9 @@
} else if (part.endsWith('SM') || part.match(/^\d+$/) || part.match(/^\d\/\dSM$/)) {
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)+$/)) {
sections.push({ raw: part, decoded: decodeWeather(part) });
sections.push({ raw: part, decoded: decodeWeather(part, metarString) });
} else if (part.match(/^(SKC|CLR|FEW|SCT|BKN|OVC)/)) {
sections.push({ raw: part, decoded: decodeClouds(part) });
sections.push({ raw: part, decoded: decodeClouds(part, metarString) });
} else if (part.match(/^(M?\d{2})\/(M?\d{2})$/)) {
sections.push({ raw: part, decoded: decodeTempDew(part) });
} else if (part.startsWith('A') && part.length === 5 && !isNaN(part.substring(1))) {
@@ -346,7 +356,7 @@
const remarkParts = parts.slice(rmkIndex + 1);
sections.push({
raw: `RMK ${remarkParts.join(' ')}`,
decoded: decodeRemarks(remarkParts)
decoded: decodeRemarks(remarkParts, metarString)
});
}