@expressots/cli 3.0.0 → 4.0.0-preview.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 (180) hide show
  1. package/README.md +41 -95
  2. package/bin/cicd/cli.d.ts +6 -0
  3. package/bin/cicd/cli.js +126 -0
  4. package/bin/cicd/form.d.ts +29 -0
  5. package/bin/cicd/form.js +345 -0
  6. package/bin/cicd/generators/azure-devops.d.ts +2 -0
  7. package/bin/cicd/generators/azure-devops.js +370 -0
  8. package/bin/cicd/generators/bitbucket.d.ts +2 -0
  9. package/bin/cicd/generators/bitbucket.js +217 -0
  10. package/bin/cicd/generators/circleci.d.ts +2 -0
  11. package/bin/cicd/generators/circleci.js +274 -0
  12. package/bin/cicd/generators/github-actions.d.ts +14 -0
  13. package/bin/cicd/generators/github-actions.js +426 -0
  14. package/bin/cicd/generators/gitlab-ci.d.ts +2 -0
  15. package/bin/cicd/generators/gitlab-ci.js +237 -0
  16. package/bin/cicd/generators/index.d.ts +6 -0
  17. package/bin/cicd/generators/index.js +15 -0
  18. package/bin/cicd/generators/jenkins.d.ts +2 -0
  19. package/bin/cicd/generators/jenkins.js +248 -0
  20. package/bin/cicd/generators/template-loader.d.ts +17 -0
  21. package/bin/cicd/generators/template-loader.js +128 -0
  22. package/bin/cicd/index.d.ts +1 -0
  23. package/bin/cicd/index.js +5 -0
  24. package/bin/cli.d.ts +1 -1
  25. package/bin/cli.js +18 -3
  26. package/bin/commands/project.commands.d.ts +19 -6
  27. package/bin/commands/project.commands.js +390 -61
  28. package/bin/config/index.d.ts +5 -0
  29. package/bin/config/index.js +10 -0
  30. package/bin/config/manager.d.ts +98 -0
  31. package/bin/config/manager.js +222 -0
  32. package/bin/containerize/analyzers/bootstrap-analyzer.d.ts +46 -0
  33. package/bin/containerize/analyzers/bootstrap-analyzer.js +187 -0
  34. package/bin/containerize/analyzers/project-analyzer.d.ts +20 -0
  35. package/bin/containerize/analyzers/project-analyzer.js +150 -0
  36. package/bin/containerize/cli.d.ts +4 -0
  37. package/bin/containerize/cli.js +113 -0
  38. package/bin/containerize/form.d.ts +15 -0
  39. package/bin/containerize/form.js +154 -0
  40. package/bin/containerize/generators/ci-generator.d.ts +31 -0
  41. package/bin/containerize/generators/ci-generator.js +936 -0
  42. package/bin/containerize/generators/docker-compose-generator.d.ts +8 -0
  43. package/bin/containerize/generators/docker-compose-generator.js +186 -0
  44. package/bin/containerize/generators/dockerfile-generator.d.ts +8 -0
  45. package/bin/containerize/generators/dockerfile-generator.js +635 -0
  46. package/bin/containerize/generators/kubernetes-generator.d.ts +8 -0
  47. package/bin/containerize/generators/kubernetes-generator.js +133 -0
  48. package/bin/containerize/generators/template-loader.d.ts +36 -0
  49. package/bin/containerize/generators/template-loader.js +129 -0
  50. package/bin/containerize/index.d.ts +4 -0
  51. package/bin/containerize/index.js +13 -0
  52. package/bin/containerize/presets/preset-registry.d.ts +20 -0
  53. package/bin/containerize/presets/preset-registry.js +102 -0
  54. package/bin/costs/cli.d.ts +5 -0
  55. package/bin/costs/cli.js +183 -0
  56. package/bin/costs/form.d.ts +44 -0
  57. package/bin/costs/form.js +412 -0
  58. package/bin/costs/index.d.ts +4 -0
  59. package/bin/costs/index.js +25 -0
  60. package/bin/costs/pricing-manager.d.ts +84 -0
  61. package/bin/costs/pricing-manager.js +342 -0
  62. package/bin/costs/providers/index.d.ts +32 -0
  63. package/bin/costs/providers/index.js +153 -0
  64. package/bin/costs/sources/api-source.d.ts +10 -0
  65. package/bin/costs/sources/api-source.js +32 -0
  66. package/bin/costs/sources/index.d.ts +6 -0
  67. package/bin/costs/sources/index.js +15 -0
  68. package/bin/costs/sources/local-json-source.d.ts +23 -0
  69. package/bin/costs/sources/local-json-source.js +59 -0
  70. package/bin/costs/sources/remote-json-source.d.ts +11 -0
  71. package/bin/costs/sources/remote-json-source.js +53 -0
  72. package/bin/costs/types.d.ts +53 -0
  73. package/bin/costs/types.js +5 -0
  74. package/bin/dev/cli.d.ts +4 -0
  75. package/bin/dev/cli.js +134 -0
  76. package/bin/dev/form.d.ts +36 -0
  77. package/bin/dev/form.js +254 -0
  78. package/bin/dev/index.d.ts +1 -0
  79. package/bin/dev/index.js +5 -0
  80. package/bin/generate/cli.js +29 -2
  81. package/bin/generate/form.d.ts +5 -1
  82. package/bin/generate/form.js +3 -3
  83. package/bin/generate/templates/nonopinionated/config.tpl +12 -0
  84. package/bin/generate/templates/nonopinionated/event.tpl +10 -0
  85. package/bin/generate/templates/nonopinionated/guard.tpl +18 -0
  86. package/bin/generate/templates/nonopinionated/handler.tpl +12 -0
  87. package/bin/generate/templates/nonopinionated/interceptor.tpl +27 -0
  88. package/bin/generate/templates/opinionated/config.tpl +47 -0
  89. package/bin/generate/templates/opinionated/entity.tpl +1 -8
  90. package/bin/generate/templates/opinionated/event.tpl +15 -0
  91. package/bin/generate/templates/opinionated/guard.tpl +41 -0
  92. package/bin/generate/templates/opinionated/handler.tpl +23 -0
  93. package/bin/generate/templates/opinionated/interceptor.tpl +50 -0
  94. package/bin/generate/utils/command-utils.d.ts +7 -3
  95. package/bin/generate/utils/command-utils.js +95 -31
  96. package/bin/generate/utils/nonopininated-cmd.d.ts +10 -1
  97. package/bin/generate/utils/nonopininated-cmd.js +100 -1
  98. package/bin/generate/utils/opinionated-cmd.d.ts +10 -1
  99. package/bin/generate/utils/opinionated-cmd.js +112 -7
  100. package/bin/generate/utils/string-utils.d.ts +6 -0
  101. package/bin/generate/utils/string-utils.js +13 -1
  102. package/bin/help/form.js +11 -3
  103. package/bin/migrate/analyzers/platform-detector.d.ts +14 -0
  104. package/bin/migrate/analyzers/platform-detector.js +116 -0
  105. package/bin/migrate/cli.d.ts +6 -0
  106. package/bin/migrate/cli.js +96 -0
  107. package/bin/migrate/form.d.ts +25 -0
  108. package/bin/migrate/form.js +347 -0
  109. package/bin/migrate/generators/compose-to-k8s.d.ts +2 -0
  110. package/bin/migrate/generators/compose-to-k8s.js +324 -0
  111. package/bin/migrate/generators/compose-to-railway.d.ts +2 -0
  112. package/bin/migrate/generators/compose-to-railway.js +138 -0
  113. package/bin/migrate/generators/compose-to-render.d.ts +2 -0
  114. package/bin/migrate/generators/compose-to-render.js +148 -0
  115. package/bin/migrate/generators/generic-migration.d.ts +9 -0
  116. package/bin/migrate/generators/generic-migration.js +221 -0
  117. package/bin/migrate/generators/heroku-to-fly.d.ts +2 -0
  118. package/bin/migrate/generators/heroku-to-fly.js +291 -0
  119. package/bin/migrate/generators/heroku-to-railway.d.ts +2 -0
  120. package/bin/migrate/generators/heroku-to-railway.js +283 -0
  121. package/bin/migrate/generators/heroku-to-render.d.ts +2 -0
  122. package/bin/migrate/generators/heroku-to-render.js +148 -0
  123. package/bin/migrate/generators/index.d.ts +7 -0
  124. package/bin/migrate/generators/index.js +17 -0
  125. package/bin/migrate/generators/template-loader.d.ts +21 -0
  126. package/bin/migrate/generators/template-loader.js +59 -0
  127. package/bin/migrate/index.d.ts +1 -0
  128. package/bin/migrate/index.js +5 -0
  129. package/bin/new/cli.js +21 -6
  130. package/bin/new/form.d.ts +25 -4
  131. package/bin/new/form.js +285 -70
  132. package/bin/profile/analyzers/dockerfile-analyzer.d.ts +27 -0
  133. package/bin/profile/analyzers/dockerfile-analyzer.js +122 -0
  134. package/bin/profile/analyzers/image-analyzer.d.ts +19 -0
  135. package/bin/profile/analyzers/image-analyzer.js +85 -0
  136. package/bin/profile/cli.d.ts +4 -0
  137. package/bin/profile/cli.js +92 -0
  138. package/bin/profile/form.d.ts +56 -0
  139. package/bin/profile/form.js +400 -0
  140. package/bin/profile/index.d.ts +1 -0
  141. package/bin/profile/index.js +5 -0
  142. package/bin/profile/optimizers/index.d.ts +19 -0
  143. package/bin/profile/optimizers/index.js +137 -0
  144. package/bin/providers/add/form.d.ts +1 -1
  145. package/bin/providers/add/form.js +27 -6
  146. package/bin/providers/create/form.js +2 -1
  147. package/bin/scripts/form.js +27 -5
  148. package/bin/studio/cli.d.ts +15 -0
  149. package/bin/studio/cli.js +166 -0
  150. package/bin/studio/index.d.ts +5 -0
  151. package/bin/studio/index.js +9 -0
  152. package/bin/templates/cache.d.ts +54 -0
  153. package/bin/templates/cache.js +180 -0
  154. package/bin/templates/cli.d.ts +8 -0
  155. package/bin/templates/cli.js +292 -0
  156. package/bin/templates/fetcher.d.ts +49 -0
  157. package/bin/templates/fetcher.js +208 -0
  158. package/bin/templates/index.d.ts +11 -0
  159. package/bin/templates/index.js +37 -0
  160. package/bin/templates/manager.d.ts +116 -0
  161. package/bin/templates/manager.js +323 -0
  162. package/bin/templates/renderer.d.ts +49 -0
  163. package/bin/templates/renderer.js +204 -0
  164. package/bin/templates/types.d.ts +51 -0
  165. package/bin/templates/types.js +5 -0
  166. package/bin/utils/add-module-to-container.d.ts +2 -2
  167. package/bin/utils/add-module-to-container.js +15 -5
  168. package/bin/utils/cli-ui.d.ts +30 -3
  169. package/bin/utils/cli-ui.js +95 -13
  170. package/bin/utils/index.d.ts +4 -0
  171. package/bin/utils/index.js +4 -0
  172. package/bin/utils/input-validation.d.ts +50 -0
  173. package/bin/utils/input-validation.js +143 -0
  174. package/bin/utils/package-manager-commands.d.ts +24 -0
  175. package/bin/utils/package-manager-commands.js +50 -0
  176. package/bin/utils/safe-spawn.d.ts +35 -0
  177. package/bin/utils/safe-spawn.js +51 -0
  178. package/bin/utils/update-tsconfig-paths.d.ts +35 -0
  179. package/bin/utils/update-tsconfig-paths.js +286 -0
  180. package/package.json +154 -154
