@devbro/pashmak 0.1.55 → 0.1.56

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 (38) hide show
  1. package/dist/cjs/app/console/index.js +268 -70
  2. package/dist/cjs/app/console/project/CreateProjectCommand.js +263 -65
  3. package/dist/cjs/app/console/project/base_project/src/config/caches.ts.tpl +11 -1
  4. package/dist/cjs/app/console/project/base_project/src/config/databases.ts.tpl +8 -6
  5. package/dist/cjs/app/console/project/base_project/src/config/default.mts.tpl +13 -20
  6. package/dist/cjs/app/console/project/base_project/src/config/loggers.ts.tpl +13 -3
  7. package/dist/cjs/app/console/project/base_project/src/config/storages.ts.tpl +1 -2
  8. package/dist/cjs/app/console/project/base_project/src/initialize.ts.tpl +48 -16
  9. package/dist/cjs/app/console/project/base_project/src/routes.ts.tpl +2 -2
  10. package/dist/cjs/bin/pashmak_cli.js +265 -66
  11. package/dist/cjs/index.js +1785 -1993
  12. package/dist/cjs/middlewares.js +60 -2
  13. package/dist/esm/app/console/project/CreateProjectCommand.d.mts +15 -2
  14. package/dist/esm/app/console/project/CreateProjectCommand.mjs +265 -67
  15. package/dist/esm/app/console/project/CreateProjectCommand.mjs.map +1 -1
  16. package/dist/esm/app/console/project/base_project/src/config/caches.ts.tpl +11 -1
  17. package/dist/esm/app/console/project/base_project/src/config/databases.ts.tpl +8 -6
  18. package/dist/esm/app/console/project/base_project/src/config/default.mts.tpl +13 -20
  19. package/dist/esm/app/console/project/base_project/src/config/loggers.ts.tpl +13 -3
  20. package/dist/esm/app/console/project/base_project/src/config/storages.ts.tpl +1 -2
  21. package/dist/esm/app/console/project/base_project/src/initialize.ts.tpl +48 -16
  22. package/dist/esm/app/console/project/base_project/src/routes.ts.tpl +2 -2
  23. package/dist/esm/bin/pashmak_cli.mjs +2 -1
  24. package/dist/esm/bin/pashmak_cli.mjs.map +1 -1
  25. package/dist/esm/config.mjs.map +1 -1
  26. package/dist/esm/index.d.mts +1 -7
  27. package/dist/esm/index.mjs +1 -32
  28. package/dist/esm/index.mjs.map +1 -1
  29. package/dist/esm/middlewares.d.mts +12 -1
  30. package/dist/esm/middlewares.mjs +52 -0
  31. package/dist/esm/middlewares.mjs.map +1 -1
  32. package/package.json +4 -2
  33. package/dist/cjs/app/console/project/base_project/package.json.tpl +0 -74
  34. package/dist/cjs/app/console/project/base_project/src/config/test.ts.tpl +0 -1
  35. package/dist/esm/app/console/project/base_project/package.json.tpl +0 -74
  36. package/dist/esm/app/console/project/base_project/src/config/test.ts.tpl +0 -1
  37. /package/dist/cjs/app/console/project/base_project/src/config/{mailer.ts.tpl → mailers.ts.tpl} +0 -0
  38. /package/dist/esm/app/console/project/base_project/src/config/{mailer.ts.tpl → mailers.ts.tpl} +0 -0
