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