Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion generated/kbapi/transform_schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -338,10 +338,30 @@ func (m Map) MustDelete(key string) {
}

func (m Map) CreateRef(schema *Schema, name string, key string) Map {
refTarget := m.MustGet(key) // Check the full path
refPath := fmt.Sprintf("schemas.%s", name)
refValue := Map{"$ref": fmt.Sprintf("#/components/schemas/%s", name)}

// If the target path doesn't exist, the Kibana componentizer likely already
// extracted it to a $ref. Skip gracefully — the rename transform will
// align component names later if needed.
refTarget, ok := m.Get(key)
if !ok {
log.Printf("CreateRef: skipping %q — path not found (likely already componentized)", key)
return refValue
}

// If the target is already a $ref, skip.
if targetMap, isMap := refTarget.(Map); isMap {
if _, hasRef := targetMap["$ref"]; hasRef {
return refValue
}
}
if targetMap, isMap := refTarget.(map[string]any); isMap {
if _, hasRef := targetMap["$ref"]; hasRef {
return refValue
}
}

// If the component schema already exists and is not the same, panic
writeComponent := true
if existing, ok := schema.Components.Get(refPath); ok {
Expand Down
143 changes: 143 additions & 0 deletions generated/kbapi/transform_schema_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,149 @@ func TestRemoveDuplicateOneOfRefsFromNode(t *testing.T) {
}
}

func newSchema() *Schema {
return &Schema{
Components: Map{
"schemas": Map{},
},
}
}

func TestCreateRef_InlineSchema(t *testing.T) {
schema := newSchema()
root := Map{
"requestBody": Map{
"content": Map{
"application/json": Map{
"schema": Map{
"properties": Map{
"config": Map{
"type": "object",
"properties": Map{
"name": Map{"type": "string"},
},
},
},
},
},
},
},
}

ref := root.CreateRef(schema, "my_config", "requestBody.content.application/json.schema.properties.config")

if ref["$ref"] != "#/components/schemas/my_config" {
t.Errorf("expected $ref to my_config, got %v", ref)
}

component, ok := schema.Components.Get("schemas.my_config")
if !ok {
t.Fatal("expected component to be registered")
}
componentMap := component.(Map)
if componentMap["type"] != "object" {
t.Errorf("expected extracted component type=object, got %v", componentMap["type"])
}

// Verify the original location was replaced with a $ref
replaced := root.MustGet("requestBody.content.application/json.schema.properties.config")
replacedMap := replaced.(Map)
if replacedMap["$ref"] != "#/components/schemas/my_config" {
t.Errorf("expected inline schema to be replaced with $ref, got %v", replacedMap)
}
}

func TestCreateRef_AlreadyRef(t *testing.T) {
schema := newSchema()
root := Map{
"responses": Map{
"200": Map{
"content": Map{
"application/json": Map{
"schema": Map{
"$ref": "#/components/schemas/existing_component",
},
},
},
},
},
}

ref := root.CreateRef(schema, "my_component", "responses.200.content.application/json.schema")

if ref["$ref"] != "#/components/schemas/my_component" {
t.Errorf("expected $ref return value, got %v", ref)
}

// Component should NOT have been registered — target was already a $ref
if _, ok := schema.Components.Get("schemas.my_component"); ok {
t.Error("expected component to NOT be registered when target is already a $ref")
}
}

func TestCreateRef_AlreadyRef_MapStringAny(t *testing.T) {
schema := newSchema()
// Use map[string]any instead of Map to test the second type check
root := Map{
"responses": Map{
"200": map[string]any{
"schema": map[string]any{
"$ref": "#/components/schemas/existing_component",
},
},
},
}

ref := root.CreateRef(schema, "my_component", "responses.200.schema")

if ref["$ref"] != "#/components/schemas/my_component" {
t.Errorf("expected $ref return value, got %v", ref)
}

if _, ok := schema.Components.Get("schemas.my_component"); ok {
t.Error("expected component to NOT be registered when target is already a $ref (map[string]any)")
}
}

func TestCreateRef_PathNotFound(t *testing.T) {
schema := newSchema()
root := Map{
"responses": Map{
"200": Map{
"content": Map{},
},
},
}

// This path doesn't exist — should return gracefully, not panic
ref := root.CreateRef(schema, "missing_schema", "responses.200.content.application/json.schema")

if ref["$ref"] != "#/components/schemas/missing_schema" {
t.Errorf("expected $ref return value, got %v", ref)
}

if _, ok := schema.Components.Get("schemas.missing_schema"); ok {
t.Error("expected component to NOT be registered when path doesn't exist")
}
}

func TestCreateRef_DuplicateIdenticalComponent(t *testing.T) {
schema := newSchema()
inlineSchema := Map{"type": "string", "description": "A name"}

// First call: register the component
root1 := Map{"props": Map{"name": deepCopyMap(inlineSchema)}}
root1.CreateRef(schema, "shared_name", "props.name")

// Second call with identical schema: should not panic
root2 := Map{"props": Map{"name": deepCopyMap(inlineSchema)}}
ref := root2.CreateRef(schema, "shared_name", "props.name")

if ref["$ref"] != "#/components/schemas/shared_name" {
t.Errorf("expected $ref return value, got %v", ref)
}
}

// deepCopyMap creates a deep copy of a Map for testing purposes
func deepCopyMap(m Map) Map {
result := make(Map)
Expand Down