LogoCyanPrint

Validate User Input

How to validate user input with custom rules

How to Validate User Input

Validation ensures users provide correct and usable input before template generation.

Basic Validation

Use the validate function in the object form:

const name = await i.text({
type: QuestionType.Text,
id: 'project.name',
message: 'Project name?',
desc: 'Enter name',
validate: (input) => {
Return error string or null for valid
if (!input) return 'Name is required';
return null;
}
});
name = await i.text({
"type": QuestionType.Text,
"id": "project.name",
"message": "Project name?",
"desc": "Enter name",
"validate": lambda input: "Name is required" if not input else None
Return error string or None for valid
})
var name = await i.Text(new TextQuestion
{
Type = QuestionType.Text,
Id = "project.name",
Message = "Project name?",
Desc = "Enter name",
Validate = (input) => string.IsNullOrEmpty(input) ? "Name is required" : null
Return error string or null for valid
});

Validation Patterns

Required Field

const name = await i.text({
type: QuestionType.Text,
id: 'project.name',
message: 'Project name?',
desc: 'Enter name',
validate: (input) => {
if (!input || input.trim() === '') {
return 'This field is required';
}
return null;
}
});
name = await i.text({
"type": QuestionType.Text,
"id": "project.name",
"message": "Project name?",
"desc": "Enter name",
"validate": lambda input: "This field is required" if not input or not input.strip() else None
Check for empty or whitespace-only input
})
var name = await i.Text(new TextQuestion
{
Type = QuestionType.Text,
Id = "project.name",
Message = "Project name?",
Desc = "Enter name",
Validate = (input) => string.IsNullOrWhiteSpace(input) ? "This field is required" : null
Check for empty or whitespace-only input
});

Length Constraints

const username = await i.text({
type: QuestionType.Text,
id: 'user.name',
message: 'Username?',
desc: '3-20 characters',
validate: (input) => {
if (input.length < 3) return 'Minimum 3 characters';
Check minimum length first
if (input.length > 20) return 'Maximum 20 characters';
Then check maximum length
return null;
}
});
username = await i.text({
"type": QuestionType.Text,
"id": "user.name",
"message": "Username?",
"desc": "3-20 characters",
"validate": lambda input: (
"Minimum 3 characters" if len(input) < 3 else
"Maximum 20 characters" if len(input) > 20 else None
)
})
var username = await i.Text(new TextQuestion
{
Type = QuestionType.Text,
Id = "user.name",
Message = "Username?",
Desc = "3-20 characters",
Validate = (input) =>
{
if (input.Length < 3) return "Minimum 3 characters";
Check minimum length first
if (input.Length > 20) return "Maximum 20 characters";
Then check maximum length
return null;
}
});

Pattern Matching

const projectName = await i.text({
type: QuestionType.Text,
id: 'project.name',
message: 'Project name?',
desc: 'Lowercase, numbers, hyphens only',
validate: (input) => {
if (!/^[a-z][a-z0-9-]*$/.test(input)) {
return 'Use lowercase letters, numbers, and hyphens. Must start with a letter.';
}
return null;
},
default: 'my-project'
});
import re
project_name = await i.text({
"type": QuestionType.Text,
"id": "project.name",
"message": "Project name?",
"desc": "Lowercase, numbers, hyphens only",
"validate": lambda input: None if re.match(r'^[a-z][a-z0-9-]*$', input) else "Use lowercase letters, numbers, and hyphens. Must start with a letter.",
"default": "my-project"
})
var projectName = await i.Text(new TextQuestion
{
Type = QuestionType.Text,
Id = "project.name",
Message = "Project name?",
Desc = "Lowercase, numbers, hyphens only",
Validate = (input) => Regex.IsMatch(input, @"^[a-z][a-z0-9-]*$")
? null
: "Use lowercase letters, numbers, and hyphens. Must start with a letter.",
Default = "my-project"
});

Email Validation

const email = await i.text({
type: QuestionType.Text,
id: 'user.email',
message: 'Email?',
desc: 'Your email address',
validate: (input) => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(input)) {
return 'Please enter a valid email address';
}
return null;
}
});
import re
email = await i.text({
"type": QuestionType.Text,
"id": "user.email",
"message": "Email?",
"desc": "Your email address",
"validate": lambda input: None if re.match(r'^[^\s@]+@[^\s@]+\.[^\s@]+$', input) else "Please enter a valid email address"
})
var email = await i.Text(new TextQuestion
{
Type = QuestionType.Text,
Id = "user.email",
Message = "Email?",
Desc = "Your email address",
Validate = (input) => Regex.IsMatch(input, @"^[^\s@]+@[^\s@]+\.[^\s@]+$")
? null
: "Please enter a valid email address"
});

URL Validation

const website = await i.text({
type: QuestionType.Text,
id: 'project.website',
message: 'Website URL?',
desc: 'Optional website',
validate: (input) => {
if (!input) return null;
Allow empty input (optional field)
try {
new URL(input);
return null;
} catch {
return 'Please enter a valid URL (including https://)';
}
}
});
from urllib.parse import urlparse
website = await i.text({
"type": QuestionType.Text,
"id": "project.website",
"message": "Website URL?",
"desc": "Optional website",
"validate": lambda input: None if not input else (
Allow empty input (optional field)
None if urlparse(input).scheme and urlparse(input).netloc
else "Please enter a valid URL (including https://)"
)
})
var website = await i.Text(new TextQuestion
{
Type = QuestionType.Text,
Id = "project.website",
Message = "Website URL?",
Desc = "Optional website",
Validate = (input) =>
{
if (string.IsNullOrEmpty(input)) return null;
Allow empty input (optional field)
if (Uri.TryCreate(input, UriKind.Absolute, out _)) return null;
return "Please enter a valid URL (including https://)";
}
});

