mirror of
https://github.com/LukeHagar/libopenapi.git
synced 2025-12-06 12:37:49 +00:00
Tuning up path -> component -> path tooling
This commit is contained in:
@@ -430,7 +430,12 @@ func (index *SpecIndex) ExtractRefs(node, parent *yaml.Node, seenPath []string,
|
||||
|
||||
if i%2 == 0 && n.Value != "$ref" && n.Value != "" {
|
||||
|
||||
loc := append(seenPath, n.Value)
|
||||
v := n.Value
|
||||
if strings.HasPrefix(v, "/") {
|
||||
v = strings.Replace(v, "/", "~1", 1)
|
||||
}
|
||||
|
||||
loc := append(seenPath, v)
|
||||
definitionPath := fmt.Sprintf("#/%s", strings.Join(loc, "/"))
|
||||
_, jsonPath := utils.ConvertComponentIdIntoFriendlyPathSearch(definitionPath)
|
||||
|
||||
|
||||
@@ -1248,15 +1248,15 @@ components:
|
||||
if assert.Contains(t, params, "/") {
|
||||
if assert.Contains(t, params["/"], "top") {
|
||||
if assert.Contains(t, params["/"]["top"], "#/components/parameters/param1") {
|
||||
assert.Equal(t, "$.components.parameters.param1", params["/"]["top"]["#/components/parameters/param1"][0].Path)
|
||||
assert.Equal(t, "$.components.parameters['param1']", params["/"]["top"]["#/components/parameters/param1"][0].Path)
|
||||
}
|
||||
if assert.Contains(t, params["/"]["top"], "paramour.yaml#/components/parameters/param3") {
|
||||
assert.Equal(t, "$.components.parameters.param3", params["/"]["top"]["paramour.yaml#/components/parameters/param3"][0].Path)
|
||||
assert.Equal(t, "$.components.parameters['param3']", params["/"]["top"]["paramour.yaml#/components/parameters/param3"][0].Path)
|
||||
}
|
||||
}
|
||||
if assert.Contains(t, params["/"], "get") {
|
||||
if assert.Contains(t, params["/"]["get"], "#/components/parameters/param2") {
|
||||
assert.Equal(t, "$.components.parameters.param2", params["/"]["get"]["#/components/parameters/param2"][0].Path)
|
||||
assert.Equal(t, "$.components.parameters['param2']", params["/"]["get"]["#/components/parameters/param2"][0].Path)
|
||||
}
|
||||
if assert.Contains(t, params["/"]["get"], "test") {
|
||||
assert.Equal(t, "$.paths['/'].get.parameters[2]", params["/"]["get"]["test"][0].Path)
|
||||
@@ -1619,9 +1619,9 @@ paths:
|
||||
idx := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
|
||||
|
||||
schemas := idx.GetAllInlineSchemas()
|
||||
assert.Equal(t, "$.paths['/test'].get.parameters.schema", schemas[0].Path)
|
||||
assert.Equal(t, "$.paths['/test'].get.parameters.schema.properties.code", schemas[1].Path)
|
||||
assert.Equal(t, "$.paths['/test'].get.parameters.schema.properties.message", schemas[2].Path)
|
||||
assert.Equal(t, "$.paths['/test'].get.parameters['schema']", schemas[0].Path)
|
||||
assert.Equal(t, "$.paths['/test'].get.parameters['schema'].properties['code']", schemas[1].Path)
|
||||
assert.Equal(t, "$.paths['/test'].get.parameters['schema'].properties['message']", schemas[2].Path)
|
||||
}
|
||||
|
||||
func TestSpecIndex_TestPathsAsRef(t *testing.T) {
|
||||
@@ -1654,8 +1654,8 @@ components:
|
||||
|
||||
index := NewSpecIndexWithConfig(&rootNode, CreateOpenAPIIndexConfig())
|
||||
params := index.GetOperationParameterReferences()
|
||||
assert.Equal(t, "$.components.parameters.test-2", params["/test"]["top"]["#/components/parameters/test-2"][0].Path)
|
||||
assert.Equal(t, "$.components.parameters.test-3", params["/test-2"]["get"]["#/components/parameters/test-3"][0].Path)
|
||||
assert.Equal(t, "$.components.parameters['test-2']", params["/test"]["top"]["#/components/parameters/test-2"][0].Path)
|
||||
assert.Equal(t, "$.components.parameters['test-3']", params["/test-2"]["get"]["#/components/parameters/test-3"][0].Path)
|
||||
assert.Equal(t, "bing bong", params["/test"]["top"]["#/components/parameters/test-2"][0].Node.Content[5].Value)
|
||||
assert.Equal(t, "ding a ling", params["/test"]["get"]["#/components/parameters/test-3"][0].Node.Content[5].Value)
|
||||
}
|
||||
|
||||
@@ -588,8 +588,8 @@ func IsHttpVerb(verb string) bool {
|
||||
|
||||
// define bracket name expression
|
||||
var (
|
||||
bracketNameExp = regexp.MustCompile(`^(\w+)\[(\w+)\]$`)
|
||||
pathCharExp = regexp.MustCompile(`[%=;~.]`)
|
||||
bracketNameExp = regexp.MustCompile(`^(\w+)\['?(\w+)\'?]$`)
|
||||
pathCharExp = regexp.MustCompile(`[\\%=;~.]`)
|
||||
)
|
||||
|
||||
func ConvertComponentIdIntoFriendlyPathSearch(id string) (string, string) {
|
||||
@@ -600,7 +600,13 @@ func ConvertComponentIdIntoFriendlyPathSearch(id string) (string, string) {
|
||||
// check for strange spaces, chars and if found, wrap them up, clean them and create a new cleaned path.
|
||||
for i := range segs {
|
||||
if pathCharExp.Match([]byte(segs[i])) {
|
||||
|
||||
segs[i], _ = url.QueryUnescape(strings.ReplaceAll(segs[i], "~1", "/"))
|
||||
if strings.Contains(id, "#") && strings.Contains(segs[i], `\`) {
|
||||
segs[i] = strings.ReplaceAll(segs[i], `\`, "")
|
||||
cleaned = append(cleaned, segs[i])
|
||||
continue
|
||||
}
|
||||
segs[i] = fmt.Sprintf("['%s']", segs[i])
|
||||
if len(cleaned) > 0 {
|
||||
cleaned[len(cleaned)-1] = fmt.Sprintf("%s%s", segs[i-1], segs[i])
|
||||
@@ -631,6 +637,18 @@ func ConvertComponentIdIntoFriendlyPathSearch(id string) (string, string) {
|
||||
cleaned[len(cleaned)-1] = fmt.Sprintf("%s%s", cleaned[len(cleaned)-1], segs[i])
|
||||
continue
|
||||
}
|
||||
|
||||
// if we have a plural parent, wrap it in quotes.
|
||||
if i > 0 && segs[i-1] != "" && segs[i-1][len(segs[i-1])-1] == 's' {
|
||||
if i == 2 { // ignore first segment.
|
||||
cleaned = append(cleaned, segs[i])
|
||||
continue
|
||||
}
|
||||
segs[i] = fmt.Sprintf("['%s']", segs[i])
|
||||
cleaned[len(cleaned)-1] = fmt.Sprintf("%s%s", cleaned[len(cleaned)-1], segs[i])
|
||||
continue
|
||||
}
|
||||
|
||||
cleaned = append(cleaned, segs[i])
|
||||
}
|
||||
}
|
||||
@@ -650,12 +668,45 @@ func ConvertComponentIdIntoFriendlyPathSearch(id string) (string, string) {
|
||||
return name, replaced
|
||||
}
|
||||
|
||||
// ConvertComponentIdIntoPath will convert a JSON Path into a component ID
|
||||
// TODO: This function is named incorrectly and should be changed to reflect the correct function
|
||||
func ConvertComponentIdIntoPath(id string) (string, string) {
|
||||
segs := strings.Split(id, "/")
|
||||
name := segs[len(segs)-1]
|
||||
|
||||
return name, strings.ReplaceAll(fmt.Sprintf("%s.%s",
|
||||
strings.Join(segs[:len(segs)-1], "."), name), "#", "$")
|
||||
segs := strings.Split(id, ".")
|
||||
name, _ := url.QueryUnescape(strings.ReplaceAll(segs[len(segs)-1], "~1", "/"))
|
||||
var cleaned []string
|
||||
|
||||
// check for strange spaces, chars and if found, wrap them up, clean them and create a new cleaned path.
|
||||
for i := range segs {
|
||||
brackets := bracketNameExp.FindStringSubmatch(segs[i])
|
||||
if i == 0 {
|
||||
if segs[i] == "$" {
|
||||
cleaned = append(cleaned, "#")
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// if there are brackets, shift the path to encapsulate them correctly.
|
||||
if len(brackets) > 0 {
|
||||
cleaned = append(cleaned[:i],
|
||||
append([]string{bracketNameExp.ReplaceAllString(segs[i], "$1/$2")}, cleaned[i:]...)...)
|
||||
continue
|
||||
}
|
||||
cleaned = append(cleaned, segs[i])
|
||||
}
|
||||
|
||||
if cleaned[0] != "#" {
|
||||
cleaned = append(cleaned[:0], append([]string{"#"}, cleaned[0:]...)...)
|
||||
|
||||
}
|
||||
replaced := strings.ReplaceAll(strings.Join(cleaned, "/"), "$", "#")
|
||||
|
||||
if len(replaced) > 0 {
|
||||
if replaced[0] != '#' {
|
||||
replaced = fmt.Sprintf("#%s", replaced)
|
||||
}
|
||||
}
|
||||
return name, replaced
|
||||
}
|
||||
|
||||
func RenderCodeSnippet(startNode *yaml.Node, specData []string, before, after int) string {
|
||||
|
||||
@@ -697,7 +697,7 @@ func TestIsHttpVerb(t *testing.T) {
|
||||
|
||||
func TestConvertComponentIdIntoFriendlyPathSearch(t *testing.T) {
|
||||
segment, path := ConvertComponentIdIntoFriendlyPathSearch("#/chicken/chips/pizza/cake")
|
||||
assert.Equal(t, "$.chicken.chips.pizza.cake", path)
|
||||
assert.Equal(t, "$.chicken.chips['pizza'].cake", path)
|
||||
assert.Equal(t, "cake", segment)
|
||||
}
|
||||
|
||||
@@ -708,15 +708,23 @@ func TestConvertComponentIdIntoFriendlyPathSearch_SuperCrazy(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestConvertComponentIdIntoFriendlyPathSearch_Crazy(t *testing.T) {
|
||||
segment, path := ConvertComponentIdIntoFriendlyPathSearch("#/components/schemas/gpg-key/properties/subkeys/example/0/expires_at")
|
||||
assert.Equal(t, "$.components.schemas.gpg-key.properties.subkeys.example[0].expires_at", path)
|
||||
segment, path := ConvertComponentIdIntoFriendlyPathSearch("#/components/schemas/gpg-key/properties/subkeys/examples/0/expires_at")
|
||||
assert.Equal(t, "$.components.schemas['gpg-key'].properties['subkeys'].examples[0].expires_at", path)
|
||||
assert.Equal(t, "expires_at", segment)
|
||||
}
|
||||
|
||||
func BenchmarkConvertComponentIdIntoFriendlyPathSearch_Crazy(t *testing.B) {
|
||||
for n := 0; n < t.N; n++ {
|
||||
segment, path := ConvertComponentIdIntoFriendlyPathSearch("#/components/schemas/gpg-key/properties/subkeys/example/0/expires_at")
|
||||
assert.Equal(t, "$.components.schemas.gpg-key.properties.subkeys.example[0].expires_at", path)
|
||||
segment, path := ConvertComponentIdIntoFriendlyPathSearch("#/components/schemas/gpg-key/properties/subkeys/examples/0/expires_at")
|
||||
assert.Equal(t, "$.components.schemas.gpg-key.properties['subkeys'].examples[0].expires_at", path)
|
||||
assert.Equal(t, "expires_at", segment)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkConvertComponentIdIntoFriendlyPathSearch_Plural(t *testing.B) {
|
||||
for n := 0; n < t.N; n++ {
|
||||
segment, path := ConvertComponentIdIntoFriendlyPathSearch("#/components/schemas/gpg-key/properties/subkeys/examples/0/expires_at")
|
||||
assert.Equal(t, "$.components.schemas['gpg-key'].properties['subkeys'].examples[0].expires_at", path)
|
||||
assert.Equal(t, "expires_at", segment)
|
||||
}
|
||||
}
|
||||
@@ -727,6 +735,12 @@ func TestConvertComponentIdIntoFriendlyPathSearch_Simple(t *testing.T) {
|
||||
assert.Equal(t, "get", segment)
|
||||
}
|
||||
|
||||
func TestConvertComponentIdIntoFriendlyPathSearch_Plural(t *testing.T) {
|
||||
segment, path := ConvertComponentIdIntoFriendlyPathSearch("#/components/schemas/FreshMan/properties/subkeys/examples/0/expires_at")
|
||||
assert.Equal(t, "$.components.schemas['FreshMan'].properties['subkeys'].examples[0].expires_at", path)
|
||||
assert.Equal(t, "expires_at", segment)
|
||||
}
|
||||
|
||||
func TestConvertComponentIdIntoFriendlyPathSearch_Params(t *testing.T) {
|
||||
segment, path := ConvertComponentIdIntoFriendlyPathSearch("#/why/0")
|
||||
assert.Equal(t, "$.why[0]", path)
|
||||
@@ -776,11 +790,22 @@ func TestConvertComponentIdIntoFriendlyPathSearch_HTTPCode(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestConvertComponentIdIntoPath(t *testing.T) {
|
||||
segment, path := ConvertComponentIdIntoPath("#/chicken/chips/pizza/cake")
|
||||
assert.Equal(t, "$.chicken.chips.pizza.cake", path)
|
||||
segment, path := ConvertComponentIdIntoPath("$.chicken.chips.pizza.cake")
|
||||
assert.Equal(t, "#/chicken/chips/pizza/cake", path)
|
||||
assert.Equal(t, "cake", segment)
|
||||
}
|
||||
|
||||
func TestConvertComponentIdIntoPath_Alt1(t *testing.T) {
|
||||
segment, path := ConvertComponentIdIntoPath("$.chicken.chips['pizza'].cakes[0].burgers[2]")
|
||||
assert.Equal(t, "#/chicken/chips/pizza/cakes/0/burgers/2", path)
|
||||
assert.Equal(t, "burgers[2]", segment)
|
||||
}
|
||||
|
||||
func TestConvertComponentIdIntoPath_Alt2(t *testing.T) {
|
||||
_, path := ConvertComponentIdIntoPath("chicken.chips['pizza'].cakes[0].burgers[2]")
|
||||
assert.Equal(t, "#/chicken/chips/pizza/cakes/0/burgers/2", path)
|
||||
}
|
||||
|
||||
func TestDetectCase(t *testing.T) {
|
||||
assert.Equal(t, PascalCase, DetectCase("PizzaPie"))
|
||||
assert.Equal(t, CamelCase, DetectCase("anyoneForTennis"))
|
||||
|
||||
Reference in New Issue
Block a user