import { useNodeTree } from '../composables/useNodeTree.ts' import { provide } from '../context.ts' import { NodeTreeContext } from '../contexts/NodeTreeContext.ts' import { type ComponentBuilder, createComponent } from '../createComponent.ts' import type { FabricNode } from '../Fabric.ts' import type { JSDoc } from '../types.ts' import { createJSDoc } from '../utils/createJSDoc.ts' import { Br } from './Br.ts' import { Dedent } from './Dedent.ts' import { Indent } from './Indent.ts' type FunctionProps = { /** * Name of the function. */ name: string /** * Export with default keyword. * - `true` generates `export default function` * - `false` generates named export or no export * @default false */ default?: boolean /** * Function parameters. * * @example 'id: number, name: string' */ params?: string /** * Export this function. * - `true` generates `export function` * - `false` generates internal function * @default false */ export?: boolean /** * Make the function async. * - `true` adds async keyword and wraps return type in Promise * - `false` generates synchronous function * @default false */ async?: boolean /** * TypeScript generics. * * @example 'T' or ['T', 'U'] */ generics?: string | string[] /** * Return type of the function. * * When async is true, this is automatically wrapped in Promise. */ returnType?: string /** * JSDoc comments for the function. */ JSDoc?: JSDoc /** * Function body. */ children?: FabricNode } /** * Generates a TypeScript function declaration. * * @example * ```tsx * * return fetch(`/users/${id}`).then(r => r.json()) * * ``` */ export const Function = createComponent('Function', ({ children, ...props }: FunctionProps) => { const { name, default: isDefault, export: canExport, async, generics, params, returnType, JSDoc } = props const nodeTree = useNodeTree() if (nodeTree) { const childTree = nodeTree.addChild({ type: 'Function', props }) provide(NodeTreeContext, childTree) } const parts: string[] = [] if (JSDoc?.comments) { parts.push(createJSDoc({ comments: JSDoc.comments })) parts.push('\n') } if (canExport) { parts.push('export ') } if (isDefault) { parts.push('default ') } if (async) { parts.push('async ') } parts.push(`function ${name}`) if (generics) { parts.push('<') parts.push(Array.isArray(generics) ? generics.join(', ').trim() : generics) parts.push('>') } parts.push(`(${params || ''})`) if (returnType && !async) { parts.push(`: ${returnType}`) } if (returnType && async) { parts.push(`: Promise<${returnType}>`) } parts.push(' {') if (children) { return [parts.join(''), Br(), Indent(), children, Br(), Dedent(), '}'] } return [parts.join(''), '}'] }) as ComponentBuilder & { Arrow: typeof ArrowFunction } Function.displayName = 'Function' type ArrowFunctionProps = FunctionProps & { /** * Create Arrow function in one line */ singleLine?: boolean } /** * ArrowFunction * * Builds an arrow function declaration string for the fsx renderer. Supports * the same options as `Function`. Use `singleLine` to produce a one-line * arrow expression. */ const ArrowFunction = createComponent('ArrowFunction', ({ children, ...props }: ArrowFunctionProps) => { const { name, default: isDefault, export: canExport, async, generics, params, returnType, JSDoc, singleLine } = props const nodeTree = useNodeTree() if (nodeTree) { const childTree = nodeTree.addChild({ type: 'ArrowFunction', props }) provide(NodeTreeContext, childTree) } const parts: string[] = [] if (JSDoc?.comments) { parts.push(createJSDoc({ comments: JSDoc.comments })) parts.push('\n') } if (canExport) { parts.push('export ') } if (isDefault) { parts.push('default ') } parts.push(`const ${name} = `) if (async) { parts.push('async ') } if (generics) { parts.push('<') parts.push(Array.isArray(generics) ? generics.join(', ').trim() : generics) parts.push('>') } parts.push(`(${params || ''})`) if (returnType && !async) { parts.push(`: ${returnType}`) } if (returnType && async) { parts.push(`: Promise<${returnType}>`) } if (singleLine) { parts.push(` => ${children || ''}\n`) return parts.join('') } if (children) { return [parts.join(''), ' => {', Br(), Indent(), children, Br(), Dedent(), '}'] } return [parts.join(''), ' => {}'] }) ArrowFunction.displayName = 'ArrowFunction' Function.Arrow = ArrowFunction