Skip to content
Merged
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
BasicUser:
type: object
description: A basic user object
required:
- id
- name
properties:
id:
type: string
format: uuid
name:
type: string
email:
type: string
format: email
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
ErrorResponse:
type: object
description: Standard error response
required:
- code
- message
properties:
code:
type: integer
message:
type: string
17 changes: 17 additions & 0 deletions index/nested_subdir_test_data/openapi/openapi.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
openapi: 3.1.0
info:
title: Nested Subdir Reference Resolution Test
version: 1.0.0
description: |
Tests that relative $ref resolution correctly preserves nested directory paths.
The /openapi/ segment must NOT be lost when resolving '../components/...' refs.
paths:
/users:
$ref: 'paths/user.yaml#/user_path'
components:
schemas:
LocalSchema:
type: object
properties:
id:
type: string
17 changes: 17 additions & 0 deletions index/nested_subdir_test_data/openapi/paths/user.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
user_path:
get:
operationId: getUser
summary: Get user by ID
responses:
'200':
description: Successful response
content:
application/json:
schema:
$ref: '../components/schemas/Basic.yaml#/BasicUser'
'404':
description: User not found
content:
application/json:
schema:
$ref: '../components/schemas/Error.yaml#/ErrorResponse'
35 changes: 34 additions & 1 deletion index/rolodex.go
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,40 @@ func (r *Rolodex) IndexTheRolodex(ctx context.Context) error {

if len(r.localFS) > 0 || len(r.remoteFS) > 0 {
if r.indexConfig.SpecFilePath != "" {
r.indexConfig.SpecAbsolutePath = filepath.Join(basePath, filepath.Base(r.indexConfig.SpecFilePath))
// Compute the absolute path to the spec file.
// - If SpecFilePath is already absolute, use it directly.
// - If SpecFilePath is relative, it needs careful handling to avoid path doubling.
//
// The original code used filepath.Base() which incorrectly stripped directory
// segments like /myproject/api-spec/ from nested paths.
//
// Handle cases:
// 1. SpecFilePath = "test_data/nested/doc.yaml", BasePath = "/abs/test_data/nested"
// -> Should NOT double to /abs/test_data/nested/test_data/nested/doc.yaml
// 2. SpecFilePath = "subdir/doc.yaml", BasePath = "/abs/test_data"
// -> Should produce /abs/test_data/subdir/doc.yaml
if filepath.IsAbs(r.indexConfig.SpecFilePath) {
r.indexConfig.SpecAbsolutePath = r.indexConfig.SpecFilePath
} else {
specPath := r.indexConfig.SpecFilePath
// Check if SpecFilePath starts with the relative basePath or its original value
// This handles cases where SpecFilePath = "test_data/file.yaml" and
// BasePath was originally "test_data" (now absolute)
origBasePath := r.indexConfig.BasePath

// Normalize paths to use OS-specific separators for Windows compatibility
// On Windows, paths may use / but os.PathSeparator is \, causing mismatches
normalizedSpecPath := filepath.FromSlash(specPath)
normalizedOrigBasePath := filepath.FromSlash(origBasePath)

if strings.HasPrefix(normalizedSpecPath, normalizedOrigBasePath+string(os.PathSeparator)) {
// SpecFilePath includes the original basePath, make it absolute directly
r.indexConfig.SpecAbsolutePath, _ = filepath.Abs(normalizedSpecPath)
} else {
// SpecFilePath is relative to basePath, join them
r.indexConfig.SpecAbsolutePath = filepath.Join(basePath, normalizedSpecPath)
}
}
} else {
r.indexConfig.SetTheoreticalRoot()
}
Expand Down
Loading