diff --git a/packages/bruno-filestore/src/formats/yml/common/actions.ts b/packages/bruno-filestore/src/formats/yml/common/actions.ts index 4a0006604..54b643a2e 100644 --- a/packages/bruno-filestore/src/formats/yml/common/actions.ts +++ b/packages/bruno-filestore/src/formats/yml/common/actions.ts @@ -1,6 +1,6 @@ import type { Action, ActionSetVariable, ActionVariableScope } from '@opencollection/types/common/actions'; import type { Variable as BrunoVariable, Variables as BrunoVariables } from '@usebruno/schema-types/common/variables'; -import { uuid } from '../../../utils'; +import { uuid, ensureString } from '../../../utils'; /** * Convert Bruno post-response variables to OpenCollection actions. @@ -58,8 +58,8 @@ export const toBrunoPostResponseVariables = (actions: Action[] | null | undefine const variable: BrunoVariable = { uid: uuid(), - name: setVarAction.variable?.name || '', - value: setVarAction.selector?.expression || '', + name: ensureString(setVarAction.variable?.name), + value: ensureString(setVarAction.selector?.expression), enabled: setVarAction.disabled !== true, local: false }; diff --git a/packages/bruno-filestore/src/formats/yml/common/assertions.ts b/packages/bruno-filestore/src/formats/yml/common/assertions.ts index 03c243903..d7b4e4277 100644 --- a/packages/bruno-filestore/src/formats/yml/common/assertions.ts +++ b/packages/bruno-filestore/src/formats/yml/common/assertions.ts @@ -1,6 +1,6 @@ import type { KeyValue as BrunoKeyValue } from '@usebruno/schema-types/common/key-value'; import type { Assertion } from '@opencollection/types/common/assertions'; -import { uuid } from '../../../utils'; +import { uuid, ensureString } from '../../../utils'; const OPERATORS = [ 'eq', @@ -119,14 +119,14 @@ export const toBrunoAssertions = (assertions: Assertion[] | null | undefined): B const brunoAssertions: BrunoKeyValue[] = assertions.map((assertion: Assertion): BrunoKeyValue => { // Reconstruct the "operator value" format that Bruno uses - let valueString = assertion.operator; + let valueString = ensureString(assertion.operator); if (assertion.value !== undefined && assertion.value !== null) { - valueString = `${assertion.operator} ${assertion.value}`; + valueString = `${assertion.operator} ${ensureString(assertion.value)}`; } const brunoAssertion: BrunoKeyValue = { uid: uuid(), - name: assertion.expression || '', + name: ensureString(assertion.expression), value: valueString, enabled: assertion.disabled !== true }; diff --git a/packages/bruno-filestore/src/formats/yml/common/body.ts b/packages/bruno-filestore/src/formats/yml/common/body.ts index 37fac3dc1..da498b6be 100644 --- a/packages/bruno-filestore/src/formats/yml/common/body.ts +++ b/packages/bruno-filestore/src/formats/yml/common/body.ts @@ -10,7 +10,7 @@ import type { FileBodyEntry } from '@opencollection/types/requests/http'; import type { KeyValue as BrunoKeyValue } from '@usebruno/schema-types/common/key-value'; -import { uuid } from '../../../utils'; +import { uuid, ensureString } from '../../../utils'; export const toOpenCollectionBody = (body: BrunoHttpRequestBody | null | undefined): HttpRequestBody | undefined => { if (!body) { @@ -179,8 +179,8 @@ export const toBrunoBody = (body: HttpRequestBody | null | undefined): BrunoHttp brunoBody.formUrlEncoded = body.data?.map((entry): BrunoKeyValue => { const formEntry: BrunoKeyValue = { uid: uuid(), - name: entry.name || '', - value: entry.value || '', + name: ensureString(entry.name), + value: ensureString(entry.value), enabled: entry.disabled !== true }; @@ -202,8 +202,8 @@ export const toBrunoBody = (body: HttpRequestBody | null | undefined): BrunoHttp const multipartEntry: any = { uid: uuid(), type: entry.type, - name: entry.name || '', - value: entry.value || (entry.type === 'file' ? [] : ''), + name: ensureString(entry.name), + value: entry.type === 'file' ? (entry.value || []) : ensureString(entry.value), contentType: entry.contentType || null, enabled: entry.disabled !== true }; diff --git a/packages/bruno-filestore/src/formats/yml/common/headers.ts b/packages/bruno-filestore/src/formats/yml/common/headers.ts index 55147d53c..0f5e3b354 100644 --- a/packages/bruno-filestore/src/formats/yml/common/headers.ts +++ b/packages/bruno-filestore/src/formats/yml/common/headers.ts @@ -1,7 +1,7 @@ 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 { HttpRequestHeader, HttpResponseHeader } from '@opencollection/types/requests/http'; -import { uuid } from '../../../utils'; +import { uuid, ensureString } from '../../../utils'; export const toOpenCollectionHttpHeaders = (headers: BrunoFolderRequest['headers']): HttpRequestHeader[] | undefined => { if (!headers?.length) { @@ -46,8 +46,8 @@ export const toBrunoHttpHeaders = (headers: HttpRequestHeader[] | HttpResponseHe const brunoHeaders = headers.map((header): BrunoKeyValue => { const brunoHeader: BrunoKeyValue = { uid: uuid(), - name: header.name || '', - value: header.value || '', + name: ensureString(header.name), + value: ensureString(header.value), enabled: ('disabled' in header) ? header.disabled !== true : true }; diff --git a/packages/bruno-filestore/src/formats/yml/common/params.ts b/packages/bruno-filestore/src/formats/yml/common/params.ts index eefd755b0..3fc6bc646 100644 --- a/packages/bruno-filestore/src/formats/yml/common/params.ts +++ b/packages/bruno-filestore/src/formats/yml/common/params.ts @@ -1,6 +1,6 @@ import type { HttpRequestParam as BrunoHttpRequestParam } from '@usebruno/schema-types/requests/http'; import type { HttpRequestParam } from '@opencollection/types/requests/http'; -import { uuid } from '../../../utils'; +import { uuid, ensureString } from '../../../utils'; export const toOpenCollectionParams = (params: BrunoHttpRequestParam[] | null | undefined): HttpRequestParam[] | undefined => { if (!params?.length) { @@ -36,8 +36,8 @@ export const toBrunoParams = (params: HttpRequestParam[] | null | undefined): Br const brunoParams = params.map((param: HttpRequestParam): BrunoHttpRequestParam => { const brunoParam: BrunoHttpRequestParam = { uid: uuid(), - name: param.name || '', - value: param.value || '', + name: ensureString(param.name), + value: ensureString(param.value), type: param.type, enabled: param.disabled !== true }; diff --git a/packages/bruno-filestore/src/formats/yml/common/variables.ts b/packages/bruno-filestore/src/formats/yml/common/variables.ts index 6972d4b12..6295a3ac3 100644 --- a/packages/bruno-filestore/src/formats/yml/common/variables.ts +++ b/packages/bruno-filestore/src/formats/yml/common/variables.ts @@ -1,7 +1,7 @@ import { Variable } from '@opencollection/types/common/variables'; import { FolderRequest as BrunoFolderRequest } from '@usebruno/schema-types/collection/folder'; import { Variable as BrunoVariable, Variables as BrunoVariables } from '@usebruno/schema-types/common/variables'; -import { uuid } from '../../../utils'; +import { uuid, ensureString } from '../../../utils'; /** * Convert Bruno pre-request variables to OpenCollection variables format. @@ -51,8 +51,8 @@ export const toBrunoVariables = (variables: Variable[] | null | undefined): { re variables.forEach((v: Variable) => { const variable: BrunoVariable = { uid: uuid(), - name: v.name || '', - value: v.value as string || '', + name: ensureString(v.name), + value: ensureString(v.value), enabled: v.disabled !== true, local: false }; diff --git a/packages/bruno-filestore/src/formats/yml/items/parseGraphQLRequest.ts b/packages/bruno-filestore/src/formats/yml/items/parseGraphQLRequest.ts index 594a10acb..dc698bc20 100644 --- a/packages/bruno-filestore/src/formats/yml/items/parseGraphQLRequest.ts +++ b/packages/bruno-filestore/src/formats/yml/items/parseGraphQLRequest.ts @@ -8,7 +8,7 @@ import { toBrunoVariables } from '../common/variables'; import { toBrunoPostResponseVariables } from '../common/actions'; import { toBrunoScripts } from '../common/scripts'; import { toBrunoAssertions } from '../common/assertions'; -import { uuid } from '../../../utils'; +import { uuid, ensureString } from '../../../utils'; const parseGraphQLRequest = (ocRequest: GraphQLRequest): BrunoItem => { const info = ocRequest.info; @@ -16,8 +16,8 @@ const parseGraphQLRequest = (ocRequest: GraphQLRequest): BrunoItem => { const runtime = ocRequest.runtime; const brunoRequest: BrunoHttpRequest = { - url: graphql?.url || '', - method: graphql?.method || 'POST', + url: ensureString(graphql?.url), + method: ensureString(graphql?.method, 'POST'), headers: toBrunoHttpHeaders(graphql?.headers) || [], params: toBrunoParams(graphql?.params) || [], auth: toBrunoAuth(graphql?.auth), @@ -86,7 +86,7 @@ const parseGraphQLRequest = (ocRequest: GraphQLRequest): BrunoItem => { uid: uuid(), type: 'graphql-request', seq: info?.seq || 1, - name: info?.name || 'Untitled Request', + name: ensureString(info?.name, 'Untitled Request'), tags: info?.tags || [], request: brunoRequest, settings: null, diff --git a/packages/bruno-filestore/src/formats/yml/items/parseGrpcRequest.ts b/packages/bruno-filestore/src/formats/yml/items/parseGrpcRequest.ts index d684617e2..f38a6ffe4 100644 --- a/packages/bruno-filestore/src/formats/yml/items/parseGrpcRequest.ts +++ b/packages/bruno-filestore/src/formats/yml/items/parseGrpcRequest.ts @@ -6,7 +6,7 @@ import { toBrunoAuth } from '../common/auth'; import { toBrunoVariables } from '../common/variables'; import { toBrunoScripts } from '../common/scripts'; import { toBrunoAssertions } from '../common/assertions'; -import { isNonEmptyString, uuid } from '../../../utils'; +import { isNonEmptyString, uuid, ensureString } from '../../../utils'; const toBrunoGrpcMetadata = (metadata: GrpcMetadata[] | null | undefined): BrunoKeyValue[] | undefined => { if (!metadata?.length) { @@ -16,8 +16,8 @@ const toBrunoGrpcMetadata = (metadata: GrpcMetadata[] | null | undefined): Bruno const brunoMetadata = metadata.map((meta: GrpcMetadata): BrunoKeyValue => { const brunoMeta: BrunoKeyValue = { uid: uuid(), - name: meta.name || '', - value: meta.value || '', + name: ensureString(meta.name), + value: ensureString(meta.value), enabled: meta.disabled !== true }; @@ -33,8 +33,8 @@ const parseGrpcRequest = (ocRequest: GrpcRequest): BrunoItem => { const runtime = ocRequest.runtime; const brunoRequest: BrunoGrpcRequest = { - url: grpc?.url || '', - method: grpc?.method || '', + url: ensureString(grpc?.url), + method: ensureString(grpc?.method), methodType: grpc?.methodType || '', protoPath: grpc?.protoFilePath || null, headers: toBrunoGrpcMetadata(grpc?.metadata) || [], @@ -98,7 +98,7 @@ const parseGrpcRequest = (ocRequest: GrpcRequest): BrunoItem => { uid: uuid(), type: 'grpc-request', seq: info?.seq || 1, - name: info?.name || 'Untitled Request', + name: ensureString(info?.name, 'Untitled Request'), tags: info?.tags || [], request: brunoRequest, settings: {}, diff --git a/packages/bruno-filestore/src/formats/yml/items/parseHttpRequest.ts b/packages/bruno-filestore/src/formats/yml/items/parseHttpRequest.ts index 57891d783..dc7a4ddbd 100644 --- a/packages/bruno-filestore/src/formats/yml/items/parseHttpRequest.ts +++ b/packages/bruno-filestore/src/formats/yml/items/parseHttpRequest.ts @@ -9,7 +9,7 @@ import { toBrunoVariables } from '../common/variables'; import { toBrunoPostResponseVariables } from '../common/actions'; import { toBrunoScripts } from '../common/scripts'; import { toBrunoAssertions } from '../common/assertions'; -import { uuid } from '../../../utils'; +import { uuid, ensureString } from '../../../utils'; const parseHttpRequest = (ocRequest: HttpRequest): BrunoItem => { const info = ocRequest.info; @@ -17,8 +17,8 @@ const parseHttpRequest = (ocRequest: HttpRequest): BrunoItem => { const runtime = ocRequest.runtime; const brunoRequest: BrunoHttpRequest = { - url: http?.url || '', - method: http?.method || 'GET', + url: ensureString(http?.url), + method: ensureString(http?.method, 'GET'), headers: toBrunoHttpHeaders(http?.headers) || [], params: toBrunoParams(http?.params) || [], auth: toBrunoAuth(http?.auth), @@ -84,7 +84,7 @@ const parseHttpRequest = (ocRequest: HttpRequest): BrunoItem => { uid: uuid(), type: 'http-request', seq: info?.seq || 1, - name: info?.name || 'Untitled Request', + name: ensureString(info?.name, 'Untitled Request'), tags: info?.tags || [], request: brunoRequest, settings: null, @@ -135,7 +135,7 @@ const parseHttpRequest = (ocRequest: HttpRequest): BrunoItem => { const brunoExample: any = { uid: uuid(), itemUid: uuid(), - name: example.name || 'Untitled Example', + name: ensureString(example.name, 'Untitled Example'), type: 'http-request', request: null, response: null @@ -151,8 +151,8 @@ const parseHttpRequest = (ocRequest: HttpRequest): BrunoItem => { if (example.request) { brunoExample.request = { - url: example.request.url || '', - method: example.request.method || 'GET', + url: ensureString(example.request.url), + method: ensureString(example.request.method, 'GET'), headers: toBrunoHttpHeaders(example.request.headers) || [], params: toBrunoParams(example.request.params) || [], body: toBrunoBody(example.request.body) || { diff --git a/packages/bruno-filestore/src/formats/yml/items/parseWebsocketRequest.ts b/packages/bruno-filestore/src/formats/yml/items/parseWebsocketRequest.ts index 1aa8e7c8e..14799ef56 100644 --- a/packages/bruno-filestore/src/formats/yml/items/parseWebsocketRequest.ts +++ b/packages/bruno-filestore/src/formats/yml/items/parseWebsocketRequest.ts @@ -5,7 +5,7 @@ import { toBrunoAuth } from '../common/auth'; import { toBrunoHttpHeaders } from '../common/headers'; import { toBrunoVariables } from '../common/variables'; import { toBrunoScripts } from '../common/scripts'; -import { uuid } from '../../../utils'; +import { uuid, ensureString } from '../../../utils'; const parseWebsocketRequest = (ocRequest: WebSocketRequest): BrunoItem => { const info = ocRequest.info; @@ -13,7 +13,7 @@ const parseWebsocketRequest = (ocRequest: WebSocketRequest): BrunoItem => { const runtime = ocRequest.runtime; const brunoRequest: BrunoWebSocketRequest = { - url: websocket?.url || '', + url: ensureString(websocket?.url), headers: toBrunoHttpHeaders(websocket?.headers) || [], auth: toBrunoAuth(websocket?.auth), body: { @@ -36,11 +36,12 @@ const parseWebsocketRequest = (ocRequest: WebSocketRequest): BrunoItem => { // message if (websocket?.message) { const message = websocket.message as WebSocketMessage; - if (message.data?.trim().length) { + const messageData = ensureString(message.data); + if (messageData.trim().length) { brunoRequest.body.ws = [{ name: '', type: message.type || 'text', - content: message.data + content: messageData }]; } } @@ -88,7 +89,7 @@ const parseWebsocketRequest = (ocRequest: WebSocketRequest): BrunoItem => { uid: uuid(), type: 'ws-request', seq: info?.seq || 1, - name: info?.name || 'Untitled Request', + name: ensureString(info?.name, 'Untitled Request'), tags: info?.tags || [], request: brunoRequest, settings: wsSettings as any, diff --git a/packages/bruno-filestore/src/formats/yml/parseCollection.ts b/packages/bruno-filestore/src/formats/yml/parseCollection.ts index c192d1750..8fe96a7c4 100644 --- a/packages/bruno-filestore/src/formats/yml/parseCollection.ts +++ b/packages/bruno-filestore/src/formats/yml/parseCollection.ts @@ -5,6 +5,7 @@ import { toBrunoAuth } from './common/auth'; import { toBrunoHttpHeaders } from './common/headers'; import { toBrunoVariables } from './common/variables'; import { toBrunoScripts } from './common/scripts'; +import { ensureString } from '../../utils'; interface ParsedCollection { collectionRoot: FolderRoot; @@ -18,7 +19,7 @@ const parseCollection = (ymlString: string): ParsedCollection => { // bruno config const brunoConfig: Record = { opencollection: oc.opencollection || '1.0.0', - name: oc.info?.name || 'Untitled Collection', + name: ensureString(oc.info?.name, 'Untitled Collection'), type: 'collection', ignore: [] }; diff --git a/packages/bruno-filestore/src/formats/yml/parseEnvironment.ts b/packages/bruno-filestore/src/formats/yml/parseEnvironment.ts index 564a2e6c4..5eaba6baf 100644 --- a/packages/bruno-filestore/src/formats/yml/parseEnvironment.ts +++ b/packages/bruno-filestore/src/formats/yml/parseEnvironment.ts @@ -2,7 +2,7 @@ import type { Environment as BrunoEnvironment, EnvironmentVariable as BrunoEnvir import type { Environment } from '@opencollection/types/config/environments'; import type { Variable, SecretVariable } from '@opencollection/types/common/variables'; import { parseYml } from './utils'; -import { uuid } from '../../utils'; +import { uuid, ensureString } from '../../utils'; const isSecretVariable = (v: Variable | SecretVariable): v is SecretVariable => { return 'secret' in v && v.secret === true; @@ -17,7 +17,7 @@ const toBrunoEnvironmentVariables = (variables: (Variable | SecretVariable)[] | if (isSecretVariable(v)) { return { uid: uuid(), - name: v.name || '', + name: ensureString(v.name), value: '', type: 'text', enabled: v.disabled !== true, @@ -26,8 +26,8 @@ const toBrunoEnvironmentVariables = (variables: (Variable | SecretVariable)[] | } const variable: BrunoEnvironmentVariable = { uid: uuid(), - name: v.name || '', - value: (typeof v.value === 'string' ? v.value : '') || '', + name: ensureString(v.name), + value: ensureString(v.value), type: 'text', enabled: v.disabled !== true, secret: false @@ -42,7 +42,7 @@ const parseEnvironment = (ymlString: string): BrunoEnvironment => { const brunoEnvironment: BrunoEnvironment = { uid: uuid(), - name: ocEnvironment.name || 'Untitled Environment', + name: ensureString(ocEnvironment.name, 'Untitled Environment'), variables: toBrunoEnvironmentVariables(ocEnvironment.variables) }; diff --git a/packages/bruno-filestore/src/formats/yml/parseFolder.ts b/packages/bruno-filestore/src/formats/yml/parseFolder.ts index 98227f851..4c8323706 100644 --- a/packages/bruno-filestore/src/formats/yml/parseFolder.ts +++ b/packages/bruno-filestore/src/formats/yml/parseFolder.ts @@ -5,7 +5,7 @@ import { toBrunoAuth } from './common/auth'; import { toBrunoHttpHeaders } from './common/headers'; import { toBrunoVariables } from './common/variables'; import { toBrunoScripts } from './common/scripts'; -import { isNonEmptyString } from '../../utils'; +import { ensureString } from '../../utils'; const parseFolder = (ymlString: string): FolderRoot => { try { @@ -15,7 +15,7 @@ const parseFolder = (ymlString: string): FolderRoot => { const folderRoot: FolderRoot = { meta: { - name: info?.name || 'Untitled Folder', + name: ensureString(info?.name, 'Untitled Folder'), seq: info?.seq || 1 }, request: null, diff --git a/packages/bruno-filestore/src/utils/index.ts b/packages/bruno-filestore/src/utils/index.ts index 590bd3140..ac41bc8db 100644 --- a/packages/bruno-filestore/src/utils/index.ts +++ b/packages/bruno-filestore/src/utils/index.ts @@ -6,6 +6,16 @@ export const isNumber = (value: unknown): value is number => typeof value === 'n export const isNonEmptyString = (value: unknown): value is string => isString(value) && value.trim().length > 0; +export const ensureString = (value: unknown, fallback: string = ''): string => { + if (value === null || value === undefined) { + return fallback; + } + if (typeof value === 'string') { + return value; + } + return String(value); +}; + export const uuid = () => { // https://github.com/ai/nanoid/blob/main/url-alphabet/index.js const urlAlphabet = 'useandom26T198340PX75pxJACKVERYMINDBUSHWOLFGQZbfghjklqvwyzrict';