diff --git a/datamodel/low/v3/constants.go b/datamodel/low/v3/constants.go index 8f75098..90d0bf6 100644 --- a/datamodel/low/v3/constants.go +++ b/datamodel/low/v3/constants.go @@ -41,4 +41,5 @@ const ( DescriptionLabel = "description" URLLabel = "url" NameLabel = "name" + EmailLabel = "email" ) diff --git a/what-changed/contact.go b/what-changed/contact.go new file mode 100644 index 0000000..40d2a56 --- /dev/null +++ b/what-changed/contact.go @@ -0,0 +1,79 @@ +// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley +// SPDX-License-Identifier: MIT + +package what_changed + +import ( + lowbase "github.com/pb33f/libopenapi/datamodel/low/base" + lowv3 "github.com/pb33f/libopenapi/datamodel/low/v3" +) + +type ContactChanges struct { + PropertyChanges[*lowbase.Contact] +} + +func (c *ContactChanges) TotalChanges() int { + return len(c.Changes) +} + +func CompareContact(l, r *lowbase.Contact) *ContactChanges { + + var changes []*Change[*lowbase.Contact] + changeType := 0 + + // check if the url was added + if l != nil && r != nil && l.URL.Value == "" && r.URL.Value != "" { + changeType = PropertyAdded + CreateChange[*lowbase.Contact](&changes, changeType, lowv3.URLLabel, + nil, r.Name.ValueNode, false, l, r) + } + + // check if the name was added + if l != nil && r != nil && l.Name.Value == "" && r.Name.Value != "" { + changeType = PropertyAdded + CreateChange[*lowbase.Contact](&changes, changeType, lowv3.NameLabel, + nil, r.Name.ValueNode, false, l, r) + } + + // if both urls are set, but are different. + if l != nil && r != nil && l.URL.Value != r.URL.Value { + changeType = Modified + ctx := CreateContext(l.URL.ValueNode, r.URL.ValueNode) + if ctx.HasChanged() { + changeType = ModifiedAndMoved + } + CreateChange(&changes, changeType, lowv3.URLLabel, + l.URL.ValueNode, r.Name.ValueNode, false, l, r) + } + + // if both names are set, but are different. + if l != nil && r != nil && l.Name.Value != r.Name.Value { + changeType = Modified + ctx := CreateContext(l.Name.ValueNode, r.Name.ValueNode) + if ctx.HasChanged() { + changeType = ModifiedAndMoved + } + CreateChange[*lowbase.Contact](&changes, changeType, lowv3.NameLabel, + l.Name.ValueNode, r.Name.ValueNode, false, l, r) + } + + // if both email addresses are set, but are different. + if l != nil && r != nil && l.Email.Value != r.Email.Value { + changeType = Modified + ctx := CreateContext(l.Email.ValueNode, r.Email.ValueNode) + if ctx.HasChanged() { + changeType = ModifiedAndMoved + } + CreateChange[*lowbase.Contact](&changes, changeType, lowv3.EmailLabel, + l.Email.ValueNode, r.Email.ValueNode, false, l, r) + } + + if changeType == 0 { + // no change, return nothing. + return nil + } + dc := new(ContactChanges) + dc.Changes = changes + return dc + +} diff --git a/what-changed/extensions.go b/what-changed/extensions.go index c84289e..631cc72 100644 --- a/what-changed/extensions.go +++ b/what-changed/extensions.go @@ -4,13 +4,12 @@ package what_changed import ( - "fmt" "github.com/pb33f/libopenapi/datamodel/low" "strings" ) type ExtensionChanges struct { - PropertyChanges + PropertyChanges[any] } func CompareExtensions(l, r map[low.KeyReference[string]]low.ValueReference[any]) *ExtensionChanges { @@ -27,24 +26,16 @@ func CompareExtensions(l, r map[low.KeyReference[string]]low.ValueReference[any] seenRight[strings.ToLower(i.Value)] = &h } - var changes []*Change - var changeType int + var changes []*Change[any] for i := range seenLeft { - changeType = 0 if seenRight[i] == nil { // deleted - changeType = PropertyRemoved - ctx := CreateContext(seenLeft[i].ValueNode, nil) - changes = append(changes, &Change{ - Context: ctx, - ChangeType: changeType, - Property: i, - Original: fmt.Sprintf("%v", seenLeft[i].Value), - }) + CreateChange[any](&changes, PropertyRemoved, i, seenLeft[i].ValueNode, nil, false, l, nil) } if seenRight[i] != nil { // potentially modified and or moved + var changeType int ctx := CreateContext(seenLeft[i].ValueNode, seenRight[i].ValueNode) if seenLeft[i].Value != seenRight[i].Value { changeType = Modified @@ -57,26 +48,14 @@ func CompareExtensions(l, r map[low.KeyReference[string]]low.ValueReference[any] } } if changeType != 0 { - changes = append(changes, &Change{ - Context: ctx, - ChangeType: changeType, - Property: i, - Original: fmt.Sprintf("%v", seenLeft[i].Value), - New: fmt.Sprintf("%v", seenRight[i].Value), - }) + CreateChange[any](&changes, changeType, i, seenLeft[i].ValueNode, seenRight[i].ValueNode, false, l, r) } } } for i := range seenRight { if seenLeft[i] == nil { // added - ctx := CreateContext(nil, seenRight[i].ValueNode) - changes = append(changes, &Change{ - Context: ctx, - ChangeType: PropertyAdded, - Property: i, - New: fmt.Sprintf("%v", seenRight[i].Value), - }) + CreateChange[any](&changes, PropertyAdded, i, nil, seenRight[i].ValueNode, false, nil, r) } } diff --git a/what-changed/external_docs.go b/what-changed/external_docs.go index e01aeb2..6d7bd26 100644 --- a/what-changed/external_docs.go +++ b/what-changed/external_docs.go @@ -10,7 +10,7 @@ import ( ) type ExternalDocChanges struct { - PropertyChanges + PropertyChanges[*lowbase.ExternalDoc] ExtensionChanges *ExtensionChanges } @@ -23,7 +23,7 @@ func (e *ExternalDocChanges) TotalChanges() int { } func CompareExternalDocs(l, r *lowbase.ExternalDoc) *ExternalDocChanges { - var changes []*Change + var changes []*Change[*lowbase.ExternalDoc] changeType := 0 if l != nil && r != nil && l.URL.Value != r.URL.Value { changeType = Modified @@ -31,13 +31,8 @@ func CompareExternalDocs(l, r *lowbase.ExternalDoc) *ExternalDocChanges { if ctx.HasChanged() { changeType = ModifiedAndMoved } - changes = append(changes, &Change{ - Context: ctx, - ChangeType: changeType, - Property: lowv3.URLLabel, - Original: l.URL.Value, - New: r.URL.Value, - }) + CreateChange[*lowbase.ExternalDoc](&changes, changeType, lowv3.URLLabel, l.URL.ValueNode, + r.URL.ValueNode, false, l, r) } if l != nil && r != nil && l.Description.Value != r.Description.Value { changeType = Modified @@ -45,13 +40,8 @@ func CompareExternalDocs(l, r *lowbase.ExternalDoc) *ExternalDocChanges { if ctx.HasChanged() { changeType = ModifiedAndMoved } - changes = append(changes, &Change{ - Context: ctx, - ChangeType: changeType, - Property: lowv3.DescriptionLabel, - Original: l.Description.Value, - New: r.Description.Value, - }) + CreateChange[*lowbase.ExternalDoc](&changes, changeType, lowv3.DescriptionLabel, l.Description.ValueNode, + r.Description.ValueNode, false, l, r) } if changeType == 0 { // no change, return nothing. diff --git a/what-changed/tags.go b/what-changed/tags.go index 3503ae2..8e89ca5 100644 --- a/what-changed/tags.go +++ b/what-changed/tags.go @@ -4,7 +4,6 @@ package what_changed import ( - "fmt" "github.com/pb33f/libopenapi/datamodel/low" lowbase "github.com/pb33f/libopenapi/datamodel/low/base" lowv3 "github.com/pb33f/libopenapi/datamodel/low/v3" @@ -12,7 +11,7 @@ import ( ) type TagChanges struct { - PropertyChanges + PropertyChanges[*lowbase.Tag] ExternalDocs *ExternalDocChanges ExtensionChanges *ExtensionChanges } @@ -43,22 +42,14 @@ func CompareTags(l, r []low.ValueReference[*lowbase.Tag]) *TagChanges { seenRight[strings.ToLower(r[i].Value.Name.Value)] = &h } - var changes []*Change - var changeType int + var changes []*Change[*lowbase.Tag] // check for removals, modifications and moves for i := range seenLeft { - changeType = 0 if seenRight[i] == nil { // deleted - changeType = ObjectRemoved - ctx := CreateContext(seenLeft[i].ValueNode, nil) - changes = append(changes, &Change{ - Context: ctx, - ChangeType: changeType, - Property: i, - Original: fmt.Sprintf("%v", seenLeft[i].Value), - }) + CreateChange[*lowbase.Tag](&changes, ObjectRemoved, i, seenLeft[i].ValueNode, nil, + false, seenLeft[i].Value, nil) continue } @@ -68,45 +59,32 @@ func CompareTags(l, r []low.ValueReference[*lowbase.Tag]) *TagChanges { // check if name has moved ctx := CreateContext(seenLeft[i].Value.Name.ValueNode, seenRight[i].Value.Name.ValueNode) if ctx.HasChanged() { - changeType = Moved - changes = append(changes, &Change{ - Context: ctx, - ChangeType: changeType, - Property: lowv3.NameLabel, - Original: seenLeft[i].Value.Name.Value, - New: seenRight[i].Value.Name.Value, - }) + CreateChange[*lowbase.Tag](&changes, Moved, lowv3.NameLabel, + seenLeft[i].Value.Name.ValueNode, seenRight[i].Value.Name.ValueNode, + false, seenLeft[i].Value, seenRight[i].Value) + } // check if description has been modified if seenLeft[i].Value.Description.Value != seenRight[i].Value.Description.Value { + var changeType int changeType = Modified ctx = CreateContext(seenLeft[i].Value.Description.ValueNode, seenRight[i].Value.Description.ValueNode) if ctx.HasChanged() { changeType = ModifiedAndMoved } - changes = append(changes, &Change{ - Context: ctx, - ChangeType: changeType, - Property: lowv3.DescriptionLabel, - Original: seenLeft[i].Value.Description.Value, - New: seenRight[i].Value.Description.Value, - }) - + CreateChange[*lowbase.Tag](&changes, changeType, lowv3.DescriptionLabel, + seenLeft[i].Value.Description.ValueNode, seenRight[i].Value.Description.ValueNode, + false, seenLeft[i].Value, seenRight[i].Value) } // check if description has moved if seenLeft[i].Value.Description.Value == seenRight[i].Value.Description.Value { ctx = CreateContext(seenLeft[i].Value.Description.ValueNode, seenRight[i].Value.Description.ValueNode) if ctx.HasChanged() { - changeType = Moved - changes = append(changes, &Change{ - Context: ctx, - ChangeType: changeType, - Property: lowv3.DescriptionLabel, - Original: seenLeft[i].Value.Description.Value, - New: seenRight[i].Value.Description.Value, - }) + CreateChange[*lowbase.Tag](&changes, Moved, lowv3.DescriptionLabel, + seenLeft[i].Value.Description.ValueNode, seenRight[i].Value.Description.ValueNode, + false, seenLeft[i].Value, seenRight[i].Value) } } @@ -130,13 +108,9 @@ func CompareTags(l, r []low.ValueReference[*lowbase.Tag]) *TagChanges { for i := range seenRight { if seenLeft[i] == nil { // added - ctx := CreateContext(nil, seenRight[i].ValueNode) - changes = append(changes, &Change{ - Context: ctx, - ChangeType: ObjectAdded, - Property: i, - New: fmt.Sprintf("%v", seenRight[i].Value), - }) + CreateChange[*lowbase.Tag](&changes, ObjectAdded, i, + nil, seenRight[i].ValueNode, + false, nil, seenRight[i].Value) } } if len(changes) <= 0 { diff --git a/what-changed/what_changed.go b/what-changed/what_changed.go index a8378ee..b19a4f8 100644 --- a/what-changed/what_changed.go +++ b/what-changed/what_changed.go @@ -37,22 +37,47 @@ func (c *ChangeContext) HasChanged() bool { return c.NewLine != c.OrigLine || c.NewCol != c.OrigCol } -type Change struct { - Context *ChangeContext - ChangeType int - Property string - Original string - New string +type Change[T any] struct { + Context *ChangeContext + ChangeType int + Property string + Original string + New string + Breaking bool + OriginalObject T + NewObject T } -type PropertyChanges struct { - Changes []*Change +type PropertyChanges[T any] struct { + Changes []*Change[T] } type Changes struct { TagChanges *TagChanges } +func CreateChange[T any](changes *[]*Change[T], changeType int, property string, leftValueNode, rightValueNode *yaml.Node, + breaking bool, originalObject, newObject T) *[]*Change[T] { + + ctx := CreateContext(leftValueNode, rightValueNode) + c := &Change[T]{ + Context: ctx, + ChangeType: changeType, + Property: property, + Breaking: breaking, + } + if leftValueNode != nil && leftValueNode.Value != "" { + c.Original = leftValueNode.Value + } + if rightValueNode != nil && rightValueNode.Value != "" { + c.New = rightValueNode.Value + } + c.OriginalObject = originalObject + c.NewObject = newObject + *changes = append(*changes, c) + return changes +} + //func WhatChangedBetweenDocuments(leftDocument, rightDocument *lowv3.Document) *WhatChanged { // // // compare tags @@ -80,93 +105,3 @@ func CreateContext(l, r *yaml.Node) *ChangeContext { } return ctx } - -// -//func compareTags(l, r []low.ValueReference[*lowbase.Tag]) *TagChanges { -// -// tc := new(TagChanges) -// -// // look at the original and then look through the new. -// seenLeft := make(map[string]*low.ValueReference[*lowbase.Tag]) -// seenRight := make(map[string]*low.ValueReference[*lowbase.Tag]) -// for i := range l { -// seenLeft[strings.ToLower(l[i].Value.Name.Value)] = &l[i] -// } -// for i := range r { -// seenRight[strings.ToLower(l[i].Value.Name.Value)] = &l[i] -// } -// -// for i := range seenLeft { -// if seenRight[i] == nil { -// // deleted -// //ctx := CreateContext(seenLeft[i].ValueNode, nil) -// //tc.Changes = -// -// } -// if seenRight[i] != nil { -// -// // potentially modified and or moved -// } -// } -// -// for i := range seenRight { -// if seenLeft[i] == nil { -// // added -// } -// } -// -// for i := range r { -// // if we find a match -// t := r[i] -// name := r[i].Value.Name.Value -// found := seenLeft[strings.ToLower(name)] -// if found.Value != nil { -// -// // check values -// if found.Value.Description.Value != t.Value.Description.Value { -// ctx := CreateContext(found.ValueNode, t.ValueNode) -// changeType := Modified -// if ctx.HasChanged() { -// changeType = ModifiedAndMoved -// } -// tc.Changes = append(tc.Changes, &Change{ -// Context: ctx, -// ChangeType: changeType, -// Property: lowv3.DescriptionLabel, -// Original: found.Value.Description.Value, -// New: t.Value.Description.Value, -// }) -// } -// -// } else { -// -// // new stuff -// -// } -// -// } -// -// // more tags in right hand-side -// if len(r) > len(l) { -// -// } -// -// // less tags in right hand-side -// if len(r) < len(l) { -// -// } -// -// //for i := range a { -// // eq, l, c := comparePositions(a) -// // -// //} -// -// return nil -//} -// -//func comparePositions(left, right *yaml.Node) (bool, int, int) { -// if left.Line == right.Line && left.Column == right.Column { -// return true, 0, 0 -// } -// return false, right.Line, right.Column -//}