Skip to content

Commit 3800c3a

Browse files
committed
feat(goccy): marshal back to goccy ast
1 parent 99b8b97 commit 3800c3a

File tree

2 files changed

+176
-77
lines changed

2 files changed

+176
-77
lines changed

pkg/yqlib/candidate_node_goccy_yaml.go

Lines changed: 162 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -207,82 +207,52 @@ func (o *CandidateNode) goccyProcessMappingValueNode(mappingEntry *ast.MappingVa
207207
return nil
208208
}
209209

210-
func (o *CandidateNode) goccyMarshalChild(path string) (ast.Node, error) {
211-
var node ast.Node
212-
switch o.Kind {
213-
case SequenceNode:
214-
values := make([]ast.Node, len(o.Content))
215-
for i, content := range o.Content {
216-
childNode, err := content.goccyMarshalChild(path + "[" + strconv.Itoa(i) + "]")
217-
if err != nil {
218-
return nil, err
219-
}
220-
221-
values[i] = childNode
222-
}
223-
224-
seq := ast.Sequence(
225-
goccyToken.SequenceStart(o.Value, &goccyToken.Position{}),
226-
o.Style == FlowStyle,
227-
)
228-
229-
seq.Values = values
230-
seq.ValueHeadComments = []*ast.CommentGroupNode{ast.CommentGroup([]*goccyToken.Token{goccyToken.Comment(o.HeadComment, o.HeadComment, &goccyToken.Position{})})}
231-
seq.FootComment = goccyMarshalFootComment(o.FootComment)
232-
node = seq
233-
case MappingNode:
234-
values := make([]*ast.MappingValueNode, len(o.Content)/2)
235-
for i := 0; i < len(o.Content); i += 2 {
236-
key, err := o.Content[i].goccyMarshalMapKeyNode(path)
237-
if err != nil {
238-
return nil, err
239-
}
210+
func (o *CandidateNode) MarshalGoccyYAML() (ast.Node, error) {
211+
marshaller := &goccyMarshaller{}
212+
return marshaller.Marshal("$", o)
213+
}
240214

241-
value, err := o.Content[i+1].goccyMarshalChild(key.GetPath())
242-
if err != nil {
243-
return nil, err
244-
}
215+
type goccyMarshaller struct {
216+
currentToken *goccyToken.Token
217+
}
245218

246-
childNode := ast.MappingValue(
247-
goccyToken.MappingValue(&goccyToken.Position{}),
248-
key,
249-
value,
250-
)
251-
childNode.SetPath(key.GetPath())
252-
if o.Content[i].FootComment != "" {
253-
childNode.FootComment = goccyMarshalFootComment(o.Content[i].FootComment)
254-
}
219+
func (m *goccyMarshaller) PushToken(t *goccyToken.Token) *goccyToken.Token {
220+
if m.currentToken == nil {
221+
m.currentToken = t
222+
return m.currentToken
223+
}
255224

256-
values[i/2] = childNode
257-
}
225+
m.currentToken.Next = t
226+
t.Prev = m.currentToken
227+
m.currentToken = t
258228

259-
mapping := ast.Mapping(goccyToken.MappingStart("", &goccyToken.Position{}), o.Style == FlowStyle, values...)
260-
if o.FootComment != "" {
261-
mapping.FootComment = goccyMarshalFootComment(o.FootComment)
262-
}
229+
return m.currentToken
230+
}
263231

264-
node = mapping
265-
case ScalarNode:
266-
v, err := o.GetValueRep()
232+
func (m *goccyMarshaller) Marshal(path string, o *CandidateNode) (ast.Node, error) {
233+
var node ast.Node
234+
var err error
235+
switch o.Kind {
236+
case AliasNode:
237+
node, err = m.marshalAlias(path, o)
267238
if err != nil {
268239
return nil, err
269240
}
270-
271-
node, err = o.goccyMarshalScalar(path, v)
241+
case ScalarNode:
242+
node, err = m.marshalScalar(path, o)
272243
if err != nil {
273244
return nil, err
274245
}
275-
case AliasNode:
276-
value, err := o.Content[0].goccyMarshalChild(path)
246+
case SequenceNode:
247+
node, err = m.marshalSequence(path, o)
277248
if err != nil {
278249
return nil, err
279250
}
280-
281-
alias := ast.Alias(goccyToken.Alias(o.Value, &goccyToken.Position{}))
282-
alias.Value = value
283-
node = alias
251+
case MappingNode:
252+
node, err = m.marshalMapping(path, o)
284253
}
285254

255+
// TODO: Fix Tag and Anchor tokens
286256
if o.Tag != "" && !strings.HasPrefix(o.Tag, "!!") {
287257
tag := ast.Tag(goccyToken.Tag(o.Tag, o.Tag, &goccyToken.Position{}))
288258
tag.Value = node
@@ -300,25 +270,136 @@ func (o *CandidateNode) goccyMarshalChild(path string) (ast.Node, error) {
300270
return node, nil
301271
}
302272

303-
func (o *CandidateNode) MarshalGoccyYAML() (ast.Node, error) {
304-
return o.goccyMarshalChild("$")
273+
func (m *goccyMarshaller) marshalAlias(path string, o *CandidateNode) (ast.Node, error) {
274+
t := m.PushToken(goccyToken.Alias(o.Value, &goccyToken.Position{}))
275+
var value ast.Node
276+
var err error
277+
value, err = m.Marshal(path, o.Content[0])
278+
if err != nil {
279+
return nil, err
280+
}
281+
282+
alias := ast.Alias(t)
283+
alias.Value = value
284+
return alias, nil
305285
}
306286

307-
func goccyMarshalFootComment(comment string) *ast.CommentGroupNode {
308-
return ast.CommentGroup([]*goccyToken.Token{goccyToken.Comment(comment, comment, &goccyToken.Position{})})
287+
func (m *goccyMarshaller) marshalSequence(path string, o *CandidateNode) (ast.Node, error) {
288+
isFlowStyle := o.Style == FlowStyle
289+
seq := ast.Sequence(
290+
nil,
291+
isFlowStyle,
292+
)
293+
294+
if isFlowStyle {
295+
seq.Start = m.PushToken(goccyToken.SequenceStart("[", &goccyToken.Position{}))
296+
}
297+
298+
var err error
299+
values := make([]ast.Node, len(o.Content))
300+
for i, content := range o.Content {
301+
m.PushToken(goccyToken.SequenceEntry("-", &goccyToken.Position{}))
302+
values[i], err = m.Marshal(path+"["+strconv.Itoa(i)+"]", content)
303+
if err != nil {
304+
return nil, err
305+
}
306+
307+
if isFlowStyle && i < len(o.Content)-1 {
308+
m.PushToken(goccyToken.CollectEntry(",", &goccyToken.Position{}))
309+
}
310+
}
311+
312+
if isFlowStyle {
313+
seq.End = m.PushToken(goccyToken.SequenceEnd("]", &goccyToken.Position{}))
314+
}
315+
316+
seq.Values = values
317+
seq.ValueHeadComments = []*ast.CommentGroupNode{ast.CommentGroup([]*goccyToken.Token{goccyToken.Comment(o.HeadComment, o.HeadComment, &goccyToken.Position{})})}
318+
seq.FootComment = goccyMarshalFootComment(o.FootComment)
319+
320+
return seq, nil
309321
}
310322

311-
func (o *CandidateNode) goccyMarshalMapKeyNode(path string) (ast.MapKeyNode, error) {
312-
if o.Kind != ScalarNode {
313-
return nil, fmt.Errorf("cannot unmarshal non-scalar node to MapKeyNode")
323+
func (m *goccyMarshaller) marshalMapping(path string, o *CandidateNode) (ast.Node, error) {
324+
isFlowStyle := o.Style == FlowStyle
325+
mapping := ast.Mapping(nil, isFlowStyle)
326+
327+
if isFlowStyle {
328+
mapping.Start = m.PushToken(goccyToken.MappingStart("{", &goccyToken.Position{}))
314329
}
315330

316-
v, err := o.GetValueRep()
331+
values := make([]*ast.MappingValueNode, len(o.Content)/2)
332+
var err error
333+
for i := 0; i < len(o.Content); i += 2 {
334+
var childNode *ast.MappingValueNode
335+
childNode, err = m.marshalMappingValueNode(path, o.Content[i], o.Content[i+1])
336+
if err != nil {
337+
return nil, err
338+
}
339+
340+
if o.Content[i].FootComment != "" {
341+
childNode.FootComment = goccyMarshalFootComment(o.Content[i].FootComment)
342+
}
343+
344+
values[i/2] = childNode
345+
if isFlowStyle && i < len(o.Content)/2-1 {
346+
m.PushToken(goccyToken.CollectEntry(",", &goccyToken.Position{}))
347+
}
348+
}
349+
350+
mapping.Values = values
351+
352+
if !isFlowStyle && len(values) > 0 {
353+
mapping.Start = values[0].Start
354+
}
355+
356+
if isFlowStyle {
357+
mapping.End = m.PushToken(goccyToken.MappingEnd("}", &goccyToken.Position{}))
358+
}
359+
360+
if o.FootComment != "" {
361+
mapping.FootComment = goccyMarshalFootComment(o.FootComment)
362+
}
363+
364+
return mapping, nil
365+
}
366+
367+
func (m *goccyMarshaller) marshalMappingValueNode(path string, keyNode, valueNode *CandidateNode) (*ast.MappingValueNode, error) {
368+
var key ast.MapKeyNode
369+
var err error
370+
key, err = m.marshalMapKeyNode(path, keyNode)
317371
if err != nil {
318372
return nil, err
319373
}
320374

321-
key, err := o.goccyMarshalScalar(path, v)
375+
separatorToken := m.PushToken(goccyToken.MappingValue(&goccyToken.Position{}))
376+
377+
value, err := m.Marshal(key.GetPath(), valueNode)
378+
if err != nil {
379+
return nil, err
380+
}
381+
382+
childNode := ast.MappingValue(
383+
separatorToken,
384+
key,
385+
value,
386+
)
387+
childNode.SetPath(key.GetPath())
388+
389+
return childNode, nil
390+
}
391+
392+
func goccyMarshalFootComment(comment string) *ast.CommentGroupNode {
393+
// TODO: Fix Tokens
394+
return ast.CommentGroup([]*goccyToken.Token{goccyToken.Comment(comment, comment, &goccyToken.Position{})})
395+
}
396+
397+
func (m *goccyMarshaller) marshalMapKeyNode(path string, o *CandidateNode) (ast.MapKeyNode, error) {
398+
if o.Kind != ScalarNode {
399+
return nil, fmt.Errorf("cannot unmarshal non-scalar node to MapKeyNode")
400+
}
401+
402+
key, err := m.marshalScalar(path, o)
322403
if err != nil {
323404
return nil, err
324405
}
@@ -327,30 +408,35 @@ func (o *CandidateNode) goccyMarshalMapKeyNode(path string) (ast.MapKeyNode, err
327408
return key, nil
328409
}
329410

330-
func (o *CandidateNode) goccyMarshalScalar(path string, v any) (ast.ScalarNode, error) {
331-
t := goccyToken.Literal(o.Value, o.Value, &goccyToken.Position{})
411+
func (m *goccyMarshaller) marshalScalar(path string, o *CandidateNode) (ast.ScalarNode, error) {
412+
v, err := o.GetValueRep()
413+
if err != nil {
414+
return nil, err
415+
}
416+
417+
scalarToken := m.PushToken(goccyToken.Literal(o.Value, o.Value, &goccyToken.Position{}))
332418

333419
if v == nil {
334-
n := ast.Null(t)
420+
n := ast.Null(scalarToken)
335421
n.SetPath(path)
336422
return n, nil
337423
}
338424

339425
switch av := v.(type) {
340426
case float64:
341-
n := ast.Float(t)
427+
n := ast.Float(scalarToken)
342428
n.Value = av
343429
return n, nil
344430
case int64:
345-
n := ast.Integer(t)
431+
n := ast.Integer(scalarToken)
346432
n.Value = av
347433
return n, nil
348434
case bool:
349-
n := ast.Bool(t)
435+
n := ast.Bool(scalarToken)
350436
n.Value = av
351437
return n, nil
352438
case string:
353-
n := ast.String(t)
439+
n := ast.String(scalarToken)
354440
n.SetPath(path)
355441
return n, nil
356442
}

pkg/yqlib/candidate_node_goccy_yaml_test.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"fmt"
55
"testing"
66

7+
"github.com/goccy/go-yaml/parser"
78
"gopkg.in/yaml.v3"
89
)
910

@@ -17,10 +18,15 @@ a:
1718
s:
1819
- 1
1920
- 2
21+
t: [5, five]
22+
f: [6, {y: true}]
2023
`
2124

25+
goccyAst, err := parser.ParseBytes([]byte(input), parser.ParseComments)
26+
fmt.Println(goccyAst)
27+
2228
var yamlNode yaml.Node
23-
err := yaml.Unmarshal([]byte(input), &yamlNode)
29+
err = yaml.Unmarshal([]byte(input), &yamlNode)
2430
if err != nil {
2531
t.Error(err)
2632
return
@@ -39,5 +45,12 @@ s:
3945
return
4046
}
4147

48+
parsed, err := parser.ParseBytes([]byte(input), parser.ParseComments)
49+
if err != nil {
50+
t.Error(err)
51+
return
52+
}
53+
54+
fmt.Println(parsed)
4255
fmt.Println(goccyNode)
4356
}

0 commit comments

Comments
 (0)