The interactive prompts system provides types for creating guided commit message creation interfaces. This enables building interactive CLI tools that help users write valid commit messages through step-by-step prompts.
type RuleField =
| "header"
| "type"
| "scope"
| "subject"
| "body"
| "footer";Core commit message components that can be prompted:
type PromptName =
| RuleField
| "isBreaking"
| "breakingBody"
| "breaking"
| "isIssueAffected"
| "issuesBody"
| "issues";Extended set of prompt fields including breaking change and issue handling:
interface PromptConfig {
settings: {
scopeEnumSeparator: string;
enableMultipleScopes: boolean;
};
messages: PromptMessages;
questions: Partial<
Record<
PromptName,
{
description?: string;
messages?: { [K: string]: string };
enum?: {
[enumName: string]: {
description?: string;
title?: string;
emoji?: string;
};
};
}
>
>;
}Complete prompt configuration structure:
interface PromptSettings {
scopeEnumSeparator: string;
enableMultipleScopes: boolean;
}Global settings for prompt behavior:
interface PromptMessages {
skip: string;
max: string;
min: string;
emptyWarning: string;
upperLimitWarning: string;
lowerLimitWarning: string;
[_key: string]: string;
}Localized messages used throughout the prompt interface:
type UserPromptConfig = DeepPartial<PromptConfig>;
type DeepPartial<T> = {
[P in keyof T]?: {
[K in keyof T[P]]?: T[P][K];
};
};User-provided partial configuration that overrides defaults:
import { PromptConfig, PromptMessages } from "@commitlint/types";
const messages: PromptMessages = {
skip: "Skip this field",
max: "Maximum {0} characters",
min: "Minimum {0} characters",
emptyWarning: "This field cannot be empty",
upperLimitWarning: "Input too long",
lowerLimitWarning: "Input too short"
};
const basicPromptConfig: PromptConfig = {
settings: {
scopeEnumSeparator: ",",
enableMultipleScopes: true
},
messages,
questions: {
type: {
description: "Select the type of change you're committing:",
enum: {
feat: {
description: "A new feature",
title: "Features",
emoji: "✨"
},
fix: {
description: "A bug fix",
title: "Bug Fixes",
emoji: "🐛"
},
docs: {
description: "Documentation only changes",
title: "Documentation",
emoji: "📚"
}
}
},
scope: {
description: "What is the scope of this change (e.g. component, filename):",
messages: {
empty: "Scope can be empty"
}
},
subject: {
description: "Write a short, imperative tense description of the change:",
messages: {
empty: "Subject is required",
maxLength: "Subject must be no more than 50 characters"
}
}
}
};import { UserPromptConfig } from "@commitlint/types";
// Partial configuration that extends defaults
const userConfig: UserPromptConfig = {
settings: {
enableMultipleScopes: false // Override default
},
messages: {
skip: "Press Enter to skip", // Custom message
emptyWarning: "⚠️ This field is required"
},
questions: {
type: {
description: "Choose commit type:",
enum: {
feat: { title: "Feature", emoji: "🚀" },
fix: { title: "Bug Fix", emoji: "🔧" },
chore: { title: "Chore", emoji: "🧹" }
}
},
breaking: {
description: "Describe the breaking changes:",
messages: {
skip: "No breaking changes"
}
}
}
};import { PromptConfig, PromptName } from "@commitlint/types";
const advancedConfig: PromptConfig = {
settings: {
scopeEnumSeparator: "|",
enableMultipleScopes: true
},
messages: {
skip: "Leave empty to skip",
max: "Maximum {0} chars allowed",
min: "At least {0} chars required",
emptyWarning: "❌ Required field",
upperLimitWarning: "📏 Too long!",
lowerLimitWarning: "📏 Too short!"
},
questions: {
type: {
description: "🏷️ Select commit type:",
enum: {
feat: { description: "New feature", title: "✨ Feature", emoji: "✨" },
fix: { description: "Bug fix", title: "🐛 Fix", emoji: "🐛" },
docs: { description: "Documentation", title: "📝 Docs", emoji: "📝" },
style: { description: "Code style", title: "💄 Style", emoji: "💄" },
refactor: { description: "Code refactor", title: "♻️ Refactor", emoji: "♻️" },
test: { description: "Tests", title: "🧪 Test", emoji: "🧪" },
chore: { description: "Maintenance", title: "🔧 Chore", emoji: "🔧" }
}
},
scope: {
description: "📦 Scope (component/module affected):",
messages: {
empty: "Scope helps identify what changed",
invalidFormat: "Use lowercase, no spaces"
}
},
subject: {
description: "📋 Brief description (imperative mood):",
messages: {
empty: "Subject describes what the commit does",
maxLength: "Keep it under 50 characters",
invalidFormat: "Start with lowercase verb"
}
},
body: {
description: "📖 Detailed description (optional):",
messages: {
skip: "Leave empty if subject is sufficient"
}
},
isBreaking: {
description: "💥 Are there breaking changes?",
messages: {
confirmation: "This will increment major version"
}
},
breakingBody: {
description: "💥 Describe the breaking changes:",
messages: {
empty: "Explain what breaks and how to migrate"
}
},
isIssueAffected: {
description: "🐛 Does this close any issues?",
messages: {
help: "Reference issues with fixes #123"
}
},
issuesBody: {
description: "🐛 List the issues (e.g., fixes #123, closes #456):",
messages: {
empty: "Use format: fixes #123, closes #456",
invalidFormat: "Use keywords: fixes, closes, resolves"
}
}
}
};import { PromptMessages, UserPromptConfig } from "@commitlint/types";
// Spanish messages
const spanishMessages: PromptMessages = {
skip: "Presiona Enter para omitir",
max: "Máximo {0} caracteres",
min: "Mínimo {0} caracteres",
emptyWarning: "Este campo no puede estar vacío",
upperLimitWarning: "Entrada demasiado larga",
lowerLimitWarning: "Entrada demasiado corta"
};
const spanishConfig: UserPromptConfig = {
messages: spanishMessages,
questions: {
type: {
description: "Selecciona el tipo de cambio:",
enum: {
feat: { description: "Nueva funcionalidad", title: "Funcionalidad" },
fix: { description: "Corrección de error", title: "Corrección" },
docs: { description: "Solo documentación", title: "Documentación" }
}
},
subject: {
description: "Escribe una descripción breve en modo imperativo:",
messages: {
empty: "El asunto es requerido",
maxLength: "El asunto no debe exceder 50 caracteres"
}
}
}
};import { PromptConfig, UserPromptConfig } from "@commitlint/types";
// Function to generate configuration based on project type
function createPromptConfig(projectType: "library" | "application" | "monorepo"): UserPromptConfig {
const baseConfig: UserPromptConfig = {
settings: {
scopeEnumSeparator: ",",
enableMultipleScopes: projectType === "monorepo"
},
questions: {
type: {
description: "Select commit type:",
enum: {
feat: { title: "Feature", emoji: "✨" },
fix: { title: "Bug Fix", emoji: "🐛" },
docs: { title: "Documentation", emoji: "📝" }
}
}
}
};
// Add project-specific customizations
switch (projectType) {
case "library":
baseConfig.questions!.type!.enum!.perf = {
title: "Performance",
emoji: "⚡",
description: "Performance improvement"
};
break;
case "application":
baseConfig.questions!.type!.enum!.deploy = {
title: "Deployment",
emoji: "🚀",
description: "Deployment related changes"
};
break;
case "monorepo":
baseConfig.questions!.scope = {
description: "Which package/workspace is affected:",
messages: {
empty: "Scope is required for monorepo"
}
};
break;
}
return baseConfig;
}
// Usage
const libraryPrompts = createPromptConfig("library");
const appPrompts = createPromptConfig("application");
const monorepoPrompts = createPromptConfig("monorepo");import { PromptConfig, RulesConfig } from "@commitlint/types";
// Generate prompt config from commitlint rules
function generatePromptsFromRules(rules: Partial<RulesConfig>): UserPromptConfig {
const config: UserPromptConfig = {
questions: {}
};
// Extract type enum from rules
const typeEnumRule = rules["type-enum"];
if (typeEnumRule && typeEnumRule[2]) {
const types = typeEnumRule[2] as string[];
config.questions!.type = {
description: "Select commit type:",
enum: types.reduce((acc, type) => {
acc[type] = { title: type.charAt(0).toUpperCase() + type.slice(1) };
return acc;
}, {} as Record<string, { title: string }>)
};
}
// Extract subject max length
const subjectMaxRule = rules["subject-max-length"];
if (subjectMaxRule && subjectMaxRule[2]) {
const maxLength = subjectMaxRule[2] as number;
config.questions!.subject = {
description: `Brief description (max ${maxLength} chars):`,
messages: {
maxLength: `Subject must be no more than ${maxLength} characters`
}
};
}
return config;
}