mirror of
https://github.com/LukeHagar/libopenapi.git
synced 2025-12-06 12:37:49 +00:00
200 lines
5.0 KiB
Go
200 lines
5.0 KiB
Go
// Copyright 2022 Princess B33f Heavy Industries / Dave Shanley
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package what_changed
|
|
|
|
import (
|
|
"github.com/pb33f/libopenapi/datamodel/low"
|
|
"gopkg.in/yaml.v3"
|
|
)
|
|
|
|
const (
|
|
Modified = iota + 1
|
|
PropertyAdded
|
|
ObjectAdded
|
|
ObjectRemoved
|
|
PropertyRemoved
|
|
Moved
|
|
ModifiedAndMoved
|
|
)
|
|
|
|
type WhatChanged struct {
|
|
Added int
|
|
Removed int
|
|
Modified int
|
|
Moved int
|
|
TotalChanges int
|
|
Changes *Changes
|
|
}
|
|
|
|
type ChangeContext struct {
|
|
OrigLine int
|
|
OrigCol int
|
|
NewLine int
|
|
NewCol int
|
|
}
|
|
|
|
func (c *ChangeContext) HasChanged() bool {
|
|
return c.NewLine != c.OrigLine || c.NewCol != c.OrigCol
|
|
}
|
|
|
|
type Change[T any] struct {
|
|
Context *ChangeContext
|
|
ChangeType int
|
|
Property string
|
|
Original string
|
|
New string
|
|
Breaking bool
|
|
OriginalObject T
|
|
NewObject T
|
|
}
|
|
|
|
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 CreateContext(l, r *yaml.Node) *ChangeContext {
|
|
ctx := new(ChangeContext)
|
|
if l != nil {
|
|
ctx.OrigLine = l.Line
|
|
ctx.OrigCol = l.Column
|
|
} else {
|
|
ctx.OrigLine = -1
|
|
ctx.OrigCol = -1
|
|
}
|
|
if r != nil {
|
|
ctx.NewLine = r.Line
|
|
ctx.NewCol = r.Column
|
|
} else {
|
|
ctx.NewLine = -1
|
|
ctx.NewCol = -1
|
|
}
|
|
return ctx
|
|
}
|
|
|
|
type PropertyCheck[T any] struct {
|
|
Original T
|
|
New T
|
|
Label string
|
|
LeftNode *yaml.Node
|
|
RightNode *yaml.Node
|
|
Breaking bool
|
|
Changes *[]*Change[T]
|
|
}
|
|
|
|
func CheckForAdditionOrRemoval[T any](l, r map[string]*low.ValueReference[T], label string, changes *[]*Change[T],
|
|
breakingAdd, breakingRemove bool) {
|
|
var left, right T
|
|
if CheckObjectRemoved(l, r) {
|
|
left = l[label].GetValue()
|
|
CreateChange[T](changes, ObjectRemoved, label, l[label].GetValueNode(), nil,
|
|
breakingRemove, left, right)
|
|
}
|
|
if added, key := CheckObjectAdded(l, r); added {
|
|
right = r[key].GetValue()
|
|
CreateChange[T](changes, ObjectAdded, label, nil, r[key].GetValueNode(),
|
|
breakingAdd, left, right)
|
|
}
|
|
}
|
|
|
|
func CheckObjectRemoved[T any](l, r map[string]*T) bool {
|
|
for i := range l {
|
|
if r[i] == nil {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func CheckObjectAdded[T any](l, r map[string]*T) (bool, string) {
|
|
for i := range r {
|
|
if l[i] == nil {
|
|
return true, i
|
|
}
|
|
}
|
|
return false, ""
|
|
}
|
|
|
|
func CheckProperties[T any](properties []*PropertyCheck[T]) {
|
|
for _, n := range properties {
|
|
CheckPropertyAdditionOrRemoval(n.LeftNode, n.RightNode, n.Label, n.Changes, n.Breaking, n.Original, n.New)
|
|
CheckForModification(n.LeftNode, n.RightNode, n.Label, n.Changes, n.Breaking, n.Original, n.New)
|
|
CheckForMove(n.LeftNode, n.RightNode, n.Label, n.Changes, n.Breaking, n.Original, n.New)
|
|
}
|
|
}
|
|
|
|
func CheckPropertyAdditionOrRemoval[T any](l, r *yaml.Node,
|
|
label string, changes *[]*Change[T], breaking bool, orig, new T) {
|
|
CheckForRemoval[T](l, r, label, changes, breaking, orig, new)
|
|
CheckForAddition[T](l, r, label, changes, breaking, orig, new)
|
|
}
|
|
|
|
func CheckForRemoval[T any](l, r *yaml.Node, label string, changes *[]*Change[T], breaking bool, orig, new T) {
|
|
if l != nil && l.Value != "" && (r == nil || r.Value == "") {
|
|
CreateChange[T](changes, PropertyRemoved, label, l, r, breaking, orig, new)
|
|
}
|
|
}
|
|
|
|
func CheckForAddition[T any](l, r *yaml.Node, label string, changes *[]*Change[T], breaking bool, orig, new T) {
|
|
if (l == nil || l.Value == "") && r != nil && r.Value != "" {
|
|
CreateChange[T](changes, PropertyAdded, label, l, r, breaking, orig, new)
|
|
}
|
|
}
|
|
|
|
func CheckForModification[T any](l, r *yaml.Node, label string, changes *[]*Change[T], breaking bool, orig, new T) {
|
|
if l != nil && l.Value != "" && r != nil && r.Value != "" && r.Value != l.Value {
|
|
changeType := Modified
|
|
ctx := CreateContext(l, r)
|
|
if ctx.HasChanged() {
|
|
changeType = ModifiedAndMoved
|
|
}
|
|
CreateChange[T](changes, changeType, label, l, r, breaking, orig, new)
|
|
}
|
|
}
|
|
|
|
func CheckForMove[T any](l, r *yaml.Node, label string, changes *[]*Change[T], breaking bool, orig, new T) {
|
|
if l != nil && l.Value != "" && r != nil && r.Value != "" && r.Value == l.Value { // everything is equal
|
|
ctx := CreateContext(l, r)
|
|
if ctx.HasChanged() {
|
|
CreateChange[T](changes, Moved, label, l, r, breaking, orig, new)
|
|
}
|
|
}
|
|
}
|
|
|
|
func CheckExtensions[T low.HasExtensions[T]](l, r T) *ExtensionChanges {
|
|
var lExt, rExt map[low.KeyReference[string]]low.ValueReference[any]
|
|
if len(l.GetExtensions()) > 0 {
|
|
lExt = l.GetExtensions()
|
|
}
|
|
if len(r.GetExtensions()) > 0 {
|
|
rExt = r.GetExtensions()
|
|
}
|
|
return CompareExtensions(lExt, rExt)
|
|
}
|