@arkadia/ai-data-format 0.1.4

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 (57) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +198 -0
  3. package/dist/config.d.ts +75 -0
  4. package/dist/config.d.ts.map +1 -0
  5. package/dist/config.js +28 -0
  6. package/dist/config.js.map +1 -0
  7. package/dist/core/Decoder.d.ts +86 -0
  8. package/dist/core/Decoder.d.ts.map +1 -0
  9. package/dist/core/Decoder.js +951 -0
  10. package/dist/core/Decoder.js.map +1 -0
  11. package/dist/core/Encoder.d.ts +26 -0
  12. package/dist/core/Encoder.d.ts.map +1 -0
  13. package/dist/core/Encoder.js +368 -0
  14. package/dist/core/Encoder.js.map +1 -0
  15. package/dist/core/Parser.d.ts +6 -0
  16. package/dist/core/Parser.d.ts.map +1 -0
  17. package/dist/core/Parser.js +132 -0
  18. package/dist/core/Parser.js.map +1 -0
  19. package/dist/index.d.ts +22 -0
  20. package/dist/index.d.ts.map +1 -0
  21. package/dist/index.js +46 -0
  22. package/dist/index.js.map +1 -0
  23. package/dist/models/Meta.d.ts +48 -0
  24. package/dist/models/Meta.d.ts.map +1 -0
  25. package/dist/models/Meta.js +113 -0
  26. package/dist/models/Meta.js.map +1 -0
  27. package/dist/models/Node.d.ts +42 -0
  28. package/dist/models/Node.d.ts.map +1 -0
  29. package/dist/models/Node.js +179 -0
  30. package/dist/models/Node.js.map +1 -0
  31. package/dist/models/Schema.d.ts +55 -0
  32. package/dist/models/Schema.d.ts.map +1 -0
  33. package/dist/models/Schema.js +175 -0
  34. package/dist/models/Schema.js.map +1 -0
  35. package/package.json +32 -0
  36. package/scripts/verify-build.js +202 -0
  37. package/src/config.ts +102 -0
  38. package/src/core/Decoder.ts +1057 -0
  39. package/src/core/Encoder.ts +443 -0
  40. package/src/core/Parser.ts +150 -0
  41. package/src/index.ts +46 -0
  42. package/src/models/Meta.ts +135 -0
  43. package/src/models/Node.ts +212 -0
  44. package/src/models/Schema.ts +222 -0
  45. package/tests/00.meta.test.ts +31 -0
  46. package/tests/00.node.test.ts +54 -0
  47. package/tests/00.primitive.test.ts +108 -0
  48. package/tests/00.schema.test.ts +41 -0
  49. package/tests/01.schema.test.ts +70 -0
  50. package/tests/02.data.test.ts +89 -0
  51. package/tests/03.errors.test.ts +71 -0
  52. package/tests/04.list.test.ts +225 -0
  53. package/tests/05.record.test.ts +82 -0
  54. package/tests/06.meta.test.ts +506 -0
  55. package/tests/utils.ts +69 -0
  56. package/tsconfig.json +46 -0
  57. package/vitest.config.ts +9 -0
