@skalfa/skalfa-api-core 1.0.2

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 (249) hide show
  1. package/.github/workflows/publish.yml +40 -0
  2. package/dist/auth/auth.d.ts +19 -0
  3. package/dist/auth/auth.js +227 -0
  4. package/dist/auth/auth.js.map +1 -0
  5. package/dist/auth/index.d.ts +1 -0
  6. package/dist/auth/index.js +2 -0
  7. package/dist/auth/index.js.map +1 -0
  8. package/dist/auth.util.d.ts +19 -0
  9. package/dist/auth.util.js +183 -0
  10. package/dist/auth.util.js.map +1 -0
  11. package/dist/commands/cli.d.ts +1 -0
  12. package/dist/commands/cli.js +78 -0
  13. package/dist/commands/cli.js.map +1 -0
  14. package/dist/commands/make/basic-controller.d.ts +2 -0
  15. package/dist/commands/make/basic-controller.js +40 -0
  16. package/dist/commands/make/basic-controller.js.map +1 -0
  17. package/dist/commands/make/basic-migration.d.ts +5 -0
  18. package/dist/commands/make/basic-migration.js +60 -0
  19. package/dist/commands/make/basic-migration.js.map +1 -0
  20. package/dist/commands/make/basic-model.d.ts +2 -0
  21. package/dist/commands/make/basic-model.js +25 -0
  22. package/dist/commands/make/basic-model.js.map +1 -0
  23. package/dist/commands/make/basic-seeder.d.ts +3 -0
  24. package/dist/commands/make/basic-seeder.js +32 -0
  25. package/dist/commands/make/basic-seeder.js.map +1 -0
  26. package/dist/commands/make/blueprint.d.ts +2 -0
  27. package/dist/commands/make/blueprint.js +29 -0
  28. package/dist/commands/make/blueprint.js.map +1 -0
  29. package/dist/commands/make/da-migration.d.ts +5 -0
  30. package/dist/commands/make/da-migration.js +60 -0
  31. package/dist/commands/make/da-migration.js.map +1 -0
  32. package/dist/commands/make/light-controller.d.ts +3 -0
  33. package/dist/commands/make/light-controller.js +54 -0
  34. package/dist/commands/make/light-controller.js.map +1 -0
  35. package/dist/commands/make/light-model.d.ts +3 -0
  36. package/dist/commands/make/light-model.js +50 -0
  37. package/dist/commands/make/light-model.js.map +1 -0
  38. package/dist/commands/make/mail.d.ts +2 -0
  39. package/dist/commands/make/mail.js +41 -0
  40. package/dist/commands/make/mail.js.map +1 -0
  41. package/dist/commands/make/notification.d.ts +2 -0
  42. package/dist/commands/make/notification.js +33 -0
  43. package/dist/commands/make/notification.js.map +1 -0
  44. package/dist/commands/make/queue.d.ts +2 -0
  45. package/dist/commands/make/queue.js +35 -0
  46. package/dist/commands/make/queue.js.map +1 -0
  47. package/dist/commands/runner/barrels.d.ts +3 -0
  48. package/dist/commands/runner/barrels.js +78 -0
  49. package/dist/commands/runner/barrels.js.map +1 -0
  50. package/dist/commands/runner/blueprint/controller-generation.d.ts +1 -0
  51. package/dist/commands/runner/blueprint/controller-generation.js +147 -0
  52. package/dist/commands/runner/blueprint/controller-generation.js.map +1 -0
  53. package/dist/commands/runner/blueprint/documentation-generation.d.ts +6 -0
  54. package/dist/commands/runner/blueprint/documentation-generation.js +337 -0
  55. package/dist/commands/runner/blueprint/documentation-generation.js.map +1 -0
  56. package/dist/commands/runner/blueprint/migration-generation.d.ts +1 -0
  57. package/dist/commands/runner/blueprint/migration-generation.js +120 -0
  58. package/dist/commands/runner/blueprint/migration-generation.js.map +1 -0
  59. package/dist/commands/runner/blueprint/model-generation.d.ts +1 -0
  60. package/dist/commands/runner/blueprint/model-generation.js +122 -0
  61. package/dist/commands/runner/blueprint/model-generation.js.map +1 -0
  62. package/dist/commands/runner/blueprint/runner.d.ts +23 -0
  63. package/dist/commands/runner/blueprint/runner.js +139 -0
  64. package/dist/commands/runner/blueprint/runner.js.map +1 -0
  65. package/dist/commands/runner/blueprint/seeder-generation.d.ts +1 -0
  66. package/dist/commands/runner/blueprint/seeder-generation.js +40 -0
  67. package/dist/commands/runner/blueprint/seeder-generation.js.map +1 -0
  68. package/dist/commands/runner/da-migration.d.ts +39 -0
  69. package/dist/commands/runner/da-migration.js +262 -0
  70. package/dist/commands/runner/da-migration.js.map +1 -0
  71. package/dist/commands/runner/migration.d.ts +11 -0
  72. package/dist/commands/runner/migration.js +188 -0
  73. package/dist/commands/runner/migration.js.map +1 -0
  74. package/dist/commands/runner/seeder.d.ts +3 -0
  75. package/dist/commands/runner/seeder.js +40 -0
  76. package/dist/commands/runner/seeder.js.map +1 -0
  77. package/dist/commands/stubs/index.d.ts +14 -0
  78. package/dist/commands/stubs/index.js +277 -0
  79. package/dist/commands/stubs/index.js.map +1 -0
  80. package/dist/context/context.d.ts +7 -0
  81. package/dist/context/context.js +11 -0
  82. package/dist/context/context.js.map +1 -0
  83. package/dist/context/index.d.ts +1 -0
  84. package/dist/context/index.js +2 -0
  85. package/dist/context/index.js.map +1 -0
  86. package/dist/context.util.d.ts +7 -0
  87. package/dist/context.util.js +11 -0
  88. package/dist/context.util.js.map +1 -0
  89. package/dist/controller/controller.d.ts +118 -0
  90. package/dist/controller/controller.js +147 -0
  91. package/dist/controller/controller.js.map +1 -0
  92. package/dist/controller/index.d.ts +1 -0
  93. package/dist/controller/index.js +2 -0
  94. package/dist/controller/index.js.map +1 -0
  95. package/dist/controller.util.d.ts +118 -0
  96. package/dist/controller.util.js +144 -0
  97. package/dist/controller.util.js.map +1 -0
  98. package/dist/conversion/conversion.d.ts +8 -0
  99. package/dist/conversion/conversion.js +52 -0
  100. package/dist/conversion/conversion.js.map +1 -0
  101. package/dist/conversion/index.d.ts +1 -0
  102. package/dist/conversion/index.js +2 -0
  103. package/dist/conversion/index.js.map +1 -0
  104. package/dist/conversion.util.d.ts +8 -0
  105. package/dist/conversion.util.js +52 -0
  106. package/dist/conversion.util.js.map +1 -0
  107. package/dist/db/db.d.ts +84 -0
  108. package/dist/db/db.js +177 -0
  109. package/dist/db/db.js.map +1 -0
  110. package/dist/db/index.d.ts +1 -0
  111. package/dist/db/index.js +2 -0
  112. package/dist/db/index.js.map +1 -0
  113. package/dist/db.util.d.ts +84 -0
  114. package/dist/db.util.js +177 -0
  115. package/dist/db.util.js.map +1 -0
  116. package/dist/index.d.ts +21 -0
  117. package/dist/index.js +14 -0
  118. package/dist/index.js.map +1 -0
  119. package/dist/logger/index.d.ts +1 -0
  120. package/dist/logger/index.js +2 -0
  121. package/dist/logger/index.js.map +1 -0
  122. package/dist/logger/logger.d.ts +30 -0
  123. package/dist/logger/logger.js +126 -0
  124. package/dist/logger/logger.js.map +1 -0
  125. package/dist/logger.util.d.ts +30 -0
  126. package/dist/logger.util.js +126 -0
  127. package/dist/logger.util.js.map +1 -0
  128. package/dist/mail/index.d.ts +1 -0
  129. package/dist/mail/index.js +2 -0
  130. package/dist/mail/index.js.map +1 -0
  131. package/dist/mail/mail.d.ts +21 -0
  132. package/dist/mail/mail.js +53 -0
  133. package/dist/mail/mail.js.map +1 -0
  134. package/dist/mail.util.d.ts +21 -0
  135. package/dist/mail.util.js +53 -0
  136. package/dist/mail.util.js.map +1 -0
  137. package/dist/middleware/index.d.ts +1 -0
  138. package/dist/middleware/index.js +2 -0
  139. package/dist/middleware/index.js.map +1 -0
  140. package/dist/middleware/middleware.d.ts +263 -0
  141. package/dist/middleware/middleware.js +233 -0
  142. package/dist/middleware/middleware.js.map +1 -0
  143. package/dist/middleware.util.d.ts +263 -0
  144. package/dist/middleware.util.js +233 -0
  145. package/dist/middleware.util.js.map +1 -0
  146. package/dist/model/index.d.ts +3 -0
  147. package/dist/model/index.js +4 -0
  148. package/dist/model/index.js.map +1 -0
  149. package/dist/model/model.d.ts +204 -0
  150. package/dist/model/model.js +1495 -0
  151. package/dist/model/model.js.map +1 -0
  152. package/dist/model.util.d.ts +204 -0
  153. package/dist/model.util.js +1495 -0
  154. package/dist/model.util.js.map +1 -0
  155. package/dist/permission/index.d.ts +1 -0
  156. package/dist/permission/index.js +2 -0
  157. package/dist/permission/index.js.map +1 -0
  158. package/dist/permission/permission.d.ts +38 -0
  159. package/dist/permission/permission.js +91 -0
  160. package/dist/permission/permission.js.map +1 -0
  161. package/dist/permission.util.d.ts +38 -0
  162. package/dist/permission.util.js +91 -0
  163. package/dist/permission.util.js.map +1 -0
  164. package/dist/registry/index.d.ts +1 -0
  165. package/dist/registry/index.js +2 -0
  166. package/dist/registry/index.js.map +1 -0
  167. package/dist/registry/registry.d.ts +28 -0
  168. package/dist/registry/registry.js +19 -0
  169. package/dist/registry/registry.js.map +1 -0
  170. package/dist/registry.util.d.ts +28 -0
  171. package/dist/registry.util.js +19 -0
  172. package/dist/registry.util.js.map +1 -0
  173. package/dist/route/index.d.ts +1 -0
  174. package/dist/route/index.js +2 -0
  175. package/dist/route/index.js.map +1 -0
  176. package/dist/route/route.d.ts +1 -0
  177. package/dist/route/route.js +12 -0
  178. package/dist/route/route.js.map +1 -0
  179. package/dist/route.util.d.ts +1 -0
  180. package/dist/route.util.js +12 -0
  181. package/dist/route.util.js.map +1 -0
  182. package/dist/storage/index.d.ts +1 -0
  183. package/dist/storage/index.js +2 -0
  184. package/dist/storage/index.js.map +1 -0
  185. package/dist/storage/storage.d.ts +56 -0
  186. package/dist/storage/storage.js +86 -0
  187. package/dist/storage/storage.js.map +1 -0
  188. package/dist/storage.util.d.ts +56 -0
  189. package/dist/storage.util.js +82 -0
  190. package/dist/storage.util.js.map +1 -0
  191. package/dist/validation/index.d.ts +1 -0
  192. package/dist/validation/index.js +2 -0
  193. package/dist/validation/index.js.map +1 -0
  194. package/dist/validation/validation.d.ts +7 -0
  195. package/dist/validation/validation.js +245 -0
  196. package/dist/validation/validation.js.map +1 -0
  197. package/dist/validation.util.d.ts +7 -0
  198. package/dist/validation.util.js +237 -0
  199. package/dist/validation.util.js.map +1 -0
  200. package/package.json +34 -0
  201. package/src/auth/auth.ts +282 -0
  202. package/src/auth/index.ts +1 -0
  203. package/src/commands/cli.ts +89 -0
  204. package/src/commands/make/basic-controller.ts +49 -0
  205. package/src/commands/make/basic-migration.ts +89 -0
  206. package/src/commands/make/basic-model.ts +32 -0
  207. package/src/commands/make/basic-seeder.ts +38 -0
  208. package/src/commands/make/blueprint.ts +36 -0
  209. package/src/commands/make/da-migration.ts +90 -0
  210. package/src/commands/make/light-controller.ts +67 -0
  211. package/src/commands/make/light-model.ts +61 -0
  212. package/src/commands/make/mail.ts +51 -0
  213. package/src/commands/make/notification.ts +43 -0
  214. package/src/commands/make/queue.ts +45 -0
  215. package/src/commands/runner/barrels.ts +85 -0
  216. package/src/commands/runner/blueprint/controller-generation.ts +194 -0
  217. package/src/commands/runner/blueprint/documentation-generation.ts +463 -0
  218. package/src/commands/runner/blueprint/migration-generation.ts +153 -0
  219. package/src/commands/runner/blueprint/model-generation.ts +149 -0
  220. package/src/commands/runner/blueprint/runner.ts +181 -0
  221. package/src/commands/runner/blueprint/seeder-generation.ts +55 -0
  222. package/src/commands/runner/da-migration.ts +333 -0
  223. package/src/commands/runner/migration.ts +245 -0
  224. package/src/commands/runner/seeder.ts +44 -0
  225. package/src/commands/stubs/index.ts +289 -0
  226. package/src/context/context.ts +17 -0
  227. package/src/context/index.ts +1 -0
  228. package/src/controller/controller.ts +240 -0
  229. package/src/controller/index.ts +1 -0
  230. package/src/conversion/conversion.ts +65 -0
  231. package/src/conversion/index.ts +1 -0
  232. package/src/index.ts +22 -0
  233. package/src/logger/index.ts +1 -0
  234. package/src/logger/logger.ts +177 -0
  235. package/src/mail/index.ts +1 -0
  236. package/src/mail/mail.ts +86 -0
  237. package/src/middleware/index.ts +1 -0
  238. package/src/middleware/middleware.ts +289 -0
  239. package/src/permission/index.ts +1 -0
  240. package/src/permission/permission.ts +136 -0
  241. package/src/registry/index.ts +1 -0
  242. package/src/registry/registry.ts +37 -0
  243. package/src/route/index.ts +1 -0
  244. package/src/route/route.ts +12 -0
  245. package/src/storage/index.ts +1 -0
  246. package/src/storage/storage.ts +107 -0
  247. package/src/validation/index.ts +1 -0
  248. package/src/validation/validation.ts +346 -0
  249. package/tsconfig.json +23 -0
