@warlock.js/core 4.2.1 → 4.2.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 (107) hide show
  1. package/esm/_virtual/_rolldown/runtime.mjs +7 -0
  2. package/esm/cli/cli-commands.manager.mjs +290 -0
  3. package/esm/cli/cli-commands.manager.mjs.map +1 -0
  4. package/esm/cli/cli-commands.utils.mjs +217 -0
  5. package/esm/cli/cli-commands.utils.mjs.map +1 -0
  6. package/esm/cli/commands/add.command.mjs +27 -0
  7. package/esm/cli/commands/add.command.mjs.map +1 -0
  8. package/esm/cli/commands/build.command.mjs +14 -0
  9. package/esm/cli/commands/build.command.mjs.map +1 -0
  10. package/esm/cli/commands/create-database.command.mjs +24 -0
  11. package/esm/cli/commands/create-database.command.mjs.map +1 -0
  12. package/esm/cli/commands/dev-server.command.mjs +48 -0
  13. package/esm/cli/commands/dev-server.command.mjs.map +1 -0
  14. package/esm/cli/commands/drop-tables.command.mjs +23 -0
  15. package/esm/cli/commands/drop-tables.command.mjs.map +1 -0
  16. package/esm/cli/commands/generate/generate.command.mjs +201 -0
  17. package/esm/cli/commands/generate/generate.command.mjs.map +1 -0
  18. package/esm/cli/commands/generate/generators/column-dsl-parser.mjs +49 -0
  19. package/esm/cli/commands/generate/generators/column-dsl-parser.mjs.map +1 -0
  20. package/esm/cli/commands/generate/generators/controller.generator.mjs +48 -0
  21. package/esm/cli/commands/generate/generators/controller.generator.mjs.map +1 -0
  22. package/esm/cli/commands/generate/generators/migration.generator.mjs +81 -0
  23. package/esm/cli/commands/generate/generators/migration.generator.mjs.map +1 -0
  24. package/esm/cli/commands/generate/generators/model.generator.mjs +60 -0
  25. package/esm/cli/commands/generate/generators/model.generator.mjs.map +1 -0
  26. package/esm/cli/commands/generate/generators/module.generator.mjs +113 -0
  27. package/esm/cli/commands/generate/generators/module.generator.mjs.map +1 -0
  28. package/esm/cli/commands/generate/generators/repository.generator.mjs +42 -0
  29. package/esm/cli/commands/generate/generators/repository.generator.mjs.map +1 -0
  30. package/esm/cli/commands/generate/generators/resource.generator.mjs +42 -0
  31. package/esm/cli/commands/generate/generators/resource.generator.mjs.map +1 -0
  32. package/esm/cli/commands/generate/generators/service.generator.mjs +42 -0
  33. package/esm/cli/commands/generate/generators/service.generator.mjs.map +1 -0
  34. package/esm/cli/commands/generate/templates/stubs.mjs +514 -0
  35. package/esm/cli/commands/generate/templates/stubs.mjs.map +1 -0
  36. package/esm/cli/commands/generate/utils/name-parser.mjs +69 -0
  37. package/esm/cli/commands/generate/utils/name-parser.mjs.map +1 -0
  38. package/esm/cli/commands/generate/utils/path-resolver.mjs +56 -0
  39. package/esm/cli/commands/generate/utils/path-resolver.mjs.map +1 -0
  40. package/esm/cli/commands/generate/utils/prompt.mjs +28 -0
  41. package/esm/cli/commands/generate/utils/prompt.mjs.map +1 -0
  42. package/esm/cli/commands/generate/utils/writer.mjs +60 -0
  43. package/esm/cli/commands/generate/utils/writer.mjs.map +1 -0
  44. package/esm/cli/commands/migrate.command.mjs +60 -0
  45. package/esm/cli/commands/migrate.command.mjs.map +1 -0
  46. package/esm/cli/commands/seed.command.mjs +41 -0
  47. package/esm/cli/commands/seed.command.mjs.map +1 -0
  48. package/esm/cli/commands/start-production.command.mjs +50 -0
  49. package/esm/cli/commands/start-production.command.mjs.map +1 -0
  50. package/esm/cli/commands/storage-put.action.mjs +75 -0
  51. package/esm/cli/commands/storage-put.action.mjs.map +1 -0
  52. package/esm/cli/commands/storage-put.command.mjs +46 -0
  53. package/esm/cli/commands/storage-put.command.mjs.map +1 -0
  54. package/esm/cli/commands/typings-generator.command.mjs +38 -0
  55. package/esm/cli/commands/typings-generator.command.mjs.map +1 -0
  56. package/esm/cli/commands-loader.mjs +50 -0
  57. package/esm/cli/commands-loader.mjs.map +1 -0
  58. package/esm/cli/framework-cli-commands.mjs +37 -0
  59. package/esm/cli/framework-cli-commands.mjs.map +1 -0
  60. package/esm/cli/parse-cli-args.mjs +62 -0
  61. package/esm/cli/parse-cli-args.mjs.map +1 -0
  62. package/esm/cli/start.d.mts +1 -0
  63. package/esm/cli/start.mjs +8 -0
  64. package/esm/cli/start.mjs.map +1 -0
  65. package/esm/cli/string-similarity.mjs +56 -0
  66. package/esm/cli/string-similarity.mjs.map +1 -0
  67. package/esm/database/create-database-action.mjs +32 -0
  68. package/esm/database/create-database-action.mjs.map +1 -0
  69. package/esm/database/drop-tables-action.mjs +35 -0
  70. package/esm/database/drop-tables-action.mjs.map +1 -0
  71. package/esm/database/migrate-action.mjs +99 -0
  72. package/esm/database/migrate-action.mjs.map +1 -0
  73. package/esm/database/seed-command-action.mjs +74 -0
  74. package/esm/database/seed-command-action.mjs.map +1 -0
  75. package/esm/database/seeds/seeders.manager.mjs +129 -0
  76. package/esm/database/seeds/seeders.manager.mjs.map +1 -0
  77. package/esm/database/seeds/seeds-table-migration.mjs +31 -0
  78. package/esm/database/seeds/seeds-table-migration.mjs.map +1 -0
  79. package/esm/database/seeds/utils.mjs +6 -0
  80. package/esm/database/seeds/utils.mjs.map +1 -0
  81. package/esm/dev-server/dev-logger.mjs +12 -1
  82. package/esm/dev-server/dev-logger.mjs.map +1 -1
  83. package/esm/dev-server/development-server.mjs +115 -0
  84. package/esm/dev-server/development-server.mjs.map +1 -0
  85. package/esm/dev-server/layer-executor.mjs +114 -0
  86. package/esm/dev-server/layer-executor.mjs.map +1 -0
  87. package/esm/dev-server/start-development-server.mjs +63 -0
  88. package/esm/dev-server/start-development-server.mjs.map +1 -0
  89. package/esm/dev-server/type-generator.mjs +453 -0
  90. package/esm/dev-server/type-generator.mjs.map +1 -0
  91. package/esm/generations/add-command.action.mjs +480 -0
  92. package/esm/generations/add-command.action.mjs.map +1 -0
  93. package/esm/generations/stubs.mjs +436 -0
  94. package/esm/generations/stubs.mjs.map +1 -0
  95. package/esm/manifest/manifest-manager.mjs +79 -0
  96. package/esm/manifest/manifest-manager.mjs.map +1 -0
  97. package/esm/production/build-app-production.mjs +14 -0
  98. package/esm/production/build-app-production.mjs.map +1 -0
  99. package/esm/production/esbuild-plugins.mjs +37 -0
  100. package/esm/production/esbuild-plugins.mjs.map +1 -0
  101. package/esm/production/production-builder.mjs +264 -0
  102. package/esm/production/production-builder.mjs.map +1 -0
  103. package/esm/production/resolve-build-config.mjs +28 -0
  104. package/esm/production/resolve-build-config.mjs.map +1 -0
  105. package/esm/utils/framework-vesion.mjs +10 -1
  106. package/esm/utils/framework-vesion.mjs.map +1 -1
  107. package/package.json +15 -9
