pdf_signature/tool/prune_unused_steps.dart

97 lines
2.9 KiB
Dart

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/<file>.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<String> 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<File>()
.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/<file>.dart';
final importRegex = RegExp(r'''import ['"]\./step/([^'\"]+)['"];\s*''');
final imported = <String>{};
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 = <File>[];
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;
}