@tiveor/scg 0.2.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +188 -41
  2. package/dist/chunk-XKYTW4HW.js +589 -0
  3. package/dist/chunk-XKYTW4HW.js.map +1 -0
  4. package/dist/cli.cjs +779 -0
  5. package/dist/cli.cjs.map +1 -0
  6. package/dist/cli.d.cts +1 -0
  7. package/dist/cli.d.ts +1 -0
  8. package/dist/cli.js +173 -0
  9. package/dist/cli.js.map +1 -0
  10. package/dist/index.cjs +991 -0
  11. package/dist/index.cjs.map +1 -0
  12. package/dist/index.d.cts +653 -0
  13. package/dist/index.d.ts +653 -0
  14. package/dist/index.js +373 -0
  15. package/dist/index.js.map +1 -0
  16. package/package.json +50 -7
  17. package/templates/express-route/controller.ejs +35 -0
  18. package/templates/express-route/routes.ejs +10 -0
  19. package/templates/express-route/scaffold.json +13 -0
  20. package/templates/express-route/service.ejs +16 -0
  21. package/templates/github-action/scaffold.json +12 -0
  22. package/templates/github-action/workflow.ejs +33 -0
  23. package/templates/react-component/component.ejs +25 -0
  24. package/templates/react-component/index.ejs +2 -0
  25. package/templates/react-component/scaffold.json +15 -0
  26. package/templates/react-component/styles.ejs +4 -0
  27. package/templates/react-component/test.ejs +14 -0
  28. package/templates/vue-component/component.ejs +19 -0
  29. package/templates/vue-component/scaffold.json +12 -0
  30. package/templates/vue-component/test.ejs +16 -0
  31. package/.prettierignore +0 -1
  32. package/.prettierrc +0 -10
  33. package/.travis.yml +0 -9
  34. package/example/ejs/conditional.ejs +0 -9
  35. package/example/ejs/hello.ejs +0 -8
  36. package/example/handlebars/conditional.handlebars +0 -9
  37. package/example/handlebars/hello.handlebars +0 -6
  38. package/example/index.js +0 -180
  39. package/example/pug/conditional.pug +0 -4
  40. package/example/pug/hello.pug +0 -3
  41. package/index.js +0 -15
  42. package/src/command_helper.js +0 -41
  43. package/src/ejs_helper.js +0 -30
  44. package/src/file_helper.js +0 -140
  45. package/src/handlebars_helper.js +0 -32
  46. package/src/param_helper.js +0 -25
  47. package/src/pug_helper.js +0 -28
  48. package/src/string_helper.js +0 -18
  49. package/src/template_builder.js +0 -38
  50. package/src/template_handlers.js +0 -7
  51. package/test/test.js +0 -394
