1515package sunset
1616
1717import (
18- "maps"
19- "regexp"
20- "slices"
2118 "sort"
2219
2320 "github.com/oasdiff/kin-openapi/openapi3"
@@ -45,33 +42,39 @@ func NewListFromSpec(spec *load.SpecInfo) []*Sunset {
4542 for path , pathBody := range paths .Map () {
4643 for operationName , operationBody := range pathBody .Operations () {
4744 teamName := teamName (operationBody )
48- extensions := successResponseExtensions (operationBody .Responses .Map ())
49- if extensions == nil {
50- continue
45+ extensionsList := successResponseExtensions (operationBody .Responses .Map ())
46+
47+ for _ , extensions := range extensionsList {
48+ apiVersion , ok := extensions [apiVersionExtensionName ]
49+ if ! ok {
50+ continue
51+ }
52+
53+ sunsetExt , ok := extensions [sunsetExtensionName ]
54+ if ! ok {
55+ continue
56+ }
57+
58+ sunset := Sunset {
59+ Operation : operationName ,
60+ Path : path ,
61+ SunsetDate : sunsetExt .(string ),
62+ Version : apiVersion .(string ),
63+ Team : teamName ,
64+ }
65+
66+ sunsets = append (sunsets , & sunset )
5167 }
52-
53- apiVersion , ok := extensions [apiVersionExtensionName ]
54- if ! ok {
55- continue
56- }
57-
58- sunsetExt , ok := extensions [sunsetExtensionName ]
59- if ! ok {
60- continue
61- }
62-
63- sunset := Sunset {
64- Operation : operationName ,
65- Path : path ,
66- SunsetDate : sunsetExt .(string ),
67- Version : apiVersion .(string ),
68- Team : teamName ,
69- }
70-
71- sunsets = append (sunsets , & sunset )
7268 }
7369 }
7470
71+ sort .Slice (sunsets , func (i , j int ) bool {
72+ if sunsets [i ].SunsetDate != sunsets [j ].SunsetDate {
73+ return sunsets [i ].SunsetDate < sunsets [j ].SunsetDate
74+ }
75+ return sunsets [i ].Version < sunsets [j ].Version
76+ })
77+
7578 return sunsets
7679}
7780
@@ -95,7 +98,7 @@ func teamName(op *openapi3.Operation) string {
9598// Returns:
9699// - A map of extension names to their values from the first successful response content,
97100// or nil if no successful responses are found or if none contain relevant extensions
98- func successResponseExtensions (responsesMap map [string ]* openapi3.ResponseRef ) map [string ]any {
101+ func successResponseExtensions (responsesMap map [string ]* openapi3.ResponseRef ) [] map [string ]any {
99102 if val , ok := responsesMap ["200" ]; ok {
100103 return contentExtensions (val .Value .Content )
101104 }
@@ -112,36 +115,28 @@ func successResponseExtensions(responsesMap map[string]*openapi3.ResponseRef) ma
112115 return nil
113116}
114117
115- // contentExtensions extracts extensions from OpenAPI content objects, prioritizing content entries
116- // with the oldest date in their keys.
118+ // contentExtensions extracts extensions from all OpenAPI content entries that have a sunset extension.
117119//
118- // The function sorts content keys by date (in YYYY-MM-DD format) if present, with older dates taking
119- // precedence. If multiple keys contain dates, it selects the entry with the earliest date.
120+ // The function iterates over all content entries and returns the extensions for each entry
121+ // that contains a sunset extension, allowing multiple API versions with different sunset
122+ // dates to be tracked independently.
120123//
121124// Parameters:
122125// - content: An OpenAPI content map with media types as keys and schema objects as values
123126//
124127// Returns:
125- // - A map of extension names to their values from the selected content entry,
126- // or nil if the content map is empty or the selected entry has no extensions
127- //
128- // Assumption: the older version will have the earliest sunset date.
129- func contentExtensions (content openapi3.Content ) map [string ]any {
130- keysContent := slices .Collect (maps .Keys (content ))
131- // Regex to find a date in YYYY-MM-DD format.
132- dateRegex := regexp .MustCompile (`\d{4}-\d{2}-\d{2}` )
133- // we need the content of the API version with the older date.
134- sort .Slice (keysContent , func (i , j int ) bool {
135- dateI := dateRegex .FindString (keysContent [i ])
136- dateJ := dateRegex .FindString (keysContent [j ])
137-
138- // If both have dates, compare them as strings.
139- if dateI != "" && dateJ != "" {
140- return dateI < dateJ
128+ // - A slice of extension maps, one per content entry that has a sunset extension,
129+ // or nil if no entries have sunset extensions
130+ func contentExtensions (content openapi3.Content ) []map [string ]any {
131+ var result []map [string ]any
132+ for _ , mediaType := range content {
133+ if mediaType .Extensions == nil {
134+ continue
141135 }
142- // Strings with dates should come before those without.
143- return dateI != ""
144- })
145-
146- return content [keysContent [0 ]].Extensions
136+ if _ , ok := mediaType .Extensions [sunsetExtensionName ]; ! ok {
137+ continue
138+ }
139+ result = append (result , mediaType .Extensions )
140+ }
141+ return result
147142}
0 commit comments