Skip to content

Commit c7dff89

Browse files
committed
refactor: openapi3: standardize OAS3 extension support; move embedded x-tagGroups functionality to ext/taggroups
1 parent cfaf70f commit c7dff89

File tree

14 files changed

+224
-49
lines changed

14 files changed

+224
-49
lines changed

cmd/oas3lint/main.go

+10
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"github.com/grokify/mogo/fmt/fmtutil"
88
"github.com/grokify/mogo/log/logutil"
99
"github.com/grokify/mogo/os/osutil"
10+
"github.com/grokify/spectrum/openapi3"
1011
"github.com/grokify/spectrum/openapi3lint"
1112
"github.com/grokify/spectrum/openapi3lint/lintutil"
1213
flags "github.com/jessevdk/go-flags"
@@ -24,6 +25,15 @@ func main() {
2425
logutil.FatalErr(err)
2526
fmtutil.PrintJSON(opts)
2627

28+
if 1 == 1 {
29+
spec, err := openapi3.ReadFile(opts.InputFileOAS3, false)
30+
logutil.FatalErr(err)
31+
sm := openapi3.SpecMore{Spec: spec}
32+
ont := sm.Ontology()
33+
fmtutil.PrintJSON(ont)
34+
panic("Z")
35+
}
36+
2737
vsets, err := ValidateSpecFiles(opts.InputFileOAS3, opts.PolicyFile, opts.Severity)
2838
logutil.FatalErr(err)
2939

cmd/oas3validate/main.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ func main() {
6262
fmt.Println(md)
6363
opts.XlsxWrite = strings.TrimSpace(opts.XlsxWrite)
6464
if len(opts.XlsxWrite) > 0 {
65-
err := sm.WriteFileXLSX(opts.XlsxWrite, nil, nil)
65+
err := sm.WriteFileXLSX(opts.XlsxWrite, nil, nil, nil)
6666
if err != nil {
6767
log.Fatal(err)
6868
}

ext/taggroups/taggroups.go

+135
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
package taggroups
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"reflect"
7+
"strings"
8+
9+
"github.com/grokify/mogo/type/stringsutil"
10+
"github.com/grokify/spectrum/openapi3"
11+
"github.com/grokify/spectrum/openapi3edit"
12+
)
13+
14+
const XTagGroupsPropertyName = "x-tag-groups"
15+
16+
type TagGroupSet struct {
17+
TagGroups []TagGroup
18+
}
19+
20+
func NewTagGroupSet() TagGroupSet {
21+
return TagGroupSet{TagGroups: []TagGroup{}}
22+
}
23+
24+
func (set *TagGroupSet) Exists(tagName string) bool {
25+
for _, tg := range set.TagGroups {
26+
for _, tgTagName := range tg.Tags {
27+
if tagName == tgTagName {
28+
return true
29+
}
30+
}
31+
}
32+
return false
33+
}
34+
35+
func (set *TagGroupSet) GetTagGroupNamesForTagNames(wantTagNames ...string) []string {
36+
tagGroupNames := []string{}
37+
for _, tg := range set.TagGroups {
38+
for _, tgTagName := range tg.Tags {
39+
for _, wantTagName := range wantTagNames {
40+
if wantTagName == tgTagName {
41+
tagGroupNames = append(tagGroupNames, tg.Name)
42+
}
43+
}
44+
}
45+
}
46+
return stringsutil.SliceCondenseSpace(tagGroupNames, true, true)
47+
}
48+
49+
func (set *TagGroupSet) AddToSpec(spec *openapi3.Spec) error {
50+
if len(set.TagGroups) == 0 {
51+
return nil
52+
}
53+
missing := SpecTagsWithoutGroups(spec, *set)
54+
if len(missing) > 0 {
55+
return fmt.Errorf("E_TAGS_WITHOUT_GROUPS [%s]", strings.Join(missing, ","))
56+
}
57+
se := openapi3edit.SpecEdit{}
58+
se.SpecSet(spec)
59+
se.ExtensionSet(XTagGroupsPropertyName, set.TagGroups)
60+
// spec.ExtensionProps.Extensions[XTagGroupsPropertyName] = set.TagGroups
61+
return nil
62+
}
63+
64+
// OperationMoreTagGroupNames this function is meant to be used wtih `SpecMore.Table()`
65+
// and must follow the `OperationMoreStringFunc` interface.
66+
func (set *TagGroupSet) OperationMoreTagGroupNames(opm *openapi3.OperationMore) string {
67+
// row = append(row, strings.Join(tgs.GetTagGroupNamesForTagNames(op.Tags...), ", "))
68+
if opm == nil || opm.Operation == nil {
69+
return ""
70+
}
71+
return strings.Join(set.GetTagGroupNamesForTagNames(opm.Operation.Tags...), ", ")
72+
}
73+
74+
type TagGroup struct {
75+
Name string `json:"name"`
76+
Popular bool `json:"popular"`
77+
Tags []string `json:"tags"`
78+
}
79+
80+
/*
81+
func (sm *SpecMore) TagsWithoutGroups() ([]string, []string, []string, error) {
82+
tgs, err := sm.TagGroups()
83+
if err != nil {
84+
return []string{}, []string{}, []string{}, err
85+
}
86+
allTags := []string{}
87+
88+
topTags := stringsutil.SliceCondenseSpace(sm.Tags(true, false), true, true)
89+
allTags = append(allTags, topTags...)
90+
91+
opsTags := stringsutil.SliceCondenseSpace(sm.Tags(false, true), true, true)
92+
allTags = append(allTags, opsTags...)
93+
94+
allTags = stringsutil.SliceCondenseSpace(allTags, true, true)
95+
return allTags, topTags, opsTags, nil
96+
}
97+
*/
98+
99+
func SpecTagsWithoutGroups(spec *openapi3.Spec, tagGroupSet TagGroupSet) []string {
100+
missing := []string{}
101+
for _, tag := range spec.Tags {
102+
if !tagGroupSet.Exists(tag.Name) {
103+
missing = append(missing, tag.Name)
104+
}
105+
}
106+
return missing
107+
}
108+
109+
// SpecTagGroups parses a TagGroupSet from an OpenAPI3 spec.
110+
func SpecTagGroups(spec *openapi3.Spec) (TagGroupSet, error) {
111+
sm := openapi3.SpecMore{Spec: spec}
112+
tgs := NewTagGroupSet()
113+
iface, ok := sm.Spec.ExtensionProps.Extensions[XTagGroupsPropertyName]
114+
if !ok {
115+
return tgs, nil
116+
}
117+
118+
tagGroups := []TagGroup{}
119+
if reflect.TypeOf(iface) == reflect.TypeOf(tagGroups) {
120+
tgs.TagGroups = iface.([]TagGroup)
121+
return tgs, nil
122+
}
123+
124+
// message is stored as `json.RawMessage` when the data
125+
// is read in from JSON, vs. set via code.
126+
rawMessage := iface.(json.RawMessage)
127+
err := json.Unmarshal(rawMessage, &tagGroups)
128+
if err != nil {
129+
return tgs, err
130+
}
131+
tgs.TagGroups = tagGroups
132+
delete(sm.Spec.ExtensionProps.Extensions, XTagGroupsPropertyName)
133+
sm.Spec.ExtensionProps.Extensions[XTagGroupsPropertyName] = tagGroups
134+
return tgs, nil
135+
}

openapi3/extension_taggroups.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package openapi3
22

3+
/*
34
import (
45
"encoding/json"
56
"fmt"
@@ -62,8 +63,7 @@ type TagGroup struct {
6263
Tags []string `json:"tags"`
6364
}
6465
65-
/*
66-
func (sm *SpecMore) TagsWithoutGroups() ([]string, []string, []string, error) {
66+
func (sm *SpecMore) TagsWithoutGroupsOLDOLD() ([]string, []string, []string, error) {
6767
tgs, err := sm.TagGroups()
6868
if err != nil {
6969
return []string{}, []string{}, []string{}, err
@@ -79,7 +79,6 @@ func (sm *SpecMore) TagsWithoutGroups() ([]string, []string, []string, error) {
7979
allTags = stringsutil.SliceCondenseSpace(allTags, true, true)
8080
return allTags, topTags, opsTags, nil
8181
}
82-
*/
8382
8483
func TagsWithoutGroups(spec *Spec, tagGroupSet TagGroupSet) []string {
8584
missing := []string{}
@@ -117,3 +116,4 @@ func (sm *SpecMore) TagGroups() (TagGroupSet, error) {
117116
sm.Spec.ExtensionProps.Extensions[XTagGroupsPropertyName] = tagGroups
118117
return tgs, nil
119118
}
119+
*/

openapi3/merge.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -119,13 +119,13 @@ func MergeWithTables(spec1, spec2 *Spec, specExtraNote string, mergeOpts *MergeO
119119
tbls := []*table.Table{}
120120
sm1 := SpecMore{Spec: spec1}
121121
sm2 := SpecMore{Spec: spec2}
122-
tbls1, err := sm1.OperationsTable(mergeOpts.TableColumns, mergeOpts.TableOpFilterFunc)
122+
tbls1, err := sm1.OperationsTable(mergeOpts.TableColumns, mergeOpts.TableOpFilterFunc, mergeOpts.TableAddlColFormatFuncs)
123123
if err != nil {
124124
return nil, nil, err
125125
}
126126
tbls = append(tbls, tbls1)
127127
tbls[0].Name = "Spec1"
128-
tbls2, err := sm2.OperationsTable(mergeOpts.TableColumns, mergeOpts.TableOpFilterFunc)
128+
tbls2, err := sm2.OperationsTable(mergeOpts.TableColumns, mergeOpts.TableOpFilterFunc, mergeOpts.TableAddlColFormatFuncs)
129129
if err != nil {
130130
return nil, nil, err
131131
}
@@ -136,7 +136,7 @@ func MergeWithTables(spec1, spec2 *Spec, specExtraNote string, mergeOpts *MergeO
136136
return specf, tbls, err
137137
}
138138
smf := SpecMore{Spec: specf}
139-
tblsf, err := smf.OperationsTable(mergeOpts.TableColumns, mergeOpts.TableOpFilterFunc)
139+
tblsf, err := smf.OperationsTable(mergeOpts.TableColumns, mergeOpts.TableOpFilterFunc, mergeOpts.TableAddlColFormatFuncs)
140140
if err != nil {
141141
return nil, nil, err
142142
}

openapi3/merge_options.go

+8-7
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,14 @@ const (
1818
)
1919

2020
type MergeOptions struct {
21-
FileRx *regexp.Regexp
22-
SchemaFunc func(schemaName string, sch1, sch2 interface{}, hint2 string) CollisionCheckResult
23-
CollisionCheckResult CollisionCheckResult
24-
ValidateEach bool
25-
ValidateFinal bool
26-
TableColumns *tabulator.ColumnSet
27-
TableOpFilterFunc func(path, method string, op *oas3.Operation) bool
21+
FileRx *regexp.Regexp
22+
SchemaFunc func(schemaName string, sch1, sch2 interface{}, hint2 string) CollisionCheckResult
23+
CollisionCheckResult CollisionCheckResult
24+
ValidateEach bool
25+
ValidateFinal bool
26+
TableColumns *tabulator.ColumnSet
27+
TableOpFilterFunc func(path, method string, op *oas3.Operation) bool
28+
TableAddlColFormatFuncs *OperationMoreStringFuncMap
2829
}
2930

3031
func NewMergeOptionsSkip() *MergeOptions {

openapi3/openapi3html/pageparams.go

+9-8
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,14 @@ import (
1414
)
1515

1616
type PageParams struct {
17-
PageTitle string
18-
PageLink string
19-
TableDomID string
20-
Spec *openapi3.Spec
21-
ColumnSet *tabulator.ColumnSet
22-
OpsFilterFunc func(path, method string, op *oas3.Operation) bool
23-
TableJSON []byte
17+
PageTitle string
18+
PageLink string
19+
TableDomID string
20+
Spec *openapi3.Spec
21+
ColumnSet *tabulator.ColumnSet
22+
OpsFilterFunc func(path, method string, op *oas3.Operation) bool
23+
OpsAdditionalFormatFuncs *openapi3.OperationMoreStringFuncMap
24+
TableJSON []byte
2425
}
2526

2627
func (pp *PageParams) PageLinkHTML() string {
@@ -34,7 +35,7 @@ func (pp *PageParams) PageLinkHTML() string {
3435

3536
func (pp *PageParams) AddSpec(spec *openapi3.Spec) error {
3637
sm := openapi3.SpecMore{Spec: spec}
37-
tbl, err := sm.OperationsTable(pp.ColumnSet, pp.OpsFilterFunc)
38+
tbl, err := sm.OperationsTable(pp.ColumnSet, pp.OpsFilterFunc, pp.OpsAdditionalFormatFuncs)
3839
if err != nil {
3940
return err
4041
}

openapi3/openapi3postman2/convert.go

+6-4
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
oas3 "github.com/getkin/kin-openapi/openapi3"
1313
"github.com/grokify/mogo/errors/errorsutil"
1414
"github.com/grokify/mogo/net/urlutil"
15+
"github.com/grokify/spectrum/ext/taggroups"
1516
"github.com/grokify/spectrum/openapi3"
1617
"github.com/grokify/spectrum/postman2"
1718
"github.com/grokify/spectrum/postman2/simple"
@@ -106,9 +107,10 @@ func Merge(cfg Configuration, pman postman2.Collection, oas3spec *openapi3.Spec)
106107
return pman, err
107108
}
108109

109-
oas3specMore := openapi3.SpecMore{Spec: oas3spec}
110-
tagGroupSet, err := oas3specMore.TagGroups()
111-
//tagGroupSet, err := openapi3.SpecTagGroups(oas3spec)
110+
// tagGroupSet, err := openapi3.SpecTagGroups(oas3spec)
111+
// oas3specMore := openapi3.SpecMore{Spec: oas3spec}
112+
// tagGroupSet, err := oas3specMore.TagGroups()
113+
tagGroupSet, err := taggroups.SpecTagGroups(oas3spec)
112114
if err != nil {
113115
return pman, err
114116
}
@@ -151,7 +153,7 @@ func Merge(cfg Configuration, pman postman2.Collection, oas3spec *openapi3.Spec)
151153
return pman, nil
152154
}
153155

154-
func postmanAddItemToFolders(pman postman2.Collection, pmItem *postman2.Item, tagNames []string, tagGroupSet openapi3.TagGroupSet) postman2.Collection {
156+
func postmanAddItemToFolders(pman postman2.Collection, pmItem *postman2.Item, tagNames []string, tagGroupSet taggroups.TagGroupSet) postman2.Collection {
155157
for _, tagName := range tagNames {
156158
tagGroupNames := tagGroupSet.GetTagGroupNamesForTagNames(tagName)
157159
if len(tagGroupNames) == 0 {

openapi3/openapi3postman2/folders.go

+4-3
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@ import (
66

77
oas3 "github.com/getkin/kin-openapi/openapi3"
88
"github.com/grokify/mogo/net/httputilmore"
9+
"github.com/grokify/spectrum/ext/taggroups"
910
"github.com/grokify/spectrum/openapi3"
1011
"github.com/grokify/spectrum/postman2"
1112
)
1213

1314
func CreateTagsAndTagGroups(pman postman2.Collection, spec *openapi3.Spec) (postman2.Collection, error) {
14-
oas3specMore := openapi3.SpecMore{Spec: spec}
15-
tagGroupSet, err := oas3specMore.TagGroups()
15+
// oas3specMore := openapi3.SpecMore{Spec: spec}
16+
tagGroupSet, err := taggroups.SpecTagGroups(spec)
1617
// tagGroupSet, err := openapi3.SpecTagGroups(spec)
1718
if err != nil {
1819
return pman, err
@@ -23,7 +24,7 @@ func CreateTagsAndTagGroups(pman postman2.Collection, spec *openapi3.Spec) (post
2324
return addFoldersFromTags(pman, spec.Tags), nil
2425
}
2526

26-
func addFoldersFromTagGroups(pman postman2.Collection, tgSet openapi3.TagGroupSet, tags oas3.Tags) (postman2.Collection, error) {
27+
func addFoldersFromTagGroups(pman postman2.Collection, tgSet taggroups.TagGroupSet, tags oas3.Tags) (postman2.Collection, error) {
2728
tagsMore := openapi3.TagsMore{Tags: tags}
2829
for _, tg := range tgSet.TagGroups {
2930
tg.Name = strings.TrimSpace(tg.Name)

openapi3/operation_more.go

+13
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,19 @@ type OperationMore struct {
2727
Operation *oas3.Operation
2828
}
2929

30+
type OperationMoreStringFunc func(opm *OperationMore) string
31+
32+
type OperationMoreStringFuncMap map[string]OperationMoreStringFunc
33+
34+
func (opmmap *OperationMoreStringFuncMap) Func(key string) OperationMoreStringFunc {
35+
opmmapIndexable := map[string]OperationMoreStringFunc(*opmmap)
36+
wantFunc, ok := opmmapIndexable[key]
37+
if !ok {
38+
return nil
39+
}
40+
return wantFunc
41+
}
42+
3043
func (om *OperationMore) HasParameter(paramNameWant string) bool {
3144
paramNameWantLc := strings.ToLower(strings.TrimSpace(paramNameWant))
3245
for _, paramRef := range om.Operation.Parameters {

0 commit comments

Comments
 (0)