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.
Files changed (51) hide show
  1. package/dist/cli.js +13583 -993
  2. package/dist/templates/create-simple-app/package.json.hbs +30 -0
  3. package/dist/templates/create-simple-app/src/index.js.hbs +5 -0
  4. package/dist/templates/create-simple-app/src/index.ts.hbs +5 -0
  5. package/dist/templates/create-simple-app/tsconfig.json.hbs +14 -0
  6. package/package.json +27 -14
  7. package/{src/templates/create-node-app/resource/gitignore.ts → templates/create-simple-app/.gitignore.hbs} +1 -14
  8. package/templates/create-simple-app/.prettierrc.json.hbs +15 -0
  9. package/templates/create-simple-app/eslint.config.mjs.hbs +23 -0
  10. package/templates/create-simple-app/package.json.hbs +30 -0
  11. package/templates/create-simple-app/src/index.js.hbs +5 -0
  12. package/templates/create-simple-app/src/index.ts.hbs +5 -0
  13. package/templates/create-simple-app/tsconfig.json.hbs +14 -0
  14. package/.commitlintrc.json +0 -3
  15. package/.github/workflows/auto-pr-gen.yml +0 -25
  16. package/.github/workflows/enforce-pr-rules.yml +0 -28
  17. package/.github/workflows/npm-publish.yml +0 -17
  18. package/.github/workflows/release-changelog.yml +0 -28
  19. package/.husky/commit-msg +0 -4
  20. package/.husky/pre-push +0 -4
  21. package/.release-please-manifest.json +0 -3
  22. package/CHANGELOG.md +0 -37
  23. package/bin/cli.ts +0 -21
  24. package/esbuild.config.ts +0 -17
  25. package/prettier.config.mjs +0 -20
  26. package/release-please-config.json +0 -15
  27. package/src/config/cli-config.ts +0 -25
  28. package/src/lib/file.ts +0 -159
  29. package/src/lib/project.ts +0 -211
  30. package/src/lib/prompter.ts +0 -201
  31. package/src/lib/task.ts +0 -41
  32. package/src/templates/create-node-app/index.ts +0 -306
  33. package/src/templates/create-node-app/resource/editor-config.ts +0 -24
  34. package/src/templates/create-node-app/resource/eslint.ts +0 -62
  35. package/src/templates/create-node-app/resource/package-json.ts +0 -57
  36. package/src/templates/create-node-app/resource/prettier.ts +0 -45
  37. package/src/templates/create-node-app/resource/project-deps.ts +0 -30
  38. package/src/templates/create-node-app/resource/project-files.ts +0 -17
  39. package/src/templates/create-node-app/resource/tsconfig.ts +0 -20
  40. package/src/templates/index.ts +0 -1
  41. package/src/templates/utils/badges.ts +0 -13
  42. package/src/templates/utils/git.ts +0 -64
  43. package/src/templates/utils/package-manager.ts +0 -78
  44. package/src/templates/utils/readme.ts +0 -115
  45. package/src/utils/exec-cmd.ts +0 -80
  46. package/src/utils/index.ts +0 -60
  47. package/src/utils/logger.ts +0 -24
  48. package/tsconfig.json +0 -17
  49. /package/{eslint.config.mjs → dist/templates/create-simple-app/eslint.config.mjs.hbs} +0 -0
  50. /package/{.editorconfig → templates/create-simple-app/.editorconfig.hbs} +0 -0
  51. /package/{.prettierignore → templates/create-simple-app/.prettierignore.hbs} +0 -0