@@ -0,0 +1,453 @@
1
+ import { warlockPath } from "../utils/paths.mjs";
2
+ import "../utils/index.mjs";
3
+ import { Path } from "./path.mjs";
4
+ import { devLogError, devLogInfo, devLogSuccess, devServeLog } from "./dev-logger.mjs";
5
+ import { filesOrchestrator } from "./files-orchestrator.mjs";
6
+ import { env } from "@mongez/dotenv";
7
+ import { join, resolve } from "path";
8
+ import { ensureDirectoryAsync } from "@warlock.js/fs";
9
+ import { constants } from "fs";
10
+ import { access, readFile, writeFile } from "fs/promises";
11
+ import ts from "typescript";
12
+ import { spawn } from "child_process";
13
+
14
+ //#region ../@warlock.js/core/src/dev-server/type-generator.ts
15
+ /**
16
+ * TypeGenerator - Generates TypeScript type definitions from config files
17
+ *
18
+ * Parses source config files using the TypeScript Compiler API to extract
19
+ * keys and generate module augmentation types for IDE autocomplete.
20
+ *
21
+ * Uses manifest-based reconciliation to only regenerate when source files change.
22
+ */
23
+ var TypeGenerator = class {
24
+ constructor() {
25
+ this.outputDir = warlockPath("typings");
26
+ this.manifestPath = join(this.outputDir, "typings-manifest.json");
27
+ this.manifest = null;
28
+ this.configCache = /* @__PURE__ */ new Map();
29
+ }
30
+ /**
31
+ * Generate all framework type definitions
32
+ *
33
+ * Uses manifest-based reconciliation:
34
+ * - If output files don't exist: full regeneration
35
+ * - If files exist: only regenerate changed configs
36
+ */
37
+ async generateAll() {
38
+ await this.ensureOutputDir();
39
+ const storageFile = join(this.outputDir, "storage.d.ts");
40
+ const configFile = join(this.outputDir, "config.d.ts");
41
+ const [manifestExists, storageExists, configExists] = await Promise.all([
42
+ this.exists(this.manifestPath),
43
+ this.exists(storageFile),
44
+ this.exists(configFile)
45
+ ]);
46
+ if (!manifestExists || !storageExists || !configExists) await this.fullGeneration();
47
+ else {
48
+ await this.loadManifest();
49
+ await this.reconcile();
50
+ }
51
+ await this.saveManifest();
52
+ }
53
+ /**
54
+ * Full regeneration of all type files
55
+ */
56
+ async fullGeneration() {
57
+ const storageConfigPath = await this.findConfigFile("storage");
58
+ if (storageConfigPath) this.generateStorageTypes(storageConfigPath);
59
+ await this.generateConfigTypes();
60
+ }
61
+ /**
62
+ * Reconcile: only regenerate changed files
63
+ */
64
+ async reconcile() {
65
+ const files = filesOrchestrator.getFiles();
66
+ let configChanged = false;
67
+ let unchangedCount = 0;
68
+ for (const [path, fileManager] of files) if (path.startsWith("src/config/storage")) {
69
+ const manifestEntry = this.manifest?.storage;
70
+ if (!manifestEntry || manifestEntry.sourceHash !== fileManager.hash) await this.generateStorageTypes(path);
71
+ break;
72
+ }
73
+ for (const [path, fileManager] of files) {
74
+ if (!path.startsWith("src/config/")) continue;
75
+ if (path.includes("index")) continue;
76
+ const configName = path.replace("src/config/", "").replace(/\.[^.]+$/, "");
77
+ const manifestEntry = this.manifest?.config[configName];
78
+ if (!manifestEntry || manifestEntry.sourceHash !== fileManager.hash) {
79
+ configChanged = true;
80
+ const info = await this.extractConfigInfo(fileManager.absolutePath, configName);
81
+ this.configCache.set(configName, {
82
+ sourceHash: fileManager.hash,
83
+ typeName: info.typeName,
84
+ importSource: info.importSource,
85
+ keys: info.keys
86
+ });
87
+ } else {
88
+ unchangedCount++;
89
+ this.configCache.set(configName, manifestEntry);
90
+ }
91
+ }
92
+ if (configChanged) await this.writeConfigTypesFromCache();
93
+ else devLogInfo(`Config types unchanged (${unchangedCount} configs cached)`);
94
+ }
95
+ /**
96
+ * Generate storage driver name types
97
+ */
98
+ async generateStorageTypes(configPath) {
99
+ try {
100
+ const driverKeys = await this.extractStorageDriverKeys(configPath);
101
+ if (driverKeys.length === 0) {
102
+ devServeLog("âš\xA0️ No storage drivers found in config");
103
+ return;
104
+ }
105
+ const sourceHash = filesOrchestrator.getFiles().get(configPath)?.hash || "";
106
+ if (!this.manifest) this.manifest = this.createEmptyManifest();
107
+ this.manifest.storage = {
108
+ sourceHash,
109
+ drivers: driverKeys
110
+ };
111
+ const content = `// Auto-generated by Warlock.js - DO NOT EDIT
112
+ // Generated from: ${configPath}
113
+ // Regenerates on dev-server start and when storage config changes
114
+
115
+ import "@warlock.js/core";
116
+
117
+ declare module "@warlock.js/core" {
118
+ interface StorageDriverRegistry {
119
+ ${driverKeys.map((k) => ` ${this.toInterfaceKey(k)}: true;`).join("\n")}
120
+ }
121
+ }
122
+ `;
123
+ await writeFile(join(this.outputDir, "storage.d.ts"), content, "utf-8");
124
+ devLogSuccess(`Generated storage types: ${driverKeys.join(", ")}`);
125
+ } catch (error) {
126
+ devServeLog(`⚠️ Failed to generate storage types: ${error}`);
127
+ }
128
+ }
129
+ /**
130
+ * Check if a file change should trigger type regeneration
131
+ */
132
+ shouldRegenerateTypes(changedPath) {
133
+ return changedPath.includes("src/config/") || changedPath.includes("config/");
134
+ }
135
+ /**
136
+ * Handle file change - uses incremental update via cache
137
+ */
138
+ async handleFileChange(changedPath) {
139
+ if (!this.shouldRegenerateTypes(changedPath)) return;
140
+ if (changedPath.includes("config/storage")) {
141
+ await this.generateStorageTypes(changedPath);
142
+ await this.saveManifest();
143
+ return;
144
+ }
145
+ const match = changedPath.match(/config\/([^/]+)\.[^.]+$/);
146
+ if (!match) return;
147
+ const configName = match[1];
148
+ if (configName === "index") return;
149
+ devLogInfo(`Config changed: ${configName}, updating...`);
150
+ const sourceHash = filesOrchestrator.getFiles().get(changedPath)?.hash || Date.now().toString();
151
+ const configPath = join(join(process.cwd(), "src/config"), `${configName}.ts`);
152
+ const info = await this.extractConfigInfo(configPath, configName);
153
+ this.configCache.set(configName, {
154
+ sourceHash,
155
+ typeName: info.typeName,
156
+ importSource: info.importSource,
157
+ keys: info.keys
158
+ });
159
+ await this.writeConfigTypesFromCache();
160
+ await this.saveManifest();
161
+ }
162
+ /**
163
+ * Generate config types - populates cache and writes file
164
+ */
165
+ async generateConfigTypes() {
166
+ try {
167
+ const files = filesOrchestrator.getFiles();
168
+ this.configCache.clear();
169
+ for (const [path, fileManager] of files) {
170
+ if (!path.startsWith("src/config/")) continue;
171
+ if (path.includes("index")) continue;
172
+ const configName = path.replace("src/config/", "").replace(/\.[^.]+$/, "");
173
+ const info = await this.extractConfigInfo(fileManager.absolutePath, configName);
174
+ this.configCache.set(configName, {
175
+ sourceHash: fileManager.hash,
176
+ typeName: info.typeName,
177
+ importSource: info.importSource,
178
+ keys: info.keys
179
+ });
180
+ }
181
+ await this.writeConfigTypesFromCache();
182
+ } catch (error) {
183
+ devServeLog(`⚠️ Failed to generate config types: ${error}`);
184
+ }
185
+ }
186
+ /**
187
+ * Quote an interface key that isn't a valid JS identifier (e.g. a config
188
+ * named `use-cases` or a storage driver `do-spaces`) so the generated
189
+ * `.d.ts` stays syntactically valid. Identifier-safe names are left bare
190
+ * to keep the output clean.
191
+ */
192
+ toInterfaceKey(name) {
193
+ return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name) ? name : JSON.stringify(name);
194
+ }
195
+ /**
196
+ * Write config.d.ts from cached data
197
+ */
198
+ async writeConfigTypesFromCache() {
199
+ const configTypeInfos = [];
200
+ const allKeys = [];
201
+ if (!this.manifest) this.manifest = this.createEmptyManifest();
202
+ this.manifest.config = {};
203
+ for (const [name, data] of this.configCache) {
204
+ configTypeInfos.push({
205
+ name,
206
+ typeName: data.typeName,
207
+ importSource: data.importSource
208
+ });
209
+ allKeys.push(...data.keys);
210
+ this.manifest.config[name] = data;
211
+ }
212
+ const imports = /* @__PURE__ */ new Map();
213
+ for (const info of configTypeInfos) if (info.typeName && info.importSource) {
214
+ if (!imports.has(info.importSource)) imports.set(info.importSource, /* @__PURE__ */ new Set());
215
+ imports.get(info.importSource).add(info.typeName);
216
+ }
217
+ const content = `// Auto-generated by Warlock.js - DO NOT EDIT
218
+ // Regenerates on dev-server start and when config files change
219
+
220
+ ${Array.from(imports.entries()).map(([source, types]) => `import type { ${Array.from(types).join(", ")} } from "${source}";`).join("\n")}
221
+ import "@warlock.js/core";
222
+
223
+ declare module "@warlock.js/core" {
224
+ interface ConfigRegistry {
225
+ ${configTypeInfos.map((info) => ` ${this.toInterfaceKey(info.name)}: ${info.typeName || "unknown"};`).join("\n")}
226
+ }
227
+
228
+ interface ConfigKeyRegistry {
229
+ ${allKeys.map((key) => ` "${key}": true;`).join("\n")}
230
+ }
231
+ }
232
+ `;
233
+ await writeFile(join(this.outputDir, "config.d.ts"), content, "utf-8");
234
+ devLogSuccess(`Generated config types: ${this.configCache.size} configs, ${allKeys.length} keys`);
235
+ }
236
+ /**
237
+ * Load manifest from disk
238
+ */
239
+ async loadManifest() {
240
+ try {
241
+ if (await this.exists(this.manifestPath)) {
242
+ const content = await readFile(this.manifestPath, "utf-8");
243
+ this.manifest = JSON.parse(content);
244
+ return true;
245
+ }
246
+ } catch {}
247
+ this.manifest = null;
248
+ return false;
249
+ }
250
+ /**
251
+ * Save manifest to disk
252
+ */
253
+ async saveManifest() {
254
+ if (!this.manifest) this.manifest = this.createEmptyManifest();
255
+ this.manifest.lastBuildTime = Date.now();
256
+ await writeFile(this.manifestPath, JSON.stringify(this.manifest, null, 2), "utf-8");
257
+ }
258
+ /**
259
+ * Create empty manifest structure
260
+ */
261
+ createEmptyManifest() {
262
+ return {
263
+ version: "1.0.0",
264
+ lastBuildTime: Date.now(),
265
+ storage: null,
266
+ config: {}
267
+ };
268
+ }
269
+ /**
270
+ * Extract BOTH type info AND keys in a single pass
271
+ *
272
+ * This is optimized to create ts.createProgram() only ONCE per file
273
+ * instead of twice (once for type extraction, once for keys).
274
+ * This reduces parsing time by ~50%.
275
+ *
276
+ * @param configPath Absolute path to the config file
277
+ * @param configName Config name (e.g., "auth", "notifications")
278
+ * @returns Combined result with type info and keys
279
+ */
280
+ async extractConfigInfo(configPath, configName) {
281
+ if (!await this.exists(configPath)) return {
282
+ typeName: null,
283
+ importSource: null,
284
+ keys: []
285
+ };
286
+ const sourceFile = ts.createProgram([configPath], {
287
+ target: ts.ScriptTarget.ESNext,
288
+ module: ts.ModuleKind.ESNext,
289
+ moduleResolution: ts.ModuleResolutionKind.NodeJs
290
+ }).getSourceFile(configPath);
291
+ if (!sourceFile) return {
292
+ typeName: null,
293
+ importSource: null,
294
+ keys: []
295
+ };
296
+ const importedTypes = /* @__PURE__ */ new Map();
297
+ const localExportedTypes = /* @__PURE__ */ new Set();
298
+ let foundTypeName = null;
299
+ const keys = [];
300
+ const visitForTypes = (node) => {
301
+ if (ts.isImportDeclaration(node)) {
302
+ const moduleSpecifier = node.moduleSpecifier;
303
+ if (ts.isStringLiteral(moduleSpecifier)) {
304
+ const source = moduleSpecifier.text;
305
+ const importClause = node.importClause;
306
+ if (importClause?.namedBindings && ts.isNamedImports(importClause.namedBindings)) for (const element of importClause.namedBindings.elements) importedTypes.set(element.name.text, source);
307
+ }
308
+ }
309
+ if (ts.isTypeAliasDeclaration(node)) {
310
+ if (ts.getModifiers(node)?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword)) localExportedTypes.add(node.name.text);
311
+ }
312
+ if (ts.isInterfaceDeclaration(node)) {
313
+ if (ts.getModifiers(node)?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword)) localExportedTypes.add(node.name.text);
314
+ }
315
+ if (ts.isVariableDeclaration(node)) {
316
+ if (node.type && ts.isTypeReferenceNode(node.type)) foundTypeName = node.type.typeName.getText(sourceFile);
317
+ if (node.initializer && ts.isObjectLiteralExpression(node.initializer)) {
318
+ const visitKeys = (objNode, prefix) => {
319
+ for (const prop of objNode.properties) if (ts.isPropertyAssignment(prop) && prop.name) {
320
+ const keyName = prop.name.getText(sourceFile);
321
+ const fullKey = prefix ? `${prefix}.${keyName}` : keyName;
322
+ keys.push(fullKey);
323
+ if (ts.isObjectLiteralExpression(prop.initializer)) visitKeys(prop.initializer, fullKey);
324
+ }
325
+ };
326
+ visitKeys(node.initializer, configName);
327
+ }
328
+ }
329
+ ts.forEachChild(node, visitForTypes);
330
+ };
331
+ ts.forEachChild(sourceFile, visitForTypes);
332
+ let typeName = null;
333
+ let importSource = null;
334
+ if (foundTypeName) {
335
+ if (importedTypes.has(foundTypeName)) {
336
+ typeName = foundTypeName;
337
+ importSource = importedTypes.get(foundTypeName);
338
+ } else if (localExportedTypes.has(foundTypeName)) {
339
+ typeName = foundTypeName;
340
+ importSource = `../../${Path.toRelative(configPath).replace(/\.(ts|tsx)$/, "")}`;
341
+ }
342
+ }
343
+ return {
344
+ typeName,
345
+ importSource,
346
+ keys
347
+ };
348
+ }
349
+ /**
350
+ * Extract driver keys from storage config
351
+ */
352
+ async extractStorageDriverKeys(configPath) {
353
+ const absolutePath = resolve(configPath);
354
+ if (!await this.exists(absolutePath)) {
355
+ devServeLog(`⚠️ Storage config not found: ${absolutePath}`);
356
+ return [];
357
+ }
358
+ const sourceFile = ts.createProgram([absolutePath], {
359
+ target: ts.ScriptTarget.ESNext,
360
+ module: ts.ModuleKind.ESNext,
361
+ moduleResolution: ts.ModuleResolutionKind.NodeJs
362
+ }).getSourceFile(absolutePath);
363
+ if (!sourceFile) {
364
+ devServeLog(`⚠️ Could not parse storage config: ${absolutePath}`);
365
+ return [];
366
+ }
367
+ const keys = [];
368
+ const visit = (node) => {
369
+ if (ts.isPropertyAssignment(node)) {
370
+ if (node.name.getText(sourceFile) === "drivers" && ts.isObjectLiteralExpression(node.initializer)) {
371
+ for (const prop of node.initializer.properties) if (ts.isPropertyAssignment(prop) || ts.isShorthandPropertyAssignment(prop)) {
372
+ const keyName = prop.name?.getText(sourceFile);
373
+ if (keyName) keys.push(keyName);
374
+ }
375
+ }
376
+ }
377
+ ts.forEachChild(node, visit);
378
+ };
379
+ ts.forEachChild(sourceFile, visit);
380
+ return keys;
381
+ }
382
+ /**
383
+ * Find a config file by name
384
+ */
385
+ async findConfigFile(configName) {
386
+ const possiblePaths = [`src/config/${configName}.ts`, `config/${configName}.ts`];
387
+ for (const path of possiblePaths) {
388
+ const fullPath = join(process.cwd(), path);
389
+ if (await this.exists(fullPath)) return path;
390
+ }
391
+ try {
392
+ const files = filesOrchestrator.getFiles();
393
+ for (const [filePath] of files) if (filePath.includes(`config/${configName}`)) return filePath;
394
+ } catch {}
395
+ }
396
+ /**
397
+ * Ensure output directory exists
398
+ */
399
+ async ensureOutputDir() {
400
+ await ensureDirectoryAsync(this.outputDir);
401
+ }
402
+ /**
403
+ * Check if a path exists (async wrapper)
404
+ */
405
+ async exists(path) {
406
+ try {
407
+ await access(path, constants.F_OK);
408
+ return true;
409
+ } catch {
410
+ return false;
411
+ }
412
+ }
413
+ /**
414
+ * Execute generateAll command using spawn
415
+ */
416
+ async executeGenerateAllCommand() {
417
+ devLogInfo("Checking for types generation");
418
+ const isDevServeCore = env("DEV_SERVER_CORE");
419
+ spawn(isDevServeCore ? "yarn" : "npx", [isDevServeCore ? "cli" : "warlock", "generate.typings"], {
420
+ stdio: "inherit",
421
+ cwd: process.cwd(),
422
+ shell: true
423
+ }).on("exit", (code) => {
424
+ if (code === 0) devLogSuccess("Types generated successfully");
425
+ else devLogError("Failed to generate types");
426
+ });
427
+ }
428
+ /**
429
+ * Execute a typings generator for the given files
430
+ */
431
+ async executeTypingsGenerator(upcomingFiles) {
432
+ const configFilesOnly = Array.from(new Set(upcomingFiles)).filter((file) => Path.normalize(file).includes("src/config/"));
433
+ if (configFilesOnly.length === 0) return;
434
+ configFilesOnly.map((file) => "./" + Path.toRelative(file));
435
+ const isDevServeCore = env("DEV_SERVER_CORE");
436
+ spawn(isDevServeCore ? "yarn" : "npx", [isDevServeCore ? "cli" : "warlock", "generate.typings"], {
437
+ stdio: "inherit",
438
+ cwd: process.cwd(),
439
+ shell: true
440
+ }).on("exit", (code) => {
441
+ if (code === 0) devLogSuccess("Types generated successfully");
442
+ else devLogError("Failed to generate types");
443
+ });
444
+ }
445
+ };
446
+ /**
447
+ * Singleton instance for use throughout dev-server
448
+ */
449
+ const typeGenerator = new TypeGenerator();
450
+
451
+ //#endregion
452
+ export { typeGenerator };
453
+ //# sourceMappingURL=type-generator.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"type-generator.mjs","names":[],"sources":["../../../../../../../@warlock.js/core/src/dev-server/type-generator.ts"],"sourcesContent":["import { env } from \"@mongez/dotenv\";\r\nimport { ensureDirectoryAsync } from \"@warlock.js/fs\";\r\nimport { spawn } from \"child_process\";\r\nimport { constants } from \"fs\";\r\nimport { access, readFile, writeFile } from \"fs/promises\";\r\nimport { join, resolve } from \"path\";\r\nimport ts from \"typescript\";\r\nimport { warlockPath } from \"../utils\";\r\nimport { devLogError, devLogInfo, devLogSuccess, devServeLog } from \"./dev-logger\";\r\nimport { filesOrchestrator } from \"./files-orchestrator\";\r\nimport { Path } from \"./path\";\r\n\r\n/**\r\n * Typings manifest structure for tracking file hashes\r\n */\r\ntype TypingsManifest = {\r\n version: string;\r\n lastBuildTime: number;\r\n storage: {\r\n sourceHash: string;\r\n drivers: string[];\r\n } | null;\r\n config: Record<\r\n string,\r\n {\r\n sourceHash: string;\r\n typeName: string | null;\r\n importSource: string | null;\r\n keys: string[];\r\n }\r\n >;\r\n};\r\n\r\n/**\r\n * TypeGenerator - Generates TypeScript type definitions from config files\r\n *\r\n * Parses source config files using the TypeScript Compiler API to extract\r\n * keys and generate module augmentation types for IDE autocomplete.\r\n *\r\n * Uses manifest-based reconciliation to only regenerate when source files change.\r\n */\r\nexport class TypeGenerator {\r\n /**\r\n * Output directory for generated typings\r\n */\r\n private outputDir = warlockPath(\"typings\");\r\n\r\n /**\r\n * Path to typings manifest file\r\n */\r\n private manifestPath = join(this.outputDir, \"typings-manifest.json\");\r\n\r\n /**\r\n * Cached manifest data\r\n */\r\n private manifest: TypingsManifest | null = null;\r\n\r\n /**\r\n * Cache for config type info and keys\r\n */\r\n private configCache = new Map<\r\n string,\r\n {\r\n sourceHash: string;\r\n typeName: string | null;\r\n importSource: string | null;\r\n keys: string[];\r\n }\r\n >();\r\n\r\n /**\r\n * Generate all framework type definitions\r\n *\r\n * Uses manifest-based reconciliation:\r\n * - If output files don't exist: full regeneration\r\n * - If files exist: only regenerate changed configs\r\n */\r\n public async generateAll(): Promise<void> {\r\n await this.ensureOutputDir();\r\n\r\n const storageFile = join(this.outputDir, \"storage.d.ts\");\r\n const configFile = join(this.outputDir, \"config.d.ts\");\r\n\r\n const [manifestExists, storageExists, configExists] = await Promise.all([\r\n this.exists(this.manifestPath),\r\n this.exists(storageFile),\r\n this.exists(configFile),\r\n ]);\r\n\r\n if (!manifestExists || !storageExists || !configExists) {\r\n // Full regeneration (first run or files deleted)\r\n await this.fullGeneration();\r\n } else {\r\n // Load manifest for hash comparison\r\n await this.loadManifest();\r\n // Reconciliation: only regenerate changed files\r\n await this.reconcile();\r\n }\r\n\r\n await this.saveManifest();\r\n }\r\n\r\n /**\r\n * Full regeneration of all type files\r\n */\r\n private async fullGeneration(): Promise<void> {\r\n // Generate storage types\r\n const storageConfigPath = await this.findConfigFile(\"storage\");\r\n if (storageConfigPath) {\r\n this.generateStorageTypes(storageConfigPath);\r\n }\r\n\r\n // Generate config types\r\n await this.generateConfigTypes();\r\n }\r\n\r\n /**\r\n * Reconcile: only regenerate changed files\r\n */\r\n private async reconcile(): Promise<void> {\r\n const files = filesOrchestrator.getFiles();\r\n let storageChanged = false;\r\n let configChanged = false;\r\n let unchangedCount = 0;\r\n\r\n // Check storage config\r\n for (const [path, fileManager] of files) {\r\n if (path.startsWith(\"src/config/storage\")) {\r\n const manifestEntry = this.manifest?.storage;\r\n if (!manifestEntry || manifestEntry.sourceHash !== fileManager.hash) {\r\n storageChanged = true;\r\n await this.generateStorageTypes(path);\r\n }\r\n break;\r\n }\r\n }\r\n\r\n // Check config files\r\n for (const [path, fileManager] of files) {\r\n if (!path.startsWith(\"src/config/\")) continue;\r\n if (path.includes(\"index\")) continue;\r\n\r\n // Extract config name (remove dir prefix and extension)\r\n const configName = path.replace(\"src/config/\", \"\").replace(/\\.[^.]+$/, \"\");\r\n\r\n const manifestEntry = this.manifest?.config[configName];\r\n\r\n if (!manifestEntry || manifestEntry.sourceHash !== fileManager.hash) {\r\n // File changed or new - regenerate\r\n configChanged = true;\r\n const info = await this.extractConfigInfo(fileManager.absolutePath, configName);\r\n\r\n this.configCache.set(configName, {\r\n sourceHash: fileManager.hash,\r\n typeName: info.typeName,\r\n importSource: info.importSource,\r\n keys: info.keys,\r\n });\r\n } else {\r\n // Unchanged - load from manifest\r\n unchangedCount++;\r\n this.configCache.set(configName, manifestEntry);\r\n }\r\n }\r\n\r\n if (configChanged) {\r\n await this.writeConfigTypesFromCache();\r\n } else {\r\n devLogInfo(`Config types unchanged (${unchangedCount} configs cached)`);\r\n }\r\n }\r\n\r\n /**\r\n * Generate storage driver name types\r\n */\r\n public async generateStorageTypes(configPath: string): Promise<void> {\r\n try {\r\n const driverKeys = await this.extractStorageDriverKeys(configPath);\r\n\r\n if (driverKeys.length === 0) {\r\n devServeLog(\"⚠️ No storage drivers found in config\");\r\n return;\r\n }\r\n\r\n // Get file hash from filesOrchestrator\r\n const fileManager = filesOrchestrator.getFiles().get(configPath);\r\n const sourceHash = fileManager?.hash || \"\";\r\n\r\n // Update manifest\r\n if (!this.manifest) {\r\n this.manifest = this.createEmptyManifest();\r\n }\r\n this.manifest.storage = {\r\n sourceHash,\r\n drivers: driverKeys,\r\n };\r\n\r\n const interfaceContent = driverKeys.map((k) => ` ${this.toInterfaceKey(k)}: true;`).join(\"\\n\");\r\n\r\n const content = `// Auto-generated by Warlock.js - DO NOT EDIT\r\n// Generated from: ${configPath}\r\n// Regenerates on dev-server start and when storage config changes\r\n\r\nimport \"@warlock.js/core\";\r\n\r\ndeclare module \"@warlock.js/core\" {\r\n interface StorageDriverRegistry {\r\n${interfaceContent}\r\n }\r\n}\r\n`;\r\n\r\n const outputPath = join(this.outputDir, \"storage.d.ts\");\r\n await writeFile(outputPath, content, \"utf-8\");\r\n\r\n devLogSuccess(`Generated storage types: ${driverKeys.join(\", \")}`);\r\n } catch (error) {\r\n devServeLog(`⚠️ Failed to generate storage types: ${error}`);\r\n }\r\n }\r\n\r\n /**\r\n * Check if a file change should trigger type regeneration\r\n */\r\n public shouldRegenerateTypes(changedPath: string): boolean {\r\n return changedPath.includes(\"src/config/\") || changedPath.includes(\"config/\");\r\n }\r\n\r\n /**\r\n * Handle file change - uses incremental update via cache\r\n */\r\n public async handleFileChange(changedPath: string): Promise<void> {\r\n if (!this.shouldRegenerateTypes(changedPath)) {\r\n return;\r\n }\r\n\r\n // Regenerate storage types if storage config changed\r\n if (changedPath.includes(\"config/storage\")) {\r\n await this.generateStorageTypes(changedPath);\r\n await this.saveManifest();\r\n return;\r\n }\r\n\r\n // Extract config name from path\r\n const match = changedPath.match(/config\\/([^/]+)\\.[^.]+$/);\r\n if (!match) {\r\n return;\r\n }\r\n\r\n const configName = match[1];\r\n if (configName === \"index\") return;\r\n\r\n devLogInfo(`Config changed: ${configName}, updating...`);\r\n\r\n // Get file manager for hash\r\n const fileManager = filesOrchestrator.getFiles().get(changedPath);\r\n const sourceHash = fileManager?.hash || Date.now().toString();\r\n\r\n // Update only the changed config in cache (use optimized combined extraction)\r\n const configDir = join(process.cwd(), \"src/config\");\r\n const configPath = join(configDir, `${configName}.ts`);\r\n\r\n const info = await this.extractConfigInfo(configPath, configName);\r\n\r\n this.configCache.set(configName, {\r\n sourceHash,\r\n typeName: info.typeName,\r\n importSource: info.importSource,\r\n keys: info.keys,\r\n });\r\n\r\n // Regenerate config.d.ts from cache\r\n await this.writeConfigTypesFromCache();\r\n await this.saveManifest();\r\n }\r\n\r\n /**\r\n * Generate config types - populates cache and writes file\r\n */\r\n public async generateConfigTypes(): Promise<void> {\r\n try {\r\n const files = filesOrchestrator.getFiles();\r\n\r\n // Clear and repopulate cache\r\n this.configCache.clear();\r\n\r\n for (const [path, fileManager] of files) {\r\n if (!path.startsWith(\"src/config/\")) continue;\r\n if (path.includes(\"index\")) continue;\r\n\r\n // Extract config name\r\n const configName = path.replace(\"src/config/\", \"\").replace(/\\.[^.]+$/, \"\");\r\n\r\n // Use optimized combined extraction (single ts.createProgram call)\r\n const info = await this.extractConfigInfo(fileManager.absolutePath, configName);\r\n\r\n this.configCache.set(configName, {\r\n sourceHash: fileManager.hash,\r\n typeName: info.typeName,\r\n importSource: info.importSource,\r\n keys: info.keys,\r\n });\r\n }\r\n\r\n await this.writeConfigTypesFromCache();\r\n } catch (error) {\r\n devServeLog(`⚠️ Failed to generate config types: ${error}`);\r\n }\r\n }\r\n\r\n /**\r\n * Quote an interface key that isn't a valid JS identifier (e.g. a config\r\n * named `use-cases` or a storage driver `do-spaces`) so the generated\r\n * `.d.ts` stays syntactically valid. Identifier-safe names are left bare\r\n * to keep the output clean.\r\n */\r\n private toInterfaceKey(name: string): string {\r\n return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(name) ? name : JSON.stringify(name);\r\n }\r\n\r\n /**\r\n * Write config.d.ts from cached data\r\n */\r\n private async writeConfigTypesFromCache(): Promise<void> {\r\n const configTypeInfos: Array<{\r\n name: string;\r\n typeName: string | null;\r\n importSource: string | null;\r\n }> = [];\r\n const allKeys: string[] = [];\r\n\r\n // Update manifest config section\r\n if (!this.manifest) {\r\n this.manifest = this.createEmptyManifest();\r\n }\r\n this.manifest.config = {};\r\n\r\n for (const [name, data] of this.configCache) {\r\n configTypeInfos.push({\r\n name,\r\n typeName: data.typeName,\r\n importSource: data.importSource,\r\n });\r\n allKeys.push(...data.keys);\r\n\r\n // Store in manifest\r\n this.manifest.config[name] = data;\r\n }\r\n\r\n // Group imports by source\r\n const imports = new Map<string, Set<string>>();\r\n for (const info of configTypeInfos) {\r\n if (info.typeName && info.importSource) {\r\n if (!imports.has(info.importSource)) {\r\n imports.set(info.importSource, new Set());\r\n }\r\n imports.get(info.importSource)!.add(info.typeName);\r\n }\r\n }\r\n\r\n const importStatements = Array.from(imports.entries())\r\n .map(([source, types]) => `import type { ${Array.from(types).join(\", \")} } from \"${source}\";`)\r\n .join(\"\\n\");\r\n\r\n const configEntries = configTypeInfos\r\n .map((info) => ` ${this.toInterfaceKey(info.name)}: ${info.typeName || \"unknown\"};`)\r\n .join(\"\\n\");\r\n\r\n const keyEntries = allKeys.map((key) => ` \"${key}\": true;`).join(\"\\n\");\r\n\r\n const content = `// Auto-generated by Warlock.js - DO NOT EDIT\r\n// Regenerates on dev-server start and when config files change\r\n\r\n${importStatements}\r\nimport \"@warlock.js/core\";\r\n\r\ndeclare module \"@warlock.js/core\" {\r\n interface ConfigRegistry {\r\n${configEntries}\r\n }\r\n\r\n interface ConfigKeyRegistry {\r\n${keyEntries}\r\n }\r\n}\r\n`;\r\n\r\n const outputPath = join(this.outputDir, \"config.d.ts\");\r\n await writeFile(outputPath, content, \"utf-8\");\r\n\r\n devLogSuccess(\r\n `Generated config types: ${this.configCache.size} configs, ${allKeys.length} keys`,\r\n );\r\n }\r\n\r\n // ============================================================\r\n // Manifest Management\r\n // ============================================================\r\n\r\n /**\r\n * Load manifest from disk\r\n */\r\n private async loadManifest(): Promise<boolean> {\r\n try {\r\n if (await this.exists(this.manifestPath)) {\r\n const content = await readFile(this.manifestPath, \"utf-8\");\r\n this.manifest = JSON.parse(content);\r\n return true;\r\n }\r\n } catch {\r\n // Manifest corrupted or missing\r\n }\r\n this.manifest = null;\r\n return false;\r\n }\r\n\r\n /**\r\n * Save manifest to disk\r\n */\r\n private async saveManifest(): Promise<void> {\r\n if (!this.manifest) {\r\n this.manifest = this.createEmptyManifest();\r\n }\r\n this.manifest.lastBuildTime = Date.now();\r\n\r\n await writeFile(this.manifestPath, JSON.stringify(this.manifest, null, 2), \"utf-8\");\r\n }\r\n\r\n /**\r\n * Create empty manifest structure\r\n */\r\n private createEmptyManifest(): TypingsManifest {\r\n return {\r\n version: \"1.0.0\",\r\n lastBuildTime: Date.now(),\r\n storage: null,\r\n config: {},\r\n };\r\n }\r\n\r\n // ============================================================\r\n // Type Extraction Methods\r\n // ============================================================\r\n\r\n /**\r\n * Extract BOTH type info AND keys in a single pass\r\n *\r\n * This is optimized to create ts.createProgram() only ONCE per file\r\n * instead of twice (once for type extraction, once for keys).\r\n * This reduces parsing time by ~50%.\r\n *\r\n * @param configPath Absolute path to the config file\r\n * @param configName Config name (e.g., \"auth\", \"notifications\")\r\n * @returns Combined result with type info and keys\r\n */\r\n private async extractConfigInfo(\r\n configPath: string,\r\n configName: string,\r\n ): Promise<{\r\n typeName: string | null;\r\n importSource: string | null;\r\n keys: string[];\r\n }> {\r\n if (!(await this.exists(configPath))) {\r\n return { typeName: null, importSource: null, keys: [] };\r\n }\r\n\r\n // Create program ONCE (this is the expensive operation)\r\n const program = ts.createProgram([configPath], {\r\n target: ts.ScriptTarget.ESNext,\r\n module: ts.ModuleKind.ESNext,\r\n moduleResolution: ts.ModuleResolutionKind.NodeJs,\r\n });\r\n\r\n const sourceFile = program.getSourceFile(configPath);\r\n if (!sourceFile) {\r\n return { typeName: null, importSource: null, keys: [] };\r\n }\r\n\r\n // === Type Info Extraction ===\r\n const importedTypes = new Map<string, string>();\r\n const localExportedTypes = new Set<string>();\r\n let foundTypeName: string | null = null;\r\n\r\n // === Keys Extraction ===\r\n const keys: string[] = [];\r\n\r\n const visitForTypes = (node: ts.Node): void => {\r\n // Collect imported types\r\n if (ts.isImportDeclaration(node)) {\r\n const moduleSpecifier = node.moduleSpecifier;\r\n if (ts.isStringLiteral(moduleSpecifier)) {\r\n const source = moduleSpecifier.text;\r\n const importClause = node.importClause;\r\n if (importClause?.namedBindings && ts.isNamedImports(importClause.namedBindings)) {\r\n for (const element of importClause.namedBindings.elements) {\r\n importedTypes.set(element.name.text, source);\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Collect locally exported types\r\n if (ts.isTypeAliasDeclaration(node)) {\r\n const modifiers = ts.getModifiers(node);\r\n if (modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword)) {\r\n localExportedTypes.add(node.name.text);\r\n }\r\n }\r\n\r\n // Collect locally exported interfaces\r\n if (ts.isInterfaceDeclaration(node)) {\r\n const modifiers = ts.getModifiers(node);\r\n if (modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword)) {\r\n localExportedTypes.add(node.name.text);\r\n }\r\n }\r\n\r\n // Find type used on config variable + extract keys\r\n if (ts.isVariableDeclaration(node)) {\r\n // Type info\r\n if (node.type && ts.isTypeReferenceNode(node.type)) {\r\n foundTypeName = node.type.typeName.getText(sourceFile);\r\n }\r\n\r\n // Keys extraction\r\n if (node.initializer && ts.isObjectLiteralExpression(node.initializer)) {\r\n const visitKeys = (objNode: ts.ObjectLiteralExpression, prefix: string): void => {\r\n for (const prop of objNode.properties) {\r\n if (ts.isPropertyAssignment(prop) && prop.name) {\r\n const keyName = prop.name.getText(sourceFile);\r\n const fullKey = prefix ? `${prefix}.${keyName}` : keyName;\r\n keys.push(fullKey);\r\n if (ts.isObjectLiteralExpression(prop.initializer)) {\r\n visitKeys(prop.initializer, fullKey);\r\n }\r\n }\r\n }\r\n };\r\n visitKeys(node.initializer, configName);\r\n }\r\n }\r\n\r\n ts.forEachChild(node, visitForTypes);\r\n };\r\n\r\n ts.forEachChild(sourceFile, visitForTypes);\r\n\r\n // Resolve type info\r\n let typeName: string | null = null;\r\n let importSource: string | null = null;\r\n\r\n if (foundTypeName) {\r\n if (importedTypes.has(foundTypeName)) {\r\n typeName = foundTypeName;\r\n importSource = importedTypes.get(foundTypeName)!;\r\n } else if (localExportedTypes.has(foundTypeName)) {\r\n typeName = foundTypeName;\r\n const relativePath = Path.toRelative(configPath).replace(/\\.(ts|tsx)$/, \"\");\r\n importSource = `../../${relativePath}`;\r\n }\r\n }\r\n\r\n return { typeName, importSource, keys };\r\n }\r\n\r\n /**\r\n * Extract driver keys from storage config\r\n */\r\n private async extractStorageDriverKeys(configPath: string): Promise<string[]> {\r\n const absolutePath = resolve(configPath);\r\n\r\n if (!(await this.exists(absolutePath))) {\r\n devServeLog(`⚠️ Storage config not found: ${absolutePath}`);\r\n return [];\r\n }\r\n\r\n const program = ts.createProgram([absolutePath], {\r\n target: ts.ScriptTarget.ESNext,\r\n module: ts.ModuleKind.ESNext,\r\n moduleResolution: ts.ModuleResolutionKind.NodeJs,\r\n });\r\n\r\n const sourceFile = program.getSourceFile(absolutePath);\r\n\r\n if (!sourceFile) {\r\n devServeLog(`⚠️ Could not parse storage config: ${absolutePath}`);\r\n return [];\r\n }\r\n\r\n const keys: string[] = [];\r\n\r\n const visit = (node: ts.Node): void => {\r\n if (ts.isPropertyAssignment(node)) {\r\n const propName = node.name.getText(sourceFile);\r\n\r\n if (propName === \"drivers\" && ts.isObjectLiteralExpression(node.initializer)) {\r\n for (const prop of node.initializer.properties) {\r\n if (ts.isPropertyAssignment(prop) || ts.isShorthandPropertyAssignment(prop)) {\r\n const keyName = prop.name?.getText(sourceFile);\r\n\r\n if (keyName) {\r\n keys.push(keyName);\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n ts.forEachChild(node, visit);\r\n };\r\n\r\n ts.forEachChild(sourceFile, visit);\r\n\r\n return keys;\r\n }\r\n\r\n /**\r\n * Find a config file by name\r\n */\r\n private async findConfigFile(configName: string): Promise<string | undefined> {\r\n const possiblePaths = [`src/config/${configName}.ts`, `config/${configName}.ts`];\r\n\r\n for (const path of possiblePaths) {\r\n const fullPath = join(process.cwd(), path);\r\n\r\n if (await this.exists(fullPath)) {\r\n return path;\r\n }\r\n }\r\n\r\n try {\r\n const files = filesOrchestrator.getFiles();\r\n\r\n for (const [filePath] of files) {\r\n if (filePath.includes(`config/${configName}`)) {\r\n return filePath;\r\n }\r\n }\r\n } catch {\r\n // Files orchestrator not initialized yet\r\n }\r\n\r\n return undefined;\r\n }\r\n\r\n /**\r\n * Ensure output directory exists\r\n */\r\n private async ensureOutputDir(): Promise<void> {\r\n await ensureDirectoryAsync(this.outputDir);\r\n }\r\n\r\n /**\r\n * Check if a path exists (async wrapper)\r\n */\r\n private async exists(path: string): Promise<boolean> {\r\n try {\r\n await access(path, constants.F_OK);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n /**\r\n * Execute generateAll command using spawn\r\n */\r\n public async executeGenerateAllCommand(): Promise<void> {\r\n devLogInfo(\"Checking for types generation\");\r\n const isDevServeCore = env(\"DEV_SERVER_CORE\");\r\n const childProcess = spawn(\r\n isDevServeCore ? \"yarn\" : \"npx\",\r\n [isDevServeCore ? \"cli\" : \"warlock\", \"generate.typings\"],\r\n {\r\n // const childProcess = spawn(\"yarn\", [\"cli\", \"generate.typings\"], {\r\n stdio: \"inherit\",\r\n cwd: process.cwd(),\r\n shell: true, // Required on Windows to find yarn in PATH\r\n },\r\n );\r\n\r\n childProcess.on(\"exit\", (code) => {\r\n if (code === 0) {\r\n devLogSuccess(\"Types generated successfully\");\r\n } else {\r\n devLogError(\"Failed to generate types\");\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * Execute a typings generator for the given files\r\n */\r\n public async executeTypingsGenerator(upcomingFiles: string[]): Promise<void> {\r\n const uniqueFiles = Array.from(new Set(upcomingFiles));\r\n\r\n const configFilesOnly = uniqueFiles.filter((file) =>\r\n Path.normalize(file).includes(\"src/config/\"),\r\n );\r\n\r\n if (configFilesOnly.length === 0) return;\r\n\r\n const files = configFilesOnly.map((file) => \"./\" + Path.toRelative(file));\r\n\r\n const isDevServeCore = env(\"DEV_SERVER_CORE\");\r\n\r\n const childProcess = spawn(\r\n isDevServeCore ? \"yarn\" : \"npx\",\r\n [isDevServeCore ? \"cli\" : \"warlock\", \"generate.typings\"],\r\n {\r\n stdio: \"inherit\",\r\n cwd: process.cwd(),\r\n shell: true, // Required on Windows to find yarn in PATH\r\n },\r\n );\r\n\r\n childProcess.on(\"exit\", (code) => {\r\n if (code === 0) {\r\n devLogSuccess(\"Types generated successfully\");\r\n } else {\r\n devLogError(\"Failed to generate types\");\r\n }\r\n });\r\n }\r\n}\r\n\r\n/**\r\n * Singleton instance for use throughout dev-server\r\n */\r\nexport const typeGenerator = new TypeGenerator();\r\n"],"mappings":"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"}