magic_value_extractor 0.1.0
magic_value_extractor: ^0.1.0 copied to clipboard
Extracts hard-coded magic strings and numbers from Dart and Flutter sources into AppStrings / AppNumbers constants and rewrites the call sites for you.
example/README.md
example — before and after #
example/demo/ is a small project you can actually run the tool on. It needs no
Flutter SDK: demo/lib/flutter_stub.dart contains minimal widget-like classes,
so dart analyze can prove that the converted code still compiles.
The sample UI text is Japanese on purpose — that is what the built-in naming dictionary is for.
Running it #
As a dev_dependency (the normal way) #
Add magic_value_extractor to demo/ and run it from there.
cd example/demo
dart pub add --dev 'magic_value_extractor:{"path":"../.."}'
dart pub get
# See what would change first
dart run magic_value_extractor --target=lib/ --output=lib/constants/ \
--dry-run --verbose
# Apply it, then check that everything still compiles
dart run magic_value_extractor --target=lib/ --output=lib/constants/
dart analyze
From a clone of this repository #
--project-root points the tool at another project without adding anything to
that project's dependencies.
# in the repository root
dart pub get
dart run bin/magic_value_extractor.dart \
--project-root=example/demo --target=lib/ --output=lib/constants/ \
--dry-run --verbose
Either way, git checkout example/demo && git clean -fd example/demo resets it.
Before #
class LoginScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(16.0),
// ログインボタンのコンテナ
child: Text('ログインに失敗しました'),
);
}
}
After #
import 'package:demo/constants/app_numbers.dart';
import 'package:demo/constants/app_strings.dart';
class LoginScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(AppNumbers.double_16_0), // 16.0
// ログインボタンのコンテナ
child: Text(AppStrings.loginFailed), // 'ログインに失敗しました'
);
}
}
lib/constants/app_strings.dart #
/// Constants collected by `magic_value_extractor`.
class AppStrings {
const AppStrings._();
/// `'ログインに失敗しました'`
///
/// - lib/ui/login_screen.dart:11:19 (LoginScreen.build / Text)
static const String loginFailed = 'ログインに失敗しました';
}
lib/constants/app_numbers.dart #
/// Constants collected by `magic_value_extractor`.
class AppNumbers {
const AppNumbers._();
/// `16.0`
///
/// - lib/ui/login_screen.dart:9:31 (LoginScreen.build / EdgeInsets.all)
static const double double_16_0 = 16.0;
}
Values the demo deliberately leaves alone #
| Value | Why it is skipped |
|---|---|
'https://example.com/api/login' |
URL |
'assets/images/logo.png' |
asset path |
'#FF00FF' |
hex colour code |
r'^\d{4}$' |
regular expression / RegExp() argument |
'' |
empty string |
0, 1, -1, 0.0, 1.0 |
common numbers |
the argument of debugPrint('...') |
logging call |
the argument of Key('...') |
widget key |
a line marked // magic:ignore |
explicit exclusion |