(
spec: PromptSpec,
flags: { toolCalls: boolean; bindings: boolean; usesActionExpression: boolean },
)
| 521 | // ─── Component signatures ─────────────────────────────────────────────────── |
| 522 | |
| 523 | function generateComponentSignatures( |
| 524 | spec: PromptSpec, |
| 525 | flags: { toolCalls: boolean; bindings: boolean; usesActionExpression: boolean }, |
| 526 | ): string { |
| 527 | const lines = [ |
| 528 | "## Component Signatures", |
| 529 | "", |
| 530 | "Arguments marked with ? are optional. Sub-components can be inline or referenced; prefer references for better streaming.", |
| 531 | ]; |
| 532 | if (flags.usesActionExpression) { |
| 533 | const allSteps = [ |
| 534 | flags.toolCalls ? "@Run" : "", |
| 535 | "@ToAssistant", |
| 536 | "@OpenUrl", |
| 537 | flags.bindings ? "@Set" : "", |
| 538 | flags.bindings ? "@Reset" : "", |
| 539 | ].filter(Boolean); |
| 540 | lines.push( |
| 541 | `Props typed \`ActionExpression\` accept an Action([@steps...]) expression. See the Action section for available steps (${allSteps.join(", ")}).`, |
| 542 | ); |
| 543 | } |
| 544 | const usesBindings = |
| 545 | flags.bindings || Object.values(spec.components).some((c) => c.signature?.includes("$binding")); |
| 546 | if (usesBindings) { |
| 547 | lines.push("Props marked `$binding<type>` accept a `$variable` reference for two-way binding."); |
| 548 | } |
| 549 | |
| 550 | const formatSig = (comp: { signature: string; description?: string }) => |
| 551 | comp.description ? `${comp.signature} — ${comp.description}` : comp.signature; |
| 552 | |
| 553 | if (spec.componentGroups?.length) { |
| 554 | const grouped = new Set<string>(); |
| 555 | for (const group of spec.componentGroups) { |
| 556 | lines.push("", `### ${group.name}`); |
| 557 | for (const name of group.components) { |
| 558 | if (grouped.has(name)) continue; |
| 559 | const comp = spec.components[name]; |
| 560 | if (!comp) continue; |
| 561 | grouped.add(name); |
| 562 | lines.push(formatSig(comp)); |
| 563 | } |
| 564 | if (group.notes?.length) { |
| 565 | for (const note of group.notes) lines.push(note); |
| 566 | } |
| 567 | } |
| 568 | const ungrouped = Object.keys(spec.components).filter((n) => !grouped.has(n)); |
| 569 | if (ungrouped.length) { |
| 570 | lines.push("", "### Other"); |
| 571 | for (const name of ungrouped) { |
| 572 | const comp = spec.components[name]; |
| 573 | lines.push(formatSig(comp)); |
| 574 | } |
| 575 | } |
| 576 | } else { |
| 577 | lines.push(""); |
| 578 | for (const [, comp] of Object.entries(spec.components)) { |
| 579 | lines.push(formatSig(comp)); |
| 580 | } |
no test coverage detected