From 989594263323da1210f7a0d12721cfc492eb68da Mon Sep 17 00:00:00 2001 From: Sameh Khamis Date: Thu, 1 Oct 2026 12:05:41 -0700 Subject: [PATCH] refactor: move TLE text parsing into a portable source module The satellites layer parsed catalog text inside its Cesium-backed orbit owner. Move the parser unchanged to src/sources/tle.js, add a catalog number helper, and have the layer delegate to it so code outside the layer can read TLE text without loading rendering. --- scripts/package-boundaries.json | 3 +++ src/layers/satellites/orbits.js | 20 ++------------------ src/sources/tle.js | 27 +++++++++++++++++++++++++++ 3 files changed, 32 insertions(+), 18 deletions(-) create mode 100644 src/sources/tle.js diff --git a/scripts/package-boundaries.json b/scripts/package-boundaries.json index 636004286..2bb2e1121 100644 --- a/scripts/package-boundaries.json +++ b/scripts/package-boundaries.json @@ -922,6 +922,7 @@ "src/data/issPass.js", "src/data/satelliteClass.js", "src/data/satellitePass.js", + "src/sources/tle.js", "src/layers/satellites/catalog.js", "src/layers/satellites/controls.js", "src/layers/satellites/index.js", @@ -1659,6 +1660,7 @@ "src/layers/satellites/labels.js", "src/layers/satellites/lifecycle.js", "src/layers/satellites/orbits.js", + "src/sources/tle.js", "src/layers/satellites/records.js", "src/layers/satellites/policy.js", "src/layers/satellites/rendering.js", @@ -2323,6 +2325,7 @@ "src/layers/satellites/labels.js", "src/layers/satellites/lifecycle.js", "src/layers/satellites/orbits.js", + "src/sources/tle.js", "src/layers/satellites/records.js", "src/layers/satellites/policy.js", "src/layers/satellites/rendering.js", diff --git a/src/layers/satellites/orbits.js b/src/layers/satellites/orbits.js index ed26a8883..32bb57cf9 100644 --- a/src/layers/satellites/orbits.js +++ b/src/layers/satellites/orbits.js @@ -8,6 +8,7 @@ import { twoline2satrec, } from 'satellite.js'; import { findNextSatellitePass } from '../../data/satellitePass.js'; +import { parseTleText } from '../../sources/tle.js'; import { ORBIT_PATH_STEPS, ISS_NORAD } from './policy.js'; export function createOrbits({ state: layerState, services, parts, source }) { @@ -40,24 +41,7 @@ export function createOrbits({ state: layerState, services, parts, source }) { /** * Parse TLE text into array of { name, line1, line2 } objects. */ - - function parseTLE(text) { - const lines = text - .trim() - .split('\n') - .map((l) => l.trim()) - .filter((l) => l.length > 0); - const result = []; - for (let i = 0; i < lines.length - 2; i += 3) { - const name = lines[i]; - const line1 = lines[i + 1]; - const line2 = lines[i + 2]; - if (line1.startsWith('1 ') && line2.startsWith('2 ')) { - result.push({ name, line1, line2 }); - } - } - return result; - } + const parseTLE = parseTleText; /** * Propagate satellite position at a given JS Date. diff --git a/src/sources/tle.js b/src/sources/tle.js new file mode 100644 index 000000000..423651e6b --- /dev/null +++ b/src/sources/tle.js @@ -0,0 +1,27 @@ +/** + * Parse three-line TLE catalog text into `{ name, line1, line2 }` entries. + * Blocks whose second and third lines are not TLE lines 1 and 2 are skipped. + */ +export function parseTleText(text) { + const lines = String(text) + .trim() + .split('\n') + .map((line) => line.trim()) + .filter((line) => line.length > 0); + const result = []; + for (let i = 0; i < lines.length - 2; i += 3) { + const name = lines[i]; + const line1 = lines[i + 1]; + const line2 = lines[i + 2]; + if (line1.startsWith('1 ') && line2.startsWith('2 ')) { + result.push({ name, line1, line2 }); + } + } + return result; +} + +/** The NORAD catalog number from TLE line 1, or null. */ +export function tleCatalogNumber(line1) { + const number = Number.parseInt(String(line1).slice(2, 7), 10); + return Number.isInteger(number) ? number : null; +}