/** * @fileoverview Extract complete provider endpoint details from api-docs.json * Extracts all 147 provider endpoints with exact parameter names, types, and descriptions */ import fs from 'fs'; import path from 'path'; /** * Extract complete provider endpoint details */ function extractCompleteProviderDetails() { try { console.log('=== EXTRACTING COMPLETE PROVIDER ENDPOINT DETAILS ==='); console.log(''); // Read the categorized endpoints const categorizedPath = path.join(process.cwd(), 'categorized-endpoints.json'); const categorizedContent = fs.readFileSync(categorizedPath, 'utf8'); const categorized = JSON.parse(categorizedContent); // Read the original api-docs.json for complete parameter details const apiDocsPath = path.join(process.cwd(), '..', 'api-docs.json'); const apiDocsContent = fs.readFileSync(apiDocsPath, 'utf8'); const apiDocs = JSON.parse(apiDocsContent); console.log(`Found ${categorized.provider.length} provider endpoints to process`); console.log(''); const completeProviderEndpoints = []; // Process each provider endpoint categorized.provider.forEach((endpoint, index) => { console.log(`Processing ${index + 1}/${categorized.provider.length}: ${endpoint.method} ${endpoint.path}`); // Find the complete endpoint details in api-docs.json const completeDetails = findCompleteEndpointDetails(apiDocs, endpoint.path, endpoint.method); if (completeDetails) { const enhancedEndpoint = { ...endpoint, completeParameters: extractCompleteParameters(completeDetails), requestBodySchema: extractRequestBodySchema(completeDetails), responseSchema: extractResponseSchema(completeDetails), exactToolName: generateExactToolName(endpoint, completeDetails), detailedDescription: completeDetails.summary || completeDetails.description || endpoint.summary, operationId: completeDetails.operationId, tags: completeDetails.tags || [] }; completeProviderEndpoints.push(enhancedEndpoint); } else { console.warn(`⚠️ Could not find complete details for: ${endpoint.method} ${endpoint.path}`); // Still add the endpoint with available information completeProviderEndpoints.push({ ...endpoint, completeParameters: {}, requestBodySchema: null, responseSchema: null, exactToolName: generateExactToolName(endpoint, null), detailedDescription: endpoint.summary || endpoint.description, operationId: null, tags: [] }); } }); console.log(''); console.log(`=== EXTRACTION COMPLETE ===`); console.log(`Processed ${completeProviderEndpoints.length} provider endpoints`); console.log(''); // Save the complete provider details const outputPath = path.join(process.cwd(), 'complete-provider-endpoints.json'); fs.writeFileSync(outputPath, JSON.stringify(completeProviderEndpoints, null, 2)); console.log(`Complete provider endpoint details saved to: ${outputPath}`); // Display summary by category const categoryCount = {}; completeProviderEndpoints.forEach(endpoint => { const category = endpoint.category || 'unknown'; categoryCount[category] = (categoryCount[category] || 0) + 1; }); console.log(''); console.log('=== PROVIDER ENDPOINTS BY CATEGORY ==='); Object.keys(categoryCount).sort().forEach(category => { console.log(`${category}: ${categoryCount[category]} endpoints`); }); return completeProviderEndpoints; } catch (error) { console.error('Error extracting complete provider details:', error); throw error; } } /** * Find complete endpoint details in api-docs.json */ function findCompleteEndpointDetails(apiDocs, path, method) { const paths = apiDocs.paths || {}; const pathData = paths[path]; if (!pathData) { return null; } const methodData = pathData[method.toLowerCase()]; return methodData || null; } /** * Extract complete parameters from endpoint definition */ function extractCompleteParameters(endpointDetails) { const parameters = {}; // Extract path parameters, query parameters, header parameters if (endpointDetails.parameters) { endpointDetails.parameters.forEach(param => { parameters[param.name] = { name: param.name, in: param.in, // path, query, header, etc. type: param.schema?.type || param.type || 'string', format: param.schema?.format || param.format, required: param.required || false, description: param.description || `${param.name} parameter`, example: param.schema?.example || param.example, enum: param.schema?.enum || param.enum, minimum: param.schema?.minimum || param.minimum, maximum: param.schema?.maximum || param.maximum }; }); } return parameters; } /** * Extract request body schema */ function extractRequestBodySchema(endpointDetails) { if (!endpointDetails.requestBody) { return null; } const requestBody = { required: endpointDetails.requestBody.required || false, description: endpointDetails.requestBody.description || '', content: {} }; // Extract content types and their schemas if (endpointDetails.requestBody.content) { Object.keys(endpointDetails.requestBody.content).forEach(contentType => { const contentData = endpointDetails.requestBody.content[contentType]; if (contentData.schema) { requestBody.content[contentType] = { schema: contentData.schema, properties: extractSchemaProperties(contentData.schema), required: contentData.schema.required || [] }; } }); } return requestBody; } /** * Extract schema properties recursively */ function extractSchemaProperties(schema) { if (!schema || !schema.properties) { return {}; } const properties = {}; Object.keys(schema.properties).forEach(propName => { const prop = schema.properties[propName]; properties[propName] = { type: prop.type || 'string', format: prop.format, description: prop.description || `${propName} property`, example: prop.example, enum: prop.enum, items: prop.items, properties: prop.properties ? extractSchemaProperties(prop) : undefined, required: schema.required ? schema.required.includes(propName) : false }; }); return properties; } /** * Extract response schema */ function extractResponseSchema(endpointDetails) { if (!endpointDetails.responses) { return null; } const responses = {}; Object.keys(endpointDetails.responses).forEach(statusCode => { const response = endpointDetails.responses[statusCode]; responses[statusCode] = { description: response.description || '', content: response.content || {} }; }); return responses; } /** * Generate exact tool name following the established convention */ function generateExactToolName(endpoint, completeDetails) { const method = endpoint.method.toLowerCase(); const path = endpoint.path.toLowerCase(); // Extract meaningful parts from the path let pathParts = path.split('/').filter(part => part && !part.startsWith('{') && !part.endsWith('}')); // Remove common prefixes pathParts = pathParts.filter(part => !['api', 'emr', 'emr-api'].includes(part)); // Determine action based on method and path context let action = method; if (method === 'get') { action = 'get'; } else if (method === 'post') { if (path.includes('/login') || path.includes('/register') || path.includes('/create')) { action = 'create'; } else if (path.includes('/search') || path.includes('/find')) { action = 'search'; } else { action = 'create'; } } else if (method === 'put' || method === 'patch') { action = 'update'; } else if (method === 'delete') { action = 'delete'; } // Create resource name from path parts let resource = pathParts.join('_').replace(/-/g, '_'); // Clean up resource name resource = resource.replace(/[^a-z0-9_]/g, ''); // Handle special cases for better naming if (path.includes('/appointment')) { resource = resource.replace(/appointment/, 'appointment'); } if (path.includes('/patient')) { resource = resource.replace(/patient/, 'patient'); } if (path.includes('/meeting')) { resource = resource.replace(/meeting/, 'meeting'); } if (path.includes('/form')) { resource = resource.replace(/form/, 'form'); } if (path.includes('/document')) { resource = resource.replace(/document/, 'document'); } // Ensure we have a resource name if (!resource) { if (completeDetails && completeDetails.operationId) { resource = completeDetails.operationId.toLowerCase().replace(/[^a-z0-9_]/g, '_'); } else { resource = 'unknown'; } } return `provider_${action}_${resource}`; } // Run the extraction if (import.meta.url === `file://${process.argv[1]}`) { extractCompleteProviderDetails(); } export { extractCompleteProviderDetails };