diff --git a/datamodel/low/reference.go b/datamodel/low/reference.go index b0b2636..2ae2580 100644 --- a/datamodel/low/reference.go +++ b/datamodel/low/reference.go @@ -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. diff --git a/datamodel/spec_info.go b/datamodel/spec_info.go index ed0d141..6f1a536 100644 --- a/datamodel/spec_info.go +++ b/datamodel/spec_info.go @@ -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) diff --git a/document.go b/document.go index 2084df6..28f297d 100644 --- a/document.go +++ b/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 { diff --git a/document_test.go b/document_test.go index 6643d88..f4c8101 100644 --- a/document_test.go +++ b/document_test.go @@ -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)) +} diff --git a/libopenapi.go b/libopenapi.go index 1bb36d8..320b093 100644 --- a/libopenapi.go +++ b/libopenapi.go @@ -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") +// +//}