@@ -0,0 +1,208 @@
1
+ "use strict";
2
+ /**
3
+ * Template fetcher - fetches templates from GitHub repository
4
+ */
5
+ var __importDefault = (this && this.__importDefault) || function (mod) {
6
+ return (mod && mod.__esModule) ? mod : { "default": mod };
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.resetFetcher = exports.getGitHubFetcher = exports.GitHubFetcher = void 0;
10
+ const https_1 = __importDefault(require("https"));
11
+ const DEFAULT_REPO = "expressots/templates";
12
+ const DEFAULT_BRANCH = "main";
13
+ const GITHUB_RAW_BASE = "https://raw.githubusercontent.com";
14
+ const FETCH_TIMEOUT = 5000; // 5 seconds for faster fallback
15
+ class GitHubFetcher {
16
+ constructor(config) {
17
+ this.retryCount = 1; // Single retry for faster fallback
18
+ this.retryDelay = 500;
19
+ this.config = {
20
+ repository: config?.repository || DEFAULT_REPO,
21
+ branch: config?.branch || DEFAULT_BRANCH,
22
+ timeout: config?.timeout || FETCH_TIMEOUT,
23
+ };
24
+ }
25
+ /**
26
+ * Build raw GitHub URL for a file
27
+ */
28
+ buildUrl(filePath) {
29
+ return `${GITHUB_RAW_BASE}/${this.config.repository}/${this.config.branch}/${filePath}`;
30
+ }
31
+ /**
32
+ * Fetch content from URL with retry logic
33
+ */
34
+ async fetchWithRetry(url, attempt = 1) {
35
+ return new Promise((resolve, reject) => {
36
+ const request = https_1.default.get(url, { timeout: this.config.timeout }, (response) => {
37
+ // Handle redirects
38
+ if (response.statusCode === 301 ||
39
+ response.statusCode === 302) {
40
+ const redirectUrl = response.headers.location;
41
+ if (redirectUrl) {
42
+ this.fetchWithRetry(redirectUrl, attempt)
43
+ .then(resolve)
44
+ .catch(reject);
45
+ return;
46
+ }
47
+ }
48
+ if (response.statusCode === 404) {
49
+ reject(new Error(`Template not found: ${url}`));
50
+ return;
51
+ }
52
+ if (response.statusCode === 403) {
53
+ // Rate limited
54
+ if (attempt < this.retryCount) {
55
+ setTimeout(() => {
56
+ this.fetchWithRetry(url, attempt + 1)
57
+ .then(resolve)
58
+ .catch(reject);
59
+ }, this.retryDelay * Math.pow(2, attempt - 1));
60
+ return;
61
+ }
62
+ reject(new Error("GitHub API rate limit exceeded"));
63
+ return;
64
+ }
65
+ if (response.statusCode !== 200) {
66
+ reject(new Error(`HTTP ${response.statusCode}: Failed to fetch ${url}`));
67
+ return;
68
+ }
69
+ let data = "";
70
+ response.on("data", (chunk) => {
71
+ data += chunk;
72
+ });
73
+ response.on("end", () => {
74
+ resolve(data);
75
+ });
76
+ });
77
+ request.on("error", (error) => {
78
+ if (attempt < this.retryCount) {
79
+ setTimeout(() => {
80
+ this.fetchWithRetry(url, attempt + 1)
81
+ .then(resolve)
82
+ .catch(reject);
83
+ }, this.retryDelay * Math.pow(2, attempt - 1));
84
+ }
85
+ else {
86
+ reject(error);
87
+ }
88
+ });
89
+ request.on("timeout", () => {
90
+ request.destroy();
91
+ if (attempt < this.retryCount) {
92
+ setTimeout(() => {
93
+ this.fetchWithRetry(url, attempt + 1)
94
+ .then(resolve)
95
+ .catch(reject);
96
+ }, this.retryDelay * Math.pow(2, attempt - 1));
97
+ }
98
+ else {
99
+ reject(new Error(`Timeout fetching ${url}`));
100
+ }
101
+ });
102
+ });
103
+ }
104
+ /**
105
+ * Fetch template manifest
106
+ */
107
+ async fetchManifest() {
108
+ try {
109
+ const url = this.buildUrl("manifest.json");
110
+ const content = await this.fetchWithRetry(url);
111
+ const manifest = JSON.parse(content);
112
+ return { data: manifest, source: "remote" };
113
+ }
114
+ catch (error) {
115
+ return {
116
+ data: null,
117
+ source: "remote",
118
+ error: error instanceof Error ? error.message : "Unknown error",
119
+ };
120
+ }
121
+ }
122
+ /**
123
+ * Fetch template content by path
124
+ */
125
+ async fetchTemplate(templatePath) {
126
+ try {
127
+ const url = this.buildUrl(templatePath);
128
+ const content = await this.fetchWithRetry(url);
129
+ return { data: content, source: "remote" };
130
+ }
131
+ catch (error) {
132
+ return {
133
+ data: null,
134
+ source: "remote",
135
+ error: error instanceof Error ? error.message : "Unknown error",
136
+ };
137
+ }
138
+ }
139
+ /**
140
+ * Fetch template by category, platform, and variant
141
+ */
142
+ async fetchByType(category, platform, variant) {
143
+ // Build the path based on category
144
+ let templatePath;
145
+ switch (category) {
146
+ case "cicd":
147
+ templatePath = `cicd/${platform}/${variant || "basic"}.yml`;
148
+ break;
149
+ case "docker":
150
+ templatePath = `docker/${platform}.tpl`;
151
+ break;
152
+ case "kubernetes":
153
+ templatePath = `kubernetes/${platform}.yml.tpl`;
154
+ break;
155
+ case "migrations":
156
+ templatePath = `migrations/${platform}/${variant || "checklist"}.md.tpl`;
157
+ break;
158
+ default:
159
+ return {
160
+ data: null,
161
+ source: "remote",
162
+ error: `Unknown template category: ${category}`,
163
+ };
164
+ }
165
+ return this.fetchTemplate(templatePath);
166
+ }
167
+ /**
168
+ * Check if repository is accessible
169
+ */
170
+ async checkConnection() {
171
+ try {
172
+ const result = await this.fetchManifest();
173
+ return result.data !== null;
174
+ }
175
+ catch {
176
+ return false;
177
+ }
178
+ }
179
+ /**
180
+ * Update repository configuration
181
+ */
182
+ setRepository(repository, branch) {
183
+ this.config.repository = repository;
184
+ if (branch) {
185
+ this.config.branch = branch;
186
+ }
187
+ }
188
+ /**
189
+ * Get current configuration
190
+ */
191
+ getConfig() {
192
+ return { ...this.config };
193
+ }
194
+ }
195
+ exports.GitHubFetcher = GitHubFetcher;
196
+ // Singleton instance
197
+ let fetcherInstance = null;
198
+ function getGitHubFetcher(config) {
199
+ if (!fetcherInstance) {
200
+ fetcherInstance = new GitHubFetcher(config);
201
+ }
202
+ return fetcherInstance;
203
+ }
204
+ exports.getGitHubFetcher = getGitHubFetcher;
205
+ function resetFetcher() {
206
+ fetcherInstance = null;
207
+ }
208
+ exports.resetFetcher = resetFetcher;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Template system exports
3
+ */
4
+ export * from "./types";
5
+ export { TemplateCache, getTemplateCache } from "./cache";
6
+ export { GitHubFetcher, getGitHubFetcher, resetFetcher } from "./fetcher";
7
+ export { TemplateRenderer, getTemplateRenderer } from "./renderer";
8
+ export { TemplateManager, getTemplateManager, resetTemplateManager, } from "./manager";
9
+ export { templatesCommand } from "./cli";
10
+ export type { TemplateManagerConfig } from "./manager";
11
+ export type { FetcherConfig } from "./fetcher";
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ /**
3
+ * Template system exports
4
+ */
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
17
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
18
+ };
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.templatesCommand = exports.resetTemplateManager = exports.getTemplateManager = exports.TemplateManager = exports.getTemplateRenderer = exports.TemplateRenderer = exports.resetFetcher = exports.getGitHubFetcher = exports.GitHubFetcher = exports.getTemplateCache = exports.TemplateCache = void 0;
21
+ __exportStar(require("./types"), exports);
22
+ var cache_1 = require("./cache");
23
+ Object.defineProperty(exports, "TemplateCache", { enumerable: true, get: function () { return cache_1.TemplateCache; } });
24
+ Object.defineProperty(exports, "getTemplateCache", { enumerable: true, get: function () { return cache_1.getTemplateCache; } });
25
+ var fetcher_1 = require("./fetcher");
26
+ Object.defineProperty(exports, "GitHubFetcher", { enumerable: true, get: function () { return fetcher_1.GitHubFetcher; } });
27
+ Object.defineProperty(exports, "getGitHubFetcher", { enumerable: true, get: function () { return fetcher_1.getGitHubFetcher; } });
28
+ Object.defineProperty(exports, "resetFetcher", { enumerable: true, get: function () { return fetcher_1.resetFetcher; } });
29
+ var renderer_1 = require("./renderer");
30
+ Object.defineProperty(exports, "TemplateRenderer", { enumerable: true, get: function () { return renderer_1.TemplateRenderer; } });
31
+ Object.defineProperty(exports, "getTemplateRenderer", { enumerable: true, get: function () { return renderer_1.getTemplateRenderer; } });
32
+ var manager_1 = require("./manager");
33
+ Object.defineProperty(exports, "TemplateManager", { enumerable: true, get: function () { return manager_1.TemplateManager; } });
34
+ Object.defineProperty(exports, "getTemplateManager", { enumerable: true, get: function () { return manager_1.getTemplateManager; } });
35
+ Object.defineProperty(exports, "resetTemplateManager", { enumerable: true, get: function () { return manager_1.resetTemplateManager; } });
36
+ var cli_1 = require("./cli");
37
+ Object.defineProperty(exports, "templatesCommand", { enumerable: true, get: function () { return cli_1.templatesCommand; } });
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Template Manager - orchestrates template fetching, caching, and rendering
3
+ */
4
+ import type { TemplateCategory, CICDPlatform, CIStrategy, TemplateManifest, RenderOptions, FetchResult } from "./types";
5
+ export interface TemplateManagerConfig {
6
+ repository?: string;
7
+ branch?: string;
8
+ cacheTTL?: number;
9
+ offline?: boolean;
10
+ }
11
+ export declare class TemplateManager {
12
+ private cache;
13
+ private fetcher;
14
+ private renderer;
15
+ private offline;
16
+ private manifest;
17
+ constructor(config?: TemplateManagerConfig);
18
+ /**
19
+ * Fetch and cache the template manifest
20
+ */
21
+ getManifest(forceRefresh?: boolean): Promise<TemplateManifest | null>;
22
+ /**
23
+ * Fetch a template by type
24
+ */
25
+ fetchTemplate(category: TemplateCategory, platform: string, variant?: string): Promise<FetchResult<string>>;
26
+ /**
27
+ * Fetch CI/CD template
28
+ */
29
+ fetchCICDTemplate(platform: CICDPlatform, strategy?: CIStrategy): Promise<FetchResult<string>>;
30
+ /**
31
+ * Fetch Docker template
32
+ */
33
+ fetchDockerTemplate(type: string): Promise<FetchResult<string>>;
34
+ /**
35
+ * Fetch Kubernetes template
36
+ */
37
+ fetchKubernetesTemplate(type: string): Promise<FetchResult<string>>;
38
+ /**
39
+ * Fetch migration template
40
+ */
41
+ fetchMigrationTemplate(from: string, to: string, file?: string): Promise<FetchResult<string>>;
42
+ /**
43
+ * Render a template with variables
44
+ */
45
+ render(template: string, options: RenderOptions): string;
46
+ /**
47
+ * Fetch and render template in one step
48
+ */
49
+ fetchAndRender(category: TemplateCategory, platform: string, variant: string | undefined, renderOptions: RenderOptions): Promise<FetchResult<string>>;
50
+ /**
51
+ * Update all cached templates
52
+ */
53
+ updateCache(): Promise<{
54
+ updated: number;
55
+ errors: string[];
56
+ }>;
57
+ /**
58
+ * Clear template cache
59
+ */
60
+ clearCache(): void;
61
+ /**
62
+ * Get cache statistics
63
+ */
64
+ getCacheStats(): {
65
+ files: number;
66
+ totalSize: number;
67
+ oldestEntry: Date | null;
68
+ };
69
+ /**
70
+ * List available templates
71
+ */
72
+ listTemplates(): Promise<{
73
+ cicd: Record<string, string[]>;
74
+ docker: string[];
75
+ kubernetes: string[];
76
+ migrations: string[];
77
+ source: "remote" | "embedded";
78
+ }>;
79
+ /**
80
+ * Get list of embedded templates (fallback when remote unavailable)
81
+ */
82
+ private getEmbeddedTemplatesList;
83
+ /**
84
+ * Set repository for template fetching
85
+ */
86
+ setRepository(repository: string, branch?: string): void;
87
+ /**
88
+ * Set offline mode
89
+ */
90
+ setOfflineMode(offline: boolean): void;
91
+ /**
92
+ * Check if templates are available (cached or remote)
93
+ */
94
+ checkAvailability(): Promise<{
95
+ online: boolean;
96
+ cached: boolean;
97
+ manifest: boolean;
98
+ }>;
99
+ /**
100
+ * Validate a template
101
+ */
102
+ validateTemplate(template: string): {
103
+ valid: boolean;
104
+ errors: string[];
105
+ };
106
+ /**
107
+ * Extract variables from template
108
+ */
109
+ extractVariables(template: string): string[];
110
+ /**
111
+ * Print template status (for CLI output)
112
+ */
113
+ printStatus(): Promise<void>;
114
+ }
115
+ export declare function getTemplateManager(config?: TemplateManagerConfig): TemplateManager;
116
+ export declare function resetTemplateManager(): void;
@@ -0,0 +1,323 @@
1
+ "use strict";
2
+ /**
3
+ * Template Manager - orchestrates template fetching, caching, and rendering
4
+ */
5
+ var __importDefault = (this && this.__importDefault) || function (mod) {
6
+ return (mod && mod.__esModule) ? mod : { "default": mod };
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.resetTemplateManager = exports.getTemplateManager = exports.TemplateManager = void 0;
10
+ const chalk_1 = __importDefault(require("chalk"));
11
+ const cache_1 = require("./cache");
12
+ const fetcher_1 = require("./fetcher");
13
+ const renderer_1 = require("./renderer");
14
+ class TemplateManager {
15
+ constructor(config) {
16
+ this.manifest = null;
17
+ this.cache = (0, cache_1.getTemplateCache)({ ttl: config?.cacheTTL });
18
+ this.fetcher = (0, fetcher_1.getGitHubFetcher)({
19
+ repository: config?.repository,
20
+ branch: config?.branch,
21
+ });
22
+ this.renderer = (0, renderer_1.getTemplateRenderer)();
23
+ this.offline = config?.offline ?? false;
24
+ }
25
+ /**
26
+ * Fetch and cache the template manifest
27
+ */
28
+ async getManifest(forceRefresh = false) {
29
+ // Check memory cache first
30
+ if (this.manifest && !forceRefresh) {
31
+ return this.manifest;
32
+ }
33
+ // Check disk cache
34
+ if (!forceRefresh) {
35
+ const cached = this.cache.get("manifest", "root");
36
+ if (cached) {
37
+ this.manifest = cached;
38
+ return cached;
39
+ }
40
+ }
41
+ // Fetch from remote (if not offline)
42
+ if (!this.offline) {
43
+ const result = await this.fetcher.fetchManifest();
44
+ if (result.data) {
45
+ this.manifest = result.data;
46
+ this.cache.set("manifest", "root", result.data);
47
+ return result.data;
48
+ }
49
+ }
50
+ return null;
51
+ }
52
+ /**
53
+ * Fetch a template by type
54
+ */
55
+ async fetchTemplate(category, platform, variant) {
56
+ const cacheKey = variant ? `${platform}-${variant}` : platform;
57
+ // Check cache first
58
+ const cached = this.cache.get(category, cacheKey);
59
+ if (cached) {
60
+ return { data: cached, source: "cache" };
61
+ }
62
+ // If offline, return null
63
+ if (this.offline) {
64
+ return {
65
+ data: null,
66
+ source: "cache",
67
+ error: "Offline mode - template not in cache",
68
+ };
69
+ }
70
+ // Fetch from remote
71
+ const result = await this.fetcher.fetchByType(category, platform, variant);
72
+ if (result.data) {
73
+ // Cache the template
74
+ this.cache.set(category, cacheKey, result.data);
75
+ return { data: result.data, source: "remote" };
76
+ }
77
+ return result;
78
+ }
79
+ /**
80
+ * Fetch CI/CD template
81
+ */
82
+ async fetchCICDTemplate(platform, strategy = "basic") {
83
+ return this.fetchTemplate("cicd", platform, strategy);
84
+ }
85
+ /**
86
+ * Fetch Docker template
87
+ */
88
+ async fetchDockerTemplate(type) {
89
+ return this.fetchTemplate("docker", type);
90
+ }
91
+ /**
92
+ * Fetch Kubernetes template
93
+ */
94
+ async fetchKubernetesTemplate(type) {
95
+ return this.fetchTemplate("kubernetes", type);
96
+ }
97
+ /**
98
+ * Fetch migration template
99
+ */
100
+ async fetchMigrationTemplate(from, to, file) {
101
+ const migrationPath = `${from}-to-${to}`;
102
+ return this.fetchTemplate("migrations", migrationPath, file);
103
+ }
104
+ /**
105
+ * Render a template with variables
106
+ */
107
+ render(template, options) {
108
+ return this.renderer.render(template, options);
109
+ }
110
+ /**
111
+ * Fetch and render template in one step
112
+ */
113
+ async fetchAndRender(category, platform, variant, renderOptions) {
114
+ const fetchResult = await this.fetchTemplate(category, platform, variant);
115
+ if (!fetchResult.data) {
116
+ return fetchResult;
117
+ }
118
+ const rendered = this.render(fetchResult.data, renderOptions);
119
+ return { data: rendered, source: fetchResult.source };
120
+ }
121
+ /**
122
+ * Update all cached templates
123
+ */
124
+ async updateCache() {
125
+ const errors = [];
126
+ let updated = 0;
127
+ // Fetch fresh manifest
128
+ const manifest = await this.getManifest(true);
129
+ if (!manifest) {
130
+ return { updated: 0, errors: ["Failed to fetch manifest"] };
131
+ }
132
+ // Update CI/CD templates
133
+ if (manifest.templates.cicd) {
134
+ for (const [platform, strategies] of Object.entries(manifest.templates.cicd)) {
135
+ for (const [strategy, info] of Object.entries(strategies)) {
136
+ const result = await this.fetcher.fetchTemplate(info.path);
137
+ if (result.data) {
138
+ this.cache.set("cicd", `${platform}-${strategy}`, result.data);
139
+ updated++;
140
+ }
141
+ else if (result.error) {
142
+ errors.push(`${platform}/${strategy}: ${result.error}`);
143
+ }
144
+ }
145
+ }
146
+ }
147
+ // Update Docker templates
148
+ if (manifest.templates.docker) {
149
+ for (const [type, info] of Object.entries(manifest.templates.docker)) {
150
+ const result = await this.fetcher.fetchTemplate(info.path);
151
+ if (result.data) {
152
+ this.cache.set("docker", type, result.data);
153
+ updated++;
154
+ }
155
+ else if (result.error) {
156
+ errors.push(`docker/${type}: ${result.error}`);
157
+ }
158
+ }
159
+ }
160
+ // Update Kubernetes templates
161
+ if (manifest.templates.kubernetes) {
162
+ for (const [type, info] of Object.entries(manifest.templates.kubernetes)) {
163
+ const result = await this.fetcher.fetchTemplate(info.path);
164
+ if (result.data) {
165
+ this.cache.set("kubernetes", type, result.data);
166
+ updated++;
167
+ }
168
+ else if (result.error) {
169
+ errors.push(`kubernetes/${type}: ${result.error}`);
170
+ }
171
+ }
172
+ }
173
+ return { updated, errors };
174
+ }
175
+ /**
176
+ * Clear template cache
177
+ */
178
+ clearCache() {
179
+ this.cache.clear();
180
+ this.manifest = null;
181
+ }
182
+ /**
183
+ * Get cache statistics
184
+ */
185
+ getCacheStats() {
186
+ return this.cache.getStats();
187
+ }
188
+ /**
189
+ * List available templates
190
+ */
191
+ async listTemplates() {
192
+ const manifest = await this.getManifest();
193
+ // If remote manifest available, use it
194
+ if (manifest) {
195
+ const result = {
196
+ cicd: {},
197
+ docker: [],
198
+ kubernetes: [],
199
+ migrations: [],
200
+ source: "remote",
201
+ };
202
+ // CI/CD templates
203
+ if (manifest.templates.cicd) {
204
+ for (const [platform, strategies] of Object.entries(manifest.templates.cicd)) {
205
+ result.cicd[platform] = Object.keys(strategies);
206
+ }
207
+ }
208
+ // Docker templates
209
+ if (manifest.templates.docker) {
210
+ result.docker = Object.keys(manifest.templates.docker);
211
+ }
212
+ // Kubernetes templates
213
+ if (manifest.templates.kubernetes) {
214
+ result.kubernetes = Object.keys(manifest.templates.kubernetes);
215
+ }
216
+ // Migration templates
217
+ if (manifest.templates.migrations) {
218
+ for (const [from, targets] of Object.entries(manifest.templates.migrations)) {
219
+ for (const to of Object.keys(targets)) {
220
+ result.migrations.push(`${from} → ${to}`);
221
+ }
222
+ }
223
+ }
224
+ return result;
225
+ }
226
+ // Fallback to embedded templates list
227
+ return this.getEmbeddedTemplatesList();
228
+ }
229
+ /**
230
+ * Get list of embedded templates (fallback when remote unavailable)
231
+ */
232
+ getEmbeddedTemplatesList() {
233
+ return {
234
+ cicd: {
235
+ github: ["basic", "comprehensive", "security-focused"],
236
+ gitlab: ["basic", "comprehensive", "security-focused"],
237
+ circleci: ["basic", "comprehensive"],
238
+ jenkins: ["basic"],
239
+ bitbucket: ["basic"],
240
+ azure: ["basic"],
241
+ },
242
+ docker: [
243
+ "production",
244
+ "development",
245
+ "compose",
246
+ "compose-development",
247
+ ],
248
+ kubernetes: ["deployment", "service", "configmap", "ingress"],
249
+ migrations: [
250
+ "heroku → railway",
251
+ "heroku → render",
252
+ "heroku → fly",
253
+ "compose → kubernetes",
254
+ ],
255
+ source: "embedded",
256
+ };
257
+ }
258
+ /**
259
+ * Set repository for template fetching
260
+ */
261
+ setRepository(repository, branch) {
262
+ this.fetcher.setRepository(repository, branch);
263
+ // Clear cache when repository changes
264
+ this.clearCache();
265
+ }
266
+ /**
267
+ * Set offline mode
268
+ */
269
+ setOfflineMode(offline) {
270
+ this.offline = offline;
271
+ }
272
+ /**
273
+ * Check if templates are available (cached or remote)
274
+ */
275
+ async checkAvailability() {
276
+ const online = !this.offline && (await this.fetcher.checkConnection());
277
+ const cached = this.cache.getStats().files > 0;
278
+ const manifest = (await this.getManifest()) !== null;
279
+ return { online, cached, manifest };
280
+ }
281
+ /**
282
+ * Validate a template
283
+ */
284
+ validateTemplate(template) {
285
+ return this.renderer.validateTemplate(template);
286
+ }
287
+ /**
288
+ * Extract variables from template
289
+ */
290
+ extractVariables(template) {
291
+ return this.renderer.extractVariables(template);
292
+ }
293
+ /**
294
+ * Print template status (for CLI output)
295
+ */
296
+ async printStatus() {
297
+ const availability = await this.checkAvailability();
298
+ const stats = this.getCacheStats();
299
+ console.log(chalk_1.default.bold("\nTemplate System Status:\n"));
300
+ console.log(` Online: ${availability.online ? chalk_1.default.green("✓") : chalk_1.default.red("✗")}`);
301
+ console.log(` Cached: ${availability.cached ? chalk_1.default.green("✓") : chalk_1.default.yellow("No templates cached")}`);
302
+ console.log(` Manifest: ${availability.manifest ? chalk_1.default.green("✓") : chalk_1.default.yellow("Not loaded")}`);
303
+ console.log(chalk_1.default.bold("\nCache Statistics:\n"));
304
+ console.log(` Files: ${stats.files}`);
305
+ console.log(` Size: ${(stats.totalSize / 1024).toFixed(2)} KB`);
306
+ console.log(` Oldest: ${stats.oldestEntry?.toLocaleString() || "N/A"}`);
307
+ console.log(` Location: ${this.cache.getCacheDirectory()}`);
308
+ }
309
+ }
310
+ exports.TemplateManager = TemplateManager;
311
+ // Singleton instance
312
+ let managerInstance = null;
313
+ function getTemplateManager(config) {
314
+ if (!managerInstance) {
315
+ managerInstance = new TemplateManager(config);
316
+ }
317
+ return managerInstance;
318
+ }
319
+ exports.getTemplateManager = getTemplateManager;
320
+ function resetTemplateManager() {
321
+ managerInstance = null;
322
+ }
323
+ exports.resetTemplateManager = resetTemplateManager;