Tutorial 4 - Asking Questions
Collect user input to customize generated projects
Tutorial 4: Asking Questions
Collect user input to customize the generated project. Questions make templates interactive and reusable.
The IInquirer Interface
The i parameter provides methods to ask different question types:
StartTemplateWithLambda(async (i, d) => {// i is the IInquirer interfaceconst name = await i.text('Project name?', 'project.name', 'Enter name');// ...});
def template(i: Inquirer, d: DirectoryTree) -> dict:# i is the Inquirer interfacename = i.text('Project name?', 'project.name', 'Enter name')# ...
StartTemplate.WithLambda(async (i, d) => {// i is the IInquirer interfacevar name = await i.Text("Project name?", "project.name", "Enter name");// ...});
Adding Questions
Combine multiple question types for a rich setup experience:
import { StartTemplateWithLambda, GlobType } from '@atomicloud/cyan-sdk';StartTemplateWithLambda(async (i, d) => {// Text inputconst name = await i.text('Project name?', 'my-template.name', 'Enter project name');// Boolean confirmationconst docker = await i.confirm('Add Docker?', 'my-template.docker', 'Include Dockerfile');// Multi-selectconst features = await i.checkbox('Features?',['TypeScript', 'ESLint', 'Prettier', 'Testing'],'my-template.features','Select features');return {processors: [{name: 'cyan/default',files: [{ root: 'templates', glob: '**/*', exclude: [], type: GlobType.Template }],config: {vars: {name,docker: docker ? 'yes' : 'no',features: features.join(', ')}}}]};});
from cyan import Inquirer, DirectoryTreefrom cyan import GlobTypedef template(i: Inquirer, d: DirectoryTree) -> dict:# Text inputname = i.text('Project name?', 'my-template.name', 'Enter project name')# Boolean confirmationdocker = i.confirm('Add Docker?', 'my-template.docker', 'Include Dockerfile')# Multi-selectfeatures = i.checkbox('Features?',['TypeScript', 'ESLint', 'Prettier', 'Testing'],'my-template.features','Select features')return {'processors': [{'name': 'cyan/default','files': [{'root': 'templates', 'glob': '**/*', 'exclude': [], 'type': GlobType.Template}],'config': {'vars': {'name': name,'docker': 'yes' if docker else 'no','features': ', '.join(features)}}}]}
using Atomiq.Cloud.Cyan;StartTemplate.WithLambda(async (i, d) => {// Text inputvar name = await i.Text("Project name?", "my-template.name", "Enter project name");// Boolean confirmationvar docker = await i.Confirm("Add Docker?", "my-template.docker", "Include Dockerfile");// Multi-selectvar features = await i.Checkbox("Features?",new[] { "TypeScript", "ESLint", "Prettier", "Testing" },"my-template.features","Select features");return new {processors = new[] {new {name = "cyan/default",files = new[] {new { root = "templates", glob = "**/*", exclude = Array.Empty<string>(), type = GlobType.Template }},config = new {vars = new {name,docker = docker ? "yes" : "no",features = string.Join(", ", features)}}}}};});
Question Types
| Method | Returns | Example Use |
|---|---|---|
text() | string | Project name, author |
select() | string | License, framework choice |
confirm() | boolean | Yes/no decisions |
checkbox() | string[] | Feature selection |
password() | string | Secrets, API keys |
dateSelect() | string | Dates, deadlines |
| Method | Returns | Example Use |
|---|---|---|
text() | str | Project name, author |
select() | str | License, framework choice |
confirm() | bool | Yes/no decisions |
checkbox() | list[str] | Feature selection |
password() | str | Secrets, API keys |
date_select() | str | Dates, deadlines |
| Method | Returns | Example Use |
|---|---|---|
Text() | string | Project name, author |
Select() | string | License, framework choice |
Confirm() | bool | Yes/no decisions |
Checkbox() | string[] | Feature selection |
Password() | string | Secrets, API keys |
DateSelect() | string | Dates, deadlines |
For detailed usage of each question type, see the How-to guides:
Ask Text Questions
Ask Select Questions
Ask Confirm Questions
Ask Checkbox Questions
Ask Password Questions
Ask Date Questions
Question IDs (Keys)
The second argument is the question ID (also called a key). Keys enable answer reuse:
// Both questions get the same answer!const name1 = await i.text('Project name?', 'name', '...');const name2 = await i.text('Confirm name?', 'name', '...');// name1 === name2 (same key = same answer)
# Both questions get the same answer!name1 = i.text('Project name?', 'name', '...')name2 = i.text('Confirm name?', 'name', '...')# name1 == name2 (same key = same answer)
// Both questions get the same answer!var name1 = await i.Text("Project name?", "name", "...");var name2 = await i.Text("Confirm name?", "name", "...");// name1 == name2 (same key = same answer)
Namespacing Your Keys
Always namespace your keys to prevent collisions when templates are composed.
// Good: namespaced keysconst name = await i.text('Project name?', 'my-template.project.name', '...');// Bad: generic keys that might collideconst name = await i.text('Project name?', 'name', '...');
# Good: namespaced keysname = i.text('Project name?', 'my-template.project.name', '...')# Bad: generic keys that might collidename = i.text('Project name?', 'name', '...')
// Good: namespaced keysvar name = await i.Text("Project name?", "my-template.project.name", "...");// Bad: generic keys that might collidevar name = await i.Text("Project name?", "name", "...");
For a detailed explanation of how question namespacing works and why it matters, see the Question Namespacing concept guide.
Using Answers in Templates
Pass collected answers to processor config:
config: {vars: {name, // Project namedocker: docker ? 'yes' : 'no', // Conditional valuefeatures: features.join(', ') // Array to string}}
'config': {'vars': {'name': name,'docker': 'yes' if docker else 'no','features': ', '.join(features)}}
config = new {vars = new {name,docker = docker ? "yes" : "no",features = string.Join(", ", features)}}
Use in template files:
# var__name__## Docker SupportThis project includes Docker: **var__docker__**## FeaturesThis project includes: var__features__
What You Learned
- How to use basic question types: text, confirm, checkbox
- What question IDs are and how they enable answer reuse
- Why namespacing keys is important
- How to use answers in template files
Next Steps
Now you understand the basics of template development. Explore specific patterns in the How-to Guides: