@nxtedition/lib 28.0.2 → 28.0.5

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.
Files changed (3) hide show
  1. package/package.json +3 -2
  2. package/sequence.js +48 -11
  3. package/slice.js +294 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxtedition/lib",
3
- "version": "28.0.2",
3
+ "version": "28.0.5",
4
4
  "license": "UNLICENSED",
5
5
  "author": "Robert Nagy <robert.nagy@boffins.se>",
6
6
  "type": "module",
@@ -37,6 +37,7 @@
37
37
  "errors.js",
38
38
  "errors.d.ts",
39
39
  "worker.js",
40
+ "slice.js",
40
41
  "stream.js",
41
42
  "transcript.js",
42
43
  "docker-secrets.js",
@@ -91,5 +92,5 @@
91
92
  "pino": ">=7.0.0",
92
93
  "rxjs": "^7.0.0"
93
94
  },
94
- "gitHead": "10cdafd06260ca5abfabbf08f503ccd78819c3e2"
95
+ "gitHead": "f778b4c525a240411f681137d8dd0fe19031c7b0"
95
96
  }
package/sequence.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import assert from 'node:assert'
2
+ import util from 'node:util'
2
3
 
3
4
  export const ID_SEP = '~'
4
5
 
@@ -46,12 +47,12 @@ export class Sequence {
46
47
  return -1
47
48
  }
48
49
 
