@agiflowai/aicode-utils 1.0.3 → 1.0.5
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.
- package/README.md +0 -1
- package/dist/index.cjs +269 -48
- package/dist/index.d.cts +67 -1
- package/dist/{index.d.ts → index.d.mts} +67 -1
- package/dist/{index.js → index.mjs} +230 -41
- package/package.json +4 -6
package/README.md
CHANGED
|
@@ -360,7 +360,6 @@ await TemplatesManagerService.writeToolkitConfig({
|
|
|
360
360
|
|
|
361
361
|
**Dependencies**:
|
|
362
362
|
- `chalk` - Terminal colors and styling
|
|
363
|
-
- `fs-extra` - Enhanced file system operations
|
|
364
363
|
- `js-yaml` - YAML parsing for toolkit.yaml
|
|
365
364
|
- `pino` - Structured logging
|
|
366
365
|
|
package/dist/index.cjs
CHANGED
|
@@ -23,8 +23,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
23
23
|
//#endregion
|
|
24
24
|
let node_path = require("node:path");
|
|
25
25
|
node_path = __toESM(node_path);
|
|
26
|
-
let
|
|
27
|
-
|
|
26
|
+
let node_fs_promises = require("node:fs/promises");
|
|
27
|
+
node_fs_promises = __toESM(node_fs_promises);
|
|
28
|
+
let node_fs = require("node:fs");
|
|
28
29
|
let node_os = require("node:os");
|
|
29
30
|
node_os = __toESM(node_os);
|
|
30
31
|
let pino = require("pino");
|
|
@@ -50,6 +51,114 @@ const ConfigSource = {
|
|
|
50
51
|
TOOLKIT_YAML: "toolkit.yaml"
|
|
51
52
|
};
|
|
52
53
|
|
|
54
|
+
//#endregion
|
|
55
|
+
//#region src/utils/fsHelpers.ts
|
|
56
|
+
/**
|
|
57
|
+
* Native FS Helper Functions
|
|
58
|
+
*
|
|
59
|
+
* Provides fs-extra-like API using native node:fs/promises
|
|
60
|
+
* to avoid ESM compatibility issues with fs-extra
|
|
61
|
+
*/
|
|
62
|
+
/**
|
|
63
|
+
* Check if a file or directory exists
|
|
64
|
+
*/
|
|
65
|
+
async function pathExists(filePath) {
|
|
66
|
+
try {
|
|
67
|
+
await node_fs_promises.access(filePath);
|
|
68
|
+
return true;
|
|
69
|
+
} catch {
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Check if a file or directory exists (sync)
|
|
75
|
+
*/
|
|
76
|
+
function pathExistsSync(filePath) {
|
|
77
|
+
try {
|
|
78
|
+
(0, node_fs.accessSync)(filePath);
|
|
79
|
+
return true;
|
|
80
|
+
} catch {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Ensure a directory exists, creating it recursively if needed
|
|
86
|
+
*/
|
|
87
|
+
async function ensureDir(dirPath) {
|
|
88
|
+
await node_fs_promises.mkdir(dirPath, { recursive: true });
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Ensure a directory exists (sync), creating it recursively if needed
|
|
92
|
+
*/
|
|
93
|
+
function ensureDirSync(dirPath) {
|
|
94
|
+
(0, node_fs.mkdirSync)(dirPath, { recursive: true });
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Remove a file or directory recursively
|
|
98
|
+
*/
|
|
99
|
+
async function remove(filePath) {
|
|
100
|
+
await node_fs_promises.rm(filePath, {
|
|
101
|
+
recursive: true,
|
|
102
|
+
force: true
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Copy a file or directory recursively
|
|
107
|
+
*/
|
|
108
|
+
async function copy(src, dest) {
|
|
109
|
+
await node_fs_promises.cp(src, dest, { recursive: true });
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Move a file or directory
|
|
113
|
+
*/
|
|
114
|
+
async function move(src, dest) {
|
|
115
|
+
await ensureDir(node_path.default.dirname(dest));
|
|
116
|
+
await node_fs_promises.rename(src, dest);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Read and parse a JSON file
|
|
120
|
+
*/
|
|
121
|
+
async function readJson(filePath) {
|
|
122
|
+
const content = await node_fs_promises.readFile(filePath, "utf-8");
|
|
123
|
+
return JSON.parse(content);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Read and parse a JSON file (sync)
|
|
127
|
+
*/
|
|
128
|
+
function readJsonSync(filePath) {
|
|
129
|
+
const content = (0, node_fs.readFileSync)(filePath, "utf-8");
|
|
130
|
+
return JSON.parse(content);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Write an object as JSON to a file
|
|
134
|
+
*/
|
|
135
|
+
async function writeJson(filePath, data, options) {
|
|
136
|
+
const content = JSON.stringify(data, null, options?.spaces ?? 2);
|
|
137
|
+
await node_fs_promises.writeFile(filePath, `${content}\n`, "utf-8");
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Write an object as JSON to a file (sync)
|
|
141
|
+
*/
|
|
142
|
+
function writeJsonSync(filePath, data, options) {
|
|
143
|
+
(0, node_fs.writeFileSync)(filePath, `${JSON.stringify(data, null, options?.spaces ?? 2)}\n`, "utf-8");
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Output file - writes content ensuring directory exists
|
|
147
|
+
*/
|
|
148
|
+
async function outputFile(filePath, content) {
|
|
149
|
+
await ensureDir(node_path.default.dirname(filePath));
|
|
150
|
+
await node_fs_promises.writeFile(filePath, content, "utf-8");
|
|
151
|
+
}
|
|
152
|
+
const readFile = node_fs_promises.readFile;
|
|
153
|
+
const writeFile = node_fs_promises.writeFile;
|
|
154
|
+
const readdir = node_fs_promises.readdir;
|
|
155
|
+
const mkdir = node_fs_promises.mkdir;
|
|
156
|
+
const stat = node_fs_promises.stat;
|
|
157
|
+
const unlink = node_fs_promises.unlink;
|
|
158
|
+
const rename = node_fs_promises.rename;
|
|
159
|
+
const rm = node_fs_promises.rm;
|
|
160
|
+
const cp = node_fs_promises.cp;
|
|
161
|
+
|
|
53
162
|
//#endregion
|
|
54
163
|
//#region src/utils/logger.ts
|
|
55
164
|
const logsDir = node_path.join(node_os.tmpdir(), "scaffold-mcp-logs");
|
|
@@ -70,6 +179,29 @@ const log = {
|
|
|
70
179
|
|
|
71
180
|
//#endregion
|
|
72
181
|
//#region src/services/TemplatesManagerService.ts
|
|
182
|
+
/**
|
|
183
|
+
* TemplatesManagerService
|
|
184
|
+
*
|
|
185
|
+
* DESIGN PATTERNS:
|
|
186
|
+
* - Class-based service pattern for encapsulating business logic
|
|
187
|
+
* - Static methods for utility-like functionality
|
|
188
|
+
* - File system traversal for workspace detection
|
|
189
|
+
* - Configuration-driven template path resolution
|
|
190
|
+
*
|
|
191
|
+
* CODING STANDARDS:
|
|
192
|
+
* - Service class names use PascalCase with 'Service' suffix
|
|
193
|
+
* - Method names use camelCase with descriptive verbs
|
|
194
|
+
* - Return types should be explicit (never use implicit any)
|
|
195
|
+
* - Use async/await for asynchronous operations
|
|
196
|
+
* - Handle errors with try-catch and throw descriptive Error objects
|
|
197
|
+
* - Document public methods with JSDoc comments
|
|
198
|
+
*
|
|
199
|
+
* AVOID:
|
|
200
|
+
* - Side effects in constructors (keep them lightweight)
|
|
201
|
+
* - Mixing concerns (keep services focused on single domain)
|
|
202
|
+
* - Direct coupling to other services (use dependency injection)
|
|
203
|
+
* - Exposing internal implementation details
|
|
204
|
+
*/
|
|
73
205
|
var TemplatesManagerService = class TemplatesManagerService {
|
|
74
206
|
static SCAFFOLD_CONFIG_FILE = "scaffold.yaml";
|
|
75
207
|
static TEMPLATES_FOLDER = "templates";
|
|
@@ -92,18 +224,18 @@ var TemplatesManagerService = class TemplatesManagerService {
|
|
|
92
224
|
static async findTemplatesPath(startPath = process.cwd()) {
|
|
93
225
|
const workspaceRoot = await TemplatesManagerService.findWorkspaceRoot(startPath);
|
|
94
226
|
const toolkitConfigPath = node_path.default.join(workspaceRoot, TemplatesManagerService.TOOLKIT_CONFIG_FILE);
|
|
95
|
-
if (await
|
|
227
|
+
if (await pathExists(toolkitConfigPath)) {
|
|
96
228
|
const yaml = await import("js-yaml");
|
|
97
|
-
const content = await
|
|
229
|
+
const content = await node_fs_promises.readFile(toolkitConfigPath, "utf-8");
|
|
98
230
|
const config = yaml.load(content);
|
|
99
231
|
if (config?.templatesPath) {
|
|
100
232
|
const templatesPath$1 = node_path.default.isAbsolute(config.templatesPath) ? config.templatesPath : node_path.default.join(workspaceRoot, config.templatesPath);
|
|
101
|
-
if (await
|
|
233
|
+
if (await pathExists(templatesPath$1)) return templatesPath$1;
|
|
102
234
|
else throw new Error(`Templates path specified in toolkit.yaml does not exist: ${templatesPath$1}`);
|
|
103
235
|
}
|
|
104
236
|
}
|
|
105
237
|
const templatesPath = node_path.default.join(workspaceRoot, TemplatesManagerService.TEMPLATES_FOLDER);
|
|
106
|
-
if (await
|
|
238
|
+
if (await pathExists(templatesPath)) return templatesPath;
|
|
107
239
|
throw new Error(`Templates folder not found at ${templatesPath}.\nEither create a 'templates' folder or specify templatesPath in toolkit.yaml`);
|
|
108
240
|
}
|
|
109
241
|
/**
|
|
@@ -113,8 +245,7 @@ var TemplatesManagerService = class TemplatesManagerService {
|
|
|
113
245
|
let currentPath = node_path.default.resolve(startPath);
|
|
114
246
|
const rootPath = node_path.default.parse(currentPath).root;
|
|
115
247
|
while (true) {
|
|
116
|
-
|
|
117
|
-
if (await fs_extra.pathExists(gitPath)) return currentPath;
|
|
248
|
+
if (await pathExists(node_path.default.join(currentPath, ".git"))) return currentPath;
|
|
118
249
|
if (currentPath === rootPath) return process.cwd();
|
|
119
250
|
currentPath = node_path.default.dirname(currentPath);
|
|
120
251
|
}
|
|
@@ -130,18 +261,18 @@ var TemplatesManagerService = class TemplatesManagerService {
|
|
|
130
261
|
static findTemplatesPathSync(startPath = process.cwd()) {
|
|
131
262
|
const workspaceRoot = TemplatesManagerService.findWorkspaceRootSync(startPath);
|
|
132
263
|
const toolkitConfigPath = node_path.default.join(workspaceRoot, TemplatesManagerService.TOOLKIT_CONFIG_FILE);
|
|
133
|
-
if (
|
|
264
|
+
if (pathExistsSync(toolkitConfigPath)) {
|
|
134
265
|
const yaml = require("js-yaml");
|
|
135
|
-
const content =
|
|
266
|
+
const content = (0, node_fs.readFileSync)(toolkitConfigPath, "utf-8");
|
|
136
267
|
const config = yaml.load(content);
|
|
137
268
|
if (config?.templatesPath) {
|
|
138
269
|
const templatesPath$1 = node_path.default.isAbsolute(config.templatesPath) ? config.templatesPath : node_path.default.join(workspaceRoot, config.templatesPath);
|
|
139
|
-
if (
|
|
270
|
+
if (pathExistsSync(templatesPath$1)) return templatesPath$1;
|
|
140
271
|
else throw new Error(`Templates path specified in toolkit.yaml does not exist: ${templatesPath$1}`);
|
|
141
272
|
}
|
|
142
273
|
}
|
|
143
274
|
const templatesPath = node_path.default.join(workspaceRoot, TemplatesManagerService.TEMPLATES_FOLDER);
|
|
144
|
-
if (
|
|
275
|
+
if (pathExistsSync(templatesPath)) return templatesPath;
|
|
145
276
|
throw new Error(`Templates folder not found at ${templatesPath}.\nEither create a 'templates' folder or specify templatesPath in toolkit.yaml`);
|
|
146
277
|
}
|
|
147
278
|
/**
|
|
@@ -151,8 +282,7 @@ var TemplatesManagerService = class TemplatesManagerService {
|
|
|
151
282
|
let currentPath = node_path.default.resolve(startPath);
|
|
152
283
|
const rootPath = node_path.default.parse(currentPath).root;
|
|
153
284
|
while (true) {
|
|
154
|
-
|
|
155
|
-
if (fs_extra.pathExistsSync(gitPath)) return currentPath;
|
|
285
|
+
if (pathExistsSync(node_path.default.join(currentPath, ".git"))) return currentPath;
|
|
156
286
|
if (currentPath === rootPath) return process.cwd();
|
|
157
287
|
currentPath = node_path.default.dirname(currentPath);
|
|
158
288
|
}
|
|
@@ -164,8 +294,8 @@ var TemplatesManagerService = class TemplatesManagerService {
|
|
|
164
294
|
* @returns true if templates folder exists and is a directory
|
|
165
295
|
*/
|
|
166
296
|
static async isInitialized(templatesPath) {
|
|
167
|
-
if (!await
|
|
168
|
-
return (await
|
|
297
|
+
if (!await pathExists(templatesPath)) return false;
|
|
298
|
+
return (await node_fs_promises.stat(templatesPath)).isDirectory();
|
|
169
299
|
}
|
|
170
300
|
/**
|
|
171
301
|
* Get the scaffold config file name
|
|
@@ -188,9 +318,9 @@ var TemplatesManagerService = class TemplatesManagerService {
|
|
|
188
318
|
static async readToolkitConfig(startPath = process.cwd()) {
|
|
189
319
|
const workspaceRoot = await TemplatesManagerService.findWorkspaceRoot(startPath);
|
|
190
320
|
const toolkitConfigPath = node_path.default.join(workspaceRoot, TemplatesManagerService.TOOLKIT_CONFIG_FILE);
|
|
191
|
-
if (!await
|
|
321
|
+
if (!await pathExists(toolkitConfigPath)) return null;
|
|
192
322
|
const yaml = await import("js-yaml");
|
|
193
|
-
const content = await
|
|
323
|
+
const content = await node_fs_promises.readFile(toolkitConfigPath, "utf-8");
|
|
194
324
|
return yaml.load(content);
|
|
195
325
|
}
|
|
196
326
|
/**
|
|
@@ -202,9 +332,9 @@ var TemplatesManagerService = class TemplatesManagerService {
|
|
|
202
332
|
static readToolkitConfigSync(startPath = process.cwd()) {
|
|
203
333
|
const workspaceRoot = TemplatesManagerService.findWorkspaceRootSync(startPath);
|
|
204
334
|
const toolkitConfigPath = node_path.default.join(workspaceRoot, TemplatesManagerService.TOOLKIT_CONFIG_FILE);
|
|
205
|
-
if (!
|
|
335
|
+
if (!pathExistsSync(toolkitConfigPath)) return null;
|
|
206
336
|
const yaml = require("js-yaml");
|
|
207
|
-
const content =
|
|
337
|
+
const content = (0, node_fs.readFileSync)(toolkitConfigPath, "utf-8");
|
|
208
338
|
return yaml.load(content);
|
|
209
339
|
}
|
|
210
340
|
/**
|
|
@@ -217,7 +347,7 @@ var TemplatesManagerService = class TemplatesManagerService {
|
|
|
217
347
|
const workspaceRoot = await TemplatesManagerService.findWorkspaceRoot(startPath);
|
|
218
348
|
const toolkitConfigPath = node_path.default.join(workspaceRoot, TemplatesManagerService.TOOLKIT_CONFIG_FILE);
|
|
219
349
|
const content = (await import("js-yaml")).dump(config, { indent: 2 });
|
|
220
|
-
await
|
|
350
|
+
await node_fs_promises.writeFile(toolkitConfigPath, content, "utf-8");
|
|
221
351
|
}
|
|
222
352
|
/**
|
|
223
353
|
* Get the workspace root directory
|
|
@@ -244,6 +374,28 @@ var TemplatesManagerService = class TemplatesManagerService {
|
|
|
244
374
|
/**
|
|
245
375
|
* ProjectConfigResolver
|
|
246
376
|
*
|
|
377
|
+
* DESIGN PATTERNS:
|
|
378
|
+
* - Class-based service pattern for resolving project configuration
|
|
379
|
+
* - Priority-based configuration resolution (project.json > toolkit.yaml > package.json)
|
|
380
|
+
* - Singleton-like static methods for common operations
|
|
381
|
+
*
|
|
382
|
+
* CODING STANDARDS:
|
|
383
|
+
* - Service class names use PascalCase with 'Service' suffix
|
|
384
|
+
* - Method names use camelCase with descriptive verbs
|
|
385
|
+
* - Return types should be explicit (never use implicit any)
|
|
386
|
+
* - Use async/await for asynchronous operations
|
|
387
|
+
* - Handle errors with try-catch and throw descriptive Error objects
|
|
388
|
+
* - Document public methods with JSDoc comments
|
|
389
|
+
*
|
|
390
|
+
* AVOID:
|
|
391
|
+
* - Side effects in constructors (keep them lightweight)
|
|
392
|
+
* - Mixing concerns (keep services focused on single domain)
|
|
393
|
+
* - Direct coupling to other services (use dependency injection)
|
|
394
|
+
* - Exposing internal implementation details
|
|
395
|
+
*/
|
|
396
|
+
/**
|
|
397
|
+
* ProjectConfigResolver
|
|
398
|
+
*
|
|
247
399
|
* Resolves project configuration from multiple sources with priority:
|
|
248
400
|
* 1. project.json (monorepo - Nx/Lerna/Turborepo)
|
|
249
401
|
* 2. toolkit.yaml at workspace root (monolith)
|
|
@@ -271,8 +423,8 @@ var ProjectConfigResolver = class ProjectConfigResolver {
|
|
|
271
423
|
configSource: ConfigSource.TOOLKIT_YAML
|
|
272
424
|
};
|
|
273
425
|
const projectJsonPath = node_path.default.join(absolutePath, "project.json");
|
|
274
|
-
if (await
|
|
275
|
-
const projectJson = await
|
|
426
|
+
if (await pathExists(projectJsonPath)) {
|
|
427
|
+
const projectJson = await readJson(projectJsonPath);
|
|
276
428
|
if (projectJson.sourceTemplate && typeof projectJson.sourceTemplate === "string" && projectJson.sourceTemplate.trim()) return {
|
|
277
429
|
type: ProjectType.MONOREPO,
|
|
278
430
|
sourceTemplate: projectJson.sourceTemplate.trim(),
|
|
@@ -364,7 +516,7 @@ Run 'scaffold-mcp scaffold list --help' for more info.`;
|
|
|
364
516
|
const projectJsonPath = node_path.default.join(projectPath, "project.json");
|
|
365
517
|
try {
|
|
366
518
|
let projectJson;
|
|
367
|
-
if (await
|
|
519
|
+
if (await pathExists(projectJsonPath)) projectJson = await readJson(projectJsonPath);
|
|
368
520
|
else {
|
|
369
521
|
const relativePath = node_path.default.relative(projectPath, process.cwd());
|
|
370
522
|
projectJson = {
|
|
@@ -375,8 +527,7 @@ Run 'scaffold-mcp scaffold list --help' for more info.`;
|
|
|
375
527
|
};
|
|
376
528
|
}
|
|
377
529
|
projectJson.sourceTemplate = sourceTemplate;
|
|
378
|
-
|
|
379
|
-
await fs_extra.writeFile(projectJsonPath, `${content}\n`);
|
|
530
|
+
await writeJson(projectJsonPath, projectJson);
|
|
380
531
|
log.info(`Created/updated project.json with sourceTemplate: ${sourceTemplate}`);
|
|
381
532
|
} catch (error) {
|
|
382
533
|
throw new Error(`Failed to create project.json: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -386,6 +537,26 @@ Run 'scaffold-mcp scaffold list --help' for more info.`;
|
|
|
386
537
|
|
|
387
538
|
//#endregion
|
|
388
539
|
//#region src/services/ProjectFinderService.ts
|
|
540
|
+
/**
|
|
541
|
+
* ProjectFinderService
|
|
542
|
+
*
|
|
543
|
+
* DESIGN PATTERNS:
|
|
544
|
+
* - Class-based service pattern for encapsulating business logic
|
|
545
|
+
* - Caching for performance optimization
|
|
546
|
+
* - File system traversal for project detection
|
|
547
|
+
*
|
|
548
|
+
* CODING STANDARDS:
|
|
549
|
+
* - Service class names use PascalCase with 'Service' suffix
|
|
550
|
+
* - Method names use camelCase with descriptive verbs
|
|
551
|
+
* - Return types should be explicit
|
|
552
|
+
* - Use async/await for asynchronous operations
|
|
553
|
+
* - Handle errors with try-catch and throw descriptive Error objects
|
|
554
|
+
*
|
|
555
|
+
* AVOID:
|
|
556
|
+
* - Side effects in constructors
|
|
557
|
+
* - Mixing concerns
|
|
558
|
+
* - Direct coupling to other services
|
|
559
|
+
*/
|
|
389
560
|
var ProjectFinderService = class {
|
|
390
561
|
projectCache = /* @__PURE__ */ new Map();
|
|
391
562
|
workspaceRoot;
|
|
@@ -436,7 +607,7 @@ var ProjectFinderService = class {
|
|
|
436
607
|
async loadProjectConfig(projectJsonPath) {
|
|
437
608
|
if (this.projectCache.has(projectJsonPath)) return this.projectCache.get(projectJsonPath);
|
|
438
609
|
try {
|
|
439
|
-
const content = await
|
|
610
|
+
const content = await node_fs_promises.readFile(projectJsonPath, "utf-8");
|
|
440
611
|
const config = JSON.parse(content);
|
|
441
612
|
const projectConfig = {
|
|
442
613
|
name: config.name || node_path.default.basename(node_path.default.dirname(projectJsonPath)),
|
|
@@ -456,7 +627,7 @@ var ProjectFinderService = class {
|
|
|
456
627
|
loadProjectConfigSync(projectJsonPath) {
|
|
457
628
|
if (this.projectCache.has(projectJsonPath)) return this.projectCache.get(projectJsonPath);
|
|
458
629
|
try {
|
|
459
|
-
const content =
|
|
630
|
+
const content = (0, node_fs.readFileSync)(projectJsonPath, "utf-8");
|
|
460
631
|
const config = JSON.parse(content);
|
|
461
632
|
const projectConfig = {
|
|
462
633
|
name: config.name || node_path.default.basename(node_path.default.dirname(projectJsonPath)),
|
|
@@ -544,9 +715,9 @@ var ScaffoldProcessingService = class {
|
|
|
544
715
|
if (!item) continue;
|
|
545
716
|
const itemPath = node_path.default.join(dirPath, item);
|
|
546
717
|
try {
|
|
547
|
-
const stat = await this.fileSystem.stat(itemPath);
|
|
548
|
-
if (stat.isDirectory()) await this.trackCreatedFilesRecursive(itemPath, createdFiles);
|
|
549
|
-
else if (stat.isFile()) createdFiles.push(itemPath);
|
|
718
|
+
const stat$1 = await this.fileSystem.stat(itemPath);
|
|
719
|
+
if (stat$1.isDirectory()) await this.trackCreatedFilesRecursive(itemPath, createdFiles);
|
|
720
|
+
else if (stat$1.isFile()) createdFiles.push(itemPath);
|
|
550
721
|
} catch (error) {
|
|
551
722
|
console.warn(`Cannot stat ${itemPath}: ${error}`);
|
|
552
723
|
}
|
|
@@ -567,9 +738,9 @@ var ScaffoldProcessingService = class {
|
|
|
567
738
|
if (!item) continue;
|
|
568
739
|
const itemPath = node_path.default.join(dirPath, item);
|
|
569
740
|
try {
|
|
570
|
-
const stat = await this.fileSystem.stat(itemPath);
|
|
571
|
-
if (stat.isDirectory()) await this.trackExistingFilesRecursive(itemPath, existingFiles);
|
|
572
|
-
else if (stat.isFile()) existingFiles.push(itemPath);
|
|
741
|
+
const stat$1 = await this.fileSystem.stat(itemPath);
|
|
742
|
+
if (stat$1.isDirectory()) await this.trackExistingFilesRecursive(itemPath, existingFiles);
|
|
743
|
+
else if (stat$1.isFile()) existingFiles.push(itemPath);
|
|
573
744
|
} catch (error) {
|
|
574
745
|
console.warn(`Cannot stat ${itemPath}: ${error}`);
|
|
575
746
|
}
|
|
@@ -704,6 +875,27 @@ const sections = {
|
|
|
704
875
|
//#endregion
|
|
705
876
|
//#region src/utils/projectTypeDetector.ts
|
|
706
877
|
/**
|
|
878
|
+
* projectTypeDetector Utilities
|
|
879
|
+
*
|
|
880
|
+
* DESIGN PATTERNS:
|
|
881
|
+
* - Pure function pattern: No side effects, deterministic output
|
|
882
|
+
* - Single domain focus: All functions related to project type detection
|
|
883
|
+
* - Composability: Functions can be combined to create complex behavior
|
|
884
|
+
*
|
|
885
|
+
* CODING STANDARDS:
|
|
886
|
+
* - Function names use camelCase with descriptive verbs (validate, format, parse, transform)
|
|
887
|
+
* - All functions should be pure (same input = same output, no side effects)
|
|
888
|
+
* - Use explicit return types
|
|
889
|
+
* - Document complex logic with JSDoc comments
|
|
890
|
+
* - Keep functions small and focused on single responsibility
|
|
891
|
+
*
|
|
892
|
+
* AVOID:
|
|
893
|
+
* - Side effects (mutations, I/O, random values, Date.now(), etc.)
|
|
894
|
+
* - Stateful behavior or closures with mutable state
|
|
895
|
+
* - Dependencies on external services or global variables
|
|
896
|
+
* - Classes (use pure functions instead)
|
|
897
|
+
*/
|
|
898
|
+
/**
|
|
707
899
|
* Monorepo configuration files that indicate a monorepo setup
|
|
708
900
|
*/
|
|
709
901
|
const MONOREPO_INDICATOR_FILES = [
|
|
@@ -729,8 +921,8 @@ const MONOREPO_INDICATOR_FILES = [
|
|
|
729
921
|
async function detectProjectType(workspaceRoot) {
|
|
730
922
|
const indicators = [];
|
|
731
923
|
const toolkitYamlPath = node_path.default.join(workspaceRoot, "toolkit.yaml");
|
|
732
|
-
if (await
|
|
733
|
-
const content = await
|
|
924
|
+
if (await pathExists(toolkitYamlPath)) try {
|
|
925
|
+
const content = await node_fs_promises.readFile(toolkitYamlPath, "utf-8");
|
|
734
926
|
const config = js_yaml.load(content);
|
|
735
927
|
if (config?.projectType) {
|
|
736
928
|
indicators.push(`toolkit.yaml specifies ${config.projectType}`);
|
|
@@ -740,19 +932,16 @@ async function detectProjectType(workspaceRoot) {
|
|
|
740
932
|
};
|
|
741
933
|
}
|
|
742
934
|
} catch {}
|
|
743
|
-
for (const filename of MONOREPO_INDICATOR_FILES) {
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
indicators
|
|
750
|
-
};
|
|
751
|
-
}
|
|
935
|
+
for (const filename of MONOREPO_INDICATOR_FILES) if (await pathExists(node_path.default.join(workspaceRoot, filename))) {
|
|
936
|
+
indicators.push(`${filename} found`);
|
|
937
|
+
return {
|
|
938
|
+
projectType: ProjectType.MONOREPO,
|
|
939
|
+
indicators
|
|
940
|
+
};
|
|
752
941
|
}
|
|
753
942
|
const packageJsonPath = node_path.default.join(workspaceRoot, "package.json");
|
|
754
|
-
if (await
|
|
755
|
-
if ((await
|
|
943
|
+
if (await pathExists(packageJsonPath)) try {
|
|
944
|
+
if ((await readJson(packageJsonPath)).workspaces) {
|
|
756
945
|
indicators.push("package.json with workspaces found");
|
|
757
946
|
return {
|
|
758
947
|
projectType: ProjectType.MONOREPO,
|
|
@@ -794,12 +983,44 @@ exports.ProjectFinderService = ProjectFinderService;
|
|
|
794
983
|
exports.ProjectType = ProjectType;
|
|
795
984
|
exports.ScaffoldProcessingService = ScaffoldProcessingService;
|
|
796
985
|
exports.TemplatesManagerService = TemplatesManagerService;
|
|
986
|
+
exports.accessSync = node_fs.accessSync;
|
|
987
|
+
exports.copy = copy;
|
|
988
|
+
exports.cp = cp;
|
|
797
989
|
exports.detectProjectType = detectProjectType;
|
|
990
|
+
exports.ensureDir = ensureDir;
|
|
991
|
+
exports.ensureDirSync = ensureDirSync;
|
|
992
|
+
Object.defineProperty(exports, 'fs', {
|
|
993
|
+
enumerable: true,
|
|
994
|
+
get: function () {
|
|
995
|
+
return node_fs_promises;
|
|
996
|
+
}
|
|
997
|
+
});
|
|
798
998
|
exports.icons = icons;
|
|
799
999
|
exports.isMonolith = isMonolith;
|
|
800
1000
|
exports.isMonorepo = isMonorepo;
|
|
801
1001
|
exports.log = log;
|
|
802
1002
|
exports.logger = logger;
|
|
803
1003
|
exports.messages = messages;
|
|
1004
|
+
exports.mkdir = mkdir;
|
|
1005
|
+
exports.mkdirSync = node_fs.mkdirSync;
|
|
1006
|
+
exports.move = move;
|
|
1007
|
+
exports.outputFile = outputFile;
|
|
1008
|
+
exports.pathExists = pathExists;
|
|
1009
|
+
exports.pathExistsSync = pathExistsSync;
|
|
804
1010
|
exports.print = print;
|
|
805
|
-
exports.
|
|
1011
|
+
exports.readFile = readFile;
|
|
1012
|
+
exports.readFileSync = node_fs.readFileSync;
|
|
1013
|
+
exports.readJson = readJson;
|
|
1014
|
+
exports.readJsonSync = readJsonSync;
|
|
1015
|
+
exports.readdir = readdir;
|
|
1016
|
+
exports.remove = remove;
|
|
1017
|
+
exports.rename = rename;
|
|
1018
|
+
exports.rm = rm;
|
|
1019
|
+
exports.sections = sections;
|
|
1020
|
+
exports.stat = stat;
|
|
1021
|
+
exports.statSync = node_fs.statSync;
|
|
1022
|
+
exports.unlink = unlink;
|
|
1023
|
+
exports.writeFile = writeFile;
|
|
1024
|
+
exports.writeFileSync = node_fs.writeFileSync;
|
|
1025
|
+
exports.writeJson = writeJson;
|
|
1026
|
+
exports.writeJsonSync = writeJsonSync;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import { accessSync, mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
1
3
|
import pino from "pino";
|
|
2
4
|
|
|
3
5
|
//#region src/constants/projectType.d.ts
|
|
@@ -43,6 +45,7 @@ interface NxProjectJson {
|
|
|
43
45
|
}
|
|
44
46
|
//#endregion
|
|
45
47
|
//#region src/types/index.d.ts
|
|
48
|
+
|
|
46
49
|
/**
|
|
47
50
|
* Toolkit configuration from toolkit.yaml
|
|
48
51
|
*/
|
|
@@ -337,6 +340,69 @@ declare class TemplatesManagerService {
|
|
|
337
340
|
static getWorkspaceRootSync(startPath?: string): string;
|
|
338
341
|
}
|
|
339
342
|
//#endregion
|
|
343
|
+
//#region src/utils/fsHelpers.d.ts
|
|
344
|
+
/**
|
|
345
|
+
* Check if a file or directory exists
|
|
346
|
+
*/
|
|
347
|
+
declare function pathExists(filePath: string): Promise<boolean>;
|
|
348
|
+
/**
|
|
349
|
+
* Check if a file or directory exists (sync)
|
|
350
|
+
*/
|
|
351
|
+
declare function pathExistsSync(filePath: string): boolean;
|
|
352
|
+
/**
|
|
353
|
+
* Ensure a directory exists, creating it recursively if needed
|
|
354
|
+
*/
|
|
355
|
+
declare function ensureDir(dirPath: string): Promise<void>;
|
|
356
|
+
/**
|
|
357
|
+
* Ensure a directory exists (sync), creating it recursively if needed
|
|
358
|
+
*/
|
|
359
|
+
declare function ensureDirSync(dirPath: string): void;
|
|
360
|
+
/**
|
|
361
|
+
* Remove a file or directory recursively
|
|
362
|
+
*/
|
|
363
|
+
declare function remove(filePath: string): Promise<void>;
|
|
364
|
+
/**
|
|
365
|
+
* Copy a file or directory recursively
|
|
366
|
+
*/
|
|
367
|
+
declare function copy(src: string, dest: string): Promise<void>;
|
|
368
|
+
/**
|
|
369
|
+
* Move a file or directory
|
|
370
|
+
*/
|
|
371
|
+
declare function move(src: string, dest: string): Promise<void>;
|
|
372
|
+
/**
|
|
373
|
+
* Read and parse a JSON file
|
|
374
|
+
*/
|
|
375
|
+
declare function readJson<T = unknown>(filePath: string): Promise<T>;
|
|
376
|
+
/**
|
|
377
|
+
* Read and parse a JSON file (sync)
|
|
378
|
+
*/
|
|
379
|
+
declare function readJsonSync<T = unknown>(filePath: string): T;
|
|
380
|
+
/**
|
|
381
|
+
* Write an object as JSON to a file
|
|
382
|
+
*/
|
|
383
|
+
declare function writeJson(filePath: string, data: unknown, options?: {
|
|
384
|
+
spaces?: number;
|
|
385
|
+
}): Promise<void>;
|
|
386
|
+
/**
|
|
387
|
+
* Write an object as JSON to a file (sync)
|
|
388
|
+
*/
|
|
389
|
+
declare function writeJsonSync(filePath: string, data: unknown, options?: {
|
|
390
|
+
spaces?: number;
|
|
391
|
+
}): void;
|
|
392
|
+
/**
|
|
393
|
+
* Output file - writes content ensuring directory exists
|
|
394
|
+
*/
|
|
395
|
+
declare function outputFile(filePath: string, content: string): Promise<void>;
|
|
396
|
+
declare const readFile: typeof fs.readFile;
|
|
397
|
+
declare const writeFile: typeof fs.writeFile;
|
|
398
|
+
declare const readdir: typeof fs.readdir;
|
|
399
|
+
declare const mkdir: typeof fs.mkdir;
|
|
400
|
+
declare const stat: typeof fs.stat;
|
|
401
|
+
declare const unlink: typeof fs.unlink;
|
|
402
|
+
declare const rename: typeof fs.rename;
|
|
403
|
+
declare const rm: typeof fs.rm;
|
|
404
|
+
declare const cp: typeof fs.cp;
|
|
405
|
+
//#endregion
|
|
340
406
|
//#region src/utils/logger.d.ts
|
|
341
407
|
declare const logger: pino.Logger<never, boolean>;
|
|
342
408
|
declare const log: {
|
|
@@ -514,4 +580,4 @@ declare function isMonorepo(workspaceRoot: string): Promise<boolean>;
|
|
|
514
580
|
*/
|
|
515
581
|
declare function isMonolith(workspaceRoot: string): Promise<boolean>;
|
|
516
582
|
//#endregion
|
|
517
|
-
export { ConfigSource, GeneratorContext, GeneratorFunction, IFileSystemService, IVariableReplacementService, NxProjectJson, ParsedInclude, ProjectConfig, ProjectConfigResolver, ProjectConfigResult, ProjectFinderService, ProjectType, ProjectTypeDetectionResult, ScaffoldProcessingService, ScaffoldResult, TemplatesManagerService, ToolkitConfig, detectProjectType, icons, isMonolith, isMonorepo, log, logger, messages, print, sections };
|
|
583
|
+
export { ConfigSource, GeneratorContext, GeneratorFunction, IFileSystemService, IVariableReplacementService, NxProjectJson, ParsedInclude, ProjectConfig, ProjectConfigResolver, ProjectConfigResult, ProjectFinderService, ProjectType, ProjectTypeDetectionResult, ScaffoldProcessingService, ScaffoldResult, TemplatesManagerService, ToolkitConfig, accessSync, copy, cp, detectProjectType, ensureDir, ensureDirSync, fs, icons, isMonolith, isMonorepo, log, logger, messages, mkdir, mkdirSync, move, outputFile, pathExists, pathExistsSync, print, readFile, readFileSync, readJson, readJsonSync, readdir, remove, rename, rm, sections, stat, statSync, unlink, writeFile, writeFileSync, writeJson, writeJsonSync };
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import { accessSync, mkdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
1
3
|
import pino from "pino";
|
|
2
4
|
|
|
3
5
|
//#region src/constants/projectType.d.ts
|
|
@@ -43,6 +45,7 @@ interface NxProjectJson {
|
|
|
43
45
|
}
|
|
44
46
|
//#endregion
|
|
45
47
|
//#region src/types/index.d.ts
|
|
48
|
+
|
|
46
49
|
/**
|
|
47
50
|
* Toolkit configuration from toolkit.yaml
|
|
48
51
|
*/
|
|
@@ -337,6 +340,69 @@ declare class TemplatesManagerService {
|
|
|
337
340
|
static getWorkspaceRootSync(startPath?: string): string;
|
|
338
341
|
}
|
|
339
342
|
//#endregion
|
|
343
|
+
//#region src/utils/fsHelpers.d.ts
|
|
344
|
+
/**
|
|
345
|
+
* Check if a file or directory exists
|
|
346
|
+
*/
|
|
347
|
+
declare function pathExists(filePath: string): Promise<boolean>;
|
|
348
|
+
/**
|
|
349
|
+
* Check if a file or directory exists (sync)
|
|
350
|
+
*/
|
|
351
|
+
declare function pathExistsSync(filePath: string): boolean;
|
|
352
|
+
/**
|
|
353
|
+
* Ensure a directory exists, creating it recursively if needed
|
|
354
|
+
*/
|
|
355
|
+
declare function ensureDir(dirPath: string): Promise<void>;
|
|
356
|
+
/**
|
|
357
|
+
* Ensure a directory exists (sync), creating it recursively if needed
|
|
358
|
+
*/
|
|
359
|
+
declare function ensureDirSync(dirPath: string): void;
|
|
360
|
+
/**
|
|
361
|
+
* Remove a file or directory recursively
|
|
362
|
+
*/
|
|
363
|
+
declare function remove(filePath: string): Promise<void>;
|
|
364
|
+
/**
|
|
365
|
+
* Copy a file or directory recursively
|
|
366
|
+
*/
|
|
367
|
+
declare function copy(src: string, dest: string): Promise<void>;
|
|
368
|
+
/**
|
|
369
|
+
* Move a file or directory
|
|
370
|
+
*/
|
|
371
|
+
declare function move(src: string, dest: string): Promise<void>;
|
|
372
|
+
/**
|
|
373
|
+
* Read and parse a JSON file
|
|
374
|
+
*/
|
|
375
|
+
declare function readJson<T = unknown>(filePath: string): Promise<T>;
|
|
376
|
+
/**
|
|
377
|
+
* Read and parse a JSON file (sync)
|
|
378
|
+
*/
|
|
379
|
+
declare function readJsonSync<T = unknown>(filePath: string): T;
|
|
380
|
+
/**
|
|
381
|
+
* Write an object as JSON to a file
|
|
382
|
+
*/
|
|
383
|
+
declare function writeJson(filePath: string, data: unknown, options?: {
|
|
384
|
+
spaces?: number;
|
|
385
|
+
}): Promise<void>;
|
|
386
|
+
/**
|
|
387
|
+
* Write an object as JSON to a file (sync)
|
|
388
|
+
*/
|
|
389
|
+
declare function writeJsonSync(filePath: string, data: unknown, options?: {
|
|
390
|
+
spaces?: number;
|
|
391
|
+
}): void;
|
|
392
|
+
/**
|
|
393
|
+
* Output file - writes content ensuring directory exists
|
|
394
|
+
*/
|
|
395
|
+
declare function outputFile(filePath: string, content: string): Promise<void>;
|
|
396
|
+
declare const readFile: typeof fs.readFile;
|
|
397
|
+
declare const writeFile: typeof fs.writeFile;
|
|
398
|
+
declare const readdir: typeof fs.readdir;
|
|
399
|
+
declare const mkdir: typeof fs.mkdir;
|
|
400
|
+
declare const stat: typeof fs.stat;
|
|
401
|
+
declare const unlink: typeof fs.unlink;
|
|
402
|
+
declare const rename: typeof fs.rename;
|
|
403
|
+
declare const rm: typeof fs.rm;
|
|
404
|
+
declare const cp: typeof fs.cp;
|
|
405
|
+
//#endregion
|
|
340
406
|
//#region src/utils/logger.d.ts
|
|
341
407
|
declare const logger: pino.Logger<never, boolean>;
|
|
342
408
|
declare const log: {
|
|
@@ -514,4 +580,4 @@ declare function isMonorepo(workspaceRoot: string): Promise<boolean>;
|
|
|
514
580
|
*/
|
|
515
581
|
declare function isMonolith(workspaceRoot: string): Promise<boolean>;
|
|
516
582
|
//#endregion
|
|
517
|
-
export { ConfigSource, GeneratorContext, GeneratorFunction, IFileSystemService, IVariableReplacementService, NxProjectJson, ParsedInclude, ProjectConfig, ProjectConfigResolver, ProjectConfigResult, ProjectFinderService, ProjectType, ProjectTypeDetectionResult, ScaffoldProcessingService, ScaffoldResult, TemplatesManagerService, ToolkitConfig, detectProjectType, icons, isMonolith, isMonorepo, log, logger, messages, print, sections };
|
|
583
|
+
export { ConfigSource, GeneratorContext, GeneratorFunction, IFileSystemService, IVariableReplacementService, NxProjectJson, ParsedInclude, ProjectConfig, ProjectConfigResolver, ProjectConfigResult, ProjectFinderService, ProjectType, ProjectTypeDetectionResult, ScaffoldProcessingService, ScaffoldResult, TemplatesManagerService, ToolkitConfig, accessSync, copy, cp, detectProjectType, ensureDir, ensureDirSync, fs, icons, isMonolith, isMonorepo, log, logger, messages, mkdir, mkdirSync, move, outputFile, pathExists, pathExistsSync, print, readFile, readFileSync, readJson, readJsonSync, readdir, remove, rename, rm, sections, stat, statSync, unlink, writeFile, writeFileSync, writeJson, writeJsonSync };
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
2
|
import * as path$1 from "node:path";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import * as fs from "fs
|
|
4
|
+
import * as fs from "node:fs/promises";
|
|
5
|
+
import { accessSync, mkdirSync, readFileSync, readFileSync as readFileSync$1, statSync, writeFileSync } from "node:fs";
|
|
5
6
|
import * as os from "node:os";
|
|
6
7
|
import pino from "pino";
|
|
7
8
|
import * as yaml from "js-yaml";
|
|
@@ -27,6 +28,114 @@ const ConfigSource = {
|
|
|
27
28
|
TOOLKIT_YAML: "toolkit.yaml"
|
|
28
29
|
};
|
|
29
30
|
|
|
31
|
+
//#endregion
|
|
32
|
+
//#region src/utils/fsHelpers.ts
|
|
33
|
+
/**
|
|
34
|
+
* Native FS Helper Functions
|
|
35
|
+
*
|
|
36
|
+
* Provides fs-extra-like API using native node:fs/promises
|
|
37
|
+
* to avoid ESM compatibility issues with fs-extra
|
|
38
|
+
*/
|
|
39
|
+
/**
|
|
40
|
+
* Check if a file or directory exists
|
|
41
|
+
*/
|
|
42
|
+
async function pathExists(filePath) {
|
|
43
|
+
try {
|
|
44
|
+
await fs.access(filePath);
|
|
45
|
+
return true;
|
|
46
|
+
} catch {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Check if a file or directory exists (sync)
|
|
52
|
+
*/
|
|
53
|
+
function pathExistsSync(filePath) {
|
|
54
|
+
try {
|
|
55
|
+
accessSync(filePath);
|
|
56
|
+
return true;
|
|
57
|
+
} catch {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Ensure a directory exists, creating it recursively if needed
|
|
63
|
+
*/
|
|
64
|
+
async function ensureDir(dirPath) {
|
|
65
|
+
await fs.mkdir(dirPath, { recursive: true });
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Ensure a directory exists (sync), creating it recursively if needed
|
|
69
|
+
*/
|
|
70
|
+
function ensureDirSync(dirPath) {
|
|
71
|
+
mkdirSync(dirPath, { recursive: true });
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Remove a file or directory recursively
|
|
75
|
+
*/
|
|
76
|
+
async function remove(filePath) {
|
|
77
|
+
await fs.rm(filePath, {
|
|
78
|
+
recursive: true,
|
|
79
|
+
force: true
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Copy a file or directory recursively
|
|
84
|
+
*/
|
|
85
|
+
async function copy(src, dest) {
|
|
86
|
+
await fs.cp(src, dest, { recursive: true });
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Move a file or directory
|
|
90
|
+
*/
|
|
91
|
+
async function move(src, dest) {
|
|
92
|
+
await ensureDir(path.dirname(dest));
|
|
93
|
+
await fs.rename(src, dest);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Read and parse a JSON file
|
|
97
|
+
*/
|
|
98
|
+
async function readJson(filePath) {
|
|
99
|
+
const content = await fs.readFile(filePath, "utf-8");
|
|
100
|
+
return JSON.parse(content);
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Read and parse a JSON file (sync)
|
|
104
|
+
*/
|
|
105
|
+
function readJsonSync(filePath) {
|
|
106
|
+
const content = readFileSync(filePath, "utf-8");
|
|
107
|
+
return JSON.parse(content);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Write an object as JSON to a file
|
|
111
|
+
*/
|
|
112
|
+
async function writeJson(filePath, data, options) {
|
|
113
|
+
const content = JSON.stringify(data, null, options?.spaces ?? 2);
|
|
114
|
+
await fs.writeFile(filePath, `${content}\n`, "utf-8");
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Write an object as JSON to a file (sync)
|
|
118
|
+
*/
|
|
119
|
+
function writeJsonSync(filePath, data, options) {
|
|
120
|
+
writeFileSync(filePath, `${JSON.stringify(data, null, options?.spaces ?? 2)}\n`, "utf-8");
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Output file - writes content ensuring directory exists
|
|
124
|
+
*/
|
|
125
|
+
async function outputFile(filePath, content) {
|
|
126
|
+
await ensureDir(path.dirname(filePath));
|
|
127
|
+
await fs.writeFile(filePath, content, "utf-8");
|
|
128
|
+
}
|
|
129
|
+
const readFile = fs.readFile;
|
|
130
|
+
const writeFile = fs.writeFile;
|
|
131
|
+
const readdir = fs.readdir;
|
|
132
|
+
const mkdir = fs.mkdir;
|
|
133
|
+
const stat = fs.stat;
|
|
134
|
+
const unlink = fs.unlink;
|
|
135
|
+
const rename = fs.rename;
|
|
136
|
+
const rm = fs.rm;
|
|
137
|
+
const cp = fs.cp;
|
|
138
|
+
|
|
30
139
|
//#endregion
|
|
31
140
|
//#region src/utils/logger.ts
|
|
32
141
|
const logsDir = path$1.join(os.tmpdir(), "scaffold-mcp-logs");
|
|
@@ -47,6 +156,29 @@ const log = {
|
|
|
47
156
|
|
|
48
157
|
//#endregion
|
|
49
158
|
//#region src/services/TemplatesManagerService.ts
|
|
159
|
+
/**
|
|
160
|
+
* TemplatesManagerService
|
|
161
|
+
*
|
|
162
|
+
* DESIGN PATTERNS:
|
|
163
|
+
* - Class-based service pattern for encapsulating business logic
|
|
164
|
+
* - Static methods for utility-like functionality
|
|
165
|
+
* - File system traversal for workspace detection
|
|
166
|
+
* - Configuration-driven template path resolution
|
|
167
|
+
*
|
|
168
|
+
* CODING STANDARDS:
|
|
169
|
+
* - Service class names use PascalCase with 'Service' suffix
|
|
170
|
+
* - Method names use camelCase with descriptive verbs
|
|
171
|
+
* - Return types should be explicit (never use implicit any)
|
|
172
|
+
* - Use async/await for asynchronous operations
|
|
173
|
+
* - Handle errors with try-catch and throw descriptive Error objects
|
|
174
|
+
* - Document public methods with JSDoc comments
|
|
175
|
+
*
|
|
176
|
+
* AVOID:
|
|
177
|
+
* - Side effects in constructors (keep them lightweight)
|
|
178
|
+
* - Mixing concerns (keep services focused on single domain)
|
|
179
|
+
* - Direct coupling to other services (use dependency injection)
|
|
180
|
+
* - Exposing internal implementation details
|
|
181
|
+
*/
|
|
50
182
|
var TemplatesManagerService = class TemplatesManagerService {
|
|
51
183
|
static SCAFFOLD_CONFIG_FILE = "scaffold.yaml";
|
|
52
184
|
static TEMPLATES_FOLDER = "templates";
|
|
@@ -69,18 +201,18 @@ var TemplatesManagerService = class TemplatesManagerService {
|
|
|
69
201
|
static async findTemplatesPath(startPath = process.cwd()) {
|
|
70
202
|
const workspaceRoot = await TemplatesManagerService.findWorkspaceRoot(startPath);
|
|
71
203
|
const toolkitConfigPath = path.join(workspaceRoot, TemplatesManagerService.TOOLKIT_CONFIG_FILE);
|
|
72
|
-
if (await
|
|
204
|
+
if (await pathExists(toolkitConfigPath)) {
|
|
73
205
|
const yaml$1 = await import("js-yaml");
|
|
74
206
|
const content = await fs.readFile(toolkitConfigPath, "utf-8");
|
|
75
207
|
const config = yaml$1.load(content);
|
|
76
208
|
if (config?.templatesPath) {
|
|
77
209
|
const templatesPath$1 = path.isAbsolute(config.templatesPath) ? config.templatesPath : path.join(workspaceRoot, config.templatesPath);
|
|
78
|
-
if (await
|
|
210
|
+
if (await pathExists(templatesPath$1)) return templatesPath$1;
|
|
79
211
|
else throw new Error(`Templates path specified in toolkit.yaml does not exist: ${templatesPath$1}`);
|
|
80
212
|
}
|
|
81
213
|
}
|
|
82
214
|
const templatesPath = path.join(workspaceRoot, TemplatesManagerService.TEMPLATES_FOLDER);
|
|
83
|
-
if (await
|
|
215
|
+
if (await pathExists(templatesPath)) return templatesPath;
|
|
84
216
|
throw new Error(`Templates folder not found at ${templatesPath}.\nEither create a 'templates' folder or specify templatesPath in toolkit.yaml`);
|
|
85
217
|
}
|
|
86
218
|
/**
|
|
@@ -90,8 +222,7 @@ var TemplatesManagerService = class TemplatesManagerService {
|
|
|
90
222
|
let currentPath = path.resolve(startPath);
|
|
91
223
|
const rootPath = path.parse(currentPath).root;
|
|
92
224
|
while (true) {
|
|
93
|
-
|
|
94
|
-
if (await fs.pathExists(gitPath)) return currentPath;
|
|
225
|
+
if (await pathExists(path.join(currentPath, ".git"))) return currentPath;
|
|
95
226
|
if (currentPath === rootPath) return process.cwd();
|
|
96
227
|
currentPath = path.dirname(currentPath);
|
|
97
228
|
}
|
|
@@ -107,18 +238,18 @@ var TemplatesManagerService = class TemplatesManagerService {
|
|
|
107
238
|
static findTemplatesPathSync(startPath = process.cwd()) {
|
|
108
239
|
const workspaceRoot = TemplatesManagerService.findWorkspaceRootSync(startPath);
|
|
109
240
|
const toolkitConfigPath = path.join(workspaceRoot, TemplatesManagerService.TOOLKIT_CONFIG_FILE);
|
|
110
|
-
if (
|
|
241
|
+
if (pathExistsSync(toolkitConfigPath)) {
|
|
111
242
|
const yaml$1 = __require("js-yaml");
|
|
112
|
-
const content =
|
|
243
|
+
const content = readFileSync$1(toolkitConfigPath, "utf-8");
|
|
113
244
|
const config = yaml$1.load(content);
|
|
114
245
|
if (config?.templatesPath) {
|
|
115
246
|
const templatesPath$1 = path.isAbsolute(config.templatesPath) ? config.templatesPath : path.join(workspaceRoot, config.templatesPath);
|
|
116
|
-
if (
|
|
247
|
+
if (pathExistsSync(templatesPath$1)) return templatesPath$1;
|
|
117
248
|
else throw new Error(`Templates path specified in toolkit.yaml does not exist: ${templatesPath$1}`);
|
|
118
249
|
}
|
|
119
250
|
}
|
|
120
251
|
const templatesPath = path.join(workspaceRoot, TemplatesManagerService.TEMPLATES_FOLDER);
|
|
121
|
-
if (
|
|
252
|
+
if (pathExistsSync(templatesPath)) return templatesPath;
|
|
122
253
|
throw new Error(`Templates folder not found at ${templatesPath}.\nEither create a 'templates' folder or specify templatesPath in toolkit.yaml`);
|
|
123
254
|
}
|
|
124
255
|
/**
|
|
@@ -128,8 +259,7 @@ var TemplatesManagerService = class TemplatesManagerService {
|
|
|
128
259
|
let currentPath = path.resolve(startPath);
|
|
129
260
|
const rootPath = path.parse(currentPath).root;
|
|
130
261
|
while (true) {
|
|
131
|
-
|
|
132
|
-
if (fs.pathExistsSync(gitPath)) return currentPath;
|
|
262
|
+
if (pathExistsSync(path.join(currentPath, ".git"))) return currentPath;
|
|
133
263
|
if (currentPath === rootPath) return process.cwd();
|
|
134
264
|
currentPath = path.dirname(currentPath);
|
|
135
265
|
}
|
|
@@ -141,7 +271,7 @@ var TemplatesManagerService = class TemplatesManagerService {
|
|
|
141
271
|
* @returns true if templates folder exists and is a directory
|
|
142
272
|
*/
|
|
143
273
|
static async isInitialized(templatesPath) {
|
|
144
|
-
if (!await
|
|
274
|
+
if (!await pathExists(templatesPath)) return false;
|
|
145
275
|
return (await fs.stat(templatesPath)).isDirectory();
|
|
146
276
|
}
|
|
147
277
|
/**
|
|
@@ -165,7 +295,7 @@ var TemplatesManagerService = class TemplatesManagerService {
|
|
|
165
295
|
static async readToolkitConfig(startPath = process.cwd()) {
|
|
166
296
|
const workspaceRoot = await TemplatesManagerService.findWorkspaceRoot(startPath);
|
|
167
297
|
const toolkitConfigPath = path.join(workspaceRoot, TemplatesManagerService.TOOLKIT_CONFIG_FILE);
|
|
168
|
-
if (!await
|
|
298
|
+
if (!await pathExists(toolkitConfigPath)) return null;
|
|
169
299
|
const yaml$1 = await import("js-yaml");
|
|
170
300
|
const content = await fs.readFile(toolkitConfigPath, "utf-8");
|
|
171
301
|
return yaml$1.load(content);
|
|
@@ -179,9 +309,9 @@ var TemplatesManagerService = class TemplatesManagerService {
|
|
|
179
309
|
static readToolkitConfigSync(startPath = process.cwd()) {
|
|
180
310
|
const workspaceRoot = TemplatesManagerService.findWorkspaceRootSync(startPath);
|
|
181
311
|
const toolkitConfigPath = path.join(workspaceRoot, TemplatesManagerService.TOOLKIT_CONFIG_FILE);
|
|
182
|
-
if (!
|
|
312
|
+
if (!pathExistsSync(toolkitConfigPath)) return null;
|
|
183
313
|
const yaml$1 = __require("js-yaml");
|
|
184
|
-
const content =
|
|
314
|
+
const content = readFileSync$1(toolkitConfigPath, "utf-8");
|
|
185
315
|
return yaml$1.load(content);
|
|
186
316
|
}
|
|
187
317
|
/**
|
|
@@ -221,6 +351,28 @@ var TemplatesManagerService = class TemplatesManagerService {
|
|
|
221
351
|
/**
|
|
222
352
|
* ProjectConfigResolver
|
|
223
353
|
*
|
|
354
|
+
* DESIGN PATTERNS:
|
|
355
|
+
* - Class-based service pattern for resolving project configuration
|
|
356
|
+
* - Priority-based configuration resolution (project.json > toolkit.yaml > package.json)
|
|
357
|
+
* - Singleton-like static methods for common operations
|
|
358
|
+
*
|
|
359
|
+
* CODING STANDARDS:
|
|
360
|
+
* - Service class names use PascalCase with 'Service' suffix
|
|
361
|
+
* - Method names use camelCase with descriptive verbs
|
|
362
|
+
* - Return types should be explicit (never use implicit any)
|
|
363
|
+
* - Use async/await for asynchronous operations
|
|
364
|
+
* - Handle errors with try-catch and throw descriptive Error objects
|
|
365
|
+
* - Document public methods with JSDoc comments
|
|
366
|
+
*
|
|
367
|
+
* AVOID:
|
|
368
|
+
* - Side effects in constructors (keep them lightweight)
|
|
369
|
+
* - Mixing concerns (keep services focused on single domain)
|
|
370
|
+
* - Direct coupling to other services (use dependency injection)
|
|
371
|
+
* - Exposing internal implementation details
|
|
372
|
+
*/
|
|
373
|
+
/**
|
|
374
|
+
* ProjectConfigResolver
|
|
375
|
+
*
|
|
224
376
|
* Resolves project configuration from multiple sources with priority:
|
|
225
377
|
* 1. project.json (monorepo - Nx/Lerna/Turborepo)
|
|
226
378
|
* 2. toolkit.yaml at workspace root (monolith)
|
|
@@ -248,8 +400,8 @@ var ProjectConfigResolver = class ProjectConfigResolver {
|
|
|
248
400
|
configSource: ConfigSource.TOOLKIT_YAML
|
|
249
401
|
};
|
|
250
402
|
const projectJsonPath = path.join(absolutePath, "project.json");
|
|
251
|
-
if (await
|
|
252
|
-
const projectJson = await
|
|
403
|
+
if (await pathExists(projectJsonPath)) {
|
|
404
|
+
const projectJson = await readJson(projectJsonPath);
|
|
253
405
|
if (projectJson.sourceTemplate && typeof projectJson.sourceTemplate === "string" && projectJson.sourceTemplate.trim()) return {
|
|
254
406
|
type: ProjectType.MONOREPO,
|
|
255
407
|
sourceTemplate: projectJson.sourceTemplate.trim(),
|
|
@@ -341,7 +493,7 @@ Run 'scaffold-mcp scaffold list --help' for more info.`;
|
|
|
341
493
|
const projectJsonPath = path.join(projectPath, "project.json");
|
|
342
494
|
try {
|
|
343
495
|
let projectJson;
|
|
344
|
-
if (await
|
|
496
|
+
if (await pathExists(projectJsonPath)) projectJson = await readJson(projectJsonPath);
|
|
345
497
|
else {
|
|
346
498
|
const relativePath = path.relative(projectPath, process.cwd());
|
|
347
499
|
projectJson = {
|
|
@@ -352,8 +504,7 @@ Run 'scaffold-mcp scaffold list --help' for more info.`;
|
|
|
352
504
|
};
|
|
353
505
|
}
|
|
354
506
|
projectJson.sourceTemplate = sourceTemplate;
|
|
355
|
-
|
|
356
|
-
await fs.writeFile(projectJsonPath, `${content}\n`);
|
|
507
|
+
await writeJson(projectJsonPath, projectJson);
|
|
357
508
|
log.info(`Created/updated project.json with sourceTemplate: ${sourceTemplate}`);
|
|
358
509
|
} catch (error) {
|
|
359
510
|
throw new Error(`Failed to create project.json: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -363,6 +514,26 @@ Run 'scaffold-mcp scaffold list --help' for more info.`;
|
|
|
363
514
|
|
|
364
515
|
//#endregion
|
|
365
516
|
//#region src/services/ProjectFinderService.ts
|
|
517
|
+
/**
|
|
518
|
+
* ProjectFinderService
|
|
519
|
+
*
|
|
520
|
+
* DESIGN PATTERNS:
|
|
521
|
+
* - Class-based service pattern for encapsulating business logic
|
|
522
|
+
* - Caching for performance optimization
|
|
523
|
+
* - File system traversal for project detection
|
|
524
|
+
*
|
|
525
|
+
* CODING STANDARDS:
|
|
526
|
+
* - Service class names use PascalCase with 'Service' suffix
|
|
527
|
+
* - Method names use camelCase with descriptive verbs
|
|
528
|
+
* - Return types should be explicit
|
|
529
|
+
* - Use async/await for asynchronous operations
|
|
530
|
+
* - Handle errors with try-catch and throw descriptive Error objects
|
|
531
|
+
*
|
|
532
|
+
* AVOID:
|
|
533
|
+
* - Side effects in constructors
|
|
534
|
+
* - Mixing concerns
|
|
535
|
+
* - Direct coupling to other services
|
|
536
|
+
*/
|
|
366
537
|
var ProjectFinderService = class {
|
|
367
538
|
projectCache = /* @__PURE__ */ new Map();
|
|
368
539
|
workspaceRoot;
|
|
@@ -433,7 +604,7 @@ var ProjectFinderService = class {
|
|
|
433
604
|
loadProjectConfigSync(projectJsonPath) {
|
|
434
605
|
if (this.projectCache.has(projectJsonPath)) return this.projectCache.get(projectJsonPath);
|
|
435
606
|
try {
|
|
436
|
-
const content =
|
|
607
|
+
const content = readFileSync$1(projectJsonPath, "utf-8");
|
|
437
608
|
const config = JSON.parse(content);
|
|
438
609
|
const projectConfig = {
|
|
439
610
|
name: config.name || path.basename(path.dirname(projectJsonPath)),
|
|
@@ -521,9 +692,9 @@ var ScaffoldProcessingService = class {
|
|
|
521
692
|
if (!item) continue;
|
|
522
693
|
const itemPath = path.join(dirPath, item);
|
|
523
694
|
try {
|
|
524
|
-
const stat = await this.fileSystem.stat(itemPath);
|
|
525
|
-
if (stat.isDirectory()) await this.trackCreatedFilesRecursive(itemPath, createdFiles);
|
|
526
|
-
else if (stat.isFile()) createdFiles.push(itemPath);
|
|
695
|
+
const stat$1 = await this.fileSystem.stat(itemPath);
|
|
696
|
+
if (stat$1.isDirectory()) await this.trackCreatedFilesRecursive(itemPath, createdFiles);
|
|
697
|
+
else if (stat$1.isFile()) createdFiles.push(itemPath);
|
|
527
698
|
} catch (error) {
|
|
528
699
|
console.warn(`Cannot stat ${itemPath}: ${error}`);
|
|
529
700
|
}
|
|
@@ -544,9 +715,9 @@ var ScaffoldProcessingService = class {
|
|
|
544
715
|
if (!item) continue;
|
|
545
716
|
const itemPath = path.join(dirPath, item);
|
|
546
717
|
try {
|
|
547
|
-
const stat = await this.fileSystem.stat(itemPath);
|
|
548
|
-
if (stat.isDirectory()) await this.trackExistingFilesRecursive(itemPath, existingFiles);
|
|
549
|
-
else if (stat.isFile()) existingFiles.push(itemPath);
|
|
718
|
+
const stat$1 = await this.fileSystem.stat(itemPath);
|
|
719
|
+
if (stat$1.isDirectory()) await this.trackExistingFilesRecursive(itemPath, existingFiles);
|
|
720
|
+
else if (stat$1.isFile()) existingFiles.push(itemPath);
|
|
550
721
|
} catch (error) {
|
|
551
722
|
console.warn(`Cannot stat ${itemPath}: ${error}`);
|
|
552
723
|
}
|
|
@@ -681,6 +852,27 @@ const sections = {
|
|
|
681
852
|
//#endregion
|
|
682
853
|
//#region src/utils/projectTypeDetector.ts
|
|
683
854
|
/**
|
|
855
|
+
* projectTypeDetector Utilities
|
|
856
|
+
*
|
|
857
|
+
* DESIGN PATTERNS:
|
|
858
|
+
* - Pure function pattern: No side effects, deterministic output
|
|
859
|
+
* - Single domain focus: All functions related to project type detection
|
|
860
|
+
* - Composability: Functions can be combined to create complex behavior
|
|
861
|
+
*
|
|
862
|
+
* CODING STANDARDS:
|
|
863
|
+
* - Function names use camelCase with descriptive verbs (validate, format, parse, transform)
|
|
864
|
+
* - All functions should be pure (same input = same output, no side effects)
|
|
865
|
+
* - Use explicit return types
|
|
866
|
+
* - Document complex logic with JSDoc comments
|
|
867
|
+
* - Keep functions small and focused on single responsibility
|
|
868
|
+
*
|
|
869
|
+
* AVOID:
|
|
870
|
+
* - Side effects (mutations, I/O, random values, Date.now(), etc.)
|
|
871
|
+
* - Stateful behavior or closures with mutable state
|
|
872
|
+
* - Dependencies on external services or global variables
|
|
873
|
+
* - Classes (use pure functions instead)
|
|
874
|
+
*/
|
|
875
|
+
/**
|
|
684
876
|
* Monorepo configuration files that indicate a monorepo setup
|
|
685
877
|
*/
|
|
686
878
|
const MONOREPO_INDICATOR_FILES = [
|
|
@@ -706,7 +898,7 @@ const MONOREPO_INDICATOR_FILES = [
|
|
|
706
898
|
async function detectProjectType(workspaceRoot) {
|
|
707
899
|
const indicators = [];
|
|
708
900
|
const toolkitYamlPath = path.join(workspaceRoot, "toolkit.yaml");
|
|
709
|
-
if (await
|
|
901
|
+
if (await pathExists(toolkitYamlPath)) try {
|
|
710
902
|
const content = await fs.readFile(toolkitYamlPath, "utf-8");
|
|
711
903
|
const config = yaml.load(content);
|
|
712
904
|
if (config?.projectType) {
|
|
@@ -717,19 +909,16 @@ async function detectProjectType(workspaceRoot) {
|
|
|
717
909
|
};
|
|
718
910
|
}
|
|
719
911
|
} catch {}
|
|
720
|
-
for (const filename of MONOREPO_INDICATOR_FILES) {
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
indicators
|
|
727
|
-
};
|
|
728
|
-
}
|
|
912
|
+
for (const filename of MONOREPO_INDICATOR_FILES) if (await pathExists(path.join(workspaceRoot, filename))) {
|
|
913
|
+
indicators.push(`${filename} found`);
|
|
914
|
+
return {
|
|
915
|
+
projectType: ProjectType.MONOREPO,
|
|
916
|
+
indicators
|
|
917
|
+
};
|
|
729
918
|
}
|
|
730
919
|
const packageJsonPath = path.join(workspaceRoot, "package.json");
|
|
731
|
-
if (await
|
|
732
|
-
if ((await
|
|
920
|
+
if (await pathExists(packageJsonPath)) try {
|
|
921
|
+
if ((await readJson(packageJsonPath)).workspaces) {
|
|
733
922
|
indicators.push("package.json with workspaces found");
|
|
734
923
|
return {
|
|
735
924
|
projectType: ProjectType.MONOREPO,
|
|
@@ -765,4 +954,4 @@ async function isMonolith(workspaceRoot) {
|
|
|
765
954
|
}
|
|
766
955
|
|
|
767
956
|
//#endregion
|
|
768
|
-
export { ConfigSource, ProjectConfigResolver, ProjectFinderService, ProjectType, ScaffoldProcessingService, TemplatesManagerService, detectProjectType, icons, isMonolith, isMonorepo, log, logger, messages, print, sections };
|
|
957
|
+
export { ConfigSource, ProjectConfigResolver, ProjectFinderService, ProjectType, ScaffoldProcessingService, TemplatesManagerService, accessSync, copy, cp, detectProjectType, ensureDir, ensureDirSync, fs, icons, isMonolith, isMonorepo, log, logger, messages, mkdir, mkdirSync, move, outputFile, pathExists, pathExistsSync, print, readFile, readFileSync, readJson, readJsonSync, readdir, remove, rename, rm, sections, stat, statSync, unlink, writeFile, writeFileSync, writeJson, writeJsonSync };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agiflowai/aicode-utils",
|
|
3
3
|
"description": "Shared utilities and types for AI-powered code generation, scaffolding, and analysis",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.5",
|
|
5
5
|
"license": "AGPL-3.0",
|
|
6
6
|
"author": "AgiflowIO",
|
|
7
7
|
"repository": {
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"code-generation"
|
|
24
24
|
],
|
|
25
25
|
"main": "./dist/index.cjs",
|
|
26
|
-
"module": "./dist/index.
|
|
26
|
+
"module": "./dist/index.mjs",
|
|
27
27
|
"types": "./dist/index.d.cts",
|
|
28
28
|
"files": [
|
|
29
29
|
"dist",
|
|
@@ -31,18 +31,16 @@
|
|
|
31
31
|
],
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"chalk": "5.6.2",
|
|
34
|
-
"fs-extra": "11.3.2",
|
|
35
34
|
"js-yaml": "4.1.0",
|
|
36
35
|
"ora": "^9.0.0",
|
|
37
36
|
"pino": "^10.0.0"
|
|
38
37
|
},
|
|
39
38
|
"devDependencies": {
|
|
40
|
-
"@types/fs-extra": "^11.0.4",
|
|
41
39
|
"@types/js-yaml": "^4.0.9",
|
|
42
40
|
"@types/node": "^22.0.0",
|
|
43
41
|
"@types/ora": "^3.2.0",
|
|
44
42
|
"@vitest/coverage-v8": "^3.0.0",
|
|
45
|
-
"tsdown": "^0.
|
|
43
|
+
"tsdown": "^0.16.4",
|
|
46
44
|
"typescript": "5.9.3",
|
|
47
45
|
"vitest": "^3.0.0"
|
|
48
46
|
},
|
|
@@ -52,7 +50,7 @@
|
|
|
52
50
|
},
|
|
53
51
|
"exports": {
|
|
54
52
|
".": {
|
|
55
|
-
"import": "./dist/index.
|
|
53
|
+
"import": "./dist/index.mjs",
|
|
56
54
|
"require": "./dist/index.cjs"
|
|
57
55
|
},
|
|
58
56
|
"./package.json": "./package.json"
|