@@ -46,24 +46,17 @@ var CreateProjectCommand = class extends import_clipanion.Command {
46
46
  category: `Project`,
47
47
  description: `Create a new project`,
48
48
  details: `
49
- This command creates a new project with the specified name at the given path.
50
- If no path is provided, the project will be created in the current directory.
49
+ This command creates a new project interactively.
50
+ You will be prompted for the project path and other configuration options.
51
51
  `,
52
- examples: [
53
- [
54
- `Create a new project in specified directory`,
55
- `create project --path /path/to/my-project --git`
56
- ],
57
- [
58
- `Create a new project at a specific path with git initialized`,
59
- `create project --path /path/to/my-project --git`
60
- ]
61
- ]
62
- });
63
- projectPath = import_clipanion.Option.String("--path", { required: true });
64
- git = import_clipanion.Option.Boolean(`--git`, false, {
65
- description: `Initialize a git repository in the new project`
52
+ examples: [[`Create a new project`, `create project`]]
66
53
  });
54
+ projectPath = "";
55
+ executor = "";
56
+ packageManager = "";
57
+ linter = "";
58
+ validation_library = "";
59
+ database_type = "";
67
60
  async folderExists(folderPath) {
68
61
  try {
69
62
  const stats = await fs.stat(folderPath);
@@ -76,14 +69,148 @@ var CreateProjectCommand = class extends import_clipanion.Command {
76
69
  }
77
70
  }
78
71
  async execute() {
79
- const projectPath = import_path.default.join(this.projectPath);
80
- try {
81
- await fs.access(projectPath);
82
- console.error(`Error: Directory ${projectPath} already exists.`);
83
- return 1;
84
- } catch {
72
+ await this.setupProjectPath();
73
+ await this.setupGit();
74
+ await this.setupExecutorAndPackageManager();
75
+ await this.setupLinter();
76
+ await this.setupGeneralPackages();
77
+ await this.setupBaseProject();
78
+ await this.installPackages();
79
+ }
80
+ async processTplFolder(src, dest, data = {}) {
81
+ const files = await fs.readdir(src, { withFileTypes: true });
82
+ for (const file of files) {
83
+ const srcPath = import_path.default.join(src, file.name);
84
+ const destPath = file.isFile() && file.name.endsWith(".tpl") ? import_path.default.join(dest, file.name.substring(0, file.name.length - 4)) : import_path.default.join(dest, file.name);
85
+ if (file.isDirectory()) {
86
+ await fs.mkdir(destPath, { recursive: true });
87
+ await this.processTplFolder(srcPath, destPath, data);
88
+ } else if (file.name.endsWith(".tpl")) {
89
+ await this.processTplFile(srcPath, destPath, data);
90
+ } else {
91
+ throw new Error(
92
+ "unexpected non tpl file: " + srcPath + " " + file.name
93
+ );
94
+ }
95
+ }
96
+ }
97
+ async processTplFile(src, dest, data = {}) {
98
+ import_handlebars.default.registerHelper("eq", (a, b) => a === b);
99
+ const compiledTemplate = import_handlebars.default.compile(
100
+ (await fs.readFile(src)).toString()
101
+ );
102
+ const template = await compiledTemplate(data);
103
+ await fs.writeFile(dest, template);
104
+ }
105
+ async setupProjectPath() {
106
+ const pathInput = await (0, import_prompts.input)({
107
+ message: "Enter project path (leave empty to use current directory):",
108
+ default: ""
109
+ });
110
+ this.projectPath = pathInput.trim() ? import_path.default.resolve(pathInput.trim()) : process.cwd();
111
+ await fs.mkdir(this.projectPath, { recursive: true });
112
+ const files = await fs.readdir(this.projectPath);
113
+ if (files.length > 0) {
114
+ throw new Error(
115
+ `Directory ${this.projectPath} is not empty. Please use an empty directory.`
116
+ );
117
+ }
118
+ }
119
+ async setupExecutorAndPackageManager() {
120
+ this.executor = await (0, import_prompts.select)({
121
+ message: "Select a TypeScript executor",
122
+ choices: [
123
+ {
124
+ name: "Bun",
125
+ value: "bun",
126
+ description: "Fast all-in-one JavaScript runtime"
127
+ },
128
+ {
129
+ name: "TSX",
130
+ value: "tsx",
131
+ description: "TypeScript execute (tsx) - Node.js enhanced with esbuild"
132
+ }
133
+ ]
134
+ });
135
+ this.packageManager = this.executor === "bun" ? "bun" : await (0, import_prompts.select)({
136
+ message: "Select a package manager",
137
+ choices: [
138
+ {
139
+ name: "Yarn",
140
+ value: "yarn",
141
+ description: "Fast, reliable, and secure dependency management"
142
+ },
143
+ {
144
+ name: "npm",
145
+ value: "npm",
146
+ description: "Node package manager (default)"
147
+ },
148
+ {
149
+ name: "Bun",
150
+ value: "bun",
151
+ description: "Ultra-fast package manager built into Bun"
152
+ }
153
+ ],
154
+ default: "yarn"
155
+ });
156
+ (0, import_child_process.execSync)(`${this.packageManager} init -y`, {
157
+ stdio: "inherit",
158
+ cwd: this.projectPath
159
+ });
160
+ const packageJsonPath = import_path.default.join(this.projectPath, `package.json`);
161
+ let packageJson = JSON.parse(await fs.readFile(packageJsonPath, `utf-8`));
162
+ packageJson.type = "module";
163
+ packageJson.scripts = packageJson.scripts || {};
164
+ packageJson.scripts.prepare = "husky init";
165
+ packageJson.scripts.clean = "rm -rf dist";
166
+ if (this.executor === "bun") {
167
+ packageJson.scripts.dev = "bun run dev";
168
+ packageJson.scripts.start = "bun run pdev";
169
+ packageJson.scripts.build = "bun run build";
170
+ packageJson.scripts.test = "vitest";
171
+ packageJson.scripts["test:watch"] = "vitest --watch";
172
+ packageJson.scripts["test:coverage"] = "vitest run --coverage";
173
+ } else if (this.executor === "tsx") {
174
+ packageJson.scripts.dev = "tsx --watch -r tsconfig-paths/register src/index.ts start --all | npx pino-pretty";
175
+ packageJson.scripts.start = "tsx dist/index.js";
176
+ packageJson.scripts.build = "tsc";
177
+ packageJson.scripts.test = "vitest";
178
+ packageJson.scripts["test:watch"] = "vitest --watch";
179
+ packageJson.scripts["test:coverage"] = "vitest run --coverage";
180
+ }
181
+ await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
182
+ }
183
+ async setupLinter() {
184
+ this.linter = await (0, import_prompts.select)({
185
+ message: "Select a linter",
186
+ choices: [
187
+ {
188
+ name: "Biome",
189
+ value: "biome",
190
+ description: "Fast formatter and linter for JavaScript, TypeScript, and more"
191
+ },
192
+ {
193
+ name: "ESLint",
194
+ value: "eslint",
195
+ description: "Find and fix problems in your JavaScript code"
196
+ }
197
+ ]
198
+ });
199
+ const packageJsonPath = import_path.default.join(this.projectPath, `package.json`);
200
+ let packageJson = JSON.parse(await fs.readFile(packageJsonPath, `utf-8`));
201
+ if (this.linter === "biome") {
202
+ packageJson.scripts.lint = "biome check . --ext .ts,.tsx";
203
+ packageJson.scripts.format = "biome format . --ext .ts,.tsx --write";
204
+ this.addPackage("@biomejs/biome", true);
205
+ } else if (this.linter === "eslint") {
206
+ packageJson.scripts.lint = "eslint . --ext .ts,.tsx";
207
+ packageJson.scripts.format = "eslint . --ext .ts,.tsx --fix";
208
+ this.addPackage("eslint", true);
85
209
  }
86
- const validation_library = await (0, import_prompts.select)({
210
+ await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
211
+ }
212
+ async setupGeneralPackages() {
213
+ this.validation_library = await (0, import_prompts.select)({
87
214
  message: "Select a package you want for validation",
88
215
  choices: [
89
216
  {
@@ -104,8 +231,42 @@ var CreateProjectCommand = class extends import_clipanion.Command {
104
231
  }
105
232
  ]
106
233
  });
107
- await fs.mkdir(projectPath, { recursive: true });
108
- console.log(`Created project directory at: ${projectPath}`);
234
+ this.validation_library === "none" || await this.addPackage(this.validation_library);
235
+ this.database_type = await (0, import_prompts.select)({
236
+ message: "Select a database type (you can add more databases later)",
237
+ choices: [
238
+ {
239
+ name: "PostgreSQL",
240
+ value: "postgresql",
241
+ description: "A powerful, open source object-relational database system"
242
+ },
243
+ {
244
+ name: "MySQL",
245
+ value: "mysql",
246
+ description: "The world's most popular open source database"
247
+ },
248
+ {
249
+ name: "SQLite",
250
+ value: "sqlite",
251
+ description: "A C library that provides a lightweight disk-based database"
252
+ }
253
+ ]
254
+ });
255
+ if (this.database_type === "postgresql") {
256
+ await this.addPackage("pg pg-cursor");
257
+ } else if (this.database_type === "mysql") {
258
+ await this.addPackage("mysql2");
259
+ } else if (this.database_type === "sqlite") {
260
+ await this.addPackage("sqlite3");
261
+ }
262
+ await this.addPackage("@devbro/pashmak tsconfig-paths dotenv ");
263
+ await this.addPackage(
264
+ "husky vitest supertest @types/supertest pino-pretty typescript tsx",
265
+ true
266
+ );
267
+ }
268
+ async setupBaseProject() {
269
+ console.log(`Using project directory: ${this.projectPath}`);
109
270
  const dirname = typeof __dirname === "undefined" ? import_path.default.dirname((0, import_url.fileURLToPath)(import_meta.url)) : __dirname;
110
271
  let basePath = import_path.default.join(dirname, `./base_project`);
111
272
  if (await this.folderExists(basePath) === false) {
@@ -113,53 +274,90 @@ var CreateProjectCommand = class extends import_clipanion.Command {
113
274
  }
114
275
  console.log(`Using base project path: ${basePath}`);
115
276
  const baseProjectPath = basePath;
116
- await this.processTplFolder(baseProjectPath, projectPath, {
117
- validation_library
277
+ await this.processTplFolder(baseProjectPath, this.projectPath, {
278
+ validation_library: this.validation_library,
279
+ executor: this.executor,
280
+ package_manager: this.packageManager,
281
+ linter: this.linter,
282
+ database_type: this.database_type
118
283
  });
119
- console.log(`Copied base project files to: ${projectPath}`);
120
- const packageJsonPath = import_path.default.join(projectPath, `package.json`);
121
- const packageJson = JSON.parse(await fs.readFile(packageJsonPath, `utf-8`));
122
- packageJson.name = import_change_case_all.Case.snake(import_path.default.basename(projectPath));
284
+ console.log(`Copied base project files to: ${this.projectPath}`);
285
+ const packageJsonPath = import_path.default.join(this.projectPath, "package.json");
286
+ let packageJson = JSON.parse(await fs.readFile(packageJsonPath, `utf-8`));
287
+ packageJson.name = import_change_case_all.Case.snake(import_path.default.basename(this.projectPath));
123
288
  await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
124
289
  console.log(`Updated package.json with project name: ${packageJson.name}`);
125
- if (this.git) {
126
- try {
127
- (0, import_child_process.execSync)(
128
- 'git init; git add --all; git commit --allow-empty -m "chore: first commit for pashmak"',
129
- {
130
- cwd: projectPath
131
- }
132
- );
133
- } catch (error) {
134
- console.error(`Failed to create project.`, error);
135
- return 1;
136
- }
290
+ }
291
+ async addPackage(packageName, dev = false) {
292
+ let install_command = "";
293
+ switch (this.packageManager) {
294
+ case "bun":
295
+ install_command = `bun add ${packageName}${dev ? " -d" : ""}`;
296
+ break;
297
+ case "yarn":
298
+ install_command = `yarn add ${packageName}${dev ? " -D" : ""} --no-install`;
299
+ break;
300
+ case "npm":
301
+ install_command = `npm install ${packageName}${dev ? " --save-dev" : ""} --package-lock-only`;
302
+ break;
137
303
  }
304
+ (0, import_child_process.execSync)(install_command, {
305
+ stdio: "inherit",
306
+ cwd: this.projectPath
307
+ });
138
308
  }
139
- async processTplFolder(src, dest, data = {}) {
140
- const files = await fs.readdir(src, { withFileTypes: true });
141
- for (const file of files) {
142
- const srcPath = import_path.default.join(src, file.name);
143
- const destPath = file.isFile() && file.name.endsWith(".tpl") ? import_path.default.join(dest, file.name.substring(0, file.name.length - 4)) : import_path.default.join(dest, file.name);
144
- if (file.isDirectory()) {
145
- await fs.mkdir(destPath, { recursive: true });
146
- await this.processTplFolder(srcPath, destPath, data);
147
- } else if (file.name.endsWith(".tpl")) {
148
- await this.processTplFile(srcPath, destPath, data);
149
- } else {
150
- throw new Error(
151
- "unexpected non tpl file: " + srcPath + " " + file.name
152
- );
153
- }
309
+ async installPackages() {
310
+ const install_command = this.packageManager === "bun" ? `bun install` : this.packageManager === "yarn" ? `yarn` : `npm install`;
311
+ (0, import_child_process.execSync)(install_command, {
312
+ stdio: "inherit",
313
+ cwd: this.projectPath
314
+ });
315
+ }
316
+ async setupGit() {
317
+ const initGit = await (0, import_prompts.select)({
318
+ message: "Initialize a git repository?",
319
+ choices: [
320
+ {
321
+ name: "Yes",
322
+ value: true,
323
+ description: "Initialize git and create first commit"
324
+ },
325
+ {
326
+ name: "No",
327
+ value: false,
328
+ description: "Skip git initialization"
329
+ }
330
+ ]
331
+ });
332
+ if (initGit) {
333
+ const gitignoreContent = [
334
+ "node_modules/",
335
+ "dist/",
336
+ ".env",
337
+ ".env.*",
338
+ "!.env.example",
339
+ "*.log",
340
+ "coverage/",
341
+ ".DS_Store"
342
+ ].join("\n") + "\n";
343
+ await fs.writeFile(
344
+ import_path.default.join(this.projectPath, ".gitignore"),
345
+ gitignoreContent
346
+ );
347
+ (0, import_child_process.execSync)(
348
+ `git init; git add --all; git commit --allow-empty -m "chore: first commit"`,
349
+ {
350
+ cwd: this.projectPath
351
+ }
352
+ );
154
353
  }
155
354
  }
156
- async processTplFile(src, dest, data = {}) {
157
- import_handlebars.default.registerHelper("eq", (a, b) => a === b);
158
- const compiledTemplate = import_handlebars.default.compile(
159
- (await fs.readFile(src)).toString()
160
- );
161
- const template = await compiledTemplate(data);
162
- await fs.writeFile(dest, template);
355
+ async catch(error) {
356
+ if (Error.isError(error)) {
357
+ console.error(error.message);
358
+ } else {
359
+ console.error(error);
360
+ }
163
361
  }
164
362
  };
165
363
 
@@ -173,5 +371,6 @@ var cli = new import_clipanion2.Cli({
173
371
  cli.register(CreateProjectCommand);
174
372
  cli.runExit(args).then(() => {
175
373
  }).catch((err) => {
176
- console.error(err);
374
+ console.error("Fatal error:", err.message);
375
+ process.exit(1);
177
376
  });