Update index.ts

This commit is contained in:
Luke Hagar
2025-10-31 16:30:23 -05:00
committed by GitHub
parent 646c6cbec7
commit 4e918ea5f0

View File

@@ -182,6 +182,21 @@ function isOpenAPIFile(content: any, filePath?: string): boolean {
return true;
}
// Check for header-like structures (OpenAPI 3.0+)
if (isHeaderObject(content)) {
return true;
}
// Check for link-like structures (OpenAPI 3.0+)
if (isLinkObject(content)) {
return true;
}
// Check for request body-like structures (OpenAPI 3.0+)
if (isRequestBodyObject(content)) {
return true;
}
// Check for security scheme-like structures
if (isSecuritySchemeObject(content)) {
return true;
@@ -293,9 +308,38 @@ function formatOpenAPI(content: any, format: 'json' | 'yaml', options?: OpenAPIP
}
function sortOpenAPIKeys(obj: any): any {
// Special handling: if root object is a referenced OpenAPI object (for referenced files)
// Check for ref-able object types before checking for root-level keys
let contextKey = 'top-level';
// Determine what class of OpebAPI schema this is
const contextKey = getContextKey("", obj);
// Skip detection if it's a full OpenAPI spec (has openapi/swagger)
if (!('openapi' in obj) && !('swagger' in obj)) {
// Check for all ref-able object types in priority order
// Check more specific types first to avoid false positives
if (isLinkObject(obj)) {
contextKey = 'link';
} else if (isOperationObject(obj)) {
contextKey = 'operation';
} else if (isSchemaObject(obj)) {
contextKey = 'schema';
} else if (isParameterObject(obj)) {
contextKey = 'parameter';
} else if (isResponseObject(obj)) {
contextKey = 'response';
} else if (isHeaderObject(obj)) {
contextKey = 'header';
} else if (isPathItemObject(obj)) {
contextKey = 'pathItem';
} else if (isRequestBodyObject(obj)) {
contextKey = 'requestBody';
} else {
// Fall back to standard context detection
contextKey = getContextKey("", obj);
}
} else {
// Determine what class of OpenAPI schema this is for full specs
contextKey = getContextKey("", obj);
}
const standardKeys = getStandardKeysForContext(contextKey);
const customExtensions = vendorExtensions[contextKey] || {};
@@ -331,6 +375,19 @@ function sortOpenAPIKeysEnhanced(obj: any, path: string = ''): any {
return sortedObjs.sort((a, b) => sortTags(a, b));
}
// Sort parameter arrays so $ref items come first
// Check if this array is a parameters array (path ends with '.parameters' or is 'parameters')
if (path.endsWith('.parameters') || path === 'parameters') {
return sortedObjs.sort((a, b) => {
const aHasRef = a && typeof a === 'object' && '$ref' in a;
const bHasRef = b && typeof b === 'object' && '$ref' in b;
if (aHasRef && !bHasRef) return -1; // $ref comes first
if (!aHasRef && bHasRef) return 1; // $ref comes first
return 0; // Keep original order for items of same type
});
}
return sortedObjs;
}
@@ -394,8 +451,25 @@ function sortResponseCodes(a: string, b: string): number {
//#region Object type detection functions
function isOperationObject(obj: any): boolean {
const httpMethods = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace'];
return Object.keys(obj).some(key => httpMethods.includes(key.toLowerCase()));
if (!obj || typeof obj !== 'object') {
return false;
}
// An operation object must have strong operation indicators
// HTTP methods indicate a path item, not an operation
// Strong indicators: operationId or responses (required fields in operations)
// Secondary indicators: requestBody, callbacks (operation-specific)
if ('operationId' in obj || 'responses' in obj) {
return true;
}
// If it has both requestBody or callbacks (operation-specific) AND other operation keys
if (('requestBody' in obj || 'callbacks' in obj) &&
('parameters' in obj || 'security' in obj || 'servers' in obj)) {
return true;
}
return false;
}
function isParameterObject(obj: any): boolean {
@@ -468,7 +542,11 @@ function isHeaderObject(obj: any): boolean {
}
function isLinkObject(obj: any): boolean {
return obj && typeof obj === 'object' && ('operationRef' in obj || 'operationId' in obj);
if (!obj || typeof obj !== 'object') {
return false;
}
// Link objects have operationRef OR operationId, but NOT responses (which indicates an operation)
return ('operationRef' in obj || ('operationId' in obj && !('responses' in obj)));
}
function isExampleObject(obj: any): boolean {
@@ -622,7 +700,10 @@ function getContextKey(path: string, obj: any): string {
if (path.includes('.variables.')) return 'serverVariable';
// Check object types as fallback
if (isOperationObject(obj)) return 'operation';
// Only check for operation if path is not empty (not at root level)
// Root-level objects should not be detected as operations unless they're truly operations
// (handled separately in sortOpenAPIKeys for referenced operation files)
if (path && isOperationObject(obj)) return 'operation';
if (isParameterObject(obj)) return 'parameter';
if (isSchemaObject(obj)) return 'schema';
if (isResponseObject(obj)) return 'response';