@kinotic-ai/kinotic-cli 1.0.2 → 2.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 (69) hide show
  1. package/README.md +57 -22
  2. package/dist/commands/create/project.d.ts +10 -0
  3. package/dist/commands/create/project.js +62 -0
  4. package/dist/commands/generate.d.ts +2 -1
  5. package/dist/commands/generate.js +6 -4
  6. package/dist/commands/initialize.d.ts +4 -3
  7. package/dist/commands/initialize.js +21 -16
  8. package/dist/commands/synchronize.d.ts +6 -5
  9. package/dist/commands/synchronize.js +5 -4
  10. package/dist/internal/CommandHelper.d.ts +4 -0
  11. package/dist/internal/CommandHelper.js +29 -0
  12. package/dist/internal/{CodeGenerationService.d.ts → EntityCodeGenerationService.d.ts} +12 -3
  13. package/dist/internal/{CodeGenerationService.js → EntityCodeGenerationService.js} +69 -19
  14. package/dist/internal/GitChangeDetector.d.ts +24 -0
  15. package/dist/internal/GitChangeDetector.js +119 -0
  16. package/dist/internal/Utils.d.ts +6 -1
  17. package/dist/internal/Utils.js +10 -1
  18. package/dist/internal/converter/IConverterStrategy.d.ts +1 -1
  19. package/dist/internal/converter/codegen/ArrayC3TypeToStatementMapper.d.ts +2 -2
  20. package/dist/internal/converter/codegen/ObjectC3TypeToStatementMapper.d.ts +2 -2
  21. package/dist/internal/converter/codegen/PrimitiveC3TypeToStatementMapper.d.ts +2 -2
  22. package/dist/internal/converter/codegen/StatementMapper.js +1 -1
  23. package/dist/internal/converter/codegen/StatementMapperConversionState.d.ts +1 -1
  24. package/dist/internal/converter/codegen/StatementMapperConversionState.js +1 -1
  25. package/dist/internal/converter/codegen/StatementMapperConverterStrategy.d.ts +3 -3
  26. package/dist/internal/converter/codegen/UnionC3TypeToStatementMapper.d.ts +2 -2
  27. package/dist/internal/converter/codegen/UnionC3TypeToStatementMapper.js +1 -1
  28. package/dist/internal/converter/typescript/ArrayToC3Type.d.ts +2 -2
  29. package/dist/internal/converter/typescript/EnumToC3Type.d.ts +2 -2
  30. package/dist/internal/converter/typescript/ObjectLikeToC3Type.d.ts +2 -2
  31. package/dist/internal/converter/typescript/ObjectLikeToC3Type.js +1 -1
  32. package/dist/internal/converter/typescript/PrimitiveToC3Type.d.ts +1 -1
  33. package/dist/internal/converter/typescript/PrimitiveToC3Type.js +1 -1
  34. package/dist/internal/converter/typescript/QueryOptionsToC3Type.d.ts +2 -2
  35. package/dist/internal/converter/typescript/TenantSelectionToC3Type.d.ts +2 -2
  36. package/dist/internal/converter/typescript/TypescriptConversionState.d.ts +1 -1
  37. package/dist/internal/converter/typescript/TypescriptConversionState.js +1 -1
  38. package/dist/internal/converter/typescript/TypescriptConverterStrategy.d.ts +3 -3
  39. package/dist/internal/converter/typescript/UnionToC3Type.d.ts +2 -2
  40. package/dist/internal/spawn/SpawnConfig.d.ts +31 -0
  41. package/dist/internal/spawn/SpawnConfig.js +12 -0
  42. package/dist/internal/spawn/SpawnEngine.d.ts +27 -0
  43. package/dist/internal/spawn/SpawnEngine.js +187 -0
  44. package/dist/internal/spawn/SpawnResolver.d.ts +17 -0
  45. package/dist/internal/spawn/SpawnResolver.js +14 -0
  46. package/dist/templates/entity/AdminRepository.liquid +14 -0
  47. package/dist/templates/{BaseAdminEntityService.liquid → entity/BaseAdminRepository.liquid} +2 -2
  48. package/dist/templates/{BaseEntityService.liquid → entity/BaseRepository.liquid} +2 -2
  49. package/dist/templates/entity/Repository.liquid +14 -0
  50. package/dist/templates/spawns/library/package.json.liquid +30 -0
  51. package/dist/templates/spawns/library/spawn.json +8 -0
  52. package/dist/templates/spawns/library/src/index.ts +3 -0
  53. package/dist/templates/spawns/library/tsconfig.json +5 -0
  54. package/dist/templates/spawns/project/.config/kinotic.config.ts.liquid +16 -0
  55. package/dist/templates/spawns/project/bunup.config.ts.liquid +11 -0
  56. package/dist/templates/spawns/project/package.json.liquid +22 -0
  57. package/dist/templates/spawns/project/packages/domain/.gitkeep +0 -0
  58. package/dist/templates/spawns/project/packages/domain/model/.gitkeep +0 -0
  59. package/dist/templates/spawns/project/packages/domain/package.json.liquid +34 -0
  60. package/dist/templates/spawns/project/packages/domain/repositories/.gitkeep +0 -0
  61. package/dist/templates/spawns/project/packages/domain/tsconfig.json +5 -0
  62. package/dist/templates/spawns/project/packages/microservices/.gitkeep +0 -0
  63. package/dist/templates/spawns/project/packages/ui/.gitkeep +0 -0
  64. package/dist/templates/spawns/project/spawn.json +11 -0
  65. package/dist/templates/spawns/project/tsconfig.base.json +26 -0
  66. package/oclif.manifest.json +62 -10
  67. package/package.json +19 -10
  68. package/dist/templates/AdminEntityService.liquid +0 -14
  69. package/dist/templates/EntityService.liquid +0 -14
