import 'dart:io'; /// Prunes unused step files under test/features/step. /// /// Heuristic: A step file is considered used if any test under test/features /// imports it like: `import './step/.dart';` (as generated by bdd_widget_test). /// Otherwise it's unused and can be deleted. /// /// Usage: /// dart run tool/prune_unused_steps.dart # dry-run (prints list) /// dart run tool/prune_unused_steps.dart --delete # delete unused files /// dart run tool/prune_unused_steps.dart --verbose # show details void main(List args) { final delete = args.contains('--delete'); final verbose = args.contains('--verbose'); final stepDir = Directory('test/features/step'); final testsDir = Directory('test/features'); if (!stepDir.existsSync()) { stderr.writeln('Step folder not found at ${stepDir.path}'); exitCode = 2; return; } if (!testsDir.existsSync()) { stderr.writeln('Tests folder not found at ${testsDir.path}'); exitCode = 2; return; } // Collect all step files (exclude private helpers like _world.dart) final stepFiles = stepDir .listSync(recursive: false) .whereType() .where((f) => f.path.endsWith('.dart')) .where((f) => !basename(f.path).startsWith('_')) .toList(); // Collect all step imports from generated tests // Matches imports like: import './step/.dart'; final importRegex = RegExp(r'''import ['"]\./step/([^'\"]+)['"];\s*'''); final imported = {}; for (final entity in testsDir.listSync(recursive: true)) { if (entity is! File) continue; if (!entity.path.endsWith('_test.dart')) continue; final content = entity.readAsStringSync(); for (final m in importRegex.allMatches(content)) { imported.add(m.group(1)!); } } final unused = []; for (final f in stepFiles) { final name = basename(f.path); final isUsed = imported.contains(name); if (verbose) { stdout.writeln('- ${isUsed ? 'USED ' : 'UNUSED '} $name'); } if (!isUsed) unused.add(f); } if (unused.isEmpty) { stdout.writeln('No unused step files found.'); return; } stdout.writeln('Unused step files (${unused.length}):'); for (final f in unused) { stdout.writeln(' ${relative(f.path)}'); } if (!delete) { stdout.writeln('\nDry-run. Re-run with --delete to remove these files.'); return; } // Delete unused files var deleted = 0; for (final f in unused) { try { f.deleteSync(); deleted++; } catch (e) { stderr.writeln('Failed to delete ${f.path}: $e'); } } stdout.writeln('Deleted $deleted unused step files.'); } String basename(String path) => path.split(RegExp(r'[\\/]')).last; String relative(String path) { final cwd = Directory.current.path.replaceAll('\\\\', '/'); final norm = path.replaceAll('\\\\', '/'); return norm.startsWith('$cwd/') ? norm.substring(cwd.length + 1) : norm; }