/** * Small helper for permissive imports (goView / low-code exports). * * Many widgets store their URL-ish source in slightly different shapes: * - string * - { value: string } * - { url: string } * - { src: string } * - { dataset: string | { value/url/src } } * - nested objects under `data` / `config` / `options` */ export function pickUrlLike(input: unknown, maxDepth = 3): string { return pickUrlLikeInner(input, maxDepth); } function pickUrlLikeInner(input: unknown, depth: number): string { if (typeof input === 'string') return input; if (!input) return ''; if (Array.isArray(input)) { for (const item of input) { const v = pickUrlLikeInner(item, depth - 1); if (v) return v; } return ''; } if (typeof input !== 'object') return ''; const obj = input as Record; // Common direct keys. // Keep this list generous; imports come from many low-code editors. for (const key of [ 'value', 'url', 'src', 'href', 'link', 'path', 'source', 'address', // iframe-ish 'iframeUrl', 'iframeSrc', 'embedUrl', // video-ish 'videoUrl', 'videoSrc', 'mp4', 'm3u8', 'flv', // other streaming-ish keys 'hls', 'hlsUrl', 'stream', 'streamUrl', 'rtsp', 'rtspUrl', ]) { const v = obj[key]; if (typeof v === 'string' && v) return v; } if (depth <= 0) return ''; // Common nesting keys. for (const key of ['dataset', 'data', 'config', 'option', 'options', 'props', 'source', 'media']) { const v = obj[key]; const nested = pickUrlLikeInner(v, depth - 1); if (nested) return nested; } return ''; }