mirror of
https://github.com/LukeHagar/libopenapi.git
synced 2025-12-06 04:20:11 +00:00
Added mutate command to low level API
This simple method gives the low API a super powerful and simple way to mutate the value of any node, which is then reflected in the root node, can than be serialized again and, voila! now our spec is editable.
This commit is contained in:
@@ -40,6 +40,10 @@ func (n NodeReference[T]) GenerateMapKey() string {
|
||||
return fmt.Sprintf("%d:%d", n.ValueNode.Line, n.ValueNode.Column)
|
||||
}
|
||||
|
||||
func (n NodeReference[T]) Mutate(value T) {
|
||||
n.ValueNode.Value = fmt.Sprintf("%v", value)
|
||||
}
|
||||
|
||||
func (n ValueReference[T]) IsEmpty() bool {
|
||||
return n.ValueNode == nil
|
||||
}
|
||||
@@ -56,6 +60,10 @@ func (n KeyReference[T]) GenerateMapKey() string {
|
||||
return fmt.Sprintf("%d:%d", n.KeyNode.Line, n.KeyNode.Column)
|
||||
}
|
||||
|
||||
func (n ValueReference[T]) Mutate(value T) {
|
||||
n.ValueNode.Value = fmt.Sprintf("%v", value)
|
||||
}
|
||||
|
||||
func IsCircular(node *yaml.Node, idx *index.SpecIndex) bool {
|
||||
if idx == nil {
|
||||
return false // no index! nothing we can do.
|
||||
|
||||
@@ -13,6 +13,11 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
JSONFileType = "json"
|
||||
YAMLFileType = "yaml"
|
||||
)
|
||||
|
||||
// SpecInfo represents a 'ready-to-process' OpenAPI Document.
|
||||
type SpecInfo struct {
|
||||
SpecType string `json:"type"`
|
||||
@@ -59,9 +64,9 @@ func ExtractSpecInfo(spec []byte) (*SpecInfo, error) {
|
||||
}
|
||||
|
||||
if runes[0] == '{' && runes[len(runes)-1] == '}' {
|
||||
specVersion.SpecFileType = "json"
|
||||
specVersion.SpecFileType = JSONFileType
|
||||
} else {
|
||||
specVersion.SpecFileType = "yaml"
|
||||
specVersion.SpecFileType = YAMLFileType
|
||||
}
|
||||
|
||||
err := yaml.Unmarshal(spec, &parsedSpec)
|
||||
|
||||
14
document.go
14
document.go
@@ -10,6 +10,8 @@ import (
|
||||
v3high "github.com/pb33f/libopenapi/datamodel/high/3.0"
|
||||
v2low "github.com/pb33f/libopenapi/datamodel/low/2.0"
|
||||
v3low "github.com/pb33f/libopenapi/datamodel/low/3.0"
|
||||
"github.com/pb33f/libopenapi/utils"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type Document struct {
|
||||
@@ -40,6 +42,18 @@ func (d *Document) GetSpecInfo() *datamodel.SpecInfo {
|
||||
return d.info
|
||||
}
|
||||
|
||||
func (d *Document) Serialize() ([]byte, error) {
|
||||
if d.info == nil {
|
||||
return nil, fmt.Errorf("unable to serialize, document has not yet been initialized")
|
||||
}
|
||||
if d.info.SpecFileType == datamodel.YAMLFileType {
|
||||
return yaml.Marshal(d.info.RootNode)
|
||||
} else {
|
||||
yamlData, _ := yaml.Marshal(d.info.RootNode)
|
||||
return utils.ConvertYAMLtoJSON(yamlData)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Document) BuildV2Document() (*DocumentModel[v2high.Swagger], []error) {
|
||||
var errors []error
|
||||
if d.info == nil {
|
||||
|
||||
@@ -106,3 +106,63 @@ paths:
|
||||
assert.Len(t, docErr, 1)
|
||||
assert.Nil(t, v3Doc)
|
||||
}
|
||||
|
||||
func TestDocument_Serialize_Error(t *testing.T) {
|
||||
doc := new(Document) // not how this should be instantiated.
|
||||
_, err := doc.Serialize()
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestDocument_Serialize(t *testing.T) {
|
||||
|
||||
yml := `openapi: 3.0
|
||||
info:
|
||||
title: The magic API
|
||||
`
|
||||
doc, _ := NewDocument([]byte(yml))
|
||||
serial, err := doc.Serialize()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, yml, string(serial))
|
||||
}
|
||||
|
||||
func TestDocument_Serialize_Modified(t *testing.T) {
|
||||
|
||||
yml := `openapi: 3.0
|
||||
info:
|
||||
title: The magic API
|
||||
`
|
||||
|
||||
ymlModified := `openapi: 3.0
|
||||
info:
|
||||
title: The magic API - but now, altered!
|
||||
`
|
||||
doc, _ := NewDocument([]byte(yml))
|
||||
|
||||
v3Doc, _ := doc.BuildV3Document()
|
||||
|
||||
v3Doc.Model.Info.GoLow().Title.Mutate("The magic API - but now, altered!")
|
||||
|
||||
serial, err := doc.Serialize()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, ymlModified, string(serial))
|
||||
}
|
||||
|
||||
func TestDocument_Serialize_JSON_Modified(t *testing.T) {
|
||||
|
||||
json := `{ 'openapi': '3.0',
|
||||
'info': {
|
||||
'title': 'The magic API'
|
||||
}
|
||||
}
|
||||
`
|
||||
jsonModified := `{"info":{"title":"The magic API - but now, altered!"},"openapi":"3.0"}`
|
||||
doc, _ := NewDocument([]byte(json))
|
||||
|
||||
v3Doc, _ := doc.BuildV3Document()
|
||||
|
||||
v3Doc.Model.Info.GoLow().Title.Mutate("The magic API - but now, altered!")
|
||||
|
||||
serial, err := doc.Serialize()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, jsonModified, string(serial))
|
||||
}
|
||||
|
||||
@@ -1,51 +1,41 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/pb33f/libopenapi/datamodel"
|
||||
high "github.com/pb33f/libopenapi/datamodel/high/3.0"
|
||||
low "github.com/pb33f/libopenapi/datamodel/low/3.0"
|
||||
"gopkg.in/yaml.v3"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
testData := `openapi: 3.0.1
|
||||
info:
|
||||
title: this is a title
|
||||
description: this is a description
|
||||
tags:
|
||||
- name: Tag A
|
||||
description: cake
|
||||
x-hack: true
|
||||
- name: Tag B
|
||||
description: coffee
|
||||
x-code: hack`
|
||||
|
||||
data := []byte(testData)
|
||||
_ = ioutil.WriteFile("sample.yaml", data, 0664)
|
||||
|
||||
info, _ := datamodel.ExtractSpecInfo(data)
|
||||
lowDoc, err := low.CreateDocument(info)
|
||||
if len(err) > 0 {
|
||||
for e := range err {
|
||||
fmt.Printf("%e\n", err[e])
|
||||
}
|
||||
return
|
||||
}
|
||||
highDoc := high.NewDocument(lowDoc)
|
||||
|
||||
highDoc.Info.GoLow().Title.ValueNode.Value = "let's hack this"
|
||||
//highDoc.Tags[0].SetName("We are a new name now")
|
||||
//highDoc.Tags[0].SetDescription("and a new description")
|
||||
|
||||
//newTag := lowDoc.AddTag()
|
||||
//fmt.Println(newTag)
|
||||
modified, _ := yaml.Marshal(info.RootNode)
|
||||
fmt.Println(string(modified))
|
||||
|
||||
os.Remove("sample.yaml")
|
||||
|
||||
}
|
||||
//func main() {
|
||||
//
|
||||
// testData := `openapi: 3.0.1
|
||||
//info:
|
||||
// title: this is a title
|
||||
// description: this is a description
|
||||
//tags:
|
||||
// - name: Tag A
|
||||
// description: cake
|
||||
// x-hack: true
|
||||
// - name: Tag B
|
||||
// description: coffee
|
||||
// x-code: hack`
|
||||
//
|
||||
// data := []byte(testData)
|
||||
// _ = ioutil.WriteFile("sample.yaml", data, 0664)
|
||||
//
|
||||
// info, _ := datamodel.ExtractSpecInfo(data)
|
||||
// lowDoc, err := low.CreateDocument(info)
|
||||
// if len(err) > 0 {
|
||||
// for e := range err {
|
||||
// fmt.Printf("%e\n", err[e])
|
||||
// }
|
||||
// return
|
||||
// }
|
||||
// highDoc := high.NewDocument(lowDoc)
|
||||
//
|
||||
// highDoc.Info.GoLow().Title.ValueNode.Value = "let's hack this"
|
||||
// //highDoc.Tags[0].SetName("We are a new name now")
|
||||
// //highDoc.Tags[0].SetDescription("and a new description")
|
||||
//
|
||||
// //newTag := lowDoc.AddTag()
|
||||
// //fmt.Println(newTag)
|
||||
// modified, _ := yaml.Marshal(info.RootNode)
|
||||
// fmt.Println(string(modified))
|
||||
//
|
||||
// os.Remove("sample.yaml")
|
||||
//
|
||||
//}
|
||||
|
||||
Reference in New Issue
Block a user