@@ -0,0 +1,85 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import { exec, execSync } from "child_process";
4
+ import { Command } from "commander";
5
+ import { logger } from "@utils";
6
+
7
+ // =====================================>
8
+ // ## Command: barrels (run once)
9
+ // =====================================>
10
+ export const barrelsCommand = new Command("barrels")
11
+ .description("Generate barrels auto-imports using barrelsby")
12
+ .action(() => {
13
+ const rootDir = process.cwd();
14
+ const configPath = path.join(rootDir, "barrels.json");
15
+
16
+ if (!fs.existsSync(configPath)) {
17
+ logger.error("barrels.json config file not found at project root");
18
+ process.exit(1);
19
+ }
20
+
21
+ logger.info("Generating barrels...");
22
+ try {
23
+ execSync("bunx barrelsby -c barrels.json", { cwd: rootDir, stdio: "inherit" });
24
+ logger.info("Barrels successfully generated!");
25
+ process.exit(0);
26
+ } catch (err) {
27
+ logger.error(`Failed to generate barrels: ${err}`);
28
+ process.exit(1);
29
+ }
30
+ });
31
+
32
+ // =====================================>
33
+ // ## Command: watch:barrels (file watcher)
34
+ // =====================================>
35
+ export const watchBarrelsCommand = new Command("watch:barrels")
36
+ .description("Watch directories and update barrels automatically on file changes")
37
+ .action(async () => {
38
+ const rootDir = process.cwd();
39
+ const configPath = path.join(rootDir, "barrels.json");
40
+
41
+ if (!fs.existsSync(configPath)) {
42
+ logger.error("barrels.json config file not found at project root");
43
+ process.exit(1);
44
+ }
45
+
46
+ let config: any = {};
47
+ try {
48
+ const configText = fs.readFileSync(configPath, "utf8");
49
+ config = JSON.parse(configText);
50
+ } catch (err) {
51
+ logger.error(`Failed to parse barrels.json: ${err}`);
52
+ process.exit(1);
53
+ }
54
+
55
+ const directories: string[] = Array.isArray(config.directory) ? config.directory : [config.directory];
56
+
57
+ // Run barrels once at startup
58
+ logger.info("Initializing barrels generation...");
59
+ try {
60
+ execSync("bunx barrelsby -c barrels.json", { cwd: rootDir });
61
+ } catch {}
62
+
63
+ directories.forEach((dir) => {
64
+ const absoluteDir = path.join(rootDir, dir);
65
+
66
+ if (!fs.existsSync(absoluteDir)) {
67
+ logger.error(`Barrels error: ${absoluteDir} directory not found`);
68
+ return;
69
+ }
70
+
71
+ fs.watch(absoluteDir, { recursive: true }, (_, filename) => {
72
+ if (filename && filename.endsWith(".ts") && filename !== "index.ts") {
73
+ exec("bunx barrelsby -c barrels.json", { cwd: rootDir }, (error) => {
74
+ if (error) {
75
+ logger.error(`Failed to update barrels for ${dir}: ${error.message}`);
76
+ } else {
77
+ logger.info(`Barrels updated: ${path.join(dir, "index.ts")}`);
78
+ }
79
+ });
80
+ }
81
+ });
82
+ });
83
+
84
+ logger.start("Barrels watcher running for: " + directories.join(", "));
85
+ });
@@ -0,0 +1,194 @@
1
+ import fs from "fs";
2
+ import path from "path";
3
+ import { conversion } from "@utils";
4
+ import { resolveBlueprintPath } from "./runner";
5
+ import { lightControllerStub, routeStub } from "../../stubs";
6
+
7
+ // ================================>
8
+ // ## Command: Blueprint controller generation
9
+ // ================================>
10
+ export async function controllerGeneration(
11
+ model: string,
12
+ schema: Record<string, string> = {},
13
+ relations: Record<string, string> = {},
14
+ controller: string = "",
15
+ route: string = "",
16
+ permission: string = "",
17
+ marker: string
18
+ ) {
19
+ const resolvePath = resolveBlueprintPath(controller, "controller");
20
+ if (!resolvePath) { return false; }
21
+
22
+ const { filePath } = resolvePath;
23
+
24
+ const modelName = conversion.strPascal(model?.split("/")?.pop() || "");
25
+ const controllerName = conversion.strPascal(controller?.split("/")?.pop() || "") + "Controller";
26
+ const permissionCode = conversion.strPascal(permission?.split(":")?.[0] || "");
27
+ const permissionName = conversion.strPascal(permission?.split(":")?.[1] || "", " ") || conversion.strPascal(controller?.split("/")?.pop() || "");
28
+
29
+ const validations = {
30
+ ...generateFieldValidations(model, schema),
31
+ ...generateRelationValidations(relations)
32
+ };
33
+
34
+ let stub = lightControllerStub;
35
+
36
+ stub = stub
37
+ .replace(/{{\s*marker\s*}}/g, marker)
38
+ .replace(/{{\s*name\s*}}/g, controllerName)
39
+ .replace(/{{\s*model\s*}}/g, modelName)
40
+ .replace(/{{\s*permission_code\s*}}/g, permissionCode)
41
+ .replace(/{{\s*permission_name\s*}}/g, permissionName)
42
+ .replace(/{{\s*validations\s*}}/g, renderValidationObject(validations));
43
+
44
+ fs.writeFileSync(filePath, stub, "utf-8");
45
+
46
+ apiRouteGeneration(route, controllerName);
47
+
48
+ return true;
49
+ }
50
+
51
+ // =============================>
52
+ // ## Command: Blueprint route generation
53
+ // =============================>
54
+ function apiRouteGeneration(routePath: string, controllerName: string) {
55
+ const { file, apiPath } = parseRoutePath(routePath);
56
+
57
+ const routesPath = ensureRouteFile(file);
58
+ let content = fs.readFileSync(routesPath, "utf-8");
59
+
60
+ content = ensureControllerImported(content, controllerName);
61
+ content = ensureApiRoute(content, apiPath, controllerName);
62
+
63
+ fs.writeFileSync(routesPath, content, "utf-8");
64
+ }
65
+
66
+ function renderValidationObject(rules: Record<string, string[]>) {
67
+ return `\n${Object.entries(rules).map(([k, v]) => ` "${k}": ${JSON.stringify(v)}`).join(",\n")}\n `;
68
+ }
69
+
70
+ function generateRelationValidations(relations: Record<string, string>) {
71
+ const rules: Record<string, string[]> = {};
72
+
73
+ for (const [name, def] of Object.entries(relations)) {
74
+ if (!def.includes("fillable")) continue;
75
+
76
+ const isMany = def.startsWith("[]") || def.startsWith("[]:");
77
+ const target = def.replace(/[\[\]:]/g, "").split(" ")[0];
78
+ const table = conversion.strSnake(conversion.strPlural(target));
79
+
80
+ if (isMany) {
81
+ rules[name] = ["array"];
82
+ rules[`${name}.*`] = ["number", `exists:${table},id`];
83
+ } else {
84
+ rules[conversion.strSingular(table) + "_id"] = ["number", `exists:${table},id`];
85
+ }
86
+ }
87
+
88
+ return rules;
89
+ }
90
+
91
+ function generateFieldValidations(model: string, schema: Record<string, string>) {
92
+ const rules: Record<string, string[]> = {};
93
+ const table = conversion.strSnake(conversion.strPlural(model));
94
+
95
+ for (const [field, def] of Object.entries(schema)) {
96
+ const r: string[] = [];
97
+
98
+ if (def.includes("required")) {
99
+ r.push("required");
100
+ }
101
+
102
+ if (def.includes("type:string")) {
103
+ r.push("string");
104
+
105
+ const len = def.match(/type:string,(\d+)/);
106
+ if (len) r.push(`max:${len[1]}`);
107
+ }
108
+
109
+ if (def.includes("type:integer") || def.includes("type:bigInteger") || def.includes("type:float")) {
110
+ r.push("numeric");
111
+ }
112
+
113
+ const min = def.match(/min:(\d+)/);
114
+ if (min) r.push(`min:${min[1]}`);
115
+
116
+ const max = def.match(/max:(\d+)/);
117
+ if (max) r.push(`max:${max[1]}`);
118
+
119
+ if (def.includes("unique")) {
120
+ r.push(`unique:${table},${field}`);
121
+ }
122
+
123
+ if (r?.length) rules[field] = r;
124
+ }
125
+
126
+ return rules;
127
+ }
128
+
129
+ function ensureControllerImported(content: string, controllerName: string): string {
130
+ const importBlockRegex = /import\s*\{([\s\S]*?)\}\s*from\s*['"]@[\w-]*controllers['"]/;
131
+
132
+ if (importBlockRegex.test(content)) {
133
+ return content.replace(importBlockRegex, (match, group) => {
134
+ if (group.includes(controllerName)) return match;
135
+
136
+ const updated = group.trim() ? `${group.trim()}\n ${controllerName},` : controllerName;
137
+
138
+ return `import {\n${updated}\n} from '@controllers'`;
139
+ });
140
+ }
141
+
142
+ const importLine =
143
+ `import {
144
+ ${controllerName}
145
+ } from '@controllers'\n\n`;
146
+
147
+ return importLine + content;
148
+ }
149
+
150
+ function ensureApiRoute(content: string, routePath: string, controllerName: string): string {
151
+ const apiLine = `api(route, "${routePath}", ${controllerName});`;
152
+
153
+ if (content.includes(apiLine)) return content;
154
+
155
+ const returnIndex = content.lastIndexOf("return route;");
156
+ if (returnIndex === -1) {
157
+ throw new Error("Cannot find `return route;` in routes file");
158
+ }
159
+
160
+ return (content.slice(0, returnIndex) + apiLine + "\n " + content.slice(returnIndex));
161
+ }
162
+
163
+ function parseRoutePath(routePath: string) {
164
+ if (!routePath.includes(":")) {
165
+ return { file: "index", apiPath: routePath };
166
+ }
167
+
168
+ const parts = routePath.split(":").filter(Boolean);
169
+
170
+ const file = parts.shift()!;
171
+ const apiPath = parts.join("/");
172
+
173
+ return { file, apiPath };
174
+ }
175
+
176
+ function ensureRouteFile(file: string) {
177
+ const routesDir = path.join(process.cwd(), "app", "routes");
178
+ if (file === "index") return path.join(routesDir, "base.routes.ts");
179
+
180
+ const filePath = path.join(routesDir, `${file}.routes.ts`);
181
+ if (fs.existsSync(filePath)) return filePath;
182
+
183
+ let stub = routeStub;
184
+
185
+ stub = stub.replace(/{{\s*name\s*}}/g, file).replace(/{{\s*path\s*}}/g, file);
186
+
187
+ if (!fs.existsSync(routesDir)) {
188
+ fs.mkdirSync(routesDir, { recursive: true });
189
+ }
190
+
191
+ fs.writeFileSync(filePath, stub, "utf-8");
192
+
193
+ return filePath;
194
+ }