package/README.md CHANGED
@@ -12,7 +12,7 @@ $ npm install -g @kinotic-ai/kinotic-cli
12
12
  $ kinotic COMMAND
13
13
  running command...
14
14
  $ kinotic (--version)
15
- @kinotic-ai/kinotic-cli/1.0.2 darwin-arm64 node-v22.13.1
15
+ @kinotic-ai/kinotic-cli/2.0.0 darwin-arm64 node-v22.13.1
16
16
  $ kinotic --help [COMMAND]
17
17
  USAGE
18
18
  $ kinotic COMMAND
@@ -22,6 +22,7 @@ USAGE
22
22
  # Commands
23
23
  <!-- commands -->
24
24
  * [`kinotic autocomplete [SHELL]`](#kinotic-autocomplete-shell)
25
+ * [`kinotic create project NAME`](#kinotic-create-project-name)
25
26
  * [`kinotic gen`](#kinotic-gen)
26
27
  * [`kinotic generate`](#kinotic-generate)
27
28
  * [`kinotic help [COMMAND]`](#kinotic-help-command)
@@ -72,19 +73,40 @@ EXAMPLES
72
73
 
73
74
  _See code: [@oclif/plugin-autocomplete](https://github.com/oclif/plugin-autocomplete/blob/v3.2.41/src/commands/autocomplete/index.ts)_
74
75
 
76
+ ## `kinotic create project NAME`
77
+
78
+ Creates a Kinotic Project
79
+
80
+ ```
81
+ USAGE
82
+ $ kinotic create project NAME
83
+
84
+ ARGUMENTS
85
+ NAME The name for the project
86
+
87
+ DESCRIPTION
88
+ Creates a Kinotic Project
89
+
90
+ EXAMPLES
91
+ $ kinotic create project MyProjectName
92
+ ```
93
+
94
+ _See code: [src/commands/create/project.ts](https://github.com/kinotic-ai/kinotic/blob/v2.0.0/src/commands/create/project.ts)_
95
+
75
96
  ## `kinotic gen`
76
97
 
77
- This will generate all Entity Service classes.
98
+ This will generate all Repository classes.
78
99
 
79
100
  ```
80
101
  USAGE
81
- $ kinotic gen [-v]
102
+ $ kinotic gen [-v] [-f]
82
103
 
83
104
  FLAGS
105
+ -f, --force Force full regeneration, ignoring incremental change detection
84
106
  -v, --verbose Enable verbose logging
85
107
 
86
108
  DESCRIPTION
87
- This will generate all Entity Service classes.
109
+ This will generate all Repository classes.
88
110
 
89
111
  ALIASES
90
112
  $ kinotic gen
@@ -95,21 +117,24 @@ EXAMPLES
95
117
  $ kinotic gen
96
118
 
97
119
  $ kinotic gen -v
120
+
121
+ $ kinotic gen --force
98
122
  ```
99
123
 
100
124
  ## `kinotic generate`
101
125
 
102
- This will generate all Entity Service classes.
126
+ This will generate all Repository classes.
103
127
 
104
128
  ```
105
129
  USAGE
106
- $ kinotic generate [-v]
130
+ $ kinotic generate [-v] [-f]
107
131
 
108
132
  FLAGS
133
+ -f, --force Force full regeneration, ignoring incremental change detection
109
134
  -v, --verbose Enable verbose logging
110
135
 
111
136
  DESCRIPTION
112
- This will generate all Entity Service classes.
137
+ This will generate all Repository classes.
113
138
 
114
139
  ALIASES
115
140
  $ kinotic gen
@@ -120,9 +145,11 @@ EXAMPLES
120
145
  $ kinotic gen
121
146
 
122
147
  $ kinotic gen -v
148
+
149
+ $ kinotic gen --force
123
150
  ```
124
151
 
125
- _See code: [src/commands/generate.ts](https://github.com/kinotic-ai/kinotic/blob/v1.0.2/src/commands/generate.ts)_
152
+ _See code: [src/commands/generate.ts](https://github.com/kinotic-ai/kinotic/blob/v2.0.0/src/commands/generate.ts)_
126
153
 
127
154
  ## `kinotic help [COMMAND]`
128
155
 
@@ -150,12 +177,13 @@ This will initialize a new Kinotic Project for use with the Kinotic CLI.
150
177
 
151
178
  ```
152
179
  USAGE
153
- $ kinotic init [-a <value>] [-e <value>] [-g <value>]
180
+ $ kinotic init [-a <value>] [-e <value>] [-r <value>] [-m]
154
181
 
155
182
  FLAGS
156
183
  -a, --application=<value> The name of the application you want to use
157
184
  -e, --entities=<value> Path to the directory containing the Entity definitions
158
- -g, --generated=<value> Path to the directory to write generated Services
185
+ -m, --mirror Mirror the entity folder structure under the repository path
186
+ -r, --repository=<value> Path to the directory to write generated Repository classes
159
187
 
160
188
  DESCRIPTION
161
189
  This will initialize a new Kinotic Project for use with the Kinotic CLI.
@@ -164,11 +192,13 @@ ALIASES
164
192
  $ kinotic init
165
193
 
166
194
  EXAMPLES
167
- $ kinotic initialize --application my.app --entities path/to/entities --generated path/to/services
195
+ $ kinotic initialize --application my.app --entities path/to/entities --repository path/to/repository
168
196
 
169
- $ kinotic init --application my.app --entities path/to/entities --generated path/to/services
197
+ $ kinotic init --application my.app --entities path/to/entities --repository path/to/repository
170
198
 
171
- $ kinotic init -a my.app -e path/to/entities -g path/to/services
199
+ $ kinotic init -a my.app -e path/to/entities -r path/to/repository
200
+
201
+ $ kinotic init -a my.app -e path/to/entities -r path/to/repository --mirror
172
202
  ```
173
203
 
174
204
  ## `kinotic initialize`
@@ -177,12 +207,13 @@ This will initialize a new Kinotic Project for use with the Kinotic CLI.
177
207
 
178
208
  ```
179
209
  USAGE
180
- $ kinotic initialize [-a <value>] [-e <value>] [-g <value>]
210
+ $ kinotic initialize [-a <value>] [-e <value>] [-r <value>] [-m]
181
211
 
182
212
  FLAGS
183
213
  -a, --application=<value> The name of the application you want to use
184
214
  -e, --entities=<value> Path to the directory containing the Entity definitions
185
- -g, --generated=<value> Path to the directory to write generated Services
215
+ -m, --mirror Mirror the entity folder structure under the repository path
216
+ -r, --repository=<value> Path to the directory to write generated Repository classes
186
217
 
187
218
  DESCRIPTION
188
219
  This will initialize a new Kinotic Project for use with the Kinotic CLI.
@@ -191,14 +222,16 @@ ALIASES
191
222
  $ kinotic init
192
223
 
193
224
  EXAMPLES
194
- $ kinotic initialize --application my.app --entities path/to/entities --generated path/to/services
225
+ $ kinotic initialize --application my.app --entities path/to/entities --repository path/to/repository
226
+
227
+ $ kinotic init --application my.app --entities path/to/entities --repository path/to/repository
195
228
 
196
- $ kinotic init --application my.app --entities path/to/entities --generated path/to/services
229
+ $ kinotic init -a my.app -e path/to/entities -r path/to/repository
197
230
 
198
- $ kinotic init -a my.app -e path/to/entities -g path/to/services
231
+ $ kinotic init -a my.app -e path/to/entities -r path/to/repository --mirror
199
232
  ```
200
233
 
201
- _See code: [src/commands/initialize.ts](https://github.com/kinotic-ai/kinotic/blob/v1.0.2/src/commands/initialize.ts)_
234
+ _See code: [src/commands/initialize.ts](https://github.com/kinotic-ai/kinotic/blob/v2.0.0/src/commands/initialize.ts)_
202
235
 
203
236
  ## `kinotic plugins`
204
237
 
@@ -496,7 +529,7 @@ Synchronize the local Entity definitions with the Kinotic Server
496
529
 
497
530
  ```
498
531
  USAGE
499
- $ kinotic sync [-s <value>] [-p] [-v] [-f <value>] [--dryRun]
532
+ $ kinotic sync [-s <value>] [-p] [-v] [-f <value>] [--dryRun] [--force]
500
533
 
501
534
  FLAGS
502
535
  -f, --authHeaderFile=<value> JSON File containing authentication headers
@@ -504,6 +537,7 @@ FLAGS
504
537
  -s, --server=<value> The Kinotic server to connect to
505
538
  -v, --verbose Enable verbose logging
506
539
  --dryRun Dry run enables verbose logging and does not save any changes to the server
540
+ --force Force full regeneration, ignoring incremental change detection
507
541
 
508
542
  DESCRIPTION
509
543
  Synchronize the local Entity definitions with the Kinotic Server
@@ -527,7 +561,7 @@ Synchronize the local Entity definitions with the Kinotic Server
527
561
 
528
562
  ```
529
563
  USAGE
530
- $ kinotic synchronize [-s <value>] [-p] [-v] [-f <value>] [--dryRun]
564
+ $ kinotic synchronize [-s <value>] [-p] [-v] [-f <value>] [--dryRun] [--force]
531
565
 
532
566
  FLAGS
533
567
  -f, --authHeaderFile=<value> JSON File containing authentication headers
@@ -535,6 +569,7 @@ FLAGS
535
569
  -s, --server=<value> The Kinotic server to connect to
536
570
  -v, --verbose Enable verbose logging
537
571
  --dryRun Dry run enables verbose logging and does not save any changes to the server
572
+ --force Force full regeneration, ignoring incremental change detection
538
573
 
539
574
  DESCRIPTION
540
575
  Synchronize the local Entity definitions with the Kinotic Server
@@ -552,7 +587,7 @@ EXAMPLES
552
587
  $ kinotic sync -p -v -s http://localhost:9090
553
588
  ```
554
589
 
555
- _See code: [src/commands/synchronize.ts](https://github.com/kinotic-ai/kinotic/blob/v1.0.2/src/commands/synchronize.ts)_
590
+ _See code: [src/commands/synchronize.ts](https://github.com/kinotic-ai/kinotic/blob/v2.0.0/src/commands/synchronize.ts)_
556
591
 
557
592
  ## `kinotic update [CHANNEL]`
558
593
 
@@ -0,0 +1,10 @@
1
+ import { Command } from '@oclif/core';
2
+ export declare class Project extends Command {
3
+ static description: string;
4
+ static examples: string[];
5
+ static args: {
6
+ name: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
7
+ };
8
+ run(): Promise<void>;
9
+ private renderProjectModule;
10
+ }
@@ -0,0 +1,62 @@
1
+ import { Args, Command } from '@oclif/core';
2
+ import { input, select } from '@inquirer/prompts';
3
+ import chalk from 'chalk';
4
+ import ora from 'ora';
5
+ import path from 'node:path';
6
+ import process from 'node:process';
7
+ import { spawnEngine } from '../../internal/spawn/SpawnEngine.js';
8
+ import { createFrontEnd } from '../../internal/CommandHelper.js';
9
+ export class Project extends Command {
10
+ static description = 'Creates a Kinotic Project';
11
+ static examples = [
12
+ '$ kinotic create project MyProjectName',
13
+ ];
14
+ static args = {
15
+ name: Args.string({ description: 'The name for the project', required: true })
16
+ };
17
+ async run() {
18
+ const { args } = await this.parse(Project);
19
+ const projectDir = path.resolve(args.name);
20
+ let context = { projectName: args.name };
21
+ this.log(chalk.cyan('Creating Kinotic Project'));
22
+ const spinner = ora('Generating project...').start();
23
+ try {
24
+ context = (await spawnEngine.renderSpawn('project', projectDir, context)) ?? context;
25
+ spinner.succeed(chalk.green('Project generated'));
26
+ }
27
+ catch (err) {
28
+ spinner.fail('Project generation failed');
29
+ throw err;
30
+ }
31
+ process.chdir(projectDir);
32
+ let choice;
33
+ do {
34
+ choice = await select({
35
+ message: 'What would you like to add?',
36
+ choices: [{ value: 'Library' }, { value: 'Frontend' }, { value: 'Quit' }]
37
+ });
38
+ switch (choice) {
39
+ case 'Library': {
40
+ const libraryName = await input({ message: 'Library Name' });
41
+ context.libraryName = libraryName;
42
+ await this.renderProjectModule('library', libraryName, projectDir, context);
43
+ break;
44
+ }
45
+ case 'Frontend': {
46
+ const name = await input({ message: 'Project Name' });
47
+ await createFrontEnd(name);
48
+ break;
49
+ }
50
+ case 'Quit':
51
+ break;
52
+ }
53
+ } while (choice !== 'Quit');
54
+ }
55
+ async renderProjectModule(spawn, name, projectDir, context) {
56
+ const dir = path.resolve(name);
57
+ if (!dir.startsWith(projectDir)) {
58
+ throw new Error(`Module dir ${dir} must be within ${projectDir}`);
59
+ }
60
+ await spawnEngine.renderSpawn(spawn, dir, context);
61
+ }
62
+ }
@@ -4,7 +4,8 @@ export declare class Generate extends Command {
4
4
  static description: string;
5
5
  static examples: string[];
6
6
  static flags: {
7
- verbose: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
7
+ verbose: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
8
+ force: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
8
9
  };
9
10
  run(): Promise<void>;
10
11
  logVerbose(message: string | (() => string), verbose: boolean): void;
@@ -1,16 +1,18 @@
1
- import { CodeGenerationService } from '../internal/CodeGenerationService.js';
1
+ import { EntityCodeGenerationService } from '../internal/EntityCodeGenerationService.js';
2
2
  import { Command, Flags } from '@oclif/core';
3
3
  import { isKinoticProject, loadKinoticProjectConfig } from '../internal/state/KinoticProjectConfigUtil.js';
4
4
  export class Generate extends Command {
5
5
  static aliases = ['gen'];
6
- static description = 'This will generate all Entity Service classes.';
6
+ static description = 'This will generate all Repository classes.';
7
7
  static examples = [
8
8
  '$ kinotic generate',
9
9
  '$ kinotic gen',
10
10
  '$ kinotic gen -v',
11
+ '$ kinotic gen --force',
11
12
  ];
12
13
  static flags = {
13
14
  verbose: Flags.boolean({ char: 'v', description: 'Enable verbose logging', default: false }),
15
+ force: Flags.boolean({ char: 'f', description: 'Force full regeneration, ignoring incremental change detection', default: false }),
14
16
  };
15
17
  async run() {
16
18
  const { flags } = await this.parse(Generate);
@@ -18,8 +20,8 @@ export class Generate extends Command {
18
20
  this.error('The working directory is not a Kinotic Project');
19
21
  }
20
22
  const kinoticProjectConfig = await loadKinoticProjectConfig();
21
- const codeGenerationService = new CodeGenerationService(kinoticProjectConfig.application, kinoticProjectConfig.fileExtensionForImports, this);
22
- await codeGenerationService.generateAllEntities(kinoticProjectConfig, flags.verbose);
23
+ const codeGenerationService = new EntityCodeGenerationService(kinoticProjectConfig.application, kinoticProjectConfig.fileExtensionForImports, this);
24
+ await codeGenerationService.generateAllEntities(kinoticProjectConfig, flags.verbose, undefined, flags.force);
23
25
  this.log(`Code Generation Complete For application: ${kinoticProjectConfig.application}`);
24
26
  }
25
27
  // This is needed for the CodeGenerationService to log verbose messages
@@ -4,9 +4,10 @@ export declare class Initialize extends Command {
4
4
  static description: string;
5
5
  static examples: string[];
6
6
  static flags: {
7
- application: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
8
- entities: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
9
- generated: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
7
+ application: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
8
+ entities: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
9
+ repository: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
10
+ mirror: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
10
11
  };
11
12
  run(): Promise<void>;
12
13
  }
@@ -28,14 +28,16 @@ export class Initialize extends Command {
28
28
  static aliases = ['init'];
29
29
  static description = 'This will initialize a new Kinotic Project for use with the Kinotic CLI.';
30
30
  static examples = [
31
- '$ kinotic initialize --application my.app --entities path/to/entities --generated path/to/services',
32
- '$ kinotic init --application my.app --entities path/to/entities --generated path/to/services',
33
- '$ kinotic init -a my.app -e path/to/entities -g path/to/services',
31
+ '$ kinotic initialize --application my.app --entities path/to/entities --repository path/to/repository',
32
+ '$ kinotic init --application my.app --entities path/to/entities --repository path/to/repository',
33
+ '$ kinotic init -a my.app -e path/to/entities -r path/to/repository',
34
+ '$ kinotic init -a my.app -e path/to/entities -r path/to/repository --mirror',
34
35
  ];
35
36
  static flags = {
36
37
  application: Flags.string({ char: 'a', description: 'The name of the application you want to use', required: false }),
37
38
  entities: Flags.string({ char: 'e', description: 'Path to the directory containing the Entity definitions', required: false }),
38
- generated: Flags.string({ char: 'g', description: 'Path to the directory to write generated Services', required: false }),
39
+ repository: Flags.string({ char: 'r', description: 'Path to the directory to write generated Repository classes', required: false }),
40
+ mirror: Flags.boolean({ char: 'm', description: 'Mirror the entity folder structure under the repository path', default: true }),
39
41
  };
40
42
  async run() {
41
43
  const { flags } = await this.parse(Initialize);
@@ -67,33 +69,36 @@ export class Initialize extends Command {
67
69
  if (!entitiesPath) {
68
70
  entitiesPath = await input({
69
71
  message: 'Path to the directory containing Entity definitions:',
70
- default: 'src/entities',
72
+ default: 'src/model',
71
73
  validate: (input) => input.trim() !== '' || 'Entities path is required'
72
74
  });
73
75
  }
74
- let generatedPath = flags.generated;
75
- if (!generatedPath) {
76
- generatedPath = await input({
77
- message: 'Path to the directory to write generated Services:',
78
- default: 'src/generated',
79
- validate: (input) => input.trim() !== '' || 'Generated path is required'
76
+ let repositoryPath = flags.repository;
77
+ if (!repositoryPath) {
78
+ repositoryPath = await input({
79
+ message: 'Path to the directory to write generated Repository classes:',
80
+ default: 'src/repository',
81
+ validate: (input) => input.trim() !== '' || 'Repository path is required'
80
82
  });
81
83
  }
82
84
  const entitiesAbsPath = path.resolve(entitiesPath);
83
- const generatedAbsPath = path.resolve(generatedPath);
85
+ const repositoryAbsPath = path.resolve(repositoryPath);
84
86
  if (!fs.existsSync(entitiesAbsPath)) {
85
87
  this.error(`Entities path does not exist: ${entitiesAbsPath}`);
86
88
  }
87
- if (!fs.existsSync(generatedAbsPath)) {
88
- this.error(`Generated path does not exist: ${generatedAbsPath}`);
89
+ if (!fs.existsSync(repositoryAbsPath)) {
90
+ this.error(`Repository path does not exist: ${repositoryAbsPath}`);
89
91
  }
90
92
  // Only use TypescriptProjectConfig for initialization
91
93
  const configDir = path.resolve(process.cwd(), '.config');
92
94
  const configObj = new KinoticProjectConfig();
93
95
  // Don't set name - it will be loaded from package.json
94
96
  configObj.application = application;
95
- configObj.entitiesPaths = [entitiesPath];
96
- configObj.generatedPath = generatedPath;
97
+ configObj.entitiesPaths = [{
98
+ path: entitiesPath,
99
+ repositoryPath: repositoryPath,
100
+ mirrorFolderStructure: flags.mirror
101
+ }];
97
102
  configObj.validate = false;
98
103
  configObj.fileExtensionForImports = '.js';
99
104
  await saveKinoticProjectConfig(configObj, configDir);
@@ -4,11 +4,12 @@ export declare class Synchronize extends Command {
4
4
  static description: string;
5
5
  static examples: string[];
6
6
  static flags: {
7
- server: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
8
- publish: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
9
- verbose: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
10
- authHeaderFile: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
11
- dryRun: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
7
+ server: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
8
+ publish: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
9
+ verbose: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
10
+ authHeaderFile: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
11
+ dryRun: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
12
+ force: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
12
13
  };
13
14
  run(): Promise<void>;
14
15
  logVerbose(message: string | (() => string), verbose: boolean): void;
@@ -4,7 +4,7 @@ import { EntityDefinition, NamedQueriesDefinition, OsApiPlugin, Project, Project
4
4
  import { Command, Flags } from '@oclif/core';
5
5
  import chalk from 'chalk';
6
6
  import { WebSocket } from 'ws';
7
- import { CodeGenerationService } from '../internal/CodeGenerationService.js';
7
+ import { EntityCodeGenerationService } from '../internal/EntityCodeGenerationService.js';
8
8
  import { ProjectMigrationService } from '../internal/ProjectMigrationService.js';
9
9
  import { resolveServer } from '../internal/state/Environment.js';
10
10
  import { connectAndUpgradeSession } from '../internal/Utils.js';
@@ -25,7 +25,8 @@ export class Synchronize extends Command {
25
25
  publish: Flags.boolean({ char: 'p', description: 'Publish each Entity after save/update' }),
26
26
  verbose: Flags.boolean({ char: 'v', description: 'Enable verbose logging' }),
27
27
  authHeaderFile: Flags.string({ char: 'f', description: 'JSON File containing authentication headers', required: false }),
28
- dryRun: Flags.boolean({ description: 'Dry run enables verbose logging and does not save any changes to the server' })
28
+ dryRun: Flags.boolean({ description: 'Dry run enables verbose logging and does not save any changes to the server' }),
29
+ force: Flags.boolean({ description: 'Force full regeneration, ignoring incremental change detection', default: false })
29
30
  };
30
31
  async run() {
31
32
  const { flags } = await this.parse(Synchronize);
@@ -48,7 +49,7 @@ export class Synchronize extends Command {
48
49
  project.sourceOfTruth = ProjectType.TYPESCRIPT;
49
50
  project = await Kinotic.projects.createProjectIfNotExist(project);
50
51
  }
51
- const codeGenerationService = new CodeGenerationService(kinoticProjectConfig.application, kinoticProjectConfig.fileExtensionForImports, this);
52
+ const codeGenerationService = new EntityCodeGenerationService(kinoticProjectConfig.application, kinoticProjectConfig.fileExtensionForImports, this);
52
53
  await codeGenerationService
53
54
  .generateAllEntities(kinoticProjectConfig, flags.verbose || flags.dryRun, async (entityInfo, services) => {
54
55
  // combine named queries from generated services
@@ -66,7 +67,7 @@ export class Synchronize extends Command {
66
67
  if (!flags.dryRun) {
67
68
  await this.synchronizeEntity(project.id, entityInfo.entity, flags.publish, flags.verbose);
68
69
  }
69
- });
70
+ }, flags.force);
70
71
  // Apply migrations after entity synchronization
71
72
  if (!flags.dryRun) {
72
73
  const migrationService = new ProjectMigrationService(this);
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Creates a new front end project using either React or Vue depending on the user's choice
3
+ */
4
+ export declare function createFrontEnd(name: string): Promise<void>;
@@ -0,0 +1,29 @@
1
+ import { select } from '@inquirer/prompts';
2
+ import { execa } from 'execa';
3
+ /**
4
+ * Creates a new front end project using either React or Vue depending on the user's choice
5
+ */
6
+ export async function createFrontEnd(name) {
7
+ const framework = await select({
8
+ message: 'Which framework would you like to use?',
9
+ choices: [{ value: 'React' }, { value: 'Vue' }]
10
+ });
11
+ if (framework === 'React') {
12
+ await createReact(name);
13
+ }
14
+ else {
15
+ await createVue(name);
16
+ }
17
+ }
18
+ /**
19
+ * Creates a new React project using create-react-app
20
+ */
21
+ async function createReact(name) {
22
+ await execa('npx', ['create-react-app', name], { stdio: 'inherit' });
23
+ }
24
+ /**
25
+ * Creates a new Vue project using vue-cli with npx
26
+ */
27
+ async function createVue(name) {
28
+ await execa('npx', ['@vue/cli', 'create', name], { stdio: 'inherit' });
29
+ }
@@ -5,16 +5,25 @@ export type GeneratedEntityProcessor = (entityInfo: EntityInfo, serviceInfo: Gen
5
5
  /**
6
6
  * Helper service for generating code.s
7
7
  */
8
- export declare class CodeGenerationService {
8
+ export declare class EntityCodeGenerationService {
9
9
  private readonly fileExtensionForImports;
10
10
  private readonly logger;
11
11
  private readonly engine;
12
12
  private readonly tsMorphProject;
13
13
  private readonly conversionContext;
14
14
  constructor(application: string, fileExtensionForImports: string, logger: Logger);
15
- generateAllEntities(projectConfig: KinoticProjectConfig, verbose: boolean, entityProcessor?: GeneratedEntityProcessor): Promise<void>;
15
+ generateAllEntities(projectConfig: KinoticProjectConfig, verbose: boolean, entityProcessor?: GeneratedEntityProcessor, force?: boolean): Promise<void>;
16
+ /**
17
+ * Normalizes an entitiesPaths entry into a fully resolved {@link EntitiesPathConfig}.
18
+ */
19
+ private resolveEntitiesPathConfig;
16
20
  private processEntities;
17
- private generateEntityService;
21
+ /**
22
+ * Resolves the output path for generated repository files based on the entity's source location
23
+ * and the path configuration.
24
+ */
25
+ private resolveRepositoryOutputPath;
26
+ private generateRepository;
18
27
  /**
19
28
  * Adds invocation logic to named queries and returns the {@link FunctionDefinition}s that define them.
20
29
  */