import yaml from 'js-yaml' import type { OpenCollectionRoot, CollectionInfo, CollectionConfig, ProxyConfig, CollectionRequestDefaults, HeaderItem, AuthConfig, VarItem } from '../types.js' function parseHeaders(raw: unknown): HeaderItem[] { if (!Array.isArray(raw)) return [] return raw.map((h: Record) => ({ name: String(h.name ?? ''), value: String(h.value ?? ''), disabled: Boolean(h.disabled), })) } function parseVars(raw: unknown): VarItem[] { if (!Array.isArray(raw)) return [] return raw.map((v: Record) => ({ name: String(v.name ?? ''), value: String(v.value ?? ''), enabled: v.enabled !== false, local: Boolean(v.local), })) } function parseAuth(raw: unknown): AuthConfig | undefined { if (!raw || typeof raw !== 'object') return undefined const r = raw as Record const type = String(r.type ?? 'none') const auth: AuthConfig = { type } if (type === 'basic' && r.basic && typeof r.basic === 'object') { const b = r.basic as Record auth.basic = { username: String(b.username ?? ''), password: String(b.password ?? '') } } if (type === 'bearer' && r.bearer && typeof r.bearer === 'object') { const b = r.bearer as Record auth.bearer = { token: String(b.token ?? '') } } if (type === 'apikey' && r.apikey && typeof r.apikey === 'object') { const b = r.apikey as Record auth.apikey = { key: String(b.key ?? ''), value: String(b.value ?? ''), placement: String(b.placement ?? 'header') } } if (type === 'oauth2') { auth.oauth2 = typeof r.oauth2 === 'object' && r.oauth2 !== null ? r.oauth2 as Record : {} } return auth } function parseRequestDefaults(raw: unknown): CollectionRequestDefaults | undefined { if (!raw || typeof raw !== 'object') return undefined const r = raw as Record const scriptRaw = r.script as Record | undefined const varsRaw = r.vars as Record | undefined return { auth: parseAuth(r.auth), headers: parseHeaders(r.headers), script: scriptRaw ? { req: typeof scriptRaw.req === 'string' ? scriptRaw.req : undefined, res: typeof scriptRaw.res === 'string' ? scriptRaw.res : undefined, } : undefined, tests: typeof r.tests === 'string' ? r.tests : undefined, vars: varsRaw ? { req: parseVars(varsRaw.req), res: parseVars(varsRaw.res) } : undefined, } } function parseProxy(raw: unknown): ProxyConfig | undefined { if (!raw || typeof raw !== 'object') return undefined const r = raw as Record const authRaw = r.auth as Record | undefined return { inherit: typeof r.inherit === 'boolean' ? r.inherit : undefined, protocol: typeof r.protocol === 'string' ? r.protocol : undefined, hostname: typeof r.hostname === 'string' ? r.hostname : undefined, port: typeof r.port === 'string' ? r.port : undefined, auth: authRaw ? { username: String(authRaw.username ?? ''), password: String(authRaw.password ?? '') } : undefined, bypassProxy: typeof r.bypassProxy === 'string' ? r.bypassProxy : undefined, } } export function parseCollection(yamlContent: string): OpenCollectionRoot { const raw = yaml.load(yamlContent) as Record if (!raw || typeof raw !== 'object') { throw new Error('Invalid opencollection.yml — expected an object') } const infoRaw = raw.info as Record | undefined if (!infoRaw?.name || typeof infoRaw.name !== 'string' || infoRaw.name.trim() === '') { throw new Error("opencollection.yml: Missing required field 'info.name'") } const info: CollectionInfo = { name: infoRaw.name, summary: typeof infoRaw.summary === 'string' ? infoRaw.summary : undefined, version: typeof infoRaw.version === 'string' ? infoRaw.version : undefined, authors: Array.isArray(infoRaw.authors) ? infoRaw.authors.map(String) : undefined, } const configRaw = raw.config as Record | undefined const config: CollectionConfig | undefined = configRaw ? { proxy: parseProxy(configRaw.proxy) } : undefined const extensionsRaw = raw.extensions as Record | undefined const brunoExt = extensionsRaw?.bruno as Record | undefined return { specVersion: typeof raw.opencollection === 'string' ? raw.opencollection : undefined, info, config, request: parseRequestDefaults(raw.request), bundled: typeof raw.bundled === 'boolean' ? raw.bundled : undefined, extensions: brunoExt ? { bruno: { ignore: Array.isArray(brunoExt.ignore) ? brunoExt.ignore.map(String) : undefined } } : undefined, } }