Skip to content
Open
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
16 changes: 16 additions & 0 deletions .github/workflows/ads-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: ADS check

on:
push:
branches: [master, dsl/adopt-v1]
pull_request:
workflow_dispatch:

jobs:
ads-generated-up-to-date:
uses: airframesio/acars-decoder/.github/workflows/codegen-check.yml@init/ads-v1
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Get the commit SHA for the init/ads-v1 branch
gh api repos/airframesio/acars-decoder/git/ref/heads/init/ads-v1 --jq '.object.sha'

Repository: airframesio/acars-decoder-typescript

Length of output: 121


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the workflow content around the referenced `uses:` line and top-level permissions
echo "=== File head (with line numbers) ==="
nl -ba .github/workflows/ads-check.yml | head -n 120

echo
echo "=== Grep for permissions/use blocks ==="
rg -n "^[[:space:]]*permissions:|^[[:space:]]*uses:" .github/workflows/ads-check.yml || true

Repository: airframesio/acars-decoder-typescript

Length of output: 179


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "=== Confirm file exists ==="
ls -la .github/workflows/ads-check.yml

echo
echo "=== File head (with line numbers) ==="
cat -n .github/workflows/ads-check.yml | head -n 120

echo
echo "=== Grep for permissions/use blocks ==="
rg -n "^[[:space:]]*permissions:|^[[:space:]]*uses:" .github/workflows/ads-check.yml || true

echo
echo "=== Show lines around uses: (approx) ==="
# Show a reasonable window around the reported uses line
sed -n '1,80p' .github/workflows/ads-check.yml

Repository: airframesio/acars-decoder-typescript

Length of output: 1299


🏁 Script executed:

#!/bin/bash
set -euo pipefail
echo "=== Full file ==="
cat -n .github/workflows/ads-check.yml

Repository: airframesio/acars-decoder-typescript

Length of output: 605


Pin the reusable workflow to a commit SHA.

.github/workflows/ads-check.yml (job ads-generated-up-to-date) currently calls codegen-check.yml via a branch ref (@init/ads-v1), which is a supply-chain risk. Pin it to the current commit for that ref:

uses: airframesio/acars-decoder/.github/workflows/codegen-check.yml@6da198f085a6ae56eb0291fe938c239aef8faa93

Also add an explicit permissions: block (workflow- or job-level) to scope GITHUB_TOKEN to the minimum required; this workflow currently has no permissions: configured.

🧰 Tools
🪛 GitHub Check: CodeQL

[warning] 11-16: Workflow does not contain permissions
Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {{}}

🪛 zizmor (1.25.2)

[error] 11-11: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ads-check.yml at line 11, Update the reusable workflow
reference used by the ads-generated-up-to-date job (the line using
airframesio/acars-decoder/.github/workflows/codegen-check.yml@init/ads-v1) to
pin it to the specific commit SHA provided in the review and replace the branch
ref with that SHA; also add an explicit permissions: block (either at workflow
top or inside the ads-generated-up-to-date job) that scopes GITHUB_TOKEN to the
minimum required permissions for the codegen check so the workflow no longer
relies on default, broad token scopes.

with:
Comment on lines +9 to +12
language: ts
generated-path: lib/plugins/generated
spec-path: vendor/airframes-decoder/spec
codegen-path: vendor/airframes-decoder/codegen

Check warning

Code scanning / CodeQL

Workflow does not contain permissions Medium

Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {}
Comment on lines +11 to +16
Comment on lines +10 to +16
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add an explicit permissions block.

The workflow inherits default GITHUB_TOKEN permissions, which may be broader than required. For a validation-only workflow that runs codegen checks, read-only access should suffice.

🛡️ Proposed fix to add minimal permissions
 jobs:
   ads-generated-up-to-date:
+    permissions:
+      contents: read
     uses: airframesio/acars-decoder/.github/workflows/codegen-check.yml@init/ads-v1

