interface CloneableComponentBinding { adapters: readonly string[] props: readonly string[] } interface NamedComponentBinding { template_id: string component: string } interface ComponentImportStatement { statement: string } export function cloneBindingMap( bindings: Record ): Record { const result = {} as Record for (const name of Object.keys(bindings) as TName[]) { result[name] = cloneBindings(bindings[name]) } return result } export function cloneBindings( bindings: readonly TBinding[] ): TBinding[] { return bindings.map(cloneBinding) } export function cloneBinding(binding: TBinding): TBinding { return { ...binding, adapters: [...binding.adapters], props: [...binding.props], } } export function uniquePropsName( binding: NamedComponentBinding, usedNames: Map ): string { const base = toCamelIdentifier(`${binding.template_id} ${binding.component} props`) const count = usedNames.get(base) ?? 0 usedNames.set(base, count + 1) return count === 0 ? base : `${base}${count + 1}` } function toCamelIdentifier(value: string): string { const words = value .replace(/([a-z0-9])([A-Z])/g, '$1 $2') .split(/[^A-Za-z0-9]+/) .filter(Boolean) if (words.length === 0) return 'componentProps' return words .map((word, index) => { const lower = word.toLowerCase() return index === 0 ? lower : lower.charAt(0).toUpperCase() + lower.slice(1) }) .join('') } export function toVueSfc( imports: readonly ComponentImportStatement[], setupLines: readonly string[], template: string, includeTargetTypeImport: boolean ): string { const importLines = [ ...imports.map(item => item.statement), "import { toBioTemplateComponentProps } from '@morscherlab/mint-sdk/templates'", ...(includeTargetTypeImport ? ["import type { BioTemplateEnvelope, TemplateCollectionEnvelope } from '@morscherlab/mint-sdk/templates'"] : []), ] const templateLines = template ? template.split('\n').map(line => ` ${line}`).join('\n') : '' return [ '', '', '', ].join('\n') }