Skip to content

Commit b20bbc1

Browse files
committed
feat(plugin-inquirer): add complete-input inquirer plugin
link #32
1 parent e8dac95 commit b20bbc1

7 files changed

Lines changed: 199 additions & 7 deletions

File tree

‎package.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
"docs:dev": "pnpm --filter=docs docs:dev",
3434
"docs:serve": "pnpm --filter=docs docs:serve",
3535
"example:checkbox": "node ./packages/@cz-git/plugin-inquirer/examples/checkbox.js",
36+
"example:input": "node ./packages/@cz-git/plugin-inquirer/examples/input.js",
3637
"example:list": "node ./packages/@cz-git/plugin-inquirer/examples/list.js",
3738
"lint": "eslint --ext .ts packages docs/.vuepress",
3839
"prepare": "husky install",

‎packages/@cz-git/plugin-inquirer/README.md‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,19 @@
22

33
(WIP)
44

5-
> provide cz-git's inquirer plugins, include **search-list, search-checkbox**
5+
> provide cz-git's inquirer plugins, include **search-list, search-checkbox**, **complete-input**
66
77
## demo
88
```
99
pnpm install
1010
pnpm run dev
1111
node ./packages/@cz-git/plugin-inquirer/examples/checkbox.js
1212
node ./packages/@cz-git/plugin-inquirer/examples/list.js
13+
node ./packages/@cz-git/plugin-inquirer/examples/input.js
14+
15+
# or
16+
17+
pnpm example:checkbox
18+
pnpm example:list
19+
pnpm example:input
1320
```
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
"use strict";
2+
var inquirer = require("inquirer");
3+
var { CompleteInput, style } = require("@cz-git/inquirer");
4+
5+
const useThemeCode = (input, themeColorCode) =>
6+
themeColorCode ? style.rgb(themeColorCode)(input) : style.cyan(input);
7+
8+
inquirer.registerPrompt("complete-input", CompleteInput);
9+
inquirer
10+
.prompt([
11+
{
12+
type: "complete-input",
13+
name: "testOne",
14+
message: "Input empty test: \n",
15+
completeValue: "",
16+
validate: (input) => {
17+
return input.length ? true : style.red("[ERROR] value is required");
18+
},
19+
transformer: (input) => useThemeCode(input, '38;5;042')
20+
},
21+
{
22+
type: "complete-input",
23+
name: "testTwo",
24+
message: "Write a SHORT, IMPERATIVE tense description of the change:\n",
25+
validate: (input) => {
26+
return input.length ? true : style.red("[ERROR] value is required");
27+
},
28+
transformer: (input) => {
29+
if (input.length < 100) {
30+
return useThemeCode(input, '38;5;042');
31+
}else {
32+
return style.red(input);
33+
}
34+
},
35+
completeValue: "[Form] "
36+
},
37+
{
38+
type: "complete-input",
39+
name: "cz",
40+
completeValue: "cz-git",
41+
message: "Denote the SCOPE of this change:",
42+
validate: (input) => {
43+
return input.length ? true : style.red("[ERROR] value is required");
44+
},
45+
transformer: (input) => useThemeCode(input, '38;5;043')
46+
}
47+
])
48+
.then(function (answers) {
49+
console.log(JSON.stringify(answers, null, " "));
50+
})
51+
.catch((e) => console.log(e));

