@saber-usa/node-common 1.7.33 → 1.7.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/tle/TleParseUtils.js +168 -147
package/package.json
CHANGED
package/src/tle/TleParseUtils.js
CHANGED
|
@@ -1,147 +1,168 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
static
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
"
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
* @param {string}
|
|
79
|
-
* @param {
|
|
80
|
-
* @param {
|
|
81
|
-
* @param {number}
|
|
82
|
-
* @
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
* @
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
1
|
+
import {isDefined} from "../utils.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Utility class for TLE parsing, including Alpha-5 TLE satellite IDs.
|
|
5
|
+
* Ported from org.orekit.propagation.analytical.tle.ParseUtils / TLE.
|
|
6
|
+
*
|
|
7
|
+
* Alpha-5 extends the range of existing 5-digit TLE satellite numbers
|
|
8
|
+
* by allowing the first digit to be an upper case letter, ignoring 'I'
|
|
9
|
+
* and 'O' to avoid confusion with numbers '1' and '0'.
|
|
10
|
+
*
|
|
11
|
+
* @see https://www.space-track.org/documentation#tle-alpha5
|
|
12
|
+
*/
|
|
13
|
+
export class TleParseUtils {
|
|
14
|
+
/** Maximum satellite number representable with 5 numeric digits. */
|
|
15
|
+
static MAX_NUMERIC_SATNUM = 99999;
|
|
16
|
+
|
|
17
|
+
/** Scaling factor for Alpha-5 numbers. */
|
|
18
|
+
static ALPHA5_SCALING = 10000;
|
|
19
|
+
|
|
20
|
+
/** Letter → number map for Alpha-5 satellite numbers. */
|
|
21
|
+
static ALPHA5_NUMBERS = new Map();
|
|
22
|
+
|
|
23
|
+
/** Number → letter map for Alpha-5 satellite numbers. */
|
|
24
|
+
static ALPHA5_LETTERS = new Map();
|
|
25
|
+
|
|
26
|
+
static {
|
|
27
|
+
const alpha5Letters = [
|
|
28
|
+
"A", "B", "C", "D", "E", "F", "G", "H", "J",
|
|
29
|
+
"K", "L", "M", "N", "P", "Q", "R", "S", "T",
|
|
30
|
+
"U", "V", "W", "X", "Y", "Z",
|
|
31
|
+
];
|
|
32
|
+
for (let i = 0; i < alpha5Letters.length; ++i) {
|
|
33
|
+
TleParseUtils.ALPHA5_NUMBERS.set(alpha5Letters[i], i + 10);
|
|
34
|
+
TleParseUtils.ALPHA5_LETTERS.set(i + 10, alpha5Letters[i]);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Private constructor for a utility class. */
|
|
39
|
+
constructor() {
|
|
40
|
+
throw new Error("TleParseUtils is a utility class and cannot be instantiated");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* True if token is a valid 5-char TLE catalog field:
|
|
45
|
+
* five digits, or Alpha-5 letter (no I/O) plus four digits.
|
|
46
|
+
* @param {string} token
|
|
47
|
+
* @return {boolean}
|
|
48
|
+
*/
|
|
49
|
+
static isValidSatelliteNumberField(token) {
|
|
50
|
+
if (typeof token !== "string" || token.length !== 5) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
if (/^\d{5}$/.test(token)) {
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
if (!TleParseUtils.ALPHA5_NUMBERS.has(token.charAt(0))) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
return /^\d{4}$/.test(token.substring(1));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Stricter int parser: accepts an optional sign plus digits only, else throws.
|
|
64
|
+
* Unlike Number.parseInt, rejects partial parses (e.g. "12abc").
|
|
65
|
+
* @param {string} string
|
|
66
|
+
* @return {number}
|
|
67
|
+
*/
|
|
68
|
+
static #strictParseInt(string) {
|
|
69
|
+
if (!/^[+-]?\d+$/.test(string)) {
|
|
70
|
+
throw new Error(`Invalid integer: "${string}"`);
|
|
71
|
+
}
|
|
72
|
+
return Number.parseInt(string, 10);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Add padding characters to a string.
|
|
77
|
+
* Port of ParseUtils.addPadding.
|
|
78
|
+
* @param {string} name parameter name
|
|
79
|
+
* @param {string} string string to pad
|
|
80
|
+
* @param {string} c padding character
|
|
81
|
+
* @param {number} size desired size
|
|
82
|
+
* @param {boolean} rightJustified if true, pad on the left
|
|
83
|
+
* @param {number} satelliteNumber satellite number (for error context)
|
|
84
|
+
* @return {string} padded string
|
|
85
|
+
*/
|
|
86
|
+
static addPadding(name, string, c, size, rightJustified, satelliteNumber) {
|
|
87
|
+
if (string.length > size) {
|
|
88
|
+
throw new Error(
|
|
89
|
+
`TLE invalid parameter: satelliteNumber=${satelliteNumber}, name=${name}, value=${string}`,
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const padding = c.repeat(size);
|
|
94
|
+
|
|
95
|
+
if (rightJustified) {
|
|
96
|
+
const concatenated = padding + string;
|
|
97
|
+
const l = concatenated.length;
|
|
98
|
+
return concatenated.substring(l - size, l);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return (string + padding).substring(0, size);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Build an Alpha-5 (or numeric) satellite number field.
|
|
106
|
+
* Port of ParseUtils.buildSatelliteNumber.
|
|
107
|
+
* @param {number} satelliteNumber satellite number, that may exceed the 99999 limit
|
|
108
|
+
* @param {string} name parameter name (used in error messages)
|
|
109
|
+
* @return {string} satellite number in alpha5 / 5-digit representation
|
|
110
|
+
*/
|
|
111
|
+
static buildSatelliteNumber(satelliteNumber, name) {
|
|
112
|
+
if (satelliteNumber > TleParseUtils.MAX_NUMERIC_SATNUM) {
|
|
113
|
+
const highDigits = Math.trunc(satelliteNumber / TleParseUtils.ALPHA5_SCALING);
|
|
114
|
+
const lowDigits = satelliteNumber - highDigits * TleParseUtils.ALPHA5_SCALING;
|
|
115
|
+
|
|
116
|
+
const alpha = TleParseUtils.ALPHA5_LETTERS.get(highDigits);
|
|
117
|
+
if (alpha === undefined) {
|
|
118
|
+
throw new Error(
|
|
119
|
+
`TLE invalid parameter: satelliteNumber=${satelliteNumber}, name=${name}, value=null`,
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
return alpha + TleParseUtils.addPadding(
|
|
123
|
+
name, String(lowDigits), "0", 4, true, satelliteNumber,
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
return TleParseUtils.addPadding(
|
|
127
|
+
name, String(satelliteNumber), "0", 5, true, satelliteNumber,
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Parse a satellite number from a string field (supports Alpha-5).
|
|
133
|
+
* Port of TLE.parseSatelliteNumber / ParseUtils.parseSatelliteNumber.
|
|
134
|
+
* @param {string} satNumberString the string to parse (e.g., "25544" or "A0001")
|
|
135
|
+
* @return {number} the satellite number as an integer
|
|
136
|
+
*/
|
|
137
|
+
static getSatnoFromTle(satNumberString) {
|
|
138
|
+
if (!TleParseUtils.isValidSatelliteNumberField(satNumberString)) {
|
|
139
|
+
throw new Error(`Invalid satellite number field: "${satNumberString}"`);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const alpha = TleParseUtils.ALPHA5_NUMBERS.get(satNumberString.charAt(0));
|
|
143
|
+
if (alpha !== undefined) {
|
|
144
|
+
return (alpha * TleParseUtils.ALPHA5_SCALING)
|
|
145
|
+
+ TleParseUtils.#strictParseInt(satNumberString.substring(1));
|
|
146
|
+
}
|
|
147
|
+
return TleParseUtils.#strictParseInt(satNumberString);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Lenient catalog NORAD ID decode: 5-char TLE field (digits or Alpha-5),
|
|
152
|
+
* or an unpadded plain integer string (e.g. "16", "900").
|
|
153
|
+
* Returns null for nullish / empty / non-numeric values instead of throwing.
|
|
154
|
+
* @param {string|number|null|undefined} value
|
|
155
|
+
* @return {number|null}
|
|
156
|
+
*/
|
|
157
|
+
static parseCatalogSatno(value) {
|
|
158
|
+
if (!isDefined(value) || value === "") {
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
const token = String(value).trim();
|
|
162
|
+
if (TleParseUtils.isValidSatelliteNumberField(token)) {
|
|
163
|
+
return TleParseUtils.getSatnoFromTle(token);
|
|
164
|
+
}
|
|
165
|
+
const n = Number.parseInt(token, 10);
|
|
166
|
+
return Number.isNaN(n) ? null : n;
|
|
167
|
+
}
|
|
168
|
+
}
|