@kithinji/pod 1.0.0

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 (98) hide show
  1. package/build.js +22 -0
  2. package/dist/main.js +4464 -0
  3. package/dist/main.js.map +7 -0
  4. package/dist/types/add/component/component.d.ts +5 -0
  5. package/dist/types/add/component/component.d.ts.map +1 -0
  6. package/dist/types/add/component/index.d.ts +2 -0
  7. package/dist/types/add/component/index.d.ts.map +1 -0
  8. package/dist/types/add/index.d.ts +4 -0
  9. package/dist/types/add/index.d.ts.map +1 -0
  10. package/dist/types/add/module/index.d.ts +2 -0
  11. package/dist/types/add/module/index.d.ts.map +1 -0
  12. package/dist/types/add/module/module.d.ts +3 -0
  13. package/dist/types/add/module/module.d.ts.map +1 -0
  14. package/dist/types/add/new/index.d.ts +2 -0
  15. package/dist/types/add/new/index.d.ts.map +1 -0
  16. package/dist/types/config/config.d.ts +18 -0
  17. package/dist/types/config/config.d.ts.map +1 -0
  18. package/dist/types/config/index.d.ts +2 -0
  19. package/dist/types/config/index.d.ts.map +1 -0
  20. package/dist/types/dev/index.d.ts +2 -0
  21. package/dist/types/dev/index.d.ts.map +1 -0
  22. package/dist/types/dev/project.d.ts +9 -0
  23. package/dist/types/dev/project.d.ts.map +1 -0
  24. package/dist/types/dev/server.d.ts +2 -0
  25. package/dist/types/dev/server.d.ts.map +1 -0
  26. package/dist/types/docker/docker.d.ts +2 -0
  27. package/dist/types/docker/docker.d.ts.map +1 -0
  28. package/dist/types/docker/index.d.ts +2 -0
  29. package/dist/types/docker/index.d.ts.map +1 -0
  30. package/dist/types/macros/expand_macros.d.ts +48 -0
  31. package/dist/types/macros/expand_macros.d.ts.map +1 -0
  32. package/dist/types/macros/index.d.ts +3 -0
  33. package/dist/types/macros/index.d.ts.map +1 -0
  34. package/dist/types/macros/macro_executer.d.ts +12 -0
  35. package/dist/types/macros/macro_executer.d.ts.map +1 -0
  36. package/dist/types/main.d.ts +13 -0
  37. package/dist/types/main.d.ts.map +1 -0
  38. package/dist/types/plugins/analyzers/graph.d.ts +25 -0
  39. package/dist/types/plugins/analyzers/graph.d.ts.map +1 -0
  40. package/dist/types/plugins/css/index.d.ts +7 -0
  41. package/dist/types/plugins/css/index.d.ts.map +1 -0
  42. package/dist/types/plugins/generators/generate_controller.d.ts +2 -0
  43. package/dist/types/plugins/generators/generate_controller.d.ts.map +1 -0
  44. package/dist/types/plugins/generators/generate_rsc.d.ts +2 -0
  45. package/dist/types/plugins/generators/generate_rsc.d.ts.map +1 -0
  46. package/dist/types/plugins/generators/generate_server_component.d.ts +2 -0
  47. package/dist/types/plugins/generators/generate_server_component.d.ts.map +1 -0
  48. package/dist/types/plugins/generators/tsx_server_stub.d.ts +2 -0
  49. package/dist/types/plugins/generators/tsx_server_stub.d.ts.map +1 -0
  50. package/dist/types/plugins/index.d.ts +4 -0
  51. package/dist/types/plugins/index.d.ts.map +1 -0
  52. package/dist/types/plugins/my.d.ts +10 -0
  53. package/dist/types/plugins/my.d.ts.map +1 -0
  54. package/dist/types/plugins/transformers/j2d.d.ts +11 -0
  55. package/dist/types/plugins/transformers/j2d.d.ts.map +1 -0
  56. package/dist/types/store/index.d.ts +2 -0
  57. package/dist/types/store/index.d.ts.map +1 -0
  58. package/dist/types/store/store.d.ts +14 -0
  59. package/dist/types/store/store.d.ts.map +1 -0
  60. package/dist/types/utils/cases.d.ts +4 -0
  61. package/dist/types/utils/cases.d.ts.map +1 -0
  62. package/dist/types/utils/create.d.ts +12 -0
  63. package/dist/types/utils/create.d.ts.map +1 -0
  64. package/dist/types/utils/index.d.ts +3 -0
  65. package/dist/types/utils/index.d.ts.map +1 -0
  66. package/package.json +44 -0
  67. package/src/add/component/component.ts +496 -0
  68. package/src/add/component/index.ts +1 -0
  69. package/src/add/index.ts +3 -0
  70. package/src/add/module/index.ts +1 -0
  71. package/src/add/module/module.ts +521 -0
  72. package/src/add/new/index.ts +135 -0
  73. package/src/config/config.ts +141 -0
  74. package/src/config/index.ts +1 -0
  75. package/src/dev/index.ts +1 -0
  76. package/src/dev/project.ts +45 -0
  77. package/src/dev/server.ts +190 -0
  78. package/src/docker/docker.ts +452 -0
  79. package/src/docker/index.ts +1 -0
  80. package/src/macros/expand_macros.ts +791 -0
  81. package/src/macros/index.ts +2 -0
  82. package/src/macros/macro_executer.ts +189 -0
  83. package/src/main.ts +95 -0
  84. package/src/plugins/analyzers/graph.ts +291 -0
  85. package/src/plugins/css/index.ts +25 -0
  86. package/src/plugins/generators/generate_controller.ts +308 -0
  87. package/src/plugins/generators/generate_rsc.ts +274 -0
  88. package/src/plugins/generators/generate_server_component.ts +279 -0
  89. package/src/plugins/generators/tsx_server_stub.ts +295 -0
  90. package/src/plugins/index.ts +3 -0
  91. package/src/plugins/my.ts +274 -0
  92. package/src/plugins/transformers/j2d.ts +1014 -0
  93. package/src/store/index.ts +1 -0
  94. package/src/store/store.ts +44 -0
  95. package/src/utils/cases.ts +15 -0
  96. package/src/utils/create.ts +26 -0
  97. package/src/utils/index.ts +2 -0
  98. package/tsconfig.json +27 -0
