Merge remote-tracking branch 'origin/pr/google-street-view' into pr/google-street-view

This commit is contained in:
Said Turksever committed 2026-10-13 13:36:13 +01:00
commit eb07b9d5ad
3 files changed
+28 -2

No files matched your search

+4
View File
@@ -1184,6 +1184,10 @@ The Node-only `gods-eye-view/server/providers/space` export supplies factories;
`sources/space` supplies fixed upstream URL builders with no I/O or environment `sources/space` supplies fixed upstream URL builders with no I/O or environment
access. Callers retain validation, transport and response policy. access. Callers retain validation, transport and response policy.
The shared TLE text parser skips incomplete named sets and resumes at the next
complete set. A missing orbital line does not discard the later satellites in
the catalog; satellite layers and next-pass tools use the same parser.
## Build configuration and local provider boundaries ## Build configuration and local provider boundaries
`vite.config.js` delegates to `server/standalone/vite.config.js`, which loads `vite.config.js` delegates to `server/standalone/vite.config.js`, which loads
+3 -2
View File
@@ -1,6 +1,6 @@
/** /**
* Parse three-line TLE catalog text into `{ name, line1, line2 }` entries. * 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. * Malformed sets are skipped without dropping the valid sets that follow.
*/ */
export function parseTleText(text) { export function parseTleText(text) {
const lines = String(text) const lines = String(text)
@@ -9,12 +9,13 @@ export function parseTleText(text) {
.map((line) => line.trim()) .map((line) => line.trim())
.filter((line) => line.length > 0); .filter((line) => line.length > 0);
const result = []; const result = [];
for (let i = 0; i < lines.length - 2; i += 3) { for (let i = 0; i < lines.length - 2; i++) {
const name = lines[i]; const name = lines[i];
const line1 = lines[i + 1]; const line1 = lines[i + 1];
const line2 = lines[i + 2]; const line2 = lines[i + 2];
if (line1.startsWith('1 ') && line2.startsWith('2 ')) { if (line1.startsWith('1 ') && line2.startsWith('2 ')) {
result.push({ name, line1, line2 }); result.push({ name, line1, line2 });
i += 2;
} }
} }
return result; return result;
+21
View File
@@ -30,6 +30,27 @@ test('TLE text parses into named entries with catalog numbers', () => {
assert.equal(tleCatalogNumber('1 xx'), null); assert.equal(tleCatalogNumber('1 xx'), null);
}); });
for (const missingLine of [1, 2]) {
test(`TLE parsing resumes after a set missing line ${missingLine}`, () => {
const sets = Array.from({ length: 8 }, (_, i) => {
const lines = TLE.trim().split('\n').slice(0, 3);
lines[0] = `SAT ${i}`;
return lines;
});
sets[1].splice(missingLine, 1);
const entries = parseTleText(sets.flat().join('\r\n'));
assert.deepEqual(
entries.map((entry) => entry.name),
['SAT 0', 'SAT 2', 'SAT 3', 'SAT 4', 'SAT 5', 'SAT 6', 'SAT 7'],
);
assert.ok(
entries.every(
(entry) => entry.line1.startsWith('1 ') && entry.line2.startsWith('2 '),
),
);
});
}
test('the next pass defaults to the ISS and reports times, peak and direction', async () => { test('the next pass defaults to the ISS and reports times, peak and direction', async () => {
const catalog = composeCatalog({ const catalog = composeCatalog({
tools: coreTools, tools: coreTools,