Skip to content

Commit 342278a

Browse files
committed
fix(jsonschema): fix parsing schema with recursion
1 parent 465f7af commit 342278a

5 files changed

Lines changed: 208 additions & 167 deletions

File tree

providers/openapi/schema/schema.go

Lines changed: 16 additions & 151 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"fmt"
66
"mokapi/config/dynamic"
77
"mokapi/schema/json/schema"
8-
"strings"
98

109
"gopkg.in/yaml.v3"
1110
)
@@ -98,103 +97,87 @@ func (s *Schema) HasProperties() bool {
9897
}
9998

10099
func (s *Schema) Parse(config *dynamic.Config, reader dynamic.Reader) error {
101-
p := &schemaParser{visited: map[*Schema]bool{}, config: config, reader: reader}
102-
return p.parse(s)
103-
}
104-
105-
type schemaParser struct {
106-
visited map[*Schema]bool
107-
config *dynamic.Config
108-
reader dynamic.Reader
109-
}
110-
111-
func (p *schemaParser) parse(s *Schema) error {
112100
if s == nil {
113101
return nil
114102
}
115103

116-
if p.visited[s] {
117-
return nil
118-
}
119-
p.visited[s] = true
120-
121104
if s.Id != "" {
122-
p.config.OpenScope(s.Id)
123-
defer p.config.CloseScope()
105+
config.OpenScope(s.Id)
106+
defer config.CloseScope()
124107
} else {
125-
p.config.Scope.OpenIfNeeded(p.config.Info.Path())
108+
config.Scope.OpenIfNeeded(config.Info.Path())
126109
}
127110

128111
for _, d := range s.Definitions {
129-
if err := p.parse(d); err != nil {
112+
if err := d.Parse(config, reader); err != nil {
130113
return err
131114
}
132115
}
133116

134117
for _, d := range s.Defs {
135-
if err := p.parse(d); err != nil {
118+
if err := d.Parse(config, reader); err != nil {
136119
return err
137120
}
138121
}
139122

140123
if s.Anchor != "" {
141-
if err := p.config.Scope.SetLexical(s.Anchor, s); err != nil {
124+
if err := config.Scope.SetLexical(s.Anchor, s); err != nil {
142125
return err
143126
}
144127
}
145128

146129
if s.DynamicAnchor != "" {
147-
if err := p.config.Scope.SetDynamic(s.DynamicAnchor, s); err != nil {
130+
if err := config.Scope.SetDynamic(s.DynamicAnchor, s); err != nil {
148131
return err
149132
}
150133
}
151134

152135
if !s.skipParse("items") {
153-
if err := p.parse(s.Items); err != nil {
136+
if err := s.Items.Parse(config, reader); err != nil {
154137
return err
155138
}
156139
}
157140

158141
if s.Properties != nil && !s.skipParse("properties") {
159142
for it := s.Properties.Iter(); it.Next(); {
160-
if err := p.parse(it.Value()); err != nil {
143+
if err := it.Value().Parse(config, reader); err != nil {
161144
return fmt.Errorf("parse schema '%v' failed: %w", it.Key(), err)
162145
}
163146
}
164147
}
165148

166149
if !s.skipParse("additionalProperties") {
167-
if err := p.parse(s.AdditionalProperties); err != nil {
150+
if err := s.AdditionalProperties.Parse(config, reader); err != nil {
168151
return err
169152
}
170153
}
171154

172155
if !s.skipParse("anyOf") {
173156
for _, r := range s.AnyOf {
174-
if err := p.parse(r); err != nil {
157+
if err := r.Parse(config, reader); err != nil {
175158
return err
176159
}
177160
}
178161
}
179162

180163
if !s.skipParse("allOf") {
181164
for _, r := range s.AllOf {
182-
if err := p.parse(r); err != nil {
165+
if err := r.Parse(config, reader); err != nil {
183166
return err
184167
}
185168
}
186169
}
187170

188171
if !s.skipParse("oneOf") {
189172
for _, r := range s.OneOf {
190-
if err := p.parse(r); err != nil {
173+
if err := r.Parse(config, reader); err != nil {
191174
return err
192175
}
193176
}
194177
}
195178

196179
if s.Ref != "" {
197-
err := dynamic.Resolve(s.Ref, &s.Sub, p.config, p.reader)
180+
err := dynamic.Resolve(s.Ref, &s.Sub, config, reader)
198181
if err != nil {
199182
return err
200183
}
@@ -208,7 +191,7 @@ func (p *schemaParser) parse(s *Schema) error {
208191
}
209192

210193
if s.DynamicRef != "" {
211-
err := dynamic.ResolveDynamic(s.DynamicRef, &s.Sub, p.config, p.reader)
194+
err := dynamic.ResolveDynamic(s.DynamicRef, &s.Sub, config, reader)
212195
if err != nil {
213196
return err
214197
}
@@ -219,125 +202,7 @@ func (p *schemaParser) parse(s *Schema) error {
219202
}
220203

221204
func (s *Schema) String() string {
222-
var sb strings.Builder
223-
224-
if s.Boolean != nil {
225-
return fmt.Sprintf("%v", s.Boolean)
226-
}
227-
228-
if len(s.AnyOf) > 0 {
229-
sb.WriteString("any of ")
230-
for _, i := range s.AnyOf {
231-
if sb.Len() > 7 {
232-
sb.WriteString(", ")
233-
}
234-
sb.WriteString(i.String())
235-
}
236-
return sb.String()
237-
}
238-
if len(s.AllOf) > 0 {
239-
sb.WriteString("all of ")
240-
for _, i := range s.AllOf {
241-
if sb.Len() > 7 {
242-
sb.WriteString(", ")
243-
}
244-
sb.WriteString(i.String())
245-
}
246-
return sb.String()
247-
}
248-
if len(s.OneOf) > 0 {
249-
sb.WriteString("one of ")
250-
for _, i := range s.OneOf {
251-
if sb.Len() > 7 {
252-
sb.WriteString(", ")
253-
}
254-
sb.WriteString(i.String())
255-
}
256-
return sb.String()
257-
}
258-
259-
if len(s.Type) > 0 {
260-
sb.WriteString(fmt.Sprintf("schema type=%v", s.Type.String()))
261-
}
262-
263-
if len(s.Format) > 0 {
264-
sb.WriteString(fmt.Sprintf(" format=%v", s.Format))
265-
}
266-
if len(s.Pattern) > 0 {
267-
sb.WriteString(fmt.Sprintf(" pattern=%v", s.Pattern))
268-
}
269-
if s.MinLength != nil {
270-
sb.WriteString(fmt.Sprintf(" minLength=%v", *s.MinLength))
271-
}
272-
if s.MaxLength != nil {
273-
sb.WriteString(fmt.Sprintf(" maxLength=%v", *s.MaxLength))
274-
}
275-
276-
if s.ExclusiveMinimum != nil {
277-
if s.ExclusiveMinimum.IsA() {
278-
sb.WriteString(fmt.Sprintf(" exclusiveMinimum=%v", s.ExclusiveMinimum.Value()))
279-
} else if s.ExclusiveMinimum.B {
280-
sb.WriteString(fmt.Sprintf(" exclusiveMinimum=%v", *s.Minimum))
281-
}
282-
} else if s.Minimum != nil {
283-
sb.WriteString(fmt.Sprintf(" minimum=%v", *s.Minimum))
284-
}
285-
286-
if s.ExclusiveMaximum != nil {
287-
if s.ExclusiveMaximum.IsA() {
288-
sb.WriteString(fmt.Sprintf(" exclusiveMaximum=%v", s.ExclusiveMaximum.Value()))
289-
} else if s.ExclusiveMaximum.B {
290-
sb.WriteString(fmt.Sprintf(" exclusiveMaximum=%v", *s.Maximum))
291-
}
292-
} else if s.Maximum != nil {
293-
sb.WriteString(fmt.Sprintf(" maximum=%v", *s.Maximum))
294-
}
295-
296-
if s.MinItems != nil {
297-
sb.WriteString(fmt.Sprintf(" minItems=%v", *s.MinItems))
298-
}
299-
if s.MaxItems != nil {
300-
sb.WriteString(fmt.Sprintf(" maxItems=%v", *s.MaxItems))
301-
}
302-
if s.MinProperties != nil {
303-
sb.WriteString(fmt.Sprintf(" minProperties=%v", *s.MinProperties))
304-
}
305-
if s.MaxProperties != nil {
306-
sb.WriteString(fmt.Sprintf(" maxProperties=%v", *s.MaxProperties))
307-
}
308-
if s.UniqueItems != nil && *s.UniqueItems {
309-
sb.WriteString(" unique-items")
310-
}
311-
312-
if s.Type.Includes("object") && s.Properties != nil {
313-
var sbProp strings.Builder
314-
for _, p := range s.Properties.Keys() {
315-
if sbProp.Len() > 0 {
316-
sbProp.WriteString(", ")
317-
}
318-
sbProp.WriteString(fmt.Sprintf("%v", p))
319-
}
320-
sb.WriteString(fmt.Sprintf(" properties=[%v]", sbProp.String()))
321-
}
322-
if len(s.Required) > 0 {
323-
sb.WriteString(fmt.Sprintf(" required=%v", s.Required))
324-
}
325-
if s.Type.Includes("object") && !s.IsFreeForm() {
326-
sb.WriteString(" free-form=false")
327-
}
328-
329-
if s.Type.Includes("array") && s.Items != nil {
330-
sb.WriteString(" items=")
331-
sb.WriteString(s.Items.String())
332-
}
333-
334-
if len(s.Title) > 0 {
335-
sb.WriteString(fmt.Sprintf(" title=%v", s.Title))
336-
} else if len(s.Description) > 0 {
337-
sb.WriteString(fmt.Sprintf(" description=%v", s.Description))
338-
}
339-
340-
return strings.TrimSpace(sb.String())
205+
return ConvertToJsonSchema(s).String()
341206
}
342207

343208
func (s *Schema) IsFreeForm() bool {

providers/openapi/schema/schema_parse_test.go

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,27 @@ $ref: '#/$defs/a'
215215

216216
err = s.Parse(&dynamic.Config{Data: s}, &dynamictest.Reader{})
217217
require.NoError(t, err)
218-
require.Equal(t, "", s.String())
218+
require.Equal(t, "empty schema", s.String())
219+
},
220+
},
221+
{
222+
name: "self-recursion",
223+
test: func(t *testing.T) {
224+
data := `
225+
$defs:
226+
a:
227+
properties:
228+
part:
229+
$ref: '#/$defs/a'
230+
$ref: '#/$defs/a'
231+
`
232+
var s *schema.Schema
233+
err := yaml.Unmarshal([]byte(data), &s)
234+
require.NoError(t, err)
235+
236+
err = s.Parse(&dynamic.Config{Data: s}, &dynamictest.Reader{})
237+
require.NoError(t, err)
238+
require.Equal(t, "schema properties=[part]", s.String())
219239
},
220240
},
221241
{

0 commit comments

Comments
 (0)