Adjust permissions based on what the reusable workflow actually requires. If it only validates generated code, contents: read should be sufficient.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
ads-generated-up-to-date:
uses: airframesio/acars-decoder/.github/workflows/codegen-check.yml@init/ads-v1
with:
language: ts
generated-path: lib/plugins/generated
spec-path: vendor/airframes-decoder/spec
codegen-path: vendor/airframes-decoder/codegen
ads-generated-up-to-date:
permissions:
contents: read
uses: airframesio/acars-decoder/.github/workflows/codegen-check.yml@init/ads-v1
with:
language: ts
generated-path: lib/plugins/generated
spec-path: vendor/airframes-decoder/spec
codegen-path: vendor/airframes-decoder/codegen
🧰 Tools
🪛 GitHub Check: CodeQL

[warning] 11-16: Workflow does not contain permissions
Actions job or workflow does not limit the permissions of the GITHUB_TOKEN. Consider setting an explicit permissions block, using the following as a minimal starting point: {{}}

🪛 zizmor (1.25.2)

[warning] 10-17: overly broad permissions (excessive-permissions): default permissions used due to no permissions: block

(excessive-permissions)


[error] 11-11: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ads-check.yml around lines 10 - 16, The workflow job
ads-generated-up-to-date is missing an explicit permissions block and currently
inherits default GITHUB_TOKEN rights; add a minimal permissions section to the
workflow (at the top-level of the job or workflow) granting only what the
reusable workflow needs—e.g., permissions: contents: read—so the codegen-check
invocation (uses:
airframesio/acars-decoder/.github/workflows/codegen-check.yml@init/ads-v1) runs
with least privilege.

3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "vendor/airframes-decoder"]
path = vendor/airframes-decoder
url = https://github.com/airframesio/acars-decoder.git
4 changes: 4 additions & 0 deletions eslint.config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ import importPlugin from 'eslint-plugin-import';
import stylistic from '@stylistic/eslint-plugin';

