diff --git a/package-lock.json b/package-lock.json index 769d50f48..150c71b00 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5669,13 +5669,6 @@ "node": ">= 8" } }, - "node_modules/@opencollection/types": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@opencollection/types/-/types-0.1.0.tgz", - "integrity": "sha512-/v64ShE+KyDUAfAlO6Qd5wBwPArd603VC44eife/CdmrtPUSIiFBYcZ9gxAD7LlW99J36wb5IkMpKFDvViINiA==", - "dev": true, - "license": "MIT" - }, "node_modules/@parcel/watcher": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.0.tgz", @@ -31912,7 +31905,7 @@ "devDependencies": { "@babel/preset-env": "^7.22.0", "@babel/preset-typescript": "^7.22.0", - "@opencollection/types": "0.1.0", + "@opencollection/types": "0.2.0", "@rollup/plugin-commonjs": "^23.0.2", "@rollup/plugin-json": "^6.1.0", "@rollup/plugin-node-resolve": "^15.0.1", @@ -31932,6 +31925,13 @@ "typescript": "^4.8.4" } }, + "packages/bruno-filestore/node_modules/@opencollection/types": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@opencollection/types/-/types-0.2.0.tgz", + "integrity": "sha512-Lucjjoy+ZzfdjL0/9HF6PFlNSDG/m11VZBiR2K5XU6ChJ2XXfJyKocRB2g0tm7e5zQNMoVL3oUoDJ2gexx6xyg==", + "dev": true, + "license": "MIT" + }, "packages/bruno-filestore/node_modules/@rollup/plugin-typescript": { "version": "12.3.0", "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-12.3.0.tgz", diff --git a/packages/bruno-filestore/package.json b/packages/bruno-filestore/package.json index 0b7078d46..771fda1ee 100644 --- a/packages/bruno-filestore/package.json +++ b/packages/bruno-filestore/package.json @@ -22,7 +22,7 @@ "devDependencies": { "@babel/preset-env": "^7.22.0", "@babel/preset-typescript": "^7.22.0", - "@opencollection/types": "0.1.0", + "@opencollection/types": "0.2.0", "@usebruno/schema-types": "0.0.1", "@rollup/plugin-commonjs": "^23.0.2", "@rollup/plugin-json": "^6.1.0", diff --git a/packages/bruno-filestore/src/formats/yml/common/auth-oauth2.ts b/packages/bruno-filestore/src/formats/yml/common/auth-oauth2.ts index 5e52918cd..46c1db056 100644 --- a/packages/bruno-filestore/src/formats/yml/common/auth-oauth2.ts +++ b/packages/bruno-filestore/src/formats/yml/common/auth-oauth2.ts @@ -163,7 +163,7 @@ const buildClientCredentialsFlow = (oauth: BrunoOAuth2): OAuth2ClientCredentials const buildResourceOwnerPasswordFlow = (oauth: BrunoOAuth2): OAuth2ResourceOwnerPasswordFlow => { const flow: OAuth2ResourceOwnerPasswordFlow = { type: 'oauth2', - flow: 'resource_owner_password' + flow: 'resource_owner_password_credentials' }; isNonEmptyString(oauth.accessTokenUrl) && (flow.accessTokenUrl = oauth.accessTokenUrl); @@ -394,7 +394,7 @@ export const toBrunoOAuth2 = (oauth: AuthOAuth2 | null | undefined): BrunoOAuth2 } break; - case 'resource_owner_password': + case 'resource_owner_password_credentials': brunoOAuth.grantType = 'password'; if (oauth.accessTokenUrl) brunoOAuth.accessTokenUrl = oauth.accessTokenUrl; if (oauth.refreshTokenUrl) brunoOAuth.refreshTokenUrl = oauth.refreshTokenUrl; diff --git a/packages/bruno-filestore/src/formats/yml/common/headers.ts b/packages/bruno-filestore/src/formats/yml/common/headers.ts index 7dac67c08..55147d53c 100644 --- a/packages/bruno-filestore/src/formats/yml/common/headers.ts +++ b/packages/bruno-filestore/src/formats/yml/common/headers.ts @@ -1,15 +1,15 @@ import type { FolderRequest as BrunoFolderRequest } from '@usebruno/schema-types/collection/folder'; import type { KeyValue as BrunoKeyValue } from '@usebruno/schema-types/common/key-value'; -import type { HttpHeader } from '@opencollection/types/requests/http'; +import type { HttpRequestHeader, HttpResponseHeader } from '@opencollection/types/requests/http'; import { uuid } from '../../../utils'; -export const toOpenCollectionHttpHeaders = (headers: BrunoFolderRequest['headers']): HttpHeader[] | undefined => { +export const toOpenCollectionHttpHeaders = (headers: BrunoFolderRequest['headers']): HttpRequestHeader[] | undefined => { if (!headers?.length) { return undefined; } - const ocHeaders = headers.map((header: BrunoKeyValue): HttpHeader => { - const httpHeader: HttpHeader = { + const ocHeaders = headers.map((header: BrunoKeyValue): HttpRequestHeader => { + const httpHeader: HttpRequestHeader = { name: header.name || '', value: header.value || '' }; @@ -25,17 +25,30 @@ export const toOpenCollectionHttpHeaders = (headers: BrunoFolderRequest['headers return ocHeaders.length ? ocHeaders : undefined; }; -export const toBrunoHttpHeaders = (headers: HttpHeader[] | null | undefined): BrunoKeyValue[] | undefined => { +export const toOpenCollectionResponseHeaders = (headers: BrunoFolderRequest['headers']): HttpResponseHeader[] | undefined => { if (!headers?.length) { return undefined; } - const brunoHeaders = headers.map((header: HttpHeader): BrunoKeyValue => { + const ocHeaders = headers.map((header: BrunoKeyValue): HttpResponseHeader => ({ + name: header.name || '', + value: header.value || '' + })); + + return ocHeaders.length ? ocHeaders : undefined; +}; + +export const toBrunoHttpHeaders = (headers: HttpRequestHeader[] | HttpResponseHeader[] | null | undefined): BrunoKeyValue[] | undefined => { + if (!headers?.length) { + return undefined; + } + + const brunoHeaders = headers.map((header): BrunoKeyValue => { const brunoHeader: BrunoKeyValue = { uid: uuid(), name: header.name || '', value: header.value || '', - enabled: header.disabled !== true + enabled: ('disabled' in header) ? header.disabled !== true : true }; return brunoHeader; diff --git a/packages/bruno-filestore/src/formats/yml/common/scripts.ts b/packages/bruno-filestore/src/formats/yml/common/scripts.ts index 694166691..70e6b9ad1 100644 --- a/packages/bruno-filestore/src/formats/yml/common/scripts.ts +++ b/packages/bruno-filestore/src/formats/yml/common/scripts.ts @@ -1,30 +1,39 @@ -import { Scripts } from '@opencollection/types/common/scripts'; -import { FolderRequest as BrunoFolderRequest } from '@usebruno/schema-types/collection/folder'; -import { HttpRequest as BrunoHttpRequest } from '@usebruno/schema-types/requests/http'; -import { WebSocketRequest as BrunoWebSocketRequest } from '@usebruno/schema-types/requests/websocket'; -import { GrpcRequest as BrunoGrpcRequest } from '@usebruno/schema-types/requests/grpc'; +import type { Scripts, Script } from '@opencollection/types/common/scripts'; +import type { FolderRequest as BrunoFolderRequest } from '@usebruno/schema-types/collection/folder'; +import type { HttpRequest as BrunoHttpRequest } from '@usebruno/schema-types/requests/http'; +import type { WebSocketRequest as BrunoWebSocketRequest } from '@usebruno/schema-types/requests/websocket'; +import type { GrpcRequest as BrunoGrpcRequest } from '@usebruno/schema-types/requests/grpc'; export const toOpenCollectionScripts = (request: BrunoFolderRequest | BrunoHttpRequest | BrunoWebSocketRequest | BrunoGrpcRequest | null | undefined): Scripts | undefined => { - const ocScripts: Scripts = {}; + const ocScripts: Scripts = []; if (request?.script?.req?.trim().length) { - ocScripts.preRequest = request.script.req.trim(); + ocScripts.push({ + type: 'before-request', + code: request.script.req.trim() + }); } if (request?.script?.res?.trim().length) { - ocScripts.postResponse = request.script.res.trim(); + ocScripts.push({ + type: 'after-response', + code: request.script.res.trim() + }); } if (request?.tests?.trim().length) { - ocScripts.tests = request.tests.trim(); + ocScripts.push({ + type: 'tests', + code: request.tests.trim() + }); } - return Object.keys(ocScripts).length > 0 ? ocScripts : undefined; + return ocScripts.length > 0 ? ocScripts : undefined; }; export const toBrunoScripts = (scripts: Scripts | null | undefined): { script?: { req?: string; res?: string }; tests?: string; } | undefined => { - if (!scripts) { + if (!scripts || !Array.isArray(scripts) || scripts.length === 0) { return undefined; } @@ -33,18 +42,22 @@ export const toBrunoScripts = (scripts: Scripts | null | undefined): { tests?: string; } = {}; - if (scripts.preRequest || scripts.postResponse) { - brunoScripts.script = {}; - if (scripts.preRequest) { - brunoScripts.script.req = scripts.preRequest; + for (const script of scripts) { + if (script.type === 'before-request' && script.code) { + if (!brunoScripts.script) { + brunoScripts.script = {}; + } + brunoScripts.script.req = script.code; } - if (scripts.postResponse) { - brunoScripts.script.res = scripts.postResponse; + if (script.type === 'after-response' && script.code) { + if (!brunoScripts.script) { + brunoScripts.script = {}; + } + brunoScripts.script.res = script.code; + } + if (script.type === 'tests' && script.code) { + brunoScripts.tests = script.code; } - } - - if (scripts.tests) { - brunoScripts.tests = scripts.tests; } return Object.keys(brunoScripts).length > 0 ? brunoScripts : undefined; diff --git a/packages/bruno-filestore/src/formats/yml/items/parseGraphQLRequest.ts b/packages/bruno-filestore/src/formats/yml/items/parseGraphQLRequest.ts index 87529a686..f75a5f2e2 100644 --- a/packages/bruno-filestore/src/formats/yml/items/parseGraphQLRequest.ts +++ b/packages/bruno-filestore/src/formats/yml/items/parseGraphQLRequest.ts @@ -10,12 +10,16 @@ import { toBrunoAssertions } from '../common/assertions'; import { uuid } from '../../../utils'; const parseGraphQLRequest = (ocRequest: GraphQLRequest): BrunoItem => { + const info = ocRequest.info; + const graphql = ocRequest.graphql; + const runtime = ocRequest.runtime; + const brunoRequest: BrunoHttpRequest = { - url: ocRequest.url || '', - method: ocRequest.method || 'POST', - headers: toBrunoHttpHeaders(ocRequest.headers) || [], - params: toBrunoParams(ocRequest.params) || [], - auth: toBrunoAuth(ocRequest.auth), + url: graphql?.url || '', + method: graphql?.method || 'POST', + headers: toBrunoHttpHeaders(graphql?.headers) || [], + params: toBrunoParams(graphql?.params) || [], + auth: toBrunoAuth(runtime?.auth), body: { mode: 'graphql', json: null, @@ -25,8 +29,8 @@ const parseGraphQLRequest = (ocRequest: GraphQLRequest): BrunoItem => { formUrlEncoded: [], multipartForm: [], graphql: { - query: (ocRequest.body as GraphQLBody)?.query || null, - variables: (ocRequest.body as GraphQLBody)?.variables || null + query: (graphql?.body as GraphQLBody)?.query || null, + variables: (graphql?.body as GraphQLBody)?.variables || null }, file: [] }, @@ -44,7 +48,7 @@ const parseGraphQLRequest = (ocRequest: GraphQLRequest): BrunoItem => { }; // scripts - const scripts = toBrunoScripts(ocRequest.scripts); + const scripts = toBrunoScripts(runtime?.scripts); if (scripts?.script && brunoRequest.script) { if (scripts.script.req) { brunoRequest.script.req = scripts.script.req; @@ -58,11 +62,11 @@ const parseGraphQLRequest = (ocRequest: GraphQLRequest): BrunoItem => { } // variables - const variables = toBrunoVariables(ocRequest.variables); + const variables = toBrunoVariables(runtime?.variables); brunoRequest.vars = variables; // assertions - const assertions = toBrunoAssertions(ocRequest.assertions); + const assertions = toBrunoAssertions(runtime?.assertions); if (assertions) { brunoRequest.assertions = assertions; } @@ -76,9 +80,9 @@ const parseGraphQLRequest = (ocRequest: GraphQLRequest): BrunoItem => { const brunoItem: BrunoItem = { uid: uuid(), type: 'graphql-request', - seq: ocRequest.seq || 1, - name: ocRequest.name || 'Untitled Request', - tags: ocRequest.tags || [], + seq: info?.seq || 1, + name: info?.name || 'Untitled Request', + tags: info?.tags || [], request: brunoRequest, settings: null, fileContent: null, diff --git a/packages/bruno-filestore/src/formats/yml/items/parseGrpcRequest.ts b/packages/bruno-filestore/src/formats/yml/items/parseGrpcRequest.ts index a9ef69a59..00352c05b 100644 --- a/packages/bruno-filestore/src/formats/yml/items/parseGrpcRequest.ts +++ b/packages/bruno-filestore/src/formats/yml/items/parseGrpcRequest.ts @@ -28,13 +28,17 @@ const toBrunoGrpcMetadata = (metadata: GrpcMetadata[] | null | undefined): Bruno }; const parseGrpcRequest = (ocRequest: GrpcRequest): BrunoItem => { + const info = ocRequest.info; + const grpc = ocRequest.grpc; + const runtime = ocRequest.runtime; + const brunoRequest: BrunoGrpcRequest = { - url: ocRequest.url || '', - method: ocRequest.method || '', - methodType: ocRequest.methodType || '', - protoPath: ocRequest.protoFilePath || null, - headers: toBrunoGrpcMetadata(ocRequest.metadata) || [], - auth: toBrunoAuth(ocRequest.auth), + url: grpc?.url || '', + method: grpc?.method || '', + methodType: grpc?.methodType || '', + protoPath: grpc?.protoFilePath || null, + headers: toBrunoGrpcMetadata(grpc?.metadata) || [], + auth: toBrunoAuth(runtime?.auth), body: { mode: 'grpc', grpc: [] @@ -53,15 +57,15 @@ const parseGrpcRequest = (ocRequest: GrpcRequest): BrunoItem => { }; // message - if (isNonEmptyString(ocRequest.message)) { + if (isNonEmptyString(grpc?.message)) { brunoRequest.body.grpc = [{ name: '', - content: ocRequest.message + content: grpc?.message as string }]; } // scripts - const scripts = toBrunoScripts(ocRequest.scripts); + const scripts = toBrunoScripts(runtime?.scripts); if (scripts?.script && brunoRequest.script) { if (scripts.script.req) { brunoRequest.script.req = scripts.script.req; @@ -75,11 +79,11 @@ const parseGrpcRequest = (ocRequest: GrpcRequest): BrunoItem => { } // variables - const variables = toBrunoVariables(ocRequest.variables); + const variables = toBrunoVariables(runtime?.variables); brunoRequest.vars = variables; // assertions - const assertions = toBrunoAssertions(ocRequest.assertions); + const assertions = toBrunoAssertions(runtime?.assertions); if (assertions) { brunoRequest.assertions = assertions; } @@ -93,9 +97,9 @@ const parseGrpcRequest = (ocRequest: GrpcRequest): BrunoItem => { const brunoItem: BrunoItem = { uid: uuid(), type: 'grpc-request', - seq: ocRequest.seq || 1, - name: ocRequest.name || 'Untitled Request', - tags: ocRequest.tags || [], + seq: info?.seq || 1, + name: info?.name || 'Untitled Request', + tags: info?.tags || [], request: brunoRequest, settings: {}, fileContent: null, diff --git a/packages/bruno-filestore/src/formats/yml/items/parseHttpRequest.ts b/packages/bruno-filestore/src/formats/yml/items/parseHttpRequest.ts index c902162d3..589f1d8fd 100644 --- a/packages/bruno-filestore/src/formats/yml/items/parseHttpRequest.ts +++ b/packages/bruno-filestore/src/formats/yml/items/parseHttpRequest.ts @@ -11,13 +11,17 @@ import { toBrunoAssertions } from '../common/assertions'; import { uuid } from '../../../utils'; const parseHttpRequest = (ocRequest: HttpRequest): BrunoItem => { + const info = ocRequest.info; + const http = ocRequest.http; + const runtime = ocRequest.runtime; + const brunoRequest: BrunoHttpRequest = { - url: ocRequest.url || '', - method: ocRequest.method || 'GET', - headers: toBrunoHttpHeaders(ocRequest.headers) || [], - params: toBrunoParams(ocRequest.params) || [], - auth: toBrunoAuth(ocRequest.auth), - body: toBrunoBody(ocRequest.body as HttpRequestBody) || { + url: http?.url || '', + method: http?.method || 'GET', + headers: toBrunoHttpHeaders(http?.headers) || [], + params: toBrunoParams(http?.params) || [], + auth: toBrunoAuth(runtime?.auth), + body: toBrunoBody(http?.body as HttpRequestBody) || { mode: 'none', json: null, text: null, @@ -42,7 +46,7 @@ const parseHttpRequest = (ocRequest: HttpRequest): BrunoItem => { }; // scripts - const scripts = toBrunoScripts(ocRequest.scripts); + const scripts = toBrunoScripts(runtime?.scripts); if (scripts?.script && brunoRequest.script) { if (scripts.script.req) { brunoRequest.script.req = scripts.script.req; @@ -56,11 +60,11 @@ const parseHttpRequest = (ocRequest: HttpRequest): BrunoItem => { } // variables - const variables = toBrunoVariables(ocRequest.variables); + const variables = toBrunoVariables(runtime?.variables); brunoRequest.vars = variables; // assertions - const assertions = toBrunoAssertions(ocRequest.assertions); + const assertions = toBrunoAssertions(runtime?.assertions); if (assertions) { brunoRequest.assertions = assertions; } @@ -74,9 +78,9 @@ const parseHttpRequest = (ocRequest: HttpRequest): BrunoItem => { const brunoItem: BrunoItem = { uid: uuid(), type: 'http-request', - seq: ocRequest.seq || 1, - name: ocRequest.name || 'Untitled Request', - tags: ocRequest.tags || [], + seq: info?.seq || 1, + name: info?.name || 'Untitled Request', + tags: info?.tags || [], request: brunoRequest, settings: null, fileContent: null, diff --git a/packages/bruno-filestore/src/formats/yml/items/parseScript.ts b/packages/bruno-filestore/src/formats/yml/items/parseScript.ts index f6fe8b1e7..d106b6294 100644 --- a/packages/bruno-filestore/src/formats/yml/items/parseScript.ts +++ b/packages/bruno-filestore/src/formats/yml/items/parseScript.ts @@ -1,8 +1,8 @@ import type { Item as BrunoItem } from '@usebruno/schema-types/collection/item'; -import type { Script } from '@opencollection/types/collection/item'; +import type { ScriptFile } from '@opencollection/types/collection/item'; import { uuid } from '../../../utils'; -const parseScript = (ocScript: Script): BrunoItem => { +const parseScript = (ocScript: ScriptFile): BrunoItem => { const brunoItem: BrunoItem = { uid: uuid(), type: 'js', diff --git a/packages/bruno-filestore/src/formats/yml/items/parseWebsocketRequest.ts b/packages/bruno-filestore/src/formats/yml/items/parseWebsocketRequest.ts index c0b642b01..6d267d216 100644 --- a/packages/bruno-filestore/src/formats/yml/items/parseWebsocketRequest.ts +++ b/packages/bruno-filestore/src/formats/yml/items/parseWebsocketRequest.ts @@ -15,10 +15,14 @@ interface WebSocketRequestWithSettings extends WebSocketRequest { } const parseWebsocketRequest = (ocRequest: WebSocketRequestWithSettings): BrunoItem => { + const info = ocRequest.info; + const websocket = ocRequest.websocket; + const runtime = ocRequest.runtime; + const brunoRequest: BrunoWebSocketRequest = { - url: ocRequest.url || '', - headers: toBrunoHttpHeaders(ocRequest.headers) || [], - auth: toBrunoAuth(ocRequest.auth), + url: websocket?.url || '', + headers: toBrunoHttpHeaders(websocket?.headers) || [], + auth: toBrunoAuth(runtime?.auth), body: { mode: 'ws', ws: [] @@ -37,8 +41,8 @@ const parseWebsocketRequest = (ocRequest: WebSocketRequestWithSettings): BrunoIt }; // message - if (ocRequest.message) { - const message = ocRequest.message as WebSocketMessage; + if (websocket?.message) { + const message = websocket.message as WebSocketMessage; if (message.data?.trim().length) { brunoRequest.body.ws = [{ name: '', @@ -49,7 +53,7 @@ const parseWebsocketRequest = (ocRequest: WebSocketRequestWithSettings): BrunoIt } // scripts - const scripts = toBrunoScripts(ocRequest.scripts); + const scripts = toBrunoScripts(runtime?.scripts); if (scripts?.script && brunoRequest.script) { if (scripts.script.req) { brunoRequest.script.req = scripts.script.req; @@ -63,7 +67,7 @@ const parseWebsocketRequest = (ocRequest: WebSocketRequestWithSettings): BrunoIt } // variables - const variables = toBrunoVariables(ocRequest.variables); + const variables = toBrunoVariables(runtime?.variables); brunoRequest.vars = variables; // docs @@ -90,9 +94,9 @@ const parseWebsocketRequest = (ocRequest: WebSocketRequestWithSettings): BrunoIt const brunoItem: BrunoItem = { uid: uuid(), type: 'ws-request', - seq: ocRequest.seq || 1, - name: ocRequest.name || 'Untitled Request', - tags: ocRequest.tags || [], + seq: info?.seq || 1, + name: info?.name || 'Untitled Request', + tags: info?.tags || [], request: brunoRequest, settings: wsSettings as any, fileContent: null, diff --git a/packages/bruno-filestore/src/formats/yml/items/stringifyGraphQLRequest.ts b/packages/bruno-filestore/src/formats/yml/items/stringifyGraphQLRequest.ts index 6f367237c..963d3f4b5 100644 --- a/packages/bruno-filestore/src/formats/yml/items/stringifyGraphQLRequest.ts +++ b/packages/bruno-filestore/src/formats/yml/items/stringifyGraphQLRequest.ts @@ -1,11 +1,11 @@ import type { Item as BrunoItem, HttpItemSettings as BrunoHttpItemSettings } from '@usebruno/schema-types/collection/item'; import type { HttpRequest as BrunoHttpRequest } from '@usebruno/schema-types/requests/http'; -import type { GraphQLRequest, GraphQLRequestSettings, GraphQLBody } from '@opencollection/types/requests/graphql'; +import type { GraphQLRequest, GraphQLRequestSettings, GraphQLBody, GraphQLRequestInfo, GraphQLRequestDetails, GraphQLRequestRuntime } from '@opencollection/types/requests/graphql'; import type { Auth } from '@opencollection/types/common/auth'; import type { Scripts } from '@opencollection/types/common/scripts'; import type { Variable } from '@opencollection/types/common/variables'; import type { Assertion } from '@opencollection/types/common/assertions'; -import type { HttpRequestParam, HttpHeader } from '@opencollection/types/requests/http'; +import type { HttpRequestParam, HttpRequestHeader } from '@opencollection/types/requests/http'; import { stringifyYml } from '../utils'; import { isNonEmptyString, isNumber } from '../../../utils'; import { toOpenCollectionAuth } from '../common/auth'; @@ -17,32 +17,38 @@ import { toOpenCollectionAssertions } from '../common/assertions'; const stringifyGraphQLRequest = (item: BrunoItem): string => { try { - const ocRequest: GraphQLRequest = { + const ocRequest: GraphQLRequest = {}; + const brunoRequest = item.request as BrunoHttpRequest; + + // info block + const info: GraphQLRequestInfo = { + name: isNonEmptyString(item.name) ? item.name : 'Untitled Request', type: 'graphql' }; - - ocRequest.name = isNonEmptyString(item.name) ? item.name : 'Untitled Request'; - - // sequence if (item.seq) { - ocRequest.seq = item.seq; + info.seq = item.seq; } + if (item.tags?.length) { + info.tags = item.tags; + } + ocRequest.info = info; - const brunoRequest = item.request as BrunoHttpRequest; - // url and method - ocRequest.url = isNonEmptyString(brunoRequest.url) ? brunoRequest.url : ''; - ocRequest.method = isNonEmptyString(brunoRequest.method) ? brunoRequest.method : 'POST'; + // graphql block + const graphql: GraphQLRequestDetails = { + method: isNonEmptyString(brunoRequest.method) ? brunoRequest.method : 'POST', + url: isNonEmptyString(brunoRequest.url) ? brunoRequest.url : '' + }; // headers - const headers: HttpHeader[] | undefined = toOpenCollectionHttpHeaders(brunoRequest.headers); + const headers: HttpRequestHeader[] | undefined = toOpenCollectionHttpHeaders(brunoRequest.headers); if (headers) { - ocRequest.headers = headers; + graphql.headers = headers; } // params const params: HttpRequestParam[] | undefined = toOpenCollectionParams(brunoRequest.params); if (params) { - ocRequest.params = params; + graphql.params = params; } // body @@ -61,83 +67,86 @@ const stringifyGraphQLRequest = (item: BrunoItem): string => { } if (hasBody) { - ocRequest.body = graphqlBody; + graphql.body = graphqlBody; } } - // auth - const auth: Auth | undefined = toOpenCollectionAuth(brunoRequest.auth); - if (auth) { - ocRequest.auth = auth; + ocRequest.graphql = graphql; + + // runtime block + const runtime: GraphQLRequestRuntime = {}; + let hasRuntime = false; + + // variables + const variables: Variable[] | undefined = toOpenCollectionVariables(brunoRequest.vars); + if (variables) { + runtime.variables = variables; + hasRuntime = true; } // scripts const scripts: Scripts | undefined = toOpenCollectionScripts(brunoRequest); if (scripts) { - ocRequest.scripts = scripts; - } - - // variables - const variables: Variable[] | undefined = toOpenCollectionVariables(brunoRequest.vars); - if (variables) { - ocRequest.variables = variables; + runtime.scripts = scripts; + hasRuntime = true; } // assertions const assertions: Assertion[] | undefined = toOpenCollectionAssertions(brunoRequest.assertions); if (assertions) { - ocRequest.assertions = assertions; + runtime.assertions = assertions; + hasRuntime = true; } - // docs - if (isNonEmptyString(brunoRequest.docs)) { - ocRequest.docs = brunoRequest.docs; + // auth + const auth: Auth | undefined = toOpenCollectionAuth(brunoRequest.auth); + if (auth) { + runtime.auth = auth; + hasRuntime = true; + } + + if (hasRuntime) { + ocRequest.runtime = runtime; } // settings const httpSettings = item.settings as BrunoHttpItemSettings | undefined; - ocRequest.settings = {} as GraphQLRequestSettings; + const settings: GraphQLRequestSettings = {}; if (httpSettings?.encodeUrl === true) { - ocRequest.settings.encodeUrl = true; + settings.encodeUrl = true; } else if (httpSettings?.encodeUrl === false) { - ocRequest.settings.encodeUrl = false; + settings.encodeUrl = false; } else { - // todo: we are defaulting to true for now as bruno config does not yet support inherit for encodeUrl - // update this when bruno config supports inherit for encodeUrl - ocRequest.settings.encodeUrl = true; + settings.encodeUrl = true; } const timeout = httpSettings?.timeout; if (isNumber(timeout)) { - ocRequest.settings.timeout = timeout; + settings.timeout = timeout; } else { - // todo: we are defaulting to 0 for now as bruno config does not yet support inherit for timeout - // update this when bruno config supports inherit for timeout - ocRequest.settings.timeout = 0; + settings.timeout = 0; } if (httpSettings?.followRedirects === true) { - ocRequest.settings.followRedirects = true; + settings.followRedirects = true; } else if (httpSettings?.followRedirects === false) { - ocRequest.settings.followRedirects = false; + settings.followRedirects = false; } else { - // todo: we are defaulting to true for now as bruno config does not yet support inherit for followRedirects - // update this when bruno config supports inherit for followRedirects - ocRequest.settings.followRedirects = true; + settings.followRedirects = true; } const maxRedirects = httpSettings?.maxRedirects; if (isNumber(maxRedirects)) { - ocRequest.settings.maxRedirects = maxRedirects; + settings.maxRedirects = maxRedirects; } else { - // todo: we are defaulting to 5 for now as bruno config does not yet support inherit for maxRedirects - // update this when bruno config supports inherit for maxRedirects - ocRequest.settings.maxRedirects = 5; + settings.maxRedirects = 5; } - // tags - if (item.tags?.length) { - ocRequest.tags = item.tags; + ocRequest.settings = settings; + + // docs + if (isNonEmptyString(brunoRequest.docs)) { + ocRequest.docs = brunoRequest.docs; } return stringifyYml(ocRequest); diff --git a/packages/bruno-filestore/src/formats/yml/items/stringifyGrpcRequest.ts b/packages/bruno-filestore/src/formats/yml/items/stringifyGrpcRequest.ts index a0557eba7..0644cce5f 100644 --- a/packages/bruno-filestore/src/formats/yml/items/stringifyGrpcRequest.ts +++ b/packages/bruno-filestore/src/formats/yml/items/stringifyGrpcRequest.ts @@ -1,7 +1,7 @@ import type { Item as BrunoItem } from '@usebruno/schema-types/collection/item'; import type { KeyValue as BrunoKeyValue } from '@usebruno/schema-types/common/key-value'; import type { GrpcRequest as BrunoGrpcRequest } from '@usebruno/schema-types/requests/grpc'; -import type { GrpcRequest, GrpcMetadata, GrpcMessage, GrpcMessageVariant } from '@opencollection/types/requests/grpc'; +import type { GrpcRequest, GrpcMetadata, GrpcMessage, GrpcRequestInfo, GrpcRequestDetails, GrpcRequestRuntime } from '@opencollection/types/requests/grpc'; import type { Auth } from '@opencollection/types/common/auth'; import type { Scripts } from '@opencollection/types/common/scripts'; import type { Variable } from '@opencollection/types/common/variables'; @@ -15,30 +15,36 @@ import { toOpenCollectionAssertions } from '../common/assertions'; const stringifyGrpcRequest = (item: BrunoItem): string => { try { - const ocRequest: GrpcRequest = { + const ocRequest: GrpcRequest = {}; + const brunoRequest = item.request as BrunoGrpcRequest; + + // info block + const info: GrpcRequestInfo = { + name: isNonEmptyString(item.name) ? item.name : 'Untitled Request', type: 'grpc' }; - - ocRequest.name = isNonEmptyString(item.name) ? item.name : 'Untitled Request'; - - // sequence if (item.seq) { - ocRequest.seq = item.seq; + info.seq = item.seq; } + if (item.tags?.length) { + info.tags = item.tags; + } + ocRequest.info = info; - const brunoRequest = item.request as BrunoGrpcRequest; - // url and method - ocRequest.url = isNonEmptyString(brunoRequest.url) ? brunoRequest.url : ''; - ocRequest.method = isNonEmptyString(brunoRequest.method) ? brunoRequest.method : ''; + // grpc block + const grpc: GrpcRequestDetails = { + url: isNonEmptyString(brunoRequest.url) ? brunoRequest.url : '', + method: isNonEmptyString(brunoRequest.method) ? brunoRequest.method : '' + }; // method type if (brunoRequest.methodType) { - ocRequest.methodType = brunoRequest.methodType; + grpc.methodType = brunoRequest.methodType; } // proto file path if (isNonEmptyString(brunoRequest.protoPath)) { - ocRequest.protoFilePath = brunoRequest.protoPath; + grpc.protoFilePath = brunoRequest.protoPath; } // metadata @@ -61,7 +67,7 @@ const stringifyGrpcRequest = (item: BrunoItem): string => { }); if (metadata.length) { - ocRequest.metadata = metadata; + grpc.metadata = metadata; } } @@ -74,33 +80,47 @@ const stringifyGrpcRequest = (item: BrunoItem): string => { if (messages.length) { const message: GrpcMessage = messages[0].content || ''; if (message.trim().length) { - ocRequest.message = message; + grpc.message = message; } } } - // auth - const auth: Auth | undefined = toOpenCollectionAuth(brunoRequest.auth); - if (auth) { - ocRequest.auth = auth; + ocRequest.grpc = grpc; + + // runtime block + const runtime: GrpcRequestRuntime = {}; + let hasRuntime = false; + + // variables + const variables: Variable[] | undefined = toOpenCollectionVariables(brunoRequest.vars); + if (variables) { + runtime.variables = variables; + hasRuntime = true; } // scripts const scripts: Scripts | undefined = toOpenCollectionScripts(brunoRequest); if (scripts) { - ocRequest.scripts = scripts; - } - - // variables - const variables: Variable[] | undefined = toOpenCollectionVariables(brunoRequest.vars); - if (variables) { - ocRequest.variables = variables; + runtime.scripts = scripts; + hasRuntime = true; } // assertions const assertions: Assertion[] | undefined = toOpenCollectionAssertions(brunoRequest.assertions); if (assertions) { - ocRequest.assertions = assertions; + runtime.assertions = assertions; + hasRuntime = true; + } + + // auth + const auth: Auth | undefined = toOpenCollectionAuth(brunoRequest.auth); + if (auth) { + runtime.auth = auth; + hasRuntime = true; + } + + if (hasRuntime) { + ocRequest.runtime = runtime; } // docs @@ -108,11 +128,6 @@ const stringifyGrpcRequest = (item: BrunoItem): string => { ocRequest.docs = brunoRequest.docs; } - // tags - if (item.tags?.length) { - ocRequest.tags = item.tags; - } - return stringifyYml(ocRequest); } catch (error) { console.error('Error stringifying gRPC request:', error); diff --git a/packages/bruno-filestore/src/formats/yml/items/stringifyHttpRequest.ts b/packages/bruno-filestore/src/formats/yml/items/stringifyHttpRequest.ts index c743f3527..61a4d0684 100644 --- a/packages/bruno-filestore/src/formats/yml/items/stringifyHttpRequest.ts +++ b/packages/bruno-filestore/src/formats/yml/items/stringifyHttpRequest.ts @@ -1,14 +1,14 @@ import type { Item as BrunoItem, HttpItemSettings as BrunoHttpItemSettings } from '@usebruno/schema-types/collection/item'; import type { HttpRequest as BrunoHttpRequest } from '@usebruno/schema-types/requests/http'; -import type { HttpRequest, HttpRequestSettings, HttpRequestExample } from '@opencollection/types/requests/http'; +import type { HttpRequest, HttpRequestSettings, HttpRequestExample, HttpRequestInfo, HttpRequestDetails, HttpRequestRuntime, HttpRequestHeader } from '@opencollection/types/requests/http'; import type { Auth } from '@opencollection/types/common/auth'; import type { Scripts } from '@opencollection/types/common/scripts'; import type { Variable } from '@opencollection/types/common/variables'; import type { Assertion } from '@opencollection/types/common/assertions'; -import type { HttpRequestParam, HttpHeader, HttpRequestBody } from '@opencollection/types/requests/http'; +import type { HttpRequestParam, HttpRequestBody } from '@opencollection/types/requests/http'; import { stringifyYml } from '../utils'; import { toOpenCollectionAuth } from '../common/auth'; -import { toOpenCollectionHttpHeaders } from '../common/headers'; +import { toOpenCollectionHttpHeaders, toOpenCollectionResponseHeaders } from '../common/headers'; import { toOpenCollectionParams } from '../common/params'; import { toOpenCollectionBody } from '../common/body'; import { toOpenCollectionVariables } from '../common/variables'; @@ -18,114 +18,118 @@ import { isNumber, isNonEmptyString } from '../../../utils'; const stringifyHttpRequest = (item: BrunoItem): string => { try { - const ocRequest: HttpRequest = { + const ocRequest: HttpRequest = {}; + const brunoRequest = item.request as BrunoHttpRequest; + + // info block + const info: HttpRequestInfo = { + name: isNonEmptyString(item.name) ? item.name : 'Untitled Request', type: 'http' }; - - ocRequest.name = isNonEmptyString(item.name) ? item.name : 'Untitled Request'; - - // sequence if (item.seq) { - ocRequest.seq = item.seq; + info.seq = item.seq; } + if (item.tags?.length) { + info.tags = item.tags; + } + ocRequest.info = info; - const brunoRequest = item.request as BrunoHttpRequest; - // url and method - ocRequest.url = isNonEmptyString(brunoRequest.url) ? brunoRequest.url : ''; - ocRequest.method = isNonEmptyString(brunoRequest.method) ? brunoRequest.method : 'GET'; + // http block + const http: HttpRequestDetails = { + method: isNonEmptyString(brunoRequest.method) ? brunoRequest.method : 'GET', + url: isNonEmptyString(brunoRequest.url) ? brunoRequest.url : '' + }; // headers - const headers: HttpHeader[] | undefined = toOpenCollectionHttpHeaders(brunoRequest.headers); + const headers: HttpRequestHeader[] | undefined = toOpenCollectionHttpHeaders(brunoRequest.headers); if (headers) { - ocRequest.headers = headers; + http.headers = headers; } // params const params: HttpRequestParam[] | undefined = toOpenCollectionParams(brunoRequest.params); if (params) { - ocRequest.params = params; + http.params = params; } // body const body: HttpRequestBody | undefined = toOpenCollectionBody(brunoRequest.body); if (body) { - ocRequest.body = body; + http.body = body; } - // auth - const auth: Auth | undefined = toOpenCollectionAuth(brunoRequest.auth); - if (auth) { - ocRequest.auth = auth; + ocRequest.http = http; + + // runtime block + const runtime: HttpRequestRuntime = {}; + let hasRuntime = false; + + // variables + const variables: Variable[] | undefined = toOpenCollectionVariables(brunoRequest.vars); + if (variables) { + runtime.variables = variables; + hasRuntime = true; } // scripts const scripts: Scripts | undefined = toOpenCollectionScripts(brunoRequest); if (scripts) { - ocRequest.scripts = scripts; - } - - // variables - const variables: Variable[] | undefined = toOpenCollectionVariables(brunoRequest.vars); - if (variables) { - ocRequest.variables = variables; + runtime.scripts = scripts; + hasRuntime = true; } // assertions const assertions: Assertion[] | undefined = toOpenCollectionAssertions(brunoRequest.assertions); if (assertions) { - ocRequest.assertions = assertions; + runtime.assertions = assertions; + hasRuntime = true; } - // docs - if (isNonEmptyString(brunoRequest.docs)) { - ocRequest.docs = brunoRequest.docs; + // auth + const auth: Auth | undefined = toOpenCollectionAuth(brunoRequest.auth); + if (auth) { + runtime.auth = auth; + hasRuntime = true; + } + + if (hasRuntime) { + ocRequest.runtime = runtime; } // settings const httpSettings = item.settings as BrunoHttpItemSettings | undefined; - ocRequest.settings = {} as HttpRequestSettings; + const settings: HttpRequestSettings = {}; if (httpSettings?.encodeUrl === true) { - ocRequest.settings.encodeUrl = true; + settings.encodeUrl = true; } else if (httpSettings?.encodeUrl === false) { - ocRequest.settings.encodeUrl = false; + settings.encodeUrl = false; } else { - // todo: we are defaulting to true for now as bruno config does not yet support inherit for encodeUrl - // update this when bruno config supports inherit for encodeUrl - ocRequest.settings.encodeUrl = true; + settings.encodeUrl = true; } const timeout = httpSettings?.timeout; if (isNumber(timeout)) { - ocRequest.settings.timeout = timeout; + settings.timeout = timeout; } else { - // todo: we are defaulting to 0 for now as bruno config does not yet support inherit for timeout - // update this when bruno config supports inherit for timeout - ocRequest.settings.timeout = 0; + settings.timeout = 0; } if (httpSettings?.followRedirects === true) { - ocRequest.settings.followRedirects = true; + settings.followRedirects = true; } else if (httpSettings?.followRedirects === false) { - ocRequest.settings.followRedirects = false; + settings.followRedirects = false; } else { - // todo: we are defaulting to true for now as bruno config does not yet support inherit for followRedirects - // update this when bruno config supports inherit for followRedirects - ocRequest.settings.followRedirects = true; + settings.followRedirects = true; } const maxRedirects = httpSettings?.maxRedirects; if (isNumber(maxRedirects)) { - ocRequest.settings.maxRedirects = maxRedirects; + settings.maxRedirects = maxRedirects; } else { - // todo: we are defaulting to 5 for now as bruno config does not yet support inherit for maxRedirects - // update this when bruno config supports inherit for maxRedirects - ocRequest.settings.maxRedirects = 5; + settings.maxRedirects = 5; } - // tags - if (item.tags?.length) { - ocRequest.tags = item.tags; - } + ocRequest.settings = settings; // examples if (item.examples?.length) { @@ -169,7 +173,7 @@ const stringifyHttpRequest = (item: BrunoItem): string => { ocExample.response.statusText = example.response.statusText; } - const responseHeaders = toOpenCollectionHttpHeaders(example.response.headers); + const responseHeaders = toOpenCollectionResponseHeaders(example.response.headers); if (responseHeaders) { ocExample.response.headers = responseHeaders; } @@ -185,12 +189,16 @@ const stringifyHttpRequest = (item: BrunoItem): string => { return ocExample; }); - // examples if (examples?.length) { ocRequest.examples = examples; } } + // docs + if (isNonEmptyString(brunoRequest.docs)) { + ocRequest.docs = brunoRequest.docs; + } + return stringifyYml(ocRequest); } catch (error) { console.error('Error stringifying HTTP request:', error); diff --git a/packages/bruno-filestore/src/formats/yml/items/stringifyScript.ts b/packages/bruno-filestore/src/formats/yml/items/stringifyScript.ts index c56e838d7..0998275e2 100644 --- a/packages/bruno-filestore/src/formats/yml/items/stringifyScript.ts +++ b/packages/bruno-filestore/src/formats/yml/items/stringifyScript.ts @@ -1,10 +1,10 @@ import type { Item as BrunoItem } from '@usebruno/schema-types/collection/item'; -import type { Script } from '@opencollection/types/collection/item'; +import type { ScriptFile } from '@opencollection/types/collection/item'; import { stringifyYml } from '../utils'; const stringifyScript = (item: BrunoItem): string => { try { - const ocScript: Script = { + const ocScript: ScriptFile = { type: 'script' }; diff --git a/packages/bruno-filestore/src/formats/yml/items/stringifyWebsocketRequest.ts b/packages/bruno-filestore/src/formats/yml/items/stringifyWebsocketRequest.ts index ab45a3e91..9a5c190f0 100644 --- a/packages/bruno-filestore/src/formats/yml/items/stringifyWebsocketRequest.ts +++ b/packages/bruno-filestore/src/formats/yml/items/stringifyWebsocketRequest.ts @@ -1,10 +1,10 @@ import type { Item as BrunoItem } from '@usebruno/schema-types/collection/item'; import type { WebSocketRequest as BrunoWebSocketRequest } from '@usebruno/schema-types/requests/websocket'; -import type { WebSocketRequest, WebSocketMessage, WebSocketMessageVariant } from '@opencollection/types/requests/websocket'; +import type { WebSocketRequest, WebSocketMessage, WebSocketRequestInfo, WebSocketRequestDetails, WebSocketRequestRuntime } from '@opencollection/types/requests/websocket'; import type { Auth } from '@opencollection/types/common/auth'; import type { Scripts } from '@opencollection/types/common/scripts'; import type { Variable } from '@opencollection/types/common/variables'; -import type { HttpHeader } from '@opencollection/types/requests/http'; +import type { HttpRequestHeader } from '@opencollection/types/requests/http'; import { stringifyYml } from '../utils'; import { isNonEmptyString } from '../../../utils'; import { toOpenCollectionAuth } from '../common/auth'; @@ -21,25 +21,31 @@ interface WebSocketRequestWithSettings extends WebSocketRequest { const stringifyWebsocketRequest = (item: BrunoItem): string => { try { - const ocRequest: WebSocketRequestWithSettings = { + const ocRequest: WebSocketRequestWithSettings = {}; + const brunoRequest = item.request as BrunoWebSocketRequest; + + // info block + const info: WebSocketRequestInfo = { + name: isNonEmptyString(item.name) ? item.name : 'Untitled Request', type: 'websocket' }; - - ocRequest.name = isNonEmptyString(item.name) ? item.name : 'Untitled Request'; - - // sequence if (item.seq) { - ocRequest.seq = item.seq; + info.seq = item.seq; } + if (item.tags?.length) { + info.tags = item.tags; + } + ocRequest.info = info; - const brunoRequest = item.request as BrunoWebSocketRequest; - // url - ocRequest.url = isNonEmptyString(brunoRequest.url) ? brunoRequest.url : ''; + // websocket block + const websocket: WebSocketRequestDetails = { + url: isNonEmptyString(brunoRequest.url) ? brunoRequest.url : '' + }; // headers - const headers: HttpHeader[] | undefined = toOpenCollectionHttpHeaders(brunoRequest.headers); + const headers: HttpRequestHeader[] | undefined = toOpenCollectionHttpHeaders(brunoRequest.headers); if (headers) { - ocRequest.headers = headers; + websocket.headers = headers; } // message @@ -55,37 +61,40 @@ const stringifyWebsocketRequest = (item: BrunoItem): string => { data: msg.content || '' }; if (message.data.trim().length) { - ocRequest.message = message; + websocket.message = message; } } } - // auth - const auth: Auth | undefined = toOpenCollectionAuth(brunoRequest.auth); - if (auth) { - ocRequest.auth = auth; + ocRequest.websocket = websocket; + + // runtime block + const runtime: WebSocketRequestRuntime = {}; + let hasRuntime = false; + + // variables + const variables: Variable[] | undefined = toOpenCollectionVariables(brunoRequest.vars); + if (variables) { + runtime.variables = variables; + hasRuntime = true; } // scripts const scripts: Scripts | undefined = toOpenCollectionScripts(brunoRequest); if (scripts) { - ocRequest.scripts = scripts; + runtime.scripts = scripts; + hasRuntime = true; } - // variables - const variables: Variable[] | undefined = toOpenCollectionVariables(brunoRequest.vars); - if (variables) { - ocRequest.variables = variables; + // auth + const auth: Auth | undefined = toOpenCollectionAuth(brunoRequest.auth); + if (auth) { + runtime.auth = auth; + hasRuntime = true; } - // docs - if (isNonEmptyString(brunoRequest.docs)) { - ocRequest.docs = brunoRequest.docs; - } - - // tags - if (item.tags?.length) { - ocRequest.tags = item.tags; + if (hasRuntime) { + ocRequest.runtime = runtime; } // settings @@ -98,6 +107,11 @@ const stringifyWebsocketRequest = (item: BrunoItem): string => { ocRequest.settings.keepAliveInterval = !isNaN(keepAliveInterval) ? keepAliveInterval : 0; } + // docs + if (isNonEmptyString(brunoRequest.docs)) { + ocRequest.docs = brunoRequest.docs; + } + return stringifyYml(ocRequest); } catch (error) { console.error('Error stringifying WebSocket request:', error); diff --git a/packages/bruno-filestore/src/formats/yml/parseEnvironment.ts b/packages/bruno-filestore/src/formats/yml/parseEnvironment.ts index 412a0bc2f..564a2e6c4 100644 --- a/packages/bruno-filestore/src/formats/yml/parseEnvironment.ts +++ b/packages/bruno-filestore/src/formats/yml/parseEnvironment.ts @@ -1,22 +1,36 @@ import type { Environment as BrunoEnvironment, EnvironmentVariable as BrunoEnvironmentVariable } from '@usebruno/schema-types/collection/environment'; import type { Environment } from '@opencollection/types/config/environments'; -import type { Variable } from '@opencollection/types/common/variables'; +import type { Variable, SecretVariable } from '@opencollection/types/common/variables'; import { parseYml } from './utils'; import { uuid } from '../../utils'; -const toBrunoEnvironmentVariables = (variables: Variable[] | null | undefined): BrunoEnvironmentVariable[] => { +const isSecretVariable = (v: Variable | SecretVariable): v is SecretVariable => { + return 'secret' in v && v.secret === true; +}; + +const toBrunoEnvironmentVariables = (variables: (Variable | SecretVariable)[] | null | undefined): BrunoEnvironmentVariable[] => { if (!variables?.length) { return []; } - return variables.map((v: Variable): BrunoEnvironmentVariable => { + return variables.map((v): BrunoEnvironmentVariable => { + if (isSecretVariable(v)) { + return { + uid: uuid(), + name: v.name || '', + value: '', + type: 'text', + enabled: v.disabled !== true, + secret: true + }; + } const variable: BrunoEnvironmentVariable = { uid: uuid(), name: v.name || '', - value: v.value as string || '', + value: (typeof v.value === 'string' ? v.value : '') || '', type: 'text', enabled: v.disabled !== true, - secret: v.transient === true + secret: false }; return variable; }); diff --git a/packages/bruno-filestore/src/formats/yml/parseFolder.ts b/packages/bruno-filestore/src/formats/yml/parseFolder.ts index 40858c5cc..98227f851 100644 --- a/packages/bruno-filestore/src/formats/yml/parseFolder.ts +++ b/packages/bruno-filestore/src/formats/yml/parseFolder.ts @@ -11,10 +11,12 @@ const parseFolder = (ymlString: string): FolderRoot => { try { const ocFolder: Folder = parseYml(ymlString); + const info = ocFolder.info; + const folderRoot: FolderRoot = { meta: { - name: ocFolder.name || 'Untitled Folder', - seq: ocFolder.seq || 1 + name: info?.name || 'Untitled Folder', + seq: info?.seq || 1 }, request: null, docs: null @@ -67,9 +69,13 @@ const parseFolder = (ymlString: string): FolderRoot => { } } - // docs - if (isNonEmptyString(ocFolder.docs)) { - folderRoot.docs = ocFolder.docs; + // docs (now at root level) + if (ocFolder.docs) { + if (typeof ocFolder.docs === 'string' && ocFolder.docs.trim().length) { + folderRoot.docs = ocFolder.docs; + } else if (typeof ocFolder.docs === 'object' && ocFolder.docs.content?.trim().length) { + folderRoot.docs = ocFolder.docs.content; + } } return folderRoot; diff --git a/packages/bruno-filestore/src/formats/yml/parseItem.ts b/packages/bruno-filestore/src/formats/yml/parseItem.ts index db70a6a92..337f37cd7 100644 --- a/packages/bruno-filestore/src/formats/yml/parseItem.ts +++ b/packages/bruno-filestore/src/formats/yml/parseItem.ts @@ -1,5 +1,9 @@ import type { Item as BrunoItem } from '@usebruno/schema-types/collection/item'; -import type { Item } from '@opencollection/types/collection/item'; +import type { Item, ScriptFile } from '@opencollection/types/collection/item'; +import type { HttpRequest } from '@opencollection/types/requests/http'; +import type { GraphQLRequest } from '@opencollection/types/requests/graphql'; +import type { GrpcRequest } from '@opencollection/types/requests/grpc'; +import type { WebSocketRequest } from '@opencollection/types/requests/websocket'; import { parseYml } from './utils'; import parseHttpRequest from './items/parseHttpRequest'; import parseGraphQLRequest from './items/parseGraphQLRequest'; @@ -7,35 +11,48 @@ import parseGrpcRequest from './items/parseGrpcRequest'; import parseWebsocketRequest from './items/parseWebsocketRequest'; import parseScript from './items/parseScript'; +// Helper to get the type from an item (now in info block) +const getItemType = (item: Item): string | undefined => { + if ('info' in item && item.info && 'type' in item.info) { + return item.info.type; + } + // For ScriptFile which still has type at root + if ('type' in item) { + return (item as ScriptFile).type; + } + return undefined; +}; + const parseItem = (ymlString: string): BrunoItem => { try { const ocItem: Item = parseYml(ymlString); + const itemType = getItemType(ocItem); - if (!ocItem || !ocItem.type) { + if (!ocItem || !itemType) { throw new Error('Invalid item: missing type'); } - switch (ocItem.type) { + switch (itemType) { case 'http': - return parseHttpRequest(ocItem); + return parseHttpRequest(ocItem as HttpRequest); case 'graphql': - return parseGraphQLRequest(ocItem); + return parseGraphQLRequest(ocItem as GraphQLRequest); case 'grpc': - return parseGrpcRequest(ocItem); + return parseGrpcRequest(ocItem as GrpcRequest); case 'websocket': - return parseWebsocketRequest(ocItem); + return parseWebsocketRequest(ocItem as WebSocketRequest); case 'script': - return parseScript(ocItem); + return parseScript(ocItem as ScriptFile); case 'folder': throw new Error('Folder items should be handled separately using parseFolder'); default: - throw new Error(`Unsupported item type: ${(ocItem as any).type}`); + throw new Error(`Unsupported item type: ${itemType}`); } } catch (error) { console.error('Error parsing item:', error); diff --git a/packages/bruno-filestore/src/formats/yml/stringifyCollection.ts b/packages/bruno-filestore/src/formats/yml/stringifyCollection.ts index 2c08446e9..4d0b74a2e 100644 --- a/packages/bruno-filestore/src/formats/yml/stringifyCollection.ts +++ b/packages/bruno-filestore/src/formats/yml/stringifyCollection.ts @@ -1,6 +1,6 @@ import type { OpenCollection } from '@opencollection/types'; import type { ProtoFileItem, ProtoFileImportPath } from '@opencollection/types/config/protobuf'; -import type { HttpHeader } from '@opencollection/types/requests/http'; +import type { HttpRequestHeader } from '@opencollection/types/requests/http'; import type { ClientCertificate, PemCertificate, Pkcs12Certificate } from '@opencollection/types/config/certificates'; import type { Variable } from '@opencollection/types/common/variables'; import type { Scripts } from '@opencollection/types/common/scripts'; @@ -128,7 +128,7 @@ const stringifyCollection = (collectionRoot: any, brunoConfig: any): string => { // headers if (collectionRoot.request?.headers?.length) { - const ocHeaders: HttpHeader[] | undefined = toOpenCollectionHttpHeaders(collectionRoot.request?.headers); + const ocHeaders: HttpRequestHeader[] | undefined = toOpenCollectionHttpHeaders(collectionRoot.request?.headers); if (ocHeaders) { oc.request.headers = ocHeaders; } diff --git a/packages/bruno-filestore/src/formats/yml/stringifyEnvironment.ts b/packages/bruno-filestore/src/formats/yml/stringifyEnvironment.ts index 9486656ec..640cef6b2 100644 --- a/packages/bruno-filestore/src/formats/yml/stringifyEnvironment.ts +++ b/packages/bruno-filestore/src/formats/yml/stringifyEnvironment.ts @@ -1,20 +1,31 @@ import type { Environment as BrunoEnvironment, EnvironmentVariable as BrunoEnvironmentVariable } from '@usebruno/schema-types/collection/environment'; import type { Environment } from '@opencollection/types/config/environments'; -import type { Variable } from '@opencollection/types/common/variables'; +import type { Variable, SecretVariable } from '@opencollection/types/common/variables'; import { stringifyYml } from './utils'; -const toOpenCollectionEnvironmentVariables = (variables: BrunoEnvironmentVariable[]): Variable[] | undefined => { +const toOpenCollectionEnvironmentVariables = (variables: BrunoEnvironmentVariable[]): (Variable | SecretVariable)[] | undefined => { if (!variables?.length) { return undefined; } - const ocVariables: Variable[] = variables + const ocVariables: (Variable | SecretVariable)[] = variables .filter((v: BrunoEnvironmentVariable) => { - // todo: currently neithwe bru lang nor bruno app supports non-string values + // todo: currently neither bru lang nor bruno app supports non-string values // update this when bruno app supports non-string values return typeof v.value === 'string'; }) - .map((v: BrunoEnvironmentVariable): Variable => { + .map((v: BrunoEnvironmentVariable): Variable | SecretVariable => { + if (v.secret === true) { + const secretVar: SecretVariable = { + secret: true, + name: v.name || '' + }; + if (v.enabled === false) { + secretVar.disabled = true; + } + return secretVar; + } + const variable: Variable = { name: v.name || '', value: v.value as string @@ -24,10 +35,6 @@ const toOpenCollectionEnvironmentVariables = (variables: BrunoEnvironmentVariabl variable.disabled = true; } - if (v.secret === true) { - variable.transient = true; - } - return variable; }); diff --git a/packages/bruno-filestore/src/formats/yml/stringifyFolder.ts b/packages/bruno-filestore/src/formats/yml/stringifyFolder.ts index 2210551e1..493d7ac65 100644 --- a/packages/bruno-filestore/src/formats/yml/stringifyFolder.ts +++ b/packages/bruno-filestore/src/formats/yml/stringifyFolder.ts @@ -1,8 +1,9 @@ import type { FolderRoot } from '@usebruno/schema-types/collection/folder'; -import type { Folder } from '@opencollection/types/collection/item'; +import type { Folder, FolderInfo } from '@opencollection/types/collection/item'; import type { Variable } from '@opencollection/types/common/variables'; import type { Scripts } from '@opencollection/types/common/scripts'; -import type { Auth, HttpHeader } from '@opencollection/types/requests/http'; +import type { Auth } from '@opencollection/types/common/auth'; +import type { HttpRequestHeader } from '@opencollection/types/requests/http'; import type { RequestDefaults } from '@opencollection/types/common/request-defaults'; import { toOpenCollectionAuth } from './common/auth'; import { toOpenCollectionHttpHeaders } from './common/headers'; @@ -31,12 +32,15 @@ const hasRequestScripts = (folderRoot: FolderRoot): boolean => { const stringifyFolder = (folderRoot: FolderRoot): string => { try { - const ocFolder: Folder = { - type: 'folder' - }; + const ocFolder: Folder = {}; - ocFolder.name = folderRoot.meta?.name || 'Untitled Folder'; - ocFolder.seq = folderRoot.meta?.seq || 1; + // info block + const info: FolderInfo = { + name: folderRoot.meta?.name || 'Untitled Folder', + type: 'folder', + seq: folderRoot.meta?.seq || 1 + }; + ocFolder.info = info; // request defaults if (hasRequestDefaults(folderRoot)) { @@ -44,7 +48,7 @@ const stringifyFolder = (folderRoot: FolderRoot): string => { // headers if (folderRoot.request?.headers?.length) { - const ocHeaders: HttpHeader[] | undefined = toOpenCollectionHttpHeaders(folderRoot.request?.headers); + const ocHeaders: HttpRequestHeader[] | undefined = toOpenCollectionHttpHeaders(folderRoot.request?.headers); if (ocHeaders) { ocFolder.request.headers = ocHeaders; } diff --git a/packages/bruno-filestore/src/formats/yml/utils.ts b/packages/bruno-filestore/src/formats/yml/utils.ts index 71011a283..0b7e9a1ef 100644 --- a/packages/bruno-filestore/src/formats/yml/utils.ts +++ b/packages/bruno-filestore/src/formats/yml/utils.ts @@ -1,12 +1,36 @@ import * as YAML from 'yaml'; +// Top-level keys that should have a blank line before them +const BLOCK_KEYS = ['info', 'http', 'graphql', 'grpc', 'websocket', 'runtime', 'settings', 'examples', 'docs', 'items', 'request']; + export const stringifyYml = (obj: any): string => { - return YAML.stringify(obj, { + const yamlStr = YAML.stringify(obj, { lineWidth: 0, indent: 2, minContentWidth: 0, defaultStringType: 'PLAIN' }); + + // Add blank lines before major blocks (only at the top level, not indented) + const lines = yamlStr.split('\n'); + const result: string[] = []; + + for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + // Check if this is a top-level key (no leading whitespace) that should have a blank line + if (i > 0 && !line.startsWith(' ') && !line.startsWith('\t')) { + const key = line.split(':')[0]; + if (BLOCK_KEYS.includes(key)) { + // Add blank line before this block (if previous line isn't already blank) + if (result.length > 0 && result[result.length - 1].trim() !== '') { + result.push(''); + } + } + } + result.push(line); + } + + return result.join('\n'); }; export const parseYml = (ymlString: string): any => {