49
- if (a && typeof a === 'string') {
50
- a = new Sequence(a)
50
+ if (a === b) {
51
+ return 0
51
52
  }
52
53
 
53
- if (typeof b === 'string') {
54
- b = new Sequence(b)
54
+ if (typeof a === 'string') {
55
+ a = new Sequence(a)
55
56
  }
56
57
 
57
58
  return a.compare(b, strict)
@@ -205,13 +206,29 @@ export class Sequence {
205
206
  }
206
207
 
207
208
  at(index) {
208
- assert(Number.isFinite(index) && index >= 0 && index * 2 < this.#parts.length)
209
+ if (!Number.isInteger(index)) {
210
+ throw new TypeError('index must be an integer')
211
+ }
212
+ if (index < 0 || index >= this.#parts.length / 2) {
213
+ throw new RangeError('index out of range')
214
+ }
215
+
209
216
  return this.#parts[index * 2 + 1]
210
217
  }
211
218
 
212
219
  set(index, sequence) {
213
- assert(Number.isFinite(index) && index >= 0 && index < this.#parts.length)
214
- assert(Number.isFinite(sequence) && sequence >= 0)
220
+ if (!Number.isInteger(index)) {
221
+ throw new TypeError('index must be an integer')
222
+ }
223
+ if (index < 0 || index >= this.#parts.length / 2) {
224
+ throw new RangeError('index out of range')
225
+ }
226
+ if (!Number.isInteger(sequence)) {
227
+ throw new TypeError('sequence must be an integer')
228
+ }
229
+ if (sequence < 0) {
230
+ throw new RangeError('sequence must be non-negative')
231
+ }
215
232
  if (this.#parts[index * 2 + 1] !== sequence) {
216
233
  this.#parts[index * 2 + 1] = sequence
217
234
  this.#value = ''
@@ -224,11 +241,23 @@ export class Sequence {
224
241
  strict = true
225
242
  }
226
243
 
227
- assert(other instanceof Sequence)
228
- assert(typeof strict === 'boolean')
244
+ if (typeof other === 'string') {
245
+ if (this.#value && this.#value === other) {
246
+ return 0
247
+ }
248
+ other = new Sequence(other)
249
+ }
250
+
251
+ if (!(other instanceof Sequence)) {
252
+ throw new TypeError('Can only compare with another Sequence')
253
+ }
254
+
255
+ if (typeof strict !== 'boolean') {
256
+ throw new TypeError('strict must be a boolean')
257
+ }
229
258
 
230
- if (strict && other.identity && this.identity) {
231
- assert.strictEqual(other.identity, this.identity)
259
+ if (strict && other.identity && this.identity && other.identity !== this.identity) {
260
+ throw new Error('Cannot compare sequences with different identities')
232
261
  }
233
262
 
234
263
  if (this.#parts.length !== other.#parts.length) {
@@ -256,4 +285,12 @@ export class Sequence {
256
285
  }
257
286
  return this.#value
258
287
  }
288
+
289
+ [Symbol.toStringTag]() {
290
+ return this.toString()
291
+ }
292
+
293
+ [util.inspect.custom](depth, options, inspect) {
294
+ return `Sequence: "${this.toString()}"`
295
+ }
259
296
  }
package/slice.js ADDED
@@ -0,0 +1,294 @@
1
+ import util from 'node:util'
2
+
3
+ const EMPTY_BUF = Buffer.alloc(0)
4
+ const POOL = []
5
+
6
+ export class Slice {
7
+ buffer
8
+ byteOffset = 0
9
+ byteLength = 0
10
+ maxByteLength = 0
11
+
12
+ static EMPTY_BUF = EMPTY_BUF
13
+
14
+ /**
15
+ *
16
+ * @param {Buffer} [buffer]
17
+ * @param {number} [byteOffset]
18
+ * @param {number} [byteLength]
19
+ * @param {number} [maxByteLength]
20
+ */
21
+ constructor(
22
+ buffer = Slice.EMPTY_BUF,
23
+ byteOffset = 0,
24
+ byteLength = buffer.byteLength,
25
+ maxByteLength = byteLength,
26
+ ) {
27
+ if (byteOffset < 0 || !Number.isInteger(byteOffset)) {
28
+ throw new RangeError(`Invalid byteOffset: ${byteOffset}`)
29
+ }
30
+
31
+ if (byteLength < 0 || !Number.isInteger(byteLength)) {
32
+ throw new RangeError(`Invalid byteLength: ${byteLength}`)
33
+ }
34
+
35
+ if (
36
+ maxByteLength < byteLength ||
37
+ maxByteLength > buffer.byteLength ||
38
+ !Number.isInteger(maxByteLength)
39
+ ) {
40
+ throw new RangeError(`Invalid maxByteLength: ${maxByteLength}`)
41
+ }
42
+
43
+ this.buffer = buffer
44
+ this.byteOffset = byteOffset
45
+ this.byteLength = byteLength
46
+ this.maxByteLength = maxByteLength
47
+ }
48
+
49
+ static create(buffer, byteOffset, byteLength, maxByteLength) {
50
+ if (buffer === undefined) {
51
+ buffer = Slice.EMPTY_BUF
52
+ }
53
+ if (byteOffset === undefined) {
54
+ byteOffset = 0
55
+ }
56
+ if (byteLength === undefined) {
57
+ byteLength = buffer.byteLength
58
+ }
59
+ if (maxByteLength === undefined) {
60
+ maxByteLength = byteLength
61
+ }
62
+
63
+ if (byteOffset < 0) {
64
+ throw new RangeError('byteOffset must be non-negative')
65
+ }
66
+
67
+ if (byteLength < 0) {
68
+ throw new RangeError('byteLength must be non-negative')
69
+ }
70
+
71
+ if (byteLength > maxByteLength) {
72
+ throw new RangeError('byteLength cannot be greater than maxByteLength')
73
+ }
74
+
75
+ if (byteOffset + maxByteLength > buffer.byteLength) {
76
+ throw new RangeError('Slice exceeds buffer length')
77
+ }
78
+
79
+ const slice = POOL.pop()
80
+
81
+ if (slice) {
82
+ slice.buffer = buffer
83
+ slice.byteOffset = byteOffset
84
+ slice.byteLength = byteLength
85
+ slice.maxByteLength = maxByteLength
86
+ return slice
87
+ }
88
+
89
+ return new Slice(buffer, byteOffset, byteLength, maxByteLength)
90
+ }
91
+
92
+ static free(slice) {
93
+ if (slice == null) {
94
+ return
95
+ }
96
+
97
+ slice.reset()
98
+
99
+ if (POOL.length < 16 * 1024) {
100
+ POOL.push(slice)
101
+ }
102
+ }
103
+
104
+ reset() {
105
+ this.buffer = Slice.EMPTY_BUF
106
+ this.byteOffset = 0
107
+ this.byteLength = 0
108
+ this.maxByteLength = 0
109
+ }
110
+
111
+ get length() {
112
+ return this.byteLength
113
+ }
114
+
115
+ /**
116
+ * @param {Buffer|Slice} target
117
+ * @param {number} [targetStart = 0]
118
+ * @param {number} [sourceStart = 0]
119
+ * @param {number} [sourceEnd = this.byteOffset]
120
+ * @returns {number} Number of bytes written.
121
+ */
122
+ copy(target, targetStart, sourceStart, sourceEnd) {
123
+ if (target instanceof Slice) {
124
+ if (targetStart === undefined) {
125
+ targetStart = target.byteOffset
126
+ } else {
127
+ targetStart += target.byteOffset
128
+ }
129
+
130
+ target = target.buffer
131
+ }
132
+
133
+ if (sourceStart === undefined) {
134
+ sourceStart = this.byteOffset
135
+ } else {
136
+ sourceStart += this.byteOffset
137
+ }
138
+
139
+ if (sourceEnd === undefined) {
140
+ sourceEnd = this.byteLength + this.byteOffset
141
+ } else {
142
+ sourceEnd += this.byteOffset
143
+ }
144
+
145
+ return this.buffer.copy(target, targetStart, sourceStart, sourceEnd)
146
+ }
147
+
148
+ /**
149
+ * @param {Buffer|Slice} target
150
+ * @param {number} [targetStart = 0]
151
+ * @param {number} [targetEnd = target.byteOffset]
152
+ * @param {number} [sourceStart = 0]
153
+ * @param {number} [sourceEnd = this.byteOffset]
154
+ * @returns
155
+ */
156
+ compare(target, targetStart, targetEnd, sourceStart, sourceEnd) {
157
+ if (target instanceof Slice) {
158
+ if (targetStart === undefined) {
159
+ targetStart = target.byteOffset
160
+ } else {
161
+ targetStart += target.byteOffset
162
+ }
163
+
164
+ if (targetEnd === undefined) {
165
+ targetEnd = target.byteLength + target.byteOffset
166
+ } else {
167
+ targetEnd += target.byteOffset
168
+ }
169
+
170
+ target = target.buffer
171
+ }
172
+
173
+ if (sourceStart === undefined) {
174
+ sourceStart = this.byteOffset
175
+ } else {
176
+ sourceStart += this.byteOffset
177
+ }
178
+
179
+ if (sourceEnd === undefined) {
180
+ sourceEnd = this.byteLength + this.byteOffset
181
+ } else {
182
+ sourceEnd += this.byteOffset
183
+ }
184
+
185
+ return this.buffer.compare(target, targetStart, targetEnd, sourceStart, sourceEnd)
186
+ }
187
+
188
+ /**
189
+ *
190
+ * @param {string} string
191
+ * @param {number} [offset=0]
192
+ * @param {number} [length=this.byteLength - offset]
193
+ * @param {NodeJS.BufferEncoding} [encoding='utf8']
194
+ * @returns {number} Number of bytes written.
195
+ */
196
+ write(string, offset, length, encoding) {
197
+ if (offset === undefined) {
198
+ offset = this.byteOffset
199
+ } else {
200
+ offset += this.byteOffset
201
+ }
202
+
203
+ if (length === undefined) {
204
+ length = this.byteLength + this.byteOffset - offset
205
+ }
206
+
207
+ return this.buffer.write(string, offset, length, encoding)
208
+ }
209
+
210
+ set(array, offset) {
211
+ if (array == null) {
212
+ return
213
+ }
214
+
215
+ if (offset === undefined) {
216
+ offset = this.byteOffset
217
+ } else {
218
+ offset += this.byteOffset
219
+ }
220
+
221
+ array?.copy(this.buffer, offset)
222
+ }
223
+
224
+ at(index) {
225
+ return index >= 0
226
+ ? this.buffer[this.byteOffset + index]
227
+ : this.buffer[this.byteOffset + this.byteLength + index]
228
+ }
229
+
230
+ test(expr) {
231
+ return expr.test(this.buffer, this.byteOffset, this.byteLength)
232
+ }
233
+
234
+ readBigUInt64BE(offset = 0) {
235
+ if (offset === undefined) {
236
+ offset = this.byteOffset
237
+ } else {
238
+ offset += this.byteOffset
239
+ }
240
+
241
+ return this.buffer.readBigUInt64BE(offset)
242
+ }
243
+
244
+ /**
245
+ *
246
+ * @param {BufferEncoding} [encoding='utf8']
247
+ * @param {number} [start=0]
248
+ * @param {number} [end=this.byteLength]
249
+ * @returns {string}
250
+ */
251
+ toString(encoding, start, end) {
252
+ if (start === undefined) {
253
+ start = this.byteOffset
254
+ } else {
255
+ start += this.byteOffset
256
+ }
257
+
258
+ if (end === undefined) {
259
+ end = this.byteLength + this.byteOffset
260
+ } else {
261
+ end += this.byteOffset
262
+ }
263
+
264
+ return this.buffer.toString(encoding, start, end)
265
+ }
266
+
267
+ toBuffer(start, end) {
268
+ if (start === undefined) {
269
+ start = this.byteOffset
270
+ } else {
271
+ start += this.byteOffset
272
+ }
273
+
274
+ if (end === undefined) {
275
+ end = this.byteLength + this.byteOffset
276
+ } else {
277
+ end += this.byteOffset
278
+ }
279
+
280
+ return this.buffer.subarray(start, end)
281
+ }
282
+
283
+ [Symbol.toStringTag]() {
284
+ return this.toString()
285
+ }
286
+
287
+ [util.inspect.custom](depth, options, inspect) {
288
+ const bytes = []
289
+ for (let i = 0; i < this.byteLength; i++) {
290
+ bytes.push(this.buffer[this.byteOffset + i].toString(16).padStart(2, '0'))
291
+ }
292
+ return `Slice: "${this.toString()}" <${bytes.join(' ')}>`
293
+ }
294
+ }