@tsed/cli-prompts 7.0.0-beta.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/esm/PromptRunner.js +29 -0
- package/lib/esm/errors/PromptCancelledError.js +6 -0
- package/lib/esm/fn/autocomplete.js +60 -0
- package/lib/esm/fn/checkbox.js +28 -0
- package/lib/esm/fn/confirm.js +10 -0
- package/lib/esm/fn/index.js +6 -0
- package/lib/esm/fn/input.js +8 -0
- package/lib/esm/fn/list.js +18 -0
- package/lib/esm/fn/password.js +8 -0
- package/lib/esm/index.js +3 -0
- package/lib/esm/interfaces/NormalizedPromptQuestion.js +1 -0
- package/lib/esm/interfaces/PromptQuestion.js +1 -0
- package/lib/esm/utils/applyTransforms.js +10 -0
- package/lib/esm/utils/ensureNotCancelled.js +9 -0
- package/lib/esm/utils/getValidationError.js +14 -0
- package/lib/esm/utils/normalizeChoices.js +17 -0
- package/lib/esm/utils/normalizeQuestion.js +23 -0
- package/lib/esm/utils/processPrompt.js +20 -0
- package/lib/esm/utils/resolveListDefault.js +13 -0
- package/lib/esm/utils/resolveMaybe.js +6 -0
- package/lib/esm/utils/shouldAsk.js +9 -0
- package/lib/tsconfig.esm.tsbuildinfo +1 -0
- package/lib/types/PromptRunner.d.ts +6 -0
- package/lib/types/errors/PromptCancelledError.d.ts +3 -0
- package/lib/types/fn/autocomplete.d.ts +2 -0
- package/lib/types/fn/checkbox.d.ts +2 -0
- package/lib/types/fn/confirm.d.ts +2 -0
- package/lib/types/fn/index.d.ts +6 -0
- package/lib/types/fn/input.d.ts +2 -0
- package/lib/types/fn/list.d.ts +2 -0
- package/lib/types/fn/password.d.ts +2 -0
- package/lib/types/index.d.ts +3 -0
- package/lib/types/interfaces/NormalizedPromptQuestion.d.ts +9 -0
- package/lib/types/interfaces/PromptQuestion.d.ts +154 -0
- package/lib/types/utils/applyTransforms.d.ts +2 -0
- package/lib/types/utils/ensureNotCancelled.d.ts +1 -0
- package/lib/types/utils/getValidationError.d.ts +2 -0
- package/lib/types/utils/normalizeChoices.d.ts +8 -0
- package/lib/types/utils/normalizeQuestion.d.ts +3 -0
- package/lib/types/utils/processPrompt.d.ts +5 -0
- package/lib/types/utils/resolveListDefault.d.ts +3 -0
- package/lib/types/utils/resolveMaybe.d.ts +1 -0
- package/lib/types/utils/shouldAsk.d.ts +2 -0
- package/package.json +47 -0
- package/readme.md +112 -0
- package/src/PromptRunner.spec.ts +64 -0
- package/src/PromptRunner.ts +42 -0
- package/src/errors/PromptCancelledError.spec.ts +13 -0
- package/src/errors/PromptCancelledError.ts +6 -0
- package/src/fn/autocomplete.ts +77 -0
- package/src/fn/checkbox.ts +40 -0
- package/src/fn/confirm.ts +16 -0
- package/src/fn/index.ts +6 -0
- package/src/fn/input.ts +13 -0
- package/src/fn/list.ts +24 -0
- package/src/fn/password.ts +13 -0
- package/src/fn/prompts.spec.ts +175 -0
- package/src/index.ts +3 -0
- package/src/interfaces/NormalizedPromptQuestion.ts +10 -0
- package/src/interfaces/PromptQuestion.ts +172 -0
- package/src/utils/applyTransforms.ts +15 -0
- package/src/utils/ensureNotCancelled.ts +12 -0
- package/src/utils/getValidationError.ts +21 -0
- package/src/utils/normalizeChoices.ts +28 -0
- package/src/utils/normalizeQuestion.ts +31 -0
- package/src/utils/processPrompt.ts +29 -0
- package/src/utils/resolveListDefault.ts +22 -0
- package/src/utils/resolveMaybe.ts +10 -0
- package/src/utils/shouldAsk.ts +13 -0
- package/src/utils/utils.spec.ts +169 -0
- package/tsconfig.esm.json +27 -0
- package/vitest.config.mts +22 -0
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import {PromptCancelledError} from "../errors/PromptCancelledError.js";
|
|
2
|
+
import type {PromptQuestion} from "../interfaces/PromptQuestion.js";
|
|
3
|
+
import {applyTransforms} from "./applyTransforms.js";
|
|
4
|
+
import {ensureNotCancelled} from "./ensureNotCancelled.js";
|
|
5
|
+
import {getValidationError} from "./getValidationError.js";
|
|
6
|
+
import {normalizeChoices} from "./normalizeChoices.js";
|
|
7
|
+
import {normalizeQuestion} from "./normalizeQuestion.js";
|
|
8
|
+
import {CONTINUE, processPrompt} from "./processPrompt.js";
|
|
9
|
+
import {resolveListDefault} from "./resolveListDefault.js";
|
|
10
|
+
import {resolveMaybe} from "./resolveMaybe.js";
|
|
11
|
+
import {shouldAsk} from "./shouldAsk.js";
|
|
12
|
+
|
|
13
|
+
const clack = vi.hoisted(() => ({
|
|
14
|
+
note: vi.fn(),
|
|
15
|
+
isCancel: vi.fn().mockReturnValue(false),
|
|
16
|
+
cancel: vi.fn()
|
|
17
|
+
}));
|
|
18
|
+
|
|
19
|
+
vi.mock("@clack/prompts", () => clack);
|
|
20
|
+
|
|
21
|
+
describe("prompt utils", () => {
|
|
22
|
+
beforeEach(() => {
|
|
23
|
+
clack.note.mockReset();
|
|
24
|
+
clack.isCancel.mockReset().mockReturnValue(false);
|
|
25
|
+
clack.cancel.mockReset();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("applyTransforms should chain transformer and filter", async () => {
|
|
29
|
+
const transformer = vi.fn().mockResolvedValue("BAR");
|
|
30
|
+
const filter = vi.fn().mockResolvedValue("bar");
|
|
31
|
+
|
|
32
|
+
const result = await applyTransforms(
|
|
33
|
+
{
|
|
34
|
+
type: "input",
|
|
35
|
+
name: "foo",
|
|
36
|
+
message: "Foo",
|
|
37
|
+
transformer,
|
|
38
|
+
filter
|
|
39
|
+
},
|
|
40
|
+
{},
|
|
41
|
+
"foo"
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
expect(transformer).toHaveBeenCalledWith("foo", {}, {isFinal: true});
|
|
45
|
+
expect(filter).toHaveBeenCalledWith("BAR", {});
|
|
46
|
+
expect(result).toBe("bar");
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it("ensureNotCancelled should throw PromptCancelledError when clack cancels", () => {
|
|
50
|
+
clack.isCancel.mockReturnValue(true);
|
|
51
|
+
|
|
52
|
+
expect(() => ensureNotCancelled(Symbol("cancel"))).toThrow(PromptCancelledError);
|
|
53
|
+
expect(clack.cancel).toHaveBeenCalled();
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("ensureNotCancelled should return value when not cancelled", () => {
|
|
57
|
+
expect(ensureNotCancelled("ok")).toBe("ok");
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("getValidationError should map validator return values", async () => {
|
|
61
|
+
const question: PromptQuestion = {
|
|
62
|
+
type: "input",
|
|
63
|
+
name: "foo",
|
|
64
|
+
message: "Foo",
|
|
65
|
+
validate: vi.fn().mockResolvedValueOnce(false).mockResolvedValueOnce("nope").mockResolvedValue(true)
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
expect(await getValidationError(question, {}, "first")).toBe("Invalid value.");
|
|
69
|
+
expect(await getValidationError(question, {}, "second")).toBe("nope");
|
|
70
|
+
expect(await getValidationError(question, {}, "third")).toBeUndefined();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("normalizeChoices should convert primitive and object choices", () => {
|
|
74
|
+
const result = normalizeChoices([{name: "Foo", value: 1, short: "F"}, "bar"]);
|
|
75
|
+
|
|
76
|
+
expect(result).toEqual([
|
|
77
|
+
{label: "Foo", value: 1, hint: "F", checked: undefined},
|
|
78
|
+
{label: "bar", value: "bar"}
|
|
79
|
+
]);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it("normalizeQuestion should resolve message, default, choices, and wrap source", async () => {
|
|
83
|
+
const source = vi.fn().mockResolvedValue(["a"]);
|
|
84
|
+
const question: PromptQuestion = {
|
|
85
|
+
type: "autocomplete",
|
|
86
|
+
name: "feature",
|
|
87
|
+
message: vi.fn().mockResolvedValue("Pick one"),
|
|
88
|
+
default: vi.fn().mockResolvedValue("b"),
|
|
89
|
+
choices: [{name: "alpha", value: "a"}],
|
|
90
|
+
source
|
|
91
|
+
} as any;
|
|
92
|
+
|
|
93
|
+
const answers = {previous: true};
|
|
94
|
+
const normalized = await normalizeQuestion(question, answers);
|
|
95
|
+
|
|
96
|
+
expect(normalized.message).toBe("Pick one");
|
|
97
|
+
expect(normalized.default).toBe("b");
|
|
98
|
+
expect(normalized.choices).toEqual([{label: "alpha", value: "a", hint: undefined, checked: undefined}]);
|
|
99
|
+
await normalized.source?.({temp: "x"}, "kw");
|
|
100
|
+
expect(source).toHaveBeenCalledWith({previous: true, temp: "x"}, "kw");
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
it("processPrompt should keep looping until validation passes", async () => {
|
|
104
|
+
const question: PromptQuestion = {
|
|
105
|
+
type: "input",
|
|
106
|
+
name: "foo",
|
|
107
|
+
message: "Foo",
|
|
108
|
+
validate: vi.fn().mockResolvedValueOnce("Error").mockResolvedValue(true)
|
|
109
|
+
};
|
|
110
|
+
const cb = vi.fn().mockResolvedValue("value");
|
|
111
|
+
|
|
112
|
+
const result = await processPrompt(question, {}, cb);
|
|
113
|
+
|
|
114
|
+
expect(result).toBe("value");
|
|
115
|
+
expect(cb).toHaveBeenCalledTimes(2);
|
|
116
|
+
expect(clack.note).toHaveBeenCalledWith("Error", "Validation error");
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it("processPrompt should honor CONTINUE sentinel", async () => {
|
|
120
|
+
const question: PromptQuestion = {
|
|
121
|
+
type: "input",
|
|
122
|
+
name: "foo",
|
|
123
|
+
message: "Foo"
|
|
124
|
+
};
|
|
125
|
+
const cb = vi.fn().mockResolvedValueOnce(CONTINUE).mockResolvedValueOnce("done");
|
|
126
|
+
|
|
127
|
+
const result = await processPrompt(question, {}, cb);
|
|
128
|
+
|
|
129
|
+
expect(result).toBe("done");
|
|
130
|
+
expect(cb).toHaveBeenCalledTimes(2);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it("resolveListDefault should prefer explicit defaults, then checked, then first value", () => {
|
|
134
|
+
expect(
|
|
135
|
+
resolveListDefault({default: 1} as any, [
|
|
136
|
+
{label: "one", value: "first"},
|
|
137
|
+
{label: "two", value: "second"}
|
|
138
|
+
])
|
|
139
|
+
).toBe("second");
|
|
140
|
+
|
|
141
|
+
expect(
|
|
142
|
+
resolveListDefault({default: undefined} as any, [
|
|
143
|
+
{label: "one", value: "first", checked: true},
|
|
144
|
+
{label: "two", value: "second"}
|
|
145
|
+
])
|
|
146
|
+
).toBe("first");
|
|
147
|
+
|
|
148
|
+
expect(resolveListDefault({} as any, [{label: "only", value: "single"}])).toBe("single");
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it("resolveMaybe should resolve thunk values", async () => {
|
|
152
|
+
expect(resolveMaybe("static", {})).toBe("static");
|
|
153
|
+
await expect(resolveMaybe(async () => "dynamic", {})).resolves.toBe("dynamic");
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it("shouldAsk should evaluate booleans and functions", async () => {
|
|
157
|
+
const when = vi.fn().mockResolvedValueOnce(false).mockResolvedValueOnce(true);
|
|
158
|
+
const question: PromptQuestion = {
|
|
159
|
+
type: "input",
|
|
160
|
+
name: "x",
|
|
161
|
+
message: "X",
|
|
162
|
+
when
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
expect(await shouldAsk(question, {})).toBe(false);
|
|
166
|
+
expect(await shouldAsk({...question, when: true}, {})).toBe(true);
|
|
167
|
+
expect(await shouldAsk({...question, when: undefined}, {})).toBe(true);
|
|
168
|
+
});
|
|
169
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "@tsed/typescript/tsconfig.node.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"baseUrl": ".",
|
|
5
|
+
"rootDir": "src",
|
|
6
|
+
"outDir": "./lib/esm",
|
|
7
|
+
"declarationDir": "./lib/types",
|
|
8
|
+
"declaration": true,
|
|
9
|
+
"composite": true,
|
|
10
|
+
"noEmit": false,
|
|
11
|
+
"sourceMap": false
|
|
12
|
+
},
|
|
13
|
+
"include": ["src", "src/**/*.json"],
|
|
14
|
+
"exclude": [
|
|
15
|
+
"node_modules",
|
|
16
|
+
"test",
|
|
17
|
+
"lib",
|
|
18
|
+
"benchmark",
|
|
19
|
+
"coverage",
|
|
20
|
+
"spec",
|
|
21
|
+
"**/*.benchmark.ts",
|
|
22
|
+
"**/*.spec.ts",
|
|
23
|
+
"keys",
|
|
24
|
+
"**/__mock__/**",
|
|
25
|
+
"webpack.config.js"
|
|
26
|
+
]
|
|
27
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// @ts-ignore
|
|
2
|
+
import {presets} from "@tsed/vitest/presets";
|
|
3
|
+
import {defineConfig} from "vitest/config";
|
|
4
|
+
|
|
5
|
+
export default defineConfig(
|
|
6
|
+
{
|
|
7
|
+
...presets,
|
|
8
|
+
test: {
|
|
9
|
+
...presets.test,
|
|
10
|
+
setupFiles: ["reflect-metadata"],
|
|
11
|
+
coverage: {
|
|
12
|
+
...presets.test?.coverage,
|
|
13
|
+
thresholds: {
|
|
14
|
+
statements: 0,
|
|
15
|
+
branches: 0,
|
|
16
|
+
functions: 0,
|
|
17
|
+
lines: 0
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
);
|