Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/plugins/Label_13Through18_Slash.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ describe('Label_13Through18_Slash', () => {
// ADS-B confirms it took off from IAD at the correct time
// Despite all this, it shows that positions may be in decimal minutes instead of DMS when using NSEW instead of +/-
// so i'm putting it here for reference
xtest('decodes position invalid', () => {
test.skip('decodes position invalid', () => {
const text = '/14 OFF EVENT / KIAD KSAT 10 122555/TIME 1225' + '\r\n' +
'/AU 55808910/AON 55729908/AIN 55731908/AOT 55804909' + '\r\n' +
'/LOC N169380,E1334348'
Expand Down
21 changes: 9 additions & 12 deletions lib/plugins/Label_1J_2J_FTX.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,26 +31,23 @@ describe('Label 1J/2J FTX', () => {
expect(decodeResult.remaining.text).toBe('MR6,');
});

// Disabled due to checksum mismatch. Possibly copy-paste issue due to non-ascii characters in message?
test('decodes Label 2J', () => {
// https://app.airframes.io/messages/4178362466
const text = 'M74AMC4086FTX/ID50007B,RCH4086,ABB02R70E037/DC10022025,011728/MR049,/FXGOOD EVENING PLEASE PASS US THE SUPER BOWL SCORE WHEN ABLE. THANK YOU/FB1791/VR0328D70'
const decodeResult = plugin.decode({ text: text });

expect(decodeResult.decoded).toBe(true);
expect(decodeResult.decoder.decodeLevel).toBe('partial');
expect(decodeResult.raw.tail).toBe('50007B');
expect(decodeResult.raw.flight_number).toBe('RCH4086');
expect(decodeResult.raw.mission_number).toBe('ABB02R70E037');
expect(decodeResult.raw.message_timestamp).toBe(1759367848);
expect(decodeResult.raw.fuel_burned).toBe(1791);
expect(decodeResult.raw.freetext).toBe('GOOD EVENING PLEASE PASS US THE SUPER BOWL SCORE WHEN ABLE. THANK YOU');
expect(decodeResult.raw.checksum).toBe(0x8D70);
expect(decodeResult.formatted.items.length).toBe(5);
expect(decodeResult.formatted.items[0].label).toBe('Flight Number');
expect(decodeResult.formatted.items[0].value).toBe('MC4086');
expect(decodeResult.formatted.items[1].label).toBe('Tail');
expect(decodeResult.formatted.items[1].value).toBe('50007B');
expect(decodeResult.formatted.items[2].label).toBe('Flight Number');
expect(decodeResult.formatted.items[2].value).toBe('RCH4086');
expect(decodeResult.formatted.items[3].label).toBe('Free Text');
expect(decodeResult.formatted.items[3].value).toBe('GOOD EVENING PLEASE PASS US THE SUPER BOWL SCORE WHEN ABLE. THANK YOU');
expect(decodeResult.formatted.items[4].label).toBe('Message Checksum');
expect(decodeResult.formatted.items[4].value).toBe('0x8d70');
expect(decodeResult.remaining.text).toBe('M74A/MR049,/FB1791/VR032');
expect(decodeResult.remaining.text).toBe('M74/MR049,/VR032');
});

test('decodes <invalid>', () => {
Expand All @@ -60,7 +57,7 @@ describe('Label 1J/2J FTX', () => {

expect(decodeResult.decoded).toBe(false);
expect(decodeResult.decoder.decodeLevel).toBe('none');
expect(decodeResult.formatted.description).toBe('Free Text');
expect(decodeResult.formatted.description).toBe('Unknown');
expect(decodeResult.message.text).toBe(text);
});
});
10 changes: 9 additions & 1 deletion lib/plugins/Label_1J_2J_FTX.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,15 @@ export class Label_1J_2J_FTX extends DecoderPlugin {
decodeResult.message = message;

const msg = message.text.replace(/\n|\r/g, "");
const decoded = H1Helper.decodeH1Message(decodeResult, msg);
const parts = msg.split('/');
let decoded = false;
if (parts[0].length > 3) {
decoded = H1Helper.decodeH1Message(decodeResult, msg.slice(parts[0].length - 3));
// flight number is already decoded in other fields
decodeResult.remaining.text = parts[0].slice(0,3) + '/' + decodeResult.remaining.text;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# First, let's examine the file and line in question
fd -t f "Label_1J_2J_FTX.ts" --exec wc -l {} \;

Repository: airframesio/acars-decoder-typescript

Length of output: 115


🏁 Script executed:

# Find the context around line 25 in Label_1J_2J_FTX.ts
fd -t f "Label_1J_2J_FTX.ts" --exec head -40 {} \;

Repository: airframesio/acars-decoder-typescript

Length of output: 1624


🏁 Script executed:

# Search for defaultResult function definition
rg -n "defaultResult\s*\(" --type ts -A 10

Repository: airframesio/acars-decoder-typescript

Length of output: 50392


🏁 Script executed:

# Search for remaining.text initialization patterns
rg -n "remaining\s*[:=\s]*{" --type ts -A 5

Repository: airframesio/acars-decoder-typescript

Length of output: 183


🏁 Script executed:

# Check decodeH1Message function
fd -t f "h1_helper.ts" --exec cat {} \;

Repository: airframesio/acars-decoder-typescript

Length of output: 15669


🏁 Script executed:

# Get full defaultResult() function
fd -t f "DecoderPlugin.ts" --exec cat {} \;

Repository: airframesio/acars-decoder-typescript

Length of output: 1580


🏁 Script executed:

# Find DecodeResult interface definition
fd -t f "DecoderPluginInterface.ts" --exec cat {} \;

Repository: airframesio/acars-decoder-typescript

Length of output: 967


Initialize remaining.text to an empty string in defaultResult() to avoid concatenating undefined.

The defaultResult() method initializes remaining as an empty object without setting remaining.text. Since decodeH1Message() does not guarantee remaining.text is set (especially when checksum validation fails), concatenating it on line 25 will result in "M80/undefined". Either initialize remaining.text = "" in defaultResult() or ensure decodeH1Message() always sets it.

🤖 Prompt for AI Agents
In `@lib/plugins/Label_1J_2J_FTX.ts` at line 25, defaultResult() currently
initializes remaining as an empty object, causing decodeResult.remaining.text
concatenation in decodeH1Message() to yield "undefined"; update defaultResult()
to set remaining.text = "" (i.e., ensure remaining has a text property
initialized to an empty string) so the line decodeResult.remaining.text =
parts[0].slice(0,3) + '/' + decodeResult.remaining.text safely concatenates, or
alternatively ensure decodeH1Message() always sets remaining.text before
concatenation.

} else {
decoded = H1Helper.decodeH1Message(decodeResult, msg);
}
decodeResult.decoded = decoded;

decodeResult.decoder.decodeLevel = !decodeResult.remaining.text ? 'full' : 'partial';
Expand Down
1 change: 0 additions & 1 deletion lib/plugins/Label_1L_3-line.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { decode } from 'punycode';
import { MessageDecoder } from '../MessageDecoder';
import { Label_1L_3Line } from './Label_1L_3-line';

Expand Down
2 changes: 1 addition & 1 deletion lib/plugins/Label_2P_FM3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export class Label_2P_FM3 extends DecoderPlugin {
ResultFormatter.unknown(decodeResult, header[0].substring(0,4));
ResultFormatter.flightNumber(decodeResult, header[0].substring(4));
}
console.log(header[1]);

if(header[1].length === 4) {
ResultFormatter.time_of_day(decodeResult, DateTimeUtils.convertHHMMSSToTod(header[1]));
} else {
Expand Down
37 changes: 16 additions & 21 deletions lib/plugins/Label_2P_POS.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,26 +19,21 @@ describe('Label_2P Preamble POS', () => {
expect(decodeResult.decoder.decodeLevel).toBe('partial');
expect(decodeResult.formatted.description).toBe('Position Report');
expect(decodeResult.message.text).toBe(text);
expect(decodeResult.formatted.items.length).toBe(9);
expect(decodeResult.formatted.items[0].label).toBe('Flight Number');
expect(decodeResult.formatted.items[0].value).toBe('MC4086');
expect(decodeResult.formatted.items[1].label).toBe('Tail');
expect(decodeResult.formatted.items[1].value).toBe('50007B');
expect(decodeResult.formatted.items[2].label).toBe('Flight Number');
expect(decodeResult.formatted.items[2].value).toBe('RCH4086');
expect(decodeResult.formatted.items[3].label).toBe('Day of Month');
expect(decodeResult.formatted.items[3].value).toBe('9');
expect(decodeResult.formatted.items[4].label).toBe('Estimated Time of Arrival');
expect(decodeResult.formatted.items[4].value).toBe('07:38:00');
expect(decodeResult.formatted.items[5].label).toBe('Aircraft Position');
expect(decodeResult.formatted.items[5].value).toBe('56.020 N, 13.455 W');
expect(decodeResult.formatted.items[6].label).toBe('Aircraft Route');
expect(decodeResult.formatted.items[6].value).toBe('@05:18:04 >> ?'); // Yuck - maybe fix?
expect(decodeResult.formatted.items[7].label).toBe('Altitude');
expect(decodeResult.formatted.items[7].value).toBe('35000 feet');
expect(decodeResult.formatted.items[8].label).toBe('Message Checksum');
expect(decodeResult.formatted.items[8].value).toBe('0x2b89');
expect(decodeResult.remaining.text).toBe('M80A/MR103,,084081,/CG,,/FB0857/VR032');
expect(decodeResult.raw.flight_number).toBe('RCH4086');
expect(decodeResult.raw.tail).toBe('50007B');
expect(decodeResult.raw.mission_number).toBe('ABB02R70E037');
expect(decodeResult.raw.day).toBe(9);
expect(decodeResult.raw.eta_time).toBe(27480);
expect(decodeResult.raw.position.latitude).toBe(56.02);
expect(decodeResult.raw.position.longitude).toBe(-13.455);
expect(decodeResult.raw.route.waypoints.length).toBe(3);
expect(decodeResult.raw.route.waypoints[0].time).toBe(19084);
expect(decodeResult.raw.route.waypoints[2].name).toBe('?');
expect(decodeResult.raw.altitude).toBe(35000);
expect(decodeResult.raw.fuel_burned).toBe(857);
expect(decodeResult.raw.checksum).toBe(0x2b89);
expect(decodeResult.formatted.items.length).toBe(11);
expect(decodeResult.remaining.text).toBe('M80/MR103,,084081,,/VR032');
});

test('<invalid>', () => {
Expand All @@ -48,7 +43,7 @@ describe('Label_2P Preamble POS', () => {

expect(decodeResult.decoded).toBe(false);
expect(decodeResult.decoder.decodeLevel).toBe('none');
expect(decodeResult.formatted.description).toBe('Unknown H1 Message');
expect(decodeResult.formatted.description).toBe('Unknown');
expect(decodeResult.formatted.items.length).toBe(0);
});
});
10 changes: 9 additions & 1 deletion lib/plugins/Label_2P_POS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,15 @@ export class Label_2P_POS extends DecoderPlugin {
decodeResult.message = message;

const msg = message.text.replace(/\n|\r/g, "");
const decoded = H1Helper.decodeH1Message(decodeResult, msg);
const parts = msg.split('/');
let decoded = false;
if (parts[0].length > 3) {
decoded = H1Helper.decodeH1Message(decodeResult, msg.slice(parts[0].length - 3));
// flight number is already decoded in other fields
decodeResult.remaining.text = parts[0].slice(0,3) + '/' + decodeResult.remaining.text;
} else {
decoded = H1Helper.decodeH1Message(decodeResult, msg);
}
decodeResult.decoded = decoded;

decodeResult.decoder.decodeLevel = !decodeResult.remaining.text ? 'full' : 'partial';
Expand Down
1 change: 0 additions & 1 deletion lib/plugins/Label_44_IN.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { decode } from 'punycode';
import { MessageDecoder } from '../MessageDecoder';
import { Label_44_IN } from './Label_44_IN';

Expand Down
1 change: 0 additions & 1 deletion lib/plugins/Label_44_OFF.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { decode } from 'punycode';
import { MessageDecoder } from '../MessageDecoder';
import { Label_44_OFF } from './Label_44_OFF';

Expand Down
1 change: 0 additions & 1 deletion lib/plugins/Label_44_ON.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { decode } from 'punycode';
import { MessageDecoder } from '../MessageDecoder';
import { Label_44_ON } from './Label_44_ON';

Expand Down
2 changes: 1 addition & 1 deletion lib/plugins/Label_44_POS.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ test('decodes Label 44 Preamble POS02 variant 1', () => {
});

// disabled because current parser decodes 'full'
xtest('decodes Label 44 Preamble POS02 <invalid>', () => {
test.skip('decodes Label 44 Preamble POS02 <invalid>', () => {
const decoder = new MessageDecoder();
const decoderPlugin = new Label_44_POS(decoder);

Expand Down
2 changes: 1 addition & 1 deletion lib/plugins/Label_4A_01.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ test('decodes Label 4A_01', () => {
});

// disabled because all messages should decode
xtest('decodes Label 4A_01 <invalid>', () => {
test.skip('decodes Label 4A_01 <invalid>', () => {
const decoder = new MessageDecoder();
const decoderPlugin = new Label_4A_01(decoder);

Expand Down
2 changes: 1 addition & 1 deletion lib/plugins/Label_4A_DIS.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ test('decodes Label 4A_DIS', () => {
});

// disabled because all messages should decode
xtest('decodes Label 4A_DIS <invalid>', () => {
test.skip('decodes Label 4A_DIS <invalid>', () => {
const decoder = new MessageDecoder();
const decoderPlugin = new Label_4A_DIS(decoder);

Expand Down
2 changes: 1 addition & 1 deletion lib/plugins/Label_4A_DOOR.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ test('decodes Label 4A_DOOR', () => {
});

// disabled because all messages should decode
xtest('decodes Label 4A_DOOR <invalid>', () => {
test.skip('decodes Label 4A_DOOR <invalid>', () => {
const decoder = new MessageDecoder();
const decoderPlugin = new Label_4A_DOOR(decoder);

Expand Down
2 changes: 1 addition & 1 deletion lib/plugins/Label_4A_Slash_01.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ test('decodes Label 4A_Slash_01', () => {
});

// disabled because all messages should decode
xtest('decodes Label 4A_Slash_01 <invalid>', () => {
test.skip('decodes Label 4A_Slash_01 <invalid>', () => {
const decoder = new MessageDecoder();
const decoderPlugin = new Label_4A_Slash_01(decoder);

Expand Down
40 changes: 3 additions & 37 deletions lib/plugins/Label_4J_POS.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ describe('Label 4J POS', () => {
});
});


test('decodes msg 1', () => {
// Disabled due to checksum mismatch. Possibly non-ascii characters in message?
test.skip('decodes msg 1', () => {
// https://app.airframes.io/messages/2434848463
const text = 'POS/ID91459S,BANKR31,/DC03032024,142813/MR64,0/ET31539/PSN39277W077359,142800,240,N39300W077110,031430,N38560W077150,M28,27619,MT370/CG311,160,350/FB732/VR329071';
const decodeResult = plugin.decode({ text: text });
Expand Down Expand Up @@ -54,48 +54,14 @@ describe('Label 4J POS', () => {
expect(decodeResult.remaining.text).toBe('MR64,0,27619,MT370/CG311,160,350/FB732/VR32');
});

// this can probably go away, as it's the same format as msg 1
// but it was in Label_H1_POS.test.ts
test('decodes msg 2', () => {
// https://app.airframes.io/messages/3157551384
const text = 'POS/ID91517S,WIDE21,7PZWTCP21222/DC09082024,140706/MR238,2/ET91456/PSN37375W077368,140700,300,JAXSN,091417,LOOEY,M26,21329,M080T490/CG293,160,350/FB583/VR32C696';
const decodeResult = plugin.decode({ text: text });

expect(decodeResult.decoded).toBe(true);
expect(decodeResult.decoder.decodeLevel).toBe('partial')
expect(decodeResult.formatted.description).toBe('Position Report');
expect(decodeResult.raw.message_timestamp).toBe(1725804426);
expect(decodeResult.raw.mission_number).toBe('7PZWTCP21222');
expect(decodeResult.formatted.items.length).toBe(9);
expect(decodeResult.formatted.items[0].label).toBe('Tail');
expect(decodeResult.formatted.items[0].value).toBe('91517S');
expect(decodeResult.formatted.items[1].label).toBe('Flight Number');
expect(decodeResult.formatted.items[1].value).toBe('WIDE21');
expect(decodeResult.formatted.items[2].label).toBe('Day of Month');
expect(decodeResult.formatted.items[2].value).toBe('9');
expect(decodeResult.formatted.items[3].label).toBe('Estimated Time of Arrival');
expect(decodeResult.formatted.items[3].value).toBe('14:56:00');
expect(decodeResult.formatted.items[4].label).toBe('Aircraft Position');
expect(decodeResult.formatted.items[4].value).toBe('37.625 N, 77.613 W');
expect(decodeResult.formatted.items[5].label).toBe('Aircraft Route');
expect(decodeResult.formatted.items[5].value).toBe('JAXSN@14:07:00 > LOOEY@09:14:17 > ?');
expect(decodeResult.formatted.items[6].label).toBe('Altitude');
expect(decodeResult.formatted.items[6].value).toBe('30000 feet');
expect(decodeResult.formatted.items[7].label).toBe('Outside Air Temperature (C)');
expect(decodeResult.formatted.items[7].value).toBe('-26 degrees');
expect(decodeResult.formatted.items[8].label).toBe('Message Checksum');
expect(decodeResult.formatted.items[8].value).toBe('0xc696');
expect(decodeResult.remaining.text).toBe('MR238,2,21329,M080T490/CG293,160,350/FB583/VR32');
});

test('decodes <invalid>', () => {

const text = 'POS/ Bogus message';
const decodeResult = plugin.decode({ text: text });

expect(decodeResult.decoded).toBe(false);
expect(decodeResult.decoder.decodeLevel).toBe('none');
expect(decodeResult.formatted.description).toBe('Position Report');
expect(decodeResult.formatted.description).toBe('Unknown');
expect(decodeResult.formatted.items.length).toBe(0);
});
});
11 changes: 0 additions & 11 deletions lib/plugins/Label_H1.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,4 @@ describe('Label_H1 INI', () => {
labels: ['H1'],
});
});

test('INI <invalid>', () => {

const text = 'Bogus message';
const decodeResult = plugin.decode({ text: text });

expect(decodeResult.decoded).toBe(false);
expect(decodeResult.decoder.decodeLevel).toBe('none');
expect(decodeResult.formatted.description).toBe('Unknown H1 Message');
expect(decodeResult.message.text).toBe(text);
});
});
16 changes: 15 additions & 1 deletion lib/plugins/Label_H1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,21 @@ export class Label_H1 extends DecoderPlugin {
decodeResult.message = message;

const msg = message.text.replace(/\n|\r/g, "");
const decoded = H1Helper.decodeH1Message(decodeResult, msg);
const parts = msg.split('#');
let decoded = false;
if(parts.length === 1) {
decoded = H1Helper.decodeH1Message(decodeResult, msg);
} else if (parts.length == 2) {
const offset = isNaN(parseInt(parts[1][1])) ? 3: 4;
decoded = H1Helper.decodeH1Message(decodeResult, msg.slice(parts[0].length + offset)); // skip up to # and then a little more
if (decoded && parts[0].length > 0) {
// ResultFormatter.unknown(decodeResult, parts[0].substring(0, 4));
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commented-out code should either be removed or explained with a TODO comment if it's temporarily disabled for a specific reason.

Suggested change
// ResultFormatter.unknown(decodeResult, parts[0].substring(0, 4));
// TODO: Previously treated the first 4 characters as an unknown field; kept commented out in favor of using flightNumber below.

Copilot uses AI. Check for mistakes.
ResultFormatter.flightNumber(decodeResult, parts[0].substring(4));
Comment on lines +27 to +29
Copy link

Copilot AI Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commented-out code should either be removed or explained with a TODO comment if it's temporarily disabled for a specific reason.

Suggested change
if (decoded && parts[0].length > 0) {
// ResultFormatter.unknown(decodeResult, parts[0].substring(0, 4));
ResultFormatter.flightNumber(decodeResult, parts[0].substring(4));
if (decoded && parts[0].length > 0) {
// TODO: Legacy handling of the prefix as an unknown field; kept for reference in case H1 prefix parsing needs to be restored.
// ResultFormatter.unknown(decodeResult, parts[0].substring(0, 4));
ResultFormatter.flightNumber(decodeResult, parts[0].substring(4));
// TODO: Legacy handling of the segment after '#' as an unknown field; kept for reference while current parsing relies on remaining.text.

Copilot uses AI. Check for mistakes.
//ResultFormatter.unknown(decodeResult, parts[1].length == 5 ? parts[1].substring(0, 2) : parts[1].substring(0, 3), '#');
// hack of the highest degree as we've parsed the rest of the message already but we want the remaining text to be in order
decodeResult.remaining.text = parts[0].substring(0, 4) + '#' + parts[1].substring(0, offset -1) + '/' + decodeResult.remaining.text;
}
}
decodeResult.decoded = decoded;

decodeResult.decoder.decodeLevel = !decodeResult.remaining.text ? 'full' : 'partial';
Expand Down
65 changes: 43 additions & 22 deletions lib/plugins/Label_H1_FPN.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,30 +233,21 @@ describe('Label_H1 FPN', () => {
expect(decodeResult.decoded).toBe(true);
expect(decodeResult.decoder.decodeLevel).toBe('partial');
expect(decodeResult.raw.message_timestamp).toBe(1708730408);
expect(decodeResult.raw.flight_number).toBe('KL0767');
expect(decodeResult.raw.route_status).toBe('RP');
expect(decodeResult.raw.departure_icao).toBe('TNCA');
expect(decodeResult.raw.arrival_icao).toBe('TNCB');
expect(decodeResult.raw.departure_runway).toBe('11O');
expect(decodeResult.raw.procedures.length).toBe(2);
expect(decodeResult.raw.procedures[0].type).toBe('departure');
expect(decodeResult.raw.procedures[0].route.name).toBe('ADRI1F');
expect(decodeResult.raw.procedures[1].type).toBe('approach');
expect(decodeResult.raw.procedures[1].route.name).toBe('RNV10(10O)');
expect(decodeResult.raw.fuel_on_board).toBe(119);
expect(decodeResult.raw.eta_time).toBe(85448);
expect(decodeResult.raw.checksum).toBe(0x47c0);
expect(decodeResult.formatted.description).toBe('Flight Plan');
expect(decodeResult.formatted.items.length).toBe(11);
expect(decodeResult.formatted.items[0].label).toBe('Flight Number');
expect(decodeResult.formatted.items[0].value).toBe('KL0767');
expect(decodeResult.formatted.items[1].label).toBe('Route Status');
expect(decodeResult.formatted.items[1].value).toBe('Route Planned');
expect(decodeResult.formatted.items[2].label).toBe('Origin');
expect(decodeResult.formatted.items[2].value).toBe('TNCA');
expect(decodeResult.formatted.items[3].label).toBe('Destination');
expect(decodeResult.formatted.items[3].value).toBe('TNCB');
expect(decodeResult.formatted.items[4].label).toBe('Departure Runway');
expect(decodeResult.formatted.items[4].value).toBe('11O');
expect(decodeResult.formatted.items[5].label).toBe('Departure Procedure');
expect(decodeResult.formatted.items[5].value).toBe('ADRI1F: >> IRLEP > A574 >> PJG');
expect(decodeResult.formatted.items[6].label).toBe('Approach Procedure');
expect(decodeResult.formatted.items[6].value).toBe('RNV10(10O)');
expect(decodeResult.formatted.items[7].label).toBe('Arrival Runway');
expect(decodeResult.formatted.items[7].value).toBe('10O');
expect(decodeResult.formatted.items[8].label).toBe('Fuel On Board');
expect(decodeResult.formatted.items[8].value).toBe('119');
expect(decodeResult.formatted.items[9].label).toBe('Estimated Time of Arrival');
expect(decodeResult.formatted.items[9].value).toBe('23:44:08');
expect(decodeResult.formatted.items[10].label).toBe('Message Checksum');
expect(decodeResult.formatted.items[10].value).toBe('0x47c0');
expect(decodeResult.remaining.text).toBe('F37A#M1B/PR,,110,,183,7,13,,M7,25,,,P30,M40,36090,13,3455,300');
});

Expand All @@ -266,7 +257,37 @@ describe('Label_H1 FPN', () => {

expect(decodeResult.decoded).toBe(false);
expect(decodeResult.decoder.decodeLevel).toBe('none');
expect(decodeResult.formatted.description).toBe('Unknown');
expect(decodeResult.message.text).toBe(text);
});

test('decode RM', () => { // TODO: enable
const text = 'FPN/ID88194A,RCH857,PMZM107QP021/MR2,/RM:AA:FJDG:F:DOH.N300..NOLSU.P307..SETSI.P307..PARAR..N20000E063000..RIGLO.L516..ELKEL.L516..BUMMR/WP,,,,E3E9';
Comment on lines +264 to +265
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Resolve the stale TODO on the RM decode test.
The test is enabled; either remove the TODO or mark the test skipped with an issue link if it’s still unstable.

If you want, I can draft a skip + issue-link pattern here.

🤖 Prompt for AI Agents
In `@lib/plugins/Label_H1_FPN.test.ts` around lines 265 - 266, The test labeled
"decode RM" currently has a stale TODO comment; either remove the "// TODO:
enable" and leave the test active or explicitly skip it using the
test.skip('decode RM', ...) pattern and add an issue link/comment referencing
the bug/issue tracking its instability; update the test declaration (the symbol
to change is the test call named "decode RM" in Label_H1_FPN.test.ts)
accordingly so intent is clear.

const decodeResult = plugin.decode({ text: text });

expect(decodeResult.decoded).toBe(true);
expect(decodeResult.decoder.decodeLevel).toBe('partial');
expect(decodeResult.raw.tail).toBe('88194A');
expect(decodeResult.raw.flight_number).toBe('RCH857');
expect(decodeResult.raw.mission_number).toBe('PMZM107QP021');
expect(decodeResult.raw.route_status).toBe('RM');
expect(decodeResult.raw.arrival_icao).toBe('FJDG');
expect(decodeResult.raw.route.waypoints.length).toBe(20);
expect(decodeResult.raw.route.waypoints[0].name).toBe('DOH');
expect(decodeResult.raw.route.waypoints[19].name).toBe('BUMMR');
expect(decodeResult.raw.checksum).toBe(0xe3e9);
expect(decodeResult.formatted.description).toBe('Flight Plan');
expect(decodeResult.formatted.items.length).toBe(6);
expect(decodeResult.message.text).toBe(text);
});

test('Decodes Empty Message', () => {
const text = 'FPNEEE6';
const decodeResult = plugin.decode({ text: text });

expect(decodeResult.decoded).toBe(true);
expect(decodeResult.decoder.decodeLevel).toBe('full');
expect(decodeResult.raw.checksum).toBe(0xeee6);
expect(decodeResult.formatted.items.length).toBe(1);
});
});
Loading