boilerforge 1.1.3 → 1.2.0
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/LICENSE +21 -0
- package/README.md +106 -0
- package/dist/cli.js +35856 -21740
- package/{src/templates/create-node-app/resource/gitignore.ts → dist/templates/create-node-app/app/.gitignore.hbs} +1 -14
- package/dist/templates/create-node-app/app/.prettierrc.json.hbs +15 -0
- package/dist/templates/create-node-app/app/README.md.hbs +54 -0
- package/dist/templates/create-node-app/app/package.json.hbs +30 -0
- package/dist/templates/create-node-app/app/src/index.js.hbs +5 -0
- package/dist/templates/create-node-app/app/src/index.ts.hbs +5 -0
- package/dist/templates/create-node-app/app/tsconfig.json.hbs +15 -0
- package/dist/templates/create-node-app/forge.config.json +14 -0
- package/dist/templates/create-node-app/forge.prompt.json +105 -0
- package/dist/templates/create-node-app/schema/prompt.schema.json +240 -0
- package/package.json +17 -2
- package/.commitlintrc.json +0 -3
- package/.github/workflows/release-pipeline.yml +0 -79
- package/.husky/commit-msg +0 -4
- package/.husky/pre-push +0 -4
- package/.release/latest/config.json +0 -16
- package/.release/latest/manifest.json +0 -3
- package/.release/rc/config.json +0 -19
- package/.release/rc/manifest.json +0 -3
- package/CHANGELOG.md +0 -68
- package/bin/cli.ts +0 -21
- package/esbuild.config.ts +0 -17
- package/prettier.config.mjs +0 -20
- 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/{.editorconfig → dist/templates/create-node-app/app/.editorconfig.hbs} +0 -0
- /package/{.prettierignore → dist/templates/create-node-app/app/.prettierignore.hbs} +0 -0
- /package/{eslint.config.mjs → dist/templates/create-node-app/app/eslint.config.mjs.hbs} +0 -0
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
|
-
}
|
|
@@ -1,306 +0,0 @@
|
|
|
1
|
-
import { sep } from 'path';
|
|
2
|
-
import { File } from '../../lib/file';
|
|
3
|
-
import {
|
|
4
|
-
NodejsProject,
|
|
5
|
-
NodejsProjectProps,
|
|
6
|
-
ProjectDependency,
|
|
7
|
-
Resource,
|
|
8
|
-
} from '../../lib/project';
|
|
9
|
-
import { Prompter } from '../../lib/prompter';
|
|
10
|
-
import { Task } from '../../lib/task';
|
|
11
|
-
import { execCmd } from '../../utils/exec-cmd';
|
|
12
|
-
import { getGitConfiguration, getGitVersion } from '../utils/git';
|
|
13
|
-
import {
|
|
14
|
-
getLockFileName,
|
|
15
|
-
getPackageManagerVersion,
|
|
16
|
-
installDependencies,
|
|
17
|
-
} from '../utils/package-manager';
|
|
18
|
-
import { getReadmeContent } from '../utils/readme';
|
|
19
|
-
import { getEditorConfigContent } from './resource/editor-config';
|
|
20
|
-
import { getEslintContent } from './resource/eslint';
|
|
21
|
-
import { getGitIgnoreContent } from './resource/gitignore';
|
|
22
|
-
import { getPackageJsonContent } from './resource/package-json';
|
|
23
|
-
import {
|
|
24
|
-
getPrettierIgnoreContent,
|
|
25
|
-
getPrettierrcContent,
|
|
26
|
-
} from './resource/prettier';
|
|
27
|
-
import { getProjectDeps } from './resource/project-deps';
|
|
28
|
-
import { srcFileContent } from './resource/project-files';
|
|
29
|
-
import { getTsConfigContent } from './resource/tsconfig';
|
|
30
|
-
import { Regex } from '../../utils';
|
|
31
|
-
|
|
32
|
-
export class CreateNodeApp extends NodejsProject {
|
|
33
|
-
constructor(props: NodejsProjectProps) {
|
|
34
|
-
super(props);
|
|
35
|
-
this.isTypescript = false;
|
|
36
|
-
this.isEslintPrettier = false;
|
|
37
|
-
this.configureCliCommand();
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
async setup(): Promise<CreateNodeApp> {
|
|
41
|
-
// creating the tasks
|
|
42
|
-
const {
|
|
43
|
-
systemCheckTask,
|
|
44
|
-
setupProjectTask,
|
|
45
|
-
installDepsTask,
|
|
46
|
-
gitInitTask,
|
|
47
|
-
} = this.buildTasks(getProjectDeps(this));
|
|
48
|
-
|
|
49
|
-
this.tasks = [
|
|
50
|
-
systemCheckTask,
|
|
51
|
-
setupProjectTask,
|
|
52
|
-
installDepsTask,
|
|
53
|
-
gitInitTask,
|
|
54
|
-
];
|
|
55
|
-
|
|
56
|
-
await this.bootstrap();
|
|
57
|
-
|
|
58
|
-
return this;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
buildTasks(projectDeps: ProjectDependency): {
|
|
62
|
-
systemCheckTask: Task;
|
|
63
|
-
setupProjectTask: Task;
|
|
64
|
-
installDepsTask: Task;
|
|
65
|
-
gitInitTask: Task;
|
|
66
|
-
} {
|
|
67
|
-
// verify git
|
|
68
|
-
const verifyGitTask = new Task({
|
|
69
|
-
title: 'Checking Git availability',
|
|
70
|
-
task: async () => {
|
|
71
|
-
this.systemCheck.git = {
|
|
72
|
-
version: await getGitVersion(),
|
|
73
|
-
};
|
|
74
|
-
},
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
// git configuration (user.name & user.email)
|
|
78
|
-
const verifyGitConfigTask = new Task({
|
|
79
|
-
title: 'Checking Git config (user.name & user.email)',
|
|
80
|
-
enabled: () => !!this.systemCheck.git,
|
|
81
|
-
task: async () => {
|
|
82
|
-
const gitConfig = await getGitConfiguration({
|
|
83
|
-
global: true,
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
if (!gitConfig) return;
|
|
87
|
-
|
|
88
|
-
const username = gitConfig['user.name'];
|
|
89
|
-
const email = gitConfig['user.email'];
|
|
90
|
-
|
|
91
|
-
username &&
|
|
92
|
-
email &&
|
|
93
|
-
(this.systemCheck.git = {
|
|
94
|
-
...this.systemCheck.git,
|
|
95
|
-
configuration: {
|
|
96
|
-
username,
|
|
97
|
-
email,
|
|
98
|
-
},
|
|
99
|
-
});
|
|
100
|
-
},
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
// verify package manager
|
|
104
|
-
const verifyPkgManagerTask = new Task({
|
|
105
|
-
title: `Verifying ${this.packageManager} availability`,
|
|
106
|
-
task: async () => {
|
|
107
|
-
const pkgManagerVersion = await getPackageManagerVersion(
|
|
108
|
-
this.packageManager,
|
|
109
|
-
);
|
|
110
|
-
|
|
111
|
-
if (!pkgManagerVersion)
|
|
112
|
-
throw new Error(`${this.packageManager} is not installed`);
|
|
113
|
-
|
|
114
|
-
this.packageManagerVersion = pkgManagerVersion;
|
|
115
|
-
this.systemCheck.packageManager = `${this.packageManager}@${pkgManagerVersion}`;
|
|
116
|
-
},
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
// checking system requirements
|
|
120
|
-
const systemCheckTask = new Task({
|
|
121
|
-
title: 'Verifying System Requirements',
|
|
122
|
-
subTasks: [
|
|
123
|
-
verifyGitTask,
|
|
124
|
-
verifyGitConfigTask,
|
|
125
|
-
verifyPkgManagerTask,
|
|
126
|
-
],
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
// creating the project dir
|
|
130
|
-
const setupProjectTask = new Task({
|
|
131
|
-
title: `Scaffolding ${this.name} project`,
|
|
132
|
-
task: async () => {
|
|
133
|
-
const resourceFileContent: Resource[] = [
|
|
134
|
-
getGitIgnoreContent(),
|
|
135
|
-
getEditorConfigContent(),
|
|
136
|
-
...(this.enabledEslintPrettier
|
|
137
|
-
? [getEslintContent(this), getPrettierrcContent()]
|
|
138
|
-
: []),
|
|
139
|
-
getPackageJsonContent(this),
|
|
140
|
-
getPrettierIgnoreContent(),
|
|
141
|
-
...(this.enabledTypescript ? [getTsConfigContent()] : []),
|
|
142
|
-
getReadmeContent(this),
|
|
143
|
-
srcFileContent(this),
|
|
144
|
-
];
|
|
145
|
-
|
|
146
|
-
this.files = resourceFileContent.map(
|
|
147
|
-
({ filename, content }) =>
|
|
148
|
-
new File(filename, {
|
|
149
|
-
dirPath: this.projectPath,
|
|
150
|
-
content: `${content.trim()}\n`,
|
|
151
|
-
}),
|
|
152
|
-
);
|
|
153
|
-
|
|
154
|
-
await Promise.all(this.files.map((file) => file.create()));
|
|
155
|
-
},
|
|
156
|
-
rollback: () => {
|
|
157
|
-
this.files.map((file) => file.delete());
|
|
158
|
-
},
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
// installing dependencies
|
|
162
|
-
const installDepsTask = new Task({
|
|
163
|
-
title: `Installing dependencies`,
|
|
164
|
-
task: async () => {
|
|
165
|
-
await installDependencies(
|
|
166
|
-
this.projectPath,
|
|
167
|
-
this.packageManager,
|
|
168
|
-
projectDeps,
|
|
169
|
-
);
|
|
170
|
-
},
|
|
171
|
-
rollback: async () => {
|
|
172
|
-
await execCmd(`rm -rf node_modules`, {
|
|
173
|
-
cwd: this.projectPath,
|
|
174
|
-
throwError: false,
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
const lockFile = getLockFileName(this.packageManager);
|
|
178
|
-
|
|
179
|
-
lockFile &&
|
|
180
|
-
(await execCmd(`rm ${lockFile}`, {
|
|
181
|
-
cwd: this.projectPath,
|
|
182
|
-
throwError: false,
|
|
183
|
-
}));
|
|
184
|
-
},
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
// initialize git
|
|
188
|
-
const gitInitTask = new Task({
|
|
189
|
-
title: 'Initializing git',
|
|
190
|
-
enabled: () => !!this.systemCheck.git?.version,
|
|
191
|
-
task: async () => {
|
|
192
|
-
await execCmd('git init', {
|
|
193
|
-
cwd: this.projectPath,
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
const { username, email } =
|
|
197
|
-
this.systemCheck.git?.configuration ?? {};
|
|
198
|
-
|
|
199
|
-
username &&
|
|
200
|
-
email &&
|
|
201
|
-
(await execCmd('git commit -am"✨ Initial project setup"', {
|
|
202
|
-
cwd: this.projectPath,
|
|
203
|
-
}));
|
|
204
|
-
},
|
|
205
|
-
rollback: async () =>
|
|
206
|
-
this.systemCheck.git?.version &&
|
|
207
|
-
(await execCmd(`rm -rf .git`, {
|
|
208
|
-
cwd: this.projectPath,
|
|
209
|
-
throwError: false,
|
|
210
|
-
})),
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
return {
|
|
214
|
-
systemCheckTask,
|
|
215
|
-
setupProjectTask,
|
|
216
|
-
installDepsTask,
|
|
217
|
-
gitInitTask,
|
|
218
|
-
};
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
async configureCliCommand(): Promise<CreateNodeApp> {
|
|
222
|
-
this.program
|
|
223
|
-
.command('create-node-app')
|
|
224
|
-
.description('Create simple node.js app')
|
|
225
|
-
.argument('[name]', 'name of the project', '')
|
|
226
|
-
.action(async (name) => {
|
|
227
|
-
this.name = name;
|
|
228
|
-
await this.promptUser();
|
|
229
|
-
await this.setup();
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
return this;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
async promptUser(): Promise<void> {
|
|
236
|
-
const prompter = new Prompter([
|
|
237
|
-
{
|
|
238
|
-
type: 'input',
|
|
239
|
-
name: 'name',
|
|
240
|
-
default: '',
|
|
241
|
-
description: {
|
|
242
|
-
message: 'Project name',
|
|
243
|
-
default: process.cwd().split(sep).slice(-1)[0],
|
|
244
|
-
},
|
|
245
|
-
validate: (value) =>
|
|
246
|
-
!value.length || Regex.PROJECT_NAME.test(value)
|
|
247
|
-
? true
|
|
248
|
-
: 'Invalid project name',
|
|
249
|
-
skip: !!this.name.length,
|
|
250
|
-
},
|
|
251
|
-
{
|
|
252
|
-
type: 'input',
|
|
253
|
-
name: 'description',
|
|
254
|
-
default: '',
|
|
255
|
-
description: { message: 'Description' },
|
|
256
|
-
},
|
|
257
|
-
{
|
|
258
|
-
type: 'input',
|
|
259
|
-
name: 'version',
|
|
260
|
-
default: '0.0.1',
|
|
261
|
-
description: { message: 'Version' },
|
|
262
|
-
validate: (value) =>
|
|
263
|
-
Regex.VERSION.test(value) ? true : 'Invalid version',
|
|
264
|
-
},
|
|
265
|
-
{
|
|
266
|
-
type: 'input',
|
|
267
|
-
name: 'author',
|
|
268
|
-
default: '',
|
|
269
|
-
description: { message: 'Author' },
|
|
270
|
-
},
|
|
271
|
-
{
|
|
272
|
-
type: 'select',
|
|
273
|
-
name: 'packageManager',
|
|
274
|
-
choices: ['npm', 'yarn', 'pnpm'],
|
|
275
|
-
default: 0,
|
|
276
|
-
description: { message: 'Package manager', default: 'npm' },
|
|
277
|
-
},
|
|
278
|
-
{
|
|
279
|
-
type: 'radio',
|
|
280
|
-
name: 'isTypescript',
|
|
281
|
-
enabled: 'Yes',
|
|
282
|
-
disabled: 'No',
|
|
283
|
-
default: true,
|
|
284
|
-
description: { message: 'Use TypeScript' },
|
|
285
|
-
},
|
|
286
|
-
{
|
|
287
|
-
type: 'radio',
|
|
288
|
-
name: 'isEslintPrettier',
|
|
289
|
-
enabled: 'Yes',
|
|
290
|
-
disabled: 'No',
|
|
291
|
-
default: true,
|
|
292
|
-
description: { message: 'Use ESLint & Prettier formatting' },
|
|
293
|
-
},
|
|
294
|
-
] as const);
|
|
295
|
-
|
|
296
|
-
const { isEslintPrettier, isTypescript, ...restResponse } =
|
|
297
|
-
await prompter.prompt();
|
|
298
|
-
|
|
299
|
-
this.configureProject({
|
|
300
|
-
...restResponse,
|
|
301
|
-
});
|
|
302
|
-
|
|
303
|
-
this.isTypescript = isTypescript;
|
|
304
|
-
this.isEslintPrettier = isEslintPrettier;
|
|
305
|
-
}
|
|
306
|
-
}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { Resource } from '../../../lib/project';
|
|
2
|
-
|
|
3
|
-
const content = `
|
|
4
|
-
root = true
|
|
5
|
-
|
|
6
|
-
[*]
|
|
7
|
-
indent_style = space
|
|
8
|
-
indent_size = 4
|
|
9
|
-
end_of_line = lf
|
|
10
|
-
charset = utf-8
|
|
11
|
-
trim_trailing_whitespace = true
|
|
12
|
-
insert_final_newline = true
|
|
13
|
-
|
|
14
|
-
[*.yml]
|
|
15
|
-
indent_style = space
|
|
16
|
-
indent_size = 2
|
|
17
|
-
`;
|
|
18
|
-
|
|
19
|
-
export const getEditorConfigContent = (): Resource => {
|
|
20
|
-
return {
|
|
21
|
-
filename: '.editorconfig',
|
|
22
|
-
content,
|
|
23
|
-
};
|
|
24
|
-
};
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
import { NodejsProject, Resource } from '../../../lib/project';
|
|
2
|
-
|
|
3
|
-
const eslintTsContent = `
|
|
4
|
-
import js from "@eslint/js";
|
|
5
|
-
import globals from "globals";
|
|
6
|
-
import tseslint from "typescript-eslint";
|
|
7
|
-
import eslintPluginTs from '@typescript-eslint/eslint-plugin';
|
|
8
|
-
import { defineConfig } from "eslint/config";
|
|
9
|
-
|
|
10
|
-
export default defineConfig([
|
|
11
|
-
{ files: ["**/*.{js,mjs,cjs,ts}"], plugins: { js }, extends: ["js/recommended"] },
|
|
12
|
-
{ files: ["**/*.{js,mjs,cjs,ts}"], languageOptions: { globals: globals.node } },
|
|
13
|
-
tseslint.configs.recommended,
|
|
14
|
-
{
|
|
15
|
-
plugins: {
|
|
16
|
-
'@typescript-eslint': eslintPluginTs,
|
|
17
|
-
},
|
|
18
|
-
rules: {
|
|
19
|
-
"@typescript-eslint/no-namespace": "off",
|
|
20
|
-
"@typescript-eslint/no-empty-interface": "off",
|
|
21
|
-
"@typescript-eslint/no-empty-object-type": "off",
|
|
22
|
-
"@typescript-eslint/no-unused-expressions": "off"
|
|
23
|
-
}
|
|
24
|
-
},
|
|
25
|
-
{ ignores: ["node_modules/*", "dist/*"] },
|
|
26
|
-
]);
|
|
27
|
-
`;
|
|
28
|
-
|
|
29
|
-
const eslintJsContent = `
|
|
30
|
-
import js from "@eslint/js";
|
|
31
|
-
import globals from "globals";
|
|
32
|
-
import tseslint from "typescript-eslint";
|
|
33
|
-
import eslintPluginTs from '@typescript-eslint/eslint-plugin';
|
|
34
|
-
import { defineConfig } from "eslint/config";
|
|
35
|
-
|
|
36
|
-
export default defineConfig([
|
|
37
|
-
{ files: ["**/*.{js,mjs,cjs,ts}"], plugins: { js }, extends: ["js/recommended"] },
|
|
38
|
-
{ files: ["**/*.{js,mjs,cjs,ts}"], languageOptions: { globals: globals.node } },
|
|
39
|
-
tseslint.configs.recommended,
|
|
40
|
-
{
|
|
41
|
-
plugins: {
|
|
42
|
-
'@typescript-eslint': eslintPluginTs,
|
|
43
|
-
},
|
|
44
|
-
rules: {
|
|
45
|
-
"@typescript-eslint/no-namespace": "off",
|
|
46
|
-
"@typescript-eslint/no-empty-interface": "off",
|
|
47
|
-
"@typescript-eslint/no-empty-object-type": "off",
|
|
48
|
-
"@typescript-eslint/no-unused-expressions": "off"
|
|
49
|
-
}
|
|
50
|
-
},
|
|
51
|
-
{ ignores: ["node_modules/*", "dist/*"] },
|
|
52
|
-
]);
|
|
53
|
-
`;
|
|
54
|
-
|
|
55
|
-
export const getEslintContent = (project: NodejsProject): Resource => {
|
|
56
|
-
const filename = 'eslint.config.mjs';
|
|
57
|
-
|
|
58
|
-
return {
|
|
59
|
-
filename,
|
|
60
|
-
content: project.enabledTypescript ? eslintTsContent : eslintJsContent,
|
|
61
|
-
};
|
|
62
|
-
};
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
import { NodejsProject, Resource } from '../../../lib/project';
|
|
2
|
-
import { PackageManager } from '../../utils/package-manager';
|
|
3
|
-
|
|
4
|
-
export const getPackageJsonContent = (project: NodejsProject): Resource => {
|
|
5
|
-
const { name, author, description, packageManager, version } = project;
|
|
6
|
-
|
|
7
|
-
const ci = `${packageManager} ${packageManager === PackageManager.NPM ? 'ci' : 'install --frozen-lockfile'}`;
|
|
8
|
-
|
|
9
|
-
const prebuildScript = [`${packageManager} run clean`];
|
|
10
|
-
|
|
11
|
-
project.enabledEslintPrettier &&
|
|
12
|
-
prebuildScript.push(
|
|
13
|
-
`${packageManager} run lint`,
|
|
14
|
-
`${packageManager} run format`,
|
|
15
|
-
);
|
|
16
|
-
|
|
17
|
-
const packageJson = {
|
|
18
|
-
name,
|
|
19
|
-
version,
|
|
20
|
-
description,
|
|
21
|
-
author,
|
|
22
|
-
license: 'ISC',
|
|
23
|
-
packageManager: project.getPackageManager(),
|
|
24
|
-
main: project.enabledTypescript ? 'dist/' : 'src/',
|
|
25
|
-
scripts: {
|
|
26
|
-
ci,
|
|
27
|
-
...(project.enabledTypescript
|
|
28
|
-
? {
|
|
29
|
-
clean: 'rimraf dist',
|
|
30
|
-
build: 'tsc',
|
|
31
|
-
dev: 'ts-node src/',
|
|
32
|
-
prebuild: prebuildScript.join(' && '),
|
|
33
|
-
start: 'node dist/',
|
|
34
|
-
...(project.enabledEslintPrettier
|
|
35
|
-
? {
|
|
36
|
-
lint: 'eslint --ext .js,.ts .',
|
|
37
|
-
format: 'prettier --write "**/*.+(js|ts)"',
|
|
38
|
-
}
|
|
39
|
-
: {}),
|
|
40
|
-
}
|
|
41
|
-
: {
|
|
42
|
-
start: 'node src/',
|
|
43
|
-
...(project.enabledEslintPrettier
|
|
44
|
-
? {
|
|
45
|
-
lint: 'eslint --ext .js .',
|
|
46
|
-
format: 'prettier --write "**/*.+(js)"',
|
|
47
|
-
}
|
|
48
|
-
: {}),
|
|
49
|
-
}),
|
|
50
|
-
},
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
return {
|
|
54
|
-
filename: 'package.json',
|
|
55
|
-
content: JSON.stringify(packageJson, null, 4),
|
|
56
|
-
};
|
|
57
|
-
};
|