@2702rebels/wpidata 1.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/LICENSE +28 -0
- package/README.md +5 -0
- package/dist/abstractions.cjs +0 -0
- package/dist/abstractions.d.cts +246 -0
- package/dist/abstractions.d.cts.map +1 -0
- package/dist/abstractions.d.mts +246 -0
- package/dist/abstractions.d.mts.map +1 -0
- package/dist/abstractions.mjs +1 -0
- package/dist/formats/json.cjs +32 -0
- package/dist/formats/json.d.cts +14 -0
- package/dist/formats/json.d.cts.map +1 -0
- package/dist/formats/json.d.mts +14 -0
- package/dist/formats/json.d.mts.map +1 -0
- package/dist/formats/json.mjs +33 -0
- package/dist/formats/json.mjs.map +1 -0
- package/dist/formats/msgpack.cjs +30 -0
- package/dist/formats/msgpack.d.cts +14 -0
- package/dist/formats/msgpack.d.cts.map +1 -0
- package/dist/formats/msgpack.d.mts +14 -0
- package/dist/formats/msgpack.d.mts.map +1 -0
- package/dist/formats/msgpack.mjs +31 -0
- package/dist/formats/msgpack.mjs.map +1 -0
- package/dist/formats/protobuf.cjs +130 -0
- package/dist/formats/protobuf.d.cts +68 -0
- package/dist/formats/protobuf.d.cts.map +1 -0
- package/dist/formats/protobuf.d.mts +68 -0
- package/dist/formats/protobuf.d.mts.map +1 -0
- package/dist/formats/protobuf.mjs +128 -0
- package/dist/formats/protobuf.mjs.map +1 -0
- package/dist/formats/struct.cjs +593 -0
- package/dist/formats/struct.d.cts +134 -0
- package/dist/formats/struct.d.cts.map +1 -0
- package/dist/formats/struct.d.mts +134 -0
- package/dist/formats/struct.d.mts.map +1 -0
- package/dist/formats/struct.mjs +591 -0
- package/dist/formats/struct.mjs.map +1 -0
- package/dist/sink.cjs +360 -0
- package/dist/sink.d.cts +93 -0
- package/dist/sink.d.cts.map +1 -0
- package/dist/sink.d.mts +93 -0
- package/dist/sink.d.mts.map +1 -0
- package/dist/sink.mjs +361 -0
- package/dist/sink.mjs.map +1 -0
- package/dist/types/protobuf.cjs +0 -0
- package/dist/types/protobuf.d.cts +302 -0
- package/dist/types/protobuf.d.cts.map +1 -0
- package/dist/types/protobuf.d.mts +302 -0
- package/dist/types/protobuf.d.mts.map +1 -0
- package/dist/types/protobuf.mjs +1 -0
- package/dist/types/sendable.cjs +0 -0
- package/dist/types/sendable.d.cts +225 -0
- package/dist/types/sendable.d.cts.map +1 -0
- package/dist/types/sendable.d.mts +225 -0
- package/dist/types/sendable.d.mts.map +1 -0
- package/dist/types/sendable.mjs +1 -0
- package/dist/types/struct.cjs +0 -0
- package/dist/types/struct.d.cts +304 -0
- package/dist/types/struct.d.cts.map +1 -0
- package/dist/types/struct.d.mts +304 -0
- package/dist/types/struct.d.mts.map +1 -0
- package/dist/types/struct.mjs +1 -0
- package/dist/utils.cjs +140 -0
- package/dist/utils.d.cts +40 -0
- package/dist/utils.d.cts.map +1 -0
- package/dist/utils.d.mts +40 -0
- package/dist/utils.d.mts.map +1 -0
- package/dist/utils.mjs +135 -0
- package/dist/utils.mjs.map +1 -0
- package/package.json +51 -0
- package/src/abstractions.ts +308 -0
- package/src/formats/json.ts +53 -0
- package/src/formats/msgpack.ts +42 -0
- package/src/formats/protobuf.ts +213 -0
- package/src/formats/struct.test.ts +814 -0
- package/src/formats/struct.ts +992 -0
- package/src/sink.ts +611 -0
- package/src/types/protobuf.ts +334 -0
- package/src/types/sendable.ts +244 -0
- package/src/types/struct.ts +333 -0
- package/src/utils.ts +241 -0
package/dist/utils.cjs
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/utils.ts
|
|
3
|
+
/** Constructs the {@link DataView} from the buffer source. */
|
|
4
|
+
function toDataView(source) {
|
|
5
|
+
if (source instanceof DataView) return source;
|
|
6
|
+
if (source instanceof ArrayBuffer) return new DataView(source);
|
|
7
|
+
if (ArrayBuffer.isView(source)) return new DataView(source.buffer, source.byteOffset, source.byteLength);
|
|
8
|
+
throw new Error(`Parameter of type '${typeof source}' cannot be wrapped into DataView`);
|
|
9
|
+
}
|
|
10
|
+
/** Returns the specified buffer source as {@link Uint8Array} view. */
|
|
11
|
+
function toUint8Array(source) {
|
|
12
|
+
if (source instanceof ArrayBuffer) return new Uint8Array(source);
|
|
13
|
+
if (ArrayBuffer.isView(source)) return source instanceof Uint8Array ? source : new Uint8Array(source.buffer, source.byteOffset, source.byteLength);
|
|
14
|
+
throw new Error(`Parameter of type '${typeof source}' cannot be represented as Uint8Array`);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Adds timestamped record to an array of records.
|
|
18
|
+
*
|
|
19
|
+
* The `records` array is assumed to be sorted by the timestamp in ascending order,
|
|
20
|
+
* earlier records have smaller indices.
|
|
21
|
+
*
|
|
22
|
+
* @returns the index at which the record has been inserted or updated
|
|
23
|
+
*/
|
|
24
|
+
function addTimestampedRecord(records, timestamp, value) {
|
|
25
|
+
if (records.length === 0) {
|
|
26
|
+
records.push({
|
|
27
|
+
timestamp,
|
|
28
|
+
value
|
|
29
|
+
});
|
|
30
|
+
return 0;
|
|
31
|
+
}
|
|
32
|
+
const tail = records[0];
|
|
33
|
+
let index = 0;
|
|
34
|
+
if (timestamp === 0) if (tail.timestamp === 0) tail.value = value;
|
|
35
|
+
else records.unshift({
|
|
36
|
+
timestamp,
|
|
37
|
+
value
|
|
38
|
+
});
|
|
39
|
+
else if (timestamp === 1) if (tail.timestamp === 1) tail.value = value;
|
|
40
|
+
else if (tail.timestamp === 0) {
|
|
41
|
+
index = 1;
|
|
42
|
+
if (records.length === 1) records.push({
|
|
43
|
+
timestamp,
|
|
44
|
+
value
|
|
45
|
+
});
|
|
46
|
+
else if (records[1].timestamp === 1) records[1].value = value;
|
|
47
|
+
else records.splice(1, 0, {
|
|
48
|
+
timestamp,
|
|
49
|
+
value
|
|
50
|
+
});
|
|
51
|
+
} else records.unshift({
|
|
52
|
+
timestamp,
|
|
53
|
+
value
|
|
54
|
+
});
|
|
55
|
+
else {
|
|
56
|
+
for (let i = records.length - 1; i >= 0; --i) {
|
|
57
|
+
const record = records[i];
|
|
58
|
+
if (record.timestamp === timestamp) {
|
|
59
|
+
index = i;
|
|
60
|
+
record.value = value;
|
|
61
|
+
return index;
|
|
62
|
+
}
|
|
63
|
+
if (record.timestamp < timestamp) {
|
|
64
|
+
index = i + 1;
|
|
65
|
+
records.splice(i + 1, 0, {
|
|
66
|
+
timestamp,
|
|
67
|
+
value
|
|
68
|
+
});
|
|
69
|
+
return index;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
records.unshift({
|
|
73
|
+
timestamp,
|
|
74
|
+
value
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
return index;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Gets nearest (latest) timestamped record and its index.
|
|
81
|
+
*
|
|
82
|
+
* The `records` array is assumed to be sorted by the timestamp in ascending order,
|
|
83
|
+
* earlier records have smaller indices.
|
|
84
|
+
*/
|
|
85
|
+
function getTimestampedRecord(records, timestamp) {
|
|
86
|
+
if (records.length === 0) return [void 0, -1];
|
|
87
|
+
if (timestamp === 0) return records[0].timestamp === 0 ? [records[0], 0] : [void 0, -1];
|
|
88
|
+
if (timestamp === 1) {
|
|
89
|
+
if (records[0].timestamp === 1) return [records[0], 0];
|
|
90
|
+
if (records.length > 1 && records[1].timestamp === 1) return [records[1], 1];
|
|
91
|
+
return [void 0, -1];
|
|
92
|
+
}
|
|
93
|
+
for (let i = records.length - 1; i >= 0; --i) {
|
|
94
|
+
const record = records[i];
|
|
95
|
+
if (record.timestamp <= timestamp) return [record, i];
|
|
96
|
+
}
|
|
97
|
+
return [void 0, -1];
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Reduces timestamps records array by pruning records with older timestamps
|
|
101
|
+
* per `maxSize` and `cutoff` window retention settings.
|
|
102
|
+
*
|
|
103
|
+
* Always retains special records with timestamps 0 and 1, these do not count
|
|
104
|
+
* towards maximum size limit.
|
|
105
|
+
*
|
|
106
|
+
* @param records array of records sorted by the timestamp in ascending order
|
|
107
|
+
* @param maxSize maximum number of entries to retain
|
|
108
|
+
* @param cutoff cutoff timestamp
|
|
109
|
+
*/
|
|
110
|
+
function pruneTimestampedRecords(records, maxSize, cutoff) {
|
|
111
|
+
if (cutoff == null && (maxSize == null || records.length <= maxSize)) return records;
|
|
112
|
+
const tailIndex = records.findIndex((_) => _.timestamp > 1);
|
|
113
|
+
if (tailIndex < 0) return records;
|
|
114
|
+
if (maxSize != null && records.length - tailIndex - maxSize > 0) records.splice(tailIndex, records.length - tailIndex - maxSize);
|
|
115
|
+
if (cutoff != null) {
|
|
116
|
+
if (records[tailIndex].timestamp >= cutoff) return records;
|
|
117
|
+
let cutoffIndex = tailIndex;
|
|
118
|
+
for (; cutoffIndex < records.length - 1; ++cutoffIndex) if (records[cutoffIndex].timestamp >= cutoff) break;
|
|
119
|
+
if (cutoffIndex > tailIndex) records.splice(tailIndex, cutoffIndex - tailIndex);
|
|
120
|
+
}
|
|
121
|
+
return records;
|
|
122
|
+
}
|
|
123
|
+
/** Sets deeply nested object value. */
|
|
124
|
+
function setValueByPath(object, path, value, insertOnly = false) {
|
|
125
|
+
path.reduce((o, key, i) => {
|
|
126
|
+
if (i === path.length - 1) {
|
|
127
|
+
if (!insertOnly || o[key] === void 0) o[key] = value;
|
|
128
|
+
} else if (o[key] === void 0) o[key] = {};
|
|
129
|
+
return o[key];
|
|
130
|
+
}, object);
|
|
131
|
+
return object;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
//#endregion
|
|
135
|
+
exports.addTimestampedRecord = addTimestampedRecord;
|
|
136
|
+
exports.getTimestampedRecord = getTimestampedRecord;
|
|
137
|
+
exports.pruneTimestampedRecords = pruneTimestampedRecords;
|
|
138
|
+
exports.setValueByPath = setValueByPath;
|
|
139
|
+
exports.toDataView = toDataView;
|
|
140
|
+
exports.toUint8Array = toUint8Array;
|
package/dist/utils.d.cts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { DataChannelRecord, DataTypeImpl } from "./abstractions.cjs";
|
|
2
|
+
|
|
3
|
+
//#region src/utils.d.ts
|
|
4
|
+
/** Constructs the {@link DataView} from the buffer source. */
|
|
5
|
+
declare function toDataView(source: unknown): DataView<ArrayBufferLike>;
|
|
6
|
+
/** Returns the specified buffer source as {@link Uint8Array} view. */
|
|
7
|
+
declare function toUint8Array(source: unknown): Uint8Array<ArrayBufferLike>;
|
|
8
|
+
/**
|
|
9
|
+
* Adds timestamped record to an array of records.
|
|
10
|
+
*
|
|
11
|
+
* The `records` array is assumed to be sorted by the timestamp in ascending order,
|
|
12
|
+
* earlier records have smaller indices.
|
|
13
|
+
*
|
|
14
|
+
* @returns the index at which the record has been inserted or updated
|
|
15
|
+
*/
|
|
16
|
+
declare function addTimestampedRecord<T extends DataTypeImpl>(records: Array<DataChannelRecord<T>>, timestamp: number, value: T): number;
|
|
17
|
+
/**
|
|
18
|
+
* Gets nearest (latest) timestamped record and its index.
|
|
19
|
+
*
|
|
20
|
+
* The `records` array is assumed to be sorted by the timestamp in ascending order,
|
|
21
|
+
* earlier records have smaller indices.
|
|
22
|
+
*/
|
|
23
|
+
declare function getTimestampedRecord<T extends DataTypeImpl>(records: Array<DataChannelRecord<T>>, timestamp: number): [DataChannelRecord<T>, number] | [undefined, -1];
|
|
24
|
+
/**
|
|
25
|
+
* Reduces timestamps records array by pruning records with older timestamps
|
|
26
|
+
* per `maxSize` and `cutoff` window retention settings.
|
|
27
|
+
*
|
|
28
|
+
* Always retains special records with timestamps 0 and 1, these do not count
|
|
29
|
+
* towards maximum size limit.
|
|
30
|
+
*
|
|
31
|
+
* @param records array of records sorted by the timestamp in ascending order
|
|
32
|
+
* @param maxSize maximum number of entries to retain
|
|
33
|
+
* @param cutoff cutoff timestamp
|
|
34
|
+
*/
|
|
35
|
+
declare function pruneTimestampedRecords(records: Array<DataChannelRecord<DataTypeImpl>>, maxSize?: number, cutoff?: number): DataChannelRecord<DataTypeImpl>[];
|
|
36
|
+
/** Sets deeply nested object value. */
|
|
37
|
+
declare function setValueByPath(object: Record<string, unknown>, path: Array<string>, value: unknown, insertOnly?: boolean): Record<string, unknown>;
|
|
38
|
+
//#endregion
|
|
39
|
+
export { addTimestampedRecord, getTimestampedRecord, pruneTimestampedRecords, setValueByPath, toDataView, toUint8Array };
|
|
40
|
+
//# sourceMappingURL=utils.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.cts","names":[],"sources":["../src/utils.ts"],"sourcesContent":[],"mappings":";;;;iBAGgB,UAAA,mBAA0B,SAAA;AAA1C;AAiBgB,iBAAA,YAAA,CAA4B,MAAA,EAAA,OAAA,CAAA,EAAA,UAAA,CAAA,eAAA,CAAA;AAoB5C;;;;;;;AAyFA;AAA+C,iBAzF/B,oBAyF+B,CAAA,UAzFA,YAyFA,CAAA,CAAA,OAAA,EAxFpC,KAwFoC,CAxF9B,iBAwF8B,CAxFZ,CAwFY,CAAA,CAAA,EAAA,SAAA,EAAA,MAAA,EAAA,KAAA,EAtFtC,CAsFsC,CAAA,EAAA,MAAA;;;;;;;AA8C/B,iBA9CA,oBA8CuB,CAAA,UA9CQ,YA8CR,CAAA,CAAA,OAAA,EA7C5B,KA6C4B,CA7CtB,iBA6CsB,CA7CJ,CA6CI,CAAA,CAAA,EAAA,SAAA,EAAA,MAAA,CAAA,EAAA,CA3CnC,iBA2CmC,CA3CjB,CA2CiB,CAAA,EAAA,MAAA,CAAA,GAAA,CAAA,SAAA,EAAA,CAAA,CAAA,CAAA;;;;;;;AA6CvC;;;;;iBA7CgB,uBAAA,UACL,MAAM,kBAAkB,oDAElB,kBAAA;;iBA0CD,cAAA,SACN,+BACF,sDAEY"}
|
package/dist/utils.d.mts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { DataChannelRecord, DataTypeImpl } from "./abstractions.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/utils.d.ts
|
|
4
|
+
/** Constructs the {@link DataView} from the buffer source. */
|
|
5
|
+
declare function toDataView(source: unknown): DataView<ArrayBufferLike>;
|
|
6
|
+
/** Returns the specified buffer source as {@link Uint8Array} view. */
|
|
7
|
+
declare function toUint8Array(source: unknown): Uint8Array<ArrayBufferLike>;
|
|
8
|
+
/**
|
|
9
|
+
* Adds timestamped record to an array of records.
|
|
10
|
+
*
|
|
11
|
+
* The `records` array is assumed to be sorted by the timestamp in ascending order,
|
|
12
|
+
* earlier records have smaller indices.
|
|
13
|
+
*
|
|
14
|
+
* @returns the index at which the record has been inserted or updated
|
|
15
|
+
*/
|
|
16
|
+
declare function addTimestampedRecord<T extends DataTypeImpl>(records: Array<DataChannelRecord<T>>, timestamp: number, value: T): number;
|
|
17
|
+
/**
|
|
18
|
+
* Gets nearest (latest) timestamped record and its index.
|
|
19
|
+
*
|
|
20
|
+
* The `records` array is assumed to be sorted by the timestamp in ascending order,
|
|
21
|
+
* earlier records have smaller indices.
|
|
22
|
+
*/
|
|
23
|
+
declare function getTimestampedRecord<T extends DataTypeImpl>(records: Array<DataChannelRecord<T>>, timestamp: number): [DataChannelRecord<T>, number] | [undefined, -1];
|
|
24
|
+
/**
|
|
25
|
+
* Reduces timestamps records array by pruning records with older timestamps
|
|
26
|
+
* per `maxSize` and `cutoff` window retention settings.
|
|
27
|
+
*
|
|
28
|
+
* Always retains special records with timestamps 0 and 1, these do not count
|
|
29
|
+
* towards maximum size limit.
|
|
30
|
+
*
|
|
31
|
+
* @param records array of records sorted by the timestamp in ascending order
|
|
32
|
+
* @param maxSize maximum number of entries to retain
|
|
33
|
+
* @param cutoff cutoff timestamp
|
|
34
|
+
*/
|
|
35
|
+
declare function pruneTimestampedRecords(records: Array<DataChannelRecord<DataTypeImpl>>, maxSize?: number, cutoff?: number): DataChannelRecord<DataTypeImpl>[];
|
|
36
|
+
/** Sets deeply nested object value. */
|
|
37
|
+
declare function setValueByPath(object: Record<string, unknown>, path: Array<string>, value: unknown, insertOnly?: boolean): Record<string, unknown>;
|
|
38
|
+
//#endregion
|
|
39
|
+
export { addTimestampedRecord, getTimestampedRecord, pruneTimestampedRecords, setValueByPath, toDataView, toUint8Array };
|
|
40
|
+
//# sourceMappingURL=utils.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.mts","names":[],"sources":["../src/utils.ts"],"sourcesContent":[],"mappings":";;;;iBAGgB,UAAA,mBAA0B,SAAA;AAA1C;AAiBgB,iBAAA,YAAA,CAA4B,MAAA,EAAA,OAAA,CAAA,EAAA,UAAA,CAAA,eAAA,CAAA;AAoB5C;;;;;;;AAyFA;AAA+C,iBAzF/B,oBAyF+B,CAAA,UAzFA,YAyFA,CAAA,CAAA,OAAA,EAxFpC,KAwFoC,CAxF9B,iBAwF8B,CAxFZ,CAwFY,CAAA,CAAA,EAAA,SAAA,EAAA,MAAA,EAAA,KAAA,EAtFtC,CAsFsC,CAAA,EAAA,MAAA;;;;;;;AA8C/B,iBA9CA,oBA8CuB,CAAA,UA9CQ,YA8CR,CAAA,CAAA,OAAA,EA7C5B,KA6C4B,CA7CtB,iBA6CsB,CA7CJ,CA6CI,CAAA,CAAA,EAAA,SAAA,EAAA,MAAA,CAAA,EAAA,CA3CnC,iBA2CmC,CA3CjB,CA2CiB,CAAA,EAAA,MAAA,CAAA,GAAA,CAAA,SAAA,EAAA,CAAA,CAAA,CAAA;;;;;;;AA6CvC;;;;;iBA7CgB,uBAAA,UACL,MAAM,kBAAkB,oDAElB,kBAAA;;iBA0CD,cAAA,SACN,+BACF,sDAEY"}
|
package/dist/utils.mjs
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
//#region src/utils.ts
|
|
2
|
+
/** Constructs the {@link DataView} from the buffer source. */
|
|
3
|
+
function toDataView(source) {
|
|
4
|
+
if (source instanceof DataView) return source;
|
|
5
|
+
if (source instanceof ArrayBuffer) return new DataView(source);
|
|
6
|
+
if (ArrayBuffer.isView(source)) return new DataView(source.buffer, source.byteOffset, source.byteLength);
|
|
7
|
+
throw new Error(`Parameter of type '${typeof source}' cannot be wrapped into DataView`);
|
|
8
|
+
}
|
|
9
|
+
/** Returns the specified buffer source as {@link Uint8Array} view. */
|
|
10
|
+
function toUint8Array(source) {
|
|
11
|
+
if (source instanceof ArrayBuffer) return new Uint8Array(source);
|
|
12
|
+
if (ArrayBuffer.isView(source)) return source instanceof Uint8Array ? source : new Uint8Array(source.buffer, source.byteOffset, source.byteLength);
|
|
13
|
+
throw new Error(`Parameter of type '${typeof source}' cannot be represented as Uint8Array`);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Adds timestamped record to an array of records.
|
|
17
|
+
*
|
|
18
|
+
* The `records` array is assumed to be sorted by the timestamp in ascending order,
|
|
19
|
+
* earlier records have smaller indices.
|
|
20
|
+
*
|
|
21
|
+
* @returns the index at which the record has been inserted or updated
|
|
22
|
+
*/
|
|
23
|
+
function addTimestampedRecord(records, timestamp, value) {
|
|
24
|
+
if (records.length === 0) {
|
|
25
|
+
records.push({
|
|
26
|
+
timestamp,
|
|
27
|
+
value
|
|
28
|
+
});
|
|
29
|
+
return 0;
|
|
30
|
+
}
|
|
31
|
+
const tail = records[0];
|
|
32
|
+
let index = 0;
|
|
33
|
+
if (timestamp === 0) if (tail.timestamp === 0) tail.value = value;
|
|
34
|
+
else records.unshift({
|
|
35
|
+
timestamp,
|
|
36
|
+
value
|
|
37
|
+
});
|
|
38
|
+
else if (timestamp === 1) if (tail.timestamp === 1) tail.value = value;
|
|
39
|
+
else if (tail.timestamp === 0) {
|
|
40
|
+
index = 1;
|
|
41
|
+
if (records.length === 1) records.push({
|
|
42
|
+
timestamp,
|
|
43
|
+
value
|
|
44
|
+
});
|
|
45
|
+
else if (records[1].timestamp === 1) records[1].value = value;
|
|
46
|
+
else records.splice(1, 0, {
|
|
47
|
+
timestamp,
|
|
48
|
+
value
|
|
49
|
+
});
|
|
50
|
+
} else records.unshift({
|
|
51
|
+
timestamp,
|
|
52
|
+
value
|
|
53
|
+
});
|
|
54
|
+
else {
|
|
55
|
+
for (let i = records.length - 1; i >= 0; --i) {
|
|
56
|
+
const record = records[i];
|
|
57
|
+
if (record.timestamp === timestamp) {
|
|
58
|
+
index = i;
|
|
59
|
+
record.value = value;
|
|
60
|
+
return index;
|
|
61
|
+
}
|
|
62
|
+
if (record.timestamp < timestamp) {
|
|
63
|
+
index = i + 1;
|
|
64
|
+
records.splice(i + 1, 0, {
|
|
65
|
+
timestamp,
|
|
66
|
+
value
|
|
67
|
+
});
|
|
68
|
+
return index;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
records.unshift({
|
|
72
|
+
timestamp,
|
|
73
|
+
value
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
return index;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Gets nearest (latest) timestamped record and its index.
|
|
80
|
+
*
|
|
81
|
+
* The `records` array is assumed to be sorted by the timestamp in ascending order,
|
|
82
|
+
* earlier records have smaller indices.
|
|
83
|
+
*/
|
|
84
|
+
function getTimestampedRecord(records, timestamp) {
|
|
85
|
+
if (records.length === 0) return [void 0, -1];
|
|
86
|
+
if (timestamp === 0) return records[0].timestamp === 0 ? [records[0], 0] : [void 0, -1];
|
|
87
|
+
if (timestamp === 1) {
|
|
88
|
+
if (records[0].timestamp === 1) return [records[0], 0];
|
|
89
|
+
if (records.length > 1 && records[1].timestamp === 1) return [records[1], 1];
|
|
90
|
+
return [void 0, -1];
|
|
91
|
+
}
|
|
92
|
+
for (let i = records.length - 1; i >= 0; --i) {
|
|
93
|
+
const record = records[i];
|
|
94
|
+
if (record.timestamp <= timestamp) return [record, i];
|
|
95
|
+
}
|
|
96
|
+
return [void 0, -1];
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Reduces timestamps records array by pruning records with older timestamps
|
|
100
|
+
* per `maxSize` and `cutoff` window retention settings.
|
|
101
|
+
*
|
|
102
|
+
* Always retains special records with timestamps 0 and 1, these do not count
|
|
103
|
+
* towards maximum size limit.
|
|
104
|
+
*
|
|
105
|
+
* @param records array of records sorted by the timestamp in ascending order
|
|
106
|
+
* @param maxSize maximum number of entries to retain
|
|
107
|
+
* @param cutoff cutoff timestamp
|
|
108
|
+
*/
|
|
109
|
+
function pruneTimestampedRecords(records, maxSize, cutoff) {
|
|
110
|
+
if (cutoff == null && (maxSize == null || records.length <= maxSize)) return records;
|
|
111
|
+
const tailIndex = records.findIndex((_) => _.timestamp > 1);
|
|
112
|
+
if (tailIndex < 0) return records;
|
|
113
|
+
if (maxSize != null && records.length - tailIndex - maxSize > 0) records.splice(tailIndex, records.length - tailIndex - maxSize);
|
|
114
|
+
if (cutoff != null) {
|
|
115
|
+
if (records[tailIndex].timestamp >= cutoff) return records;
|
|
116
|
+
let cutoffIndex = tailIndex;
|
|
117
|
+
for (; cutoffIndex < records.length - 1; ++cutoffIndex) if (records[cutoffIndex].timestamp >= cutoff) break;
|
|
118
|
+
if (cutoffIndex > tailIndex) records.splice(tailIndex, cutoffIndex - tailIndex);
|
|
119
|
+
}
|
|
120
|
+
return records;
|
|
121
|
+
}
|
|
122
|
+
/** Sets deeply nested object value. */
|
|
123
|
+
function setValueByPath(object, path, value, insertOnly = false) {
|
|
124
|
+
path.reduce((o, key, i) => {
|
|
125
|
+
if (i === path.length - 1) {
|
|
126
|
+
if (!insertOnly || o[key] === void 0) o[key] = value;
|
|
127
|
+
} else if (o[key] === void 0) o[key] = {};
|
|
128
|
+
return o[key];
|
|
129
|
+
}, object);
|
|
130
|
+
return object;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
//#endregion
|
|
134
|
+
export { addTimestampedRecord, getTimestampedRecord, pruneTimestampedRecords, setValueByPath, toDataView, toUint8Array };
|
|
135
|
+
//# sourceMappingURL=utils.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.mjs","names":[],"sources":["../src/utils.ts"],"sourcesContent":["import type { DataChannelRecord, DataTypeImpl } from \"./abstractions\";\n\n/** Constructs the {@link DataView} from the buffer source. */\nexport function toDataView(source: unknown) {\n if (source instanceof DataView) {\n return source;\n }\n\n if (source instanceof ArrayBuffer) {\n return new DataView(source);\n }\n\n if (ArrayBuffer.isView(source)) {\n return new DataView(source.buffer, source.byteOffset, source.byteLength);\n }\n\n throw new Error(`Parameter of type '${typeof source}' cannot be wrapped into DataView`);\n}\n\n/** Returns the specified buffer source as {@link Uint8Array} view. */\nexport function toUint8Array(source: unknown) {\n if (source instanceof ArrayBuffer) {\n return new Uint8Array(source);\n }\n\n if (ArrayBuffer.isView(source)) {\n return source instanceof Uint8Array ? source : new Uint8Array(source.buffer, source.byteOffset, source.byteLength);\n }\n\n throw new Error(`Parameter of type '${typeof source}' cannot be represented as Uint8Array`);\n}\n\n/**\n * Adds timestamped record to an array of records.\n *\n * The `records` array is assumed to be sorted by the timestamp in ascending order,\n * earlier records have smaller indices.\n *\n * @returns the index at which the record has been inserted or updated\n */\nexport function addTimestampedRecord<T extends DataTypeImpl>(\n records: Array<DataChannelRecord<T>>,\n timestamp: number,\n value: T\n): number {\n if (records.length === 0) {\n records.push({\n timestamp,\n value,\n });\n\n return 0;\n }\n\n // records must be sorted by the timestamp in ascending order\n // timestamps of 0 and 1 are special, representing \"weak\" (set default)\n // and \"strong\" (set while disconnected) timestamps; otherwise we\n // expect timestamps to be generally newer than existing data\n\n const tail = records[0]!;\n let index = 0;\n\n if (timestamp === 0) {\n // replace value at timestamp zero\n if (tail.timestamp === 0) {\n tail.value = value;\n } else {\n records.unshift({\n timestamp,\n value,\n });\n }\n } else if (timestamp === 1) {\n if (tail.timestamp === 1) {\n tail.value = value;\n } else if (tail.timestamp === 0) {\n index = 1;\n if (records.length === 1) {\n records.push({\n timestamp,\n value,\n });\n } else if (records[1]!.timestamp === 1) {\n records[1]!.value = value;\n } else {\n records.splice(1, 0, {\n timestamp,\n value,\n });\n }\n } else {\n records.unshift({\n timestamp,\n value,\n });\n }\n } else {\n for (let i = records.length - 1; i >= 0; --i) {\n const record = records[i]!;\n if (record.timestamp === timestamp) {\n index = i;\n record.value = value;\n return index;\n }\n if (record.timestamp < timestamp) {\n index = i + 1;\n records.splice(i + 1, 0, {\n timestamp,\n value,\n });\n return index;\n }\n }\n\n records.unshift({\n timestamp,\n value,\n });\n }\n\n return index;\n}\n\n/**\n * Gets nearest (latest) timestamped record and its index.\n *\n * The `records` array is assumed to be sorted by the timestamp in ascending order,\n * earlier records have smaller indices.\n */\nexport function getTimestampedRecord<T extends DataTypeImpl>(\n records: Array<DataChannelRecord<T>>,\n timestamp: number\n): [DataChannelRecord<T>, number] | [undefined, -1] {\n if (records.length === 0) {\n return [undefined, -1];\n }\n\n // timestamps of 0 and 1 are special\n if (timestamp === 0) {\n return records[0]!.timestamp === 0 ? [records[0]!, 0] : [undefined, -1];\n }\n\n if (timestamp === 1) {\n if (records[0]!.timestamp === 1) {\n return [records[0]!, 0];\n }\n\n if (records.length > 1 && records[1]!.timestamp === 1) {\n return [records[1]!, 1];\n }\n\n return [undefined, -1];\n }\n\n for (let i = records.length - 1; i >= 0; --i) {\n const record = records[i]!;\n if (record.timestamp <= timestamp) {\n return [record, i];\n }\n }\n\n return [undefined, -1];\n}\n\n/**\n * Reduces timestamps records array by pruning records with older timestamps\n * per `maxSize` and `cutoff` window retention settings.\n *\n * Always retains special records with timestamps 0 and 1, these do not count\n * towards maximum size limit.\n *\n * @param records array of records sorted by the timestamp in ascending order\n * @param maxSize maximum number of entries to retain\n * @param cutoff cutoff timestamp\n */\nexport function pruneTimestampedRecords(\n records: Array<DataChannelRecord<DataTypeImpl>>,\n maxSize?: number,\n cutoff?: number\n) {\n // shortcuts\n if (cutoff == null && (maxSize == null || records.length <= maxSize)) {\n return records;\n }\n\n // skip special records and find the oldest timestamp\n const tailIndex = records.findIndex((_) => _.timestamp > 1);\n if (tailIndex < 0) {\n return records;\n }\n\n // apply maximum size policy first\n if (maxSize != null && records.length - tailIndex - maxSize > 0) {\n records.splice(tailIndex, records.length - tailIndex - maxSize);\n }\n\n // apply time window policy\n if (cutoff != null) {\n const oldest = records[tailIndex]!;\n if (oldest.timestamp >= cutoff) {\n return records;\n }\n\n let cutoffIndex = tailIndex;\n // do not delete last record even if it is outside of the window\n for (; cutoffIndex < records.length - 1; ++cutoffIndex) {\n if (records[cutoffIndex]!.timestamp >= cutoff) {\n break;\n }\n }\n\n if (cutoffIndex > tailIndex) {\n records.splice(tailIndex, cutoffIndex - tailIndex);\n }\n }\n\n return records;\n}\n\n/** Sets deeply nested object value. */\nexport function setValueByPath(\n object: Record<string, unknown>,\n path: Array<string>,\n value: unknown,\n insertOnly = false\n) {\n path.reduce((o, key, i) => {\n if (i === path.length - 1) {\n if (!insertOnly || o[key] === undefined) {\n o[key] = value;\n }\n } else if (o[key] === undefined) {\n o[key] = {};\n }\n\n return o[key];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n }, object as any);\n\n return object;\n}\n"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@2702rebels/wpidata",
|
|
3
|
+
"description": "Parsers and tools to simplify consumption of FRC WPILIB data sources - NetworkTables, WPILOG.",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"license": "BSD-3-Clause",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"exports": {
|
|
8
|
+
"./*": {
|
|
9
|
+
"import": {
|
|
10
|
+
"types": "./dist/*.d.mts",
|
|
11
|
+
"default": "./dist/*.mjs"
|
|
12
|
+
},
|
|
13
|
+
"require": {
|
|
14
|
+
"types": "./dist/*.d.cts",
|
|
15
|
+
"default": "./dist/*.cjs"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"package.json",
|
|
21
|
+
"README.md",
|
|
22
|
+
"src/**/*",
|
|
23
|
+
"dist/**/*",
|
|
24
|
+
"!src/**/*.test.ts",
|
|
25
|
+
"!dist/**/*.test.*"
|
|
26
|
+
],
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"access": "public"
|
|
29
|
+
},
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "https://github.com/2702rebels/realm.git",
|
|
33
|
+
"directory": "packages/wpidata"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@msgpack/msgpack": "^3.1.3",
|
|
37
|
+
"protobufjs": "^8.0.0"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"vitest": "^4.0.16",
|
|
41
|
+
"@2702rebels/typescript-config": "1.0.0",
|
|
42
|
+
"@2702rebels/eslint-config": "1.0.0"
|
|
43
|
+
},
|
|
44
|
+
"scripts": {
|
|
45
|
+
"clean": "rimraf .turbo && rimraf node_modules && rimraf dist",
|
|
46
|
+
"build": "tsdown",
|
|
47
|
+
"lint": "eslint --ext .ts src && tsc --noEmit -p .",
|
|
48
|
+
"lint:fix": "eslint --fix --ext .ts src",
|
|
49
|
+
"format": "prettier --write ."
|
|
50
|
+
}
|
|
51
|
+
}
|