Number Range

const port = await i.text({
type: QuestionType.Text,
id: 'server.port',
message: 'Port number?',
desc: '1024-65535',
default: '3000',
validate: (input) => {
const num = parseInt(input, 10);
if (isNaN(num)) return 'Please enter a number';
Must be a valid number
if (num < 1024 || num > 65535) return 'Port must be between 1024 and 65535';
Check valid port range
return null;
}
});
port = await i.text({
"type": QuestionType.Text,
"id": "server.port",
"message": "Port number?",
"desc": "1024-65535",
"default": "3000",
"validate": lambda input: (
"Please enter a number" if not input.isdigit() else
"Port must be between 1024 and 65535" if not (1024 <= int(input) <= 65535) else None
)
})
var port = await i.Text(new TextQuestion
{
Type = QuestionType.Text,
Id = "server.port",
Message = "Port number?",
Desc = "1024-65535",
Default = "3000",
Validate = (input) =>
{
if (!int.TryParse(input, out var num)) return "Please enter a number";
Must be a valid number
if (num < 1024 || num > 65535) return "Port must be between 1024 and 65535";
Check valid port range
return null;
}
});

Password Strength

const password = await i.password({
type: QuestionType.Password,
id: 'user.password',
message: 'Password?',
desc: 'Strong password required',
validate: (input) => {
if (input.length < 8) return 'Minimum 8 characters';
Check minimum length
if (!/[A-Z]/.test(input)) return 'Include an uppercase letter';
Require uppercase letter
if (!/[a-z]/.test(input)) return 'Include a lowercase letter';
Require lowercase letter
if (!/[0-9]/.test(input)) return 'Include a number';
Require number
if (!/[^A-Za-z0-9]/.test(input)) return 'Include a special character';
Require special character
return null;
}
});
import re
password = await i.password({
"type": QuestionType.Password,
"id": "user.password",
"message": "Password?",
"desc": "Strong password required",
"validate": lambda input: (
"Minimum 8 characters" if len(input) < 8 else
"Include an uppercase letter" if not re.search(r'[A-Z]', input) else
Require uppercase letter
"Include a lowercase letter" if not re.search(r'[a-z]', input) else
Require lowercase letter
"Include a number" if not re.search(r'[0-9]', input) else
Require number
"Include a special character" if not re.search(r'[^A-Za-z0-9]', input) else None
Require special character
)
})
var password = await i.Password(new PasswordQuestion
{
Type = QuestionType.Password,
Id = "user.password",
Message = "Password?",
Desc = "Strong password required",
Validate = (input) =>
{
if (input.Length < 8) return "Minimum 8 characters";
Check minimum length
if (!Regex.IsMatch(input, @"[A-Z]")) return "Include an uppercase letter";
Require uppercase letter
if (!Regex.IsMatch(input, @"[a-z]")) return "Include a lowercase letter";
Require lowercase letter
if (!Regex.IsMatch(input, @"[0-9]")) return "Include a number";
Require number
if (!Regex.IsMatch(input, @"[^A-Za-z0-9]")) return "Include a special character";
Require special character
return null;
}
});

Supported Question Types

Validation is only supported on question types that accept text input:

Question TypeValidation Support
textYes
passwordYes
dateSelectYes
selectNo
checkboxNo
confirmNo

For select, checkbox, and confirm questions, validation is not needed since users can only choose from predefined options.

Combining Validation with Defaults

const projectName = await i.text({
type: QuestionType.Text,
id: 'project.name',
message: 'Project name?',
desc: 'Lowercase, hyphens allowed',
default: 'my-project',
validate: (input) => {
if (!input) return 'Name is required';
if (!/^[a-z][a-z0-9-]*$/.test(input)) {
return 'Use lowercase letters, numbers, and hyphens. Start with a letter.';
}
if (input.length > 50) return 'Name too long (max 50 chars)';
return null;
}
});
import re
project_name = await i.text({
"type": QuestionType.Text,
"id": "project.name",
"message": "Project name?",
"desc": "Lowercase, hyphens allowed",
"default": "my-project",
"validate": lambda input: (
"Name is required" if not input else
"Use lowercase letters, numbers, and hyphens. Start with a letter." if not re.match(r'^[a-z][a-z0-9-]*$', input) else
"Name too long (max 50 chars)" if len(input) > 50 else None
)
})
var projectName = await i.Text(new TextQuestion
{
Type = QuestionType.Text,
Id = "project.name",
Message = "Project name?",
Desc = "Lowercase, hyphens allowed",
Default = "my-project",
Validate = (input) =>
{
if (string.IsNullOrEmpty(input)) return "Name is required";
if (!Regex.IsMatch(input, @"^[a-z][a-z0-9-]*$"))
return "Use lowercase letters, numbers, and hyphens. Start with a letter.";
if (input.Length > 50) return "Name too long (max 50 chars)";
return null;
}
});