@kosdev-code/kos-nx-plugin 2.0.30 → 2.0.32

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 (35) hide show
  1. package/generators.json +5 -0
  2. package/package.json +2 -2
  3. package/src/generators/kos-add-future-to-model/README.md +106 -0
  4. package/src/generators/kos-add-future-to-model/generator.d.ts +5 -0
  5. package/src/generators/kos-add-future-to-model/generator.d.ts.map +1 -0
  6. package/src/generators/kos-add-future-to-model/generator.js +63 -0
  7. package/src/generators/kos-add-future-to-model/generator.js.map +1 -0
  8. package/src/generators/kos-add-future-to-model/lib/model-transformer.d.ts +17 -0
  9. package/src/generators/kos-add-future-to-model/lib/model-transformer.d.ts.map +1 -0
  10. package/src/generators/kos-add-future-to-model/lib/model-transformer.js +277 -0
  11. package/src/generators/kos-add-future-to-model/lib/model-transformer.js.map +1 -0
  12. package/src/generators/kos-add-future-to-model/lib/normalize-options.d.ts +4 -0
  13. package/src/generators/kos-add-future-to-model/lib/normalize-options.d.ts.map +1 -0
  14. package/src/generators/kos-add-future-to-model/lib/normalize-options.js +54 -0
  15. package/src/generators/kos-add-future-to-model/lib/normalize-options.js.map +1 -0
  16. package/src/generators/kos-add-future-to-model/lib/registration-transformer.d.ts +11 -0
  17. package/src/generators/kos-add-future-to-model/lib/registration-transformer.d.ts.map +1 -0
  18. package/src/generators/kos-add-future-to-model/lib/registration-transformer.js +73 -0
  19. package/src/generators/kos-add-future-to-model/lib/registration-transformer.js.map +1 -0
  20. package/src/generators/kos-add-future-to-model/lib/service-transformer.d.ts +13 -0
  21. package/src/generators/kos-add-future-to-model/lib/service-transformer.d.ts.map +1 -0
  22. package/src/generators/kos-add-future-to-model/lib/service-transformer.js +178 -0
  23. package/src/generators/kos-add-future-to-model/lib/service-transformer.js.map +1 -0
  24. package/src/generators/kos-add-future-to-model/schema.d.ts +24 -0
  25. package/src/generators/kos-add-future-to-model/schema.json +59 -0
  26. package/src/generators/kos-companion-model/files/types/index.d.ts.template +2 -2
  27. package/src/generators/kos-companion-model/schema.d.ts +1 -0
  28. package/src/generators/kos-model/files/model/__nameDashCase__-model.ts.template +93 -8
  29. package/src/generators/kos-model/files/model/__nameDashCase__-registration.ts.template +37 -3
  30. package/src/generators/kos-model/files/services/__nameDashCase__-services.ts.template +38 -2
  31. package/src/generators/kos-model/generator.d.ts.map +1 -1
  32. package/src/generators/kos-model/generator.js +2 -0
  33. package/src/generators/kos-model/generator.js.map +1 -1
  34. package/src/generators/kos-model/schema.d.ts +2 -0
  35. package/src/generators/kos-model/schema.json +41 -0
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RegistrationFileTransformer = void 0;
4
+ class RegistrationFileTransformer {
5
+ tree;
6
+ options;
7
+ constructor(tree, options) {
8
+ this.tree = tree;
9
+ this.options = options;
10
+ }
11
+ transform() {
12
+ const { registrationFilePath } = this.options;
13
+ if (!registrationFilePath || !this.tree.exists(registrationFilePath)) {
14
+ console.warn("Registration file not found, skipping registration updates");
15
+ return;
16
+ }
17
+ let content = this.tree.read(registrationFilePath, "utf-8");
18
+ content = this.addTypeCast(content);
19
+ content = this.updateDocumentation(content);
20
+ this.tree.write(registrationFilePath, content);
21
+ }
22
+ addTypeCast(content) {
23
+ const { nameProperCase } = this.options;
24
+ // Find the registration factory instantiation and add type cast
25
+ const factoryRegex = new RegExp(`class: ${nameProperCase}ModelImpl,`);
26
+ const replacement = `class: ${nameProperCase}ModelImpl as any, // Type cast needed for Future intersection`;
27
+ return content.replace(factoryRegex, replacement);
28
+ }
29
+ updateDocumentation(content) {
30
+ const { nameProperCase, futureType } = this.options;
31
+ // Add Future support documentation after the main description
32
+ const descriptionRegex = new RegExp(`(\\* The registration bean includes convenience methods for creating and working with ${nameProperCase}Model instances\\.)`);
33
+ const futureDocumentation = `$1
34
+ *
35
+ * ## Future Support
36
+ * This model includes ${futureType} Future support for tracking long-running operations with:
37
+ * - Progress tracking (0-1) with reactive updates
38
+ * - Status messages during operation
39
+ * - Cancellation support with bi-directional AbortController integration
40
+ * - Reactive integration for UI updates${futureType === "complete"
41
+ ? "\n * - Internal access to Future state for custom logic and computed properties"
42
+ : ""}`;
43
+ if (content.match(descriptionRegex)) {
44
+ content = content.replace(descriptionRegex, futureDocumentation);
45
+ }
46
+ // Add Future usage examples to factory documentation
47
+ const factoryExampleRegex = /(\*\s+\}\);?\s*\*\s+```)/;
48
+ const futureExample = `$1
49
+ *
50
+ * // Example: Accessing Future state (when a Future is active)
51
+ * const isRunning = model.futureIsRunning;
52
+ * const progress = model.futureProgress; // 0-1
53
+ * const status = model.futureStatus; // Current status message
54
+ * \`\`\``;
55
+ if (content.match(factoryExampleRegex)) {
56
+ content = content.replace(factoryExampleRegex, futureExample);
57
+ }
58
+ // Add Future capabilities to predicate examples
59
+ const predicateExampleRegex = /(\*\s+model\.updateAvailability\(false\);?\s*\*\s+\})/;
60
+ const predicateFutureExample = `$1
61
+ *
62
+ * // Future capabilities are also available
63
+ * const isRunning = model.futureIsRunning;
64
+ * const progress = model.futureProgress;
65
+ * }`;
66
+ if (content.match(predicateExampleRegex)) {
67
+ content = content.replace(predicateExampleRegex, predicateFutureExample);
68
+ }
69
+ return content;
70
+ }
71
+ }
72
+ exports.RegistrationFileTransformer = RegistrationFileTransformer;
73
+ //# sourceMappingURL=registration-transformer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registration-transformer.js","sourceRoot":"","sources":["../../../../../../../../packages/plugins/kos-nx-plugin/src/generators/kos-add-future-to-model/lib/registration-transformer.ts"],"names":[],"mappings":";;;AAGA,MAAa,2BAA2B;IAE5B;IACA;IAFV,YACU,IAAU,EACV,OAA4C;QAD5C,SAAI,GAAJ,IAAI,CAAM;QACV,YAAO,GAAP,OAAO,CAAqC;IACnD,CAAC;IAEJ,SAAS;QACP,MAAM,EAAE,oBAAoB,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC;QAE9C,IAAI,CAAC,oBAAoB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,oBAAoB,CAAC,EAAE,CAAC;YACrE,OAAO,CAAC,IAAI,CACV,4DAA4D,CAC7D,CAAC;YACF,OAAO;QACT,CAAC;QAED,IAAI,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,oBAAoB,EAAE,OAAO,CAAE,CAAC;QAE7D,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QACpC,OAAO,GAAG,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC;QAE5C,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,oBAAoB,EAAE,OAAO,CAAC,CAAC;IACjD,CAAC;IAEO,WAAW,CAAC,OAAe;QACjC,MAAM,EAAE,cAAc,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC;QAExC,gEAAgE;QAChE,MAAM,YAAY,GAAG,IAAI,MAAM,CAAC,UAAU,cAAc,YAAY,CAAC,CAAC;QAEtE,MAAM,WAAW,GAAG,UAAU,cAAc,gEAAgE,CAAC;QAE7G,OAAO,OAAO,CAAC,OAAO,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC;IACpD,CAAC;IAEO,mBAAmB,CAAC,OAAe;QACzC,MAAM,EAAE,cAAc,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC;QAEpD,8DAA8D;QAC9D,MAAM,gBAAgB,GAAG,IAAI,MAAM,CACjC,yFAAyF,cAAc,qBAAqB,CAC7H,CAAC;QAEF,MAAM,mBAAmB,GAAG;;;yBAGP,UAAU;;;;0CAKhC,UAAU,KAAK,UAAU;YACvB,CAAC,CAAC,iFAAiF;YACnF,CAAC,CAAC,EACN,EAAE,CAAC;QAEA,IAAI,OAAO,CAAC,KAAK,CAAC,gBAAgB,CAAC,EAAE,CAAC;YACpC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,gBAAgB,EAAE,mBAAmB,CAAC,CAAC;QACnE,CAAC;QAED,qDAAqD;QACrD,MAAM,mBAAmB,GAAG,0BAA0B,CAAC;QAEvD,MAAM,aAAa,GAAG;;;;;;UAMhB,CAAC;QAEP,IAAI,OAAO,CAAC,KAAK,CAAC,mBAAmB,CAAC,EAAE,CAAC;YACvC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,mBAAmB,EAAE,aAAa,CAAC,CAAC;QAChE,CAAC;QAED,gDAAgD;QAChD,MAAM,qBAAqB,GACzB,uDAAuD,CAAC;QAE1D,MAAM,sBAAsB,GAAG;;;;;KAK9B,CAAC;QAEF,IAAI,OAAO,CAAC,KAAK,CAAC,qBAAqB,CAAC,EAAE,CAAC;YACzC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,qBAAqB,EAAE,sBAAsB,CAAC,CAAC;QAC3E,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;CACF;AA5FD,kEA4FC"}
@@ -0,0 +1,13 @@
1
+ import { Tree } from "@nx/devkit";
2
+ import { NormalizedKosAddFutureToModelSchema } from "../schema";
3
+ export declare class ServiceFileTransformer {
4
+ private tree;
5
+ private options;
6
+ constructor(tree: Tree, options: NormalizedKosAddFutureToModelSchema);
7
+ transform(): void;
8
+ private createServicesFile;
9
+ private addFutureImports;
10
+ private addFutureService;
11
+ private addProgressTypes;
12
+ }
13
+ //# sourceMappingURL=service-transformer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-transformer.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/plugins/kos-nx-plugin/src/generators/kos-add-future-to-model/lib/service-transformer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAClC,OAAO,EAAE,mCAAmC,EAAE,MAAM,WAAW,CAAC;AAEhE,qBAAa,sBAAsB;IAE/B,OAAO,CAAC,IAAI;IACZ,OAAO,CAAC,OAAO;gBADP,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,mCAAmC;IAGtD,SAAS,IAAI,IAAI;IAkBjB,OAAO,CAAC,kBAAkB;IA+E1B,OAAO,CAAC,gBAAgB;IA8BxB,OAAO,CAAC,gBAAgB;IAkCxB,OAAO,CAAC,gBAAgB;CA4BzB"}
@@ -0,0 +1,178 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ServiceFileTransformer = void 0;
4
+ class ServiceFileTransformer {
5
+ tree;
6
+ options;
7
+ constructor(tree, options) {
8
+ this.tree = tree;
9
+ this.options = options;
10
+ }
11
+ transform() {
12
+ const { servicesFilePath } = this.options;
13
+ if (!servicesFilePath || !this.tree.exists(servicesFilePath)) {
14
+ // Create services file if it doesn't exist
15
+ this.createServicesFile();
16
+ return;
17
+ }
18
+ let content = this.tree.read(servicesFilePath, "utf-8");
19
+ content = this.addFutureImports(content);
20
+ content = this.addFutureService(content);
21
+ content = this.addProgressTypes(content);
22
+ this.tree.write(servicesFilePath, content);
23
+ }
24
+ createServicesFile() {
25
+ const { servicesFilePath, nameProperCase, nameDashCase, nameLowerCase } = this.options;
26
+ if (!servicesFilePath) {
27
+ return;
28
+ }
29
+ const content = `import {
30
+ KosLog,
31
+ type ClientResponse,
32
+ type DeepRequired,
33
+ type ElementType,
34
+ type ServiceResponse,
35
+ type FutureResponse
36
+ } from '@kosdev-code/kos-ui-sdk';
37
+
38
+ import API, { type KosApi, type ApiPath } from '../../../utils/service';
39
+
40
+ const log = KosLog.createLogger({name: "${nameDashCase}-service", group: "Services"});
41
+
42
+ const SERVICE_PATH: ApiPath = "ENTER_SERVICE_PATH"
43
+ export type ${nameProperCase}ClientResponse = ClientResponse<
44
+ KosApi,
45
+ typeof SERVICE_PATH,
46
+ 'get'
47
+ >;
48
+ export type ${nameProperCase}Response = DeepRequired<${nameProperCase}ClientResponse>;
49
+
50
+ /**
51
+ * @category Service
52
+ * Retrieves the initial ${nameLowerCase} data.
53
+ */
54
+ export const get${nameProperCase} = async (): Promise<ServiceResponse<${nameProperCase}Response>> => {
55
+ log.debug('sending GET for ${nameLowerCase}');
56
+ return await API.get(SERVICE_PATH);
57
+ };
58
+
59
+ /**
60
+ * @category Service - Future Operation
61
+ * Placeholder for a long-running operation that returns a Future for progress tracking
62
+ *
63
+ * Replace this with your actual long-running service operation
64
+ */
65
+ export const perform${nameProperCase}Operation = async (): Promise<FutureResponse> => {
66
+ // TODO: Implement your long-running service operation here
67
+ // This should return a Future that can be tracked for progress
68
+
69
+ log.debug('starting long-running ${nameLowerCase} operation');
70
+
71
+ // Example pattern:
72
+ // return API.post(OPERATION_SERVICE_PATH, {
73
+ // // operation parameters
74
+ // });
75
+
76
+ // Placeholder - replace with actual implementation
77
+ throw new Error('perform${nameProperCase}Operation not yet implemented');
78
+ };
79
+
80
+ // Additional Future-aware service types (add as needed)
81
+ export type ${nameProperCase}OperationProgress = {
82
+ // Define your progress data structure here
83
+ stage: string;
84
+ percentComplete: number;
85
+ currentItem?: string;
86
+ totalItems?: number;
87
+ };
88
+
89
+ export type ${nameProperCase}OperationResult = {
90
+ // Define your operation result structure here
91
+ success: boolean;
92
+ message?: string;
93
+ data?: any;
94
+ };
95
+ `;
96
+ this.tree.write(servicesFilePath, content);
97
+ }
98
+ addFutureImports(content) {
99
+ // Check if FutureResponse is already imported
100
+ if (content.includes("FutureResponse")) {
101
+ return content;
102
+ }
103
+ // Add FutureResponse to existing import
104
+ const importRegex = /import {\s*([^}]*)\s*} from '@kosdev-code\/kos-ui-sdk';/;
105
+ const importMatch = content.match(importRegex);
106
+ if (importMatch) {
107
+ const existingImports = importMatch[1];
108
+ if (existingImports.includes("FutureResponse")) {
109
+ return content; // Already imported
110
+ }
111
+ // Clean up existing imports and add FutureResponse
112
+ const cleanedImports = existingImports.trim().replace(/,\s*$/, ''); // Remove trailing comma
113
+ const newImports = cleanedImports
114
+ ? `${cleanedImports},\n type FutureResponse`
115
+ : `type FutureResponse`;
116
+ const newImportStatement = `import {\n ${newImports}\n} from '@kosdev-code/kos-ui-sdk';`;
117
+ return content.replace(importMatch[0], newImportStatement);
118
+ }
119
+ return content;
120
+ }
121
+ addFutureService(content) {
122
+ const { nameProperCase, nameLowerCase } = this.options;
123
+ // Check if Future service already exists
124
+ if (content.includes(`perform${nameProperCase}Operation`)) {
125
+ return content;
126
+ }
127
+ const futureService = `
128
+ /**
129
+ * @category Service - Future Operation
130
+ * Placeholder for a long-running operation that returns a Future for progress tracking
131
+ *
132
+ * Replace this with your actual long-running service operation
133
+ */
134
+ export const perform${nameProperCase}Operation = async (): Promise<FutureResponse> => {
135
+ // TODO: Implement your long-running service operation here
136
+ // This should return a Future that can be tracked for progress
137
+
138
+ log.debug('starting long-running ${nameLowerCase} operation');
139
+
140
+ // Example pattern:
141
+ // return API.post(OPERATION_SERVICE_PATH, {
142
+ // // operation parameters
143
+ // });
144
+
145
+ // Placeholder - replace with actual implementation
146
+ throw new Error('perform${nameProperCase}Operation not yet implemented');
147
+ };`;
148
+ // Add at the end of the file
149
+ return content + "\n" + futureService;
150
+ }
151
+ addProgressTypes(content) {
152
+ const { nameProperCase } = this.options;
153
+ // Check if progress types already exist
154
+ if (content.includes(`${nameProperCase}OperationProgress`)) {
155
+ return content;
156
+ }
157
+ const progressTypes = `
158
+ // Additional Future-aware service types (add as needed)
159
+ export type ${nameProperCase}OperationProgress = {
160
+ // Define your progress data structure here
161
+ stage: string;
162
+ percentComplete: number;
163
+ currentItem?: string;
164
+ totalItems?: number;
165
+ };
166
+
167
+ export type ${nameProperCase}OperationResult = {
168
+ // Define your operation result structure here
169
+ success: boolean;
170
+ message?: string;
171
+ data?: any;
172
+ };`;
173
+ // Add at the end of the file
174
+ return content + "\n" + progressTypes;
175
+ }
176
+ }
177
+ exports.ServiceFileTransformer = ServiceFileTransformer;
178
+ //# sourceMappingURL=service-transformer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-transformer.js","sourceRoot":"","sources":["../../../../../../../../packages/plugins/kos-nx-plugin/src/generators/kos-add-future-to-model/lib/service-transformer.ts"],"names":[],"mappings":";;;AAGA,MAAa,sBAAsB;IAEvB;IACA;IAFV,YACU,IAAU,EACV,OAA4C;QAD5C,SAAI,GAAJ,IAAI,CAAM;QACV,YAAO,GAAP,OAAO,CAAqC;IACnD,CAAC;IAEJ,SAAS;QACP,MAAM,EAAE,gBAAgB,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC;QAE1C,IAAI,CAAC,gBAAgB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,EAAE,CAAC;YAC7D,2CAA2C;YAC3C,IAAI,CAAC,kBAAkB,EAAE,CAAC;YAC1B,OAAO;QACT,CAAC;QAED,IAAI,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,OAAO,CAAE,CAAC;QAEzD,OAAO,GAAG,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;QACzC,OAAO,GAAG,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;QACzC,OAAO,GAAG,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;QAEzC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC;IAC7C,CAAC;IAEO,kBAAkB;QACxB,MAAM,EAAE,gBAAgB,EAAE,cAAc,EAAE,YAAY,EAAE,aAAa,EAAE,GACrE,IAAI,CAAC,OAAO,CAAC;QAEf,IAAI,CAAC,gBAAgB,EAAE,CAAC;YACtB,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG;;;;;;;;;;;0CAWsB,YAAY;;;cAGxC,cAAc;;;;;cAKd,cAAc,2BAA2B,cAAc;;;;2BAI1C,aAAa;;kBAEtB,cAAc,wCAAwC,cAAc;+BACvD,aAAa;;;;;;;;;;sBAUtB,cAAc;;;;qCAIC,aAAa;;;;;;;;4BAQtB,cAAc;;;;cAI5B,cAAc;;;;;;;;cAQd,cAAc;;;;;;CAM3B,CAAC;QAEE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC;IAC7C,CAAC;IAEO,gBAAgB,CAAC,OAAe;QACtC,8CAA8C;QAC9C,IAAI,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC;YACvC,OAAO,OAAO,CAAC;QACjB,CAAC;QAED,wCAAwC;QACxC,MAAM,WAAW,GACf,yDAAyD,CAAC;QAC5D,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QAE/C,IAAI,WAAW,EAAE,CAAC;YAChB,MAAM,eAAe,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC;YACvC,IAAI,eAAe,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC;gBAC/C,OAAO,OAAO,CAAC,CAAC,mBAAmB;YACrC,CAAC;YAED,mDAAmD;YACnD,MAAM,cAAc,GAAG,eAAe,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,wBAAwB;YAC5F,MAAM,UAAU,GAAG,cAAc;gBAC/B,CAAC,CAAC,GAAG,cAAc,0BAA0B;gBAC7C,CAAC,CAAC,qBAAqB,CAAC;YAE1B,MAAM,kBAAkB,GAAG,eAAe,UAAU,qCAAqC,CAAC;YAC1F,OAAO,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,kBAAkB,CAAC,CAAC;QAC7D,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAEO,gBAAgB,CAAC,OAAe;QACtC,MAAM,EAAE,cAAc,EAAE,aAAa,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC;QAEvD,yCAAyC;QACzC,IAAI,OAAO,CAAC,QAAQ,CAAC,UAAU,cAAc,WAAW,CAAC,EAAE,CAAC;YAC1D,OAAO,OAAO,CAAC;QACjB,CAAC;QAED,MAAM,aAAa,GAAG;;;;;;;sBAOJ,cAAc;;;;qCAIC,aAAa;;;;;;;;4BAQtB,cAAc;GACvC,CAAC;QAEA,6BAA6B;QAC7B,OAAO,OAAO,GAAG,IAAI,GAAG,aAAa,CAAC;IACxC,CAAC;IAEO,gBAAgB,CAAC,OAAe;QACtC,MAAM,EAAE,cAAc,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC;QAExC,wCAAwC;QACxC,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,cAAc,mBAAmB,CAAC,EAAE,CAAC;YAC3D,OAAO,OAAO,CAAC;QACjB,CAAC;QAED,MAAM,aAAa,GAAG;;cAEZ,cAAc;;;;;;;;cAQd,cAAc;;;;;GAKzB,CAAC;QAEA,6BAA6B;QAC7B,OAAO,OAAO,GAAG,IAAI,GAAG,aAAa,CAAC;IACxC,CAAC;CACF;AAnMD,wDAmMC"}
@@ -0,0 +1,24 @@
1
+ export interface KosAddFutureToModelSchema {
2
+ modelName: string;
3
+ modelProject: string;
4
+ futureType: "minimal" | "complete";
5
+ modelPath?: string;
6
+ updateServices?: boolean;
7
+ dryRun?: boolean;
8
+ }
9
+
10
+ export interface NormalizedKosAddFutureToModelSchema
11
+ extends KosAddFutureToModelSchema {
12
+ nameDashCase: string;
13
+ nameProperCase: string;
14
+ nameCamelCase: string;
15
+ namePascalCase: string;
16
+ nameConstantCase: string;
17
+ nameLowerCase: string;
18
+ projectRoot: string;
19
+ sourceRoot: string;
20
+ modelFilePath: string;
21
+ servicesFilePath?: string;
22
+ registrationFilePath?: string;
23
+ internal: boolean;
24
+ }
@@ -0,0 +1,59 @@
1
+ {
2
+ "$schema": "http://json-schema.org/schema",
3
+ "$id": "KosAddFutureToModel",
4
+ "title": "Add Future Support to Existing KOS Model",
5
+ "type": "object",
6
+ "properties": {
7
+ "modelName": {
8
+ "type": "string",
9
+ "description": "Name of the existing model to add Future support to",
10
+ "$default": {
11
+ "$source": "argv",
12
+ "index": 0
13
+ },
14
+ "x-prompt": "Which model do you want to add Future support to?"
15
+ },
16
+ "modelProject": {
17
+ "type": "string",
18
+ "description": "The project where the model is located",
19
+ "x-prompt": "Which project contains the model?",
20
+ "x-dropdown": "projects"
21
+ },
22
+ "futureType": {
23
+ "type": "string",
24
+ "description": "Type of Future support to add",
25
+ "enum": ["minimal", "complete"],
26
+ "default": "minimal",
27
+ "x-prompt": {
28
+ "message": "What type of Future support?",
29
+ "type": "list",
30
+ "items": [
31
+ {
32
+ "value": "minimal",
33
+ "label": "Minimal (external access only)"
34
+ },
35
+ {
36
+ "value": "complete",
37
+ "label": "Complete (internal + external access)"
38
+ }
39
+ ]
40
+ }
41
+ },
42
+ "modelPath": {
43
+ "type": "string",
44
+ "description": "Relative path to the model file within the project (optional - will be auto-detected)"
45
+ },
46
+ "updateServices": {
47
+ "type": "boolean",
48
+ "description": "Update the services file to include Future operations",
49
+ "default": true,
50
+ "x-prompt": "Update services file with Future operations?"
51
+ },
52
+ "dryRun": {
53
+ "type": "boolean",
54
+ "description": "Show what would be changed without making actual changes",
55
+ "default": false
56
+ }
57
+ },
58
+ "required": ["modelName", "modelProject"]
59
+ }
@@ -3,8 +3,8 @@ import type { <%= modelNameProperCase %>Options, <%= modelNameProperCase %>Model
3
3
 
4
4
 
5
5
  export type <%= companionModelNameProperCase %>Options = IKosCompanionOptions<
6
- <%= companionModelNameProperCase %>Model,
7
- <%= companionModelNameProperCase %>Options
6
+ <%= modelNameProperCase %>Model,
7
+ <%= modelNameProperCase %>Options
8
8
  >;
9
9
 
10
10
 
@@ -3,4 +3,5 @@ export interface KosCompanionModelGeneratorSchema {
3
3
  companionModelProject: string;
4
4
  modelName: string;
5
5
  modelProject: string;
6
+ companionPattern?: "composition" | "decorator";
6
7
  }
@@ -1,4 +1,8 @@
1
- <% if (internal) { %>import { kosModel<% if (parentAware) { %>, kosParentAware<% } %> } from "../../../core/core/decorators";
1
+ <% const hasFutureSupport = futureAware && futureAware !== 'none'; %>
2
+ <% const isCompleteFuture = futureAware === 'complete'; %>
3
+ <% const isCompositionCompanion = companion && companionPattern === 'composition'; %>
4
+ <% const isDecoratorCompanion = companion && companionPattern === 'decorator'; %>
5
+ <% if (internal) { %>import { kosModel<% if (parentAware) { %>, kosParentAware<% } %><% if (hasFutureSupport) { %>, kosFuture<% } %> } from "../../../core/core/decorators";
2
6
  import type {
3
7
  IKosDataModel,
4
8
  KosContextLogger,
@@ -6,29 +10,56 @@ import type {
6
10
  } from "../../../core/core/kosModel";
7
11
  import type { IKosIdentifiable } from "../../../core/core/types";
8
12
  import type { PublicModelInterface } from "../../../core/types";
9
- <% } else { %>import type { KosContextLogger, KosCreationContext, IKosDataModel, IKosIdentifiable, PublicModelInterface<% if (parentAware) { %>, kosParentAware<% } %> } from "@kosdev-code/kos-ui-sdk";
10
- import { kosModel } from "@kosdev-code/kos-ui-sdk";
13
+ <% if (hasFutureSupport) { %>import type {
14
+ ExternalFutureInterface,
15
+ FutureHandlerContainer<% if (isCompleteFuture) { %>,
16
+ FutureStateAccessor,
17
+ FutureUpdateHandler<% } %>,
18
+ FutureAwareContainer,
19
+ IFutureModel
20
+ } from "../../../models/types/future-interfaces";
21
+ import { setup<% if (isCompleteFuture) { %>Complete<% } else { %>Minimal<% } %>FutureSupport } from "../../../models/utils/kosmodel-compatible-future-mixin";<% } %>
22
+ <% if (isDecoratorCompanion) { %>import { setupCompanionDecoratorMixin, CompanionWithMixin } from "../../../models/utils/kosmodel-interface-companion-mixin";<% } %>
23
+ <% } else { %>import type { KosContextLogger, KosCreationContext, IKosDataModel, IKosIdentifiable, PublicModelInterface<% if (hasFutureSupport) { %>, ExternalFutureInterface, FutureHandlerContainer<% if (isCompleteFuture) { %>, FutureStateAccessor, FutureUpdateHandler<% } %>, FutureAwareContainer, IFutureModel<% } %><% if (isDecoratorCompanion) { %>, CompanionWithMixin<% } %> } from "@kosdev-code/kos-ui-sdk";
24
+ import { kosModel<% if (parentAware) { %>, kosParentAware<% } %><% if (hasFutureSupport) { %>, kosFuture, setup<% if (isCompleteFuture) { %>Complete<% } else { %>Minimal<% } %>FutureSupport<% } %><% if (isDecoratorCompanion) { %>, setupCompanionDecoratorMixin<% } %> } from "@kosdev-code/kos-ui-sdk";
11
25
  <% } %>
12
26
  import type { <%= nameProperCase %>Options} from "./types";
27
+ <% if (hasFutureSupport) { %>import type { <%= nameProperCase %>OperationProgress } from "./services";<% } %>
13
28
 
14
29
  <% if (companion) {%>
15
30
  import type { <%= companionModelProperCase %>Model } from "<%= companionModelProject %>";
16
31
  <% } %>
17
32
  export const MODEL_TYPE = "<%= nameDashCase %>-model";
18
33
 
19
- export type <%= nameProperCase %>Model = PublicModelInterface<<%= nameProperCase %>ModelImpl>;
34
+ export type <%= nameProperCase %>Model = PublicModelInterface<<%= nameProperCase %>ModelImpl><% if (hasFutureSupport) { %> & ExternalFutureInterface<<%= nameProperCase %>OperationProgress><% } %><% if (isDecoratorCompanion) { %> & CompanionWithMixin<<%= companionModelProperCase %>Model><% } %>;
20
35
 
21
36
  <% if (parentAware) { %>@kosParentAware()<% } %>
22
37
  @kosModel(MODEL_TYPE)
23
- export class <%= nameProperCase %>ModelImpl implements IKosDataModel, IKosIdentifiable {
38
+ export class <%= nameProperCase %>ModelImpl implements IKosDataModel, IKosIdentifiable<% if (isCompleteFuture) { %>, FutureUpdateHandler<% } %> {
24
39
  id: string;
25
40
  private logger: KosContextLogger;
26
- <% if (companion) { %>private <%= companionModelCamelCase %>: <%= companionModelProperCase %>Model;<% } %>
41
+ <% if (isCompositionCompanion) { %>
42
+ // Composition pattern - explicit parent access
43
+ public readonly parent: <%= companionModelProperCase %>Model;
44
+ <% } %>
45
+ <% if (hasFutureSupport) { %>
46
+ // Future support properties - guaranteed by framework
47
+ public futureHandler!: FutureAwareContainer<<%= nameProperCase %>OperationProgress>;<% if (isCompleteFuture) { %>
48
+ public future?: IFutureModel<<%= nameProperCase %>OperationProgress>; // Used internally for progress checks and custom logic<% } %><% } %>
49
+
27
50
  constructor(modelId: string, options: <%= nameProperCase %>Options, context: KosCreationContext) {
28
51
  this.id = modelId;
29
52
  this.logger = context.logger;
30
- <% if (companion) { %>
31
- this.<%= companionModelCamelCase %> = options.companionParent;
53
+ <% if (isCompositionCompanion) { %>
54
+ // Set parent from companionParent option for composition pattern
55
+ this.parent = options.companionParent;
56
+ <% } else if (isDecoratorCompanion) { %>
57
+ // Setup decorator mixin for transparent parent access
58
+ setupCompanionDecoratorMixin(this, options.companionParent);
59
+ <% } %>
60
+ <% if (hasFutureSupport) { %>
61
+ // Initialize Future support
62
+ setup<% if (isCompleteFuture) { %>Complete<% } else { %>Minimal<% } %>FutureSupport(this);
32
63
  <% } %>
33
64
  if (options) {
34
65
  // Assign options properties here.
@@ -39,6 +70,60 @@ export class <%= nameProperCase %>ModelImpl implements IKosDataModel, IKosIdent
39
70
  // Update model properties here.
40
71
  }
41
72
 
73
+ <% if (hasFutureSupport) { %>
74
+ /**
75
+ * Placeholder method for Future operations
76
+ * Replace this with your actual long-running operation
77
+ */
78
+ @kosFuture()
79
+ async performLongRunningOperation(): Promise<void> {
80
+ // TODO: Implement your long-running operation here
81
+ // This method should use a service that returns a Future for progress tracking
82
+
83
+ this.logger.debug(`Starting long-running operation for ${this.id}`);
84
+
85
+ // Example implementation pattern using services:
86
+ // import { perform<%= nameProperCase %>Operation } from './services';
87
+ //
88
+ // try {
89
+ // const future = await perform<%= nameProperCase %>Operation();
90
+ // return this.futureHandler.setFuture(future);
91
+ // } catch (error) {
92
+ // this.logger.error(`Failed to start operation for ${this.id}:`, error);
93
+ // throw error;
94
+ // }
95
+
96
+ // Placeholder that doesn't actually do anything
97
+ await new Promise(resolve => setTimeout(resolve, 1000));
98
+
99
+ this.logger.debug(`Completed long-running operation for ${this.id}`);
100
+ }
101
+ <% } %>
102
+
103
+ <% if (isCompleteFuture) { %>
104
+ /**
105
+ * Optional: Custom Future update handling
106
+ * Called whenever the Future state changes (progress, status, completion, etc.)
107
+ */
108
+ onFutureUpdate(update: IFutureModel<<%= nameProperCase %>OperationProgress>): void {
109
+ // Add custom Future update logic here
110
+ // Examples:
111
+ // - Log progress milestones
112
+ // - Update derived state based on progress
113
+ // - Handle specific error conditions
114
+ // - Trigger notifications at certain thresholds
115
+
116
+ this.logger.debug(`Future update for ${this.id}:`, {
117
+ progress: update.progress,
118
+ status: update.status,
119
+ endState: update.endState,
120
+ // Access typed progress data:
121
+ stage: update.data?.stage,
122
+ percentComplete: update.data?.percentComplete
123
+ });
124
+ }
125
+ <% } %>
126
+
42
127
  // -------------------LIFECYCLE----------------------------
43
128
 
44
129
 
@@ -1,12 +1,26 @@
1
+ <% const hasFutureSupport = futureAware && futureAware !== 'none'; %>
2
+ <% const hasCompanionSupport = companion; %>
3
+ <% const needsAnyCast = hasFutureSupport || hasCompanionSupport; %>
1
4
  import { <% if (singleton) { %>Singleton<% } %>KosModelRegistrationFactory } from "<% if (internal) {%>../../../core/core/registration<% } else { %>@kosdev-code/kos-ui-sdk<% } %>";
2
5
  import type { <%= nameProperCase %>Options } from "./types";
3
- import { <%= nameProperCase %>ModelImpl, MODEL_TYPE } from "./<%= nameDashCase %>-model";
4
- import type { <%= nameProperCase %>Model } from "./<%= nameDashCase %>-model";
6
+ import { <%= nameProperCase %>ModelImpl, MODEL_TYPE, <%= nameProperCase %>Model } from "./<%= nameDashCase %>-model";
5
7
 
6
8
  /**
7
9
  * # <%= nameProperCase %>
8
10
  *
9
11
  * The registration bean includes convenience methods for creating and working with <%= nameProperCase %>Model instances.
12
+ <% if (hasFutureSupport) { %>
13
+ *
14
+ * ## Future Support
15
+ * This model includes <%= futureAware %> Future support for tracking long-running operations with:
16
+ * - Progress tracking (0-1) with reactive updates
17
+ * - Status messages during operation
18
+ * - Cancellation support with bi-directional AbortController integration
19
+ * - Reactive integration for UI updates
20
+ <% if (futureAware === 'complete') { %>
21
+ * - Internal access to Future state for custom logic and computed properties
22
+ <% } %>
23
+ <% } %>
10
24
  *
11
25
  * ## type
12
26
  * The type property is a string that identifies the model type.
@@ -36,6 +50,13 @@ import type { <%= nameProperCase %>Model } from "./<%= nameDashCase %>-model";
36
50
  * const model = <%= nameProperCase %>.factory({
37
51
  * // Add option data
38
52
  * });
53
+ <% if (hasFutureSupport) { %>
54
+ *
55
+ * // Example: Accessing Future state (when a Future is active)
56
+ * const isRunning = model.futureIsRunning;
57
+ * const progress = model.futureProgress; // 0-1
58
+ * const status = model.futureStatus; // Current status message
59
+ <% } %>
39
60
  * ```
40
61
  <% } else { %>
41
62
  * The factory function is a curried function that takes the model id as the first argument and the options as the second argument.
@@ -48,6 +69,13 @@ import type { <%= nameProperCase %>Model } from "./<%= nameDashCase %>-model";
48
69
  * const model = <%= nameProperCase %>.factory("<%= nameCamelCase %>Id")({
49
70
  * // Add option data
50
71
  * });
72
+ <% if (hasFutureSupport) { %>
73
+ *
74
+ * // Example: Accessing Future state (when a Future is active)
75
+ * const isRunning = model.futureIsRunning;
76
+ * const progress = model.futureProgress; // 0-1
77
+ * const status = model.futureStatus; // Current status message
78
+ <% } %>
51
79
  * ```
52
80
  <% } %>
53
81
 
@@ -65,6 +93,12 @@ import type { <%= nameProperCase %>Model } from "./<%= nameDashCase %>-model";
65
93
  * // if the function evaluates to true, the model is narrowed down to <%= nameProperCase %>Model
66
94
  * // and the compiler will know that the model has the <%= nameProperCase %>Model interface
67
95
  * model.updateAvailability(false);
96
+ <% if (hasFutureSupport) { %>
97
+ *
98
+ * // Future capabilities are also available
99
+ * const isRunning = model.futureIsRunning;
100
+ * const progress = model.futureProgress;
101
+ <% } %>
68
102
  * }
69
103
  * ```
70
104
  *
@@ -105,6 +139,6 @@ export const <%= nameProperCase %> = new <% if (singleton) { %>Singleton<% } %>K
105
139
  <%= nameProperCase %>Model,
106
140
  <%= nameProperCase %>Options
107
141
  >({
108
- class: <%= nameProperCase %>ModelImpl,
142
+ class: <%= nameProperCase %>ModelImpl<% if (needsAnyCast) { %> as any<% } %>, <% if (needsAnyCast) { %>// Type cast needed for<% if (hasFutureSupport && hasCompanionSupport) { %> Future and companion<% } else if (hasFutureSupport) { %> Future<% } else { %> companion<% } %> intersection<% } %>
109
143
  type: MODEL_TYPE,
110
144
  });
@@ -1,9 +1,11 @@
1
+ <% const hasFutureSupport = futureAware && futureAware !== 'none'; %>
1
2
  import {
2
3
  KosLog,
3
4
  type ClientResponse,
4
5
  type DeepRequired,
5
6
  type ElementType,
6
- type ServiceResponse
7
+ type ServiceResponse<% if (hasFutureSupport) { %>,
8
+ type FutureResponse<% } %>
7
9
  } from '@kosdev-code/kos-ui-sdk';
8
10
 
9
11
  import API, { type KosApi, type ApiPath } from '../../../utils/service';
@@ -25,4 +27,38 @@ export type <%= nameProperCase %>Response = DeepRequired<<%= nameProperCase %>Cl
25
27
  export const get<%= nameProperCase %> = async (): Promise<ServiceResponse<<%= nameProperCase %>Response>> => {
26
28
  log.debug('sending GET for <%= name %>');
27
29
  return await API.get(SERVICE_PATH);
28
- };
30
+ };
31
+
32
+ <% if (hasFutureSupport) { %>
33
+ /**
34
+ * @category Service - Future Operation
35
+ * Placeholder for a long-running operation that returns a Future for progress tracking
36
+ *
37
+ * Replace this with your actual long-running service operation
38
+ */
39
+ export const perform<%= nameProperCase %>Operation = async (): Promise<FutureResponse> => {
40
+ // TODO: Implement your long-running service operation here
41
+ // This should return a Future that can be tracked for progress
42
+
43
+ log.debug('starting long-running <%= name %> operation');
44
+
45
+ // Example pattern:
46
+ // return API.post(OPERATION_SERVICE_PATH, {
47
+ // // operation parameters
48
+ // });
49
+
50
+ // Placeholder - replace with actual implementation
51
+ throw new Error('perform<%= nameProperCase %>Operation not yet implemented');
52
+ };
53
+
54
+ // Additional Future-aware service types (add as needed)
55
+ export type <%= nameProperCase %>OperationProgress = {
56
+ // Define your progress data structure here
57
+
58
+ };
59
+
60
+ export type <%= nameProperCase %>OperationResult = {
61
+ // Define your operation result structure here
62
+
63
+ };
64
+ <% } %>
@@ -1 +1 @@
1
- {"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../../../../../../packages/plugins/kos-nx-plugin/src/generators/kos-model/generator.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,IAAI,EAKL,MAAM,YAAY,CAAC;AAWpB,OAAO,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAC;AAEnD,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,uBAAuB,iBAwJjC;AAED,eAAe,iBAAiB,CAAC"}
1
+ {"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../../../../../../../packages/plugins/kos-nx-plugin/src/generators/kos-model/generator.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,IAAI,EAKL,MAAM,YAAY,CAAC;AAWpB,OAAO,EAAE,uBAAuB,EAAE,MAAM,UAAU,CAAC;AAEnD,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,uBAAuB,iBA2JjC;AAED,eAAe,iBAAiB,CAAC"}