@devbro/pashmak 0.1.54 → 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.
- package/README.md +2 -2
- package/dist/cjs/app/console/index.js +268 -70
- package/dist/cjs/app/console/project/CreateProjectCommand.js +263 -65
- package/dist/cjs/app/console/project/base_project/src/config/caches.ts.tpl +11 -1
- package/dist/cjs/app/console/project/base_project/src/config/databases.ts.tpl +8 -6
- package/dist/cjs/app/console/project/base_project/src/config/default.mts.tpl +13 -20
- package/dist/cjs/app/console/project/base_project/src/config/loggers.ts.tpl +13 -3
- package/dist/cjs/app/console/project/base_project/src/config/storages.ts.tpl +1 -2
- package/dist/cjs/app/console/project/base_project/src/initialize.ts.tpl +48 -16
- package/dist/cjs/app/console/project/base_project/src/routes.ts.tpl +2 -2
- package/dist/cjs/bin/pashmak_cli.js +265 -66
- package/dist/cjs/index.js +1785 -1993
- package/dist/cjs/middlewares.js +60 -2
- package/dist/esm/app/console/project/CreateProjectCommand.d.mts +15 -2
- package/dist/esm/app/console/project/CreateProjectCommand.mjs +265 -67
- package/dist/esm/app/console/project/CreateProjectCommand.mjs.map +1 -1
- package/dist/esm/app/console/project/base_project/src/config/caches.ts.tpl +11 -1
- package/dist/esm/app/console/project/base_project/src/config/databases.ts.tpl +8 -6
- package/dist/esm/app/console/project/base_project/src/config/default.mts.tpl +13 -20
- package/dist/esm/app/console/project/base_project/src/config/loggers.ts.tpl +13 -3
- package/dist/esm/app/console/project/base_project/src/config/storages.ts.tpl +1 -2
- package/dist/esm/app/console/project/base_project/src/initialize.ts.tpl +48 -16
- package/dist/esm/app/console/project/base_project/src/routes.ts.tpl +2 -2
- package/dist/esm/bin/pashmak_cli.mjs +2 -1
- package/dist/esm/bin/pashmak_cli.mjs.map +1 -1
- package/dist/esm/config.mjs.map +1 -1
- package/dist/esm/facades.mjs.map +1 -1
- package/dist/esm/index.d.mts +1 -7
- package/dist/esm/index.mjs +1 -32
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/middlewares.d.mts +12 -1
- package/dist/esm/middlewares.mjs +52 -0
- package/dist/esm/middlewares.mjs.map +1 -1
- package/package.json +6 -4
- package/dist/cjs/app/console/project/base_project/package.json.tpl +0 -74
- package/dist/cjs/app/console/project/base_project/src/config/test.ts.tpl +0 -1
- package/dist/esm/app/console/project/base_project/package.json.tpl +0 -74
- package/dist/esm/app/console/project/base_project/src/config/test.ts.tpl +0 -1
- /package/dist/cjs/app/console/project/base_project/src/config/{mailer.ts.tpl → mailers.ts.tpl} +0 -0
- /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
|
|
50
|
-
|
|
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
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
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
|
-
|
|
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
|
-
|
|
108
|
-
|
|
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,
|
|
121
|
-
|
|
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
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
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
|
|
140
|
-
const
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
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
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
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
|
});
|