Skip to content

Commit fb4e5c8

Browse files
committed
feat(goccy): marshal back to goccy ast
1 parent 097a0bf commit fb4e5c8

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
@@ -180,82 +180,52 @@ func (o *CandidateNode) goccyProcessMappingValueNode(mappingEntry *ast.MappingVa
180180
return nil
181181
}
182182

183-
func (o *CandidateNode) goccyMarshalChild(path string) (ast.Node, error) {
184-
var node ast.Node
185-
switch o.Kind {
186-
case SequenceNode:
187-
values := make([]ast.Node, len(o.Content))
188-
for i, content := range o.Content {
189-
childNode, err := content.goccyMarshalChild(path + "[" + strconv.Itoa(i) + "]")
190-
if err != nil {
191-
return nil, err
192-
}
193-
194-
values[i] = childNode
195-
}
196-
197-
seq := ast.Sequence(
198-
goccyToken.SequenceStart(o.Value, &goccyToken.Position{}),
199-
o.Style == FlowStyle,
200-
)
201-
202-
seq.Values = values
203-
seq.ValueHeadComments = []*ast.CommentGroupNode{ast.CommentGroup([]*goccyToken.Token{goccyToken.Comment(o.HeadComment, o.HeadComment, &goccyToken.Position{})})}
204-
seq.FootComment = goccyMarshalFootComment(o.FootComment)
205-
node = seq
206-
case MappingNode:
207-
values := make([]*ast.MappingValueNode, len(o.Content)/2)
208-
for i := 0; i < len(o.Content); i += 2 {
209-
key, err := o.Content[i].goccyMarshalMapKeyNode(path)
210-
if err != nil {
211-
return nil, err
212-
}
183+
func (o *CandidateNode) MarshalGoccyYAML() (ast.Node, error) {
184+
marshaller := &goccyMarshaller{}
185+
return marshaller.Marshal("$", o)
186+
}
213187

214-
value, err := o.Content[i+1].goccyMarshalChild(key.GetPath())
215-
if err != nil {
216-
return nil, err
217-
}
188+
type goccyMarshaller struct {
189+
currentToken *goccyToken.Token
190+
}
218191

219-
childNode := ast.MappingValue(
220-
goccyToken.MappingValue(&goccyToken.Position{}),
221-
key,
222-
value,
223-
)
224-
childNode.SetPath(key.GetPath())
225-
if o.Content[i].FootComment != "" {
226-
childNode.FootComment = goccyMarshalFootComment(o.Content[i].FootComment)
227-
}
192+
func (m *goccyMarshaller) PushToken(t *goccyToken.Token) *goccyToken.Token {
193+
if m.currentToken == nil {
194+
m.currentToken = t
195+
return m.currentToken
196+
}
228197

229-
values[i/2] = childNode
230-
}
198+
m.currentToken.Next = t
199+
t.Prev = m.currentToken
200+
m.currentToken = t
231201

232-
mapping := ast.Mapping(goccyToken.MappingStart("", &goccyToken.Position{}), o.Style == FlowStyle, values...)
233-
if o.FootComment != "" {
234-
mapping.FootComment = goccyMarshalFootComment(o.FootComment)
235-
}
202+
return m.currentToken
203+
}
236204

237-
node = mapping
238-
case ScalarNode:
239-
v, err := o.GetValueRep()
205+
func (m *goccyMarshaller) Marshal(path string, o *CandidateNode) (ast.Node, error) {
206+
var node ast.Node
207+
var err error
208+
switch o.Kind {
209+
case AliasNode:
210+
node, err = m.marshalAlias(path, o)
240211
if err != nil {
241212
return nil, err
242213
}
243-
244-
node, err = o.goccyMarshalScalar(path, v)
214+
case ScalarNode:
215+
node, err = m.marshalScalar(path, o)
245216
if err != nil {
246217
return nil, err
247218
}
248-
case AliasNode:
249-
value, err := o.Content[0].goccyMarshalChild(path)
219+
case SequenceNode:
220+
node, err = m.marshalSequence(path, o)
250221
if err != nil {
251222
return nil, err
252223
}
253-
254-
alias := ast.Alias(goccyToken.Alias(o.Value, &goccyToken.Position{}))
255-
alias.Value = value
256-
node = alias
224+
case MappingNode:
225+
node, err = m.marshalMapping(path, o)
257226
}
258227

228+
// TODO: Fix Tag and Anchor tokens
259229
if o.Tag != "" && !strings.HasPrefix(o.Tag, "!!") {
260230
tag := ast.Tag(goccyToken.Tag(o.Tag, o.Tag, &goccyToken.Position{}))
261231
tag.Value = node
@@ -273,25 +243,136 @@ func (o *CandidateNode) goccyMarshalChild(path string) (ast.Node, error) {
273243
return node, nil
274244
}
275245

276-
func (o *CandidateNode) MarshalGoccyYAML() (ast.Node, error) {
277-
return o.goccyMarshalChild("$")
246+
func (m *goccyMarshaller) marshalAlias(path string, o *CandidateNode) (ast.Node, error) {
247+
t := m.PushToken(goccyToken.Alias(o.Value, &goccyToken.Position{}))
248+
var value ast.Node
249+
var err error
250+
value, err = m.Marshal(path, o.Content[0])
251+
if err != nil {
252+
return nil, err
253+
}
254+
255+
alias := ast.Alias(t)
256+
alias.Value = value
257+
return alias, nil
278258
}
279259

280-
func goccyMarshalFootComment(comment string) *ast.CommentGroupNode {
281-
return ast.CommentGroup([]*goccyToken.Token{goccyToken.Comment(comment, comment, &goccyToken.Position{})})
260+
func (m *goccyMarshaller) marshalSequence(path string, o *CandidateNode) (ast.Node, error) {
261+
isFlowStyle := o.Style == FlowStyle
262+
seq := ast.Sequence(
263+
nil,
264+
isFlowStyle,
265+
)
266+
267+
if isFlowStyle {
268+
seq.Start = m.PushToken(goccyToken.SequenceStart("[", &goccyToken.Position{}))
269+
}
270+
271+
var err error
272+
values := make([]ast.Node, len(o.Content))
273+
for i, content := range o.Content {
274+
m.PushToken(goccyToken.SequenceEntry("-", &goccyToken.Position{}))
275+
values[i], err = m.Marshal(path+"["+strconv.Itoa(i)+"]", content)
276+
if err != nil {
277+
return nil, err
278+
}
279+
280+
if isFlowStyle && i < len(o.Content)-1 {
281+
m.PushToken(goccyToken.CollectEntry(",", &goccyToken.Position{}))
282+
}
283+
}
284+
285+
if isFlowStyle {
286+
seq.End = m.PushToken(goccyToken.SequenceEnd("]", &goccyToken.Position{}))
287+
}
288+
289+
seq.Values = values
290+
seq.ValueHeadComments = []*ast.CommentGroupNode{ast.CommentGroup([]*goccyToken.Token{goccyToken.Comment(o.HeadComment, o.HeadComment, &goccyToken.Position{})})}
291+
seq.FootComment = goccyMarshalFootComment(o.FootComment)
292+
293+
return seq, nil
282294
}
283295

284-
func (o *CandidateNode) goccyMarshalMapKeyNode(path string) (ast.MapKeyNode, error) {
285-
if o.Kind != ScalarNode {
286-
return nil, fmt.Errorf("cannot unmarshal non-scalar node to MapKeyNode")
296+
func (m *goccyMarshaller) marshalMapping(path string, o *CandidateNode) (ast.Node, error) {
297+
isFlowStyle := o.Style == FlowStyle
298+
mapping := ast.Mapping(nil, isFlowStyle)
299+
300+
if isFlowStyle {
301+
mapping.Start = m.PushToken(goccyToken.MappingStart("{", &goccyToken.Position{}))
287302
}
288303

289-
v, err := o.GetValueRep()
304+
values := make([]*ast.MappingValueNode, len(o.Content)/2)
305+
var err error
306+
for i := 0; i < len(o.Content); i += 2 {
307+
var childNode *ast.MappingValueNode
308+
childNode, err = m.marshalMappingValueNode(path, o.Content[i], o.Content[i+1])
309+
if err != nil {
310+
return nil, err
311+
}
312+
313+
if o.Content[i].FootComment != "" {
314+
childNode.FootComment = goccyMarshalFootComment(o.Content[i].FootComment)
315+
}
316+
317+
values[i/2] = childNode
318+
if isFlowStyle && i < len(o.Content)/2-1 {
319+
m.PushToken(goccyToken.CollectEntry(",", &goccyToken.Position{}))
320+
}
321+
}
322+
323+
mapping.Values = values
324+
325+
if !isFlowStyle && len(values) > 0 {
326+
mapping.Start = values[0].Start
327+
}
328+
329+
if isFlowStyle {
330+
mapping.End = m.PushToken(goccyToken.MappingEnd("}", &goccyToken.Position{}))
331+
}
332+
333+
if o.FootComment != "" {
334+
mapping.FootComment = goccyMarshalFootComment(o.FootComment)
335+
}
336+
337+
return mapping, nil
338+
}
339+
340+
func (m *goccyMarshaller) marshalMappingValueNode(path string, keyNode, valueNode *CandidateNode) (*ast.MappingValueNode, error) {
341+
var key ast.MapKeyNode
342+
var err error
343+
key, err = m.marshalMapKeyNode(path, keyNode)
290344
if err != nil {
291345
return nil, err
292346
}
293347

294-
key, err := o.goccyMarshalScalar(path, v)
348+
separatorToken := m.PushToken(goccyToken.MappingValue(&goccyToken.Position{}))
349+
350+
value, err := m.Marshal(key.GetPath(), valueNode)
351+
if err != nil {
352+
return nil, err
353+
}
354+
355+
childNode := ast.MappingValue(
356+
separatorToken,
357+
key,
358+
value,
359+
)
360+
childNode.SetPath(key.GetPath())
361+
362+
return childNode, nil
363+
}
364+
365+
func goccyMarshalFootComment(comment string) *ast.CommentGroupNode {
366+
// TODO: Fix Tokens
367+
return ast.CommentGroup([]*goccyToken.Token{goccyToken.Comment(comment, comment, &goccyToken.Position{})})
368+
}
369+
370+
func (m *goccyMarshaller) marshalMapKeyNode(path string, o *CandidateNode) (ast.MapKeyNode, error) {
371+
if o.Kind != ScalarNode {
372+
return nil, fmt.Errorf("cannot unmarshal non-scalar node to MapKeyNode")
373+
}
374+
375+
key, err := m.marshalScalar(path, o)
295376
if err != nil {
296377
return nil, err
297378
}
@@ -300,30 +381,35 @@ func (o *CandidateNode) goccyMarshalMapKeyNode(path string) (ast.MapKeyNode, err
300381
return key, nil
301382
}
302383

303-
func (o *CandidateNode) goccyMarshalScalar(path string, v any) (ast.ScalarNode, error) {
304-
t := goccyToken.Literal(o.Value, o.Value, &goccyToken.Position{})
384+
func (m *goccyMarshaller) marshalScalar(path string, o *CandidateNode) (ast.ScalarNode, error) {
385+
v, err := o.GetValueRep()
386+
if err != nil {
387+
return nil, err
388+
}
389+
390+
scalarToken := m.PushToken(goccyToken.Literal(o.Value, o.Value, &goccyToken.Position{}))
305391

306392
if v == nil {
307-
n := ast.Null(t)
393+
n := ast.Null(scalarToken)
308394
n.SetPath(path)
309395
return n, nil
310396
}
311397

312398
switch av := v.(type) {
313399
case float64:
314-
n := ast.Float(t)
400+
n := ast.Float(scalarToken)
315401
n.Value = av
316402
return n, nil
317403
case int64:
318-
n := ast.Integer(t)
404+
n := ast.Integer(scalarToken)
319405
n.Value = av
320406
return n, nil
321407
case bool:
322-
n := ast.Bool(t)
408+
n := ast.Bool(scalarToken)
323409
n.Value = av
324410
return n, nil
325411
case string:
326-
n := ast.String(t)
412+
n := ast.String(scalarToken)
327413
n.SetPath(path)
328414
return n, nil
329415
}

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)