@tak-ps/node-cot 12.30.1 → 12.31.0

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/CHANGELOG.md CHANGED
@@ -12,6 +12,10 @@
12
12
 
13
13
  ### Pending Fixed
14
14
 
15
+ ### v12.31.0 - 2025-04-30
16
+
17
+ - :tada: Add CoT Type <=> SIDC
18
+
15
19
  ### v12.30.1 - 2025-04-28
16
20
 
17
21
  - :arrow_up: Update Core Deps
package/dist/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tak-ps/node-cot",
3
3
  "type": "module",
4
- "version": "12.30.1",
4
+ "version": "12.31.0",
5
5
  "description": "Lightweight JavaScript library for parsing and manipulating TAK messages",
6
6
  "author": "Nick Ingalls <nick@ingalls.ca>",
7
7
  "main": "dist/index.js",
@@ -30,6 +30,7 @@
30
30
  "archiver": "^7.0.1",
31
31
  "color": "^5.0.0",
32
32
  "json-diff-ts": "^4.0.1",
33
+ "milsymbol": "^3.0.2",
33
34
  "node-stream-zip": "^1.15.0",
34
35
  "protobufjs": "^7.3.0",
35
36
  "rimraf": "^6.0.0",
@@ -0,0 +1,53 @@
1
+ /**
2
+ * @class
3
+ *
4
+ * Convert a COT Atom Type to/from Symbol Identification Code (SIDC)
5
+ * Migrated to TypeScript from the original Kotlin verison
6
+ * @ https://github.com/cyberpython/kotcot under the MIT License
7
+ */
8
+ export default class Type2525 {
9
+
10
+ /**
11
+ * Given a COT Atom Type, return an SIDC
12
+ * @param cotType - Cursor On Target Type (Note must start with atomic "a")
13
+ */
14
+ static to2525B(cotType: string): string {
15
+ if (!cotType.match(/^a-[puafnshjkox]-[PAGSUFXZ](-\w+)*$/)) {
16
+ throw new TypeError("CoT to 2525B can only be applied to well-formed Atom type CoT Events.")
17
+ }
18
+
19
+ const m2525bChars = cotType.substring(4).replace(/[^A-Z0-9]+/g, "");
20
+ const m2525bBattleDim = m2525bChars.substring(0, 1);
21
+
22
+ const cotAffiliation = cotType.substring(2, 3);
23
+ const m2525bAffiliation = (cotAffiliation === "o" || cotAffiliation === "x")
24
+ ? "U"
25
+ : cotAffiliation.toUpperCase();
26
+
27
+ const m2525bFuncId = m2525bChars.length > 1
28
+ ? m2525bChars.substring(1).padEnd(6, "-").substring(0, 6)
29
+ : "------";
30
+
31
+ return `S${m2525bAffiliation}${m2525bBattleDim}P${m2525bFuncId}-----`;
32
+ }
33
+
34
+ static from2525B(sidc : string) : string {
35
+ if (!/^S[PUAFNSHGWMDLJK-][PAGSUFXZ-][AP-][A-Z0-9-]{10}[AECGNS-]$/.test(sidc)) {
36
+ throw new Error("2525B to CoT can only be applied to well-formed warfighting 2525B SIDCs.");
37
+ }
38
+
39
+ const m2525bAffiliation = sidc.substring(1, 2);
40
+ const cotAffiliation = ["G", "W", "M", "D", "L"].includes(m2525bAffiliation)
41
+ ? "f"
42
+ : m2525bAffiliation === "-"
43
+ ? "o"
44
+ : m2525bAffiliation.toLowerCase();
45
+
46
+ const cotBattleDim = sidc.substring(2, 3);
47
+ const cotFuncId = Array.from(sidc.substring(4, 10).replace(/[^A-Z0-9]+/g, ""))
48
+ .map((x) => `-${x}`)
49
+ .join("");
50
+
51
+ return `a-${cotAffiliation}-${cotBattleDim}${cotFuncId}`;
52
+ }
53
+ }
@@ -0,0 +1,53 @@
1
+ import { Static, TSchema, TUnknown } from '@sinclair/typebox'
2
+ import { Value } from '@sinclair/typebox/value'
3
+
4
+ export type TypeOpts = {
5
+ verbose?: boolean;
6
+ default?: boolean;
7
+ convert?: boolean;
8
+ clean?: boolean;
9
+ }
10
+
11
+ export default class TypeValidator {
12
+ /**
13
+ * Arbitrary JSON objects occasionally need to get typed as part of an ETL
14
+ * This function provides the ability to strictly type unknown objects at runtime
15
+ */
16
+ static type<T extends TSchema = TUnknown>(
17
+ type: T,
18
+ body: unknown,
19
+ opts?: TypeOpts
20
+ ): Static<T> {
21
+ if (!opts) opts = {};
22
+ if (opts.verbose === undefined) opts.verbose = false;
23
+ if (opts.default === undefined) opts.default = true;
24
+ if (opts.convert === undefined) opts.convert = true;
25
+ if (opts.clean === undefined) opts.clean = true;
26
+
27
+ if (opts.default) {
28
+ Value.Default(type, body)
29
+ }
30
+
31
+ if (opts.clean) {
32
+ Value.Clean(type, body)
33
+ }
34
+
35
+ if (opts.convert) {
36
+ Value.Convert(type, body)
37
+ }
38
+
39
+ const result = Value.Check(type, body)
40
+
41
+ if (result) return body;
42
+
43
+ const errors = Value.Errors(type, body);
44
+
45
+ const firstError = errors.First();
46
+
47
+ if (opts.verbose) {
48
+ throw new Error(`Internal Validation Error: ${JSON.stringify(firstError)} -- Body: ${JSON.stringify(body)}`);
49
+ } else {
50
+ throw new Error(`Internal Validation Error`);
51
+ }
52
+ }
53
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tak-ps/node-cot",
3
3
  "type": "module",
4
- "version": "12.30.1",
4
+ "version": "12.31.0",
5
5
  "description": "Lightweight JavaScript library for parsing and manipulating TAK messages",
6
6
  "author": "Nick Ingalls <nick@ingalls.ca>",
7
7
  "main": "dist/index.js",
@@ -30,6 +30,7 @@
30
30
  "archiver": "^7.0.1",
31
31
  "color": "^5.0.0",
32
32
  "json-diff-ts": "^4.0.1",
33
+ "milsymbol": "^3.0.2",
33
34
  "node-stream-zip": "^1.15.0",
34
35
  "protobufjs": "^7.3.0",
35
36
  "rimraf": "^6.0.0",