|
9 | 9 | "bytes" |
10 | 10 | "fmt" |
11 | 11 | "io" |
12 | | - "strings" |
13 | 12 |
|
14 | 13 | "go.yaml.in/yaml/v4" |
15 | 14 | "go.yaml.in/yaml/v4/internal/libyaml" |
@@ -68,59 +67,20 @@ func ProcessEvents(reader io.Reader, profuse, compact, unmarshal bool) error { |
68 | 67 | return processEventsDecode(reader, profuse, compact) |
69 | 68 | } |
70 | 69 |
|
71 | | -// processEventsDecode uses Loader.Load for YAML processing |
| 70 | +// processEventsDecode uses libyaml.Parser.Parse for YAML processing |
72 | 71 | func processEventsDecode(reader io.Reader, profuse, compact bool) error { |
73 | 72 | // Read all input from reader |
74 | 73 | input, err := io.ReadAll(reader) |
75 | 74 | if err != nil { |
76 | 75 | return fmt.Errorf("failed to read input: %w", err) |
77 | 76 | } |
78 | 77 |
|
79 | | - // Get implicit flags from libyaml parser |
80 | | - implicitFlags, err := getDocumentImplicitFlags(input) |
| 78 | + // Get events from parser directly |
| 79 | + events, err := getEventsFromParser(input, profuse) |
81 | 80 | if err != nil { |
82 | 81 | return err |
83 | 82 | } |
84 | 83 |
|
85 | | - // Use yaml.Loader to get events with comments |
86 | | - loader, err := yaml.NewLoader(bytes.NewReader(input)) |
87 | | - if err != nil { |
88 | | - return fmt.Errorf("failed to create loader: %w", err) |
89 | | - } |
90 | | - docIndex := 0 |
91 | | - var allEvents []*Event |
92 | | - |
93 | | - for { |
94 | | - var node yaml.Node |
95 | | - err := loader.Load(&node) |
96 | | - if err != nil { |
97 | | - if err.Error() == "EOF" { |
98 | | - break |
99 | | - } |
100 | | - return fmt.Errorf("failed to load YAML: %w", err) |
101 | | - } |
102 | | - |
103 | | - // Get events from node (includes comments) |
104 | | - events := processNodeToEvents(&node, profuse) |
105 | | - |
106 | | - // Augment document start/end events with implicit flags |
107 | | - if docIndex < len(implicitFlags) { |
108 | | - for _, event := range events { |
109 | | - switch event.Type { |
110 | | - case "DOCUMENT-START": |
111 | | - event.Implicit = implicitFlags[docIndex].StartImplicit |
112 | | - case "DOCUMENT-END": |
113 | | - event.Implicit = implicitFlags[docIndex].EndImplicit |
114 | | - } |
115 | | - } |
116 | | - } |
117 | | - |
118 | | - allEvents = append(allEvents, events...) |
119 | | - docIndex++ |
120 | | - } |
121 | | - |
122 | | - events := allEvents |
123 | | - |
124 | 84 | if compact { |
125 | 85 | // For compact mode, output each event as a flow style mapping in a sequence |
126 | 86 | for _, event := range events { |
@@ -227,58 +187,20 @@ func processEventsDecode(reader io.Reader, profuse, compact bool) error { |
227 | 187 | return nil |
228 | 188 | } |
229 | 189 |
|
230 | | -// processEventsUnmarshal uses yaml.Unmarshal for YAML processing with implicit field augmentation |
| 190 | +// processEventsUnmarshal uses libyaml.Parser.Parse for YAML processing |
231 | 191 | func processEventsUnmarshal(reader io.Reader, profuse, compact bool) error { |
232 | 192 | // Read all input from reader |
233 | 193 | input, err := io.ReadAll(reader) |
234 | 194 | if err != nil { |
235 | 195 | return fmt.Errorf("failed to read input: %w", err) |
236 | 196 | } |
237 | 197 |
|
238 | | - // Get implicit flags from libyaml parser |
239 | | - implicitFlags, err := getDocumentImplicitFlags(input) |
| 198 | + // Get events from parser directly |
| 199 | + events, err := getEventsFromParser(input, profuse) |
240 | 200 | if err != nil { |
241 | 201 | return err |
242 | 202 | } |
243 | 203 |
|
244 | | - // Split input into documents |
245 | | - documents := bytes.Split(input, []byte("---")) |
246 | | - docIndex := 0 |
247 | | - var allEvents []*Event |
248 | | - |
249 | | - for _, doc := range documents { |
250 | | - // Skip empty documents |
251 | | - if len(bytes.TrimSpace(doc)) == 0 { |
252 | | - continue |
253 | | - } |
254 | | - |
255 | | - // Convert to yaml.Node for event processing |
256 | | - var node yaml.Node |
257 | | - if err := yaml.Load(doc, &node); err != nil { |
258 | | - return fmt.Errorf("failed to load YAML to node: %w", err) |
259 | | - } |
260 | | - |
261 | | - // Get events from node (includes comments) |
262 | | - events := processNodeToEvents(&node, profuse) |
263 | | - |
264 | | - // Augment document start/end events with implicit flags |
265 | | - if docIndex < len(implicitFlags) { |
266 | | - for _, event := range events { |
267 | | - switch event.Type { |
268 | | - case "DOCUMENT-START": |
269 | | - event.Implicit = implicitFlags[docIndex].StartImplicit |
270 | | - case "DOCUMENT-END": |
271 | | - event.Implicit = implicitFlags[docIndex].EndImplicit |
272 | | - } |
273 | | - } |
274 | | - } |
275 | | - |
276 | | - allEvents = append(allEvents, events...) |
277 | | - docIndex++ |
278 | | - } |
279 | | - |
280 | | - events := allEvents |
281 | | - |
282 | 204 | if compact { |
283 | 205 | // For compact mode, output each event as a flow style mapping in a sequence |
284 | 206 | for _, event := range events { |
@@ -385,166 +307,6 @@ func processEventsUnmarshal(reader io.Reader, profuse, compact bool) error { |
385 | 307 | return nil |
386 | 308 | } |
387 | 309 |
|
388 | | -// adjustColumn converts yaml.Node 1-based column to 0-based (libyaml format) |
389 | | -func adjustColumn(col int) int { |
390 | | - if col > 0 { |
391 | | - return col - 1 |
392 | | - } |
393 | | - return 0 |
394 | | -} |
395 | | - |
396 | | -// processNodeToEvents converts a node to a slice of events for compact output |
397 | | -func processNodeToEvents(node *yaml.Node, profuse bool) []*Event { |
398 | | - var events []*Event |
399 | | - |
400 | | - // Add document start event |
401 | | - // yaml.Node uses 1-based columns, but we need 0-based (libyaml format) |
402 | | - startCol := adjustColumn(node.Column) |
403 | | - events = append(events, &Event{ |
404 | | - Type: "DOCUMENT-START", |
405 | | - StartLine: node.Line, |
406 | | - StartColumn: startCol, |
407 | | - EndLine: node.Line, |
408 | | - EndColumn: startCol, |
409 | | - }) |
410 | | - |
411 | | - // Process the node content |
412 | | - events = append(events, processNodeToEventsRecursive(node, profuse)...) |
413 | | - |
414 | | - // Add document end event |
415 | | - events = append(events, &Event{ |
416 | | - Type: "DOCUMENT-END", |
417 | | - StartLine: node.Line, |
418 | | - StartColumn: startCol, |
419 | | - EndLine: node.Line, |
420 | | - EndColumn: startCol, |
421 | | - }) |
422 | | - |
423 | | - return events |
424 | | -} |
425 | | - |
426 | | -// processNodeToEventsRecursive recursively converts a node to events |
427 | | -func processNodeToEventsRecursive(node *yaml.Node, profuse bool) []*Event { |
428 | | - var events []*Event |
429 | | - |
430 | | - switch node.Kind { |
431 | | - case yaml.DocumentNode: |
432 | | - for _, child := range node.Content { |
433 | | - events = append(events, processNodeToEventsRecursive(child, profuse)...) |
434 | | - } |
435 | | - case yaml.MappingNode: |
436 | | - startCol := adjustColumn(node.Column) |
437 | | - events = append(events, &Event{ |
438 | | - Type: "MAPPING-START", |
439 | | - StartLine: node.Line, |
440 | | - StartColumn: startCol, |
441 | | - EndLine: node.Line, |
442 | | - EndColumn: startCol, |
443 | | - Style: formatStyle(node.Style, profuse), |
444 | | - HeadComment: node.HeadComment, |
445 | | - LineComment: node.LineComment, |
446 | | - FootComment: node.FootComment, |
447 | | - }) |
448 | | - for i := 0; i < len(node.Content); i += 2 { |
449 | | - if i+1 < len(node.Content) { |
450 | | - // Key |
451 | | - keyEvents := processNodeToEventsRecursive(node.Content[i], profuse) |
452 | | - events = append(events, keyEvents...) |
453 | | - // Value |
454 | | - valueEvents := processNodeToEventsRecursive(node.Content[i+1], profuse) |
455 | | - events = append(events, valueEvents...) |
456 | | - } |
457 | | - } |
458 | | - events = append(events, &Event{ |
459 | | - Type: "MAPPING-END", |
460 | | - StartLine: node.Line, |
461 | | - StartColumn: startCol, |
462 | | - EndLine: node.Line, |
463 | | - EndColumn: startCol, |
464 | | - }) |
465 | | - case yaml.SequenceNode: |
466 | | - startCol := adjustColumn(node.Column) |
467 | | - events = append(events, &Event{ |
468 | | - Type: "SEQUENCE-START", |
469 | | - StartLine: node.Line, |
470 | | - StartColumn: startCol, |
471 | | - EndLine: node.Line, |
472 | | - EndColumn: startCol, |
473 | | - Style: formatStyle(node.Style, profuse), |
474 | | - HeadComment: node.HeadComment, |
475 | | - LineComment: node.LineComment, |
476 | | - FootComment: node.FootComment, |
477 | | - }) |
478 | | - for _, child := range node.Content { |
479 | | - childEvents := processNodeToEventsRecursive(child, profuse) |
480 | | - events = append(events, childEvents...) |
481 | | - } |
482 | | - events = append(events, &Event{ |
483 | | - Type: "SEQUENCE-END", |
484 | | - StartLine: node.Line, |
485 | | - StartColumn: startCol, |
486 | | - EndLine: node.Line, |
487 | | - EndColumn: startCol, |
488 | | - }) |
489 | | - case yaml.ScalarNode: |
490 | | - // Calculate end position for scalars based on value length |
491 | | - // yaml.Node uses 1-based columns, adjust to 0-based |
492 | | - startCol := adjustColumn(node.Column) |
493 | | - endLine := node.Line |
494 | | - endColumn := startCol |
495 | | - if node.Value != "" { |
496 | | - // For single-line values, add the length to the column |
497 | | - if !strings.Contains(node.Value, "\n") { |
498 | | - endColumn = startCol + len(node.Value) |
499 | | - } |
500 | | - } |
501 | | - |
502 | | - // Filter out default YAML tags |
503 | | - tag := node.Tag |
504 | | - // Check if the tag was explicit in the input |
505 | | - tagWasExplicit := node.Style&yaml.TaggedStyle != 0 |
506 | | - |
507 | | - // Show !!str only if it was explicit in the input |
508 | | - if tag == "!!str" { |
509 | | - if !tagWasExplicit { |
510 | | - tag = "" |
511 | | - } |
512 | | - } |
513 | | - // Show all other tags (no filtering) |
514 | | - |
515 | | - events = append(events, &Event{ |
516 | | - Type: "SCALAR", |
517 | | - Value: node.Value, |
518 | | - Anchor: node.Anchor, |
519 | | - Tag: tag, |
520 | | - StartLine: node.Line, |
521 | | - StartColumn: startCol, |
522 | | - EndLine: endLine, |
523 | | - EndColumn: endColumn, |
524 | | - Style: formatStyle(node.Style, profuse), |
525 | | - HeadComment: node.HeadComment, |
526 | | - LineComment: node.LineComment, |
527 | | - FootComment: node.FootComment, |
528 | | - }) |
529 | | - case yaml.AliasNode: |
530 | | - // Generate ALIAS event for alias nodes |
531 | | - startCol := adjustColumn(node.Column) |
532 | | - events = append(events, &Event{ |
533 | | - Type: "ALIAS", |
534 | | - Value: node.Value, |
535 | | - StartLine: node.Line, |
536 | | - StartColumn: startCol, |
537 | | - EndLine: node.Line, |
538 | | - EndColumn: startCol, |
539 | | - HeadComment: node.HeadComment, |
540 | | - LineComment: node.LineComment, |
541 | | - FootComment: node.FootComment, |
542 | | - }) |
543 | | - } |
544 | | - |
545 | | - return events |
546 | | -} |
547 | | - |
548 | 310 | // formatEventInfo converts an Event to an EventInfo struct for YAML encoding |
549 | 311 | func formatEventInfo(event *Event, profuse bool) *EventInfo { |
550 | 312 | info := &EventInfo{ |
@@ -605,48 +367,6 @@ func formatEventInfo(event *Event, profuse bool) *EventInfo { |
605 | 367 | return info |
606 | 368 | } |
607 | 369 |
|
608 | | -// DocumentImplicitFlags holds implicit flags for document start and end events |
609 | | -type DocumentImplicitFlags struct { |
610 | | - StartImplicit bool |
611 | | - EndImplicit bool |
612 | | -} |
613 | | - |
614 | | -// getDocumentImplicitFlags extracts implicit flags for all documents |
615 | | -func getDocumentImplicitFlags(input []byte) ([]*DocumentImplicitFlags, error) { |
616 | | - p := libyaml.NewParser() |
617 | | - if len(input) == 0 { |
618 | | - input = []byte{'\n'} |
619 | | - } |
620 | | - p.SetInputString(input) |
621 | | - |
622 | | - var flags []*DocumentImplicitFlags |
623 | | - var currentDoc *DocumentImplicitFlags |
624 | | - var ev libyaml.Event |
625 | | - |
626 | | - for { |
627 | | - if err := p.Parse(&ev); err != nil { |
628 | | - return nil, fmt.Errorf("failed to parse YAML: %w", err) |
629 | | - } |
630 | | - |
631 | | - switch ev.Type { |
632 | | - case libyaml.DOCUMENT_START_EVENT: |
633 | | - currentDoc = &DocumentImplicitFlags{ |
634 | | - StartImplicit: ev.Implicit, |
635 | | - } |
636 | | - flags = append(flags, currentDoc) |
637 | | - case libyaml.DOCUMENT_END_EVENT: |
638 | | - if currentDoc != nil { |
639 | | - currentDoc.EndImplicit = ev.Implicit |
640 | | - } |
641 | | - case libyaml.STREAM_END_EVENT: |
642 | | - ev.Delete() |
643 | | - return flags, nil |
644 | | - } |
645 | | - |
646 | | - ev.Delete() |
647 | | - } |
648 | | -} |
649 | | - |
650 | 370 | // getEventsFromParser parses YAML input and extracts events with implicit field information |
651 | 371 | func getEventsFromParser(input []byte, profuse bool) ([]*Event, error) { |
652 | 372 | p := libyaml.NewParser() |
@@ -690,6 +410,9 @@ func convertLibyamlEvent(ev *libyaml.Event, profuse bool) *Event { |
690 | 410 | StartColumn: ev.StartMark.Column, |
691 | 411 | EndLine: ev.EndMark.Line + 1, |
692 | 412 | EndColumn: ev.EndMark.Column, |
| 413 | + HeadComment: string(ev.HeadComment), |
| 414 | + LineComment: string(ev.LineComment), |
| 415 | + FootComment: string(ev.FootComment), |
693 | 416 | } |
694 | 417 |
|
695 | 418 | switch ev.Type { |
|
0 commit comments