@timeax/scaffold 0.0.1 → 0.0.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.
package/src/cli/main.ts CHANGED
@@ -5,6 +5,7 @@ import { Command } from 'commander';
5
5
  import { runOnce, RunOptions } from '../core/runner';
6
6
  import { watchScaffold } from '../core/watcher';
7
7
  import {
8
+ ensureStructureFilesFromConfig,
8
9
  scanDirectoryToStructureText,
9
10
  writeScannedStructuresFromConfig,
10
11
  } from '../core/scan-structure';
@@ -170,6 +171,30 @@ async function handleInitCommand(
170
171
  );
171
172
  }
172
173
 
174
+
175
+ async function handleStructuresCommand(
176
+ cwd: string,
177
+ baseOpts: BaseCliOptions,
178
+ ) {
179
+ const logger = createCliLogger(baseOpts);
180
+
181
+ logger.info('Ensuring structure files declared in config exist...');
182
+
183
+ const { created, existing } = await ensureStructureFilesFromConfig(cwd, {
184
+ scaffoldDirOverride: baseOpts.dir,
185
+ });
186
+
187
+ if (created.length === 0) {
188
+ logger.info('All structure files already exist. Nothing to do.');
189
+ } else {
190
+ for (const filePath of created) {
191
+ logger.info(`Created structure file: ${filePath}`);
192
+ }
193
+ }
194
+
195
+ existing.forEach((p) => logger.debug(`Structure file already exists: ${p}`));
196
+ }
197
+
173
198
  async function main() {
174
199
  const cwd = process.cwd();
175
200
 
@@ -234,9 +259,22 @@ async function main() {
234
259
  await handleRunCommand(cwd, opts);
235
260
  });
236
261
 
262
+ interface StructuresCliOptions { }
263
+
264
+ program
265
+ .command('structures')
266
+ .description(
267
+ 'Create missing structure files specified in the config (does not overwrite existing files)',
268
+ )
269
+ .action(async (_opts: StructuresCliOptions, cmd: Command) => {
270
+ const baseOpts = cmd.parent?.opts<BaseCliOptions>() ?? {};
271
+ await handleStructuresCommand(cwd, baseOpts);
272
+ });
273
+
237
274
  await program.parseAsync(process.argv);
238
275
  }
239
276
 
277
+
240
278
  // Run and handle errors
241
279
  main().catch((err) => {
242
280
  defaultLogger.error(err);
@@ -211,4 +211,75 @@ export async function writeScannedStructuresFromConfig(
211
211
  `Wrote structure for group "${result.groupName}" to ${result.structureFilePath}`,
212
212
  );
213
213
  }
214
+ }
215
+
216
+
217
+
218
+ export interface EnsureStructuresResult {
219
+ created: string[];
220
+ existing: string[];
221
+ }
222
+
223
+ /**
224
+ * Ensure all structure files declared in the config exist.
225
+ *
226
+ * - Grouped mode: one file per group (group.structureFile || `${group.name}.txt`)
227
+ * - Single-root mode: config.structureFile || "structure.txt"
228
+ *
229
+ * Existing files are left untouched. Only missing files are created with
230
+ * a small header comment.
231
+ */
232
+ export async function ensureStructureFilesFromConfig(
233
+ cwd: string,
234
+ options: { scaffoldDirOverride?: string } = {},
235
+ ): Promise<EnsureStructuresResult> {
236
+ const { config, scaffoldDir } = await loadScaffoldConfig(cwd, {
237
+ scaffoldDir: options.scaffoldDirOverride,
238
+ });
239
+
240
+ ensureDirSync(scaffoldDir);
241
+
242
+ const created: string[] = [];
243
+ const existing: string[] = [];
244
+
245
+ const seen = new Set<string>();
246
+
247
+ const ensureFile = (fileName: string) => {
248
+ if (!fileName) return;
249
+
250
+ const filePath = path.join(scaffoldDir, fileName);
251
+ const key = path.resolve(filePath);
252
+
253
+ if (seen.has(key)) return;
254
+ seen.add(key);
255
+
256
+ if (fs.existsSync(filePath)) {
257
+ existing.push(filePath);
258
+ return;
259
+ }
260
+
261
+ const header =
262
+ `# ${fileName}\n` +
263
+ `# Structure file for @timeax/scaffold\n` +
264
+ `# Define your desired folders/files here.\n`;
265
+
266
+ fs.writeFileSync(filePath, header, 'utf8');
267
+ created.push(filePath);
268
+ };
269
+
270
+ if (config.groups && config.groups.length > 0) {
271
+ for (const group of config.groups) {
272
+ const fileName = group.structureFile ?? `${group.name}.txt`;
273
+ ensureFile(fileName);
274
+ }
275
+ } else {
276
+ const fileName = config.structureFile ?? 'structure.txt';
277
+ ensureFile(fileName);
278
+ }
279
+
280
+ logger.debug(
281
+ `ensureStructureFilesFromConfig: created=${created.length}, existing=${existing.length}`,
282
+ );
283
+
284
+ return { created, existing };
214
285
  }