‎packages/@cz-git/plugin-inquirer/package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@cz-git/inquirer",
33
"version": "1.3.3",
4-
"description": "provide cz-git inquirer plugins, include search-list, search-checkbox",
4+
"description": "provide cz-git inquirer plugins, include search-list, search-checkbox, complete-input",
55
"keywords": [
66
"cz-git",
77
"inquirer",
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export * from "./list";
22
export * from "./checkbox";
3+
export * from "./input";
34
export * from "./shared";
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/**
2+
* @description: inquirer plugin - Search Checkbox
3+
* @author: @Zhengqbbb (zhengqbbb@gmail.com)
4+
* @license MIT
5+
*/
6+
7+
import Base from "inquirer/lib/prompts/base";
8+
import observe from "inquirer/lib/utils/events";
9+
import { map, takeUntil } from "rxjs/operators";
10+
import type { Interface as ReadlineInterface } from "readline";
11+
import type { Answers, Question } from "inquirer";
12+
import { ansiEscapes, style } from "../shared";
13+
import type { CompletePromptQuestionOptions } from "../shared";
14+
15+
export type { CompletePromptQuestionOptions } from "../shared";
16+
export class CompleteInput extends Base {
17+
private completeValue?: string;
18+
private answer?: string;
19+
private state?: string;
20+
private done: any;
21+
22+
constructor(questions: Question, readline: ReadlineInterface, answers: Answers) {
23+
super(questions, readline, answers);
24+
const { completeValue } = this.opt as unknown as CompletePromptQuestionOptions;
25+
if (typeof completeValue === "string") this.completeValue = completeValue;
26+
}
27+
28+
/**
29+
* @description: Start the Inquiry session
30+
* @param {Function} cb Callback when prompt is done
31+
*/
32+
_run(cb: any): this {
33+
this.done = cb;
34+
35+
// Once user confirm (enter key)
36+
const events = observe(this.rl);
37+
const submit = events.line.pipe(map(this.filterInput.bind(this)));
38+
39+
const validation = this.handleSubmitEvents(submit);
40+
validation.success.forEach(this.onEnd.bind(this));
41+
validation.error.forEach(this.onError.bind(this));
42+
43+
events.keypress.pipe(takeUntil(validation.success)).forEach(this.onKeypress.bind(this));
44+
45+
// Init the prompt
46+
this.render();
47+
48+
return this;
49+
}
50+
51+
/**
52+
* @description: render screen
53+
*/
54+
render(error?: string) {
55+
let bottomContent = "";
56+
let appendContent = "";
57+
let message = this.getQuestion();
58+
const { transformer, completeValue } = this.opt as unknown as CompletePromptQuestionOptions;
59+
const isFinal = this.status === "answered";
60+
61+
if (isFinal) {
62+
appendContent = this.answer || "";
63+
} else {
64+
appendContent = this.rl.line;
65+
}
66+
67+
if (transformer) {
68+
message += transformer(appendContent, this.answers, { isFinal });
69+
} else {
70+
message += isFinal ? style.cyan(appendContent) : appendContent;
71+
}
72+
if (!this.state && !isFinal && completeValue) {
73+
message += style.gray(completeValue);
74+
bottomContent = style.gray("Press <tab>|<right> complete;Press <Enter> submit value");
75+
}
76+
77+
if (error) {
78+
bottomContent = style.red(">> ") + error;
79+
}
80+
81+
this.screen.render(message, bottomContent);
82+
}
83+
84+
filterInput(input?: string) {
85+
if (!input) {
86+
return this.completeValue || "";
87+
}
88+
return input;
89+
}
90+
91+
onEnd(state: { value?: string }) {
92+
this.answer = state.value;
93+
this.status = "answered";
94+
95+
// Re-render prompt
96+
this.render();
97+
98+
this.screen.done();
99+
this.done(state.value);
100+
}
101+
102+
onError({ value = "", isValid }: any) {
103+
// @ts-ignore
104+
this.rl.line += value;
105+
// @ts-ignore
106+
this.rl.cursor += value.length;
107+
this.render(isValid);
108+
}
109+
110+
/**
111+
* @description: Search <any key>
112+
*/
113+
onKeypress(e: { key: { name?: string; ctrl?: boolean }; value: string }) {
114+
if (!this.state && (e.key.name === "tab" || e.key.name === "right")) {
115+
this.rl.write(ansiEscapes.cursorLeft);
116+
this.rl.write(ansiEscapes.cursorForward(this.completeValue?.length));
117+
// @ts-ignore
118+
this.rl.line = this.completeValue;
119+
// @ts-ignore
120+
this.rl.cursor = this.completeValue?.length;
121+
}
122+
this.state = "touched";
123+
124+
this.render();
125+
}
126+
}

‎packages/@cz-git/plugin-inquirer/src/shared/types/inquirer.ts‎

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ export interface BaseOptionType {
2828
default?: any;
2929
}
3030

31-
export interface CZPromptOptionType extends BaseOptionType {
32-
source: ChoiceType<Separator["type"]>[];
33-
isInitDefault: boolean;
34-
}
35-
export interface CZPromptQuestionOptions<T extends Answers = Answers> extends Question<T> {
31+
type isFinal = {
32+
isFinal: boolean;
33+
};
34+
35+
export interface SearchPromptQuestionOptions<T extends Answers = Answers> extends Question<T> {
3636
separator: string;
3737

3838
/**
@@ -60,3 +60,9 @@ export interface CZPromptQuestionOptions<T extends Answers = Answers> extends Qu
6060
*/
6161
isInitDefault?: boolean | undefined;
6262
}
63+
64+
export interface CompletePromptQuestionOptions<T extends Answers = Answers> extends Question<T> {
65+
completeValue?: string;
66+
67+
transformer?: (input: string, answers: Answers, { isFinal }: isFinal) => string;
68+
}

0 commit comments

Comments
 (0)