@saber-usa/node-common 1.7.33 → 1.7.35
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 +6 -5
- package/src/astro.js +9 -10
- package/src/index.js +0 -3
- package/src/tle/TLEValidator.js +4 -5
- package/src/transform.js +1 -13
- package/src/udl.js +3 -6
- package/src/tle/TleParseUtils.js +0 -147
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@saber-usa/node-common",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.35",
|
|
4
4
|
"description": "Common node functions for Saber",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"test:wasmProp": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --config jest.config.wasmProp.js --no-coverage --silent --runInBand",
|
|
16
16
|
"test:all": "npm test && npm run test:wasmProp",
|
|
17
17
|
"bench:wasmProp": "node benchmarks/benchmarkBulkPropagator.js",
|
|
18
|
-
"sonar": "sonar -Dsonar.host.url=http://localhost:9000"
|
|
18
|
+
"sonar": "sonar-scanner-npm -Dsonar.host.url=http://localhost:9000"
|
|
19
19
|
},
|
|
20
20
|
"files": [
|
|
21
21
|
"src/**/*"
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"author": "Saber USA",
|
|
24
24
|
"license": "ISC",
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@aws-sdk/client-s3": "^3.
|
|
26
|
+
"@aws-sdk/client-s3": "^3.1092.0",
|
|
27
27
|
"date-fns": "^4.4.0",
|
|
28
28
|
"lodash": "4.18.1",
|
|
29
29
|
"mathjs": "^15.2.0",
|
|
@@ -39,10 +39,10 @@
|
|
|
39
39
|
"@babel/preset-env": "^8.0.2",
|
|
40
40
|
"@eslint/js": "^10.0.1",
|
|
41
41
|
"@jest/globals": "^30.4.1",
|
|
42
|
-
"@sonar/scan": "^
|
|
42
|
+
"@sonar/scan": "^5.0.0",
|
|
43
43
|
"cross-env": "^10.1.0",
|
|
44
44
|
"eslint": "^10.7.0",
|
|
45
|
-
"eslint-plugin-jest": "^29.15.
|
|
45
|
+
"eslint-plugin-jest": "^29.15.5",
|
|
46
46
|
"globals": "^17.7.0",
|
|
47
47
|
"jest": "^30.4.2",
|
|
48
48
|
"jest-diff": "^30.4.1",
|
|
@@ -50,6 +50,7 @@
|
|
|
50
50
|
},
|
|
51
51
|
"overrides": {
|
|
52
52
|
"braces": "3.0.3",
|
|
53
|
+
"brace-expansion": "2.1.2",
|
|
53
54
|
"lodash": "4.18.1"
|
|
54
55
|
}
|
|
55
56
|
}
|
package/src/astro.js
CHANGED
|
@@ -48,7 +48,6 @@ import {DEG2RAD,
|
|
|
48
48
|
import TLEValidator from "./tle/TLEValidator.js";
|
|
49
49
|
import MultiLineTLEValidator from "./tle/MultiLineTLEValidator.js";
|
|
50
50
|
import {TLE_ERRORS} from "./tle/tleErrors.js";
|
|
51
|
-
import {TleParseUtils} from "./tle/TleParseUtils.js";
|
|
52
51
|
|
|
53
52
|
// Solar Terminator
|
|
54
53
|
// Returns sun latitude and longitude as -180/180
|
|
@@ -146,24 +145,24 @@ const validateTle = (line1, line2) => {
|
|
|
146
145
|
* @return {boolean} true if the propagation output is valid, false otherwise
|
|
147
146
|
*/
|
|
148
147
|
const isPropagateValid = (out) => {
|
|
149
|
-
if (
|
|
148
|
+
if (out === null || out === undefined) {
|
|
150
149
|
return false;
|
|
151
150
|
}
|
|
152
151
|
|
|
153
152
|
if (out.position) {
|
|
154
153
|
const pos = out.position;
|
|
155
|
-
if (
|
|
156
|
-
||
|
|
157
|
-
||
|
|
154
|
+
if (pos.x === null || pos.x === undefined || Number.isNaN(pos.x)
|
|
155
|
+
|| pos.y === null || pos.y === undefined || Number.isNaN(pos.y)
|
|
156
|
+
|| pos.z === null || pos.z === undefined || Number.isNaN(pos.z)) {
|
|
158
157
|
return false;
|
|
159
158
|
}
|
|
160
159
|
}
|
|
161
160
|
|
|
162
161
|
if (out.velocity) {
|
|
163
162
|
const vel = out.velocity;
|
|
164
|
-
if (
|
|
165
|
-
||
|
|
166
|
-
||
|
|
163
|
+
if (vel.x === null || vel.x === undefined || Number.isNaN(vel.x)
|
|
164
|
+
|| vel.y === null || vel.y === undefined || Number.isNaN(vel.y)
|
|
165
|
+
|| vel.z === null || vel.z === undefined || Number.isNaN(vel.z)) {
|
|
167
166
|
return false;
|
|
168
167
|
}
|
|
169
168
|
}
|
|
@@ -1392,7 +1391,7 @@ const GetElsetUdlFromTle = (
|
|
|
1392
1391
|
// and we may be unsure of entering true or false for any reason.
|
|
1393
1392
|
if (isBoolean(isUct)) {
|
|
1394
1393
|
elset.uct = isUct;
|
|
1395
|
-
} else if (
|
|
1394
|
+
} else if (isUct === null || isUct === undefined) {
|
|
1396
1395
|
// Do nothing, do not populate nor put null.
|
|
1397
1396
|
} else {
|
|
1398
1397
|
throw new Error("Input uct flag is not of type boolean.");
|
|
@@ -1424,7 +1423,7 @@ const GetElsetUdlFromTle = (
|
|
|
1424
1423
|
const date = julianToGregorian(satrec.jdsatepoch);
|
|
1425
1424
|
elset.epoch = date.toISOString();
|
|
1426
1425
|
|
|
1427
|
-
elset.satNo =
|
|
1426
|
+
elset.satNo = Number.parseInt(satrec.satnum);
|
|
1428
1427
|
|
|
1429
1428
|
// Eccentricity
|
|
1430
1429
|
elset.eccentricity = satrec.ecco;
|
package/src/index.js
CHANGED
|
@@ -11,7 +11,6 @@ export * from "./OrbitUtils.js";
|
|
|
11
11
|
export * from "./PropagateUtils.js";
|
|
12
12
|
export * from "./ballisticPropagator.js";
|
|
13
13
|
export * from "./NodeVector3D.js";
|
|
14
|
-
export * from "./tle/TleParseUtils.js";
|
|
15
14
|
|
|
16
15
|
// UDL exports are grouped; re-export individually and as namespace if needed
|
|
17
16
|
import * as udl from "./udl.js";
|
|
@@ -31,7 +30,6 @@ import * as OrbitUtilsNS from "./OrbitUtils.js";
|
|
|
31
30
|
import * as PropagateUtilsNS from "./PropagateUtils.js";
|
|
32
31
|
import * as ballisticPropagatorNS from "./ballisticPropagator.js";
|
|
33
32
|
import * as NodeVector3DNS from "./NodeVector3D.js";
|
|
34
|
-
import * as TleParseUtilsNS from "./tle/TleParseUtils.js";
|
|
35
33
|
|
|
36
34
|
const aggregate = {
|
|
37
35
|
...loggerFactoryNS,
|
|
@@ -46,7 +44,6 @@ const aggregate = {
|
|
|
46
44
|
...PropagateUtilsNS,
|
|
47
45
|
...ballisticPropagatorNS,
|
|
48
46
|
...NodeVector3DNS,
|
|
49
|
-
...TleParseUtilsNS,
|
|
50
47
|
...udl,
|
|
51
48
|
};
|
|
52
49
|
|
package/src/tle/TLEValidator.js
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import {formatChecksumError, formatLengthError, TLE_ERRORS} from "./tleErrors.js";
|
|
2
|
-
import {TleParseUtils} from "./TleParseUtils.js";
|
|
3
2
|
|
|
4
3
|
/**
|
|
5
4
|
* NORAD TLE line-pair validator.
|
|
6
5
|
* Logic derived from whatswrongwithmytle.com (Dr. TS Kelso's field guide).
|
|
7
|
-
* Catalog-number grammar is owned by TleParseUtils (Alpha-5 aware).
|
|
8
6
|
*/
|
|
9
7
|
class TLEValidator {
|
|
10
8
|
constructor() {
|
|
9
|
+
this.lineOneRegexCatalogNumber = /[0-Z]{5}[CSU]/;
|
|
11
10
|
this.lineOneRegexInternationalDesignator = / (\d{5}[A-Z][ A-Z]{2}|\d{5}[ A-Z]{2}[A-Z]| {8})/;
|
|
12
11
|
this.lineOneRegexEpoch = / \d{5}\.\d{8}/;
|
|
13
12
|
this.lineOneRegexDMeanMotion = / [ +-]\.\d{8}/;
|
|
@@ -16,6 +15,7 @@ class TLEValidator {
|
|
|
16
15
|
this.lineOneRegexEphemType = / [0-5]/;
|
|
17
16
|
this.lineOneRegexSetNumber = / [ \d]{3}\d/;
|
|
18
17
|
|
|
18
|
+
this.lineTwoRegexCatalogNumber = /[0-Z]{5}/;
|
|
19
19
|
this.lineTwoRegexInclination = / [ \d]{3}\.\d{4}/;
|
|
20
20
|
this.lineTwoRegexRAAN = / [ \d]{3}\.\d{4}/;
|
|
21
21
|
this.lineTwoRegexEccentricity = / \d{7}/;
|
|
@@ -57,8 +57,7 @@ class TLEValidator {
|
|
|
57
57
|
if (line.length < 69) {
|
|
58
58
|
return formatLengthError(TLE_ERRORS.LINE1_LENGTH, line.length);
|
|
59
59
|
}
|
|
60
|
-
if (!
|
|
61
|
-
|| !/[CSU]/.test(line.slice(7, 8))) {
|
|
60
|
+
if (!this.lineOneRegexCatalogNumber.test(line.slice(2, 8))) {
|
|
62
61
|
return TLE_ERRORS.LINE1_CATALOG_NUMBER;
|
|
63
62
|
}
|
|
64
63
|
if (!this.lineOneRegexInternationalDesignator.test(line.slice(8, 17))) {
|
|
@@ -97,7 +96,7 @@ class TLEValidator {
|
|
|
97
96
|
if (line.length < 69) {
|
|
98
97
|
return formatLengthError(TLE_ERRORS.LINE2_LENGTH, line.length);
|
|
99
98
|
}
|
|
100
|
-
if (!
|
|
99
|
+
if (!this.lineTwoRegexCatalogNumber.test(line.slice(2, 7))) {
|
|
101
100
|
return TLE_ERRORS.LINE2_CATALOG_NUMBER;
|
|
102
101
|
}
|
|
103
102
|
if (!this.lineTwoRegexInclination.test(line.slice(7, 16))) {
|
package/src/transform.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import _ from "lodash";
|
|
2
|
-
import {isDefined} from "./utils.js";
|
|
3
2
|
|
|
4
3
|
const transformObjectKeys = (transform, object, deep = true) => _.cond([
|
|
5
4
|
[
|
|
@@ -33,15 +32,4 @@ const pascalCaseObjectKeys = (transformItem, deep) => transformObjectKeys(
|
|
|
33
32
|
deep,
|
|
34
33
|
);
|
|
35
34
|
|
|
36
|
-
|
|
37
|
-
// when a value is absent, so nullable JSON/TEXT columns stay unambiguously empty.
|
|
38
|
-
const jsonOrNull = (value) => (isDefined(value) ? JSON.stringify(value) : null);
|
|
39
|
-
|
|
40
|
-
// As jsonOrNull, but additionally rejects non-array values (e.g. a provider returning the
|
|
41
|
-
// string "OTHER" in place of a real array), coercing them to null rather than serializing them.
|
|
42
|
-
const jsonArrayOrNull = (value) => (Array.isArray(value) ? JSON.stringify(value) : null);
|
|
43
|
-
|
|
44
|
-
export {
|
|
45
|
-
transformObjectKeys, lowerCaseObjectKeys, pascalCaseObjectKeys, pascalCase,
|
|
46
|
-
jsonOrNull, jsonArrayOrNull,
|
|
47
|
-
};
|
|
35
|
+
export {transformObjectKeys, lowerCaseObjectKeys, pascalCaseObjectKeys, pascalCase};
|
package/src/udl.js
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
raDecToGeodetic,
|
|
11
11
|
estimateSlantRange,
|
|
12
12
|
} from "./astro.js";
|
|
13
|
-
import {lowerCaseObjectKeys
|
|
13
|
+
import {lowerCaseObjectKeys} from "./transform.js";
|
|
14
14
|
import {isDefined} from "./utils.js";
|
|
15
15
|
import _ from "lodash";
|
|
16
16
|
|
|
@@ -335,7 +335,7 @@ const udlToNpsState = (udlRow) => {
|
|
|
335
335
|
const Xvel = _.get(udlRow, "xvel", null); // kilometers/second
|
|
336
336
|
const Yvel = _.get(udlRow, "yvel", null);
|
|
337
337
|
const Zvel = _.get(udlRow, "zvel", null);
|
|
338
|
-
const
|
|
338
|
+
const cov = _.get(udlRow, "cov", null );
|
|
339
339
|
const covRefFrame = _.get(udlRow, "covReferenceFrame", null );
|
|
340
340
|
let keplerians = {a: null, e: null, i: null, raan: null, w: null, f: null};
|
|
341
341
|
|
|
@@ -368,10 +368,7 @@ const udlToNpsState = (udlRow) => {
|
|
|
368
368
|
Xvel: Xvel,
|
|
369
369
|
Yvel: Yvel,
|
|
370
370
|
Zvel: Zvel,
|
|
371
|
-
|
|
372
|
-
// "OTHER" in place of a real covariance matrix), and write a true SQL NULL rather
|
|
373
|
-
// than the string "null" when there is no covariance at all.
|
|
374
|
-
Covariance: jsonArrayOrNull(rawCov),
|
|
371
|
+
Covariance: JSON.stringify(cov),
|
|
375
372
|
CovarianceRefFrame: covRefFrame,
|
|
376
373
|
SemiMajorAxis: keplerians.a,
|
|
377
374
|
Eccentricity: keplerians.e,
|
package/src/tle/TleParseUtils.js
DELETED
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Utility class for TLE parsing, including Alpha-5 TLE satellite IDs.
|
|
3
|
-
* Ported from org.orekit.propagation.analytical.tle.ParseUtils / TLE.
|
|
4
|
-
*
|
|
5
|
-
* Alpha-5 extends the range of existing 5-digit TLE satellite numbers
|
|
6
|
-
* by allowing the first digit to be an upper case letter, ignoring 'I'
|
|
7
|
-
* and 'O' to avoid confusion with numbers '1' and '0'.
|
|
8
|
-
*
|
|
9
|
-
* @see https://www.space-track.org/documentation#tle-alpha5
|
|
10
|
-
*/
|
|
11
|
-
export class TleParseUtils {
|
|
12
|
-
/** Maximum satellite number representable with 5 numeric digits. */
|
|
13
|
-
static MAX_NUMERIC_SATNUM = 99999;
|
|
14
|
-
|
|
15
|
-
/** Scaling factor for Alpha-5 numbers. */
|
|
16
|
-
static ALPHA5_SCALING = 10000;
|
|
17
|
-
|
|
18
|
-
/** Letter → number map for Alpha-5 satellite numbers. */
|
|
19
|
-
static ALPHA5_NUMBERS = new Map();
|
|
20
|
-
|
|
21
|
-
/** Number → letter map for Alpha-5 satellite numbers. */
|
|
22
|
-
static ALPHA5_LETTERS = new Map();
|
|
23
|
-
|
|
24
|
-
static {
|
|
25
|
-
const alpha5Letters = [
|
|
26
|
-
"A", "B", "C", "D", "E", "F", "G", "H", "J",
|
|
27
|
-
"K", "L", "M", "N", "P", "Q", "R", "S", "T",
|
|
28
|
-
"U", "V", "W", "X", "Y", "Z",
|
|
29
|
-
];
|
|
30
|
-
for (let i = 0; i < alpha5Letters.length; ++i) {
|
|
31
|
-
TleParseUtils.ALPHA5_NUMBERS.set(alpha5Letters[i], i + 10);
|
|
32
|
-
TleParseUtils.ALPHA5_LETTERS.set(i + 10, alpha5Letters[i]);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/** Private constructor for a utility class. */
|
|
37
|
-
constructor() {
|
|
38
|
-
throw new Error("TleParseUtils is a utility class and cannot be instantiated");
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* True if token is a valid 5-char TLE catalog field:
|
|
43
|
-
* five digits, or Alpha-5 letter (no I/O) plus four digits.
|
|
44
|
-
* @param {string} token
|
|
45
|
-
* @return {boolean}
|
|
46
|
-
*/
|
|
47
|
-
static isValidSatelliteNumberField(token) {
|
|
48
|
-
if (typeof token !== "string" || token.length !== 5) {
|
|
49
|
-
return false;
|
|
50
|
-
}
|
|
51
|
-
if (/^\d{5}$/.test(token)) {
|
|
52
|
-
return true;
|
|
53
|
-
}
|
|
54
|
-
if (!TleParseUtils.ALPHA5_NUMBERS.has(token.charAt(0))) {
|
|
55
|
-
return false;
|
|
56
|
-
}
|
|
57
|
-
return /^\d{4}$/.test(token.substring(1));
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Stricter int parser: accepts an optional sign plus digits only, else throws.
|
|
62
|
-
* Unlike Number.parseInt, rejects partial parses (e.g. "12abc").
|
|
63
|
-
* @param {string} string
|
|
64
|
-
* @return {number}
|
|
65
|
-
*/
|
|
66
|
-
static #strictParseInt(string) {
|
|
67
|
-
if (!/^[+-]?\d+$/.test(string)) {
|
|
68
|
-
throw new Error(`Invalid integer: "${string}"`);
|
|
69
|
-
}
|
|
70
|
-
return Number.parseInt(string, 10);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Add padding characters to a string.
|
|
75
|
-
* Port of ParseUtils.addPadding.
|
|
76
|
-
* @param {string} name parameter name
|
|
77
|
-
* @param {string} string string to pad
|
|
78
|
-
* @param {string} c padding character
|
|
79
|
-
* @param {number} size desired size
|
|
80
|
-
* @param {boolean} rightJustified if true, pad on the left
|
|
81
|
-
* @param {number} satelliteNumber satellite number (for error context)
|
|
82
|
-
* @return {string} padded string
|
|
83
|
-
*/
|
|
84
|
-
static addPadding(name, string, c, size, rightJustified, satelliteNumber) {
|
|
85
|
-
if (string.length > size) {
|
|
86
|
-
throw new Error(
|
|
87
|
-
`TLE invalid parameter: satelliteNumber=${satelliteNumber}, name=${name}, value=${string}`,
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const padding = c.repeat(size);
|
|
92
|
-
|
|
93
|
-
if (rightJustified) {
|
|
94
|
-
const concatenated = padding + string;
|
|
95
|
-
const l = concatenated.length;
|
|
96
|
-
return concatenated.substring(l - size, l);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
return (string + padding).substring(0, size);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Build an Alpha-5 (or numeric) satellite number field.
|
|
104
|
-
* Port of ParseUtils.buildSatelliteNumber.
|
|
105
|
-
* @param {number} satelliteNumber satellite number, that may exceed the 99999 limit
|
|
106
|
-
* @param {string} name parameter name (used in error messages)
|
|
107
|
-
* @return {string} satellite number in alpha5 / 5-digit representation
|
|
108
|
-
*/
|
|
109
|
-
static buildSatelliteNumber(satelliteNumber, name) {
|
|
110
|
-
if (satelliteNumber > TleParseUtils.MAX_NUMERIC_SATNUM) {
|
|
111
|
-
const highDigits = Math.trunc(satelliteNumber / TleParseUtils.ALPHA5_SCALING);
|
|
112
|
-
const lowDigits = satelliteNumber - highDigits * TleParseUtils.ALPHA5_SCALING;
|
|
113
|
-
|
|
114
|
-
const alpha = TleParseUtils.ALPHA5_LETTERS.get(highDigits);
|
|
115
|
-
if (alpha === undefined) {
|
|
116
|
-
throw new Error(
|
|
117
|
-
`TLE invalid parameter: satelliteNumber=${satelliteNumber}, name=${name}, value=null`,
|
|
118
|
-
);
|
|
119
|
-
}
|
|
120
|
-
return alpha + TleParseUtils.addPadding(
|
|
121
|
-
name, String(lowDigits), "0", 4, true, satelliteNumber,
|
|
122
|
-
);
|
|
123
|
-
}
|
|
124
|
-
return TleParseUtils.addPadding(
|
|
125
|
-
name, String(satelliteNumber), "0", 5, true, satelliteNumber,
|
|
126
|
-
);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Parse a satellite number from a string field (supports Alpha-5).
|
|
131
|
-
* Port of TLE.parseSatelliteNumber / ParseUtils.parseSatelliteNumber.
|
|
132
|
-
* @param {string} satNumberString the string to parse (e.g., "25544" or "A0001")
|
|
133
|
-
* @return {number} the satellite number as an integer
|
|
134
|
-
*/
|
|
135
|
-
static getSatnoFromTle(satNumberString) {
|
|
136
|
-
if (!TleParseUtils.isValidSatelliteNumberField(satNumberString)) {
|
|
137
|
-
throw new Error(`Invalid satellite number field: "${satNumberString}"`);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
const alpha = TleParseUtils.ALPHA5_NUMBERS.get(satNumberString.charAt(0));
|
|
141
|
-
if (alpha !== undefined) {
|
|
142
|
-
return (alpha * TleParseUtils.ALPHA5_SCALING)
|
|
143
|
-
+ TleParseUtils.#strictParseInt(satNumberString.substring(1));
|
|
144
|
-
}
|
|
145
|
-
return TleParseUtils.#strictParseInt(satNumberString);
|
|
146
|
-
}
|
|
147
|
-
}
|