@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.
- package/dist/config.d.ts +75 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +28 -0
- package/dist/config.js.map +1 -0
- package/dist/core/Decoder.d.ts +88 -0
- package/dist/core/Decoder.d.ts.map +1 -0
- package/dist/core/Decoder.js +968 -0
- package/dist/core/Decoder.js.map +1 -0
- package/dist/core/Encoder.d.ts +26 -0
- package/dist/core/Encoder.d.ts.map +1 -0
- package/dist/core/Encoder.js +368 -0
- package/dist/core/Encoder.js.map +1 -0
- package/dist/core/Parser.d.ts +6 -0
- package/dist/core/Parser.d.ts.map +1 -0
- package/dist/core/Parser.js +132 -0
- package/dist/core/Parser.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +46 -0
- package/dist/index.js.map +1 -0
- package/dist/models/Meta.d.ts +48 -0
- package/dist/models/Meta.d.ts.map +1 -0
- package/dist/models/Meta.js +113 -0
- package/dist/models/Meta.js.map +1 -0
- package/dist/models/Node.d.ts +42 -0
- package/dist/models/Node.d.ts.map +1 -0
- package/dist/models/Node.js +179 -0
- package/dist/models/Node.js.map +1 -0
- package/dist/models/Schema.d.ts +55 -0
- package/dist/models/Schema.d.ts.map +1 -0
- package/dist/models/Schema.js +175 -0
- package/dist/models/Schema.js.map +1 -0
- package/package.json +32 -0
- package/src/config.ts +102 -0
- package/src/core/Decoder.ts +1074 -0
- package/src/core/Encoder.ts +443 -0
- package/src/core/Parser.ts +150 -0
- package/src/index.ts +46 -0
- package/src/models/Meta.ts +135 -0
- package/src/models/Node.ts +212 -0
- package/src/models/Schema.ts +222 -0
- package/tests/00.meta.test.ts +31 -0
- package/tests/00.node.test.ts +54 -0
- package/tests/00.primitive.test.ts +108 -0
- package/tests/00.schema.test.ts +41 -0
- package/tests/01.schema.test.ts +70 -0
- package/tests/02.data.test.ts +89 -0
- package/tests/03.errors.test.ts +71 -0
- package/tests/04.list.test.ts +225 -0
- package/tests/05.record.test.ts +82 -0
- package/tests/06.meta.test.ts +506 -0
- package/tests/utils.ts +69 -0
- package/tsconfig.json +46 -0
- 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
|