export default [
{
// Skip the vendored submodule and the auto-generated plugins from linting.
ignores: ['vendor/**', 'lib/plugins/generated/**'],
},
{
files: ['**/*.ts'],

Expand Down
16 changes: 12 additions & 4 deletions jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,14 @@ export default {
// ],

// A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module
// moduleNameMapper: {},
moduleNameMapper: {
"^@airframes/ads-runtime-ts$":
"<rootDir>/vendor/airframes-decoder/runtimes/typescript/index.ts",
"^@airframes/ads-runtime-ts/helpers$":
"<rootDir>/vendor/airframes-decoder/runtimes/typescript/helpers.ts",
"^@airframes/ads-runtime-ts/escape_hatches$":
"<rootDir>/vendor/airframes-decoder/runtimes/typescript/escape_hatches/index.ts",
},
Comment on lines +91 to +98
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Fix quote style to match Prettier configuration.

All string literals in moduleNameMapper use double quotes, but Prettier is configured to enforce single quotes. This will cause linting to fail.

🎨 Proposed fix
  moduleNameMapper: {
-    "^`@airframes/ads-runtime-ts`$":
-      "<rootDir>/vendor/airframes-decoder/runtimes/typescript/index.ts",
-    "^`@airframes/ads-runtime-ts/helpers`$":
-      "<rootDir>/vendor/airframes-decoder/runtimes/typescript/helpers.ts",
-    "^`@airframes/ads-runtime-ts/escape_hatches`$":
-      "<rootDir>/vendor/airframes-decoder/runtimes/typescript/escape_hatches/index.ts",
+    '^`@airframes/ads-runtime-ts`$':
+      '<rootDir>/vendor/airframes-decoder/runtimes/typescript/index.ts',
+    '^`@airframes/ads-runtime-ts/helpers`$':
+      '<rootDir>/vendor/airframes-decoder/runtimes/typescript/helpers.ts',
+    '^`@airframes/ads-runtime-ts/escape_hatches`$':
+      '<rootDir>/vendor/airframes-decoder/runtimes/typescript/escape_hatches/index.ts',
  },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
moduleNameMapper: {
"^@airframes/ads-runtime-ts$":
"<rootDir>/vendor/airframes-decoder/runtimes/typescript/index.ts",
"^@airframes/ads-runtime-ts/helpers$":
"<rootDir>/vendor/airframes-decoder/runtimes/typescript/helpers.ts",
"^@airframes/ads-runtime-ts/escape_hatches$":
"<rootDir>/vendor/airframes-decoder/runtimes/typescript/escape_hatches/index.ts",
},
moduleNameMapper: {
'^`@airframes/ads-runtime-ts`$':
'<rootDir>/vendor/airframes-decoder/runtimes/typescript/index.ts',
'^`@airframes/ads-runtime-ts/helpers`$':
'<rootDir>/vendor/airframes-decoder/runtimes/typescript/helpers.ts',
'^`@airframes/ads-runtime-ts/escape_hatches`$':
'<rootDir>/vendor/airframes-decoder/runtimes/typescript/escape_hatches/index.ts',
},
🧰 Tools
🪛 ESLint

[error] 92-92: Replace "^@airframes/ads-runtime-ts$" with '^@airframes/ads-runtime-ts$'

(prettier/prettier)


[error] 93-93: Replace "<rootDir>/vendor/airframes-decoder/runtimes/typescript/index.ts" with '<rootDir>/vendor/airframes-decoder/runtimes/typescript/index.ts'

(prettier/prettier)


[error] 94-94: Replace "^@airframes/ads-runtime-ts/helpers$" with '^@airframes/ads-runtime-ts/helpers$'

(prettier/prettier)


[error] 95-95: Replace "<rootDir>/vendor/airframes-decoder/runtimes/typescript/helpers.ts" with '<rootDir>/vendor/airframes-decoder/runtimes/typescript/helpers.ts'

(prettier/prettier)


[error] 96-96: Replace "^@airframes/ads-runtime-ts/escape_hatches$" with '^@airframes/ads-runtime-ts/escape_hatches$'

(prettier/prettier)


[error] 97-97: Replace "<rootDir>/vendor/airframes-decoder/runtimes/typescript/escape_hatches/index.ts" with '<rootDir>/vendor/airframes-decoder/runtimes/typescript/escape_hatches/index.ts'

(prettier/prettier)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@jest.config.ts` around lines 91 - 98, Update the string literals in the
moduleNameMapper object to use single quotes to match Prettier settings: change
the keys and mapped path values inside moduleNameMapper (the
"^`@airframes/ads-runtime-ts`$", "^`@airframes/ads-runtime-ts/helpers`$",
"^`@airframes/ads-runtime-ts/escape_hatches`$" entries) from double-quoted to
single-quoted strings so linting/formatting passes.


// An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader
// modulePathIgnorePatterns: [],
Expand Down Expand Up @@ -159,9 +166,10 @@ export default {
// ],

// An array of regexp pattern strings that are matched against all test paths, matched tests are skipped
// testPathIgnorePatterns: [
// "/node_modules/"
// ],
testPathIgnorePatterns: [
"/node_modules/",
"/vendor/", // skip vendored airframes-decoder submodule's tests
],
Comment on lines +169 to +172
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Fix quote style to match Prettier configuration.

The string literals use double quotes, but Prettier is configured to enforce single quotes. This will cause the build to fail or require a formatting pass.

🎨 Proposed fix
  testPathIgnorePatterns: [
-    "/node_modules/",
-    "/vendor/", // skip vendored airframes-decoder submodule's tests
+    '/node_modules/',
+    '/vendor/', // skip vendored airframes-decoder submodule's tests
  ],
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
testPathIgnorePatterns: [
"/node_modules/",
"/vendor/", // skip vendored airframes-decoder submodule's tests
],
testPathIgnorePatterns: [
'/node_modules/',
'/vendor/', // skip vendored airframes-decoder submodule's tests
],
🧰 Tools
🪛 ESLint

[error] 163-163: Replace "/node_modules/" with '/node_modules/'

(prettier/prettier)


[error] 164-164: Replace "/vendor/" with '/vendor/'

(prettier/prettier)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@jest.config.ts` around lines 162 - 165, The string literals in the Jest
config's testPathIgnorePatterns array use double quotes which conflicts with the
project's Prettier single-quote rule; update the array entries (the values
within testPathIgnorePatterns) to use single quotes (e.g., '/node_modules/' and
'/vendor/') so formatting/linting passes, leaving the rest of the
testPathIgnorePatterns property and its comments unchanged.


// The regexp pattern or array of patterns that Jest uses to detect test files
// testRegex: [],
Expand Down
215 changes: 149 additions & 66 deletions lib/MessageDecoder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,77 +7,160 @@ import {

import * as Plugins from './plugins/official';

// Stage 2.5 bulk swap: ALL 67 plugins now run through the ADS-generated tree
// (lib/plugins/generated/*) backed by escape-hatch implementations in
// lib/plugins/escape_hatches/*. Behavior is byte-for-byte identical against
// the existing test suite.
//
// Label_4A: switched to whole-plugin parse-custom in the spec (matches the
// shape of other complex plugins like CBand and ARINC_702); hatch
// implements all three variants inline.
//
// Label_44_POS: keeps its declarative spec with two field-level customs
// (parse_flight_level_or_ground + flight_level_to_altitude_feet) backed
// by direct ports in lib/plugins/escape_hatches/Label_44_POS.ts.
import { Label_10_LDR as Gen_Label_10_LDR } from './plugins/generated/Label_10_LDR';
import { Label_10_POS as Gen_Label_10_POS } from './plugins/generated/Label_10_POS';
import { Label_10_Slash as Gen_Label_10_Slash } from './plugins/generated/Label_10_Slash';
import { Label_12_N_Space as Gen_Label_12_N_Space } from './plugins/generated/Label_12_N_Space';
import { Label_12_POS as Gen_Label_12_POS } from './plugins/generated/Label_12_POS';
import { Label_13Through18_Slash as Gen_Label_13Through18_Slash } from './plugins/generated/Label_13Through18_Slash';
import { Label_15 as Gen_Label_15 } from './plugins/generated/Label_15';
import { Label_15_FST as Gen_Label_15_FST } from './plugins/generated/Label_15_FST';
import { Label_16_AUTPOS as Gen_Label_16_AUTPOS } from './plugins/generated/Label_16_AUTPOS';
import { Label_16_Honeywell as Gen_Label_16_Honeywell } from './plugins/generated/Label_16_Honeywell';
import { Label_16_N_Space as Gen_Label_16_N_Space } from './plugins/generated/Label_16_N_Space';
import { Label_16_POSA1 as Gen_Label_16_POSA1 } from './plugins/generated/Label_16_POSA1';
import { Label_16_TOD as Gen_Label_16_TOD } from './plugins/generated/Label_16_TOD';
import { Label_1L_070 as Gen_Label_1L_070 } from './plugins/generated/Label_1L_070';
import { Label_1L_3Line as Gen_Label_1L_3Line } from './plugins/generated/Label_1L_3Line';
import { Label_1L_660 as Gen_Label_1L_660 } from './plugins/generated/Label_1L_660';
import { Label_1L_Slash as Gen_Label_1L_Slash } from './plugins/generated/Label_1L_Slash';
import { Label_1M_Slash as Gen_Label_1M_Slash } from './plugins/generated/Label_1M_Slash';
import { Label_20_CFB01 as Gen_Label_20_CFB01 } from './plugins/generated/Label_20_CFB01';
import { Label_20_POS as Gen_Label_20_POS } from './plugins/generated/Label_20_POS';
import { Label_21_POS as Gen_Label_21_POS } from './plugins/generated/Label_21_POS';
import { Label_22_OFF as Gen_Label_22_OFF } from './plugins/generated/Label_22_OFF';
import { Label_22_POS as Gen_Label_22_POS } from './plugins/generated/Label_22_POS';
import { Label_24_Slash as Gen_Label_24_Slash } from './plugins/generated/Label_24_Slash';
import { Label_2P_FM3 as Gen_Label_2P_FM3 } from './plugins/generated/Label_2P_FM3';
import { Label_2P_FM4 as Gen_Label_2P_FM4 } from './plugins/generated/Label_2P_FM4';
import { Label_2P_FM5 as Gen_Label_2P_FM5 } from './plugins/generated/Label_2P_FM5';
import { Label_30_Slash_EA as Gen_Label_30_Slash_EA } from './plugins/generated/Label_30_Slash_EA';
import { Label_44_ETA as Gen_Label_44_ETA } from './plugins/generated/Label_44_ETA';
import { Label_44_IN as Gen_Label_44_IN } from './plugins/generated/Label_44_IN';
import { Label_44_OFF as Gen_Label_44_OFF } from './plugins/generated/Label_44_OFF';
import { Label_44_ON as Gen_Label_44_ON } from './plugins/generated/Label_44_ON';
import { Label_44_POS as Gen_Label_44_POS } from './plugins/generated/Label_44_POS';
import { Label_44_Slash as Gen_Label_44_Slash } from './plugins/generated/Label_44_Slash';
import { Label_4A as Gen_Label_4A } from './plugins/generated/Label_4A';
import { Label_4A_01 as Gen_Label_4A_01 } from './plugins/generated/Label_4A_01';
import { Label_4A_DIS as Gen_Label_4A_DIS } from './plugins/generated/Label_4A_DIS';
import { Label_4A_DOOR as Gen_Label_4A_DOOR } from './plugins/generated/Label_4A_DOOR';
import { Label_4A_Slash_01 as Gen_Label_4A_Slash_01 } from './plugins/generated/Label_4A_Slash_01';
import { Label_4N as Gen_Label_4N } from './plugins/generated/Label_4N';
import { Label_4T_AGFSR as Gen_Label_4T_AGFSR } from './plugins/generated/Label_4T_AGFSR';
import { Label_4T_ETA as Gen_Label_4T_ETA } from './plugins/generated/Label_4T_ETA';
import { Label_58 as Gen_Label_58 } from './plugins/generated/Label_58';
import { Label_5Z_Slash as Gen_Label_5Z_Slash } from './plugins/generated/Label_5Z_Slash';
import { Label_80 as Gen_Label_80 } from './plugins/generated/Label_80';
import { Label_83 as Gen_Label_83 } from './plugins/generated/Label_83';
import { Label_8E as Gen_Label_8E } from './plugins/generated/Label_8E';
import { Label_B6_Forwardslash as Gen_Label_B6_Forwardslash } from './plugins/generated/Label_B6_Forwardslash';
import { Label_ColonComma as Gen_Label_ColonComma } from './plugins/generated/Label_ColonComma';
import { Label_H1_ATIS as Gen_Label_H1_ATIS } from './plugins/generated/Label_H1_ATIS';
import { Label_H1_EZF as Gen_Label_H1_EZF } from './plugins/generated/Label_H1_EZF';
import { Label_H1_FLR as Gen_Label_H1_FLR } from './plugins/generated/Label_H1_FLR';
import { Label_H1_M_POS as Gen_Label_H1_M_POS } from './plugins/generated/Label_H1_M_POS';
import { Label_H1_OFP as Gen_Label_H1_OFP } from './plugins/generated/Label_H1_OFP';
import { Label_H1_OHMA as Gen_Label_H1_OHMA } from './plugins/generated/Label_H1_OHMA';
import { Label_H1_Paren as Gen_Label_H1_Paren } from './plugins/generated/Label_H1_Paren';
import { Label_H1_StarPOS as Gen_Label_H1_StarPOS } from './plugins/generated/Label_H1_StarPOS';
import { Label_H1_WRN as Gen_Label_H1_WRN } from './plugins/generated/Label_H1_WRN';
import { Label_H2_02E as Gen_Label_H2_02E } from './plugins/generated/Label_H2_02E';
import { Label_HX as Gen_Label_HX } from './plugins/generated/Label_HX';
import { Label_MA as Gen_Label_MA } from './plugins/generated/Label_MA';
import { Label_QP as Gen_Label_QP } from './plugins/generated/Label_QP';
import { Label_QQ as Gen_Label_QQ } from './plugins/generated/Label_QQ';
import { Label_QR as Gen_Label_QR } from './plugins/generated/Label_QR';
import { Label_QS as Gen_Label_QS } from './plugins/generated/Label_QS';
import { Label_SQ as Gen_Label_SQ } from './plugins/generated/Label_SQ';
import { ARINC_702 as Gen_ARINC_702 } from './plugins/generated/ARINC_702';
import { CBand as Gen_CBand } from './plugins/generated/CBand';

/**
* Ordered list of plugin constructors. Order matters — plugins are tried
* sequentially until one returns decoded: true.
*/
const pluginClasses = [
Plugins.CBand, // first, for now, so it can wrap other plugins
Plugins.Arinc702,
Plugins.Label_ColonComma,
Plugins.Label_5Z_Slash,
Plugins.Label_10_LDR,
Plugins.Label_10_POS,
Plugins.Label_10_Slash,
Plugins.Label_12_N_Space,
Plugins.Label_12_POS,
Plugins.Label_13Through18_Slash,
Plugins.Label_15,
Plugins.Label_15_FST,
Plugins.Label_16_Honeywell,
Plugins.Label_16_N_Space,
Plugins.Label_16_POSA1,
Plugins.Label_16_TOD,
Plugins.Label_1L_3Line,
Plugins.Label_1L_070,
Plugins.Label_1L_660,
Plugins.Label_1L_Slash,
Plugins.Label_20_POS,
Plugins.Label_21_POS,
Plugins.Label_22_OFF,
Plugins.Label_22_POS,
Plugins.Label_24_Slash,
Plugins.Label_2P_FM3,
Plugins.Label_2P_FM4,
Plugins.Label_2P_FM5,
Plugins.Label_30_Slash_EA,
Plugins.Label_44_ETA,
Plugins.Label_44_IN,
Plugins.Label_44_OFF,
Plugins.Label_44_ON,
Plugins.Label_44_POS,
Plugins.Label_44_Slash,
Plugins.Label_4A,
Plugins.Label_4A_01,
Plugins.Label_4A_DIS,
Plugins.Label_4A_DOOR,
Plugins.Label_4A_Slash_01,
Plugins.Label_4N,
Plugins.Label_4T_AGFSR,
Plugins.Label_4T_ETA,
Plugins.Label_B6_Forwardslash,
Plugins.Label_H2_02E,
Plugins.Label_H1_ATIS,
Plugins.Label_H1_EZF,
Plugins.Label_H1_FLR,
Plugins.Label_H1_M_POS,
Plugins.Label_H1_OHMA,
Plugins.Label_H1_OFP,
Plugins.Label_H1_Paren,
Plugins.Label_H1_WRN,
Plugins.Label_H1_StarPOS,
Plugins.Label_HX,
Plugins.Label_58,
Plugins.Label_80,
Plugins.Label_83,
Plugins.Label_8E,
Plugins.Label_1M_Slash,
Plugins.Label_MA,
Plugins.Label_SQ,
Plugins.Label_QP,
Plugins.Label_QQ,
Plugins.Label_QR,
Plugins.Label_QS,
Gen_CBand, // first, for now, so it can wrap other plugins
Gen_ARINC_702,
Gen_Label_ColonComma,
Gen_Label_5Z_Slash,
Gen_Label_10_LDR,
Gen_Label_10_POS,
Gen_Label_10_Slash,
Gen_Label_12_N_Space,
Gen_Label_12_POS,
Gen_Label_13Through18_Slash,
Gen_Label_15,
Gen_Label_15_FST,
Gen_Label_16_AUTPOS,
Gen_Label_16_Honeywell,
Gen_Label_16_N_Space,
Gen_Label_16_POSA1,
Gen_Label_16_TOD,
Gen_Label_1L_3Line,
Gen_Label_1L_070,
Gen_Label_1L_660,
Gen_Label_1L_Slash,
Gen_Label_20_CFB01,
Gen_Label_20_POS,
Gen_Label_21_POS,
Gen_Label_22_OFF,
Gen_Label_22_POS,
Gen_Label_24_Slash,
Gen_Label_2P_FM3,
Gen_Label_2P_FM4,
Gen_Label_2P_FM5,
Gen_Label_30_Slash_EA,
Gen_Label_44_ETA,
Gen_Label_44_IN,
Gen_Label_44_OFF,
Gen_Label_44_ON,
Gen_Label_44_POS,
Gen_Label_44_Slash,
Gen_Label_4A,
Gen_Label_4A_01,
Gen_Label_4A_DIS,
Gen_Label_4A_DOOR,
Gen_Label_4A_Slash_01,
Gen_Label_4N,
Gen_Label_4T_AGFSR,
Gen_Label_4T_ETA,
Gen_Label_B6_Forwardslash,
Gen_Label_H2_02E,
Gen_Label_H1_ATIS,
Gen_Label_H1_EZF,
Gen_Label_H1_FLR,
Gen_Label_H1_M_POS,
Gen_Label_H1_OHMA,
Gen_Label_H1_OFP,
Gen_Label_H1_Paren,
Gen_Label_H1_WRN,
Gen_Label_H1_StarPOS,
Gen_Label_HX,
Gen_Label_58,
Gen_Label_80,
Gen_Label_83,
Gen_Label_8E,
Gen_Label_1M_Slash,
Gen_Label_MA,
Gen_Label_SQ,
Gen_Label_QP,
Gen_Label_QQ,
Gen_Label_QR,
Gen_Label_QS,
];

export class MessageDecoder {
Expand Down
107 changes: 107 additions & 0 deletions lib/plugins/escape_hatches/ARINC_702.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import type {
DecodeResult,
DecoderPlugin,
Message,
Options,
} from '@airframes/ads-runtime-ts';
import { ResultFormatter } from '@airframes/ads-runtime-ts';
import { Arinc702Helper } from '../../utils/arinc_702_helper';

/**
* Whole-plugin parse hatch for ARINC_702 (ARINC 702 Message).
*
* Tries Arinc702Helper.decodeH1Message on, in order:
* 1. the raw (CR/LF stripped) text;
* 2. when the text starts with '/', the body after the first '.';
* 3. when split by '#' gives exactly two parts, the chunk after a
* heuristic offset (3 or 4 depending on preceding context),
* pulling the flight number from the leading chunk and rebuilding
* remaining.text in original order;
* 4. when split by '/' has a leading chunk > 3 chars, the slice
* starting 3 chars before the '/', with the leading 3 chars +
* '/' restored at the front of remaining.text.
*
* processDecodeResult finalizes the decoded flag and decodeLevel; if no
* items were emitted, falls back to unknown with debug logging.
*/
export function arinc_702_dispatch(
_plugin: DecoderPlugin,
message: Message,
result: DecodeResult,
options: Options,
): DecodeResult {
const msg = message.text.replace(/\n|\r/g, '');

let decoded = false;
decoded = Arinc702Helper.decodeH1Message(result, msg);
if (decoded) {
return processDecodeResult(result, decoded, options, message);
}

if (msg.startsWith('/')) {
const headerData = msg.split('.');
decoded = Arinc702Helper.decodeH1Message(
result,
headerData.slice(1).join('.'),
);

if (decoded) {
result.remaining.text =
headerData[0] + '.' + result.remaining.text;
return processDecodeResult(result, decoded, options, message);
}
}

const hashParts = msg.split('#');
if (hashParts.length === 2) {
const offset =
hashParts[0] === '- ' || isNaN(parseInt(hashParts[1][1])) ? 3 : 4;
decoded = Arinc702Helper.decodeH1Message(
result,
msg.slice(hashParts[0].length + offset),
);
if (decoded && hashParts[0].length > 0) {
ResultFormatter.flightNumber(result, hashParts[0].substring(4));
result.remaining.text =
hashParts[0].substring(0, 4) +
'#' +
hashParts[1].substring(0, offset - 1) +
'/' +
result.remaining.text;
}
if (decoded) {
return processDecodeResult(result, decoded, options, message);
}
}

const slashParts = msg.split('/');
if (slashParts[0].length > 3) {
decoded = Arinc702Helper.decodeH1Message(
result,
msg.slice(slashParts[0].length - 3),
);
result.remaining.text =
slashParts[0].slice(0, 3) + '/' + result.remaining.text;
}

return processDecodeResult(result, decoded, options, message);
}

function processDecodeResult(
result: DecodeResult,
decoded: boolean,
options: Options,
message: Message,
): DecodeResult {
result.decoded = decoded;
result.decoder.decodeLevel = !result.remaining.text ? 'full' : 'partial';
if (result.formatted.items.length === 0) {
if (options.debug) {
console.log(`Decoder: Unknown H1 message: ${message.text}`);
}
ResultFormatter.unknown(result, message.text);
result.decoded = false;
result.decoder.decodeLevel = 'none';
}
return result;
}
Loading
Loading