auwgent-yaml-lite 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,1153 @@
1
+ // src/tokenizer.ts
2
+ class Tokenizer {
3
+ input = "";
4
+ state;
5
+ options;
6
+ finishing = false;
7
+ constructor(options = {}) {
8
+ this.options = {
9
+ indentSize: options.indentSize ?? 2,
10
+ allowTabs: options.allowTabs ?? false,
11
+ preserveComments: options.preserveComments ?? false
12
+ };
13
+ this.state = this.createInitialState();
14
+ }
15
+ createInitialState() {
16
+ return {
17
+ pos: 0,
18
+ line: 1,
19
+ column: 1,
20
+ indentStack: [0],
21
+ currentIndent: 0,
22
+ pending: [],
23
+ atLineStart: true
24
+ };
25
+ }
26
+ reset() {
27
+ this.input = "";
28
+ this.state = this.createInitialState();
29
+ }
30
+ write(chunk) {
31
+ this.input += chunk;
32
+ }
33
+ getPosition() {
34
+ return {
35
+ line: this.state.line,
36
+ column: this.state.column,
37
+ offset: this.state.pos
38
+ };
39
+ }
40
+ hasMore() {
41
+ return this.state.pos < this.input.length || this.state.pending.length > 0;
42
+ }
43
+ next() {
44
+ if (this.state.pending.length > 0) {
45
+ return this.state.pending.shift();
46
+ }
47
+ if (this.state.pos >= this.input.length) {
48
+ return null;
49
+ }
50
+ if (this.state.atLineStart) {
51
+ return this.tokenizeLineStart();
52
+ }
53
+ return this.tokenizeContent();
54
+ }
55
+ tokenizeAll() {
56
+ const tokens = [];
57
+ let token;
58
+ while ((token = this.next()) !== null) {
59
+ tokens.push(token);
60
+ }
61
+ tokens.push(...this.finalize());
62
+ return tokens;
63
+ }
64
+ finalize() {
65
+ const tokens = [];
66
+ this.finishing = true;
67
+ let token;
68
+ while ((token = this.next()) !== null) {
69
+ tokens.push(token);
70
+ }
71
+ this.finishing = false;
72
+ while (this.state.indentStack.length > 1) {
73
+ this.state.indentStack.pop();
74
+ tokens.push(this.createToken("DEDENT", ""));
75
+ }
76
+ tokens.push(this.createToken("EOF", ""));
77
+ return tokens;
78
+ }
79
+ tokenizeLineStart() {
80
+ const indent = this.consumeIndent();
81
+ const indentLevel = Math.floor(indent / this.options.indentSize);
82
+ const currentLevel = this.state.indentStack[this.state.indentStack.length - 1] ?? 0;
83
+ this.state.atLineStart = false;
84
+ if (this.peekChar() === `
85
+ ` || this.peekChar() === "\r") {
86
+ return this.tokenizeNewline();
87
+ }
88
+ if (this.peekChar() === "#") {
89
+ return this.tokenizeComment();
90
+ }
91
+ if (indentLevel > currentLevel) {
92
+ this.state.indentStack.push(indentLevel);
93
+ this.state.currentIndent = indentLevel;
94
+ const token = this.createToken("INDENT", " ".repeat(indentLevel - currentLevel));
95
+ return token;
96
+ } else if (indentLevel < currentLevel) {
97
+ this.state.currentIndent = indentLevel;
98
+ while (this.state.indentStack.length > 1 && (this.state.indentStack[this.state.indentStack.length - 1] ?? 0) > indentLevel) {
99
+ this.state.indentStack.pop();
100
+ this.state.pending.push(this.createToken("DEDENT", ""));
101
+ }
102
+ return this.state.pending.shift() ?? this.tokenizeContent();
103
+ }
104
+ this.state.currentIndent = indentLevel;
105
+ return this.tokenizeContent();
106
+ }
107
+ tokenizeContent() {
108
+ this.skipSpaces();
109
+ const char = this.peekChar();
110
+ if (char === "") {
111
+ return null;
112
+ }
113
+ if (char === `
114
+ ` || char === "\r") {
115
+ return this.tokenizeNewline();
116
+ }
117
+ if (char === "#") {
118
+ return this.tokenizeComment();
119
+ }
120
+ if (char === "-" && this.peekChar(1) === " ") {
121
+ this.advance();
122
+ return this.createToken("DASH", "-");
123
+ }
124
+ if (char === '"' || char === "'") {
125
+ return this.tokenizeQuotedString(char);
126
+ }
127
+ if (char === ":") {
128
+ this.advance();
129
+ return this.createToken("COLON", ":");
130
+ }
131
+ if (char === "|") {
132
+ return this.tokenizeMultilineString();
133
+ }
134
+ return this.tokenizeKeyOrScalar();
135
+ }
136
+ tokenizeMultilineString() {
137
+ const startCol = this.state.column;
138
+ this.advance();
139
+ while (this.state.pos < this.input.length) {
140
+ const c = this.peekChar();
141
+ if (c === `
142
+ ` || c === "\r")
143
+ break;
144
+ if (c !== " ")
145
+ break;
146
+ this.advance();
147
+ }
148
+ if (this.peekChar() === "\r")
149
+ this.advance();
150
+ if (this.peekChar() === `
151
+ `) {
152
+ this.advance();
153
+ this.state.line++;
154
+ this.state.column = 1;
155
+ }
156
+ const baseIndent = this.measureIndent();
157
+ if (baseIndent === 0) {
158
+ return {
159
+ type: "SCALAR",
160
+ value: "",
161
+ line: this.state.line,
162
+ column: startCol,
163
+ indent: this.state.currentIndent
164
+ };
165
+ }
166
+ const lines = [];
167
+ while (this.state.pos < this.input.length) {
168
+ const lineIndent = this.measureIndent();
169
+ if (lineIndent < baseIndent && this.peekChar() !== `
170
+ ` && this.peekChar() !== "\r") {
171
+ break;
172
+ }
173
+ for (let i = 0;i < baseIndent && this.peekChar() === " "; i++) {
174
+ this.advance();
175
+ }
176
+ let lineContent = "";
177
+ while (this.state.pos < this.input.length) {
178
+ const c = this.peekChar();
179
+ if (c === `
180
+ ` || c === "\r")
181
+ break;
182
+ lineContent += c;
183
+ this.advance();
184
+ }
185
+ lines.push(lineContent);
186
+ if (this.peekChar() === "\r")
187
+ this.advance();
188
+ if (this.peekChar() === `
189
+ `) {
190
+ this.advance();
191
+ this.state.line++;
192
+ this.state.column = 1;
193
+ this.state.atLineStart = true;
194
+ } else {
195
+ break;
196
+ }
197
+ }
198
+ return {
199
+ type: "SCALAR",
200
+ value: lines.join(`
201
+ `),
202
+ line: this.state.line,
203
+ column: startCol,
204
+ indent: this.state.currentIndent
205
+ };
206
+ }
207
+ tokenizeKeyOrScalar() {
208
+ const startCol = this.state.column;
209
+ const startPos = this.state.pos;
210
+ const startLine = this.state.line;
211
+ let value = "";
212
+ while (this.state.pos < this.input.length) {
213
+ const char = this.peekChar();
214
+ if (char === `
215
+ ` || char === "\r" || char === "#") {
216
+ break;
217
+ }
218
+ if (char === ":") {
219
+ const next = this.peekChar(1);
220
+ if (next === " " || next === `
221
+ ` || next === "\r" || next === "") {
222
+ break;
223
+ }
224
+ }
225
+ value += char;
226
+ this.advance();
227
+ }
228
+ const reachedEOF = this.state.pos >= this.input.length;
229
+ if (reachedEOF && !this.finishing) {
230
+ this.state.pos = startPos;
231
+ this.state.column = startCol;
232
+ this.state.line = startLine;
233
+ return null;
234
+ }
235
+ value = value.trim();
236
+ if (this.peekChar() === ":") {
237
+ return {
238
+ type: "KEY",
239
+ value,
240
+ line: this.state.line,
241
+ column: startCol,
242
+ indent: this.state.currentIndent
243
+ };
244
+ }
245
+ return {
246
+ type: "SCALAR",
247
+ value,
248
+ line: this.state.line,
249
+ column: startCol,
250
+ indent: this.state.currentIndent
251
+ };
252
+ }
253
+ tokenizeQuotedString(quote) {
254
+ const startCol = this.state.column;
255
+ this.advance();
256
+ let value = "";
257
+ let closed = false;
258
+ while (this.state.pos < this.input.length) {
259
+ const char = this.peekChar();
260
+ if (char === quote) {
261
+ closed = true;
262
+ this.advance();
263
+ break;
264
+ }
265
+ if (char === "\\" && this.state.pos + 1 < this.input.length) {
266
+ this.advance();
267
+ const escaped = this.peekChar();
268
+ switch (escaped) {
269
+ case "n":
270
+ value += `
271
+ `;
272
+ break;
273
+ case "t":
274
+ value += "\t";
275
+ break;
276
+ case "r":
277
+ value += "\r";
278
+ break;
279
+ case "\\":
280
+ value += "\\";
281
+ break;
282
+ case '"':
283
+ value += '"';
284
+ break;
285
+ case "'":
286
+ value += "'";
287
+ break;
288
+ default:
289
+ value += escaped;
290
+ }
291
+ this.advance();
292
+ continue;
293
+ }
294
+ if (char === `
295
+ ` || char === "\r") {
296
+ break;
297
+ }
298
+ value += char;
299
+ this.advance();
300
+ }
301
+ return {
302
+ type: "QUOTED",
303
+ value,
304
+ line: this.state.line,
305
+ column: startCol,
306
+ indent: this.state.currentIndent
307
+ };
308
+ }
309
+ tokenizeComment() {
310
+ const startCol = this.state.column;
311
+ let value = "";
312
+ this.advance();
313
+ while (this.state.pos < this.input.length) {
314
+ const char = this.peekChar();
315
+ if (char === `
316
+ ` || char === "\r") {
317
+ break;
318
+ }
319
+ value += char;
320
+ this.advance();
321
+ }
322
+ if (!this.options.preserveComments) {
323
+ return this.tokenizeNewline();
324
+ }
325
+ return {
326
+ type: "COMMENT",
327
+ value: value.trim(),
328
+ line: this.state.line,
329
+ column: startCol,
330
+ indent: this.state.currentIndent
331
+ };
332
+ }
333
+ tokenizeNewline() {
334
+ const token = this.createToken("NEWLINE", `
335
+ `);
336
+ if (this.peekChar() === "\r") {
337
+ this.advance();
338
+ }
339
+ if (this.peekChar() === `
340
+ `) {
341
+ this.advance();
342
+ }
343
+ this.state.line++;
344
+ this.state.column = 1;
345
+ this.state.atLineStart = true;
346
+ return token;
347
+ }
348
+ consumeIndent() {
349
+ let spaces = 0;
350
+ while (this.state.pos < this.input.length) {
351
+ const char = this.peekChar();
352
+ if (char === " ") {
353
+ spaces++;
354
+ this.advance();
355
+ } else if (char === "\t") {
356
+ if (!this.options.allowTabs) {
357
+ spaces += this.options.indentSize;
358
+ } else {
359
+ spaces += this.options.indentSize;
360
+ }
361
+ this.advance();
362
+ } else {
363
+ break;
364
+ }
365
+ }
366
+ return spaces;
367
+ }
368
+ measureIndent() {
369
+ let spaces = 0;
370
+ let offset = 0;
371
+ while (true) {
372
+ const char = this.input[this.state.pos + offset];
373
+ if (char === " ") {
374
+ spaces++;
375
+ offset++;
376
+ } else if (char === "\t" && this.options.allowTabs) {
377
+ spaces += this.options.indentSize;
378
+ offset++;
379
+ } else {
380
+ break;
381
+ }
382
+ }
383
+ return spaces;
384
+ }
385
+ skipSpaces() {
386
+ while (this.peekChar() === " ") {
387
+ this.advance();
388
+ }
389
+ }
390
+ peekChar(offset = 0) {
391
+ return this.input[this.state.pos + offset] ?? "";
392
+ }
393
+ advance() {
394
+ if (this.state.pos < this.input.length) {
395
+ this.state.pos++;
396
+ this.state.column++;
397
+ }
398
+ }
399
+ createToken(type, value) {
400
+ return {
401
+ type,
402
+ value,
403
+ line: this.state.line,
404
+ column: this.state.column,
405
+ indent: this.state.currentIndent
406
+ };
407
+ }
408
+ }
409
+ function tokenize(input, options) {
410
+ const tokenizer = new Tokenizer(options);
411
+ tokenizer.write(input);
412
+ return tokenizer.tokenizeAll();
413
+ }
414
+ // src/parser.ts
415
+ class Parser {
416
+ tokenizer;
417
+ tokens = [];
418
+ pos = 0;
419
+ state;
420
+ options;
421
+ constructor(options = {}) {
422
+ this.options = options;
423
+ this.tokenizer = new Tokenizer(options);
424
+ this.state = this.createInitialState();
425
+ }
426
+ createInitialState() {
427
+ return {
428
+ stack: [],
429
+ errors: [],
430
+ listeners: new Map
431
+ };
432
+ }
433
+ reset() {
434
+ this.tokenizer.reset();
435
+ this.tokens = [];
436
+ this.pos = 0;
437
+ this.state = this.createInitialState();
438
+ }
439
+ on(event, handler) {
440
+ if (!this.state.listeners.has(event)) {
441
+ this.state.listeners.set(event, new Set);
442
+ }
443
+ this.state.listeners.get(event).add(handler);
444
+ }
445
+ off(event, handler) {
446
+ this.state.listeners.get(event)?.delete(handler);
447
+ }
448
+ emit(type, data, position) {
449
+ const event = { type, data, position };
450
+ this.state.listeners.get(type)?.forEach((handler) => handler(data));
451
+ this.options.middleware?.forEach((mw) => mw(event));
452
+ }
453
+ write(chunk) {
454
+ this.tokenizer.write(chunk);
455
+ }
456
+ peek() {
457
+ let token;
458
+ while ((token = this.tokenizer.next()) !== null) {
459
+ this.tokens.push(token);
460
+ }
461
+ return this.parseTokens(false);
462
+ }
463
+ end() {
464
+ let token;
465
+ while ((token = this.tokenizer.next()) !== null) {
466
+ this.tokens.push(token);
467
+ }
468
+ this.tokens.push(...this.tokenizer.finalize());
469
+ return this.parseTokens(true);
470
+ }
471
+ parseTokens(complete) {
472
+ if (this.state.stack.length === 0) {
473
+ const firstNonCommentToken = this.tokens.find((t) => t && t.type !== "COMMENT" && t.type !== "NEWLINE");
474
+ const isRootSequence = firstNonCommentToken?.type === "DASH";
475
+ if (isRootSequence) {
476
+ this.pushFrame("sequence", 0);
477
+ } else {
478
+ this.pushFrame("root", 0);
479
+ }
480
+ }
481
+ while (this.pos < this.tokens.length) {
482
+ const token = this.tokens[this.pos];
483
+ if (token) {
484
+ this.processToken(token);
485
+ }
486
+ this.pos++;
487
+ }
488
+ const rootFrame = this.state.stack[0];
489
+ const ast = rootFrame ? this.frameToNode(rootFrame) : null;
490
+ return {
491
+ ast,
492
+ errors: [...this.state.errors],
493
+ complete
494
+ };
495
+ }
496
+ processToken(token) {
497
+ const pos = {
498
+ line: token.line,
499
+ column: token.column,
500
+ offset: 0
501
+ };
502
+ switch (token.type) {
503
+ case "KEY":
504
+ this.handleKey(token, pos);
505
+ break;
506
+ case "COLON":
507
+ break;
508
+ case "SCALAR":
509
+ case "QUOTED":
510
+ this.handleValue(token, pos);
511
+ break;
512
+ case "DASH":
513
+ this.handleDash(token, pos);
514
+ break;
515
+ case "INDENT":
516
+ this.handleIndent(token, pos);
517
+ break;
518
+ case "DEDENT":
519
+ this.handleDedent(token, pos);
520
+ break;
521
+ case "NEWLINE":
522
+ this.handleNewline(token, pos);
523
+ break;
524
+ case "EOF":
525
+ this.handleEOF(pos);
526
+ break;
527
+ case "COMMENT":
528
+ this.emit("line", { comment: token.value }, pos);
529
+ break;
530
+ }
531
+ }
532
+ handleKey(token, pos) {
533
+ this.emit("key", { key: token.value }, pos);
534
+ const frame = this.currentFrame();
535
+ if (frame.type !== "mapping" && frame.type !== "root") {
536
+ this.pushFrame("mapping", token.indent);
537
+ }
538
+ const mappingFrame = this.currentFrame();
539
+ if (mappingFrame.type === "mapping" || mappingFrame.type === "root") {
540
+ if (mappingFrame.pendingKey && mappingFrame.pendingKeyPos) {
541
+ const emptyNode = {
542
+ kind: "empty",
543
+ hint: "mapping",
544
+ line: mappingFrame.pendingKeyPos.line,
545
+ column: mappingFrame.pendingKeyPos.column
546
+ };
547
+ this.addMappingEntry(mappingFrame, mappingFrame.pendingKey, emptyNode, mappingFrame.pendingKeyPos);
548
+ }
549
+ mappingFrame.pendingKey = token.value;
550
+ mappingFrame.pendingKeyPos = { line: token.line, column: token.column };
551
+ }
552
+ }
553
+ handleValue(token, pos) {
554
+ const value = token.value;
555
+ const quoted = token.type === "QUOTED";
556
+ this.emit("value", { value, quoted }, pos);
557
+ const frame = this.currentFrame();
558
+ if (frame.type === "mapping" || frame.type === "root") {
559
+ if (frame.pendingKey) {
560
+ const scalarNode = {
561
+ kind: "scalar",
562
+ value,
563
+ quoted,
564
+ line: token.line,
565
+ column: token.column
566
+ };
567
+ this.addMappingEntry(frame, frame.pendingKey, scalarNode, frame.pendingKeyPos);
568
+ frame.pendingKey = undefined;
569
+ frame.pendingKeyPos = undefined;
570
+ }
571
+ } else if (frame.type === "sequence") {
572
+ const scalarNode = {
573
+ kind: "scalar",
574
+ value,
575
+ quoted,
576
+ line: token.line,
577
+ column: token.column
578
+ };
579
+ frame.node.items.push(scalarNode);
580
+ }
581
+ }
582
+ handleDash(token, pos) {
583
+ this.emit("block_start", { type: "sequence_item" }, pos);
584
+ while (this.state.stack.length > 1) {
585
+ const topFrame = this.currentFrame();
586
+ if (topFrame.indent <= token.indent) {
587
+ break;
588
+ }
589
+ this.popFrame(pos);
590
+ }
591
+ const frame = this.currentFrame();
592
+ const nextToken = this.tokens[this.pos + 1];
593
+ const isScalarItem = nextToken && (nextToken.type === "SCALAR" || nextToken.type === "QUOTED");
594
+ const isKeyItem = nextToken && nextToken.type === "KEY";
595
+ const isDashItem = nextToken && nextToken.type === "DASH";
596
+ if ((frame.type === "mapping" || frame.type === "root") && frame.pendingKey) {
597
+ const seqNode = {
598
+ kind: "sequence",
599
+ items: [],
600
+ line: token.line,
601
+ column: token.column
602
+ };
603
+ this.addMappingEntry(frame, frame.pendingKey, seqNode, frame.pendingKeyPos);
604
+ frame.pendingKey = undefined;
605
+ frame.pendingKeyPos = undefined;
606
+ this.state.stack.push({
607
+ type: "sequence",
608
+ node: seqNode,
609
+ indent: token.indent
610
+ });
611
+ if (isKeyItem) {
612
+ const itemMapping = {
613
+ kind: "mapping",
614
+ entries: [],
615
+ line: token.line,
616
+ column: token.column
617
+ };
618
+ seqNode.items.push(itemMapping);
619
+ this.state.stack.push({
620
+ type: "mapping",
621
+ node: itemMapping,
622
+ indent: token.indent + 1
623
+ });
624
+ } else if (isDashItem) {
625
+ const innerSeq = {
626
+ kind: "sequence",
627
+ items: [],
628
+ line: token.line,
629
+ column: token.column
630
+ };
631
+ seqNode.items.push(innerSeq);
632
+ this.state.stack.push({
633
+ type: "sequence",
634
+ node: innerSeq,
635
+ indent: token.indent + 1
636
+ });
637
+ }
638
+ } else if (frame.type === "sequence") {
639
+ if (isKeyItem) {
640
+ const itemMapping = {
641
+ kind: "mapping",
642
+ entries: [],
643
+ line: token.line,
644
+ column: token.column
645
+ };
646
+ frame.node.items.push(itemMapping);
647
+ this.state.stack.push({
648
+ type: "mapping",
649
+ node: itemMapping,
650
+ indent: token.indent + 1
651
+ });
652
+ } else if (isDashItem) {
653
+ const innerSeq = {
654
+ kind: "sequence",
655
+ items: [],
656
+ line: token.line,
657
+ column: token.column
658
+ };
659
+ frame.node.items.push(innerSeq);
660
+ this.state.stack.push({
661
+ type: "sequence",
662
+ node: innerSeq,
663
+ indent: token.indent + 1
664
+ });
665
+ }
666
+ } else {
667
+ if (frame.type === "root") {
668
+ const seqNode = {
669
+ kind: "sequence",
670
+ items: [],
671
+ line: token.line,
672
+ column: token.column
673
+ };
674
+ frame.node = seqNode;
675
+ frame.type = "sequence";
676
+ }
677
+ }
678
+ }
679
+ handleIndent(token, pos) {
680
+ this.emit("indent", { level: token.indent }, pos);
681
+ const frame = this.currentFrame();
682
+ if ((frame.type === "mapping" || frame.type === "root") && frame.pendingKey) {
683
+ const nextToken = this.tokens[this.pos + 1];
684
+ if (nextToken && nextToken.type === "DASH") {
685
+ return;
686
+ }
687
+ const nestedMapping = {
688
+ kind: "mapping",
689
+ entries: [],
690
+ line: token.line,
691
+ column: token.column
692
+ };
693
+ this.addMappingEntry(frame, frame.pendingKey, nestedMapping, frame.pendingKeyPos);
694
+ frame.pendingKey = undefined;
695
+ frame.pendingKeyPos = undefined;
696
+ this.state.stack.push({
697
+ type: "mapping",
698
+ node: nestedMapping,
699
+ indent: token.indent
700
+ });
701
+ }
702
+ }
703
+ handleDedent(token, pos) {
704
+ this.emit("dedent", { level: token.indent }, pos);
705
+ while (this.state.stack.length > 1) {
706
+ const frame = this.currentFrame();
707
+ if (frame.indent <= token.indent) {
708
+ break;
709
+ }
710
+ this.popFrame(pos);
711
+ }
712
+ }
713
+ handleNewline(token, pos) {
714
+ this.emit("line", {}, pos);
715
+ const frame = this.currentFrame();
716
+ if ((frame.type === "mapping" || frame.type === "root") && frame.pendingKey) {
717
+ const nextToken = this.tokens[this.pos + 1];
718
+ if (nextToken && (nextToken.type === "DEDENT" || nextToken.type === "EOF")) {
719
+ const emptyNode = {
720
+ kind: "empty",
721
+ hint: "mapping",
722
+ line: token.line,
723
+ column: token.column
724
+ };
725
+ this.addMappingEntry(frame, frame.pendingKey, emptyNode, frame.pendingKeyPos);
726
+ frame.pendingKey = undefined;
727
+ frame.pendingKeyPos = undefined;
728
+ }
729
+ }
730
+ }
731
+ handleEOF(pos) {
732
+ while (this.state.stack.length > 1) {
733
+ this.popFrame(pos);
734
+ }
735
+ const rootFrame = this.state.stack[0];
736
+ if (rootFrame && rootFrame.pendingKey) {
737
+ const emptyNode = {
738
+ kind: "empty",
739
+ hint: "mapping",
740
+ line: pos.line,
741
+ column: pos.column
742
+ };
743
+ this.addMappingEntry(rootFrame, rootFrame.pendingKey, emptyNode, rootFrame.pendingKeyPos);
744
+ rootFrame.pendingKey = undefined;
745
+ }
746
+ this.checkIntentReady(pos);
747
+ }
748
+ pushFrame(type, indent) {
749
+ const node = type === "sequence" ? { kind: "sequence", items: [], line: 0, column: 0 } : { kind: "mapping", entries: [], line: 0, column: 0 };
750
+ this.state.stack.push({
751
+ type: type === "root" ? "mapping" : type,
752
+ node,
753
+ indent
754
+ });
755
+ }
756
+ popFrame(pos) {
757
+ const frame = this.state.stack.pop();
758
+ if (frame) {
759
+ this.emit("block_end", { type: frame.type }, pos);
760
+ }
761
+ }
762
+ currentFrame() {
763
+ return this.state.stack[this.state.stack.length - 1];
764
+ }
765
+ addMappingEntry(frame, key, value, keyPos) {
766
+ const mapping = frame.node;
767
+ if (key === "ref" && value.kind === "scalar") {
768
+ const refNode = {
769
+ kind: "ref",
770
+ target: value.value,
771
+ line: value.line,
772
+ column: value.column
773
+ };
774
+ mapping.entries.push({
775
+ key,
776
+ value: refNode,
777
+ line: keyPos.line,
778
+ column: keyPos.column
779
+ });
780
+ } else {
781
+ mapping.entries.push({
782
+ key,
783
+ value,
784
+ line: keyPos.line,
785
+ column: keyPos.column
786
+ });
787
+ }
788
+ }
789
+ checkIntentReady(pos) {
790
+ const rootFrame = this.state.stack[0];
791
+ if (!rootFrame || rootFrame.node.kind !== "mapping")
792
+ return;
793
+ const entries = rootFrame.node.entries;
794
+ const intentEntry = entries.find((e) => e.key === "intent");
795
+ if (intentEntry && intentEntry.value.kind === "mapping") {
796
+ const intentEntries = intentEntry.value.entries;
797
+ const typeEntry = intentEntries.find((e) => e.key === "type");
798
+ if (typeEntry) {
799
+ this.emit("intent_ready", {
800
+ type: typeEntry.value.kind === "scalar" ? typeEntry.value.value : null
801
+ }, pos);
802
+ }
803
+ }
804
+ }
805
+ frameToNode(frame) {
806
+ return frame.node;
807
+ }
808
+ addError(message, line, column) {
809
+ this.state.errors.push({
810
+ message,
811
+ severity: "error",
812
+ line,
813
+ column
814
+ });
815
+ }
816
+ }
817
+ function parse(input, options) {
818
+ const parser = new Parser(options);
819
+ parser.write(input);
820
+ return parser.end();
821
+ }
822
+ function createParser(options) {
823
+ return new Parser(options);
824
+ }
825
+ // src/ir-builder.ts
826
+ function coerceValue(value, quoted) {
827
+ if (quoted) {
828
+ return value;
829
+ }
830
+ const trimmed = value.trim();
831
+ if (trimmed === "null" || trimmed === "Null" || trimmed === "NULL" || trimmed === "~") {
832
+ return null;
833
+ }
834
+ if (trimmed === "" && value === "") {
835
+ return "";
836
+ }
837
+ if (trimmed === "true" || trimmed === "True" || trimmed === "TRUE") {
838
+ return true;
839
+ }
840
+ if (trimmed === "false" || trimmed === "False" || trimmed === "FALSE") {
841
+ return false;
842
+ }
843
+ if (/^-?\d+$/.test(trimmed)) {
844
+ const num = parseInt(trimmed, 10);
845
+ if (Number.isSafeInteger(num)) {
846
+ return num;
847
+ }
848
+ }
849
+ if (/^-?\d+\.\d+$/.test(trimmed)) {
850
+ const num = parseFloat(trimmed);
851
+ if (Number.isFinite(num)) {
852
+ return num;
853
+ }
854
+ }
855
+ if (/^-?\d+\.?\d*[eE][+-]?\d+$/.test(trimmed)) {
856
+ const num = parseFloat(trimmed);
857
+ if (Number.isFinite(num)) {
858
+ return num;
859
+ }
860
+ }
861
+ if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
862
+ try {
863
+ const parsed = JSON.parse(trimmed);
864
+ if (Array.isArray(parsed)) {
865
+ return parsed;
866
+ }
867
+ } catch {}
868
+ }
869
+ if (trimmed.startsWith("{") && trimmed.endsWith("}")) {
870
+ try {
871
+ const parsed = JSON.parse(trimmed);
872
+ if (typeof parsed === "object" && parsed !== null) {
873
+ return parsed;
874
+ }
875
+ } catch {}
876
+ }
877
+ return value;
878
+ }
879
+
880
+ class IRBuilder {
881
+ registry = new Map;
882
+ unresolvedRefs = [];
883
+ errors = [];
884
+ currentPath = [];
885
+ build(ast) {
886
+ this.registry.clear();
887
+ this.unresolvedRefs = [];
888
+ this.errors = [];
889
+ this.currentPath = [];
890
+ let value = ast ? this.transformNode(ast) : null;
891
+ if (value !== null) {
892
+ this.resolveRefs(value);
893
+ value = this.liftRefOnlyObjects(value);
894
+ }
895
+ return {
896
+ value: value ?? {},
897
+ registry: new Map(this.registry),
898
+ unresolvedRefs: [...this.unresolvedRefs],
899
+ errors: [...this.errors]
900
+ };
901
+ }
902
+ transformNode(node) {
903
+ switch (node.kind) {
904
+ case "scalar":
905
+ return this.transformScalar(node);
906
+ case "mapping":
907
+ return this.transformMapping(node);
908
+ case "sequence":
909
+ return this.transformSequence(node);
910
+ case "ref":
911
+ return this.transformRef(node);
912
+ case "empty":
913
+ return this.transformEmpty(node);
914
+ default:
915
+ return null;
916
+ }
917
+ }
918
+ transformScalar(node) {
919
+ return coerceValue(node.value, node.quoted);
920
+ }
921
+ transformMapping(node) {
922
+ const obj = {};
923
+ let nodeId = null;
924
+ for (const entry of node.entries) {
925
+ this.currentPath.push(entry.key);
926
+ const value = this.transformNode(entry.value);
927
+ obj[entry.key] = value;
928
+ if (entry.key === "id" && typeof value === "string") {
929
+ nodeId = value;
930
+ }
931
+ this.currentPath.pop();
932
+ }
933
+ if (nodeId !== null) {
934
+ this.registry.set(nodeId, obj);
935
+ }
936
+ return obj;
937
+ }
938
+ transformSequence(node) {
939
+ const arr = [];
940
+ for (let i = 0;i < node.items.length; i++) {
941
+ const item = node.items[i];
942
+ if (item) {
943
+ this.currentPath.push(`[${i}]`);
944
+ arr.push(this.transformNode(item));
945
+ this.currentPath.pop();
946
+ }
947
+ }
948
+ return arr;
949
+ }
950
+ transformRef(node) {
951
+ return { $ref: node.target };
952
+ }
953
+ transformEmpty(node) {
954
+ return node.hint === "sequence" ? [] : {};
955
+ }
956
+ resolveRefs(value, visited = new Set) {
957
+ if (value === null || typeof value !== "object") {
958
+ return;
959
+ }
960
+ if (visited.has(value)) {
961
+ return;
962
+ }
963
+ visited.add(value);
964
+ if (Array.isArray(value)) {
965
+ for (let i = 0;i < value.length; i++) {
966
+ const item = value[i];
967
+ if (item === undefined)
968
+ continue;
969
+ if (typeof item === "string" && this.registry.has(item)) {
970
+ value[i] = this.deepCopy(this.registry.get(item));
971
+ continue;
972
+ }
973
+ if (this.isRef(item)) {
974
+ const resolved = this.registry.get(item.$ref);
975
+ if (resolved !== undefined) {
976
+ value[i] = this.deepCopy(resolved);
977
+ } else {
978
+ this.unresolvedRefs.push(item.$ref);
979
+ }
980
+ } else {
981
+ this.resolveRefs(item, visited);
982
+ }
983
+ }
984
+ } else {
985
+ for (const key of Object.keys(value)) {
986
+ const child = value[key];
987
+ if (child === undefined)
988
+ continue;
989
+ if (this.isRef(child)) {
990
+ const resolved = this.registry.get(child.$ref);
991
+ if (resolved !== undefined) {
992
+ value[key] = this.deepCopy(resolved);
993
+ } else {
994
+ this.unresolvedRefs.push(child.$ref);
995
+ }
996
+ } else {
997
+ this.resolveRefs(child, visited);
998
+ }
999
+ }
1000
+ }
1001
+ }
1002
+ deepCopy(value) {
1003
+ if (value === null || typeof value !== "object") {
1004
+ return value;
1005
+ }
1006
+ if (Array.isArray(value)) {
1007
+ return value.map((item) => this.deepCopy(item));
1008
+ }
1009
+ const copy = {};
1010
+ for (const key of Object.keys(value)) {
1011
+ const child = value[key];
1012
+ if (child !== undefined) {
1013
+ copy[key] = this.deepCopy(child);
1014
+ }
1015
+ }
1016
+ return copy;
1017
+ }
1018
+ liftRefOnlyObjects(value) {
1019
+ if (value === null || typeof value !== "object") {
1020
+ return value;
1021
+ }
1022
+ if (Array.isArray(value)) {
1023
+ return value.map((item) => this.liftRefOnlyObjects(item));
1024
+ }
1025
+ const keys = Object.keys(value);
1026
+ if (keys.length === 1 && keys[0] === "ref") {
1027
+ const refValue = value["ref"];
1028
+ return refValue !== undefined ? this.liftRefOnlyObjects(refValue) : null;
1029
+ }
1030
+ const result = {};
1031
+ for (const key of keys) {
1032
+ const child = value[key];
1033
+ if (child !== undefined) {
1034
+ result[key] = this.liftRefOnlyObjects(child);
1035
+ }
1036
+ }
1037
+ return result;
1038
+ }
1039
+ isRef(value) {
1040
+ return typeof value === "object" && value !== null && "$ref" in value && typeof value.$ref === "string";
1041
+ }
1042
+ addError(message) {
1043
+ this.errors.push({
1044
+ message,
1045
+ severity: "error",
1046
+ path: [...this.currentPath]
1047
+ });
1048
+ }
1049
+ }
1050
+ function buildIR(ast) {
1051
+ const builder = new IRBuilder;
1052
+ return builder.build(ast);
1053
+ }
1054
+ // src/index.ts
1055
+ function parseToJSON(input, options) {
1056
+ const parser = new Parser(options);
1057
+ parser.write(input);
1058
+ const result = parser.end();
1059
+ const irBuilder = new IRBuilder;
1060
+ const ir = irBuilder.build(result.ast);
1061
+ return ir.value;
1062
+ }
1063
+ function parseWithDiagnostics(input, options) {
1064
+ const parser = new Parser(options);
1065
+ parser.write(input);
1066
+ const parseResult = parser.end();
1067
+ const irBuilder = new IRBuilder;
1068
+ const irResult = irBuilder.build(parseResult.ast);
1069
+ return {
1070
+ parse: parseResult,
1071
+ ir: irResult
1072
+ };
1073
+ }
1074
+ function createStreamingParser(options) {
1075
+ const parser = new Parser(options);
1076
+ const irBuilder = new IRBuilder;
1077
+ let intentHandler = null;
1078
+ parser.on("intent_ready", (data) => {
1079
+ const { type } = data;
1080
+ if (intentHandler && type) {
1081
+ intentHandler(type);
1082
+ }
1083
+ });
1084
+ return {
1085
+ write(chunk) {
1086
+ parser.write(chunk);
1087
+ },
1088
+ peek() {
1089
+ const result = parser.peek();
1090
+ return irBuilder.build(result.ast).value;
1091
+ },
1092
+ end() {
1093
+ const result = parser.end();
1094
+ return irBuilder.build(result.ast).value;
1095
+ },
1096
+ onIntentReady(handler) {
1097
+ intentHandler = handler;
1098
+ }
1099
+ };
1100
+ }
1101
+ function validate(input, options) {
1102
+ const parser = new Parser({ ...options, strict: true });
1103
+ parser.write(input);
1104
+ const result = parser.end();
1105
+ if (result.errors.length === 0) {
1106
+ return true;
1107
+ }
1108
+ return result.errors;
1109
+ }
1110
+ function extractYAML(input) {
1111
+ let text = input;
1112
+ const fenceMatch = text.match(/```(?:yaml|yml)?\s*\n([\s\S]*?)```/);
1113
+ if (fenceMatch && fenceMatch[1]) {
1114
+ return fenceMatch[1].trim();
1115
+ }
1116
+ const lines = text.split(`
1117
+ `);
1118
+ let start = 0;
1119
+ let end = lines.length;
1120
+ for (let i = 0;i < lines.length; i++) {
1121
+ const t = (lines[i] ?? "").trim();
1122
+ if (/^[a-zA-Z_]\w*:/.test(t) || /^-\s/.test(t)) {
1123
+ start = i;
1124
+ break;
1125
+ }
1126
+ }
1127
+ for (let i = lines.length - 1;i >= start; i--) {
1128
+ const line = lines[i] ?? "";
1129
+ const t = line.trim();
1130
+ if (!t)
1131
+ continue;
1132
+ if (/^\s/.test(line) || /^[a-zA-Z_]\w*:/.test(t) || /^-\s/.test(t)) {
1133
+ end = i + 1;
1134
+ break;
1135
+ }
1136
+ }
1137
+ return lines.slice(start, end).join(`
1138
+ `).trim();
1139
+ }
1140
+ export {
1141
+ validate,
1142
+ tokenize,
1143
+ parseWithDiagnostics,
1144
+ parseToJSON,
1145
+ parse,
1146
+ extractYAML,
1147
+ createStreamingParser,
1148
+ createParser,
1149
+ buildIR,
1150
+ Tokenizer,
1151
+ Parser,
1152
+ IRBuilder
1153
+ };