mcbe-leveldb 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/SNBTUtils.js ADDED
@@ -0,0 +1,1374 @@
1
+ import NBT, {} from "prismarine-nbt";
2
+ function toPrimitive(tag) {
3
+ switch (tag.type) {
4
+ case "byte":
5
+ case "short":
6
+ case "int":
7
+ case "float":
8
+ case "double":
9
+ return tag.value;
10
+ case "long":
11
+ return Number(toLong(tag.value));
12
+ default:
13
+ throw new SyntaxError("Cannot convert to primitive: " + tag.type);
14
+ }
15
+ }
16
+ function uuidToIntArray(uuidStr) {
17
+ const hex = uuidStr.replace(/-/g, "");
18
+ if (hex.length !== 32)
19
+ throw new SyntaxError("Invalid UUID: " + uuidStr, {
20
+ cause: {
21
+ position: 0,
22
+ stack: [
23
+ {
24
+ input: uuidStr,
25
+ positionInInput: 0,
26
+ function: "uuidToIntArray",
27
+ error: { type: "InvalidUUID", uuid: uuidStr },
28
+ },
29
+ ],
30
+ },
31
+ });
32
+ const arr = [];
33
+ for (let i = 0; i < 16; i += 4) {
34
+ arr.push((parseInt(hex.slice(i, i + 4), 16) << 16) >> 16); // 32-bit signed chunks
35
+ }
36
+ return arr;
37
+ }
38
+ export const SNBTParseErrorTypeToCode = {
39
+ DisallowedTypeInTypedArray: "disallowed-type-in-typed-array",
40
+ ExpectedCompoundOrList: "expected-compound-or-list",
41
+ InvalidArgumentToFunction: "invalid-argument-to-function",
42
+ InvalidSNBTKey: "invalid-snbt-key",
43
+ InvalidSNBTString: "invalid-snbt-string",
44
+ InvalidUUID: "invalid-uuid",
45
+ UnsupportedFunction: "unsupported-function",
46
+ UnsupportedSNBTPrimitive: "unsupported-snbt-primitive",
47
+ MixedListTypesNotAllowed: "mixed-list-types-not-allowed",
48
+ UnsupportedTypeInTypedArray: "unsupported-type-in-typed-array",
49
+ ExpectedEndOfInput: "expected-end-of-input",
50
+ };
51
+ export const SNBTParseErrorDisplayNamespace = "mcbe-leveldb";
52
+ export var SNBTParseError = new Proxy(class SNBTParseError extends Error {
53
+ isResolved = false;
54
+ originalInput = null;
55
+ constructor(message, options) {
56
+ if (arguments.length !== 2)
57
+ throw new TypeError(`Incorrect number of arguments to constructor, expected 2 but got ${arguments.length} instead.`);
58
+ if (typeof message !== "string")
59
+ throw new TypeError(`Expected args[0] (message) to be a string but got ${typeof message} instead.`);
60
+ if (typeof options !== "object" || options === null)
61
+ throw new TypeError(`Expected args[1] (options) to be an object but got ${options === null ? "null" : typeof options} instead.`);
62
+ if (typeof options.cause !== "object" || options.cause === null)
63
+ throw new TypeError(`Expected options.cause to be an object but got ${options === null ? "null" : typeof options.cause} instead.`);
64
+ super(message, options);
65
+ this.isResolved = options.resolved ?? false;
66
+ this.originalInput = options.originalInput ?? null;
67
+ }
68
+ getErrorPosition() {
69
+ if (!this.isResolved || this.originalInput === null)
70
+ return null;
71
+ const cause = this.cause;
72
+ const position = cause.position;
73
+ const input = this.originalInput;
74
+ return [input.slice(0, position).split("\n").length, position - input.slice(0, position).lastIndexOf("\n") + 1];
75
+ }
76
+ getErrorEndPosition() {
77
+ if (!this.isResolved || this.originalInput === null)
78
+ return null;
79
+ const cause = this.cause;
80
+ let offset = 0;
81
+ const stackItem = cause.stack[0];
82
+ stackItemFunctionSwitcher: switch (stackItem.function) {
83
+ case "extractSNBT":
84
+ switch (stackItem.error?.type) {
85
+ case "InvalidSNBTKey":
86
+ offset = stackItem.error.raw.length;
87
+ break stackItemFunctionSwitcher;
88
+ default:
89
+ offset = stackItem.input.length - stackItem.positionInInput;
90
+ break stackItemFunctionSwitcher;
91
+ }
92
+ case "parseList":
93
+ switch (stackItem.error?.type) {
94
+ case "MixedListTypesNotAllowed":
95
+ offset = stackItem.inputItem.length - stackItem.positionInInputItem;
96
+ break stackItemFunctionSwitcher;
97
+ default:
98
+ offset = stackItem.inputItem.length - stackItem.positionInInputItem;
99
+ break stackItemFunctionSwitcher;
100
+ }
101
+ case "parseSNBTCompoundString":
102
+ switch (stackItem.error?.type) {
103
+ case "InvalidSNBTKey":
104
+ offset = stackItem.error.raw.length;
105
+ break stackItemFunctionSwitcher;
106
+ default:
107
+ offset = stackItem.input.length - stackItem.positionInInput;
108
+ break stackItemFunctionSwitcher;
109
+ }
110
+ case "parseSNBTPrimitive":
111
+ switch (stackItem.error?.type) {
112
+ case "InvalidArgumentToFunction":
113
+ offset = stackItem.error.argument.length;
114
+ break stackItemFunctionSwitcher;
115
+ case "UnsupportedFunction":
116
+ offset = stackItem.error.functionName.length;
117
+ break stackItemFunctionSwitcher;
118
+ case "UnsupportedSNBTPrimitive":
119
+ offset = stackItem.error.raw.length;
120
+ break stackItemFunctionSwitcher;
121
+ case "InvalidSNBTString":
122
+ offset = stackItem.error.raw.length;
123
+ break stackItemFunctionSwitcher;
124
+ default:
125
+ offset = stackItem.input.length - stackItem.positionInInput;
126
+ break stackItemFunctionSwitcher;
127
+ }
128
+ case "parseTypedArray":
129
+ switch (stackItem.error?.type) {
130
+ case "DisallowedTypeInTypedArray":
131
+ offset = stackItem.inputItem.length - stackItem.positionInInputItem;
132
+ break stackItemFunctionSwitcher;
133
+ case "UnsupportedTypeInTypedArray":
134
+ offset = stackItem.inputItem.length - stackItem.positionInInputItem;
135
+ break stackItemFunctionSwitcher;
136
+ default:
137
+ offset = stackItem.inputItem.length - stackItem.positionInInputItem;
138
+ break stackItemFunctionSwitcher;
139
+ }
140
+ case "uuidToIntArray":
141
+ offset = stackItem.error.uuid.length;
142
+ break;
143
+ }
144
+ const position = cause.position + offset;
145
+ const input = this.originalInput;
146
+ return [input.slice(0, position).split("\n").length, position - input.slice(0, position).lastIndexOf("\n") + 1];
147
+ }
148
+ getErrorPositionWithOffset(offset) {
149
+ if (!this.isResolved || this.originalInput === null)
150
+ return null;
151
+ const cause = this.cause;
152
+ const position = cause.position + offset;
153
+ const input = this.originalInput;
154
+ return [input.slice(0, position).split("\n").length, position - input.slice(0, position).lastIndexOf("\n") + 1];
155
+ }
156
+ getErrorPositionForStackItem(stackItem) {
157
+ const input = "input" in stackItem ? stackItem.input : stackItem.inputItem;
158
+ const position = "positionInInput" in stackItem ? stackItem.positionInInput : stackItem.positionInInputItem;
159
+ return [input.slice(0, position).split("\n").length, position - input.slice(0, position).lastIndexOf("\n") + 1];
160
+ }
161
+ }, {
162
+ apply(target, thisArg, argumentsList) {
163
+ return new target(...argumentsList);
164
+ },
165
+ });
166
+ function parseSNBTPrimitive(raw, options = {}) {
167
+ const errors = [];
168
+ function structureResult(val) {
169
+ if (options.keepGoingAfterError)
170
+ return { value: val, errors };
171
+ return val;
172
+ }
173
+ try {
174
+ if (typeof raw === "string") {
175
+ const originalInput = raw;
176
+ raw = raw.trim();
177
+ const funcMatch = raw.match(/^(\w+)\((.*)\)$/s);
178
+ if (funcMatch) {
179
+ const fn = funcMatch[1];
180
+ const arg = funcMatch[2].trim();
181
+ switch (fn) {
182
+ case "bool": {
183
+ const baseVal = parseSNBTPrimitive(arg, options);
184
+ if ("errors" in baseVal) {
185
+ baseVal.errors.forEach((err) => {
186
+ err.cause.stack.push({
187
+ input: originalInput,
188
+ positionInInput: originalInput.indexOf(raw) + fn.length + 1,
189
+ function: "parseSNBTPrimitive",
190
+ });
191
+ err.cause.position += originalInput.indexOf(raw) + fn.length + 1;
192
+ });
193
+ errors.push(...baseVal.errors);
194
+ }
195
+ const val = "errors" in baseVal ? baseVal.value : baseVal;
196
+ if (!val)
197
+ return structureResult();
198
+ if (val.type === "short" || val.type === "int" || val.type === "long" || val.type === "float" || val.type === "double") {
199
+ const num = Number(toPrimitive(val));
200
+ return structureResult(NBT.byte(num === 0 ? 0 : 1));
201
+ }
202
+ if (val.type === "byte")
203
+ return val;
204
+ throw new SNBTParseError(`Invalid argument to bool(): ${arg}`, {
205
+ cause: {
206
+ position: originalInput.indexOf(raw) + fn.length + 1,
207
+ stack: [
208
+ {
209
+ input: originalInput,
210
+ positionInInput: originalInput.indexOf(raw) + fn.length + 1,
211
+ function: "parseSNBTPrimitive",
212
+ error: { type: "InvalidArgumentToFunction", functionName: "bool", argument: arg },
213
+ },
214
+ ],
215
+ },
216
+ });
217
+ }
218
+ case "uuid": {
219
+ const uuidStr = arg.replace(/^["']|["']$/g, "");
220
+ try {
221
+ const uuidIntArray = uuidToIntArray(uuidStr);
222
+ return structureResult(NBT.intArray(uuidIntArray));
223
+ }
224
+ catch (e) {
225
+ if (e instanceof Error && e.cause) {
226
+ e.cause.stack.push({
227
+ positionInInput: originalInput.indexOf(raw) + fn.length + 1,
228
+ input: originalInput,
229
+ function: "parseSNBTPrimitive",
230
+ error: {
231
+ type: "InvalidArgumentToFunction",
232
+ functionName: "uuid",
233
+ argument: arg,
234
+ },
235
+ });
236
+ e.cause.position += originalInput.indexOf(raw) + fn.length + 1;
237
+ }
238
+ throw e;
239
+ }
240
+ }
241
+ default:
242
+ throw ((new ReferenceError(`Unsupported SNBT function: ${fn}`),
243
+ {
244
+ cause: {
245
+ position: originalInput.indexOf(raw) + fn.length + 1,
246
+ stack: [
247
+ {
248
+ input: originalInput,
249
+ positionInInput: originalInput.indexOf(raw) + fn.length + 1,
250
+ function: "parseSNBTPrimitive",
251
+ error: { type: "UnsupportedFunction", functionName: fn },
252
+ },
253
+ ],
254
+ },
255
+ }));
256
+ }
257
+ }
258
+ const arrMatch = raw.match(/^\[(B|S|I|L);\s*(.*?)\]$/is);
259
+ if (arrMatch) {
260
+ const type = arrMatch[1].toUpperCase();
261
+ const items = arrMatch[2].split(/\s*,\s*/).filter(Boolean);
262
+ const baseVal = parseTypedArray(type, items, options);
263
+ if ("errors" in baseVal) {
264
+ baseVal.errors.forEach((err) => {
265
+ const lastStackItem = err.cause.stack.at(-1);
266
+ const baseOffset = arrMatch[2].match(new RegExp(`^(.*?\\s*(,\\s*|$)){${lastStackItem.inputItemIndex}}`))?.[0]?.length ?? 0;
267
+ err.cause.stack.push({
268
+ input: originalInput,
269
+ positionInInput: originalInput.indexOf(raw) + raw.indexOf(arrMatch[2]) + baseOffset,
270
+ function: "parseSNBTPrimitive",
271
+ });
272
+ err.cause.position += originalInput.indexOf(raw) + raw.indexOf(arrMatch[2]) + baseOffset;
273
+ });
274
+ errors.push(...baseVal.errors);
275
+ }
276
+ return structureResult("errors" in baseVal ? baseVal.value : baseVal);
277
+ }
278
+ const listMatch = raw.match(/^\[\s*(.*?)\]$/is);
279
+ if (listMatch) {
280
+ const baseVal = extractSNBT(raw, options);
281
+ if ("errors" in baseVal) {
282
+ baseVal.errors.forEach((err) => {
283
+ err.cause.stack.push({
284
+ input: originalInput,
285
+ positionInInput: originalInput.indexOf(raw),
286
+ function: "parseSNBTPrimitive",
287
+ });
288
+ err.cause.position += originalInput.indexOf(raw);
289
+ });
290
+ errors.push(...baseVal.errors);
291
+ }
292
+ return structureResult("errors" in baseVal ? baseVal.value : baseVal.value);
293
+ }
294
+ const match = raw.match(/^([-+]?0x[\da-fA-F]+|0b[01]+|[-+]?\d*\.?\d*(?:[eE][-+]?\d+)?)([bsilfdBSILFD])?$/i);
295
+ if (match) {
296
+ const numStr = match[1];
297
+ const suffix = match[2]?.toLowerCase();
298
+ let value;
299
+ if (numStr.startsWith("0x"))
300
+ value = parseInt(numStr, 16);
301
+ else if (numStr.startsWith("0b"))
302
+ value = parseInt(numStr.slice(2), 2);
303
+ else if (suffix === "l")
304
+ value = BigInt(numStr);
305
+ else
306
+ value = Number(numStr);
307
+ switch (suffix) {
308
+ case "b":
309
+ return structureResult(NBT.byte(Number(value)));
310
+ case "s":
311
+ return structureResult(NBT.short(Number(value)));
312
+ case "i":
313
+ return structureResult(NBT.int(Number(value)));
314
+ case "l":
315
+ return structureResult(NBT.long(toLongParts(BigInt(value))));
316
+ case "f":
317
+ return structureResult(NBT.float(Number(value)));
318
+ case "d":
319
+ return structureResult(NBT.double(Number(value)));
320
+ default:
321
+ if (typeof value === "bigint")
322
+ return structureResult(NBT.long(toLongParts(value)));
323
+ if (Number.isInteger(value))
324
+ return structureResult(NBT.int(value));
325
+ return structureResult(NBT.double(value));
326
+ }
327
+ }
328
+ if (["true", "false"].includes(raw))
329
+ return structureResult(NBT.byte(+(raw === "true")));
330
+ try {
331
+ return structureResult({
332
+ type: "string",
333
+ value: parseFormattedString(raw),
334
+ });
335
+ }
336
+ catch {
337
+ const error = new SNBTParseError("Invalid SNBT string: " + raw, {
338
+ cause: {
339
+ position: originalInput.indexOf(raw),
340
+ stack: [
341
+ {
342
+ function: "parseSNBTPrimitive",
343
+ input: originalInput,
344
+ positionInInput: originalInput.indexOf(raw),
345
+ error: {
346
+ type: "InvalidSNBTString",
347
+ raw,
348
+ },
349
+ },
350
+ ],
351
+ },
352
+ });
353
+ if (options.keepGoingAfterError)
354
+ errors.push(error);
355
+ else
356
+ throw error;
357
+ return structureResult();
358
+ }
359
+ }
360
+ if (typeof raw === "number") {
361
+ if (raw % 1 !== 0)
362
+ return structureResult(NBT.double(raw));
363
+ return structureResult(NBT.int(raw));
364
+ }
365
+ if (typeof raw === "bigint")
366
+ return structureResult(NBT.long(toLongParts(raw)));
367
+ if (typeof raw === "boolean")
368
+ return structureResult(NBT.byte(+raw));
369
+ throw new SNBTParseError("Unsupported SNBT primitive: " + raw, {
370
+ cause: {
371
+ position: 0,
372
+ stack: [
373
+ {
374
+ function: "parseSNBTPrimitive",
375
+ input: raw,
376
+ positionInInput: 0,
377
+ error: {
378
+ type: "UnsupportedSNBTPrimitive",
379
+ raw,
380
+ },
381
+ },
382
+ ],
383
+ },
384
+ });
385
+ }
386
+ catch (e) {
387
+ if (options.keepGoingAfterError && e instanceof SNBTParseError)
388
+ errors.push(e);
389
+ else
390
+ throw e;
391
+ return structureResult();
392
+ }
393
+ }
394
+ var TypedArrayLetterTypes;
395
+ (function (TypedArrayLetterTypes) {
396
+ TypedArrayLetterTypes["B"] = "byte";
397
+ TypedArrayLetterTypes["S"] = "short";
398
+ TypedArrayLetterTypes["I"] = "int";
399
+ TypedArrayLetterTypes["L"] = "long";
400
+ })(TypedArrayLetterTypes || (TypedArrayLetterTypes = {}));
401
+ function parseTypedArray(type, items, options = {}) {
402
+ const errors = [];
403
+ const values = [];
404
+ let i = 0;
405
+ for (const x of items) {
406
+ try {
407
+ if (/^-?\d+b$/i.test(x)) {
408
+ const n = Number(x.slice(0, -1));
409
+ if (type === "L")
410
+ values.push(toLongParts(BigInt(n)));
411
+ else if (!["B", "S", "I", "L"].includes(type))
412
+ throw new SNBTParseError(`Byte value not allowed in ${TypedArrayLetterTypes[type]} array: ${x}`, {
413
+ cause: {
414
+ position: 0,
415
+ stack: [
416
+ {
417
+ function: "parseTypedArray",
418
+ inputItems: items,
419
+ inputItem: x,
420
+ inputItemIndex: i,
421
+ positionInInputItem: 0,
422
+ arrayType: TypedArrayLetterTypes[type],
423
+ error: {
424
+ type: "DisallowedTypeInTypedArray",
425
+ allowedTypes: [TypedArrayLetterTypes.B, TypedArrayLetterTypes.S, TypedArrayLetterTypes.I, TypedArrayLetterTypes.L],
426
+ itemType: NBT.TagType.Byte,
427
+ },
428
+ },
429
+ ],
430
+ },
431
+ });
432
+ else
433
+ values.push(n);
434
+ }
435
+ else if (/^-?\d+s$/i.test(x)) {
436
+ const n = Number(x.slice(0, -1));
437
+ if (type === "L")
438
+ values.push(toLongParts(BigInt(n)));
439
+ else if (!["S", "I", "L"].includes(type))
440
+ throw new SNBTParseError(`Short value not allowed in ${TypedArrayLetterTypes[type]} array: ${x}`, {
441
+ cause: {
442
+ position: 0,
443
+ stack: [
444
+ {
445
+ function: "parseTypedArray",
446
+ inputItems: items,
447
+ inputItem: x,
448
+ inputItemIndex: i,
449
+ positionInInputItem: 0,
450
+ arrayType: TypedArrayLetterTypes[type],
451
+ error: {
452
+ type: "DisallowedTypeInTypedArray",
453
+ allowedTypes: [TypedArrayLetterTypes.B, TypedArrayLetterTypes.S, TypedArrayLetterTypes.I, TypedArrayLetterTypes.L],
454
+ itemType: NBT.TagType.Short,
455
+ },
456
+ },
457
+ ],
458
+ },
459
+ });
460
+ else
461
+ values.push(n);
462
+ }
463
+ else if (/^-?\d+l$/i.test(x)) {
464
+ if (type !== "L")
465
+ throw new SNBTParseError(`Long value not allowed in ${TypedArrayLetterTypes[type]} array: ${x}`, {
466
+ cause: {
467
+ position: 0,
468
+ stack: [
469
+ {
470
+ function: "parseTypedArray",
471
+ inputItems: items,
472
+ inputItem: x,
473
+ inputItemIndex: i,
474
+ positionInInputItem: 0,
475
+ arrayType: TypedArrayLetterTypes[type],
476
+ error: {
477
+ type: "DisallowedTypeInTypedArray",
478
+ allowedTypes: [TypedArrayLetterTypes.B, TypedArrayLetterTypes.S, TypedArrayLetterTypes.I, TypedArrayLetterTypes.L],
479
+ itemType: NBT.TagType.Long,
480
+ },
481
+ },
482
+ ],
483
+ },
484
+ });
485
+ values.push(parseLong(x));
486
+ }
487
+ else if (/^-?\d+i?$/.test(x)) {
488
+ const n = x.toLowerCase().endsWith("i") ? Number(x.slice(0, -1)) : Number(x);
489
+ if (type === "L")
490
+ values.push(toLongParts(BigInt(n)));
491
+ else if (!["I", "L"].includes(type))
492
+ throw new SNBTParseError(`Int value not allowed in ${TypedArrayLetterTypes[type]} array: ${x}`, {
493
+ cause: {
494
+ position: 0,
495
+ stack: [
496
+ {
497
+ function: "parseTypedArray",
498
+ inputItems: items,
499
+ inputItem: x,
500
+ inputItemIndex: i,
501
+ positionInInputItem: 0,
502
+ arrayType: TypedArrayLetterTypes[type],
503
+ error: {
504
+ type: "DisallowedTypeInTypedArray",
505
+ allowedTypes: [TypedArrayLetterTypes.B, TypedArrayLetterTypes.S, TypedArrayLetterTypes.I, TypedArrayLetterTypes.L],
506
+ itemType: NBT.TagType.Int,
507
+ },
508
+ },
509
+ ],
510
+ },
511
+ });
512
+ else
513
+ values.push(n);
514
+ }
515
+ else if (["true", "false"].includes(x)) {
516
+ values.push(+(x === "true"));
517
+ }
518
+ else {
519
+ throw new SNBTParseError(`Unsupported value in ${TypedArrayLetterTypes[type]} array: ${x}`, {
520
+ cause: {
521
+ position: 0,
522
+ stack: [
523
+ {
524
+ function: "parseTypedArray",
525
+ inputItems: items,
526
+ inputItem: x,
527
+ inputItemIndex: i,
528
+ positionInInputItem: 0,
529
+ arrayType: TypedArrayLetterTypes[type],
530
+ error: {
531
+ type: "UnsupportedTypeInTypedArray",
532
+ itemType: (() => {
533
+ try {
534
+ return parseSNBTPrimitive(x).type;
535
+ }
536
+ catch {
537
+ return undefined;
538
+ }
539
+ })(),
540
+ },
541
+ },
542
+ ],
543
+ },
544
+ });
545
+ }
546
+ }
547
+ catch (e) {
548
+ if (options.keepGoingAfterError && e instanceof SNBTParseError)
549
+ errors.push(e);
550
+ else
551
+ throw e;
552
+ }
553
+ i++;
554
+ }
555
+ let result;
556
+ switch (type) {
557
+ case "B":
558
+ result = NBT.byteArray(values);
559
+ break;
560
+ case "S":
561
+ result = NBT.shortArray(values);
562
+ break;
563
+ case "I":
564
+ result = NBT.intArray(values);
565
+ break;
566
+ case "L":
567
+ result = NBT.longArray(values);
568
+ break;
569
+ }
570
+ return options.keepGoingAfterError ? { value: result, errors } : result;
571
+ }
572
+ function parseList(items, options = {}) {
573
+ console.log(items, items.length);
574
+ const errors = [];
575
+ let values = [];
576
+ let valueIndices = [];
577
+ let i = 0;
578
+ for (const x of items) {
579
+ try {
580
+ if (x.trim().startsWith("{")) {
581
+ const baseVal = parseSNBTCompoundString(x, options);
582
+ if ("errors" in baseVal) {
583
+ baseVal.errors.forEach((err) => {
584
+ err.cause.stack.push({
585
+ inputItem: x,
586
+ inputItemIndex: i,
587
+ inputItems: items,
588
+ positionInInputItem: 0,
589
+ function: "parseList",
590
+ });
591
+ err.cause.position += 0;
592
+ });
593
+ errors.push(...baseVal.errors);
594
+ }
595
+ values.push("errors" in baseVal ? baseVal.value : baseVal);
596
+ }
597
+ else {
598
+ const baseVal = parseSNBTPrimitive(x, options);
599
+ if ("errors" in baseVal) {
600
+ baseVal.errors.forEach((err) => {
601
+ err.cause.stack.push({
602
+ inputItem: x,
603
+ inputItemIndex: i,
604
+ inputItems: items,
605
+ positionInInputItem: 0,
606
+ function: "parseList",
607
+ });
608
+ err.cause.position += 0;
609
+ });
610
+ errors.push(...baseVal.errors);
611
+ }
612
+ const val = "errors" in baseVal ? baseVal.value : baseVal;
613
+ if (val !== undefined)
614
+ values.push(val);
615
+ }
616
+ valueIndices.push(i);
617
+ }
618
+ catch (e) {
619
+ if (options.keepGoingAfterError && e instanceof SNBTParseError)
620
+ errors.push(e);
621
+ else
622
+ throw e;
623
+ }
624
+ i++;
625
+ }
626
+ let type = values[0]?.type;
627
+ if (type &&
628
+ !values.every((v, i) => {
629
+ if (v.type === type) {
630
+ return true;
631
+ }
632
+ if (!(options.mixedListsAllowed ?? true)) {
633
+ if (!options.keepGoingAfterError)
634
+ throw new SNBTParseError("Mixed list types not allowed.", {
635
+ cause: {
636
+ position: 0,
637
+ stack: [
638
+ {
639
+ function: "parseList",
640
+ inputItems: items,
641
+ inputItem: items[i],
642
+ inputItemIndex: valueIndices[i],
643
+ positionInInputItem: 0,
644
+ error: {
645
+ type: "MixedListTypesNotAllowed",
646
+ itemType: v.type,
647
+ item: v,
648
+ detectedArrayType: type,
649
+ },
650
+ },
651
+ ],
652
+ },
653
+ });
654
+ }
655
+ return false;
656
+ })) {
657
+ if (!(options.mixedListsAllowed ?? true) && options.keepGoingAfterError) {
658
+ const numOfEachType = values.reduce((acc, v) => ({ ...acc, [v.type]: (acc[v.type] ?? 0) + 1 }), {});
659
+ const mostCommonType = Object.entries(numOfEachType).reduce((a, b) => (a[1] > b[1] ? a : b))[0];
660
+ for (let i = 0; i < values.length; i++) {
661
+ if (values[i].type === mostCommonType)
662
+ continue;
663
+ errors.push(new SNBTParseError("Mixed list types not allowed.", {
664
+ cause: {
665
+ position: 0,
666
+ stack: [
667
+ {
668
+ function: "parseList",
669
+ inputItems: items,
670
+ inputItem: items[i],
671
+ inputItemIndex: valueIndices[i],
672
+ positionInInputItem: 0,
673
+ error: {
674
+ type: "MixedListTypesNotAllowed",
675
+ itemType: values[i].type,
676
+ item: values[i],
677
+ detectedArrayType: type,
678
+ },
679
+ },
680
+ ],
681
+ },
682
+ }));
683
+ }
684
+ }
685
+ if (options.convertMixedListsToCompoundLists ?? true)
686
+ values = values.map((v, i) => ({ type: NBT.TagType.Compound, value: { "": v } }));
687
+ }
688
+ const result = NBT.list({ type: values[0]?.type ?? "end", value: values.map((v) => v.value) });
689
+ return options.keepGoingAfterError ? { value: result, errors } : result;
690
+ }
691
+ export function parseSNBTCompoundString(input, options = {}) {
692
+ const errors = [];
693
+ const originalInput = input;
694
+ input = input.trim();
695
+ if (input.startsWith("{")) {
696
+ input = input.slice(1);
697
+ }
698
+ const result = {};
699
+ let depth = 0;
700
+ let currentValuePos = -1;
701
+ let currentKey = "";
702
+ let currentValue = "";
703
+ let inString = null;
704
+ function commitPair() {
705
+ if (!currentKey)
706
+ return;
707
+ result[currentKey.trim()] = parseValue(currentValue.trim(), currentKey, currentValuePos);
708
+ currentKey = "";
709
+ currentValue = "";
710
+ currentValuePos = -1;
711
+ }
712
+ function parseValue(val, key, pos) {
713
+ const originalVal = val;
714
+ val = val.trim();
715
+ if (!val)
716
+ return NBT.comp({});
717
+ if (val.startsWith("{") && val.endsWith("}")) {
718
+ const baseVal = parseSNBTCompoundString(val, { ...options, isInnerStack: true });
719
+ if ("errors" in baseVal) {
720
+ baseVal.errors.forEach((err) => {
721
+ err.cause.stack.push({
722
+ input: originalInput,
723
+ positionInInput: originalInput.indexOf(input) + pos + originalVal.indexOf(val),
724
+ key,
725
+ function: "extractSNBT",
726
+ });
727
+ err.cause.position += originalInput.indexOf(input) + pos + originalVal.indexOf(val);
728
+ });
729
+ errors.push(...baseVal.errors);
730
+ }
731
+ return "errors" in baseVal ? baseVal.value : baseVal;
732
+ }
733
+ if (val.startsWith("[") && val.endsWith("]")) {
734
+ const baseVal = parseSNBTPrimitive(val, { ...options, isInnerStack: true });
735
+ if ("errors" in baseVal) {
736
+ baseVal.errors.forEach((err) => {
737
+ err.cause.stack.push({
738
+ input: originalInput,
739
+ positionInInput: originalInput.indexOf(input) + pos + originalVal.indexOf(val),
740
+ key,
741
+ function: "extractSNBT",
742
+ });
743
+ err.cause.position += originalInput.indexOf(input) + pos + originalVal.indexOf(val);
744
+ });
745
+ errors.push(...baseVal.errors);
746
+ }
747
+ return "errors" in baseVal ? baseVal.value : baseVal;
748
+ }
749
+ const baseVal = parseSNBTPrimitive(val, { ...options, isInnerStack: true });
750
+ if ("errors" in baseVal) {
751
+ baseVal.errors.forEach((err) => {
752
+ err.cause.stack.push({
753
+ input: originalInput,
754
+ positionInInput: originalInput.indexOf(input) + pos + originalVal.indexOf(val),
755
+ key,
756
+ function: "extractSNBT",
757
+ });
758
+ err.cause.position += originalInput.indexOf(input) + pos + originalVal.indexOf(val);
759
+ });
760
+ errors.push(...baseVal.errors);
761
+ }
762
+ return "errors" in baseVal ? baseVal.value : baseVal;
763
+ }
764
+ let readingKey = true;
765
+ for (let i = 0; i < input.length; i++) {
766
+ if (depth < 0)
767
+ break;
768
+ const c = input[i];
769
+ if (c === '"' || c === "'") {
770
+ if (inString === c)
771
+ inString = null;
772
+ else if (!inString)
773
+ inString = c;
774
+ }
775
+ if (!inString) {
776
+ if (c === ":" && readingKey) {
777
+ readingKey = false;
778
+ continue;
779
+ }
780
+ else if (c === "," && depth === 0) {
781
+ commitPair();
782
+ readingKey = true;
783
+ continue;
784
+ }
785
+ else if (c === "{" || c === "[") {
786
+ depth++;
787
+ }
788
+ else if (c === "}" || c === "]") {
789
+ depth--;
790
+ if (depth === -1) {
791
+ commitPair();
792
+ readingKey = true;
793
+ continue;
794
+ }
795
+ if ((options.stopAtNegativeDepth ?? true) && depth < 0) {
796
+ i++;
797
+ break;
798
+ }
799
+ }
800
+ }
801
+ if (readingKey)
802
+ currentKey += c;
803
+ else {
804
+ currentValue += c;
805
+ if (currentValuePos === -1 && depth === 0)
806
+ currentValuePos = i;
807
+ }
808
+ }
809
+ commitPair();
810
+ const val = NBT.comp(Object.fromEntries(Object.entries(result)
811
+ .map(([k, v]) => [
812
+ (() => {
813
+ try {
814
+ return parseFormattedKey(k.trim());
815
+ }
816
+ catch {
817
+ const error = new SNBTParseError("Invalid SNBT key: " + k.trim(), {
818
+ cause: {
819
+ position: k.indexOf(k.trim()),
820
+ stack: [
821
+ {
822
+ function: "parseSNBTCompoundString",
823
+ input: k,
824
+ positionInInput: k.indexOf(k.trim()),
825
+ key: k.trim(),
826
+ error: {
827
+ type: "InvalidSNBTKey",
828
+ raw: k.trim(),
829
+ },
830
+ },
831
+ ],
832
+ },
833
+ });
834
+ if (options.keepGoingAfterError)
835
+ errors.push(error);
836
+ else
837
+ throw error;
838
+ return undefined;
839
+ }
840
+ })(),
841
+ v,
842
+ ])
843
+ .filter((v) => v[0] !== undefined)));
844
+ return options.keepGoingAfterError ? { value: val, errors } : val;
845
+ }
846
+ export function extractSNBT(input, options = {}) {
847
+ const errors = [];
848
+ const originalInput = input;
849
+ input = input.trim();
850
+ let resultType = "compound";
851
+ if (input.startsWith("{")) {
852
+ input = input.slice(1);
853
+ resultType = "compound";
854
+ }
855
+ else if (input.startsWith("[")) {
856
+ input = input.slice(1);
857
+ resultType = "list";
858
+ }
859
+ const result = {};
860
+ const listResult = [];
861
+ let depth = 0;
862
+ let currentKey = "";
863
+ let currentValue = "";
864
+ let currentValuePos = -1;
865
+ let inString = null;
866
+ function commitPair() {
867
+ if (resultType === "compound") {
868
+ if (!currentKey)
869
+ return;
870
+ result[currentKey.trim()] = parseValue(currentValue.trim(), currentKey, currentValuePos);
871
+ currentKey = "";
872
+ currentValue = "";
873
+ currentValuePos = -1;
874
+ }
875
+ else if (resultType === "list") {
876
+ listResult.push([currentValue.trim(), currentValuePos + currentValue.indexOf(currentValue.trim())]);
877
+ currentValue = "";
878
+ currentValuePos = -1;
879
+ }
880
+ }
881
+ function parseValue(val, key, pos) {
882
+ const originalVal = val;
883
+ val = val.trim();
884
+ if (!val)
885
+ return NBT.comp({});
886
+ if (val.startsWith("{") && val.endsWith("}")) {
887
+ const baseVal = parseSNBTCompoundString(val, { ...options, isInnerStack: true });
888
+ if ("errors" in baseVal) {
889
+ baseVal.errors.forEach((err) => {
890
+ err.cause.stack.push({
891
+ input: originalInput,
892
+ positionInInput: originalInput.indexOf(input) + pos + originalVal.indexOf(val),
893
+ key,
894
+ function: "extractSNBT",
895
+ });
896
+ err.cause.position += originalInput.indexOf(input) + pos + originalVal.indexOf(val);
897
+ });
898
+ errors.push(...baseVal.errors);
899
+ }
900
+ return "errors" in baseVal ? baseVal.value : baseVal;
901
+ }
902
+ if (val.startsWith("[") && val.endsWith("]")) {
903
+ const baseVal = parseSNBTPrimitive(val, { ...options, isInnerStack: true });
904
+ if ("errors" in baseVal) {
905
+ baseVal.errors.forEach((err) => {
906
+ err.cause.stack.push({
907
+ input: originalInput,
908
+ positionInInput: originalInput.indexOf(input) + pos + originalVal.indexOf(val),
909
+ key,
910
+ function: "extractSNBT",
911
+ });
912
+ err.cause.position += originalInput.indexOf(input) + pos + originalVal.indexOf(val);
913
+ });
914
+ errors.push(...baseVal.errors);
915
+ }
916
+ return "errors" in baseVal ? baseVal.value : baseVal;
917
+ }
918
+ const baseVal = parseSNBTPrimitive(val, { ...options, isInnerStack: true });
919
+ if ("errors" in baseVal) {
920
+ baseVal.errors.forEach((err) => {
921
+ err.cause.stack.push({
922
+ input: originalInput,
923
+ positionInInput: originalInput.indexOf(input) + pos + originalVal.indexOf(val),
924
+ key,
925
+ function: "extractSNBT",
926
+ });
927
+ err.cause.position += originalInput.indexOf(input) + pos + originalVal.indexOf(val);
928
+ });
929
+ errors.push(...baseVal.errors);
930
+ }
931
+ return "errors" in baseVal ? baseVal.value : baseVal;
932
+ }
933
+ let readingKey = resultType === "list" ? false : true;
934
+ let bracketTypeStack = [resultType];
935
+ let i = 0;
936
+ for (i; i < input.length; i++) {
937
+ const c = input[i];
938
+ if (c === '"' || c === "'") {
939
+ if (inString === c)
940
+ inString = null;
941
+ else if (!inString)
942
+ inString = c;
943
+ }
944
+ if (!inString) {
945
+ if (c === ":" && readingKey) {
946
+ readingKey = false;
947
+ continue;
948
+ }
949
+ else if (c === "," && depth === 0) {
950
+ resultType !== "list" || currentValue.trim() !== "" ? commitPair() : ((currentKey = ""), (currentValue = ""), (currentValuePos = -1));
951
+ if (resultType === "compound")
952
+ readingKey = true;
953
+ continue;
954
+ }
955
+ else if (c === "{" || c === "[") {
956
+ bracketTypeStack.push(c === "{" ? "compound" : "list");
957
+ depth++;
958
+ }
959
+ else if (c === "}" || c === "]") {
960
+ bracketTypeStack.pop();
961
+ depth--;
962
+ if ((options.stopAtNegativeDepth ?? true) && depth < 0) {
963
+ i++;
964
+ break;
965
+ }
966
+ }
967
+ }
968
+ if (readingKey)
969
+ currentKey += c;
970
+ else {
971
+ currentValue += c;
972
+ if (currentValuePos === -1 && depth === 0)
973
+ currentValuePos = i;
974
+ }
975
+ }
976
+ resultType !== "list" || currentValue.trim() !== "" ? commitPair() : ((currentKey = ""), (currentValue = ""), (currentValuePos = -1));
977
+ if (resultType === "list") {
978
+ const baseVal = parseList(listResult.map(([v]) => v), { ...options, isInnerStack: true });
979
+ if ("errors" in baseVal) {
980
+ baseVal.errors.forEach((err) => {
981
+ const lastStackItem = err.cause.stack.at(-1);
982
+ // console.log(listResult, lastStackItem, lastStackItem.inputItemIndex, err);
983
+ const baseOffset = listResult[lastStackItem.inputItemIndex][1];
984
+ err.cause.stack.push({
985
+ input: originalInput,
986
+ positionInInput: originalInput.indexOf(input) + baseOffset,
987
+ function: "extractSNBT",
988
+ });
989
+ err.cause.position += originalInput.indexOf(input) + baseOffset;
990
+ });
991
+ errors.push(...baseVal.errors);
992
+ }
993
+ if (!options.isInnerStack) {
994
+ errors.forEach((err) => {
995
+ err.isResolved = true;
996
+ err.originalInput = originalInput;
997
+ });
998
+ }
999
+ return {
1000
+ value: "errors" in baseVal ? baseVal.value : baseVal,
1001
+ remaining: originalInput.slice(i + originalInput.indexOf(input)),
1002
+ startPos: originalInput.indexOf(input),
1003
+ endPos: i + originalInput.indexOf(input),
1004
+ ...(options.keepGoingAfterError ? { errors } : undefined),
1005
+ };
1006
+ }
1007
+ if (!options.isInnerStack) {
1008
+ errors.forEach((err) => {
1009
+ err.isResolved = true;
1010
+ err.originalInput = originalInput;
1011
+ });
1012
+ }
1013
+ return {
1014
+ value: NBT.comp(Object.fromEntries(Object.entries(result)
1015
+ .map(([k, v]) => [
1016
+ (() => {
1017
+ try {
1018
+ return parseFormattedKey(k.trim());
1019
+ }
1020
+ catch {
1021
+ const error = new SNBTParseError("Invalid SNBT key: " + k.trim(), {
1022
+ cause: {
1023
+ position: k.indexOf(k.trim()),
1024
+ stack: [
1025
+ {
1026
+ function: "parseSNBTCompoundString",
1027
+ input: k,
1028
+ positionInInput: k.indexOf(k.trim()),
1029
+ key: k.trim(),
1030
+ error: {
1031
+ type: "InvalidSNBTKey",
1032
+ raw: k.trim(),
1033
+ },
1034
+ },
1035
+ ],
1036
+ },
1037
+ });
1038
+ if (options.keepGoingAfterError)
1039
+ errors.push(error);
1040
+ else
1041
+ throw error;
1042
+ return undefined;
1043
+ }
1044
+ })(),
1045
+ v,
1046
+ ])
1047
+ .filter((v) => v[0] !== undefined))),
1048
+ remaining: originalInput.slice(i + originalInput.indexOf(input)),
1049
+ startPos: originalInput.indexOf(input),
1050
+ endPos: i + originalInput.indexOf(input),
1051
+ ...(options.keepGoingAfterError ? { errors } : undefined),
1052
+ };
1053
+ }
1054
+ // console.log(
1055
+ // parseSNBTCompoundString(`{
1056
+ // id: SculkCatalyst,
1057
+ // isMovable: 1b,
1058
+ // x: -345,
1059
+ // y: -40,
1060
+ // z: 449
1061
+ // }`)
1062
+ // );
1063
+ // console.log(
1064
+ // prismarineToSNBT(
1065
+ // parseSNBTCompoundString(`{
1066
+ // "id": SculkCatalyst,
1067
+ // "isMovable": 1b,
1068
+ // "x": -345,
1069
+ // "y": -40,
1070
+ // "z": 449
1071
+ // }`)
1072
+ // )
1073
+ // );
1074
+ // console.log(
1075
+ // snbtToPrismarine(
1076
+ // prismarineToSNBT(
1077
+ // parseSNBTCompoundString(`{
1078
+ // "id": SculkCatalyst,
1079
+ // "isMovable": 1b,
1080
+ // "x": -345,
1081
+ // "y": -40,
1082
+ // "z": 449
1083
+ // }`)
1084
+ // )
1085
+ // )
1086
+ // );
1087
+ // console.log(
1088
+ // prettyPrintSNBT(
1089
+ // prismarineToSNBT(
1090
+ // parseSNBTCompoundString(`{
1091
+ // "id": SculkCatalyst,
1092
+ // "isMovable": 1b,
1093
+ // "x": -345,
1094
+ // "y": -40,
1095
+ // "z": 449
1096
+ // }`)
1097
+ // ),
1098
+ // { indent: 4, inlineArrays: false }
1099
+ // )
1100
+ // );
1101
+ /**
1102
+ * Converts SNBT-like JSON into Prismarine-NBT JSON.
1103
+ *
1104
+ * @param snbt The SNBT-like JSON to convert.
1105
+ * @returns The Prismarine-NBT JSON.
1106
+ */
1107
+ export function snbtToPrismarine(snbt) {
1108
+ const value = {};
1109
+ for (const [key, raw] of Object.entries(snbt)) {
1110
+ if (Array.isArray(raw)) {
1111
+ if (raw.length > 0 && typeof raw[0] === "object" && !Array.isArray(raw[0])) {
1112
+ value[key] = {
1113
+ type: "list",
1114
+ value: {
1115
+ type: "compound",
1116
+ value: raw.map((entry) => {
1117
+ const inner = {};
1118
+ for (const [k, v] of Object.entries(entry)) {
1119
+ inner[k] = snbtToPrismarine({ [k]: v });
1120
+ }
1121
+ return inner;
1122
+ }),
1123
+ },
1124
+ };
1125
+ }
1126
+ else {
1127
+ const parsed = raw.map((v) => parseSNBTPrimitive(v));
1128
+ const types = new Set(parsed.map((p) => p.type));
1129
+ if (types.size === 1) {
1130
+ const type = [...types][0];
1131
+ switch (type) {
1132
+ case "byte":
1133
+ value[key] = NBT.byteArray(parsed.map((p) => p.value));
1134
+ continue;
1135
+ case "short":
1136
+ value[key] = NBT.shortArray(parsed.map((p) => p.value));
1137
+ continue;
1138
+ case "int":
1139
+ value[key] = NBT.intArray(parsed.map((p) => p.value));
1140
+ continue;
1141
+ case "long":
1142
+ value[key] = NBT.longArray(parsed.map((p) => p.value));
1143
+ continue;
1144
+ }
1145
+ }
1146
+ value[key] = {
1147
+ type: "list",
1148
+ value: {
1149
+ type: parsed[0]?.type ?? "int",
1150
+ value: parsed.map((p) => p.value),
1151
+ },
1152
+ };
1153
+ }
1154
+ }
1155
+ else if (typeof raw === "object" && raw !== null) {
1156
+ if ("__typed" in raw && "value" in raw) {
1157
+ value[key] = parseTypedArray(raw.__typed, raw.value.map((v) => (typeof v === "string" ? v : String(v))));
1158
+ }
1159
+ else {
1160
+ value[key] = snbtToPrismarine(raw);
1161
+ }
1162
+ }
1163
+ else {
1164
+ value[key] = parseSNBTPrimitive(raw);
1165
+ }
1166
+ }
1167
+ return NBT.comp(value);
1168
+ }
1169
+ function formatString(s) {
1170
+ const unquotedPattern = /^[A-Za-z_][A-Za-z0-9_\-\+\.]*$/;
1171
+ if (unquotedPattern.test(s))
1172
+ return s;
1173
+ let quote = '"';
1174
+ if (!s.includes("'") && s.includes('"')) {
1175
+ quote = "'";
1176
+ }
1177
+ const escaped = s
1178
+ .replace(/\\/g, "\\\\")
1179
+ .replace(new RegExp(quote, "g"), "\\" + quote)
1180
+ .replace(/\n/g, "\\n")
1181
+ .replace(/\r/g, "\\r")
1182
+ .replace(/\t/g, "\\t")
1183
+ .replace(/\x08/g, "\\b")
1184
+ .replace(/\f/g, "\\f");
1185
+ return `${quote}${escaped}${quote}`;
1186
+ }
1187
+ function formatKey(key) {
1188
+ const unquotedPattern = /^[A-Za-z0-9_\-\+\.]+$/;
1189
+ if (unquotedPattern.test(key))
1190
+ return key;
1191
+ return formatString(key);
1192
+ }
1193
+ function parseFormattedString(string) {
1194
+ return string.startsWith('"') && string.endsWith('"')
1195
+ ? JSON.parse(string)
1196
+ : string.startsWith("'") && string.endsWith("'")
1197
+ ? JSON.parse('"' + string.replaceAll('"', '\\"').slice(1, -1) + '"')
1198
+ : /^[A-Za-z_][A-Za-z0-9_\-\+\.]*$/.test(string)
1199
+ ? string
1200
+ : (() => {
1201
+ throw new SyntaxError("Invalid SNBT string: " + string);
1202
+ })();
1203
+ }
1204
+ function parseFormattedKey(key) {
1205
+ return /^[A-Za-z0-9_\-\+\.]+$/.test(key)
1206
+ ? key
1207
+ : key.startsWith('"') && key.endsWith('"')
1208
+ ? JSON.parse(key)
1209
+ : key.startsWith("'") && key.endsWith("'")
1210
+ ? JSON.parse('"' + key.replaceAll('"', '\\"').slice(1, -1) + '"')
1211
+ : /^[A-Za-z_][A-Za-z0-9_\-\+\.]*$/.test(key)
1212
+ ? key
1213
+ : (() => {
1214
+ throw new SyntaxError("Invalid SNBT key: " + key);
1215
+ })();
1216
+ }
1217
+ export var SNBTLikeJSONTagType;
1218
+ (function (SNBTLikeJSONTagType) {
1219
+ SNBTLikeJSONTagType["Byte"] = "byte";
1220
+ SNBTLikeJSONTagType["Short"] = "short";
1221
+ SNBTLikeJSONTagType["Int"] = "int";
1222
+ SNBTLikeJSONTagType["Long"] = "long";
1223
+ SNBTLikeJSONTagType["Float"] = "float";
1224
+ SNBTLikeJSONTagType["Double"] = "double";
1225
+ SNBTLikeJSONTagType["String"] = "string";
1226
+ SNBTLikeJSONTagType["List"] = "list";
1227
+ SNBTLikeJSONTagType["Compound"] = "compound";
1228
+ SNBTLikeJSONTagType["ByteArray"] = "byteArray";
1229
+ SNBTLikeJSONTagType["ShortArray"] = "shortArray";
1230
+ SNBTLikeJSONTagType["IntArray"] = "intArray";
1231
+ SNBTLikeJSONTagType["LongArray"] = "longArray";
1232
+ })(SNBTLikeJSONTagType || (SNBTLikeJSONTagType = {}));
1233
+ /**
1234
+ * Converts Prismarine-NBT JSON to SNBT-like JSON.
1235
+ *
1236
+ * @param nbt The Prismarine-NBT JSON to convert.
1237
+ * @returns The resulting SNBT-like JSON.
1238
+ */
1239
+ export function prismarineToSNBT(nbt) {
1240
+ if (nbt.type === "compound") {
1241
+ const obj = {};
1242
+ for (const [key, val] of Object.entries(nbt.value)) {
1243
+ obj[key] = prismarineToSNBT(val);
1244
+ }
1245
+ return obj;
1246
+ }
1247
+ if (nbt.type === "list") {
1248
+ if (nbt.value.type === "compound") {
1249
+ return nbt.value.value.map((entry) => {
1250
+ const obj = {};
1251
+ for (const [k, v] of Object.entries(entry)) {
1252
+ obj[k] = prismarineToSNBT(v);
1253
+ }
1254
+ return obj;
1255
+ });
1256
+ }
1257
+ else {
1258
+ return nbt.value.value.map((v) => prismarineToSNBT({ type: nbt.value.type, value: v }));
1259
+ }
1260
+ }
1261
+ switch (nbt.type) {
1262
+ case "byteArray":
1263
+ return { __typed: "B", value: nbt.value.map((v) => `${v}b`) };
1264
+ case "shortArray":
1265
+ return { __typed: "S", value: nbt.value.map((v) => `${v}s`) };
1266
+ case "intArray":
1267
+ return { __typed: "I", value: nbt.value.map((v) => `${v}`) };
1268
+ case "longArray":
1269
+ return { __typed: "L", value: nbt.value.map((v) => `${toLong(v)}L`) };
1270
+ }
1271
+ switch (nbt.type) {
1272
+ case "byte":
1273
+ return `${nbt.value}b`;
1274
+ case "short":
1275
+ return `${nbt.value}s`;
1276
+ case "int":
1277
+ return nbt.value;
1278
+ case "long":
1279
+ return `${toLong(nbt.value).toString()}L`;
1280
+ case "float":
1281
+ return `${nbt.value}f`;
1282
+ case "double":
1283
+ return `${nbt.value}d`;
1284
+ case "string":
1285
+ return formatString(nbt.value);
1286
+ }
1287
+ return nbt.value;
1288
+ }
1289
+ /**
1290
+ * Converts a long in bigint format to tuple form.
1291
+ *
1292
+ * @param longVal The long as a bigint.
1293
+ * @returns The long as a tuple.
1294
+ */
1295
+ export function toLongParts(longVal) {
1296
+ const low = Number(longVal & 0xffffffffn) | 0;
1297
+ const high = Number((longVal >> 32n) & 0xffffffffn) | 0;
1298
+ return [high, low];
1299
+ }
1300
+ /**
1301
+ * Converts a long as a string to a tuple.
1302
+ *
1303
+ * @param literal A long as a string.
1304
+ * @returns The long as a tuple.
1305
+ */
1306
+ export function parseLong(literal) {
1307
+ const numStr = literal.slice(0, -1);
1308
+ const value = BigInt(numStr);
1309
+ return toLongParts(value);
1310
+ }
1311
+ /**
1312
+ * Converts a long in tuple form to bigint form.
1313
+ *
1314
+ * @param param0 The long as a tuple.
1315
+ * @returns The long as a bigint.
1316
+ */
1317
+ export function toLong([high, low]) {
1318
+ const lo = BigInt(low) & BigInt(0xffffffff);
1319
+ const hi = BigInt(high);
1320
+ return (hi << 32n) | lo;
1321
+ }
1322
+ /**
1323
+ * Pretty-prints SNBT.
1324
+ *
1325
+ * @param obj The SNBT-like JSON to pretty-print.
1326
+ * @param options The options to use.
1327
+ * @returns The pretty-printed SNBT.
1328
+ *
1329
+ * @example
1330
+ * ```typescript
1331
+ * prettyPrintSNBT(prismarineToSNBT({
1332
+ * type: "compound",
1333
+ * value: {
1334
+ * enabled: {
1335
+ * type: "byte",
1336
+ * value: 1
1337
+ * }
1338
+ * }
1339
+ * }))
1340
+ * ```
1341
+ */
1342
+ export function prettyPrintSNBT(obj, options = {}) {
1343
+ const { indent = 2, inlineArrays = true, maxInlineLength = 40 } = options;
1344
+ function format(value, level) {
1345
+ const pad = " ".repeat(level * indent);
1346
+ if (value && typeof value === "object" && value.__typed) {
1347
+ const type = value.__typed;
1348
+ const inner = value.value.join(", ");
1349
+ return `[${type}; ${inner}]`;
1350
+ }
1351
+ if (Array.isArray(value)) {
1352
+ if (value.length === 0)
1353
+ return "[]";
1354
+ const inline = `[${value.map((v) => format(v, 0)).join(", ")}]`;
1355
+ if (inlineArrays && inline.length <= maxInlineLength && !value.some((v) => typeof v === "object")) {
1356
+ return inline;
1357
+ }
1358
+ return "[\n" + value.map((v) => pad + " ".repeat(indent) + format(v, level + 1)).join(",\n") + "\n" + pad + "]";
1359
+ }
1360
+ if (typeof value === "object" && value !== null) {
1361
+ const entries = Object.entries(value);
1362
+ if (entries.length === 0)
1363
+ return "{}";
1364
+ return ("{\n" +
1365
+ entries.map(([k, v]) => pad + " ".repeat(indent) + `${formatKey(k)}: ${format(v, level + 1)}`).join(",\n") +
1366
+ "\n" +
1367
+ pad +
1368
+ "}");
1369
+ }
1370
+ return String(value);
1371
+ }
1372
+ return format(obj, 0);
1373
+ }
1374
+ //# sourceMappingURL=SNBTUtils.js.map