@devbro/pashmak 0.1.55 → 0.1.57
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/cjs/app/console/DefaultCommand.js +52 -0
- package/dist/cjs/app/console/KeyGenerateCommand.js +52 -0
- package/dist/cjs/app/console/StartCommand.js +52 -0
- package/dist/cjs/app/console/generate/GenerateApiDocsCommand.js +52 -0
- package/dist/cjs/app/console/generate/GenerateControllerCommand.js +52 -0
- package/dist/cjs/app/console/generate/index.js +52 -0
- package/dist/cjs/app/console/index.js +320 -70
- package/dist/cjs/app/console/migrate/GenerateMigrateCommand.js +52 -0
- package/dist/cjs/app/console/migrate/MigrateCommand.js +52 -0
- package/dist/cjs/app/console/migrate/MigrateRollbackCommand.js +52 -0
- package/dist/cjs/app/console/migrate/index.js +52 -0
- 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/app/console/queue/GenerateQueueMigrateCommand.js +52 -0
- package/dist/cjs/bin/pashmak_cli.js +265 -66
- package/dist/cjs/cache/MultiCache.js +71 -0
- package/dist/cjs/{cache.js → cache/cache.js} +54 -2
- package/dist/cjs/facades.js +52 -0
- package/dist/cjs/factories.js +52 -0
- package/dist/cjs/http.js +52 -0
- package/dist/cjs/index.js +1900 -2056
- package/dist/cjs/middlewares.js +112 -2
- package/dist/cjs/queue.js +52 -0
- 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/cache/MultiCache.d.mts +14 -0
- package/dist/esm/cache/MultiCache.mjs +47 -0
- package/dist/esm/cache/MultiCache.mjs.map +1 -0
- package/dist/esm/{cache.mjs → cache/cache.mjs} +1 -1
- package/dist/esm/cache/cache.mjs.map +1 -0
- package/dist/esm/config.mjs.map +1 -1
- package/dist/esm/factories.mjs +9 -0
- package/dist/esm/factories.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 +4 -2
- 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/esm/cache.mjs.map +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
- /package/dist/esm/{cache.d.mts → cache/cache.d.mts} +0 -0
package/dist/cjs/middlewares.js
CHANGED
|
@@ -32,6 +32,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
32
32
|
// src/middlewares.mts
|
|
33
33
|
var middlewares_exports = {};
|
|
34
34
|
__export(middlewares_exports, {
|
|
35
|
+
DatabaseProviderMiddleware: () => DatabaseProviderMiddleware,
|
|
35
36
|
RateLimiterMiddleware: () => RateLimiterMiddleware,
|
|
36
37
|
cors: () => cors,
|
|
37
38
|
dbTransaction: () => dbTransaction
|
|
@@ -555,8 +556,8 @@ var DatabaseTransport = class {
|
|
|
555
556
|
}
|
|
556
557
|
});
|
|
557
558
|
}, "processMessage");
|
|
558
|
-
constructor(
|
|
559
|
-
this.config = { ...this.config, ...
|
|
559
|
+
constructor(config3 = {}) {
|
|
560
|
+
this.config = { ...this.config, ...config3 };
|
|
560
561
|
this.repeater = (0, import_neko_helper2.createRepeater)(
|
|
561
562
|
this.processMessage,
|
|
562
563
|
this.config.listen_interval * 1e3
|
|
@@ -594,6 +595,51 @@ var DatabaseTransport = class {
|
|
|
594
595
|
// src/factories.mts
|
|
595
596
|
var import_neko_cache = require("@devbro/neko-cache");
|
|
596
597
|
var import_neko_storage = require("@devbro/neko-storage");
|
|
598
|
+
|
|
599
|
+
// src/cache/MultiCache.mts
|
|
600
|
+
var MultiCache = class {
|
|
601
|
+
constructor(caches) {
|
|
602
|
+
this.caches = caches;
|
|
603
|
+
}
|
|
604
|
+
static {
|
|
605
|
+
__name(this, "MultiCache");
|
|
606
|
+
}
|
|
607
|
+
async get(key) {
|
|
608
|
+
for (const cache2 of this.caches) {
|
|
609
|
+
const value = await cache2.get(key);
|
|
610
|
+
if (value !== void 0) {
|
|
611
|
+
return value;
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
return void 0;
|
|
615
|
+
}
|
|
616
|
+
async put(key, value, ttl) {
|
|
617
|
+
await Promise.all(this.caches.map((cache2) => cache2.put(key, value, ttl)));
|
|
618
|
+
}
|
|
619
|
+
async delete(key) {
|
|
620
|
+
await Promise.all(this.caches.map((cache2) => cache2.delete(key)));
|
|
621
|
+
}
|
|
622
|
+
async has(key) {
|
|
623
|
+
for (const cache2 of this.caches) {
|
|
624
|
+
if (await cache2.has(key)) {
|
|
625
|
+
return true;
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
return false;
|
|
629
|
+
}
|
|
630
|
+
async increment(key, amount) {
|
|
631
|
+
let rc = void 0;
|
|
632
|
+
for (const cache2 of this.caches) {
|
|
633
|
+
let rc2 = await cache2.increment(key, amount);
|
|
634
|
+
if (rc === void 0) {
|
|
635
|
+
rc = rc2;
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
return rc;
|
|
639
|
+
}
|
|
640
|
+
};
|
|
641
|
+
|
|
642
|
+
// src/factories.mts
|
|
597
643
|
var FlexibleFactory = class {
|
|
598
644
|
static {
|
|
599
645
|
__name(this, "FlexibleFactory");
|
|
@@ -664,6 +710,13 @@ CacheProviderFactory.register("redis", (opt) => {
|
|
|
664
710
|
CacheProviderFactory.register("file", (opt) => {
|
|
665
711
|
return new import_neko_cache.FileCacheProvider(opt);
|
|
666
712
|
});
|
|
713
|
+
CacheProviderFactory.register("multi", (opt) => {
|
|
714
|
+
const caches = [];
|
|
715
|
+
for (const c of opt.caches) {
|
|
716
|
+
caches.push(cache(c));
|
|
717
|
+
}
|
|
718
|
+
return new MultiCache(caches);
|
|
719
|
+
});
|
|
667
720
|
CacheProviderFactory.register("disabled", (opt) => {
|
|
668
721
|
return new import_neko_cache.DisabledCacheProvider();
|
|
669
722
|
});
|
|
@@ -806,6 +859,14 @@ var cache = wrapSingletonWithAccessors(
|
|
|
806
859
|
|
|
807
860
|
// src/middlewares.mts
|
|
808
861
|
var import_neko_http2 = require("@devbro/neko-http");
|
|
862
|
+
var import_neko_config2 = require("@devbro/neko-config");
|
|
863
|
+
|
|
864
|
+
// src/context.mts
|
|
865
|
+
var context_exports = {};
|
|
866
|
+
__reExport(context_exports, require("@devbro/neko-context"));
|
|
867
|
+
|
|
868
|
+
// src/middlewares.mts
|
|
869
|
+
var import_neko_sql = require("@devbro/neko-sql");
|
|
809
870
|
function cors(options = {}) {
|
|
810
871
|
return async (req, res, next) => {
|
|
811
872
|
const allowedOrigins = options.allowedOrigins || ["*"];
|
|
@@ -894,8 +955,57 @@ var RateLimiterMiddleware = class _RateLimiterMiddleware extends Middleware {
|
|
|
894
955
|
return;
|
|
895
956
|
}
|
|
896
957
|
};
|
|
958
|
+
var DatabaseProviderMiddleware = class _DatabaseProviderMiddleware extends Middleware {
|
|
959
|
+
static {
|
|
960
|
+
__name(this, "DatabaseProviderMiddleware");
|
|
961
|
+
}
|
|
962
|
+
async call(req, res, next) {
|
|
963
|
+
const db_configs = import_neko_config2.config.get("databases");
|
|
964
|
+
const conns = [];
|
|
965
|
+
try {
|
|
966
|
+
for (const [name, db_config] of Object.entries(db_configs)) {
|
|
967
|
+
if ((0, context_exports.ctx)().get(["database", name])) {
|
|
968
|
+
return;
|
|
969
|
+
}
|
|
970
|
+
const conn = await this.getConnection(db_config);
|
|
971
|
+
(0, context_exports.ctx)().set(["database", name], conn);
|
|
972
|
+
conns.push(conn);
|
|
973
|
+
}
|
|
974
|
+
await next();
|
|
975
|
+
} finally {
|
|
976
|
+
for (const conn of conns) {
|
|
977
|
+
await conn.disconnect();
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
static instance;
|
|
982
|
+
async register() {
|
|
983
|
+
}
|
|
984
|
+
static getInstance() {
|
|
985
|
+
if (!_DatabaseProviderMiddleware.instance) {
|
|
986
|
+
_DatabaseProviderMiddleware.instance = new _DatabaseProviderMiddleware();
|
|
987
|
+
}
|
|
988
|
+
return _DatabaseProviderMiddleware.instance;
|
|
989
|
+
}
|
|
990
|
+
getConnection(db_config) {
|
|
991
|
+
if (db_config.provider === "postgresql") {
|
|
992
|
+
const conn = new import_neko_sql.PostgresqlConnection(db_config.config);
|
|
993
|
+
return conn;
|
|
994
|
+
}
|
|
995
|
+
if (db_config.provider === "sqlite") {
|
|
996
|
+
const conn = new import_neko_sql.SqliteConnection(db_config.config);
|
|
997
|
+
return conn;
|
|
998
|
+
}
|
|
999
|
+
if (db_config.provider === "mysql") {
|
|
1000
|
+
const conn = new import_neko_sql.MysqlConnection(db_config.config);
|
|
1001
|
+
return conn;
|
|
1002
|
+
}
|
|
1003
|
+
throw new Error(`Unsupported database provider: ${db_config.provider}`);
|
|
1004
|
+
}
|
|
1005
|
+
};
|
|
897
1006
|
// Annotate the CommonJS export names for ESM import in node:
|
|
898
1007
|
0 && (module.exports = {
|
|
1008
|
+
DatabaseProviderMiddleware,
|
|
899
1009
|
RateLimiterMiddleware,
|
|
900
1010
|
cors,
|
|
901
1011
|
dbTransaction
|
package/dist/cjs/queue.js
CHANGED
|
@@ -490,6 +490,51 @@ var import_neko_mailer = require("@devbro/neko-mailer");
|
|
|
490
490
|
var import_neko_queue = require("@devbro/neko-queue");
|
|
491
491
|
var import_neko_cache = require("@devbro/neko-cache");
|
|
492
492
|
var import_neko_storage = require("@devbro/neko-storage");
|
|
493
|
+
|
|
494
|
+
// src/cache/MultiCache.mts
|
|
495
|
+
var MultiCache = class {
|
|
496
|
+
constructor(caches) {
|
|
497
|
+
this.caches = caches;
|
|
498
|
+
}
|
|
499
|
+
static {
|
|
500
|
+
__name(this, "MultiCache");
|
|
501
|
+
}
|
|
502
|
+
async get(key) {
|
|
503
|
+
for (const cache2 of this.caches) {
|
|
504
|
+
const value = await cache2.get(key);
|
|
505
|
+
if (value !== void 0) {
|
|
506
|
+
return value;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
return void 0;
|
|
510
|
+
}
|
|
511
|
+
async put(key, value, ttl) {
|
|
512
|
+
await Promise.all(this.caches.map((cache2) => cache2.put(key, value, ttl)));
|
|
513
|
+
}
|
|
514
|
+
async delete(key) {
|
|
515
|
+
await Promise.all(this.caches.map((cache2) => cache2.delete(key)));
|
|
516
|
+
}
|
|
517
|
+
async has(key) {
|
|
518
|
+
for (const cache2 of this.caches) {
|
|
519
|
+
if (await cache2.has(key)) {
|
|
520
|
+
return true;
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
return false;
|
|
524
|
+
}
|
|
525
|
+
async increment(key, amount) {
|
|
526
|
+
let rc = void 0;
|
|
527
|
+
for (const cache2 of this.caches) {
|
|
528
|
+
let rc2 = await cache2.increment(key, amount);
|
|
529
|
+
if (rc === void 0) {
|
|
530
|
+
rc = rc2;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
return rc;
|
|
534
|
+
}
|
|
535
|
+
};
|
|
536
|
+
|
|
537
|
+
// src/factories.mts
|
|
493
538
|
var FlexibleFactory = class {
|
|
494
539
|
static {
|
|
495
540
|
__name(this, "FlexibleFactory");
|
|
@@ -560,6 +605,13 @@ CacheProviderFactory.register("redis", (opt) => {
|
|
|
560
605
|
CacheProviderFactory.register("file", (opt) => {
|
|
561
606
|
return new import_neko_cache.FileCacheProvider(opt);
|
|
562
607
|
});
|
|
608
|
+
CacheProviderFactory.register("multi", (opt) => {
|
|
609
|
+
const caches = [];
|
|
610
|
+
for (const c of opt.caches) {
|
|
611
|
+
caches.push(cache(c));
|
|
612
|
+
}
|
|
613
|
+
return new MultiCache(caches);
|
|
614
|
+
});
|
|
563
615
|
CacheProviderFactory.register("disabled", (opt) => {
|
|
564
616
|
return new import_neko_cache.DisabledCacheProvider();
|
|
565
617
|
});
|
|
@@ -5,11 +5,24 @@ declare class CreateProjectCommand extends Command {
|
|
|
5
5
|
static paths: string[][];
|
|
6
6
|
static usage: clipanion.Usage;
|
|
7
7
|
projectPath: string;
|
|
8
|
-
|
|
8
|
+
executor: string;
|
|
9
|
+
packageManager: string;
|
|
10
|
+
linter: string;
|
|
11
|
+
validation_library: string;
|
|
12
|
+
database_type: string;
|
|
9
13
|
folderExists(folderPath: string): Promise<boolean>;
|
|
10
|
-
execute(): Promise<
|
|
14
|
+
execute(): Promise<void>;
|
|
11
15
|
processTplFolder(src: string, dest: string, data?: any): Promise<void>;
|
|
12
16
|
processTplFile(src: string, dest: string, data?: any): Promise<void>;
|
|
17
|
+
setupProjectPath(): Promise<void>;
|
|
18
|
+
setupExecutorAndPackageManager(): Promise<void>;
|
|
19
|
+
setupLinter(): Promise<void>;
|
|
20
|
+
setupGeneralPackages(): Promise<void>;
|
|
21
|
+
setupBaseProject(): Promise<void>;
|
|
22
|
+
addPackage(packageName: string, dev?: boolean): Promise<void>;
|
|
23
|
+
installPackages(): Promise<void>;
|
|
24
|
+
setupGit(): Promise<void>;
|
|
25
|
+
catch(error: unknown): Promise<void>;
|
|
13
26
|
}
|
|
14
27
|
|
|
15
28
|
export { CreateProjectCommand };
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
var __defProp = Object.defineProperty;
|
|
2
2
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
|
-
import { Command
|
|
3
|
+
import { Command } from "clipanion";
|
|
4
4
|
import { Case } from "change-case-all";
|
|
5
5
|
import path from "path";
|
|
6
6
|
import * as fs from "fs/promises";
|
|
7
7
|
import { fileURLToPath } from "url";
|
|
8
8
|
import handlebars from "handlebars";
|
|
9
9
|
import { execSync } from "child_process";
|
|
10
|
-
import { select, Separator } from "@inquirer/prompts";
|
|
10
|
+
import { select, Separator, input } from "@inquirer/prompts";
|
|
11
11
|
class CreateProjectCommand extends Command {
|
|
12
12
|
static {
|
|
13
13
|
__name(this, "CreateProjectCommand");
|
|
@@ -17,24 +17,17 @@ class CreateProjectCommand extends Command {
|
|
|
17
17
|
category: `Project`,
|
|
18
18
|
description: `Create a new project`,
|
|
19
19
|
details: `
|
|
20
|
-
This command creates a new project
|
|
21
|
-
|
|
20
|
+
This command creates a new project interactively.
|
|
21
|
+
You will be prompted for the project path and other configuration options.
|
|
22
22
|
`,
|
|
23
|
-
examples: [
|
|
24
|
-
[
|
|
25
|
-
`Create a new project in specified directory`,
|
|
26
|
-
`create project --path /path/to/my-project --git`
|
|
27
|
-
],
|
|
28
|
-
[
|
|
29
|
-
`Create a new project at a specific path with git initialized`,
|
|
30
|
-
`create project --path /path/to/my-project --git`
|
|
31
|
-
]
|
|
32
|
-
]
|
|
33
|
-
});
|
|
34
|
-
projectPath = Option.String("--path", { required: true });
|
|
35
|
-
git = Option.Boolean(`--git`, false, {
|
|
36
|
-
description: `Initialize a git repository in the new project`
|
|
23
|
+
examples: [[`Create a new project`, `create project`]]
|
|
37
24
|
});
|
|
25
|
+
projectPath = "";
|
|
26
|
+
executor = "";
|
|
27
|
+
packageManager = "";
|
|
28
|
+
linter = "";
|
|
29
|
+
validation_library = "";
|
|
30
|
+
database_type = "";
|
|
38
31
|
async folderExists(folderPath) {
|
|
39
32
|
try {
|
|
40
33
|
const stats = await fs.stat(folderPath);
|
|
@@ -47,14 +40,148 @@ class CreateProjectCommand extends Command {
|
|
|
47
40
|
}
|
|
48
41
|
}
|
|
49
42
|
async execute() {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
43
|
+
await this.setupProjectPath();
|
|
44
|
+
await this.setupGit();
|
|
45
|
+
await this.setupExecutorAndPackageManager();
|
|
46
|
+
await this.setupLinter();
|
|
47
|
+
await this.setupGeneralPackages();
|
|
48
|
+
await this.setupBaseProject();
|
|
49
|
+
await this.installPackages();
|
|
50
|
+
}
|
|
51
|
+
async processTplFolder(src, dest, data = {}) {
|
|
52
|
+
const files = await fs.readdir(src, { withFileTypes: true });
|
|
53
|
+
for (const file of files) {
|
|
54
|
+
const srcPath = path.join(src, file.name);
|
|
55
|
+
const destPath = file.isFile() && file.name.endsWith(".tpl") ? path.join(dest, file.name.substring(0, file.name.length - 4)) : path.join(dest, file.name);
|
|
56
|
+
if (file.isDirectory()) {
|
|
57
|
+
await fs.mkdir(destPath, { recursive: true });
|
|
58
|
+
await this.processTplFolder(srcPath, destPath, data);
|
|
59
|
+
} else if (file.name.endsWith(".tpl")) {
|
|
60
|
+
await this.processTplFile(srcPath, destPath, data);
|
|
61
|
+
} else {
|
|
62
|
+
throw new Error(
|
|
63
|
+
"unexpected non tpl file: " + srcPath + " " + file.name
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
async processTplFile(src, dest, data = {}) {
|
|
69
|
+
handlebars.registerHelper("eq", (a, b) => a === b);
|
|
70
|
+
const compiledTemplate = handlebars.compile(
|
|
71
|
+
(await fs.readFile(src)).toString()
|
|
72
|
+
);
|
|
73
|
+
const template = await compiledTemplate(data);
|
|
74
|
+
await fs.writeFile(dest, template);
|
|
75
|
+
}
|
|
76
|
+
async setupProjectPath() {
|
|
77
|
+
const pathInput = await input({
|
|
78
|
+
message: "Enter project path (leave empty to use current directory):",
|
|
79
|
+
default: ""
|
|
80
|
+
});
|
|
81
|
+
this.projectPath = pathInput.trim() ? path.resolve(pathInput.trim()) : process.cwd();
|
|
82
|
+
await fs.mkdir(this.projectPath, { recursive: true });
|
|
83
|
+
const files = await fs.readdir(this.projectPath);
|
|
84
|
+
if (files.length > 0) {
|
|
85
|
+
throw new Error(
|
|
86
|
+
`Directory ${this.projectPath} is not empty. Please use an empty directory.`
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
async setupExecutorAndPackageManager() {
|
|
91
|
+
this.executor = await select({
|
|
92
|
+
message: "Select a TypeScript executor",
|
|
93
|
+
choices: [
|
|
94
|
+
{
|
|
95
|
+
name: "Bun",
|
|
96
|
+
value: "bun",
|
|
97
|
+
description: "Fast all-in-one JavaScript runtime"
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
name: "TSX",
|
|
101
|
+
value: "tsx",
|
|
102
|
+
description: "TypeScript execute (tsx) - Node.js enhanced with esbuild"
|
|
103
|
+
}
|
|
104
|
+
]
|
|
105
|
+
});
|
|
106
|
+
this.packageManager = this.executor === "bun" ? "bun" : await select({
|
|
107
|
+
message: "Select a package manager",
|
|
108
|
+
choices: [
|
|
109
|
+
{
|
|
110
|
+
name: "Yarn",
|
|
111
|
+
value: "yarn",
|
|
112
|
+
description: "Fast, reliable, and secure dependency management"
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
name: "npm",
|
|
116
|
+
value: "npm",
|
|
117
|
+
description: "Node package manager (default)"
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
name: "Bun",
|
|
121
|
+
value: "bun",
|
|
122
|
+
description: "Ultra-fast package manager built into Bun"
|
|
123
|
+
}
|
|
124
|
+
],
|
|
125
|
+
default: "yarn"
|
|
126
|
+
});
|
|
127
|
+
execSync(`${this.packageManager} init -y`, {
|
|
128
|
+
stdio: "inherit",
|
|
129
|
+
cwd: this.projectPath
|
|
130
|
+
});
|
|
131
|
+
const packageJsonPath = path.join(this.projectPath, `package.json`);
|
|
132
|
+
let packageJson = JSON.parse(await fs.readFile(packageJsonPath, `utf-8`));
|
|
133
|
+
packageJson.type = "module";
|
|
134
|
+
packageJson.scripts = packageJson.scripts || {};
|
|
135
|
+
packageJson.scripts.prepare = "husky init";
|
|
136
|
+
packageJson.scripts.clean = "rm -rf dist";
|
|
137
|
+
if (this.executor === "bun") {
|
|
138
|
+
packageJson.scripts.dev = "bun run dev";
|
|
139
|
+
packageJson.scripts.start = "bun run pdev";
|
|
140
|
+
packageJson.scripts.build = "bun run build";
|
|
141
|
+
packageJson.scripts.test = "vitest";
|
|
142
|
+
packageJson.scripts["test:watch"] = "vitest --watch";
|
|
143
|
+
packageJson.scripts["test:coverage"] = "vitest run --coverage";
|
|
144
|
+
} else if (this.executor === "tsx") {
|
|
145
|
+
packageJson.scripts.dev = "tsx --watch -r tsconfig-paths/register src/index.ts start --all | npx pino-pretty";
|
|
146
|
+
packageJson.scripts.start = "tsx dist/index.js";
|
|
147
|
+
packageJson.scripts.build = "tsc";
|
|
148
|
+
packageJson.scripts.test = "vitest";
|
|
149
|
+
packageJson.scripts["test:watch"] = "vitest --watch";
|
|
150
|
+
packageJson.scripts["test:coverage"] = "vitest run --coverage";
|
|
151
|
+
}
|
|
152
|
+
await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
153
|
+
}
|
|
154
|
+
async setupLinter() {
|
|
155
|
+
this.linter = await select({
|
|
156
|
+
message: "Select a linter",
|
|
157
|
+
choices: [
|
|
158
|
+
{
|
|
159
|
+
name: "Biome",
|
|
160
|
+
value: "biome",
|
|
161
|
+
description: "Fast formatter and linter for JavaScript, TypeScript, and more"
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
name: "ESLint",
|
|
165
|
+
value: "eslint",
|
|
166
|
+
description: "Find and fix problems in your JavaScript code"
|
|
167
|
+
}
|
|
168
|
+
]
|
|
169
|
+
});
|
|
170
|
+
const packageJsonPath = path.join(this.projectPath, `package.json`);
|
|
171
|
+
let packageJson = JSON.parse(await fs.readFile(packageJsonPath, `utf-8`));
|
|
172
|
+
if (this.linter === "biome") {
|
|
173
|
+
packageJson.scripts.lint = "biome check . --ext .ts,.tsx";
|
|
174
|
+
packageJson.scripts.format = "biome format . --ext .ts,.tsx --write";
|
|
175
|
+
this.addPackage("@biomejs/biome", true);
|
|
176
|
+
} else if (this.linter === "eslint") {
|
|
177
|
+
packageJson.scripts.lint = "eslint . --ext .ts,.tsx";
|
|
178
|
+
packageJson.scripts.format = "eslint . --ext .ts,.tsx --fix";
|
|
179
|
+
this.addPackage("eslint", true);
|
|
56
180
|
}
|
|
57
|
-
|
|
181
|
+
await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
182
|
+
}
|
|
183
|
+
async setupGeneralPackages() {
|
|
184
|
+
this.validation_library = await select({
|
|
58
185
|
message: "Select a package you want for validation",
|
|
59
186
|
choices: [
|
|
60
187
|
{
|
|
@@ -75,8 +202,42 @@ class CreateProjectCommand extends Command {
|
|
|
75
202
|
}
|
|
76
203
|
]
|
|
77
204
|
});
|
|
78
|
-
|
|
79
|
-
|
|
205
|
+
this.validation_library === "none" || await this.addPackage(this.validation_library);
|
|
206
|
+
this.database_type = await select({
|
|
207
|
+
message: "Select a database type (you can add more databases later)",
|
|
208
|
+
choices: [
|
|
209
|
+
{
|
|
210
|
+
name: "PostgreSQL",
|
|
211
|
+
value: "postgresql",
|
|
212
|
+
description: "A powerful, open source object-relational database system"
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
name: "MySQL",
|
|
216
|
+
value: "mysql",
|
|
217
|
+
description: "The world's most popular open source database"
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
name: "SQLite",
|
|
221
|
+
value: "sqlite",
|
|
222
|
+
description: "A C library that provides a lightweight disk-based database"
|
|
223
|
+
}
|
|
224
|
+
]
|
|
225
|
+
});
|
|
226
|
+
if (this.database_type === "postgresql") {
|
|
227
|
+
await this.addPackage("pg pg-cursor");
|
|
228
|
+
} else if (this.database_type === "mysql") {
|
|
229
|
+
await this.addPackage("mysql2");
|
|
230
|
+
} else if (this.database_type === "sqlite") {
|
|
231
|
+
await this.addPackage("sqlite3");
|
|
232
|
+
}
|
|
233
|
+
await this.addPackage("@devbro/pashmak tsconfig-paths dotenv ");
|
|
234
|
+
await this.addPackage(
|
|
235
|
+
"husky vitest supertest @types/supertest pino-pretty typescript tsx",
|
|
236
|
+
true
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
async setupBaseProject() {
|
|
240
|
+
console.log(`Using project directory: ${this.projectPath}`);
|
|
80
241
|
const dirname = typeof __dirname === "undefined" ? path.dirname(fileURLToPath(import.meta.url)) : __dirname;
|
|
81
242
|
let basePath = path.join(dirname, `./base_project`);
|
|
82
243
|
if (await this.folderExists(basePath) === false) {
|
|
@@ -84,53 +245,90 @@ class CreateProjectCommand extends Command {
|
|
|
84
245
|
}
|
|
85
246
|
console.log(`Using base project path: ${basePath}`);
|
|
86
247
|
const baseProjectPath = basePath;
|
|
87
|
-
await this.processTplFolder(baseProjectPath, projectPath, {
|
|
88
|
-
validation_library
|
|
248
|
+
await this.processTplFolder(baseProjectPath, this.projectPath, {
|
|
249
|
+
validation_library: this.validation_library,
|
|
250
|
+
executor: this.executor,
|
|
251
|
+
package_manager: this.packageManager,
|
|
252
|
+
linter: this.linter,
|
|
253
|
+
database_type: this.database_type
|
|
89
254
|
});
|
|
90
|
-
console.log(`Copied base project files to: ${projectPath}`);
|
|
91
|
-
const packageJsonPath = path.join(projectPath,
|
|
92
|
-
|
|
93
|
-
packageJson.name = Case.snake(path.basename(projectPath));
|
|
255
|
+
console.log(`Copied base project files to: ${this.projectPath}`);
|
|
256
|
+
const packageJsonPath = path.join(this.projectPath, "package.json");
|
|
257
|
+
let packageJson = JSON.parse(await fs.readFile(packageJsonPath, `utf-8`));
|
|
258
|
+
packageJson.name = Case.snake(path.basename(this.projectPath));
|
|
94
259
|
await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
95
260
|
console.log(`Updated package.json with project name: ${packageJson.name}`);
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
261
|
+
}
|
|
262
|
+
async addPackage(packageName, dev = false) {
|
|
263
|
+
let install_command = "";
|
|
264
|
+
switch (this.packageManager) {
|
|
265
|
+
case "bun":
|
|
266
|
+
install_command = `bun add ${packageName}${dev ? " -d" : ""}`;
|
|
267
|
+
break;
|
|
268
|
+
case "yarn":
|
|
269
|
+
install_command = `yarn add ${packageName}${dev ? " -D" : ""} --no-install`;
|
|
270
|
+
break;
|
|
271
|
+
case "npm":
|
|
272
|
+
install_command = `npm install ${packageName}${dev ? " --save-dev" : ""} --package-lock-only`;
|
|
273
|
+
break;
|
|
108
274
|
}
|
|
275
|
+
execSync(install_command, {
|
|
276
|
+
stdio: "inherit",
|
|
277
|
+
cwd: this.projectPath
|
|
278
|
+
});
|
|
109
279
|
}
|
|
110
|
-
async
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
280
|
+
async installPackages() {
|
|
281
|
+
const install_command = this.packageManager === "bun" ? `bun install` : this.packageManager === "yarn" ? `yarn` : `npm install`;
|
|
282
|
+
execSync(install_command, {
|
|
283
|
+
stdio: "inherit",
|
|
284
|
+
cwd: this.projectPath
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
async setupGit() {
|
|
288
|
+
const initGit = await select({
|
|
289
|
+
message: "Initialize a git repository?",
|
|
290
|
+
choices: [
|
|
291
|
+
{
|
|
292
|
+
name: "Yes",
|
|
293
|
+
value: true,
|
|
294
|
+
description: "Initialize git and create first commit"
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
name: "No",
|
|
298
|
+
value: false,
|
|
299
|
+
description: "Skip git initialization"
|
|
300
|
+
}
|
|
301
|
+
]
|
|
302
|
+
});
|
|
303
|
+
if (initGit) {
|
|
304
|
+
const gitignoreContent = [
|
|
305
|
+
"node_modules/",
|
|
306
|
+
"dist/",
|
|
307
|
+
".env",
|
|
308
|
+
".env.*",
|
|
309
|
+
"!.env.example",
|
|
310
|
+
"*.log",
|
|
311
|
+
"coverage/",
|
|
312
|
+
".DS_Store"
|
|
313
|
+
].join("\n") + "\n";
|
|
314
|
+
await fs.writeFile(
|
|
315
|
+
path.join(this.projectPath, ".gitignore"),
|
|
316
|
+
gitignoreContent
|
|
317
|
+
);
|
|
318
|
+
execSync(
|
|
319
|
+
`git init; git add --all; git commit --allow-empty -m "chore: first commit"`,
|
|
320
|
+
{
|
|
321
|
+
cwd: this.projectPath
|
|
322
|
+
}
|
|
323
|
+
);
|
|
125
324
|
}
|
|
126
325
|
}
|
|
127
|
-
async
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
await fs.writeFile(dest, template);
|
|
326
|
+
async catch(error) {
|
|
327
|
+
if (Error.isError(error)) {
|
|
328
|
+
console.error(error.message);
|
|
329
|
+
} else {
|
|
330
|
+
console.error(error);
|
|
331
|
+
}
|
|
134
332
|
}
|
|
135
333
|
}
|
|
136
334
|
export {
|