Skip to content

Commit d006fdd

Browse files
committed
readme
1 parent 4f96a88 commit d006fdd

File tree

1 file changed

+272
-7
lines changed

1 file changed

+272
-7
lines changed

packages/inquirerer/README.md

Lines changed: 272 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ npm install inquirerer
3131
-**Smart Validation** - Built-in pattern matching, custom validators, and sanitizers
3232
- 🔀 **Conditional Logic** - Show/hide questions based on previous answers
3333
- 🎨 **Interactive UX** - Fuzzy search, keyboard navigation, and visual feedback
34+
- 🔄 **Dynamic Defaults** - Auto-populate defaults from git config, date/time, or custom resolvers
3435

3536
## Table of Contents
3637

@@ -55,6 +56,10 @@ npm install inquirerer
5556
- [CLI with Commander Integration](#cli-with-commander-integration)
5657
- [Dynamic Dependencies](#dynamic-dependencies)
5758
- [Custom Validation](#custom-validation)
59+
- [Dynamic Defaults with Resolvers](#dynamic-defaults-with-resolvers)
60+
- [Built-in Resolvers](#built-in-resolvers)
61+
- [Custom Resolvers](#custom-resolvers)
62+
- [Resolver Examples](#resolver-examples)
5863
- [CLI Helper](#cli-helper)
5964
- [Developing](#developing)
6065

@@ -100,7 +105,10 @@ import {
100105
ListQuestion,
101106
AutocompleteQuestion,
102107
CheckboxQuestion,
103-
InquirererOptions
108+
InquirererOptions,
109+
DefaultResolverRegistry,
110+
registerDefaultResolver,
111+
resolveDefault
104112
} from 'inquirerer';
105113

106114
interface UserConfig {
@@ -124,6 +132,7 @@ interface BaseQuestion {
124132
message?: string; // Prompt message to display
125133
description?: string; // Additional context
126134
default?: any; // Default value
135+
defaultFrom?: string; // Dynamic default from resolver (e.g., 'git.user.name')
127136
useDefault?: boolean; // Skip prompt and use default
128137
required?: boolean; // Validation requirement
129138
validate?: (input: any, answers: any) => boolean | Validation;
@@ -153,12 +162,13 @@ const prompter = new Inquirerer({
153162

154163
```typescript
155164
interface InquirererOptions {
156-
noTty?: boolean; // Disable interactive mode
157-
input?: Readable; // Input stream (default: process.stdin)
158-
output?: Writable; // Output stream (default: process.stdout)
159-
useDefaults?: boolean; // Skip prompts and use defaults
160-
globalMaxLines?: number; // Max lines for list displays (default: 10)
161-
mutateArgs?: boolean; // Mutate argv object (default: true)
165+
noTty?: boolean; // Disable interactive mode
166+
input?: Readable; // Input stream (default: process.stdin)
167+
output?: Writable; // Output stream (default: process.stdout)
168+
useDefaults?: boolean; // Skip prompts and use defaults
169+
globalMaxLines?: number; // Max lines for list displays (default: 10)
170+
mutateArgs?: boolean; // Mutate argv object (default: true)
171+
resolverRegistry?: DefaultResolverRegistry; // Custom resolver registry
162172
}
163173

164174
const prompter = new Inquirerer(options);
@@ -668,6 +678,261 @@ const questions: Question[] = [
668678
];
669679
```
670680

681+
## Dynamic Defaults with Resolvers
682+
683+
The `defaultFrom` feature allows you to automatically populate question defaults from dynamic sources like git configuration, environment variables, date/time values, or custom resolvers. This eliminates repetitive boilerplate code for common default values.
684+
685+
### Quick Example
686+
687+
```typescript
688+
import { Inquirerer } from 'inquirerer';
689+
690+
const questions = [
691+
{
692+
type: 'text',
693+
name: 'authorName',
694+
message: 'Author name?',
695+
defaultFrom: 'git.user.name' // Auto-fills from git config
696+
},
697+
{
698+
type: 'text',
699+
name: 'authorEmail',
700+
message: 'Author email?',
701+
defaultFrom: 'git.user.email' // Auto-fills from git config
702+
},
703+
{
704+
type: 'text',
705+
name: 'copyrightYear',
706+
message: 'Copyright year?',
707+
defaultFrom: 'date.year' // Auto-fills current year
708+
}
709+
];
710+
711+
const prompter = new Inquirerer();
712+
const answers = await prompter.prompt({}, questions);
713+
```
714+
715+
### Built-in Resolvers
716+
717+
Inquirerer comes with several built-in resolvers ready to use:
718+
719+
#### Git Configuration
720+
721+
| Resolver | Description | Example Output |
722+
|----------|-------------|----------------|
723+
| `git.user.name` | Git global user name | `"John Doe"` |
724+
| `git.user.email` | Git global user email | `"[email protected]"` |
725+
726+
#### Date & Time
727+
728+
| Resolver | Description | Example Output |
729+
|----------|-------------|----------------|
730+
| `date.year` | Current year | `"2025"` |
731+
| `date.month` | Current month (zero-padded) | `"11"` |
732+
| `date.day` | Current day (zero-padded) | `"23"` |
733+
| `date.iso` | ISO date (YYYY-MM-DD) | `"2025-11-23"` |
734+
| `date.now` | ISO timestamp | `"2025-11-23T15:30:45.123Z"` |
735+
| `date.timestamp` | Unix timestamp (ms) | `"1732375845123"` |
736+
737+
### Priority Order
738+
739+
When resolving default values, inquirerer follows this priority:
740+
741+
1. **CLI Arguments** - Values passed via command line (highest priority)
742+
2. **`defaultFrom`** - Dynamically resolved values
743+
3. **`default`** - Static default values
744+
4. **`undefined`** - No default available
745+
746+
```typescript
747+
{
748+
type: 'text',
749+
name: 'author',
750+
defaultFrom: 'git.user.name', // Try git first
751+
default: 'Anonymous' // Fallback if git not configured
752+
}
753+
```
754+
755+
### Custom Resolvers
756+
757+
Register your own custom resolvers for project-specific needs:
758+
759+
```typescript
760+
import { registerDefaultResolver } from 'inquirerer';
761+
762+
// Register a resolver for current directory name
763+
registerDefaultResolver('cwd.name', () => {
764+
return process.cwd().split('/').pop();
765+
});
766+
767+
// Register a resolver for environment variable
768+
registerDefaultResolver('env.user', () => {
769+
return process.env.USER;
770+
});
771+
772+
// Use in questions
773+
const questions = [
774+
{
775+
type: 'text',
776+
name: 'projectName',
777+
message: 'Project name?',
778+
defaultFrom: 'cwd.name',
779+
default: 'my-project'
780+
},
781+
{
782+
type: 'text',
783+
name: 'author',
784+
message: 'Author?',
785+
defaultFrom: 'env.user'
786+
}
787+
];
788+
```
789+
790+
### Instance-Specific Resolvers
791+
792+
For isolated resolver registries, use a custom resolver registry per Inquirerer instance:
793+
794+
```typescript
795+
import { DefaultResolverRegistry, Inquirerer } from 'inquirerer';
796+
797+
const customRegistry = new DefaultResolverRegistry();
798+
799+
// Register resolvers specific to this instance
800+
customRegistry.register('app.name', () => 'my-app');
801+
customRegistry.register('app.port', () => 3000);
802+
803+
const prompter = new Inquirerer({
804+
resolverRegistry: customRegistry // Use custom registry
805+
});
806+
807+
const questions = [
808+
{
809+
type: 'text',
810+
name: 'appName',
811+
defaultFrom: 'app.name'
812+
},
813+
{
814+
type: 'number',
815+
name: 'port',
816+
defaultFrom: 'app.port'
817+
}
818+
];
819+
820+
const answers = await prompter.prompt({}, questions);
821+
```
822+
823+
### Resolver Examples
824+
825+
#### System Information
826+
827+
```typescript
828+
import os from 'os';
829+
import { registerDefaultResolver } from 'inquirerer';
830+
831+
registerDefaultResolver('system.hostname', () => os.hostname());
832+
registerDefaultResolver('system.username', () => os.userInfo().username);
833+
834+
const questions = [
835+
{
836+
type: 'text',
837+
name: 'hostname',
838+
message: 'Hostname?',
839+
defaultFrom: 'system.hostname'
840+
}
841+
];
842+
```
843+
844+
#### Conditional Defaults
845+
846+
```typescript
847+
registerDefaultResolver('app.port', () => {
848+
return process.env.NODE_ENV === 'production' ? 80 : 3000;
849+
});
850+
851+
const questions = [
852+
{
853+
type: 'number',
854+
name: 'port',
855+
message: 'Port?',
856+
defaultFrom: 'app.port'
857+
}
858+
];
859+
```
860+
861+
### Error Handling
862+
863+
Resolvers fail silently by default. If a resolver throws an error or returns `undefined`, inquirerer falls back to the static `default` value (if provided):
864+
865+
```typescript
866+
{
867+
type: 'text',
868+
name: 'author',
869+
defaultFrom: 'git.user.name', // May fail if git not configured
870+
default: 'Anonymous', // Used if resolver fails
871+
required: true
872+
}
873+
```
874+
875+
For debugging, set `DEBUG=inquirerer` to see resolver errors:
876+
877+
```bash
878+
DEBUG=inquirerer node your-cli.js
879+
```
880+
881+
### Real-World Use Case
882+
883+
```typescript
884+
import { Inquirerer, registerDefaultResolver } from 'inquirerer';
885+
886+
// Register a resolver for current directory name
887+
registerDefaultResolver('cwd.name', () => {
888+
return process.cwd().split('/').pop();
889+
});
890+
891+
const questions = [
892+
{
893+
type: 'text',
894+
name: 'projectName',
895+
message: 'Project name?',
896+
defaultFrom: 'cwd.name',
897+
required: true
898+
},
899+
{
900+
type: 'text',
901+
name: 'author',
902+
message: 'Author?',
903+
defaultFrom: 'git.user.name',
904+
required: true
905+
},
906+
{
907+
type: 'text',
908+
name: 'email',
909+
message: 'Email?',
910+
defaultFrom: 'git.user.email',
911+
required: true
912+
},
913+
{
914+
type: 'text',
915+
name: 'year',
916+
message: 'Copyright year?',
917+
defaultFrom: 'date.year'
918+
}
919+
];
920+
921+
const prompter = new Inquirerer();
922+
const config = await prompter.prompt({}, questions);
923+
```
924+
925+
With git configured, the prompts will show:
926+
927+
```bash
928+
Project name? (my-project-dir)
929+
Author? (John Doe)
930+
931+
Copyright year? (2025)
932+
```
933+
934+
All defaults automatically populated from git config, directory name, and current date!
935+
671936
## CLI Helper
672937

673938
The `CLI` class provides integration with command-line argument parsing:

0 commit comments

Comments
 (0)