@@ -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
- };
@@ -1,45 +0,0 @@
1
- import { Resource } from '../../../lib/project';
2
-
3
- const prettierignore = `
4
- .gitignore
5
- .editorconfig
6
- *.json
7
-
8
- node_modules/
9
-
10
- # build or bundles
11
- build/
12
-
13
- # Ignore built js files
14
- dist/
15
- `;
16
-
17
- export const getPrettierrcContent = (): Resource => {
18
- const prettierrcJson = {
19
- printWidth: 80,
20
- tabWidth: 4,
21
- useTabs: false,
22
- semi: true,
23
- singleQuote: true,
24
- quoteProps: 'as-needed',
25
- trailingComma: 'all',
26
- arrowParens: 'always',
27
- parser: 'typescript',
28
- proseWrap: 'always',
29
- endOfLine: 'auto',
30
- embeddedLanguageFormatting: 'auto',
31
- singleAttributePerLine: true,
32
- };
33
-
34
- return {
35
- filename: '.prettierrc.json',
36
- content: JSON.stringify(prettierrcJson, null, 4),
37
- };
38
- };
39
-
40
- export const getPrettierIgnoreContent = (): Resource => {
41
- return {
42
- filename: '.prettierignore',
43
- content: prettierignore,
44
- };
45
- };
@@ -1,30 +0,0 @@
1
- import { NodejsProject, ProjectDependency } from '../../../lib/project';
2
-
3
- export const getProjectDeps = (project: NodejsProject): ProjectDependency => {
4
- const { enabledEslintPrettier, enabledTypescript } = project;
5
-
6
- const esLintPrettierDeps = enabledEslintPrettier
7
- ? [
8
- '@eslint/js',
9
- 'eslint',
10
- 'globals',
11
- 'prettier',
12
- ...(enabledTypescript
13
- ? [
14
- '@typescript-eslint/eslint-plugin',
15
- '@typescript-eslint/parser',
16
- 'typescript-eslint',
17
- ]
18
- : []),
19
- ]
20
- : [];
21
-
22
- const tsDeps = enabledTypescript
23
- ? ['@types/node', 'ts-node', 'typescript', 'rimraf']
24
- : [];
25
-
26
- return {
27
- dependencies: [],
28
- devDependencies: [...esLintPrettierDeps, ...tsDeps],
29
- };
30
- };
@@ -1,17 +0,0 @@
1
- import { NodejsProject, Resource } from '../../../lib/project';
2
-
3
- export const srcFileContent = (project: NodejsProject): Resource => {
4
- const filename = `src/index.${project.enabledTypescript ? 'ts' : 'js'}`;
5
- const content = `
6
- async function main() {
7
- console.log('Hello from ${project.name}');
8
- }
9
-
10
- main().catch((error) => console.error(error));
11
- `;
12
-
13
- return {
14
- filename,
15
- content,
16
- };
17
- };
@@ -1,20 +0,0 @@
1
- import { Resource } from '../../../lib/project';
2
-
3
- export const getTsConfigContent = (): Resource => {
4
- const tsconfigJson = {
5
- compilerOptions: {
6
- target: 'ES2024',
7
- module: 'commonjs',
8
- outDir: './dist',
9
- esModuleInterop: true,
10
- forceConsistentCasingInFileNames: true,
11
- strict: true,
12
- skipLibCheck: true,
13
- },
14
- include: ['src'],
15
- };
16
- return {
17
- filename: 'tsconfig.json',
18
- content: JSON.stringify(tsconfigJson, null, 4),
19
- };
20
- };
@@ -1 +0,0 @@
1
- export { CreateNodeApp } from './create-node-app';
@@ -1,13 +0,0 @@
1
- export const Badge: Record<string, string> = {
2
- TYPESCRIPT:
3
- 'https://img.shields.io/badge/typescript-%23007ACC.svg?style=for-the-badge&logo=typescript&logoColor=white',
4
- JAVASCRIPT:
5
- 'https://img.shields.io/badge/javascript-%23323330.svg?style=for-the-badge&logo=javascript&logoColor=%23F7DF1E',
6
- NODEJS: 'https://img.shields.io/badge/node.js-6DA55F?style=for-the-badge&logo=node.js&logoColor=white',
7
- YARN: 'https://img.shields.io/badge/yarn-%232C8EBB.svg?style=for-the-badge&logo=yarn&logoColor=white',
8
- NPM: 'https://img.shields.io/badge/NPM-%23CB3837.svg?style=for-the-badge&logo=npm&logoColor=white',
9
- PNPM: 'https://img.shields.io/badge/pnpm-%234a4a4a.svg?style=for-the-badge&logo=pnpm&logoColor=f69220',
10
- ESLINT: 'https://img.shields.io/badge/ESLint-4B3263?style=for-the-badge&logo=eslint&logoColor=white',
11
- PRETTIER:
12
- 'https://img.shields.io/badge/prettier-%23F7B93E.svg?style=for-the-badge&logo=prettier&logoColor=black',
13
- };
@@ -1,64 +0,0 @@
1
- import { ExecaError } from 'execa';
2
- import { execCmd, ExecCmdError } from '../../utils/exec-cmd';
3
- import { logger } from '../../utils/logger';
4
-
5
- import type {} from '../../utils';
6
-
7
- export type GitOptions = {
8
- global: boolean;
9
- };
10
-
11
- const defaultGitOptions: GitOptions = {
12
- global: false,
13
- };
14
-
15
- export const getGitVersion = async (): Promise<string | undefined> => {
16
- try {
17
- const { stdout: gitVersion = '' } =
18
- (await execCmd('git --version')) ?? {};
19
- return gitVersion.match(/(?=(\d+.\d+.\d+))/)?.[1];
20
- } catch (error) {
21
- const { code, message } = error as ExecCmdError;
22
-
23
- if (code === 'ENOENT') return undefined;
24
-
25
- logger.err(
26
- `Error while checking if git exists, Code: ${code} | Message: ${message}`,
27
- );
28
-
29
- throw new Error(
30
- `${getGitVersion.name} error, Code: ${code} | Message: ${message}`,
31
- );
32
- }
33
- };
34
-
35
- export const getGitConfiguration = async (
36
- options: GitOptions = { ...defaultGitOptions },
37
- ): Promise<Record<string, string | undefined> | undefined> => {
38
- const { global } = options;
39
-
40
- try {
41
- const { stdout: gitConfigResult = '' } =
42
- (await execCmd(`git config -l ${global ? '--global' : ''}`)) ?? {};
43
-
44
- if (!gitConfigResult.length) return undefined;
45
-
46
- const gitConfig = Object.fromEntries(
47
- gitConfigResult.split('\n').map((config) => config.split('=')),
48
- );
49
-
50
- return gitConfig;
51
- } catch (error) {
52
- const { code, message } = error as ExecaError;
53
-
54
- logger.err(
55
- `Error while getting ${global ? 'global' : 'local'} git config, Code: ${code} | Message: ${message}`,
56
- );
57
-
58
- if (code === 'ENOENT') throw new Error('git does not exists');
59
-
60
- throw new Error(
61
- `${getGitConfiguration.name} error, Code: ${code} | Message: ${message}`,
62
- );
63
- }
64
- };