@k67/kaitai-struct-ts 0.2.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/dist/index.js ADDED
@@ -0,0 +1,1405 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ BUILTIN_TYPES: () => BUILTIN_TYPES,
24
+ Context: () => Context,
25
+ EOFError: () => EOFError,
26
+ KaitaiError: () => KaitaiError,
27
+ KaitaiStream: () => KaitaiStream,
28
+ KsyParser: () => KsyParser,
29
+ NotImplementedError: () => NotImplementedError,
30
+ ParseError: () => ParseError,
31
+ TypeInterpreter: () => TypeInterpreter,
32
+ ValidationError: () => ValidationError,
33
+ getBaseType: () => getBaseType,
34
+ getTypeEndianness: () => getTypeEndianness,
35
+ isBuiltinType: () => isBuiltinType,
36
+ isFloatType: () => isFloatType,
37
+ isIntegerType: () => isIntegerType,
38
+ isStringType: () => isStringType,
39
+ parse: () => parse
40
+ });
41
+ module.exports = __toCommonJS(index_exports);
42
+
43
+ // src/utils/errors.ts
44
+ var KaitaiError = class _KaitaiError extends Error {
45
+ constructor(message, position) {
46
+ super(message);
47
+ this.position = position;
48
+ this.name = "KaitaiError";
49
+ Object.setPrototypeOf(this, _KaitaiError.prototype);
50
+ }
51
+ };
52
+ var ValidationError = class _ValidationError extends KaitaiError {
53
+ constructor(message, position) {
54
+ super(message, position);
55
+ this.name = "ValidationError";
56
+ Object.setPrototypeOf(this, _ValidationError.prototype);
57
+ }
58
+ };
59
+ var ParseError = class _ParseError extends KaitaiError {
60
+ constructor(message, position) {
61
+ super(message, position);
62
+ this.name = "ParseError";
63
+ Object.setPrototypeOf(this, _ParseError.prototype);
64
+ }
65
+ };
66
+ var EOFError = class _EOFError extends KaitaiError {
67
+ constructor(message = "Unexpected end of stream", position) {
68
+ super(message, position);
69
+ this.name = "EOFError";
70
+ Object.setPrototypeOf(this, _EOFError.prototype);
71
+ }
72
+ };
73
+ var NotImplementedError = class _NotImplementedError extends KaitaiError {
74
+ constructor(feature) {
75
+ super(`Feature not yet implemented: ${feature}`);
76
+ this.name = "NotImplementedError";
77
+ Object.setPrototypeOf(this, _NotImplementedError.prototype);
78
+ }
79
+ };
80
+
81
+ // src/utils/encoding.ts
82
+ function decodeString(bytes, encoding) {
83
+ const normalizedEncoding = encoding.toLowerCase().replace(/[-_]/g, "");
84
+ switch (normalizedEncoding) {
85
+ case "utf8":
86
+ case "utf-8":
87
+ return decodeUtf8(bytes);
88
+ case "ascii":
89
+ case "usascii":
90
+ return decodeAscii(bytes);
91
+ case "utf16":
92
+ case "utf16le":
93
+ case "utf-16le":
94
+ return decodeUtf16Le(bytes);
95
+ case "utf16be":
96
+ case "utf-16be":
97
+ return decodeUtf16Be(bytes);
98
+ case "latin1":
99
+ case "iso88591":
100
+ case "iso-8859-1":
101
+ return decodeLatin1(bytes);
102
+ default:
103
+ if (typeof TextDecoder !== "undefined") {
104
+ try {
105
+ return new TextDecoder(encoding).decode(bytes);
106
+ } catch {
107
+ throw new Error(`Unsupported encoding: ${encoding}`);
108
+ }
109
+ }
110
+ throw new Error(`Unsupported encoding: ${encoding}`);
111
+ }
112
+ }
113
+ function decodeUtf8(bytes) {
114
+ if (typeof TextDecoder !== "undefined") {
115
+ return new TextDecoder("utf-8").decode(bytes);
116
+ }
117
+ let result = "";
118
+ let i = 0;
119
+ while (i < bytes.length) {
120
+ const byte1 = bytes[i++];
121
+ if (byte1 < 128) {
122
+ result += String.fromCharCode(byte1);
123
+ } else if (byte1 < 224) {
124
+ const byte2 = bytes[i++];
125
+ result += String.fromCharCode((byte1 & 31) << 6 | byte2 & 63);
126
+ } else if (byte1 < 240) {
127
+ const byte2 = bytes[i++];
128
+ const byte3 = bytes[i++];
129
+ result += String.fromCharCode(
130
+ (byte1 & 15) << 12 | (byte2 & 63) << 6 | byte3 & 63
131
+ );
132
+ } else {
133
+ const byte2 = bytes[i++];
134
+ const byte3 = bytes[i++];
135
+ const byte4 = bytes[i++];
136
+ let codePoint = (byte1 & 7) << 18 | (byte2 & 63) << 12 | (byte3 & 63) << 6 | byte4 & 63;
137
+ codePoint -= 65536;
138
+ result += String.fromCharCode(
139
+ 55296 + (codePoint >> 10),
140
+ 56320 + (codePoint & 1023)
141
+ );
142
+ }
143
+ }
144
+ return result;
145
+ }
146
+ function decodeAscii(bytes) {
147
+ let result = "";
148
+ for (let i = 0; i < bytes.length; i++) {
149
+ result += String.fromCharCode(bytes[i] & 127);
150
+ }
151
+ return result;
152
+ }
153
+ function decodeLatin1(bytes) {
154
+ let result = "";
155
+ for (let i = 0; i < bytes.length; i++) {
156
+ result += String.fromCharCode(bytes[i]);
157
+ }
158
+ return result;
159
+ }
160
+ function decodeUtf16Le(bytes) {
161
+ if (typeof TextDecoder !== "undefined") {
162
+ return new TextDecoder("utf-16le").decode(bytes);
163
+ }
164
+ let result = "";
165
+ for (let i = 0; i < bytes.length; i += 2) {
166
+ const charCode = bytes[i] | bytes[i + 1] << 8;
167
+ result += String.fromCharCode(charCode);
168
+ }
169
+ return result;
170
+ }
171
+ function decodeUtf16Be(bytes) {
172
+ if (typeof TextDecoder !== "undefined") {
173
+ return new TextDecoder("utf-16be").decode(bytes);
174
+ }
175
+ let result = "";
176
+ for (let i = 0; i < bytes.length; i += 2) {
177
+ const charCode = bytes[i] << 8 | bytes[i + 1];
178
+ result += String.fromCharCode(charCode);
179
+ }
180
+ return result;
181
+ }
182
+
183
+ // src/stream/KaitaiStream.ts
184
+ var KaitaiStream = class _KaitaiStream {
185
+ /**
186
+ * Create a new KaitaiStream from a buffer
187
+ * @param buffer - ArrayBuffer or Uint8Array containing the binary data
188
+ */
189
+ constructor(buffer) {
190
+ this._pos = 0;
191
+ this._bits = 0;
192
+ this._bitsLeft = 0;
193
+ if (buffer instanceof ArrayBuffer) {
194
+ this.buffer = new Uint8Array(buffer);
195
+ this.view = new DataView(buffer);
196
+ } else {
197
+ this.buffer = buffer;
198
+ this.view = new DataView(
199
+ buffer.buffer,
200
+ buffer.byteOffset,
201
+ buffer.byteLength
202
+ );
203
+ }
204
+ }
205
+ /**
206
+ * Current position in the stream
207
+ */
208
+ get pos() {
209
+ return this._pos;
210
+ }
211
+ set pos(value) {
212
+ this._pos = value;
213
+ this._bitsLeft = 0;
214
+ }
215
+ /**
216
+ * Total size of the stream in bytes
217
+ */
218
+ get size() {
219
+ return this.buffer.length;
220
+ }
221
+ /**
222
+ * Check if we've reached the end of the stream
223
+ */
224
+ isEof() {
225
+ return this._pos >= this.buffer.length;
226
+ }
227
+ /**
228
+ * Seek to a specific position in the stream
229
+ * @param pos - Position to seek to
230
+ */
231
+ seek(pos) {
232
+ if (pos < 0 || pos > this.buffer.length) {
233
+ throw new Error(`Invalid seek position: ${pos}`);
234
+ }
235
+ this.pos = pos;
236
+ }
237
+ /**
238
+ * Ensure we have enough bytes available
239
+ * @param count - Number of bytes needed
240
+ */
241
+ ensureBytes(count) {
242
+ if (this._pos + count > this.buffer.length) {
243
+ throw new EOFError(
244
+ `Requested ${count} bytes at position ${this._pos}, but only ${this.buffer.length - this._pos} bytes available`,
245
+ this._pos
246
+ );
247
+ }
248
+ }
249
+ // ==================== Unsigned Integers ====================
250
+ /**
251
+ * Read 1-byte unsigned integer (0 to 255)
252
+ */
253
+ readU1() {
254
+ this.ensureBytes(1);
255
+ return this.buffer[this._pos++];
256
+ }
257
+ /**
258
+ * Read 2-byte unsigned integer, little-endian
259
+ */
260
+ readU2le() {
261
+ this.ensureBytes(2);
262
+ const value = this.view.getUint16(this._pos, true);
263
+ this._pos += 2;
264
+ return value;
265
+ }
266
+ /**
267
+ * Read 2-byte unsigned integer, big-endian
268
+ */
269
+ readU2be() {
270
+ this.ensureBytes(2);
271
+ const value = this.view.getUint16(this._pos, false);
272
+ this._pos += 2;
273
+ return value;
274
+ }
275
+ /**
276
+ * Read 4-byte unsigned integer, little-endian
277
+ */
278
+ readU4le() {
279
+ this.ensureBytes(4);
280
+ const value = this.view.getUint32(this._pos, true);
281
+ this._pos += 4;
282
+ return value;
283
+ }
284
+ /**
285
+ * Read 4-byte unsigned integer, big-endian
286
+ */
287
+ readU4be() {
288
+ this.ensureBytes(4);
289
+ const value = this.view.getUint32(this._pos, false);
290
+ this._pos += 4;
291
+ return value;
292
+ }
293
+ /**
294
+ * Read 8-byte unsigned integer, little-endian
295
+ * Returns BigInt for values > Number.MAX_SAFE_INTEGER
296
+ */
297
+ readU8le() {
298
+ this.ensureBytes(8);
299
+ const value = this.view.getBigUint64(this._pos, true);
300
+ this._pos += 8;
301
+ return value;
302
+ }
303
+ /**
304
+ * Read 8-byte unsigned integer, big-endian
305
+ * Returns BigInt for values > Number.MAX_SAFE_INTEGER
306
+ */
307
+ readU8be() {
308
+ this.ensureBytes(8);
309
+ const value = this.view.getBigUint64(this._pos, false);
310
+ this._pos += 8;
311
+ return value;
312
+ }
313
+ // ==================== Signed Integers ====================
314
+ /**
315
+ * Read 1-byte signed integer (-128 to 127)
316
+ */
317
+ readS1() {
318
+ this.ensureBytes(1);
319
+ return this.view.getInt8(this._pos++);
320
+ }
321
+ /**
322
+ * Read 2-byte signed integer, little-endian
323
+ */
324
+ readS2le() {
325
+ this.ensureBytes(2);
326
+ const value = this.view.getInt16(this._pos, true);
327
+ this._pos += 2;
328
+ return value;
329
+ }
330
+ /**
331
+ * Read 2-byte signed integer, big-endian
332
+ */
333
+ readS2be() {
334
+ this.ensureBytes(2);
335
+ const value = this.view.getInt16(this._pos, false);
336
+ this._pos += 2;
337
+ return value;
338
+ }
339
+ /**
340
+ * Read 4-byte signed integer, little-endian
341
+ */
342
+ readS4le() {
343
+ this.ensureBytes(4);
344
+ const value = this.view.getInt32(this._pos, true);
345
+ this._pos += 4;
346
+ return value;
347
+ }
348
+ /**
349
+ * Read 4-byte signed integer, big-endian
350
+ */
351
+ readS4be() {
352
+ this.ensureBytes(4);
353
+ const value = this.view.getInt32(this._pos, false);
354
+ this._pos += 4;
355
+ return value;
356
+ }
357
+ /**
358
+ * Read 8-byte signed integer, little-endian
359
+ * Returns BigInt for values outside Number.MAX_SAFE_INTEGER range
360
+ */
361
+ readS8le() {
362
+ this.ensureBytes(8);
363
+ const value = this.view.getBigInt64(this._pos, true);
364
+ this._pos += 8;
365
+ return value;
366
+ }
367
+ /**
368
+ * Read 8-byte signed integer, big-endian
369
+ * Returns BigInt for values outside Number.MAX_SAFE_INTEGER range
370
+ */
371
+ readS8be() {
372
+ this.ensureBytes(8);
373
+ const value = this.view.getBigInt64(this._pos, false);
374
+ this._pos += 8;
375
+ return value;
376
+ }
377
+ // ==================== Floating Point ====================
378
+ /**
379
+ * Read 4-byte IEEE 754 single-precision float, little-endian
380
+ */
381
+ readF4le() {
382
+ this.ensureBytes(4);
383
+ const value = this.view.getFloat32(this._pos, true);
384
+ this._pos += 4;
385
+ return value;
386
+ }
387
+ /**
388
+ * Read 4-byte IEEE 754 single-precision float, big-endian
389
+ */
390
+ readF4be() {
391
+ this.ensureBytes(4);
392
+ const value = this.view.getFloat32(this._pos, false);
393
+ this._pos += 4;
394
+ return value;
395
+ }
396
+ /**
397
+ * Read 8-byte IEEE 754 double-precision float, little-endian
398
+ */
399
+ readF8le() {
400
+ this.ensureBytes(8);
401
+ const value = this.view.getFloat64(this._pos, true);
402
+ this._pos += 8;
403
+ return value;
404
+ }
405
+ /**
406
+ * Read 8-byte IEEE 754 double-precision float, big-endian
407
+ */
408
+ readF8be() {
409
+ this.ensureBytes(8);
410
+ const value = this.view.getFloat64(this._pos, false);
411
+ this._pos += 8;
412
+ return value;
413
+ }
414
+ // ==================== Byte Arrays ====================
415
+ /**
416
+ * Read a fixed number of bytes
417
+ * @param length - Number of bytes to read
418
+ */
419
+ readBytes(length) {
420
+ this.ensureBytes(length);
421
+ const bytes = this.buffer.slice(this._pos, this._pos + length);
422
+ this._pos += length;
423
+ return bytes;
424
+ }
425
+ /**
426
+ * Read all remaining bytes until end of stream
427
+ */
428
+ readBytesFull() {
429
+ const bytes = this.buffer.slice(this._pos);
430
+ this._pos = this.buffer.length;
431
+ return bytes;
432
+ }
433
+ /**
434
+ * Read bytes until a terminator byte is found
435
+ * @param term - Terminator byte value
436
+ * @param include - Include terminator in result
437
+ * @param consume - Consume terminator from stream
438
+ * @param eosError - Throw error if EOS reached before terminator
439
+ */
440
+ readBytesterm(term, include = false, consume = true, eosError = true) {
441
+ const start = this._pos;
442
+ let end = start;
443
+ while (end < this.buffer.length && this.buffer[end] !== term) {
444
+ end++;
445
+ }
446
+ const foundTerm = end < this.buffer.length;
447
+ if (!foundTerm && eosError) {
448
+ throw new EOFError(
449
+ `Terminator byte ${term} not found before end of stream`,
450
+ this._pos
451
+ );
452
+ }
453
+ const includeEnd = include && foundTerm ? end + 1 : end;
454
+ const bytes = this.buffer.slice(start, includeEnd);
455
+ if (foundTerm && consume) {
456
+ this._pos = end + 1;
457
+ } else {
458
+ this._pos = end;
459
+ }
460
+ return bytes;
461
+ }
462
+ // ==================== Strings ====================
463
+ /**
464
+ * Read a fixed-length string
465
+ * @param length - Number of bytes to read
466
+ * @param encoding - Character encoding (default: UTF-8)
467
+ */
468
+ readStr(length, encoding = "UTF-8") {
469
+ const bytes = this.readBytes(length);
470
+ return decodeString(bytes, encoding);
471
+ }
472
+ /**
473
+ * Read a null-terminated string
474
+ * @param encoding - Character encoding (default: UTF-8)
475
+ * @param term - Terminator byte (default: 0)
476
+ * @param include - Include terminator in result
477
+ * @param consume - Consume terminator from stream
478
+ * @param eosError - Throw error if EOS reached before terminator
479
+ */
480
+ readStrz(encoding = "UTF-8", term = 0, include = false, consume = true, eosError = true) {
481
+ const bytes = this.readBytesterm(term, include, consume, eosError);
482
+ return decodeString(bytes, encoding);
483
+ }
484
+ // ==================== Bit-level Reading ====================
485
+ /**
486
+ * Align bit reading to byte boundary
487
+ */
488
+ alignToByte() {
489
+ this._bitsLeft = 0;
490
+ }
491
+ /**
492
+ * Read specified number of bits as unsigned integer (big-endian)
493
+ * @param n - Number of bits to read (1-64)
494
+ */
495
+ readBitsIntBe(n) {
496
+ if (n < 1 || n > 64) {
497
+ throw new Error(`Invalid bit count: ${n}. Must be between 1 and 64`);
498
+ }
499
+ let result = 0n;
500
+ for (let bitsNeeded = n; bitsNeeded > 0; ) {
501
+ if (this._bitsLeft === 0) {
502
+ this._bits = this.readU1();
503
+ this._bitsLeft = 8;
504
+ }
505
+ const bitsToRead = Math.min(bitsNeeded, this._bitsLeft);
506
+ const mask = (1 << bitsToRead) - 1;
507
+ const shift = this._bitsLeft - bitsToRead;
508
+ result = result << BigInt(bitsToRead) | BigInt(this._bits >> shift & mask);
509
+ this._bitsLeft -= bitsToRead;
510
+ bitsNeeded -= bitsToRead;
511
+ }
512
+ return result;
513
+ }
514
+ /**
515
+ * Read specified number of bits as unsigned integer (little-endian)
516
+ * @param n - Number of bits to read (1-64)
517
+ */
518
+ readBitsIntLe(n) {
519
+ if (n < 1 || n > 64) {
520
+ throw new Error(`Invalid bit count: ${n}. Must be between 1 and 64`);
521
+ }
522
+ let result = 0n;
523
+ let bitPos = 0;
524
+ for (let bitsNeeded = n; bitsNeeded > 0; ) {
525
+ if (this._bitsLeft === 0) {
526
+ this._bits = this.readU1();
527
+ this._bitsLeft = 8;
528
+ }
529
+ const bitsToRead = Math.min(bitsNeeded, this._bitsLeft);
530
+ const mask = (1 << bitsToRead) - 1;
531
+ result |= BigInt(this._bits & mask) << BigInt(bitPos);
532
+ this._bits >>= bitsToRead;
533
+ this._bitsLeft -= bitsToRead;
534
+ bitsNeeded -= bitsToRead;
535
+ bitPos += bitsToRead;
536
+ }
537
+ return result;
538
+ }
539
+ // ==================== Utility Methods ====================
540
+ /**
541
+ * Get the underlying buffer
542
+ */
543
+ getBuffer() {
544
+ return this.buffer;
545
+ }
546
+ /**
547
+ * Create a substream from current position with specified size
548
+ * @param size - Size of the substream in bytes
549
+ */
550
+ substream(size) {
551
+ this.ensureBytes(size);
552
+ const subBuffer = this.buffer.slice(this._pos, this._pos + size);
553
+ this._pos += size;
554
+ return new _KaitaiStream(subBuffer);
555
+ }
556
+ };
557
+
558
+ // src/parser/schema.ts
559
+ var BUILTIN_TYPES = [
560
+ // Unsigned integers
561
+ "u1",
562
+ "u2",
563
+ "u2le",
564
+ "u2be",
565
+ "u4",
566
+ "u4le",
567
+ "u4be",
568
+ "u8",
569
+ "u8le",
570
+ "u8be",
571
+ // Signed integers
572
+ "s1",
573
+ "s2",
574
+ "s2le",
575
+ "s2be",
576
+ "s4",
577
+ "s4le",
578
+ "s4be",
579
+ "s8",
580
+ "s8le",
581
+ "s8be",
582
+ // Floating point
583
+ "f4",
584
+ "f4le",
585
+ "f4be",
586
+ "f8",
587
+ "f8le",
588
+ "f8be",
589
+ // String
590
+ "str",
591
+ "strz"
592
+ ];
593
+ function isBuiltinType(type) {
594
+ return BUILTIN_TYPES.includes(type);
595
+ }
596
+ function getTypeEndianness(type) {
597
+ if (type.endsWith("le")) return "le";
598
+ if (type.endsWith("be")) return "be";
599
+ return void 0;
600
+ }
601
+ function getBaseType(type) {
602
+ if (type.endsWith("le") || type.endsWith("be")) {
603
+ return type.slice(0, -2);
604
+ }
605
+ return type;
606
+ }
607
+ function isIntegerType(type) {
608
+ const base = getBaseType(type);
609
+ return /^[us][1248]$/.test(base);
610
+ }
611
+ function isFloatType(type) {
612
+ const base = getBaseType(type);
613
+ return /^f[48]$/.test(base);
614
+ }
615
+ function isStringType(type) {
616
+ return type === "str" || type === "strz";
617
+ }
618
+
619
+ // src/parser/KsyParser.ts
620
+ var import_yaml = require("yaml");
621
+ var KsyParser = class {
622
+ /**
623
+ * Parse a .ksy YAML string into a typed schema object.
624
+ *
625
+ * @param yaml - YAML string containing the .ksy definition
626
+ * @param options - Parsing options
627
+ * @returns Parsed and validated schema
628
+ * @throws {ParseError} If YAML parsing fails
629
+ * @throws {ValidationError} If schema validation fails
630
+ */
631
+ parse(yaml, options = {}) {
632
+ const { validate = true, strict = false } = options;
633
+ let parsed;
634
+ try {
635
+ parsed = (0, import_yaml.parse)(yaml);
636
+ } catch (error) {
637
+ throw new ParseError(
638
+ `Failed to parse YAML: ${error instanceof Error ? error.message : String(error)}`
639
+ );
640
+ }
641
+ if (typeof parsed !== "object" || parsed === null) {
642
+ throw new ParseError("KSY file must contain an object");
643
+ }
644
+ const schema = parsed;
645
+ if (validate) {
646
+ const result = this.validate(schema, { strict });
647
+ if (!result.valid) {
648
+ const errorMessages = result.errors.map((e) => e.message).join("; ");
649
+ throw new ValidationError(
650
+ `Schema validation failed: ${errorMessages}`
651
+ );
652
+ }
653
+ if (result.warnings.length > 0 && !strict) {
654
+ console.warn(
655
+ "Schema validation warnings:",
656
+ result.warnings.map((w) => w.message)
657
+ );
658
+ }
659
+ }
660
+ return schema;
661
+ }
662
+ /**
663
+ * Validate a schema object.
664
+ *
665
+ * @param schema - Schema to validate
666
+ * @param options - Validation options
667
+ * @returns Validation result with errors and warnings
668
+ */
669
+ validate(schema, options = {}) {
670
+ const { strict = false, isNested = false } = options;
671
+ const errors = [];
672
+ const warnings = [];
673
+ if (!schema.meta && !isNested) {
674
+ errors.push({
675
+ message: 'Missing required "meta" section',
676
+ path: [],
677
+ code: "MISSING_META"
678
+ });
679
+ } else if (schema.meta) {
680
+ if (!schema.meta.id) {
681
+ errors.push({
682
+ message: 'Missing required "meta.id" field',
683
+ path: ["meta"],
684
+ code: "MISSING_META_ID"
685
+ });
686
+ } else if (typeof schema.meta.id !== "string") {
687
+ errors.push({
688
+ message: '"meta.id" must be a string',
689
+ path: ["meta", "id"],
690
+ code: "INVALID_META_ID_TYPE"
691
+ });
692
+ } else if (!/^[a-z][a-z0-9_]*$/.test(schema.meta.id)) {
693
+ warnings.push({
694
+ message: '"meta.id" should follow snake_case naming convention',
695
+ path: ["meta", "id"],
696
+ code: "META_ID_NAMING"
697
+ });
698
+ }
699
+ if (schema.meta.endian) {
700
+ if (typeof schema.meta.endian === "string" && schema.meta.endian !== "le" && schema.meta.endian !== "be") {
701
+ errors.push({
702
+ message: '"meta.endian" must be "le" or "be"',
703
+ path: ["meta", "endian"],
704
+ code: "INVALID_ENDIAN"
705
+ });
706
+ }
707
+ }
708
+ }
709
+ if (schema.seq) {
710
+ if (!Array.isArray(schema.seq)) {
711
+ errors.push({
712
+ message: '"seq" must be an array',
713
+ path: ["seq"],
714
+ code: "INVALID_SEQ_TYPE"
715
+ });
716
+ } else {
717
+ schema.seq.forEach((attr, index) => {
718
+ this.validateAttribute(
719
+ attr,
720
+ ["seq", String(index)],
721
+ errors,
722
+ warnings,
723
+ strict
724
+ );
725
+ });
726
+ }
727
+ }
728
+ if (schema.instances) {
729
+ if (typeof schema.instances !== "object") {
730
+ errors.push({
731
+ message: '"instances" must be an object',
732
+ path: ["instances"],
733
+ code: "INVALID_INSTANCES_TYPE"
734
+ });
735
+ } else {
736
+ Object.entries(schema.instances).forEach(([key, instance]) => {
737
+ this.validateAttribute(
738
+ instance,
739
+ ["instances", key],
740
+ errors,
741
+ warnings,
742
+ strict
743
+ );
744
+ });
745
+ }
746
+ }
747
+ if (schema.types) {
748
+ if (typeof schema.types !== "object") {
749
+ errors.push({
750
+ message: '"types" must be an object',
751
+ path: ["types"],
752
+ code: "INVALID_TYPES_TYPE"
753
+ });
754
+ } else {
755
+ Object.entries(schema.types).forEach(([key, type]) => {
756
+ const typeResult = this.validate(type, { ...options, isNested: true });
757
+ errors.push(
758
+ ...typeResult.errors.map((e) => ({
759
+ ...e,
760
+ path: ["types", key, ...e.path]
761
+ }))
762
+ );
763
+ warnings.push(
764
+ ...typeResult.warnings.map((w) => ({
765
+ ...w,
766
+ path: ["types", key, ...w.path]
767
+ }))
768
+ );
769
+ });
770
+ }
771
+ }
772
+ if (schema.enums) {
773
+ if (typeof schema.enums !== "object") {
774
+ errors.push({
775
+ message: '"enums" must be an object',
776
+ path: ["enums"],
777
+ code: "INVALID_ENUMS_TYPE"
778
+ });
779
+ }
780
+ }
781
+ return {
782
+ valid: errors.length === 0 && (strict ? warnings.length === 0 : true),
783
+ errors,
784
+ warnings
785
+ };
786
+ }
787
+ /**
788
+ * Validate an attribute specification.
789
+ *
790
+ * @param attr - Attribute to validate
791
+ * @param path - Path to this attribute in the schema
792
+ * @param errors - Array to collect errors
793
+ * @param warnings - Array to collect warnings
794
+ * @param strict - Whether to be strict about warnings
795
+ * @private
796
+ */
797
+ validateAttribute(attr, path, errors, warnings, _strict) {
798
+ if (attr.id && typeof attr.id === "string") {
799
+ if (!/^[a-z][a-z0-9_]*$/.test(attr.id)) {
800
+ warnings.push({
801
+ message: `Field "${attr.id}" should follow snake_case naming convention`,
802
+ path: [...path, "id"],
803
+ code: "FIELD_ID_NAMING"
804
+ });
805
+ }
806
+ }
807
+ if (attr.repeat) {
808
+ if (attr.repeat !== "expr" && attr.repeat !== "eos" && attr.repeat !== "until") {
809
+ errors.push({
810
+ message: '"repeat" must be "expr", "eos", or "until"',
811
+ path: [...path, "repeat"],
812
+ code: "INVALID_REPEAT"
813
+ });
814
+ }
815
+ if (attr.repeat === "expr" && !attr["repeat-expr"]) {
816
+ errors.push({
817
+ message: '"repeat-expr" is required when repeat is "expr"',
818
+ path: [...path, "repeat-expr"],
819
+ code: "MISSING_REPEAT_EXPR"
820
+ });
821
+ }
822
+ if (attr.repeat === "until" && !attr["repeat-until"]) {
823
+ errors.push({
824
+ message: '"repeat-until" is required when repeat is "until"',
825
+ path: [...path, "repeat-until"],
826
+ code: "MISSING_REPEAT_UNTIL"
827
+ });
828
+ }
829
+ }
830
+ if (attr["size-eos"] && attr.size) {
831
+ warnings.push({
832
+ message: '"size-eos" and "size" are mutually exclusive',
833
+ path: [...path],
834
+ code: "SIZE_EOS_WITH_SIZE"
835
+ });
836
+ }
837
+ if (attr.contents) {
838
+ if (!Array.isArray(attr.contents) && typeof attr.contents !== "string") {
839
+ errors.push({
840
+ message: '"contents" must be an array or string',
841
+ path: [...path, "contents"],
842
+ code: "INVALID_CONTENTS_TYPE"
843
+ });
844
+ }
845
+ }
846
+ }
847
+ /**
848
+ * Parse multiple .ksy files and resolve imports.
849
+ *
850
+ * @param mainYaml - Main .ksy file content
851
+ * @param imports - Map of import names to their YAML content
852
+ * @param options - Parsing options
853
+ * @returns Parsed schema with resolved imports
854
+ */
855
+ parseWithImports(mainYaml, _imports, options = {}) {
856
+ const mainSchema = this.parse(mainYaml, options);
857
+ return mainSchema;
858
+ }
859
+ };
860
+
861
+ // src/interpreter/Context.ts
862
+ var Context = class _Context {
863
+ /**
864
+ * Create a new execution context.
865
+ *
866
+ * @param _io - Binary stream being read
867
+ * @param _root - Root object of the parse tree
868
+ * @param _parent - Parent object (optional)
869
+ */
870
+ constructor(_io, _root = null, _parent = null) {
871
+ this._io = _io;
872
+ this._root = _root;
873
+ /** Stack of parent objects */
874
+ this.parentStack = [];
875
+ /** Current object being parsed */
876
+ this._current = {};
877
+ if (_parent !== null) {
878
+ this.parentStack.push(_parent);
879
+ }
880
+ }
881
+ /**
882
+ * Get the current I/O stream.
883
+ * Accessible in expressions as `_io`.
884
+ *
885
+ * @returns Current stream
886
+ */
887
+ get io() {
888
+ return this._io;
889
+ }
890
+ /**
891
+ * Get the root object.
892
+ * Accessible in expressions as `_root`.
893
+ *
894
+ * @returns Root object
895
+ */
896
+ get root() {
897
+ return this._root;
898
+ }
899
+ /**
900
+ * Get the parent object.
901
+ * Accessible in expressions as `_parent`.
902
+ *
903
+ * @returns Parent object or null if at root
904
+ */
905
+ get parent() {
906
+ return this.parentStack.length > 0 ? this.parentStack[this.parentStack.length - 1] : null;
907
+ }
908
+ /**
909
+ * Get the current object being parsed.
910
+ * Used to access fields defined earlier in the sequence.
911
+ *
912
+ * @returns Current object
913
+ */
914
+ get current() {
915
+ return this._current;
916
+ }
917
+ /**
918
+ * Set the current object.
919
+ *
920
+ * @param obj - Object to set as current
921
+ */
922
+ set current(obj) {
923
+ this._current = obj;
924
+ }
925
+ /**
926
+ * Push a new parent onto the stack.
927
+ * Used when entering a nested type.
928
+ *
929
+ * @param parent - Parent object to push
930
+ */
931
+ pushParent(parent) {
932
+ this.parentStack.push(parent);
933
+ }
934
+ /**
935
+ * Pop the current parent from the stack.
936
+ * Used when exiting a nested type.
937
+ *
938
+ * @returns The popped parent object
939
+ */
940
+ popParent() {
941
+ return this.parentStack.pop();
942
+ }
943
+ /**
944
+ * Get a value from the context by path.
945
+ * Supports special names: _io, _root, _parent, _index.
946
+ *
947
+ * @param name - Name or path to resolve
948
+ * @returns Resolved value
949
+ */
950
+ resolve(name) {
951
+ switch (name) {
952
+ case "_io":
953
+ return this._io;
954
+ case "_root":
955
+ return this._root;
956
+ case "_parent":
957
+ return this.parent;
958
+ case "_index":
959
+ return this._current["_index"];
960
+ default:
961
+ if (name in this._current) {
962
+ return this._current[name];
963
+ }
964
+ return void 0;
965
+ }
966
+ }
967
+ /**
968
+ * Set a value in the current object.
969
+ *
970
+ * @param name - Field name
971
+ * @param value - Value to set
972
+ */
973
+ set(name, value) {
974
+ this._current[name] = value;
975
+ }
976
+ /**
977
+ * Create a child context for nested parsing.
978
+ * The current object becomes the parent in the child context.
979
+ *
980
+ * @param stream - Stream for the child context (defaults to current stream)
981
+ * @returns New child context
982
+ */
983
+ createChild(stream) {
984
+ const childContext = new _Context(
985
+ stream || this._io,
986
+ this._root || this._current,
987
+ this._current
988
+ );
989
+ return childContext;
990
+ }
991
+ /**
992
+ * Clone this context.
993
+ * Creates a shallow copy with the same stream, root, and parent.
994
+ *
995
+ * @returns Cloned context
996
+ */
997
+ clone() {
998
+ const cloned = new _Context(this._io, this._root, this.parent);
999
+ cloned._current = { ...this._current };
1000
+ cloned.parentStack = [...this.parentStack];
1001
+ return cloned;
1002
+ }
1003
+ };
1004
+
1005
+ // src/interpreter/TypeInterpreter.ts
1006
+ var TypeInterpreter = class _TypeInterpreter {
1007
+ /**
1008
+ * Create a new type interpreter.
1009
+ *
1010
+ * @param schema - Kaitai Struct schema to interpret
1011
+ * @param parentMeta - Parent schema's meta (for nested types)
1012
+ */
1013
+ constructor(schema, parentMeta) {
1014
+ this.schema = schema;
1015
+ this.parentMeta = parentMeta;
1016
+ if (!schema.meta && !parentMeta) {
1017
+ throw new ParseError("Schema must have meta section");
1018
+ }
1019
+ if (schema.meta && !schema.meta.id && !parentMeta) {
1020
+ throw new ParseError("Root schema must have meta.id");
1021
+ }
1022
+ }
1023
+ /**
1024
+ * Parse binary data according to the schema.
1025
+ *
1026
+ * @param stream - Binary stream to parse
1027
+ * @param parent - Parent object (for nested types)
1028
+ * @returns Parsed object
1029
+ */
1030
+ parse(stream, parent) {
1031
+ const result = {};
1032
+ const context = new Context(stream, result, parent);
1033
+ context.current = result;
1034
+ if (this.schema.seq) {
1035
+ for (const attr of this.schema.seq) {
1036
+ const value = this.parseAttribute(attr, context);
1037
+ if (attr.id) {
1038
+ result[attr.id] = value;
1039
+ }
1040
+ }
1041
+ }
1042
+ return result;
1043
+ }
1044
+ /**
1045
+ * Parse a single attribute according to its specification.
1046
+ *
1047
+ * @param attr - Attribute specification
1048
+ * @param context - Execution context
1049
+ * @returns Parsed value
1050
+ * @private
1051
+ */
1052
+ parseAttribute(attr, context) {
1053
+ const stream = context.io;
1054
+ if (attr.if) {
1055
+ throw new NotImplementedError("Conditional parsing (if)");
1056
+ }
1057
+ if (attr.pos !== void 0) {
1058
+ const pos = typeof attr.pos === "number" ? attr.pos : 0;
1059
+ stream.seek(pos);
1060
+ }
1061
+ if (attr.io) {
1062
+ throw new NotImplementedError("Custom I/O streams");
1063
+ }
1064
+ if (attr.repeat) {
1065
+ return this.parseRepeated(attr, context);
1066
+ }
1067
+ if (attr.contents) {
1068
+ return this.parseContents(attr, context);
1069
+ }
1070
+ return this.parseValue(attr, context);
1071
+ }
1072
+ /**
1073
+ * Parse a repeated attribute.
1074
+ *
1075
+ * @param attr - Attribute specification with repeat
1076
+ * @param context - Execution context
1077
+ * @returns Array of parsed values
1078
+ * @private
1079
+ */
1080
+ parseRepeated(attr, context) {
1081
+ const result = [];
1082
+ const stream = context.io;
1083
+ switch (attr.repeat) {
1084
+ case "expr": {
1085
+ const count = typeof attr["repeat-expr"] === "number" ? attr["repeat-expr"] : 0;
1086
+ for (let i = 0; i < count; i++) {
1087
+ context.set("_index", i);
1088
+ result.push(this.parseValue(attr, context));
1089
+ }
1090
+ break;
1091
+ }
1092
+ case "eos": {
1093
+ while (!stream.isEof()) {
1094
+ context.set("_index", result.length);
1095
+ result.push(this.parseValue(attr, context));
1096
+ }
1097
+ break;
1098
+ }
1099
+ case "until": {
1100
+ if (!attr["repeat-until"]) {
1101
+ throw new ParseError("repeat-until expression is required");
1102
+ }
1103
+ throw new NotImplementedError("repeat-until");
1104
+ }
1105
+ default:
1106
+ throw new ParseError(`Unknown repeat type: ${attr.repeat}`);
1107
+ }
1108
+ return result;
1109
+ }
1110
+ /**
1111
+ * Parse and validate contents.
1112
+ *
1113
+ * @param attr - Attribute specification with contents
1114
+ * @param context - Execution context
1115
+ * @returns The validated contents
1116
+ * @private
1117
+ */
1118
+ parseContents(attr, context) {
1119
+ const stream = context.io;
1120
+ const expected = attr.contents;
1121
+ if (Array.isArray(expected)) {
1122
+ const bytes = stream.readBytes(expected.length);
1123
+ for (let i = 0; i < expected.length; i++) {
1124
+ if (bytes[i] !== expected[i]) {
1125
+ throw new ValidationError(
1126
+ `Contents mismatch at byte ${i}: expected ${expected[i]}, got ${bytes[i]}`,
1127
+ stream.pos - expected.length + i
1128
+ );
1129
+ }
1130
+ }
1131
+ return bytes;
1132
+ } else {
1133
+ const encoding = attr.encoding || this.schema.meta.encoding || "UTF-8";
1134
+ const str = stream.readStr(expected.length, encoding);
1135
+ if (str !== expected) {
1136
+ throw new ValidationError(
1137
+ `Contents mismatch: expected "${expected}", got "${str}"`,
1138
+ stream.pos - expected.length
1139
+ );
1140
+ }
1141
+ return str;
1142
+ }
1143
+ }
1144
+ /**
1145
+ * Parse a single value according to its type.
1146
+ *
1147
+ * @param attr - Attribute specification
1148
+ * @param context - Execution context
1149
+ * @returns Parsed value
1150
+ * @private
1151
+ */
1152
+ parseValue(attr, context) {
1153
+ const stream = context.io;
1154
+ const type = attr.type;
1155
+ if (attr.size !== void 0) {
1156
+ const size = typeof attr.size === "number" ? attr.size : 0;
1157
+ if (type === "str" || !type) {
1158
+ const encoding = attr.encoding || this.schema.meta.encoding || "UTF-8";
1159
+ if (type === "str") {
1160
+ return stream.readStr(size, encoding);
1161
+ } else {
1162
+ return stream.readBytes(size);
1163
+ }
1164
+ } else {
1165
+ const substream = stream.substream(size);
1166
+ return this.parseType(type, substream, context);
1167
+ }
1168
+ }
1169
+ if (attr["size-eos"]) {
1170
+ if (type === "str") {
1171
+ const encoding = attr.encoding || this.schema.meta.encoding || "UTF-8";
1172
+ const bytes = stream.readBytesFull();
1173
+ return new TextDecoder(encoding).decode(bytes);
1174
+ } else {
1175
+ return stream.readBytesFull();
1176
+ }
1177
+ }
1178
+ if (!type) {
1179
+ throw new ParseError("Attribute must have either type, size, or contents");
1180
+ }
1181
+ return this.parseType(type, stream, context);
1182
+ }
1183
+ /**
1184
+ * Parse a value of a specific type.
1185
+ *
1186
+ * @param type - Type name or switch specification
1187
+ * @param stream - Stream to read from
1188
+ * @param context - Execution context
1189
+ * @returns Parsed value
1190
+ * @private
1191
+ */
1192
+ parseType(type, stream, context) {
1193
+ if (typeof type === "object") {
1194
+ throw new NotImplementedError("Switch types");
1195
+ }
1196
+ if (isBuiltinType(type)) {
1197
+ return this.parseBuiltinType(type, stream, context);
1198
+ }
1199
+ if (this.schema.types && type in this.schema.types) {
1200
+ const typeSchema = this.schema.types[type];
1201
+ const meta = this.schema.meta || this.parentMeta;
1202
+ const interpreter = new _TypeInterpreter(typeSchema, meta);
1203
+ return interpreter.parse(stream, context.current);
1204
+ }
1205
+ throw new ParseError(`Unknown type: ${type}`);
1206
+ }
1207
+ /**
1208
+ * Parse a built-in type.
1209
+ *
1210
+ * @param type - Built-in type name
1211
+ * @param stream - Stream to read from
1212
+ * @param context - Execution context
1213
+ * @returns Parsed value
1214
+ * @private
1215
+ */
1216
+ parseBuiltinType(type, stream, _context) {
1217
+ const base = getBaseType(type);
1218
+ const typeEndian = getTypeEndianness(type);
1219
+ const meta = this.schema.meta || this.parentMeta;
1220
+ const metaEndian = meta?.endian;
1221
+ const endian = typeEndian || (typeof metaEndian === "string" ? metaEndian : "le");
1222
+ if (isIntegerType(type)) {
1223
+ return this.readInteger(base, endian, stream);
1224
+ }
1225
+ if (isFloatType(type)) {
1226
+ return this.readFloat(base, endian, stream);
1227
+ }
1228
+ if (isStringType(type)) {
1229
+ throw new ParseError("String types require size, size-eos, or terminator");
1230
+ }
1231
+ throw new ParseError(`Unknown built-in type: ${type}`);
1232
+ }
1233
+ /**
1234
+ * Read an integer value.
1235
+ *
1236
+ * @param type - Integer type (u1, u2, u4, u8, s1, s2, s4, s8)
1237
+ * @param endian - Endianness
1238
+ * @param stream - Stream to read from
1239
+ * @returns Integer value
1240
+ * @private
1241
+ */
1242
+ readInteger(type, endian, stream) {
1243
+ switch (type) {
1244
+ case "u1":
1245
+ return stream.readU1();
1246
+ case "u2":
1247
+ return endian === "le" ? stream.readU2le() : stream.readU2be();
1248
+ case "u4":
1249
+ return endian === "le" ? stream.readU4le() : stream.readU4be();
1250
+ case "u8":
1251
+ return endian === "le" ? stream.readU8le() : stream.readU8be();
1252
+ case "s1":
1253
+ return stream.readS1();
1254
+ case "s2":
1255
+ return endian === "le" ? stream.readS2le() : stream.readS2be();
1256
+ case "s4":
1257
+ return endian === "le" ? stream.readS4le() : stream.readS4be();
1258
+ case "s8":
1259
+ return endian === "le" ? stream.readS8le() : stream.readS8be();
1260
+ default:
1261
+ throw new ParseError(`Unknown integer type: ${type}`);
1262
+ }
1263
+ }
1264
+ /**
1265
+ * Read a floating point value.
1266
+ *
1267
+ * @param type - Float type (f4, f8)
1268
+ * @param endian - Endianness
1269
+ * @param stream - Stream to read from
1270
+ * @returns Float value
1271
+ * @private
1272
+ */
1273
+ readFloat(type, endian, stream) {
1274
+ switch (type) {
1275
+ case "f4":
1276
+ return endian === "le" ? stream.readF4le() : stream.readF4be();
1277
+ case "f8":
1278
+ return endian === "le" ? stream.readF8le() : stream.readF8be();
1279
+ default:
1280
+ throw new ParseError(`Unknown float type: ${type}`);
1281
+ }
1282
+ }
1283
+ };
1284
+
1285
+ // src/index.ts
1286
+ function parse(ksyYaml, buffer, options = {}) {
1287
+ const { validate = true, strict = false } = options;
1288
+ const parser = new KsyParser();
1289
+ const schema = parser.parse(ksyYaml, { validate, strict });
1290
+ const stream = new KaitaiStream(buffer);
1291
+ const interpreter = new TypeInterpreter(schema);
1292
+ return interpreter.parse(stream);
1293
+ }
1294
+ // Annotate the CommonJS export names for ESM import in node:
1295
+ 0 && (module.exports = {
1296
+ BUILTIN_TYPES,
1297
+ Context,
1298
+ EOFError,
1299
+ KaitaiError,
1300
+ KaitaiStream,
1301
+ KsyParser,
1302
+ NotImplementedError,
1303
+ ParseError,
1304
+ TypeInterpreter,
1305
+ ValidationError,
1306
+ getBaseType,
1307
+ getTypeEndianness,
1308
+ isBuiltinType,
1309
+ isFloatType,
1310
+ isIntegerType,
1311
+ isStringType,
1312
+ parse
1313
+ });
1314
+ /**
1315
+ * @fileoverview Custom error classes for Kaitai Struct parsing and validation
1316
+ * @module utils/errors
1317
+ * @author Fabiano Pinto
1318
+ * @license MIT
1319
+ */
1320
+ /**
1321
+ * @fileoverview String encoding and decoding utilities for binary data
1322
+ * @module utils/encoding
1323
+ * @author Fabiano Pinto
1324
+ * @license MIT
1325
+ */
1326
+ /**
1327
+ * @fileoverview Binary stream reader for Kaitai Struct
1328
+ * @module stream/KaitaiStream
1329
+ * @author Fabiano Pinto
1330
+ * @license MIT
1331
+ */
1332
+ /**
1333
+ * @fileoverview Binary stream reading functionality
1334
+ * @module stream
1335
+ * @author Fabiano Pinto
1336
+ * @license MIT
1337
+ */
1338
+ /**
1339
+ * @fileoverview Type definitions for Kaitai Struct YAML schema (.ksy files)
1340
+ * @module parser/schema
1341
+ * @author Fabiano Pinto
1342
+ * @license MIT
1343
+ */
1344
+ /**
1345
+ * @fileoverview Parser for Kaitai Struct YAML (.ksy) files
1346
+ * @module parser/KsyParser
1347
+ * @author Fabiano Pinto
1348
+ * @license MIT
1349
+ */
1350
+ /**
1351
+ * @fileoverview Parser module for Kaitai Struct YAML files
1352
+ * @module parser
1353
+ * @author Fabiano Pinto
1354
+ * @license MIT
1355
+ */
1356
+ /**
1357
+ * @fileoverview Execution context for Kaitai Struct parsing
1358
+ * @module interpreter/Context
1359
+ * @author Fabiano Pinto
1360
+ * @license MIT
1361
+ */
1362
+ /**
1363
+ * @fileoverview Type interpreter for executing Kaitai Struct schemas
1364
+ * @module interpreter/TypeInterpreter
1365
+ * @author Fabiano Pinto
1366
+ * @license MIT
1367
+ */
1368
+ /**
1369
+ * @fileoverview Interpreter module for executing Kaitai Struct schemas
1370
+ * @module interpreter
1371
+ * @author Fabiano Pinto
1372
+ * @license MIT
1373
+ */
1374
+ /**
1375
+ * @fileoverview Main entry point for kaitai-struct-ts library
1376
+ * @module kaitai-struct-ts
1377
+ * @author Fabiano Pinto
1378
+ * @license MIT
1379
+ * @version 0.2.0
1380
+ *
1381
+ * @description
1382
+ * A runtime interpreter for Kaitai Struct binary format definitions in TypeScript.
1383
+ * Parse any binary data format by providing a .ksy (Kaitai Struct YAML) definition file.
1384
+ *
1385
+ * @example
1386
+ * ```typescript
1387
+ * import { parse } from 'kaitai-struct-ts'
1388
+ *
1389
+ * const ksyDefinition = `
1390
+ * meta:
1391
+ * id: my_format
1392
+ * endian: le
1393
+ * seq:
1394
+ * - id: magic
1395
+ * contents: [0x4D, 0x5A]
1396
+ * - id: version
1397
+ * type: u2
1398
+ * `
1399
+ *
1400
+ * const buffer = new Uint8Array([0x4D, 0x5A, 0x01, 0x00])
1401
+ * const result = parse(ksyDefinition, buffer)
1402
+ * console.log(result.version) // 1
1403
+ * ```
1404
+ */
1405
+ //# sourceMappingURL=index.js.map