diff --git a/packages/bruno-converters/src/openapi/openapi-to-bruno.js b/packages/bruno-converters/src/openapi/openapi-to-bruno.js index 59929277f..f1dec55b4 100644 --- a/packages/bruno-converters/src/openapi/openapi-to-bruno.js +++ b/packages/bruno-converters/src/openapi/openapi-to-bruno.js @@ -8,14 +8,22 @@ const ensureUrl = (url) => { return url.replace(/([^:])\/{2,}/g, '$1/'); }; -const buildEmptyJsonBody = (bodySchema) => { +const buildEmptyJsonBody = (bodySchema, visited = new Map()) => { + // Check for circular references + if (visited.has(bodySchema)) { + return {}; + } + + // Add this schema to visited map + visited.set(bodySchema, true); + let _jsonBody = {}; each(bodySchema.properties || {}, (prop, name) => { if (prop.type === 'object') { - _jsonBody[name] = buildEmptyJsonBody(prop); + _jsonBody[name] = buildEmptyJsonBody(prop, visited); } else if (prop.type === 'array') { if (prop.items && prop.items.type === 'object') { - _jsonBody[name] = [buildEmptyJsonBody(prop.items)]; + _jsonBody[name] = [buildEmptyJsonBody(prop.items, visited)]; } else { _jsonBody[name] = []; } diff --git a/packages/bruno-converters/tests/openapi/openapi-to-bruno/openapi-circular-references.spec.js b/packages/bruno-converters/tests/openapi/openapi-to-bruno/openapi-circular-references.spec.js new file mode 100644 index 000000000..eedf52567 --- /dev/null +++ b/packages/bruno-converters/tests/openapi/openapi-to-bruno/openapi-circular-references.spec.js @@ -0,0 +1,248 @@ +import { describe, it, expect } from '@jest/globals'; +import openApiToBruno from '../../../src/openapi/openapi-to-bruno'; + +describe('openapi-circular-references', () => { + it('should handle simple circular references in schema correctly', async () => { + const brunoCollection = openApiToBruno(circularRefsData); + + expect(brunoCollection).toMatchObject(circularRefsOutput); + }); + + it('should handle complex circular reference chains correctly', async () => { + const brunoCollection = openApiToBruno(complexCircularRefsData); + + expect(brunoCollection).toMatchObject(circularRefsOutput); + }); +}); + +const circularRefsData = { + "components": { + "schemas": { + "schema_1": { + "additionalProperties": false, + "description": "schema_1", + "properties": { + "conditions": { + "$ref": "#/components/schemas/schema_1" + } + }, + "type": "object" + }, + "schema_2": { + "additionalProperties": false, + "description": "schema_2", + "properties": { + "conditionGroup": { + "description": "nested schema_1", + "items": { "$ref": "#/components/schemas/schema_1" }, + "type": "array" + }, + "operation": { + "description": "operation", + "enum": ["ANY", "ALL"], + "type": "string" + } + }, + "type": "object" + } + } + }, + "info": { + "description": "circular reference openapi sample json spec", + "title": "circular reference openapi sample json spec", + "version": "0.1" + }, + "openapi": "3.0.1", + "paths": { + "/": { + "post": { + "deprecated": false, + "description": "echo ping api", + "operationId": "echo ping", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/schema_1" + } + } + }, + "description": "echo ping api", + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "example": "ping" + } + }, + "description": "Returned if the request is successful." + } + } + } + } + }, + "servers": [{ "url": "https://echo.usebruno.com" }] +}; + +// More complex circular reference test with a longer chain +const complexCircularRefsData = { + "components": { + "schemas": { + "schema_1": { + "additionalProperties": false, + "description": "schema_1", + "properties": { + "conditionGroup": { + "description": "nested schema_1", + "items": { "$ref": "#/components/schemas/schema_2" }, + "type": "array" + } + }, + "type": "object" + }, + "schema_2": { + "additionalProperties": false, + "description": "schema_2", + "properties": { + "conditionGroup": { + "description": "nested schema_2", + "items": { "$ref": "#/components/schemas/schema_3" }, + "type": "array" + } + }, + "type": "object" + }, + "schema_3": { + "additionalProperties": false, + "description": "schema_3", + "properties": { + "conditionGroup": { + "description": "nested schema_3", + "items": { "$ref": "#/components/schemas/schema_4" }, + "type": "array" + } + }, + "type": "object" + }, + "schema_4": { + "additionalProperties": false, + "description": "schema_4", + "properties": { + "conditionGroup": { + "description": "nested schema_4", + "items": { "$ref": "#/components/schemas/schema_5" }, + "type": "array" + } + }, + "type": "object" + }, + "schema_5": { + "additionalProperties": false, + "description": "schema_4", + "properties": { + "conditionGroup": { + "description": "nested schema_5", + "items": { "$ref": "#/components/schemas/schema_1" }, + "type": "array" + } + }, + "type": "object" + }, + "schema_6": { + "additionalProperties": false, + "description": "schema_3", + "properties": { + "conditionGroup": { + "description": "nested schema_3", + "items": { "$ref": "#/components/schemas/schema_1" }, + "type": "array" + }, + "operation": { + "description": "operation", + "enum": ["ANY", "ALL"], + "type": "string" + } + }, + "type": "object" + } + } + }, + "info": { + "description": "circular reference openapi sample json spec", + "title": "circular reference openapi sample json spec", + "version": "0.1" + }, + "openapi": "3.0.1", + "paths": { + "/": { + "post": { + "deprecated": false, + "description": "echo ping api", + "operationId": "echo ping", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/schema_1" + } + } + }, + "description": "echo ping api", + "required": true + }, + "responses": { + "200": { + "content": { + "application/json": { + "example": "ping" + } + }, + "description": "Returned if the request is successful." + } + } + } + } + }, + "servers": [{ "url": "https://echo.usebruno.com" }] +}; + +const circularRefsOutput = { + "environments": [ + { + "name": "Environment 1", + "variables": [ + { + "enabled": true, + "name": "baseUrl", + "secret": false, + "type": "text", + "value": "https://echo.usebruno.com", + }, + ], + }, + ], + "items": [ + { + "name": "echo ping", + "type": "http-request", + "request": { + "url": "{{baseUrl}}/", + "method": "POST", + "auth": { + "mode": "none", + }, + "headers": [], + "params": [], + "body": { + "mode": "json", + } + }, + }, + ], + "name": "circular reference openapi sample json spec", + "version": "1", +}; \ No newline at end of file diff --git a/packages/bruno-converters/tests/openapi/openapi-to-bruno.spec.js b/packages/bruno-converters/tests/openapi/openapi-to-bruno/openapi-to-bruno.spec.js similarity index 97% rename from packages/bruno-converters/tests/openapi/openapi-to-bruno.spec.js rename to packages/bruno-converters/tests/openapi/openapi-to-bruno/openapi-to-bruno.spec.js index f4a06fc44..7c2c60409 100644 --- a/packages/bruno-converters/tests/openapi/openapi-to-bruno.spec.js +++ b/packages/bruno-converters/tests/openapi/openapi-to-bruno/openapi-to-bruno.spec.js @@ -1,5 +1,5 @@ import { describe, it, expect } from '@jest/globals'; -import openApiToBruno from '../../src/openapi/openapi-to-bruno'; +import openApiToBruno from '../../../src/openapi/openapi-to-bruno'; describe('openapi-collection', () => { it('should correctly import a valid OpenAPI file', async () => {