UNPKG

insomnia-plugin-export-to-openapi

Version:

Exports an Insomnia collection to OpenAPI 3.0 YAML format, preserving the folder structure as tags.

147 lines (131 loc) 6.13 kB
const { promises: fs } = require('fs'); const path = require('path'); const yaml = require('js-yaml'); function sanitizeForOperationId(name, isPath = false) { if (!name) return isPath ? 'root' : 'default'; let processedName = isPath ? name.replace(/[\/{}]/g, ' ') : name; processedName = processedName.replace(/[^a-zA-Z0-9 ]/g, '').trim(); if (!processedName) return isPath ? 'root' : 'default'; const parts = processedName.split(/\s+/).filter(p => p); if (parts.length === 0) return isPath ? 'root' : 'default'; return parts[0].toLowerCase() + parts.slice(1).map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(''); } function convertUrlToPath(url) { if (!url) return ''; let path = url.replace(/\{\{.*?base_url.*?\}\}/g, ''); path = path.replace(/\?.*$/, ''); path = path.replace(/:(\w+)/g, '{$1}'); return path.trim(); } function getRequestBody(request) { if (!request.body || !request.body.mimeType) return null; const { mimeType, params } = request.body; const schemaProps = {}; if (params) { for (const param of params) { if (!param.name) continue; const paramName = param.name.replace(/\[.*?\]/g, ''); schemaProps[paramName] = { type: 'string', description: param.description || '', example: param.value || '' }; if (param.type === 'file') schemaProps[paramName].format = 'binary'; } } return { content: { [mimeType]: { schema: { type: 'object', properties: schemaProps } } } }; } function getParameters(request) { const params = []; if (request.pathParameters) { for (const param of request.pathParameters) { if (param.name) params.push({ name: param.name, in: 'path', required: true, schema: { type: 'string' }, description: param.description || '' }); } } if (request.parameters) { for (const param of request.parameters) { if (param.name) params.push({ name: param.name, in: 'query', required: !param.disabled, schema: { type: 'string' }, description: param.description || '' }); } } return params; } function processResources(allRequests, allRequestGroups, parentId, parentTag) { const paths = {}; const children = [...allRequestGroups, ...allRequests].filter(r => r.parentId === parentId); for (const resource of children) { const resourceId = resource._id || ''; if (resourceId.startsWith('fld_')) { const tag = resource.name || parentTag; const nestedPaths = processResources(allRequests, allRequestGroups, resource._id, tag); for (const [path, methods] of Object.entries(nestedPaths)) { if (!paths[path]) paths[path] = {}; Object.assign(paths[path], methods); } } else if (resourceId.startsWith('req_')) { const pathUrl = convertUrlToPath(resource.url); if (!pathUrl) continue; const method = resource.method.toLowerCase(); if (!paths[pathUrl]) paths[pathUrl] = {}; const sanitizedPath = sanitizeForOperationId(pathUrl, true); const sanitizedName = sanitizeForOperationId(resource.name); const operationId = `${method}${sanitizedPath.charAt(0).toUpperCase() + sanitizedPath.slice(1)}${sanitizedName.charAt(0).toUpperCase() + sanitizedName.slice(1)}`; const operation = { summary: resource.name || 'No summary', description: resource.description || '', operationId: operationId, tags: parentTag ? [parentTag] : [], responses: { '200': { description: 'Successful' }, '400': { description: 'Bad Request' }, '500': { description: 'Server Error' } } }; const parameters = getParameters(resource); if (parameters.length > 0) operation.parameters = parameters; const requestBody = getRequestBody(resource); if (requestBody) operation.requestBody = requestBody; paths[pathUrl][method] = operation; } } return paths; } module.exports.workspaceActions = [{ label: 'Export to OpenAPI 3.0', icon: 'fa-file-export', action: async (context, models) => { try { const savePath = await context.app.showSaveDialog({ defaultPath: `${models.workspace.name}-openapi.yaml` }); if (!savePath) { return; } const openapiSpec = { openapi: '3.0.0', info: { title: models.workspace.name, version: '1.0.0', description: models.workspace.description || '', }, servers: [], paths: {} }; const environments = models.environments || []; const requests = models.requests || []; const requestGroups = models.requestGroups || []; const baseEnv = environments.find(e => e.parentId === models.workspace._id); if (baseEnv && baseEnv.data && baseEnv.data.base_url) { openapiSpec.servers.push({ url: baseEnv.data.base_url }); } else { openapiSpec.servers.push({ url: 'http://localhost' }); } openapiSpec.paths = processResources( requests, requestGroups, models.workspace._id, models.workspace.name ); const finalYaml = yaml.dump(openapiSpec, { indent: 2, sortKeys: false }); await fs.writeFile(savePath, finalYaml); context.app.alert('Success!', 'The OpenAPI documentation has been exported.'); } catch (err) { context.app.alert('Error!', `An error occurred during export: ${err.message}`); } }, }];