@@ -0,0 +1,521 @@
1
+ import { createStructure, DirEntry, toCamelCase, toPascalCase } from "@/utils";
2
+ import * as path from "path";
3
+ import * as fs from "fs";
4
+ import * as ts from "typescript";
5
+
6
+ export function addFeature(name: string) {
7
+ const featureDir = path.join(process.cwd(), "src", "features", name);
8
+
9
+ addModule(name, featureDir);
10
+
11
+ updateFeaturesIndex(name);
12
+
13
+ updateAppModule(name);
14
+ }
15
+
16
+ export function addModule(name: string, baseDir: string) {
17
+ const structure: DirEntry = {
18
+ files: [
19
+ { name: `${name}.module.ts`, content: createModule(name) },
20
+ { name: `${name}.service.ts`, content: createService(name) },
21
+ { name: `${name}.page.tsx`, content: createPage(name) },
22
+ ],
23
+ dirs: [
24
+ {
25
+ name: "schemas",
26
+ files: [
27
+ {
28
+ name: "get.ts",
29
+ content: createGetSchema(name),
30
+ },
31
+ {
32
+ name: "create.ts",
33
+ content: createCreateSchema(name),
34
+ },
35
+ {
36
+ name: "update.ts",
37
+ content: createUpdateSchema(name),
38
+ },
39
+ {
40
+ name: "list.ts",
41
+ content: createListSchema(name),
42
+ },
43
+ {
44
+ name: "delete.ts",
45
+ content: createDeleteSchema(name),
46
+ },
47
+ ],
48
+ },
49
+ {
50
+ name: "components",
51
+ files: [
52
+ {
53
+ name: `${name}-list.component.tsx`,
54
+ content: createListComponent(name),
55
+ },
56
+ ],
57
+ },
58
+ ],
59
+ };
60
+
61
+ createStructure(baseDir, structure);
62
+ }
63
+
64
+ function updateFeaturesIndex(featureName: string) {
65
+ const featuresIndexPath = path.join(
66
+ process.cwd(),
67
+ "src",
68
+ "features",
69
+ "index.ts"
70
+ );
71
+
72
+ const moduleName = toPascalCase(featureName + "_" + "Module");
73
+ const importPath = `./${featureName}/${featureName}.module`;
74
+
75
+ if (fs.existsSync(featuresIndexPath)) {
76
+ let content = fs.readFileSync(featuresIndexPath, "utf-8");
77
+ const sourceFile = ts.createSourceFile(
78
+ "index.ts",
79
+ content,
80
+ ts.ScriptTarget.Latest,
81
+ true
82
+ );
83
+
84
+ const hasExport = sourceFile.statements.some((statement) => {
85
+ if (ts.isExportDeclaration(statement)) {
86
+ const moduleSpecifier = statement.moduleSpecifier;
87
+ if (moduleSpecifier && ts.isStringLiteral(moduleSpecifier)) {
88
+ return moduleSpecifier.text === importPath;
89
+ }
90
+ if (
91
+ statement.exportClause &&
92
+ ts.isNamedExports(statement.exportClause)
93
+ ) {
94
+ return statement.exportClause.elements.some(
95
+ (element) => element.name.text === moduleName
96
+ );
97
+ }
98
+ }
99
+ return false;
100
+ });
101
+
102
+ if (hasExport) {
103
+ return;
104
+ }
105
+
106
+ const exportStatement = `export { ${moduleName} } from "${importPath}";\n`;
107
+ fs.appendFileSync(featuresIndexPath, exportStatement);
108
+ } else {
109
+ const featuresDir = path.dirname(featuresIndexPath);
110
+ if (!fs.existsSync(featuresDir)) {
111
+ fs.mkdirSync(featuresDir, { recursive: true });
112
+ }
113
+
114
+ const exportStatement = `export { ${moduleName} } from "${importPath}";\n`;
115
+ fs.writeFileSync(featuresIndexPath, exportStatement, "utf-8");
116
+ }
117
+ }
118
+
119
+ function updateAppModule(featureName: string) {
120
+ const appModulePath = path.join(process.cwd(), "src", "app", "app.module.ts");
121
+
122
+ if (!fs.existsSync(appModulePath)) {
123
+ return;
124
+ }
125
+
126
+ const moduleName = toPascalCase(featureName + "_" + "Module");
127
+ let content = fs.readFileSync(appModulePath, "utf-8");
128
+
129
+ const sourceFile = ts.createSourceFile(
130
+ "app.module.ts",
131
+ content,
132
+ ts.ScriptTarget.Latest,
133
+ true
134
+ );
135
+
136
+ const hasImport = sourceFile.statements.some((statement) => {
137
+ if (ts.isImportDeclaration(statement)) {
138
+ const moduleSpecifier = statement.moduleSpecifier;
139
+ if (ts.isStringLiteral(moduleSpecifier)) {
140
+ const importPath = moduleSpecifier.text;
141
+ return importPath.includes(`/${featureName}/${featureName}.module`);
142
+ }
143
+
144
+ if (
145
+ statement.importClause?.namedBindings &&
146
+ ts.isNamedImports(statement.importClause.namedBindings)
147
+ ) {
148
+ return statement.importClause.namedBindings.elements.some(
149
+ (element) => element.name.text === moduleName
150
+ );
151
+ }
152
+ }
153
+ return false;
154
+ });
155
+
156
+ if (hasImport) {
157
+ content = addToModuleImportsArray(content, sourceFile, moduleName);
158
+ fs.writeFileSync(appModulePath, content, "utf-8");
159
+ return;
160
+ }
161
+
162
+ let lastImportEnd = 0;
163
+ sourceFile.statements.forEach((statement) => {
164
+ if (ts.isImportDeclaration(statement)) {
165
+ lastImportEnd = statement.end;
166
+ }
167
+ });
168
+
169
+ const importStatement = `import { ${moduleName} } from "../features/${featureName}/${featureName}.module";\n`;
170
+ content =
171
+ content.slice(0, lastImportEnd) +
172
+ "\n" +
173
+ importStatement +
174
+ content.slice(lastImportEnd);
175
+
176
+ const newSourceFile = ts.createSourceFile(
177
+ "app.module.ts",
178
+ content,
179
+ ts.ScriptTarget.Latest,
180
+ true
181
+ );
182
+
183
+ content = addToModuleImportsArray(content, newSourceFile, moduleName);
184
+
185
+ fs.writeFileSync(appModulePath, content, "utf-8");
186
+ }
187
+
188
+ function addToModuleImportsArray(
189
+ content: string,
190
+ sourceFile: ts.SourceFile,
191
+ moduleName: string
192
+ ): string {
193
+ let decoratorNode: ts.Decorator | undefined;
194
+
195
+ sourceFile.statements.forEach((statement) => {
196
+ if (ts.isClassDeclaration(statement) && statement.modifiers) {
197
+ statement.modifiers.forEach((modifier) => {
198
+ if (ts.isDecorator(modifier)) {
199
+ const expression = modifier.expression;
200
+ if (ts.isCallExpression(expression)) {
201
+ const expressionText = expression.expression.getText(sourceFile);
202
+ if (expressionText === "Module") {
203
+ decoratorNode = modifier;
204
+ }
205
+ }
206
+ }
207
+ });
208
+ }
209
+ });
210
+
211
+ if (!decoratorNode) {
212
+ return content;
213
+ }
214
+
215
+ const callExpression = decoratorNode.expression as ts.CallExpression;
216
+ const objectLiteral = callExpression
217
+ .arguments[0] as ts.ObjectLiteralExpression;
218
+
219
+ if (!objectLiteral || !ts.isObjectLiteralExpression(objectLiteral)) {
220
+ return content;
221
+ }
222
+
223
+ let importsProperty: ts.PropertyAssignment | undefined;
224
+ objectLiteral.properties.forEach((prop) => {
225
+ if (ts.isPropertyAssignment(prop)) {
226
+ const propName = prop.name.getText(sourceFile);
227
+ if (propName === "imports") {
228
+ importsProperty = prop;
229
+ }
230
+ }
231
+ });
232
+
233
+ if (!importsProperty) {
234
+ return content;
235
+ }
236
+
237
+ const arrayLiteral = importsProperty.initializer;
238
+ if (!ts.isArrayLiteralExpression(arrayLiteral)) {
239
+ return content;
240
+ }
241
+
242
+ const hasModule = arrayLiteral.elements.some((element) => {
243
+ return element.getText(sourceFile).trim() === moduleName;
244
+ });
245
+
246
+ if (hasModule) {
247
+ return content;
248
+ }
249
+
250
+ const arrayStart = arrayLiteral.getStart(sourceFile);
251
+ const arrayEnd = arrayLiteral.getEnd();
252
+
253
+ if (arrayLiteral.elements.length === 0) {
254
+ const newArray = `[${moduleName}]`;
255
+ return (
256
+ content.substring(0, arrayStart) + newArray + content.substring(arrayEnd)
257
+ );
258
+ }
259
+
260
+ const lastElement = arrayLiteral.elements[arrayLiteral.elements.length - 1];
261
+ const insertPos = lastElement.getEnd();
262
+ const newElement = `, ${moduleName}`;
263
+
264
+ return (
265
+ content.substring(0, insertPos) + newElement + content.substring(insertPos)
266
+ );
267
+ }
268
+
269
+ function createModule(name: string) {
270
+ const serviceName = toPascalCase(name + "_" + "Service");
271
+ const pageName = toPascalCase(name + "_" + "Page");
272
+ const moduleName = toPascalCase(name + "_" + "Module");
273
+ const componentName = toPascalCase(name + "_" + "List");
274
+
275
+ return `import { Module } from "@kithinji/orca";
276
+ import { ComponentModule } from "@/component/component.module";
277
+ import { ${serviceName} } from "./${name}.service";
278
+ import { ${pageName} } from "./${name}.page";
279
+ import { ${componentName} } from "./components/${name}-list.component";
280
+
281
+ @Module({
282
+ imports: [ComponentModule],
283
+ providers: [${serviceName}],
284
+ declarations: [${pageName}, ${componentName}],
285
+ exports: [${serviceName}, ${pageName}]
286
+ })
287
+ export class ${moduleName} {}
288
+ `;
289
+ }
290
+
291
+ function createGetSchema(name: string) {
292
+ return `import { z } from "zod";
293
+
294
+ export const ${toCamelCase(name + "_" + "GetInput")} = z.object({
295
+ id: z.string().uuid(),
296
+ });
297
+
298
+ export const ${toCamelCase(name + "_" + "GetOutput")} = z.object({
299
+ id: z.string().uuid(),
300
+ name: z.string(),
301
+ description: z.string().optional(),
302
+ createdAt: z.date(),
303
+ updatedAt: z.date().optional(),
304
+ });
305
+ `;
306
+ }
307
+
308
+ function createCreateSchema(name: string) {
309
+ return `import { z } from "zod";
310
+
311
+ export const ${toCamelCase(name + "_" + "CreateInput")} = z.object({
312
+ name: z.string().min(1),
313
+ description: z.string().optional(),
314
+ });
315
+
316
+ export const ${toCamelCase(name + "_" + "CreateOutput")} = z.object({
317
+ id: z.string().uuid(),
318
+ name: z.string(),
319
+ description: z.string().optional(),
320
+ createdAt: z.date(),
321
+ });
322
+ `;
323
+ }
324
+
325
+ function createUpdateSchema(name: string) {
326
+ return `import { z } from "zod";
327
+
328
+ export const ${toCamelCase(name + "_" + "UpdateInput")} = z.object({
329
+ id: z.string().uuid(),
330
+ name: z.string().min(1).optional(),
331
+ description: z.string().optional(),
332
+ });
333
+
334
+ export const ${toCamelCase(name + "_" + "UpdateOutput")} = z.object({
335
+ id: z.string().uuid(),
336
+ name: z.string(),
337
+ description: z.string().optional(),
338
+ createdAt: z.date(),
339
+ updatedAt: z.date(),
340
+ });
341
+ `;
342
+ }
343
+
344
+ function createListSchema(name: string) {
345
+ return `import { z } from "zod";
346
+
347
+ export const ${toCamelCase(name + "_" + "ListOutput")} = z.array(
348
+ z.object({
349
+ id: z.string().uuid(),
350
+ name: z.string(),
351
+ description: z.string().optional(),
352
+ createdAt: z.date(),
353
+ updatedAt: z.date().optional(),
354
+ })
355
+ );
356
+ `;
357
+ }
358
+
359
+ function createDeleteSchema(name: string) {
360
+ return `import { z } from "zod";
361
+
362
+ export const ${toCamelCase(name + "_" + "DeleteInput")} = z.object({
363
+ id: z.string().uuid(),
364
+ });
365
+
366
+ export const ${toCamelCase(name + "_" + "DeleteOutput")} = z.object({
367
+ id: z.string().uuid(),
368
+ name: z.string(),
369
+ description: z.string().optional(),
370
+ createdAt: z.date(),
371
+ updatedAt: z.date().optional(),
372
+ });
373
+ `;
374
+ }
375
+
376
+ function createService(name: string) {
377
+ const serviceName = toPascalCase(name + "_" + "Service");
378
+
379
+ return `"use public";
380
+
381
+ import { Injectable, Signature } from "@kithinji/orca";
382
+ import {
383
+ ${toCamelCase(name + "_" + "CreateInput")},
384
+ ${toCamelCase(name + "_" + "CreateOutput")}
385
+ } from "./schemas/create";
386
+ import {
387
+ ${toCamelCase(name + "_" + "GetInput")},
388
+ ${toCamelCase(name + "_" + "GetOutput")}
389
+ } from "./schemas/get";
390
+ import {
391
+ ${toCamelCase(name + "_" + "UpdateInput")},
392
+ ${toCamelCase(name + "_" + "UpdateOutput")}
393
+ } from "./schemas/update";
394
+ import { ${toCamelCase(name + "_" + "ListOutput")} } from "./schemas/list";
395
+ import {
396
+ ${toCamelCase(name + "_" + "DeleteInput")},
397
+ ${toCamelCase(name + "_" + "DeleteOutput")}
398
+ } from "./schemas/delete";
399
+
400
+ @Injectable()
401
+ export class ${serviceName} {
402
+ private items: any[] = [];
403
+
404
+ @Signature(${toCamelCase(name + "_" + "CreateInput")}, ${toCamelCase(
405
+ name + "_" + "CreateOutput"
406
+ )})
407
+ public async create(input: any) {
408
+ const item = {
409
+ id: crypto.randomUUID(),
410
+ ...input,
411
+ createdAt: new Date(),
412
+ };
413
+ this.items.push(item);
414
+ return item;
415
+ }
416
+
417
+ @Signature(${toCamelCase(name + "_" + "GetInput")}, ${toCamelCase(
418
+ name + "_" + "GetOutput"
419
+ )})
420
+ public async get(input: any) {
421
+ const item = this.items.find((i) => i.id === input.id);
422
+ if (!item) {
423
+ throw new Error("Item not found");
424
+ }
425
+ return item;
426
+ }
427
+
428
+ @Signature(${toCamelCase(name + "_" + "ListOutput")})
429
+ public async list() {
430
+ return this.items;
431
+ }
432
+
433
+ @Signature(${toCamelCase(name + "_" + "UpdateInput")}, ${toCamelCase(
434
+ name + "_" + "UpdateOutput"
435
+ )})
436
+ public async update(input: any) {
437
+ const index = this.items.findIndex((i) => i.id === input.id);
438
+ if (index === -1) {
439
+ throw new Error("Item not found");
440
+ }
441
+
442
+ this.items[index] = {
443
+ ...this.items[index],
444
+ ...input,
445
+ updatedAt: new Date(),
446
+ };
447
+
448
+ return this.items[index];
449
+ }
450
+
451
+ @Signature(${toCamelCase(name + "_" + "DeleteInput")}, ${toCamelCase(
452
+ name + "_" + "DeleteOutput"
453
+ )})
454
+ public async delete(input: any) {
455
+ const index = this.items.findIndex((i) => i.id === input.id);
456
+ if (index === -1) {
457
+ throw new Error("Item not found");
458
+ }
459
+
460
+ const deleted = this.items.splice(index, 1)[0];
461
+ return deleted;
462
+ }
463
+ }
464
+ `;
465
+ }
466
+
467
+ function createPage(name: string) {
468
+ const pageName = toPascalCase(name + "_" + "Page");
469
+ const serviceName = toPascalCase(name + "_" + "Service");
470
+ const serviceVar = toCamelCase(name + "_" + "Service");
471
+ const listComponent = toPascalCase(name + "_" + "List");
472
+
473
+ return `import { Component } from "@kithinji/orca";
474
+ import { ${serviceName} } from "./${name}.service";
475
+ import { ${listComponent} } from "./components/${name}-list.component";
476
+
477
+ @Component()
478
+ export class ${pageName} {
479
+ constructor(
480
+ public ${serviceVar}: ${serviceName}
481
+ ) {}
482
+
483
+ build() {
484
+ return (
485
+ <div>
486
+ <h1>${toPascalCase(name)} Management</h1>
487
+ <${listComponent} service={this.${serviceVar}} />
488
+ </div>
489
+ );
490
+ }
491
+ }
492
+ `;
493
+ }
494
+
495
+ function createListComponent(name: string) {
496
+ const componentName = toPascalCase(name + "_" + "List");
497
+ const serviceName = toPascalCase(name + "_" + "Service");
498
+
499
+ return `"use interactive";
500
+
501
+ import { Component } from "@kithinji/orca";
502
+ import { ${serviceName} } from "../${name}.service";
503
+
504
+ @Component()
505
+ export class ${componentName} {
506
+ props!: {
507
+ service: ${serviceName};
508
+ };
509
+
510
+ build() {
511
+ return (
512
+ <div>
513
+ <h2>${toPascalCase(name)} List</h2>
514
+ <p>List component for ${name}</p>
515
+ {/* Add your list implementation here */}
516
+ </div>
517
+ );
518
+ }
519
+ }
520
+ `;
521
+ }
@@ -0,0 +1,135 @@
1
+ import { createStructure, DirEntry } from "@/utils";
2
+ import path from "path";
3
+ import { addModule } from "../module";
4
+ import { addComponent } from "../component";
5
+
6
+ export function addNew(name: string) {
7
+ const baseDir = path.join(process.cwd(), name);
8
+
9
+ const structure: DirEntry = {
10
+ files: [
11
+ { name: "package.json", content: genPackageJson(name) },
12
+ { name: "tsconfig.json", content: gentsconfig() },
13
+ { name: "pod.config.ts", content: genPodConfig(name) },
14
+ { name: "README.md", content: genReadMe() },
15
+ { name: ".gitignore", content: genGitIgnore() },
16
+ { name: ".env", content: genEnv() },
17
+ ],
18
+ dirs: [
19
+ {
20
+ name: "src",
21
+ files: [{ name: "main.ts", content: genMainTs() }],
22
+ },
23
+ ],
24
+ };
25
+
26
+ createStructure(baseDir, structure);
27
+
28
+ const appDir = path.join(process.cwd(), name, "src", "app");
29
+
30
+ addModule("app", appDir);
31
+
32
+ process.chdir(baseDir);
33
+
34
+ addComponent("button");
35
+
36
+ console.log(`App ${name} created successfully`);
37
+ }
38
+
39
+ function genPackageJson(name: string) {
40
+ const pj = {
41
+ name,
42
+ private: true,
43
+ version: "0.0.0",
44
+ type: "module",
45
+ scripts: {
46
+ dev: "pod dev",
47
+ build: "pod build",
48
+ start: "pod start",
49
+ },
50
+ dependencies: {
51
+ "reflect-metadata": "latest",
52
+ zod: "^4.2.1",
53
+ "@kithinji/orca": "latest",
54
+ },
55
+ devDependencies: {
56
+ "@types/node": "^20.19.27",
57
+ typescript: "~5.9.3",
58
+ "@kithinji/pod": "latest",
59
+ },
60
+ };
61
+
62
+ return JSON.stringify(pj, null, 2);
63
+ }
64
+
65
+ function gentsconfig() {
66
+ const tsconfig = {
67
+ compilerOptions: {
68
+ target: "ES2020",
69
+ module: "ESNext",
70
+ moduleResolution: "bundler",
71
+ strict: true,
72
+ esModuleInterop: true,
73
+ skipLibCheck: true,
74
+ jsx: "react-jsx",
75
+ jsxImportSource: "@kithinji/orca",
76
+ experimentalDecorators: true,
77
+ emitDecoratorMetadata: true,
78
+ baseUrl: ".",
79
+ paths: {
80
+ "@/*": ["src/*"],
81
+ },
82
+ },
83
+ include: ["src"],
84
+ };
85
+
86
+ return JSON.stringify(tsconfig, null, 2);
87
+ }
88
+
89
+ function genPodConfig(name: string) {
90
+ return `import { PodConfig, stylePlugin } from "@kithinji/pod";
91
+
92
+ export default function defaultConfig(): PodConfig {
93
+ return {
94
+ name: "${name}",
95
+ client_plugins: [stylePlugin],
96
+ };
97
+ }
98
+ `;
99
+ }
100
+
101
+ function genReadMe() {
102
+ return `# Pod Project
103
+ `;
104
+ }
105
+
106
+ function genGitIgnore() {
107
+ return `node_modules
108
+ dist
109
+ build
110
+ .orca
111
+ *.log
112
+ .env
113
+ .DS_Store
114
+ `;
115
+ }
116
+
117
+ function genEnv() {
118
+ return `NODE_ENV=development
119
+ `;
120
+ }
121
+
122
+ function genMainTs() {
123
+ return `import { NodeFactory } from "@kithinji/orca";
124
+ import { AppModule } from "./app/app.module";
125
+
126
+ async function bootstrap() {
127
+ const app = await NodeFactory.create(AppModule);
128
+ app.listen(8080, () => {
129
+ console.log("Server started");
130
+ });
131
+ }
132
+
133
+ bootstrap();
134
+ `;
135
+ }