@@ -0,0 +1,951 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Decoder = exports.DecodeWarning = exports.DecodeError = void 0;
4
+ const Node_1 = require("../models/Node");
5
+ const Schema_1 = require("../models/Schema");
6
+ const Meta_1 = require("../models/Meta");
7
+ // --- ANSI Colors Helper ---
8
+ class Ansi {
9
+ }
10
+ Ansi.RESET = "\x1b[0m";
11
+ Ansi.DIM = "\x1b[2m";
12
+ Ansi.BOLD = "\x1b[1m";
13
+ Ansi.CYAN = "\x1b[36m";
14
+ Ansi.YELLOW = "\x1b[33m";
15
+ Ansi.GREEN = "\x1b[32m";
16
+ Ansi.RED = "\x1b[31m";
17
+ Ansi.MAGENTA = "\x1b[35m";
18
+ const ANSI_RE = /\x1b\[[0-9;]*m/g;
19
+ // --- Error/Warning Data Structures ---
20
+ class DecodeError {
21
+ constructor(message, position, schema = null, node = null) {
22
+ this.context = "";
23
+ this.schema = null;
24
+ this.node = null;
25
+ this.message = message;
26
+ this.position = position;
27
+ this.schema = schema;
28
+ this.node = node;
29
+ }
30
+ toString() {
31
+ return `[DecodeError] ${this.message} (at pos ${this.position})`;
32
+ }
33
+ }
34
+ exports.DecodeError = DecodeError;
35
+ class DecodeWarning {
36
+ constructor(message, position, schema = null, node = null) {
37
+ this.message = message;
38
+ this.position = position;
39
+ this.schema = schema;
40
+ this.node = node;
41
+ }
42
+ toString() {
43
+ return `[DecodeWarn] ${this.message} (at pos ${this.position})`;
44
+ }
45
+ }
46
+ exports.DecodeWarning = DecodeWarning;
47
+ // --- DECODER CLASS ---
48
+ class Decoder {
49
+ constructor(text, schema = "", removeAnsiColors = false, debug = false) {
50
+ // Cursor State
51
+ this.i = 0;
52
+ this.line = 0;
53
+ this.col = 0;
54
+ // Context State
55
+ this.pendingMeta = new Meta_1.MetaInfo();
56
+ // Hierarchy State
57
+ this.nodeStack = [];
58
+ this.schemaStack = [];
59
+ this.errors = [];
60
+ this.warnings = [];
61
+ this.namedSchemas = new Map();
62
+ let cleanText = schema + text;
63
+ if (removeAnsiColors) {
64
+ cleanText = cleanText.replace(ANSI_RE, '');
65
+ }
66
+ this.text = cleanText;
67
+ this.debug = debug;
68
+ }
69
+ // =========================================================
70
+ // ENTRY
71
+ // =========================================================
72
+ decode() {
73
+ this._dbg("decode() start");
74
+ this.parseMeta();
75
+ let rootSchemaContext = null;
76
+ // 1. Schema Processing Loop
77
+ while (!this.eof()) {
78
+ const ch = this.peek();
79
+ // Inline Definition <x:int>
80
+ if (ch === '<') {
81
+ rootSchemaContext = this.parseSchemaBody();
82
+ this.parseMeta();
83
+ // Check lookahead for data start
84
+ const next = this.peek();
85
+ if (next === '(' || next === '{' || next === '[')
86
+ break;
87
+ continue;
88
+ }
89
+ // Named Schema @Name
90
+ if (ch === '@') {
91
+ const schema = this.parseSchemaAtRef();
92
+ this.parseMeta();
93
+ const next = this.peek();
94
+ if (next === '@' || next === '<')
95
+ continue;
96
+ rootSchemaContext = schema;
97
+ break;
98
+ }
99
+ break;
100
+ }
101
+ // 2. Push Context
102
+ if (rootSchemaContext) {
103
+ this.pushSchema(rootSchemaContext);
104
+ }
105
+ // 3. Parse Root Node
106
+ let rootNode;
107
+ if (this.eof()) {
108
+ rootNode = this.createNode(null);
109
+ }
110
+ else {
111
+ rootNode = this.parseNode();
112
+ }
113
+ // 4. Cleanup Context
114
+ if (rootSchemaContext) {
115
+ this.popSchema();
116
+ // Link schema if node ended up generic
117
+ if (!rootNode.schema || rootNode.schema.isAny) {
118
+ rootNode.schema = rootSchemaContext;
119
+ }
120
+ }
121
+ else {
122
+ rootSchemaContext = rootNode.schema;
123
+ }
124
+ // Final prefix scan
125
+ this.parseMeta();
126
+ this.applyMeta(rootNode);
127
+ this.popNode(); // Just in case
128
+ this._dbg("decode() end");
129
+ return {
130
+ node: rootNode,
131
+ schema: rootSchemaContext,
132
+ errors: this.errors,
133
+ warnings: this.warnings
134
+ };
135
+ }
136
+ // =========================================================
137
+ // SCHEMA DEFINITION PARSING
138
+ // =========================================================
139
+ parseSchemaAtRef() {
140
+ this.advance(1); // @
141
+ const typeName = this.parseIdent();
142
+ this.skipWhitespace();
143
+ if (this.peek() === '<') {
144
+ this._dbg(`defining type ${typeName}`);
145
+ const schema = this.parseSchemaBody(typeName);
146
+ if (schema.isAny)
147
+ schema.kind = Schema_1.SchemaKind.RECORD;
148
+ this.namedSchemas.set(typeName, schema);
149
+ return schema;
150
+ }
151
+ this._dbg(`referencing type ${typeName}`);
152
+ if (this.namedSchemas.has(typeName)) {
153
+ return this.namedSchemas.get(typeName);
154
+ }
155
+ return new Schema_1.Schema(Schema_1.SchemaKind.RECORD, { typeName });
156
+ }
157
+ parseSchemaBody(typeName = "") {
158
+ const typeNamePrefix = typeName ? `@${typeName}` : "";
159
+ this._dbg(`START parse_schema_body '<' ${typeNamePrefix}`);
160
+ if (!this.expect('<')) {
161
+ const s = this.createSchema(Schema_1.SchemaKind.ANY, typeName);
162
+ this.popSchema();
163
+ return s;
164
+ }
165
+ const schema = this.createSchema(Schema_1.SchemaKind.RECORD, typeName);
166
+ this.parseSchemaBodyContent(schema, '>');
167
+ this.popSchema();
168
+ this._dbg(`END parse_schema_body '>' ${typeNamePrefix}`);
169
+ return schema;
170
+ }
171
+ parseSchemaBodyContent(schema, endChar) {
172
+ // Python style: iterate and parse meta into schema inside the loop
173
+ let fieldSchema = null;
174
+ while (!this.eof()) {
175
+ this.parseMeta(schema); // Passes schema, so blocks /.../ apply to schema
176
+ const ch = this.peek();
177
+ if (ch === endChar) {
178
+ this.advance(1);
179
+ break;
180
+ }
181
+ // LIST Schema: < [ ... ] >
182
+ if (ch === '[') {
183
+ this.advance(1);
184
+ this._dbg("LIST schema begin");
185
+ schema.kind = Schema_1.SchemaKind.LIST;
186
+ schema.clearFields(); // Python: schema._fields_list = []
187
+ this.applyMeta(schema); // Apply any pending meta
188
+ const elementSchema = new Schema_1.Schema(Schema_1.SchemaKind.ANY);
189
+ this.parseSchemaBodyContent(elementSchema, ']');
190
+ schema.element = elementSchema;
191
+ this.parseMeta(schema);
192
+ if (this.peek() === endChar)
193
+ this.advance(1);
194
+ this.applyMeta(schema);
195
+ return;
196
+ }
197
+ if (ch === ',') {
198
+ this.applyMeta(fieldSchema || schema);
199
+ this.advance(1);
200
+ continue;
201
+ }
202
+ const name = this.parseIdent();
203
+ if (!name) {
204
+ this.addError("Expected identifier");
205
+ this.advance(1);
206
+ continue;
207
+ }
208
+ this.skipWhitespace();
209
+ // Detect Primitive List Definition [ int ]
210
+ if (Decoder.PRIMITIVES.has(name) && this.peek() !== ':') {
211
+ schema.kind = Schema_1.SchemaKind.PRIMITIVE;
212
+ schema.typeName = Decoder.PRIMITIVES_MAPPING[name];
213
+ continue;
214
+ }
215
+ if (this.peek() === ':') {
216
+ this.advance(1);
217
+ fieldSchema = this.parseSchemaType();
218
+ }
219
+ else {
220
+ fieldSchema = new Schema_1.Schema(Schema_1.SchemaKind.PRIMITIVE, { typeName: "any" });
221
+ }
222
+ fieldSchema.name = name;
223
+ this.applyMeta(fieldSchema);
224
+ // Trailing comments handling
225
+ this.parseMeta(schema);
226
+ this.applyMeta(fieldSchema || schema);
227
+ schema.addField(fieldSchema);
228
+ }
229
+ this.applyMeta(fieldSchema || schema);
230
+ }
231
+ parseSchemaType() {
232
+ this.parseMeta(this.currentSchema);
233
+ const ch = this.peek();
234
+ if (ch === '[') {
235
+ this.advance(1);
236
+ const lst = new Schema_1.Schema(Schema_1.SchemaKind.LIST);
237
+ this.applyMeta(lst);
238
+ lst.element = this.parseSchemaType();
239
+ this.expect(']');
240
+ return lst;
241
+ }
242
+ if (ch === '@') {
243
+ this.advance(1);
244
+ const name = this.parseIdent();
245
+ this.parseMeta(this.currentSchema);
246
+ if (this.peek() === '<') {
247
+ this._dbg(`Inline definition for @${name}`);
248
+ const s = this.parseSchemaBody(name);
249
+ if (s.isAny)
250
+ s.kind = Schema_1.SchemaKind.RECORD;
251
+ this.namedSchemas.set(name, s);
252
+ return s;
253
+ }
254
+ if (this.namedSchemas.has(name))
255
+ return this.namedSchemas.get(name);
256
+ return new Schema_1.Schema(Schema_1.SchemaKind.RECORD, { typeName: name });
257
+ }
258
+ if (ch === '<') {
259
+ return this.parseSchemaBody();
260
+ }
261
+ const name = this.parseIdent();
262
+ if (Decoder.PRIMITIVES.has(name)) {
263
+ const s = new Schema_1.Schema(Schema_1.SchemaKind.PRIMITIVE, { typeName: Decoder.PRIMITIVES_MAPPING[name] });
264
+ this.applyMeta(s);
265
+ return s;
266
+ }
267
+ if (this.namedSchemas.has(name))
268
+ return this.namedSchemas.get(name);
269
+ if (!name)
270
+ return new Schema_1.Schema(Schema_1.SchemaKind.ANY);
271
+ return new Schema_1.Schema(Schema_1.SchemaKind.RECORD, { typeName: name });
272
+ }
273
+ // =========================================================
274
+ // NODE DISPATCHER
275
+ // =========================================================
276
+ parseNode(_parent = null) {
277
+ this.parseMeta(this.currentNode);
278
+ if (this.eof()) {
279
+ this.addError("Unexpected EOF while expecting a node");
280
+ return this.createNode(null);
281
+ }
282
+ const ch = this.peek();
283
+ let node;
284
+ if (ch === '@')
285
+ node = this.parseNodeWithSchemaRef();
286
+ else if (ch === '<')
287
+ node = this.parseNodeWithInlineSchema();
288
+ else if (ch === '[')
289
+ node = this.parseList();
290
+ else if (ch === '(')
291
+ node = this.parsePositionalRecord();
292
+ else if (ch === '{')
293
+ node = this.parseNamedRecord();
294
+ else if (ch === '"') {
295
+ this._dbg("Dispatch: String");
296
+ node = this.parseString();
297
+ }
298
+ else if ((ch && /\d/.test(ch)) || ch === '-') {
299
+ this._dbg("Dispatch: Number");
300
+ node = this.parseNumber();
301
+ }
302
+ else if ((ch && /[a-zA-Z_]/.test(ch))) {
303
+ this._dbg("Dispatch: RawString/Ident");
304
+ node = this.parseRawString();
305
+ }
306
+ else {
307
+ this.addError(`Unexpected character '${ch}'`);
308
+ this.advance(1);
309
+ node = this.createNode(null);
310
+ }
311
+ this.applyMeta(node);
312
+ return node;
313
+ }
314
+ parseNodeWithSchemaRef() {
315
+ this._dbg("Start Node with Ref (@)");
316
+ const schema = this.parseSchemaAtRef();
317
+ this.pushSchema(schema);
318
+ const node = this.parseNode();
319
+ this.popSchema();
320
+ node.schema = schema;
321
+ return node;
322
+ }
323
+ parseNodeWithInlineSchema() {
324
+ this._dbg("Start Node with Inline (<)");
325
+ const schema = this.parseSchemaBody();
326
+ this.pushSchema(schema);
327
+ const node = this.parseNode();
328
+ this.popSchema();
329
+ node.schema = schema;
330
+ return node;
331
+ }
332
+ // =========================================================
333
+ // STRUCTURE PARSERS
334
+ // =========================================================
335
+ parseList() {
336
+ this._dbg("Start LIST [");
337
+ this.advance(1); // [
338
+ const node = this.createNode();
339
+ node.elements = [];
340
+ if (node.schema.kind !== Schema_1.SchemaKind.LIST) {
341
+ node.schema.kind = Schema_1.SchemaKind.LIST;
342
+ node.schema.typeName = "list";
343
+ node.schema.element = new Schema_1.Schema(Schema_1.SchemaKind.ANY);
344
+ }
345
+ const parentSchema = node.schema;
346
+ let childSchema = new Schema_1.Schema(Schema_1.SchemaKind.ANY);
347
+ if (parentSchema && parentSchema.isList && parentSchema.element) {
348
+ childSchema = parentSchema.element;
349
+ }
350
+ let childNode = null;
351
+ while (true) {
352
+ this.parseMeta(node); // Passes node, so blocks /.../ apply to list
353
+ this.pushSchema(childSchema);
354
+ if (this.eof()) {
355
+ this.addError("Unexpected EOF: List not closed");
356
+ break;
357
+ }
358
+ if (this.peek() === ']') {
359
+ this.applyMeta(childNode || node);
360
+ this.advance(1);
361
+ break;
362
+ }
363
+ if (this.peek() === ',') {
364
+ this.applyMeta(childNode || node);
365
+ this.advance(1);
366
+ continue;
367
+ }
368
+ childNode = this.parseNode(node);
369
+ node.elements.push(childNode);
370
+ if (parentSchema.element && parentSchema.element.isAny && childNode.schema) {
371
+ parentSchema.element = childNode.schema;
372
+ }
373
+ this.applyMeta(childNode || node);
374
+ this.popNode();
375
+ this.popSchema();
376
+ }
377
+ this.popSchema();
378
+ this._dbg("End LIST ]");
379
+ return node;
380
+ }
381
+ parsePositionalRecord() {
382
+ this._dbg("Start RECORD (");
383
+ this.advance(1); // (
384
+ const node = this.createNode();
385
+ if (node.schema.kind !== Schema_1.SchemaKind.RECORD) {
386
+ node.schema.kind = Schema_1.SchemaKind.RECORD;
387
+ node.schema.typeName = "any";
388
+ }
389
+ let index = 0;
390
+ const predefinedFields = node.schema.fields ? [...node.schema.fields] : [];
391
+ let valNode = null;
392
+ while (!this.eof()) {
393
+ this.parseMeta(node);
394
+ if (this.peek() === ')') {
395
+ this.applyMeta(valNode || node);
396
+ this.advance(1);
397
+ break;
398
+ }
399
+ if (this.peek() === ',') {
400
+ this.applyMeta(valNode || node);
401
+ this.advance(1);
402
+ continue;
403
+ }
404
+ let fieldSchema = new Schema_1.Schema(Schema_1.SchemaKind.ANY);
405
+ if (index < predefinedFields.length) {
406
+ fieldSchema = predefinedFields[index];
407
+ }
408
+ this.pushSchema(fieldSchema);
409
+ valNode = this.parseNode();
410
+ if (index < predefinedFields.length) {
411
+ const name = predefinedFields[index].name;
412
+ node.fields[name] = valNode;
413
+ }
414
+ else {
415
+ const name = `_${index}`;
416
+ const inferred = new Schema_1.Schema(valNode.schema.kind, { typeName: valNode.schema.typeName || "any" });
417
+ inferred.name = name;
418
+ node.schema.addField(inferred);
419
+ node.fields[name] = valNode;
420
+ }
421
+ this.applyMeta(valNode || node);
422
+ this.popNode();
423
+ this.popSchema();
424
+ index++;
425
+ }
426
+ this._dbg("End RECORD )");
427
+ return node;
428
+ }
429
+ parseNamedRecord() {
430
+ this._dbg("Start NAMED RECORD {");
431
+ this.advance(1); // {
432
+ const node = this.createNode();
433
+ node.fields = {};
434
+ if (node.schema.kind !== Schema_1.SchemaKind.RECORD) {
435
+ node.schema.kind = Schema_1.SchemaKind.RECORD;
436
+ node.schema.typeName = "any";
437
+ }
438
+ const currentSchema = node.schema;
439
+ let valNode = null;
440
+ while (!this.eof()) {
441
+ this.parseMeta(node);
442
+ if (this.peek() === '}') {
443
+ this.applyMeta(valNode || node);
444
+ this.advance(1);
445
+ break;
446
+ }
447
+ if (this.peek() === ',') {
448
+ this.applyMeta(valNode || node);
449
+ this.advance(1);
450
+ continue;
451
+ }
452
+ let keyName = this.parseIdent();
453
+ if (!keyName) {
454
+ if (this.peek() === '"') {
455
+ keyName = this.readQuotedString();
456
+ }
457
+ else {
458
+ this.addError("Expected key in record");
459
+ this.advance(1);
460
+ continue;
461
+ }
462
+ }
463
+ this.skipWhitespace();
464
+ this.expect(':');
465
+ let fieldSchema = new Schema_1.Schema(Schema_1.SchemaKind.ANY);
466
+ if (currentSchema && currentSchema.isRecord) {
467
+ const existing = currentSchema.getField(keyName);
468
+ if (existing)
469
+ fieldSchema = existing;
470
+ }
471
+ this.pushSchema(fieldSchema);
472
+ valNode = this.parseNode();
473
+ if (currentSchema.isRecord) {
474
+ const existing = currentSchema.getField(keyName);
475
+ if (existing && existing.isAny && !valNode.schema.isAny) {
476
+ valNode.schema.name = keyName;
477
+ currentSchema.replaceField(valNode.schema);
478
+ }
479
+ else if (!existing) {
480
+ const inferred = new Schema_1.Schema(valNode.schema.kind, { typeName: valNode.schema.typeName || "any" });
481
+ inferred.name = keyName;
482
+ node.schema.addField(inferred);
483
+ }
484
+ }
485
+ node.fields[keyName] = valNode;
486
+ this.applyMeta(valNode || node);
487
+ this.popNode();
488
+ this.popSchema();
489
+ }
490
+ this._dbg("End NAMED RECORD }");
491
+ return node;
492
+ }
493
+ // =========================================================
494
+ // PREFIX & META PARSING
495
+ // =========================================================
496
+ parseMeta(obj = null) {
497
+ while (!this.eof()) {
498
+ this.skipWhitespace();
499
+ const ch = this.peek();
500
+ const nextCh = this.peekNext();
501
+ if (ch === '/' && nextCh === '*') {
502
+ this.pendingMeta.comments.push(this.parseCommentBlock());
503
+ continue;
504
+ }
505
+ if (ch === '/' && nextCh !== '*') {
506
+ this.parseMetaBlock(obj);
507
+ continue;
508
+ }
509
+ if (ch === '$' || ch === '#' || ch === '!') {
510
+ this.parseModifierInline();
511
+ continue;
512
+ }
513
+ break;
514
+ }
515
+ }
516
+ parseCommentBlock() {
517
+ this._dbg("START block comment");
518
+ this.advance(2);
519
+ let nesting = 1;
520
+ let content = [];
521
+ while (!this.eof() && nesting > 0) {
522
+ const ch = this.text[this.i];
523
+ if (ch === '\\') {
524
+ this.advance(1);
525
+ if (!this.eof())
526
+ content.push(this.text[this.i]);
527
+ this.advance(1);
528
+ continue;
529
+ }
530
+ if (ch === '/' && this.peekNext() === '*') {
531
+ nesting++;
532
+ this.advance(2);
533
+ content.push("/*");
534
+ continue;
535
+ }
536
+ if (ch === '*' && this.peekNext() === '/') {
537
+ nesting--;
538
+ this.advance(2);
539
+ if (nesting > 0)
540
+ content.push("*/");
541
+ continue;
542
+ }
543
+ content.push(ch);
544
+ this.advance(1);
545
+ }
546
+ if (nesting > 0)
547
+ this.addError("Unterminated comment");
548
+ return content.join("").trim();
549
+ }
550
+ parseModifierInline() {
551
+ const ch = this.peek();
552
+ if (ch === '$')
553
+ this.parseMetaAttribute(this.pendingMeta);
554
+ else if (ch === '#')
555
+ this.parseMetaTag(this.pendingMeta);
556
+ else if (ch === '!')
557
+ this.parseMetaFlag(this.pendingMeta);
558
+ else
559
+ this.advance(1);
560
+ }
561
+ parseMetaBlock(obj = null) {
562
+ this.expect('/');
563
+ this._dbg("START meta header /.../");
564
+ const meta = new Meta_1.MetaInfo();
565
+ while (!this.eof()) {
566
+ this.skipWhitespace();
567
+ const ch = this.peek();
568
+ const nextCh = this.peekNext();
569
+ if (ch === '/' && nextCh === '*') {
570
+ meta.comments.push(this.parseCommentBlock());
571
+ continue;
572
+ }
573
+ if (ch === '/') {
574
+ this.advance(1);
575
+ break;
576
+ }
577
+ if (ch === '$') {
578
+ this.parseMetaAttribute(meta);
579
+ continue;
580
+ }
581
+ if (ch === '#') {
582
+ this.parseMetaTag(meta);
583
+ continue;
584
+ }
585
+ if (ch === '!') {
586
+ this.parseMetaFlag(meta);
587
+ continue;
588
+ }
589
+ // Implicit Attribute (Legacy support: key=value without $)
590
+ if (/[a-zA-Z0-9_]/.test(ch || '')) {
591
+ const key = this.parseIdent();
592
+ let val = true;
593
+ this.skipWhitespace();
594
+ if (this.peek() === '=') {
595
+ this.advance(1);
596
+ val = this.parsePrimitiveValue();
597
+ }
598
+ this.addWarning(`Implicit attribute '${key}'. Use '$${key}' instead.`);
599
+ meta.attr[key] = val;
600
+ continue;
601
+ }
602
+ this.addError(`Unexpected token in meta block: ${ch}`);
603
+ this.advance(1);
604
+ }
605
+ if (obj) {
606
+ obj.applyMeta(meta);
607
+ }
608
+ else {
609
+ this.addWarning(`There is no parent to add the meta block '${meta}'`);
610
+ this.pendingMeta.applyMeta(meta);
611
+ }
612
+ this._dbg("END meta header");
613
+ return meta;
614
+ }
615
+ parseMetaAttribute(meta) {
616
+ this.advance(1); // $
617
+ const key = this.parseIdent();
618
+ let val = true;
619
+ this.skipWhitespace();
620
+ if (this.peek() === '=') {
621
+ this.advance(1);
622
+ val = this.parsePrimitiveValue();
623
+ }
624
+ meta.attr[key] = val;
625
+ this._dbg(`Meta Attr: $${key}=${val}`);
626
+ }
627
+ parseMetaTag(meta) {
628
+ this.advance(1); // #
629
+ const tag = this.parseIdent();
630
+ meta.tags.push(tag);
631
+ this._dbg(`Meta Tag: #${tag}`);
632
+ }
633
+ parseMetaFlag(meta) {
634
+ this.advance(1); // !
635
+ const flag = this.parseIdent();
636
+ if (flag === 'required') {
637
+ meta.required = true;
638
+ this._dbg("Meta Flag: !required");
639
+ }
640
+ else {
641
+ this.addWarning(`Unknown flag: !${flag}`);
642
+ }
643
+ }
644
+ // =========================================================
645
+ // HELPERS & LOW-LEVEL PARSERS
646
+ // =========================================================
647
+ parseIdent() {
648
+ this.skipWhitespace();
649
+ const start = this.i;
650
+ if (this.eof())
651
+ return "";
652
+ const ch = this.text[this.i];
653
+ if (!(/[a-zA-Z_]/.test(ch)))
654
+ return "";
655
+ this.advance(1);
656
+ while (!this.eof()) {
657
+ const c = this.text[this.i];
658
+ if (/[a-zA-Z0-9_]/.test(c))
659
+ this.advance(1);
660
+ else
661
+ break;
662
+ }
663
+ return this.text.substring(start, this.i);
664
+ }
665
+ parseString() {
666
+ const val = this.readQuotedString();
667
+ return this.createNode(val);
668
+ }
669
+ parseNumber() {
670
+ const val = this.readNumber();
671
+ return this.createNode(val);
672
+ }
673
+ parseRawString() {
674
+ const raw = this.parseIdent();
675
+ let val = raw;
676
+ if (raw === "true")
677
+ val = true;
678
+ else if (raw === "false")
679
+ val = false;
680
+ else if (raw === "null")
681
+ val = null;
682
+ return this.createNode(val);
683
+ }
684
+ parsePrimitiveValue() {
685
+ const ch = this.peek();
686
+ if (!ch)
687
+ return null;
688
+ if (ch === '"')
689
+ return this.readQuotedString();
690
+ if (/\d/.test(ch) || ch === '-')
691
+ return this.readNumber();
692
+ const raw = this.parseIdent();
693
+ if (raw === "true")
694
+ return true;
695
+ if (raw === "false")
696
+ return false;
697
+ if (raw === "null")
698
+ return null;
699
+ return raw;
700
+ }
701
+ readQuotedString() {
702
+ this.expect('"');
703
+ let res = "";
704
+ while (!this.eof()) {
705
+ const ch = this.text[this.i];
706
+ if (ch === '"')
707
+ break;
708
+ if (ch === '\\') {
709
+ this.advance(1);
710
+ if (this.eof())
711
+ break;
712
+ const esc = this.text[this.i];
713
+ if (esc === 'n')
714
+ res += '\n';
715
+ else if (esc === 't')
716
+ res += '\t';
717
+ else if (esc === 'r')
718
+ res += '\r';
719
+ else if (esc === '"')
720
+ res += '"';
721
+ else if (esc === '\\')
722
+ res += '\\';
723
+ else
724
+ res += esc;
725
+ this.advance(1);
726
+ }
727
+ else {
728
+ res += ch;
729
+ this.advance(1);
730
+ }
731
+ }
732
+ this.expect('"');
733
+ return res;
734
+ }
735
+ readNumber() {
736
+ const start = this.i;
737
+ if (this.peek() === '-')
738
+ this.advance(1);
739
+ while (/\d/.test(this.peek() || ''))
740
+ this.advance(1);
741
+ if (this.peek() === '.') {
742
+ this.advance(1);
743
+ while (/\d/.test(this.peek() || ''))
744
+ this.advance(1);
745
+ }
746
+ if (['e', 'E'].includes(this.peek() || '')) {
747
+ this.advance(1);
748
+ if (['+', '-'].includes(this.peek() || ''))
749
+ this.advance(1);
750
+ while (/\d/.test(this.peek() || ''))
751
+ this.advance(1);
752
+ }
753
+ const raw = this.text.substring(start, this.i);
754
+ const num = parseFloat(raw);
755
+ if (isNaN(num)) {
756
+ this.addError(`Invalid number format: ${raw}`);
757
+ return 0;
758
+ }
759
+ return num;
760
+ }
761
+ // =========================================================
762
+ // STACK & STATE HELPERS
763
+ // =========================================================
764
+ get currentSchema() {
765
+ return this.schemaStack.length > 0 ? this.schemaStack[this.schemaStack.length - 1] : null;
766
+ }
767
+ createSchema(kind, typeName = "") {
768
+ const s = new Schema_1.Schema(kind, { typeName });
769
+ this.applyMeta(s);
770
+ this.pushSchema(s);
771
+ return s;
772
+ }
773
+ pushSchema(s) {
774
+ this.schemaStack.push(s);
775
+ this._dbg(`PUSH SCHEMA ${s.toString().substring(0, 30)}...`);
776
+ }
777
+ popSchema() {
778
+ const s = this.schemaStack.pop() || null;
779
+ if (s && s.isList && s.element) {
780
+ s.applyMeta(s.element);
781
+ s.element.clearMeta();
782
+ }
783
+ this._dbg(`POP SCHEMA ${s ? s.toString().substring(0, 30) : 'null'}...`);
784
+ return s;
785
+ }
786
+ get currentNode() {
787
+ return this.nodeStack.length > 0 ? this.nodeStack[this.nodeStack.length - 1] : null;
788
+ }
789
+ pushNode(n) {
790
+ this.nodeStack.push(n);
791
+ this._dbg(`PUSH NODE ${n.toString().substring(0, 30)}...`);
792
+ }
793
+ popNode() {
794
+ const n = this.nodeStack.pop() || null;
795
+ this._dbg(`POP NODE ${n ? n.toString().substring(0, 30) : 'null'}...`);
796
+ return n;
797
+ }
798
+ createNode(value = null) {
799
+ let currentS = this.currentSchema;
800
+ if (!currentS) {
801
+ currentS = new Schema_1.Schema(Schema_1.SchemaKind.ANY);
802
+ this.pushSchema(currentS);
803
+ }
804
+ let finalS = currentS;
805
+ if (value !== null) {
806
+ let inferred = null;
807
+ if (typeof value === 'boolean')
808
+ inferred = new Schema_1.Schema(Schema_1.SchemaKind.PRIMITIVE, { typeName: "bool" });
809
+ else if (typeof value === 'number')
810
+ inferred = new Schema_1.Schema(Schema_1.SchemaKind.PRIMITIVE, { typeName: "number" });
811
+ else if (typeof value === 'string')
812
+ inferred = new Schema_1.Schema(Schema_1.SchemaKind.PRIMITIVE, { typeName: "string" });
813
+ if (inferred) {
814
+ let compatible = false;
815
+ if (currentS.kind === Schema_1.SchemaKind.ANY) {
816
+ compatible = true;
817
+ finalS = inferred;
818
+ }
819
+ else if (currentS.typeName === inferred.typeName) {
820
+ compatible = true;
821
+ }
822
+ else if (currentS.typeName === "number" && (inferred.typeName === "int" || inferred.typeName === "float")) {
823
+ compatible = true;
824
+ }
825
+ if (!compatible) {
826
+ finalS = inferred;
827
+ }
828
+ }
829
+ }
830
+ else {
831
+ if (currentS.isRecord || currentS.isList) {
832
+ finalS = currentS;
833
+ }
834
+ else {
835
+ finalS = new Schema_1.Schema(Schema_1.SchemaKind.PRIMITIVE, { typeName: "null" });
836
+ }
837
+ }
838
+ const node = new Node_1.Node(finalS, { value });
839
+ this.applyMeta(node);
840
+ this.pushNode(node);
841
+ return node;
842
+ }
843
+ applyMeta(obj) {
844
+ obj.applyMeta(this.pendingMeta);
845
+ this.pendingMeta = new Meta_1.MetaInfo();
846
+ }
847
+ advance(n = 1) {
848
+ let lastChar = "";
849
+ for (let k = 0; k < n; k++) {
850
+ if (this.i >= this.text.length)
851
+ break;
852
+ const c = this.text[this.i];
853
+ lastChar = c;
854
+ if (c === '\n') {
855
+ this.line++;
856
+ this.col = 1;
857
+ }
858
+ else {
859
+ this.col++;
860
+ }
861
+ this.i++;
862
+ }
863
+ return lastChar;
864
+ }
865
+ skipWhitespace() {
866
+ while (!this.eof()) {
867
+ const ch = this.peek();
868
+ if (ch && /\s/.test(ch)) {
869
+ this.advance(1);
870
+ }
871
+ else {
872
+ break;
873
+ }
874
+ }
875
+ }
876
+ eof() { return this.i >= this.text.length; }
877
+ peek() { return this.eof() ? null : this.text[this.i]; }
878
+ peekNext() { return (this.i + 1 < this.text.length) ? this.text[this.i + 1] : null; }
879
+ expect(ch) {
880
+ if (this.peek() !== ch) {
881
+ this.addError(`Expected '${ch}', got '${this.peek()}'`);
882
+ return false;
883
+ }
884
+ this.advance(1);
885
+ return true;
886
+ }
887
+ addError(msg) {
888
+ if (this.errors.length >= Decoder.MAX_ERRORS)
889
+ return;
890
+ this._dbg(`ERROR: ${msg}`);
891
+ this.errors.push(new DecodeError(msg, this.i, this.currentSchema, this.currentNode));
892
+ }
893
+ addWarning(msg) {
894
+ this._dbg(`WARNING: ${msg}`);
895
+ this.warnings.push(new DecodeWarning(msg, this.i, this.currentSchema, this.currentNode));
896
+ }
897
+ _dbg(msg) {
898
+ if (!this.debug)
899
+ return;
900
+ const locStr = `${this.line + 1}:${this.col + 1}`;
901
+ const depth = this.nodeStack.length;
902
+ let treePrefix = "";
903
+ if (depth > 0) {
904
+ // Python: "│ " * (depth - 1)
905
+ treePrefix = Ansi.DIM + "│ ".repeat(depth - 1) + "├─ " + Ansi.RESET;
906
+ }
907
+ const start = Math.max(0, this.i - 10);
908
+ const end = Math.min(this.text.length, this.i + 11);
909
+ // Raw Before: replace newlines, pad start
910
+ const rawBefore = this.text.substring(start, this.i)
911
+ .padStart(10)
912
+ .replace(/\n/g, "↩︎");
913
+ // Raw Current: handle EOF, replace whitespace
914
+ // Note: undefined check needed if i is out of bounds (EOF)
915
+ const charAtI = this.text[this.i] || " ";
916
+ const rawCurrent = charAtI
917
+ .replace(/\n/g, "↩︎")
918
+ .replace(/ /g, "·")
919
+ .replace(/\t/g, "→");
920
+ // Raw After: replace newlines, pad end
921
+ const rawAfter = this.text.substring(this.i + 1, end)
922
+ .padEnd(10)
923
+ .replace(/\n/g, "↩︎");
924
+ const context = `${Ansi.DIM}${rawBefore}${Ansi.RESET}${Ansi.YELLOW}${rawCurrent}${Ansi.RESET}${Ansi.DIM}${rawAfter}${Ansi.RESET}`;
925
+ let msgColor = Ansi.RESET;
926
+ if (msg.includes("ERROR")) {
927
+ msgColor = Ansi.RED;
928
+ }
929
+ else if (msg.includes("WARNING")) {
930
+ msgColor = Ansi.YELLOW;
931
+ }
932
+ else if (msg.includes("→")) {
933
+ msgColor = Ansi.GREEN;
934
+ }
935
+ else if (msg.includes("PUSH") || msg.includes("POP")) {
936
+ msgColor = Ansi.MAGENTA;
937
+ }
938
+ else if (msg.includes("START") || msg.includes("END")) {
939
+ msgColor = Ansi.DIM;
940
+ }
941
+ console.log(`${Ansi.CYAN}|${locStr.padStart(8)}|${Ansi.RESET}${Ansi.DIM} ${Ansi.RESET}${context}${Ansi.DIM}${Ansi.CYAN}|${Ansi.RESET} ${Ansi.YELLOW}${treePrefix}${Ansi.YELLOW}@${depth}${Ansi.RESET} ${Ansi.DIM}|${Ansi.RESET} ${msgColor}${msg}${Ansi.RESET}`);
942
+ }
943
+ }
944
+ exports.Decoder = Decoder;
945
+ Decoder.PRIMITIVES = new Set(["string", "bool", "number", "null", "int", "float", "binary"]);
946
+ Decoder.PRIMITIVES_MAPPING = {
947
+ "string": "string", "bool": "bool", "number": "number", "null": "null",
948
+ "int": "number", "float": "number", "binary": "binary"
949
+ };
950
+ Decoder.MAX_ERRORS = 50;
951
+ //# sourceMappingURL=Decoder.js.map