@@ -0,0 +1,653 @@
1
+ import fs from 'fs';
2
+
3
+ /**
4
+ * Utility class for common string manipulation operations.
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * StringHelper.replace('Hello {{name}}!', '{{name}}', 'World');
9
+ * // => "Hello World!"
10
+ *
11
+ * StringHelper.capitalize('hello');
12
+ * // => "Hello"
13
+ * ```
14
+ */
15
+ declare class StringHelper {
16
+ /**
17
+ * Escapes all regex special characters in a string.
18
+ *
19
+ * @param string - The string to escape
20
+ * @returns The escaped string safe for use in `new RegExp()`
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * StringHelper.escapeRegex('$100.00 (test)');
25
+ * // => "\\$100\\.00 \\(test\\)"
26
+ * ```
27
+ */
28
+ static escapeRegex(string: string): string;
29
+ /**
30
+ * Replaces all occurrences of a token in a string. The token is treated
31
+ * as a literal string (regex special characters are escaped automatically).
32
+ *
33
+ * @param line - The source string to search in. Returns `''` if not a string.
34
+ * @param token - The token to search for. Returns `line` unchanged if not a string.
35
+ * @param value - The replacement value
36
+ * @returns The string with all occurrences replaced
37
+ *
38
+ * @example
39
+ * ```typescript
40
+ * StringHelper.replace('Price: $10.00', '$10.00', '$20.00');
41
+ * // => "Price: $20.00"
42
+ * ```
43
+ */
44
+ static replace(line: unknown, token: unknown, value: string): string;
45
+ /**
46
+ * Capitalizes the first character of a string.
47
+ *
48
+ * @param s - The string to capitalize. Returns `''` if not a string.
49
+ * @returns The string with the first character uppercased
50
+ *
51
+ * @example
52
+ * ```typescript
53
+ * StringHelper.capitalize('hello world');
54
+ * // => "Hello world"
55
+ * ```
56
+ */
57
+ static capitalize(s: unknown): string;
58
+ }
59
+
60
+ /** Defines a single token replacement with optional template-based dynamic replacement. */
61
+ interface Replacement {
62
+ /** The token string to search for in the template (e.g., `'{{name}}'`). */
63
+ token: string;
64
+ /** The static value to replace the token with. */
65
+ value?: string;
66
+ /** Path to a sub-template for dynamic replacement. */
67
+ template?: string;
68
+ /** Variables for dynamic replacement keyed by identifier. */
69
+ variables?: Record<string, Replacement[]>;
70
+ }
71
+ /** Options for creating a file from a template with variable replacements. */
72
+ interface CreateFileOptions {
73
+ /** Path to the template file. */
74
+ template: string;
75
+ /** Path for the output file. */
76
+ newFile: string;
77
+ /** Array of token replacements to apply. */
78
+ variables: Replacement[];
79
+ }
80
+ /** Options for creating a string from a template with variable replacements. */
81
+ interface CreateStringOptions {
82
+ /** Path to the template file. */
83
+ template: string;
84
+ /** Array of token replacements to apply. */
85
+ variables: Replacement[];
86
+ }
87
+ /**
88
+ * Utility class for file system operations, both synchronous and asynchronous.
89
+ *
90
+ * Provides methods for reading, writing, creating, and removing files and directories,
91
+ * as well as template-based file generation with variable replacement.
92
+ *
93
+ * @example
94
+ * ```typescript
95
+ * // Sync
96
+ * const content = FileHelper.readFileToString('config.txt');
97
+ * const config = FileHelper.convertJsonFileToObject('config.json');
98
+ *
99
+ * // Async
100
+ * const data = await FileHelper.readFileAsync('config.txt');
101
+ * await FileHelper.writeFileAsync('output.txt', 'content');
102
+ * ```
103
+ */
104
+ declare class FileHelper {
105
+ /**
106
+ * Reads a file synchronously and returns its content as a UTF-8 string.
107
+ *
108
+ * @param fileName - Path to the file to read
109
+ * @returns The file content as a string
110
+ */
111
+ static readFileToString(fileName: string): string;
112
+ /**
113
+ * Reads a JSON file synchronously and parses it into an object.
114
+ *
115
+ * @typeParam T - The expected type of the parsed object
116
+ * @param fileName - Path to the JSON file
117
+ * @returns The parsed object
118
+ */
119
+ static convertJsonFileToObject<T = unknown>(fileName: string): T;
120
+ /**
121
+ * Creates a directory (and any parent directories) if it doesn't exist.
122
+ *
123
+ * @param folderName - Path to the directory to create
124
+ */
125
+ static createFolder(folderName: string): void;
126
+ /**
127
+ * Removes a directory and all its contents recursively.
128
+ *
129
+ * @param folderName - Path to the directory to remove
130
+ */
131
+ static removeFolder(folderName: string): void;
132
+ /**
133
+ * Removes a file if it exists.
134
+ *
135
+ * @param filename - Path to the file to remove
136
+ */
137
+ static removeFile(filename: string): void;
138
+ /**
139
+ * Reads a file asynchronously and returns its content as a UTF-8 string.
140
+ *
141
+ * @param fileName - Path to the file to read
142
+ * @returns A promise resolving to the file content
143
+ */
144
+ static readFileAsync(fileName: string): Promise<string>;
145
+ /**
146
+ * Reads a JSON file asynchronously and parses it into an object.
147
+ *
148
+ * @typeParam T - The expected type of the parsed object
149
+ * @param fileName - Path to the JSON file
150
+ * @returns A promise resolving to the parsed object
151
+ */
152
+ static readJsonFileAsync<T = unknown>(fileName: string): Promise<T>;
153
+ /**
154
+ * Writes content to a file asynchronously, creating parent directories as needed.
155
+ *
156
+ * @param fileName - Path to the file to write
157
+ * @param content - The string content to write
158
+ */
159
+ static writeFileAsync(fileName: string, content: string): Promise<void>;
160
+ /**
161
+ * Creates a directory asynchronously (with recursive parent creation).
162
+ *
163
+ * @param folderName - Path to the directory to create
164
+ */
165
+ static createFolderAsync(folderName: string): Promise<void>;
166
+ /**
167
+ * Removes a directory and its contents recursively (async).
168
+ *
169
+ * @param folderName - Path to the directory to remove
170
+ */
171
+ static removeFolderAsync(folderName: string): Promise<void>;
172
+ /**
173
+ * Removes a file asynchronously.
174
+ *
175
+ * @param filename - Path to the file to remove
176
+ */
177
+ static removeFileAsync(filename: string): Promise<void>;
178
+ /**
179
+ * Checks whether a file or directory exists asynchronously.
180
+ *
181
+ * @param filePath - Path to check
182
+ * @returns `true` if the path exists, `false` otherwise
183
+ */
184
+ static existsAsync(filePath: string): Promise<boolean>;
185
+ /**
186
+ * Performs a simple token replacement on a single line.
187
+ *
188
+ * @param line - The source line
189
+ * @param replacement - The replacement definition (uses `token` and `value`)
190
+ * @returns The line with the token replaced
191
+ */
192
+ static simpleReplace(line: string, replacement: Replacement): string;
193
+ /**
194
+ * Performs dynamic replacement using a sub-template and variables.
195
+ * Reads the sub-template line by line and applies all variable replacements.
196
+ *
197
+ * @param replacement - The replacement definition with `template` and `variables`
198
+ * @returns A promise resolving to the processed string
199
+ */
200
+ static dynamicReplace(replacement: Replacement): Promise<string>;
201
+ /**
202
+ * Creates a new file from a template file, applying variable replacements line by line.
203
+ * The special token `@date` is automatically replaced with the current UTC date.
204
+ *
205
+ * @param options - The template path, output path, and variables to apply
206
+ *
207
+ * @example
208
+ * ```typescript
209
+ * await FileHelper.createFileFromFile({
210
+ * template: 'templates/component.txt',
211
+ * newFile: 'output/Button.tsx',
212
+ * variables: [
213
+ * { token: '{{name}}', value: 'Button' },
214
+ * { token: '{{style}}', value: 'primary' }
215
+ * ]
216
+ * });
217
+ * ```
218
+ */
219
+ static createFileFromFile({ template, newFile, variables }: CreateFileOptions): Promise<void>;
220
+ /**
221
+ * Creates a string from a template file, applying variable replacements line by line.
222
+ * The special token `@date` is automatically replaced with the current UTC date.
223
+ *
224
+ * @param options - The template path and variables to apply
225
+ * @returns A promise resolving to the processed string
226
+ */
227
+ static createStringFromFile({ template, variables }: CreateStringOptions): Promise<string>;
228
+ /**
229
+ * Reads a file line by line and invokes a callback for each line.
230
+ *
231
+ * @param fileName - Path to the file to read
232
+ * @param callback - Function called for each line
233
+ */
234
+ static readLineByLine(fileName: string, callback: (line: string) => void | Promise<void>): Promise<void>;
235
+ /**
236
+ * Creates a writable stream for appending to a file.
237
+ *
238
+ * @param filename - Path to the file
239
+ * @returns A writable stream in append mode
240
+ */
241
+ static writer(filename: string): fs.WriteStream;
242
+ /**
243
+ * Writes a single line to a writable stream with CRLF line ending.
244
+ *
245
+ * @param writer - The writable stream
246
+ * @param newLine - The line content to write
247
+ */
248
+ static writeLineByLine(writer: fs.WriteStream, newLine: string): Promise<void>;
249
+ }
250
+
251
+ /**
252
+ * Utility class for executing shell commands as promises with input sanitization.
253
+ *
254
+ * Commands are validated against a set of forbidden patterns (shell metacharacters,
255
+ * command substitution, path traversal) before execution.
256
+ *
257
+ * @example
258
+ * ```typescript
259
+ * const output = await CommandHelper.run('.', 'echo hello');
260
+ * const version = await CommandHelper.runClean('.', 'node --version');
261
+ * ```
262
+ */
263
+ declare class CommandHelper {
264
+ /**
265
+ * Executes one or more shell commands in the given directory.
266
+ * Multiple commands are joined with `&&` (sequential execution).
267
+ *
268
+ * @param directory - Working directory for command execution
269
+ * @param command - One or more command strings to execute
270
+ * @returns A promise resolving to the command's stdout (or stderr if stdout is empty)
271
+ * @throws If the directory is empty, no commands are provided, or a command matches a forbidden pattern
272
+ *
273
+ * @example
274
+ * ```typescript
275
+ * const output = await CommandHelper.run('.', 'echo hello');
276
+ * // => "hello\n"
277
+ *
278
+ * const result = await CommandHelper.run('.', 'git add .', 'git status');
279
+ * ```
280
+ */
281
+ static run(directory: string, ...command: string[]): Promise<string>;
282
+ /**
283
+ * Executes commands and returns the output with newlines stripped.
284
+ *
285
+ * @param folder - Working directory for command execution
286
+ * @param command - One or more command strings to execute
287
+ * @returns A promise resolving to the cleaned output (no newlines)
288
+ *
289
+ * @example
290
+ * ```typescript
291
+ * const version = await CommandHelper.runClean('.', 'node --version');
292
+ * // => "v20.10.0"
293
+ * ```
294
+ */
295
+ static runClean(folder: string, ...command: string[]): Promise<string>;
296
+ }
297
+
298
+ /**
299
+ * Utility class for parsing CLI parameters from `process.argv`.
300
+ *
301
+ * @example
302
+ * ```typescript
303
+ * // node script.js --name=Alice --port=3000
304
+ * const params = ParamHelper.getParams();
305
+ * // => { name: "Alice", port: "3000" }
306
+ * ```
307
+ */
308
+ declare class ParamHelper {
309
+ /**
310
+ * Appends a custom parameter string to `process.argv`.
311
+ *
312
+ * @param customParam - The parameter to add (e.g., `'--env=production'`)
313
+ */
314
+ static addCustomParam(customParam: string): void;
315
+ /**
316
+ * Retrieves the command-line argument at the given index.
317
+ *
318
+ * @param index - Zero-based index into `process.argv`
319
+ * @returns The argument at the given index, or `''` if out of bounds
320
+ */
321
+ static getCommandByIndex(index: number): string;
322
+ /**
323
+ * Parses all `--key=value` parameters from `process.argv` into an object.
324
+ * Surrounding quotes on values are stripped automatically.
325
+ *
326
+ * @returns An object mapping parameter names to their string values
327
+ *
328
+ * @example
329
+ * ```typescript
330
+ * // node script.js --name=Alice --port=3000
331
+ * ParamHelper.getParams();
332
+ * // => { name: "Alice", port: "3000" }
333
+ * ```
334
+ */
335
+ static getParams(): Record<string, string>;
336
+ }
337
+
338
+ /**
339
+ * Enum-like object defining the built-in template engine identifiers.
340
+ *
341
+ * @example
342
+ * ```typescript
343
+ * const builder = new TemplateBuilder(TEMPLATE_HANDLERS.EJS);
344
+ * ```
345
+ */
346
+ declare const TEMPLATE_HANDLERS: {
347
+ readonly HANDLEBARS: "HANDLEBARS";
348
+ readonly EJS: "EJS";
349
+ readonly PUG: "PUG";
350
+ };
351
+ /**
352
+ * Union type of all valid built-in template handler names.
353
+ */
354
+ type TemplateHandler = (typeof TEMPLATE_HANDLERS)[keyof typeof TEMPLATE_HANDLERS];
355
+
356
+ /**
357
+ * Interface that custom template engines must implement to be registered
358
+ * with {@link TemplateBuilder.registerEngine}.
359
+ */
360
+ interface TemplateEngine {
361
+ /** Renders a template from a source string with the given data. */
362
+ render: (source: string, data: Record<string, unknown>, options?: Record<string, unknown>) => Promise<string>;
363
+ /** Renders a template from a file path with the given data. */
364
+ renderFile: (fileName: string, data: Record<string, unknown>, options?: Record<string, unknown>) => Promise<string>;
365
+ }
366
+ /**
367
+ * Unified interface to render templates with EJS, Handlebars, Pug, or any custom engine.
368
+ *
369
+ * Supports a plugin system for registering custom template engines at runtime.
370
+ *
371
+ * @example
372
+ * ```typescript
373
+ * // Built-in engines
374
+ * const builder = new TemplateBuilder(TEMPLATE_HANDLERS.EJS);
375
+ * const html = await builder.render('Hello <%= name %>', { name: 'World' });
376
+ *
377
+ * // Custom engine
378
+ * TemplateBuilder.registerEngine('nunjucks', {
379
+ * render: async (source, data) => nunjucks.renderString(source, data),
380
+ * renderFile: async (file, data) => nunjucks.render(file, data),
381
+ * });
382
+ * const nj = new TemplateBuilder('nunjucks');
383
+ * ```
384
+ */
385
+ declare class TemplateBuilder {
386
+ private templateHandler;
387
+ /**
388
+ * Creates a new TemplateBuilder for the specified engine.
389
+ *
390
+ * @param templateHandler - The engine name (e.g., `'EJS'`, `'HANDLEBARS'`, `'PUG'`, or a custom name)
391
+ */
392
+ constructor(templateHandler: TemplateHandler | string);
393
+ /**
394
+ * Registers a custom template engine that can be used with `new TemplateBuilder(name)`.
395
+ *
396
+ * @param name - A unique name for the engine
397
+ * @param engine - An object implementing the {@link TemplateEngine} interface
398
+ * @throws If `name` is empty or `engine` doesn't implement `render()` and `renderFile()`
399
+ *
400
+ * @example
401
+ * ```typescript
402
+ * TemplateBuilder.registerEngine('nunjucks', {
403
+ * render: async (source, data) => nunjucks.renderString(source, data),
404
+ * renderFile: async (file, data) => nunjucks.render(file, data),
405
+ * });
406
+ * ```
407
+ */
408
+ static registerEngine(name: string, engine: TemplateEngine): void;
409
+ /**
410
+ * Retrieves a registered engine by name (custom engines take precedence over built-in).
411
+ *
412
+ * @param name - The engine name to look up
413
+ * @returns The engine implementation, or `undefined` if not found
414
+ */
415
+ static getEngine(name: string): TemplateEngine | undefined;
416
+ /**
417
+ * Returns an array of all registered engine names (built-in + custom).
418
+ *
419
+ * @returns Array of engine name strings
420
+ *
421
+ * @example
422
+ * ```typescript
423
+ * TemplateBuilder.getRegisteredEngines();
424
+ * // => ['HANDLEBARS', 'EJS', 'PUG']
425
+ * ```
426
+ */
427
+ static getRegisteredEngines(): string[];
428
+ private resolveEngine;
429
+ /**
430
+ * Renders a template from a source string.
431
+ *
432
+ * @param source - The template source string
433
+ * @param data - Data object to pass to the template
434
+ * @param options - Optional engine-specific options
435
+ * @returns A promise resolving to the rendered string
436
+ */
437
+ render(source: string, data: Record<string, unknown>, options?: Record<string, unknown>): Promise<string>;
438
+ /**
439
+ * Renders a template from a file path.
440
+ *
441
+ * @param fileName - Path to the template file
442
+ * @param data - Data object to pass to the template
443
+ * @param options - Optional engine-specific options
444
+ * @returns A promise resolving to the rendered string
445
+ */
446
+ renderFile(fileName: string, data: Record<string, unknown>, options?: Record<string, unknown>): Promise<string>;
447
+ }
448
+
449
+ /** A function that transforms a string, optionally returning a promise. */
450
+ type TransformFn = (content: string) => string | Promise<string>;
451
+ /**
452
+ * Chainable pipeline for composing template rendering and string transformations.
453
+ *
454
+ * Supports multiple input sources (string, file, template) and sequential
455
+ * transforms before writing the result to a file or returning it.
456
+ *
457
+ * @example
458
+ * ```typescript
459
+ * const result = await new Pipeline()
460
+ * .fromTemplate('component.ejs', { name: 'Button' }, 'EJS')
461
+ * .transform((content) => content.toUpperCase())
462
+ * .writeTo('src/components/Button.tsx');
463
+ * ```
464
+ */
465
+ declare class Pipeline {
466
+ private content;
467
+ private contentPromise;
468
+ private transforms;
469
+ /**
470
+ * Sets the pipeline content from a raw string.
471
+ *
472
+ * @param source - The string content
473
+ * @returns This pipeline instance for chaining
474
+ */
475
+ fromString(source: string): Pipeline;
476
+ /**
477
+ * Sets the pipeline content by reading a file synchronously.
478
+ *
479
+ * @param filePath - Path to the file to read
480
+ * @returns This pipeline instance for chaining
481
+ */
482
+ fromFile(filePath: string): Pipeline;
483
+ /**
484
+ * Sets the pipeline content by rendering a template file.
485
+ * If no engine is specified, it is auto-detected from the file extension.
486
+ *
487
+ * @param templatePath - Path to the template file
488
+ * @param data - Data to pass to the template
489
+ * @param engine - Template engine name (auto-detected if omitted)
490
+ * @param options - Optional engine-specific options
491
+ * @returns This pipeline instance for chaining
492
+ */
493
+ fromTemplate(templatePath: string, data: Record<string, unknown>, engine?: TemplateHandler | string, options?: Record<string, unknown>): Pipeline;
494
+ /**
495
+ * Sets the pipeline content by rendering a template from a source string.
496
+ *
497
+ * @param source - The template source string
498
+ * @param data - Data to pass to the template
499
+ * @param engine - The template engine name
500
+ * @param options - Optional engine-specific options
501
+ * @returns This pipeline instance for chaining
502
+ */
503
+ fromTemplateString(source: string, data: Record<string, unknown>, engine: TemplateHandler | string, options?: Record<string, unknown>): Pipeline;
504
+ /**
505
+ * Adds a transformation function to the pipeline.
506
+ * Transforms are executed sequentially in the order they are added.
507
+ *
508
+ * @param fn - A sync or async function that receives and returns a string
509
+ * @returns This pipeline instance for chaining
510
+ */
511
+ transform(fn: TransformFn): Pipeline;
512
+ /**
513
+ * Executes the pipeline: resolves the content and applies all transforms.
514
+ *
515
+ * @returns A promise resolving to the final transformed string
516
+ * @throws If no content source has been set
517
+ */
518
+ execute(): Promise<string>;
519
+ /**
520
+ * Executes the pipeline and writes the result to a file.
521
+ * Creates parent directories automatically if they don't exist.
522
+ *
523
+ * @param filePath - Path to the output file
524
+ * @returns A promise resolving to the written content
525
+ */
526
+ writeTo(filePath: string): Promise<string>;
527
+ }
528
+
529
+ /** Defines a single file in a scaffold structure. */
530
+ interface ScaffoldFile {
531
+ /** Relative path to the template file (within `templateDir`). */
532
+ template: string;
533
+ /** Output filename pattern (supports `{{variable}}` interpolation). */
534
+ output: string;
535
+ }
536
+ /** Configuration options for scaffold generation. */
537
+ interface ScaffoldOptions {
538
+ /** Template engine to use (e.g., `'EJS'`, `'HANDLEBARS'`, `'PUG'`). */
539
+ engine: string;
540
+ /** Base directory containing the template files. */
541
+ templateDir: string;
542
+ /** Output directory pattern (supports `{{variable}}` interpolation). */
543
+ outputDir: string;
544
+ /** Variables for template rendering and path interpolation. */
545
+ variables: Record<string, string>;
546
+ /** List of files to generate. */
547
+ structure: ScaffoldFile[];
548
+ /** If `true`, returns the file list without writing files. */
549
+ dryRun?: boolean;
550
+ }
551
+ /** Result of a scaffold generation operation. */
552
+ interface ScaffoldResult {
553
+ /** List of file paths that were created (or would be created in dry-run mode). */
554
+ files: string[];
555
+ /** Whether this was a dry-run execution. */
556
+ dryRun: boolean;
557
+ }
558
+ /**
559
+ * Generates directory structures from a manifest configuration.
560
+ *
561
+ * Reads template files, renders them with the specified engine, and writes
562
+ * the output to a directory structure with variable-interpolated paths.
563
+ *
564
+ * @example
565
+ * ```typescript
566
+ * const result = await Scaffold.from({
567
+ * engine: 'EJS',
568
+ * templateDir: './templates/react-component',
569
+ * outputDir: './src/components/{{name}}',
570
+ * variables: { name: 'UserProfile', style: 'module' },
571
+ * structure: [
572
+ * { template: 'component.ejs', output: '{{name}}.tsx' },
573
+ * { template: 'styles.ejs', output: '{{name}}.module.css' },
574
+ * { template: 'test.ejs', output: '{{name}}.test.tsx' },
575
+ * ]
576
+ * });
577
+ *
578
+ * console.log(result.files); // List of created file paths
579
+ * ```
580
+ */
581
+ declare class Scaffold {
582
+ /**
583
+ * Generates files from a scaffold manifest.
584
+ *
585
+ * @param options - The scaffold configuration
586
+ * @returns A promise resolving to a {@link ScaffoldResult} with the list of created files
587
+ */
588
+ static from(options: ScaffoldOptions): Promise<ScaffoldResult>;
589
+ }
590
+
591
+ /** Configuration options for the file watcher. */
592
+ interface WatcherOptions {
593
+ /** Directory containing template files to watch. */
594
+ templateDir: string;
595
+ /** Directory where rendered output files are written. */
596
+ outputDir: string;
597
+ /** Template engine to use for rendering (e.g., `'EJS'`, `'HANDLEBARS'`, `'PUG'`). */
598
+ engine: string;
599
+ /** Variables to pass to the template engine during rendering. */
600
+ variables: Record<string, unknown>;
601
+ /** File extensions to watch (defaults to `['.ejs', '.hbs', '.handlebars', '.pug']`). */
602
+ extensions?: string[];
603
+ /** Callback invoked after a file is successfully rebuilt. */
604
+ onRebuild?: (file: string) => void;
605
+ /** Callback invoked when a rebuild error occurs. */
606
+ onError?: (error: Error, file: string) => void;
607
+ }
608
+ /**
609
+ * Watches a template directory and automatically re-renders templates when they change.
610
+ *
611
+ * Uses `fs.watch()` with `AbortController` for clean start/stop lifecycle.
612
+ *
613
+ * @example
614
+ * ```typescript
615
+ * const watcher = new Watcher({
616
+ * templateDir: './templates',
617
+ * outputDir: './generated',
618
+ * engine: 'EJS',
619
+ * variables: { project: 'MyApp' },
620
+ * onRebuild: (file) => console.log(`Rebuilt: ${file}`),
621
+ * onError: (err, file) => console.error(`Error in ${file}: ${err.message}`),
622
+ * });
623
+ *
624
+ * watcher.start();
625
+ * // Later: watcher.stop();
626
+ * ```
627
+ */
628
+ declare class Watcher {
629
+ private options;
630
+ private abortController;
631
+ /**
632
+ * Creates a new Watcher instance.
633
+ *
634
+ * @param options - Watcher configuration
635
+ */
636
+ constructor(options: WatcherOptions);
637
+ /**
638
+ * Starts watching the template directory for changes.
639
+ * Does nothing if the watcher is already running.
640
+ */
641
+ start(): void;
642
+ /**
643
+ * Stops watching for changes and cleans up resources.
644
+ */
645
+ stop(): void;
646
+ /**
647
+ * Whether the watcher is currently active.
648
+ */
649
+ get isRunning(): boolean;
650
+ private handleChange;
651
+ }
652
+
653
+ export { CommandHelper, type CreateFileOptions, type CreateStringOptions, FileHelper, ParamHelper, Pipeline, type Replacement, Scaffold, type ScaffoldFile, type ScaffoldOptions, type ScaffoldResult, StringHelper, TEMPLATE_HANDLERS, TemplateBuilder, type TemplateEngine, type TemplateHandler, type TransformFn, Watcher, type WatcherOptions };