boilerforge 1.0.2 → 1.2.0-dev.1
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/dist/cli.js +13583 -993
- package/dist/templates/create-simple-app/package.json.hbs +30 -0
- package/dist/templates/create-simple-app/src/index.js.hbs +5 -0
- package/dist/templates/create-simple-app/src/index.ts.hbs +5 -0
- package/dist/templates/create-simple-app/tsconfig.json.hbs +14 -0
- package/package.json +27 -14
- package/{src/templates/create-node-app/resource/gitignore.ts → templates/create-simple-app/.gitignore.hbs} +1 -14
- package/templates/create-simple-app/.prettierrc.json.hbs +15 -0
- package/templates/create-simple-app/eslint.config.mjs.hbs +23 -0
- package/templates/create-simple-app/package.json.hbs +30 -0
- package/templates/create-simple-app/src/index.js.hbs +5 -0
- package/templates/create-simple-app/src/index.ts.hbs +5 -0
- package/templates/create-simple-app/tsconfig.json.hbs +14 -0
- package/.commitlintrc.json +0 -3
- package/.github/workflows/auto-pr-gen.yml +0 -25
- package/.github/workflows/enforce-pr-rules.yml +0 -28
- package/.github/workflows/npm-publish.yml +0 -17
- package/.github/workflows/release-changelog.yml +0 -28
- package/.husky/commit-msg +0 -4
- package/.husky/pre-push +0 -4
- package/.release-please-manifest.json +0 -3
- package/CHANGELOG.md +0 -37
- package/bin/cli.ts +0 -21
- package/esbuild.config.ts +0 -17
- package/prettier.config.mjs +0 -20
- package/release-please-config.json +0 -15
- package/src/config/cli-config.ts +0 -25
- package/src/lib/file.ts +0 -159
- package/src/lib/project.ts +0 -211
- package/src/lib/prompter.ts +0 -201
- package/src/lib/task.ts +0 -41
- package/src/templates/create-node-app/index.ts +0 -306
- package/src/templates/create-node-app/resource/editor-config.ts +0 -24
- package/src/templates/create-node-app/resource/eslint.ts +0 -62
- package/src/templates/create-node-app/resource/package-json.ts +0 -57
- package/src/templates/create-node-app/resource/prettier.ts +0 -45
- package/src/templates/create-node-app/resource/project-deps.ts +0 -30
- package/src/templates/create-node-app/resource/project-files.ts +0 -17
- package/src/templates/create-node-app/resource/tsconfig.ts +0 -20
- package/src/templates/index.ts +0 -1
- package/src/templates/utils/badges.ts +0 -13
- package/src/templates/utils/git.ts +0 -64
- package/src/templates/utils/package-manager.ts +0 -78
- package/src/templates/utils/readme.ts +0 -115
- package/src/utils/exec-cmd.ts +0 -80
- package/src/utils/index.ts +0 -60
- package/src/utils/logger.ts +0 -24
- package/tsconfig.json +0 -17
- /package/{eslint.config.mjs → dist/templates/create-simple-app/eslint.config.mjs.hbs} +0 -0
- /package/{.editorconfig → templates/create-simple-app/.editorconfig.hbs} +0 -0
- /package/{.prettierignore → templates/create-simple-app/.prettierignore.hbs} +0 -0
package/src/lib/file.ts
DELETED
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createReadStream,
|
|
3
|
-
createWriteStream,
|
|
4
|
-
existsSync,
|
|
5
|
-
mkdirSync,
|
|
6
|
-
readdirSync,
|
|
7
|
-
rmdirSync,
|
|
8
|
-
unlinkSync,
|
|
9
|
-
writeFileSync,
|
|
10
|
-
} from 'fs';
|
|
11
|
-
import { join, sep } from 'path';
|
|
12
|
-
|
|
13
|
-
import { logger } from '../utils/logger';
|
|
14
|
-
|
|
15
|
-
export class File {
|
|
16
|
-
private fileName: string;
|
|
17
|
-
private filePath: string;
|
|
18
|
-
private fileExtension?: string;
|
|
19
|
-
private dirPath: string;
|
|
20
|
-
private contextPath: string;
|
|
21
|
-
private relativeDirPath: string;
|
|
22
|
-
private relativeFilePath: string;
|
|
23
|
-
private content?: string;
|
|
24
|
-
|
|
25
|
-
constructor(
|
|
26
|
-
filePath: string,
|
|
27
|
-
fileOptions?: { dirPath?: string; content?: string },
|
|
28
|
-
) {
|
|
29
|
-
const { content = '', dirPath } = fileOptions ?? {};
|
|
30
|
-
|
|
31
|
-
const filePathSplit = filePath.split('/');
|
|
32
|
-
|
|
33
|
-
const relativeDirPath = join(
|
|
34
|
-
...filePathSplit.slice(0, filePathSplit.length - 1),
|
|
35
|
-
);
|
|
36
|
-
|
|
37
|
-
const fileName = filePathSplit[filePathSplit.length - 1];
|
|
38
|
-
|
|
39
|
-
this.contextPath = dirPath ?? __dirname;
|
|
40
|
-
this.fileName = fileName;
|
|
41
|
-
this.content = content;
|
|
42
|
-
this.dirPath = join(
|
|
43
|
-
this.contextPath,
|
|
44
|
-
relativeDirPath.length ? relativeDirPath : __dirname,
|
|
45
|
-
);
|
|
46
|
-
this.filePath = join(this.dirPath, fileName);
|
|
47
|
-
this.fileExtension = fileName.split('.').at(1);
|
|
48
|
-
this.relativeDirPath = relativeDirPath;
|
|
49
|
-
this.relativeFilePath = join(relativeDirPath, fileName);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
get getFileName(): string {
|
|
53
|
-
return this.fileName;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
get getFilePath(): string {
|
|
57
|
-
return this.filePath;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
get getFileExtension(): string | undefined {
|
|
61
|
-
return this.fileExtension;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
get getDirPath(): string {
|
|
65
|
-
return this.dirPath;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
get getContextPath(): string {
|
|
69
|
-
return this.contextPath;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
get getRelativeDirPath(): string {
|
|
73
|
-
return this.relativeDirPath;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
get getRelativeFilePath(): string {
|
|
77
|
-
return this.relativeFilePath;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
create(content?: string) {
|
|
81
|
-
try {
|
|
82
|
-
mkdirSync(this.dirPath, { recursive: true });
|
|
83
|
-
writeFileSync(
|
|
84
|
-
this.filePath,
|
|
85
|
-
content || this.content || '',
|
|
86
|
-
'utf-8',
|
|
87
|
-
);
|
|
88
|
-
} catch (error) {
|
|
89
|
-
logger.err(
|
|
90
|
-
`Error while creating the file: ${this.filePath}, ${(error as Error).message}`,
|
|
91
|
-
);
|
|
92
|
-
|
|
93
|
-
throw new Error(`Error while creating the file ${this.filePath}`);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
isExists() {
|
|
98
|
-
return existsSync(this.filePath);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
delete() {
|
|
102
|
-
if (!this.isExists())
|
|
103
|
-
throw new Error(`File does not exists: ${this.filePath}`);
|
|
104
|
-
|
|
105
|
-
try {
|
|
106
|
-
unlinkSync(this.filePath);
|
|
107
|
-
this.deleteDir();
|
|
108
|
-
} catch (error) {
|
|
109
|
-
logger.err(
|
|
110
|
-
`Error while deleting the file: ${this.filePath}, ${(error as Error).message}`,
|
|
111
|
-
);
|
|
112
|
-
|
|
113
|
-
throw new Error(`Error while deleting the file ${this.filePath}`);
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
async createFrom(file: File) {
|
|
118
|
-
if (!file.isExists())
|
|
119
|
-
throw new Error(
|
|
120
|
-
`File to copy from does not exist: ${file.getFilePath}`,
|
|
121
|
-
);
|
|
122
|
-
|
|
123
|
-
if (this.isExists())
|
|
124
|
-
throw new Error(`File already exists: ${this.filePath}`);
|
|
125
|
-
|
|
126
|
-
await new Promise((resolve, reject) => {
|
|
127
|
-
const readStream = createReadStream(file.getFilePath, 'utf-8');
|
|
128
|
-
const writeStream = createWriteStream(this.filePath);
|
|
129
|
-
|
|
130
|
-
readStream.pipe(writeStream);
|
|
131
|
-
|
|
132
|
-
readStream.on('error', reject);
|
|
133
|
-
writeStream.on('error', reject);
|
|
134
|
-
writeStream.on('finish', () => resolve);
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
private deleteDir() {
|
|
139
|
-
try {
|
|
140
|
-
const dirs = this.relativeDirPath.split(sep);
|
|
141
|
-
|
|
142
|
-
for (let i = dirs.length; i > 0; i--) {
|
|
143
|
-
const dirPath = join(this.contextPath, ...dirs.slice(0, i));
|
|
144
|
-
|
|
145
|
-
if (readdirSync(dirPath).length) break;
|
|
146
|
-
|
|
147
|
-
rmdirSync(dirPath);
|
|
148
|
-
}
|
|
149
|
-
} catch (error) {
|
|
150
|
-
logger.err(
|
|
151
|
-
`Error while deleting the dirs: ${this.relativeDirPath}, ${(error as Error).message}`,
|
|
152
|
-
);
|
|
153
|
-
|
|
154
|
-
throw new Error(
|
|
155
|
-
`Error while deleting the dirs: ${this.relativeDirPath}`,
|
|
156
|
-
);
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
}
|
package/src/lib/project.ts
DELETED
|
@@ -1,211 +0,0 @@
|
|
|
1
|
-
import { Command } from 'commander';
|
|
2
|
-
import { Listr, ListrTaskWrapper } from 'listr2';
|
|
3
|
-
import { dirname, join, sep } from 'path';
|
|
4
|
-
import { logger } from '../utils/logger';
|
|
5
|
-
import { File } from './file';
|
|
6
|
-
import { Task } from './task';
|
|
7
|
-
|
|
8
|
-
export interface GitCheck {
|
|
9
|
-
version?: string;
|
|
10
|
-
configuration?: {
|
|
11
|
-
username: string;
|
|
12
|
-
email: string;
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export interface SystemCheck {
|
|
17
|
-
git?: GitCheck;
|
|
18
|
-
packageManager?: string;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export interface ProjectDependency {
|
|
22
|
-
devDependencies: string[];
|
|
23
|
-
dependencies: string[];
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export interface Resource {
|
|
27
|
-
filename: string;
|
|
28
|
-
content: string;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export interface ProjectProps {
|
|
32
|
-
name: string;
|
|
33
|
-
packageManager: string;
|
|
34
|
-
description?: string;
|
|
35
|
-
version?: string;
|
|
36
|
-
author?: string;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export interface BootstrapProps extends Partial<ProjectProps> {
|
|
40
|
-
program: Command;
|
|
41
|
-
showSubTasks?: boolean;
|
|
42
|
-
showErrorMessage?: boolean;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export interface NodejsProjectProps extends BootstrapProps {}
|
|
46
|
-
|
|
47
|
-
export abstract class Project {
|
|
48
|
-
name: string = '';
|
|
49
|
-
description: string = '';
|
|
50
|
-
version: string = '';
|
|
51
|
-
author: string = '';
|
|
52
|
-
projectPath: string = '';
|
|
53
|
-
parentDirPath: string = '';
|
|
54
|
-
packageManager: string = '';
|
|
55
|
-
packageManagerVersion: string = '';
|
|
56
|
-
|
|
57
|
-
protected configureProject(projectProps: Partial<ProjectProps>) {
|
|
58
|
-
const {
|
|
59
|
-
name = this.name,
|
|
60
|
-
description,
|
|
61
|
-
version = '0.0.1',
|
|
62
|
-
author,
|
|
63
|
-
packageManager = '',
|
|
64
|
-
} = projectProps;
|
|
65
|
-
|
|
66
|
-
const cwd = process.cwd();
|
|
67
|
-
|
|
68
|
-
this.name = !name.length ? cwd.split(sep).slice(-1)[0] : name;
|
|
69
|
-
this.description = description?.length
|
|
70
|
-
? description
|
|
71
|
-
: `Node.js application for ${this.name}`;
|
|
72
|
-
this.version = version;
|
|
73
|
-
this.author = author ?? '';
|
|
74
|
-
this.packageManager = packageManager;
|
|
75
|
-
this.projectPath = join(cwd, name.length ? name : '');
|
|
76
|
-
this.parentDirPath = name.length ? cwd : dirname(cwd);
|
|
77
|
-
this.packageManagerVersion = '';
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
getPackageManager() {
|
|
81
|
-
return `${this.packageManager}@${this.packageManagerVersion}`;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export abstract class Bootstrap extends Project {
|
|
86
|
-
protected tasks: Task[];
|
|
87
|
-
protected executedTasks: Task[];
|
|
88
|
-
protected showSubTasks?: boolean;
|
|
89
|
-
protected showErrorMessage?: boolean;
|
|
90
|
-
protected taskExecutor: Listr;
|
|
91
|
-
protected systemCheck: SystemCheck;
|
|
92
|
-
protected files: File[];
|
|
93
|
-
protected program: Command;
|
|
94
|
-
protected cmdExecutedFromDir: string;
|
|
95
|
-
|
|
96
|
-
constructor(props: BootstrapProps) {
|
|
97
|
-
super();
|
|
98
|
-
this.tasks = [];
|
|
99
|
-
this.executedTasks = [];
|
|
100
|
-
this.showSubTasks = props.showSubTasks ?? true;
|
|
101
|
-
this.showErrorMessage = props.showErrorMessage ?? false;
|
|
102
|
-
this.taskExecutor = new Listr([]);
|
|
103
|
-
this.systemCheck = {};
|
|
104
|
-
this.files = [];
|
|
105
|
-
this.program = props.program;
|
|
106
|
-
this.cmdExecutedFromDir = process.cwd();
|
|
107
|
-
this.configureProject(props);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
private async buildListrTask(
|
|
111
|
-
taskHandler: Task,
|
|
112
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
113
|
-
): Promise<{ title: string; task: any; enabled?: any }> {
|
|
114
|
-
if (!taskHandler.subTasks.length) {
|
|
115
|
-
return {
|
|
116
|
-
title: taskHandler.title,
|
|
117
|
-
enabled: taskHandler.enabled,
|
|
118
|
-
task: async () => {
|
|
119
|
-
await taskHandler.task();
|
|
120
|
-
this.executedTasks.push(taskHandler);
|
|
121
|
-
},
|
|
122
|
-
};
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
return {
|
|
126
|
-
title: taskHandler.title,
|
|
127
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
128
|
-
task: async (_: any, task: ListrTaskWrapper<any, any, any>) => {
|
|
129
|
-
await taskHandler.task();
|
|
130
|
-
this.executedTasks.push(taskHandler);
|
|
131
|
-
|
|
132
|
-
const subTasks = [];
|
|
133
|
-
for (const subTask of taskHandler.subTasks) {
|
|
134
|
-
subTasks.push(await this.buildListrTask(subTask));
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
return task.newListr([...subTasks], {
|
|
138
|
-
exitOnError: taskHandler.exitOnError,
|
|
139
|
-
concurrent: taskHandler.concurrent,
|
|
140
|
-
});
|
|
141
|
-
},
|
|
142
|
-
};
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
async bootstrap(): Promise<void> {
|
|
146
|
-
try {
|
|
147
|
-
const listrTasks = await Promise.all(
|
|
148
|
-
this.tasks.map(
|
|
149
|
-
async (taskHandler) =>
|
|
150
|
-
await this.buildListrTask(taskHandler),
|
|
151
|
-
),
|
|
152
|
-
);
|
|
153
|
-
|
|
154
|
-
this.taskExecutor.add(listrTasks);
|
|
155
|
-
this.taskExecutor.options = {
|
|
156
|
-
rendererOptions: {
|
|
157
|
-
showErrorMessage: this.showErrorMessage,
|
|
158
|
-
showSubtasks: this.showSubTasks,
|
|
159
|
-
},
|
|
160
|
-
};
|
|
161
|
-
await this.taskExecutor.run();
|
|
162
|
-
} catch (error) {
|
|
163
|
-
logger.err(error);
|
|
164
|
-
|
|
165
|
-
const rollbacks = this.tasks
|
|
166
|
-
.map(({ rollback }) => rollback)
|
|
167
|
-
.reverse();
|
|
168
|
-
|
|
169
|
-
await Promise.all(
|
|
170
|
-
rollbacks.map(
|
|
171
|
-
async (rollback) => rollback && (await rollback()),
|
|
172
|
-
),
|
|
173
|
-
);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
async setup(): Promise<Bootstrap> {
|
|
178
|
-
throw new Error('Not Implemented');
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
async configureCliCommand(): Promise<Bootstrap> {
|
|
182
|
-
throw new Error('Not Implemented');
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
async promptUser() {
|
|
186
|
-
throw new Error('Not Implemented');
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
getSystemCheck() {
|
|
190
|
-
return this.systemCheck;
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
export abstract class NodejsProject extends Bootstrap {
|
|
195
|
-
protected isTypescript: boolean;
|
|
196
|
-
protected isEslintPrettier: boolean;
|
|
197
|
-
|
|
198
|
-
constructor(nodejsProjectProps: NodejsProjectProps) {
|
|
199
|
-
super(nodejsProjectProps);
|
|
200
|
-
this.isTypescript = false;
|
|
201
|
-
this.isEslintPrettier = false;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
get enabledTypescript() {
|
|
205
|
-
return this.isTypescript;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
get enabledEslintPrettier() {
|
|
209
|
-
return this.isEslintPrettier;
|
|
210
|
-
}
|
|
211
|
-
}
|
package/src/lib/prompter.ts
DELETED
|
@@ -1,201 +0,0 @@
|
|
|
1
|
-
import chalk from 'chalk';
|
|
2
|
-
import { prompt } from 'enquirer';
|
|
3
|
-
|
|
4
|
-
type QuestionResponse<Q extends Question> = Q extends InputQuestion
|
|
5
|
-
? string
|
|
6
|
-
: Q extends SelectQuestion
|
|
7
|
-
? string
|
|
8
|
-
: Q extends RadioQuestion
|
|
9
|
-
? boolean
|
|
10
|
-
: Q extends MultiselectQuestion
|
|
11
|
-
? string[]
|
|
12
|
-
: never;
|
|
13
|
-
|
|
14
|
-
type ResponseShape<T extends readonly Question[]> = {
|
|
15
|
-
[K in T[number] as K['name']]: QuestionResponse<K>;
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
type QuestionType = 'input' | 'radio' | 'select' | 'multiselect';
|
|
19
|
-
|
|
20
|
-
type QuestionDescription = {
|
|
21
|
-
message: string;
|
|
22
|
-
default?: string;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
type MultiselectChoice = {
|
|
26
|
-
name: string;
|
|
27
|
-
message: string;
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
type QuestionMap = {
|
|
31
|
-
input: InputQuestion;
|
|
32
|
-
select: SelectQuestion;
|
|
33
|
-
multiselect: MultiselectQuestion;
|
|
34
|
-
radio: RadioQuestion;
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
type PromptMap = {
|
|
38
|
-
input: InputPrompt;
|
|
39
|
-
select: SelectPrompt;
|
|
40
|
-
multiselect: MultiselectPrompt;
|
|
41
|
-
radio: RadioPrompt;
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
type QuestionHandler = {
|
|
45
|
-
[K in keyof QuestionMap]: (question: QuestionMap[K]) => PromptMap[K];
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
interface BaseQuestion {
|
|
49
|
-
type: QuestionType;
|
|
50
|
-
name: string;
|
|
51
|
-
description?: QuestionDescription;
|
|
52
|
-
skip?: boolean;
|
|
53
|
-
validate?: (value: string) => boolean | string;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
interface SelectQuestion extends BaseQuestion {
|
|
57
|
-
type: 'select';
|
|
58
|
-
choices: readonly string[];
|
|
59
|
-
default: number;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
interface MultiselectQuestion extends BaseQuestion {
|
|
63
|
-
type: 'multiselect';
|
|
64
|
-
choices: readonly MultiselectChoice[];
|
|
65
|
-
default: number;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
interface InputQuestion extends BaseQuestion {
|
|
69
|
-
type: 'input';
|
|
70
|
-
default: string;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
interface RadioQuestion extends BaseQuestion {
|
|
74
|
-
type: 'radio';
|
|
75
|
-
enabled: string;
|
|
76
|
-
disabled: string;
|
|
77
|
-
default: boolean;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
interface InputPrompt {
|
|
81
|
-
type: 'input';
|
|
82
|
-
name: string;
|
|
83
|
-
message: string;
|
|
84
|
-
initial: string;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
interface SelectPrompt {
|
|
88
|
-
type: 'select';
|
|
89
|
-
name: string;
|
|
90
|
-
message: string;
|
|
91
|
-
choices: readonly string[];
|
|
92
|
-
initial: number;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
interface MultiselectPrompt {
|
|
96
|
-
type: 'multiselect';
|
|
97
|
-
name: string;
|
|
98
|
-
message: string;
|
|
99
|
-
choices: readonly MultiselectChoice[];
|
|
100
|
-
initial: number;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
interface RadioPrompt {
|
|
104
|
-
type: 'toggle';
|
|
105
|
-
name: string;
|
|
106
|
-
message: string;
|
|
107
|
-
enabled: string;
|
|
108
|
-
disabled: string;
|
|
109
|
-
initial: boolean;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
export type Question =
|
|
113
|
-
| InputQuestion
|
|
114
|
-
| SelectQuestion
|
|
115
|
-
| RadioQuestion
|
|
116
|
-
| MultiselectQuestion;
|
|
117
|
-
|
|
118
|
-
export type PromptObject =
|
|
119
|
-
| InputPrompt
|
|
120
|
-
| SelectPrompt
|
|
121
|
-
| RadioPrompt
|
|
122
|
-
| MultiselectPrompt;
|
|
123
|
-
|
|
124
|
-
export class Prompter<T extends readonly Question[] = Question[]> {
|
|
125
|
-
questions: T;
|
|
126
|
-
|
|
127
|
-
constructor(questions?: T) {
|
|
128
|
-
this.questions = (questions ?? []) as T;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
addQuestion<Q extends Question>(question: Q): Prompter<[...T, Q]> {
|
|
132
|
-
return new Prompter<[...T, Q]>([...this.questions, question]);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
buildPrompt(): PromptObject[] {
|
|
136
|
-
const baseBuilder = <T extends Question>(
|
|
137
|
-
question: T,
|
|
138
|
-
): {
|
|
139
|
-
type: T['type'];
|
|
140
|
-
name: string;
|
|
141
|
-
message: string;
|
|
142
|
-
validate?: (value: string) => boolean | string;
|
|
143
|
-
} => ({
|
|
144
|
-
type: question.type,
|
|
145
|
-
name: question.name,
|
|
146
|
-
message:
|
|
147
|
-
chalk.cyan(question.description?.message) +
|
|
148
|
-
(question.description?.default
|
|
149
|
-
? chalk.gray(` (${question.description.default})`)
|
|
150
|
-
: ''),
|
|
151
|
-
validate: question.validate
|
|
152
|
-
? (value) => {
|
|
153
|
-
const result = question.validate?.(value);
|
|
154
|
-
if (typeof result === 'boolean') return result;
|
|
155
|
-
return chalk.redBright(result);
|
|
156
|
-
}
|
|
157
|
-
: undefined,
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
const questionHandler: QuestionHandler = {
|
|
161
|
-
input: (question: InputQuestion) => ({
|
|
162
|
-
...baseBuilder(question),
|
|
163
|
-
initial: question.default,
|
|
164
|
-
}),
|
|
165
|
-
select: (question: SelectQuestion) => ({
|
|
166
|
-
...baseBuilder(question),
|
|
167
|
-
choices: question.choices,
|
|
168
|
-
initial: question.default,
|
|
169
|
-
}),
|
|
170
|
-
multiselect: (question: MultiselectQuestion) => ({
|
|
171
|
-
...baseBuilder(question),
|
|
172
|
-
choices: question.choices,
|
|
173
|
-
initial: question.default,
|
|
174
|
-
}),
|
|
175
|
-
radio: (question: RadioQuestion) => ({
|
|
176
|
-
...baseBuilder(question),
|
|
177
|
-
type: 'toggle',
|
|
178
|
-
enabled: question.enabled,
|
|
179
|
-
disabled: question.disabled,
|
|
180
|
-
initial: question.default,
|
|
181
|
-
}),
|
|
182
|
-
};
|
|
183
|
-
|
|
184
|
-
const prompts: PromptObject[] = [];
|
|
185
|
-
|
|
186
|
-
this.questions.forEach((question) => {
|
|
187
|
-
const handler = questionHandler[question.type] as (
|
|
188
|
-
q: typeof question,
|
|
189
|
-
) => PromptObject;
|
|
190
|
-
|
|
191
|
-
!question.skip && prompts.push(handler(question));
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
return prompts;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
async prompt(): Promise<ResponseShape<T>> {
|
|
198
|
-
const prompts = this.buildPrompt();
|
|
199
|
-
return (await prompt(prompts)) as ResponseShape<T>;
|
|
200
|
-
}
|
|
201
|
-
}
|
package/src/lib/task.ts
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
export type TaskHandler = (...args: unknown[]) => Promise<unknown> | unknown;
|
|
2
|
-
|
|
3
|
-
export interface TaskProps {
|
|
4
|
-
title: string;
|
|
5
|
-
task?: TaskHandler;
|
|
6
|
-
enabled?: TaskHandler;
|
|
7
|
-
subTasks?: Task[];
|
|
8
|
-
concurrent?: boolean;
|
|
9
|
-
rollback?: TaskHandler;
|
|
10
|
-
exitOnError?: boolean;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export class Task {
|
|
14
|
-
title: string;
|
|
15
|
-
task: TaskHandler;
|
|
16
|
-
enabled?: TaskHandler;
|
|
17
|
-
subTasks: Task[];
|
|
18
|
-
concurrent: boolean;
|
|
19
|
-
rollback?: TaskHandler;
|
|
20
|
-
exitOnError?: boolean;
|
|
21
|
-
|
|
22
|
-
constructor(taskProps: TaskProps) {
|
|
23
|
-
const {
|
|
24
|
-
title,
|
|
25
|
-
task,
|
|
26
|
-
enabled,
|
|
27
|
-
subTasks,
|
|
28
|
-
concurrent,
|
|
29
|
-
rollback,
|
|
30
|
-
exitOnError,
|
|
31
|
-
} = taskProps;
|
|
32
|
-
|
|
33
|
-
this.title = title;
|
|
34
|
-
this.task = task ?? (() => {});
|
|
35
|
-
this.enabled = enabled;
|
|
36
|
-
this.subTasks = subTasks ?? [];
|
|
37
|
-
this.concurrent = concurrent ?? false;
|
|
38
|
-
this.rollback = rollback;
|
|
39
|
-
this.exitOnError = exitOnError ?? true;
|
|
40
|
-
}
|
|
41
|
-
}
|