@tak-ps/node-cot 3.5.3 → 4.0.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 +11 -0
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/lib/{xml.js → cot.js} +152 -12
- package/dist/lib/{xml.js.map → cot.js.map} +1 -1
- package/dist/test/cot.test.js +5 -5
- package/dist/test/cot.test.js.map +1 -1
- package/dist/test/cot_is.test.js +353 -0
- package/dist/test/cot_is.test.js.map +1 -0
- package/dist/test/from_geojson.test.js +20 -20
- package/dist/test/from_geojson.test.js.map +1 -1
- package/index.ts +2 -2
- package/lib/{xml.ts → cot.ts} +172 -14
- package/lib/util.ts +1 -1
- package/package.json +3 -3
- package/test/cot.test.ts +5 -5
- package/test/cot_is.test.ts +431 -0
- package/test/from_geojson.test.ts +20 -20
package/lib/{xml.ts → cot.ts}
RENAMED
|
@@ -80,14 +80,14 @@ export interface JSONCoT {
|
|
|
80
80
|
*
|
|
81
81
|
* @prop raw Raw XML-JS representation of CoT
|
|
82
82
|
*/
|
|
83
|
-
export default class
|
|
83
|
+
export default class CoT {
|
|
84
84
|
raw: JSONCoT;
|
|
85
85
|
|
|
86
86
|
constructor(cot: Buffer | JSONCoT | string) {
|
|
87
87
|
if (typeof cot === 'string' || cot instanceof Buffer) {
|
|
88
88
|
if (cot instanceof Buffer) cot = String(cot);
|
|
89
89
|
|
|
90
|
-
const raw
|
|
90
|
+
const raw = xmljs.xml2js(cot, { compact: true });
|
|
91
91
|
this.raw = raw as JSONCoT;
|
|
92
92
|
} else {
|
|
93
93
|
this.raw = cot;
|
|
@@ -100,11 +100,11 @@ export default class XMLCot {
|
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
/**
|
|
103
|
-
* Return an
|
|
103
|
+
* Return an CoT Message
|
|
104
104
|
*
|
|
105
105
|
* @param {Object} feature GeoJSON Point Feature
|
|
106
106
|
*
|
|
107
|
-
* @return {
|
|
107
|
+
* @return {CoT}
|
|
108
108
|
*/
|
|
109
109
|
static from_geojson(feature: Feature) {
|
|
110
110
|
if (feature.type !== 'Feature') throw new Error('Must be GeoJSON Feature');
|
|
@@ -199,7 +199,7 @@ export default class XMLCot {
|
|
|
199
199
|
cot.event.point._attributes.lat = String(centre.geometry.coordinates[1]);
|
|
200
200
|
}
|
|
201
201
|
|
|
202
|
-
return new
|
|
202
|
+
return new CoT(cot);
|
|
203
203
|
}
|
|
204
204
|
|
|
205
205
|
/**
|
|
@@ -226,7 +226,7 @@ export default class XMLCot {
|
|
|
226
226
|
type: 'Point',
|
|
227
227
|
coordinates: [
|
|
228
228
|
Number(raw.event.point._attributes.lon),
|
|
229
|
-
Number(raw.event.point._attributes.
|
|
229
|
+
Number(raw.event.point._attributes.lat),
|
|
230
230
|
Number(raw.event.point._attributes.hae)
|
|
231
231
|
]
|
|
232
232
|
}
|
|
@@ -235,19 +235,15 @@ export default class XMLCot {
|
|
|
235
235
|
return geojson;
|
|
236
236
|
}
|
|
237
237
|
|
|
238
|
-
to_xml() {
|
|
239
|
-
return xmljs.js2xml(this.raw, {
|
|
240
|
-
compact: true
|
|
241
|
-
});
|
|
238
|
+
to_xml(): string {
|
|
239
|
+
return xmljs.js2xml(this.raw, { compact: true });
|
|
242
240
|
}
|
|
243
241
|
|
|
244
242
|
/**
|
|
245
243
|
* Return a CoT Message
|
|
246
|
-
*
|
|
247
|
-
* @returns {XMLCot}
|
|
248
244
|
*/
|
|
249
|
-
static ping() {
|
|
250
|
-
return new
|
|
245
|
+
static ping(): CoT {
|
|
246
|
+
return new CoT({
|
|
251
247
|
event: {
|
|
252
248
|
_attributes: Util.cot_event_attr('t-x-c-t', 'h-g-i-g-o'),
|
|
253
249
|
detail: {},
|
|
@@ -255,4 +251,166 @@ export default class XMLCot {
|
|
|
255
251
|
}
|
|
256
252
|
});
|
|
257
253
|
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Determines if the CoT message represents a Friendly Element
|
|
257
|
+
*
|
|
258
|
+
* @return {boolean}
|
|
259
|
+
*/
|
|
260
|
+
is_friend(): boolean {
|
|
261
|
+
return !!this.raw.event._attributes.type.match(/^a-f-/)
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Determines if the CoT message represents a Hostile Element
|
|
266
|
+
*
|
|
267
|
+
* @return {boolean}
|
|
268
|
+
*/
|
|
269
|
+
is_hostile(): boolean {
|
|
270
|
+
return !!this.raw.event._attributes.type.match(/^a-h-/)
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Determines if the CoT message represents a Unknown Element
|
|
275
|
+
*
|
|
276
|
+
* @return {boolean}
|
|
277
|
+
*/
|
|
278
|
+
is_unknown(): boolean {
|
|
279
|
+
return !!this.raw.event._attributes.type.match(/^a-u-/)
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Determines if the CoT message represents a Pending Element
|
|
284
|
+
*
|
|
285
|
+
* @return {boolean}
|
|
286
|
+
*/
|
|
287
|
+
is_pending(): boolean {
|
|
288
|
+
return !!this.raw.event._attributes.type.match(/^a-p-/)
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Determines if the CoT message represents an Assumed Element
|
|
293
|
+
*
|
|
294
|
+
* @return {boolean}
|
|
295
|
+
*/
|
|
296
|
+
is_assumed(): boolean {
|
|
297
|
+
return !!this.raw.event._attributes.type.match(/^a-a-/)
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Determines if the CoT message represents a Neutral Element
|
|
302
|
+
*
|
|
303
|
+
* @return {boolean}
|
|
304
|
+
*/
|
|
305
|
+
is_neutral(): boolean {
|
|
306
|
+
return !!this.raw.event._attributes.type.match(/^a-n-/)
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* Determines if the CoT message represents a Suspect Element
|
|
311
|
+
*
|
|
312
|
+
* @return {boolean}
|
|
313
|
+
*/
|
|
314
|
+
is_suspect(): boolean {
|
|
315
|
+
return !!this.raw.event._attributes.type.match(/^a-s-/)
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Determines if the CoT message represents a Joker Element
|
|
320
|
+
*
|
|
321
|
+
* @return {boolean}
|
|
322
|
+
*/
|
|
323
|
+
is_joker(): boolean {
|
|
324
|
+
return !!this.raw.event._attributes.type.match(/^a-j-/)
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Determines if the CoT message represents a Faker Element
|
|
329
|
+
*
|
|
330
|
+
* @return {boolean}
|
|
331
|
+
*/
|
|
332
|
+
is_faker(): boolean {
|
|
333
|
+
return !!this.raw.event._attributes.type.match(/^a-k-/)
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Determines if the CoT message represents an Element
|
|
338
|
+
*
|
|
339
|
+
* @return {boolean}
|
|
340
|
+
*/
|
|
341
|
+
is_atom(): boolean {
|
|
342
|
+
return !!this.raw.event._attributes.type.match(/^a-/)
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Determines if the CoT message represents an Airborne Element
|
|
347
|
+
*
|
|
348
|
+
* @return {boolean}
|
|
349
|
+
*/
|
|
350
|
+
is_airborne(): boolean {
|
|
351
|
+
return !!this.raw.event._attributes.type.match(/^a-.-A/)
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* Determines if the CoT message represents a Ground Element
|
|
356
|
+
*
|
|
357
|
+
* @return {boolean}
|
|
358
|
+
*/
|
|
359
|
+
is_ground(): boolean {
|
|
360
|
+
return !!this.raw.event._attributes.type.match(/^a-.-G/)
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Determines if the CoT message represents an Installation
|
|
365
|
+
*
|
|
366
|
+
* @return {boolean}
|
|
367
|
+
*/
|
|
368
|
+
is_installation(): boolean {
|
|
369
|
+
return !!this.raw.event._attributes.type.match(/^a-.-G-I/)
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Determines if the CoT message represents a Vehicle
|
|
374
|
+
*
|
|
375
|
+
* @return {boolean}
|
|
376
|
+
*/
|
|
377
|
+
is_vehicle(): boolean {
|
|
378
|
+
return !!this.raw.event._attributes.type.match(/^a-.-G-E-V/)
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Determines if the CoT message represents Equipment
|
|
383
|
+
*
|
|
384
|
+
* @return {boolean}
|
|
385
|
+
*/
|
|
386
|
+
is_equipment(): boolean {
|
|
387
|
+
return !!this.raw.event._attributes.type.match(/^a-.-G-E/)
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Determines if the CoT message represents a Surface Element
|
|
392
|
+
*
|
|
393
|
+
* @return {boolean}
|
|
394
|
+
*/
|
|
395
|
+
is_surface(): boolean {
|
|
396
|
+
return !!this.raw.event._attributes.type.match(/^a-.-S/)
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Determines if the CoT message represents a Subsurface Element
|
|
401
|
+
*
|
|
402
|
+
* @return {boolean}
|
|
403
|
+
*/
|
|
404
|
+
is_subsurface(): boolean {
|
|
405
|
+
return !!this.raw.event._attributes.type.match(/^a-.-U/)
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* Determines if the CoT message represents a UAV Element
|
|
410
|
+
*
|
|
411
|
+
* @return {boolean}
|
|
412
|
+
*/
|
|
413
|
+
is_uav(): boolean {
|
|
414
|
+
return !!this.raw.event._attributes.type.match(/^a-f-A-M-F-Q-r/)
|
|
415
|
+
}
|
|
258
416
|
}
|
package/lib/util.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tak-ps/node-cot",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "4.0.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",
|
|
@@ -26,8 +26,8 @@
|
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@types/node": "^20.0.0",
|
|
28
28
|
"@types/tape": "^5.6.0",
|
|
29
|
-
"@typescript-eslint/eslint-plugin": "^
|
|
30
|
-
"@typescript-eslint/parser": "^
|
|
29
|
+
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
|
30
|
+
"@typescript-eslint/parser": "^6.0.0",
|
|
31
31
|
"eslint": "^8.35.0",
|
|
32
32
|
"eslint-plugin-node": "^11.1.0",
|
|
33
33
|
"tape": "^5.6.1",
|
package/test/cot.test.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import test from 'tape';
|
|
2
|
-
import
|
|
2
|
+
import CoT from '../index.js';
|
|
3
3
|
|
|
4
4
|
test('Decode COT message', (t) => {
|
|
5
5
|
const packet = '<event version="2.0" uid="ANDROID-deadbeef" type="a-f-G-U-C" how="m-g" time="2021-02-27T20:32:24.771Z" start="2021-02-27T20:32:24.771Z" stale="2021-02-27T20:38:39.771Z"><point lat="1.234567" lon="-3.141592" hae="-25.7" ce="9.9" le="9999999.0"/><detail><takv os="29" version="4.0.0.0 (deadbeef).1234567890-CIV" device="Some Android Device" platform="ATAK-CIV"/><contact xmppUsername="xmpp@host.com" endpoint="*:-1:stcp" callsign="JENNY"/><uid Droid="JENNY"/><precisionlocation altsrc="GPS" geopointsrc="GPS"/><__group role="Team Member" name="Cyan"/><status battery="78"/><track course="80.24833892285461" speed="0.0"/></detail></event>';
|
|
6
6
|
|
|
7
|
-
t.deepEquals((new
|
|
7
|
+
t.deepEquals((new CoT(packet)).raw, {
|
|
8
8
|
'event': {
|
|
9
9
|
'_attributes': {
|
|
10
10
|
'version': '2.0',
|
|
@@ -55,7 +55,7 @@ test('Decode COT message', (t) => {
|
|
|
55
55
|
test('Decode COT message', (t) => {
|
|
56
56
|
const packet = '<event version="2.0" uid="TEST-deadbeef" type="a" how="m-g" time="2021-03-12T15:49:07.138Z" start="2021-03-12T15:49:07.138Z" stale="2021-03-12T15:49:07.138Z"><point lat="0.000000" lon="0.000000" hae="0.0" ce="9999999.0" le="9999999.0"/><detail><takv os="Android" version="10" device="Some Device" platform="python unittest"/><status battery="83"/><uid Droid="JENNY"/><contact callsign="JENNY" endpoint="*:-1:stcp" phone="800-867-5309"/><__group role="Team Member" name="Cyan"/><track course="90.1" speed="10.3"/></detail></event>';
|
|
57
57
|
|
|
58
|
-
t.deepEquals((new
|
|
58
|
+
t.deepEquals((new CoT(packet)).raw, {
|
|
59
59
|
'event': {
|
|
60
60
|
'_attributes': {
|
|
61
61
|
'version': '2.0',
|
|
@@ -167,7 +167,7 @@ test('Encode COT message', (t) => {
|
|
|
167
167
|
};
|
|
168
168
|
|
|
169
169
|
t.deepEquals(
|
|
170
|
-
(new
|
|
170
|
+
(new CoT(packet)).to_xml(),
|
|
171
171
|
'<event version="2.0" uid="ANDROID-deadbeef" type="a-f-G-U-C" how="m-g" time="2021-02-27T20:32:24.771Z" start="2021-02-27T20:32:24.771Z" stale="2021-02-27T20:38:39.771Z"><point lat="1.234567" lon="-3.141592" hae="-25.7" ce="9.9" le="9999999"/><detail><takv os="29" version="4.0.0.0 (deadbeef).1234567890-CIV" device="Some Android Device" platform="ATAK-CIV"/><contact xmppUsername="xmpp@host.com" endpoint="*:-1:stcp" callsign="JENNY"/><uid Droid="JENNY"/><precisionlocation altsrc="GPS" geopointsrc="GPS"/><__group role="Team Member" name="Cyan"/><status battery="78"/><track course="80.24833892285461" speed="0.0"/></detail></event>'
|
|
172
172
|
);
|
|
173
173
|
|
|
@@ -190,7 +190,7 @@ test('Parse GeoChat message', (t) => {
|
|
|
190
190
|
' </detail>\n' +
|
|
191
191
|
'</event>';
|
|
192
192
|
|
|
193
|
-
t.deepEquals((new
|
|
193
|
+
t.deepEquals((new CoT(geochat)).raw, {
|
|
194
194
|
'event': {
|
|
195
195
|
'_attributes': {
|
|
196
196
|
'version': '2.0',
|