From be7c7e3e45f4bb7c420b2fbaba27ac64bfc8952d Mon Sep 17 00:00:00 2001 From: Valentin Vignal <32538273+ValentinVignal@users.noreply.github.com> Date: Sat, 22 Jul 2023 03:09:25 +0800 Subject: [PATCH] Suggest a potential valid name for the flutter project when using `flutter create` (#130900) Fixes https://github.com/flutter/flutter/issues/109775 *If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].* --- .../lib/src/commands/create_base.dart | 30 +++++++++++++++++-- .../commands.shard/permeable/create_test.dart | 7 +++-- .../general.shard/create_config_test.dart | 12 ++++++++ 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/packages/flutter_tools/lib/src/commands/create_base.dart b/packages/flutter_tools/lib/src/commands/create_base.dart index 36e84c40f4d..b0de202c94b 100644 --- a/packages/flutter_tools/lib/src/commands/create_base.dart +++ b/packages/flutter_tools/lib/src/commands/create_base.dart @@ -784,12 +784,38 @@ bool isValidPackageName(String name) { !_keywords.contains(name); } +/// Returns a potential valid name from the given [name]. +/// +/// If a valid name cannot be found, returns `null`. +@visibleForTesting +String? potentialValidPackageName(String name){ + String newName = name.toLowerCase(); + if (newName.startsWith(RegExp(r'[0-9]'))) { + newName = '_$newName'; + } + newName = newName.replaceAll('-', '_'); + if (isValidPackageName(newName)) { + return newName; + } else { + return null; + } +} + // Return null if the project name is legal. Return a validation message if // we should disallow the project name. String? _validateProjectName(String projectName) { if (!isValidPackageName(projectName)) { - return '"$projectName" is not a valid Dart package name.\n\n' - 'See https://dart.dev/tools/pub/pubspec#name for more information.'; + final String? potentialValidName = potentialValidPackageName(projectName); + + return [ + '"$projectName" is not a valid Dart package name.', + '\n\n', + 'The name should be all lowercase, with underscores to separate words, "just_like_this".', + 'Use only basic Latin letters and Arabic digits: [a-z0-9_].', + "Also, make sure the name is a valid Dart identifier—that it doesn't start with digits and isn't a reserved word.\n", + 'See https://dart.dev/tools/pub/pubspec#name for more information.', + if (potentialValidName != null) '\nTry "$potentialValidName" instead.', + ].join(); } if (_packageDependencies.contains(projectName)) { return "Invalid project name: '$projectName' - this will conflict with Flutter " diff --git a/packages/flutter_tools/test/commands.shard/permeable/create_test.dart b/packages/flutter_tools/test/commands.shard/permeable/create_test.dart index 1663f8cdaf2..4e5488513fb 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/create_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/create_test.dart @@ -735,10 +735,13 @@ void main() { testUsingContext('plugin project with invalid custom project name', () async { expect( () => _createProject(projectDir, - ['--no-pub', '--template=plugin', '--project-name', 'xyz.xyz', '--platforms', 'android,ios',], + ['--no-pub', '--template=plugin', '--project-name', 'xyz-xyz', '--platforms', 'android,ios',], [], ), - throwsToolExit(message: '"xyz.xyz" is not a valid Dart package name.'), + allOf( + throwsToolExit(message: '"xyz-xyz" is not a valid Dart package name.'), + throwsToolExit(message: 'Try "xyz_xyz" instead.'), + ), ); }); diff --git a/packages/flutter_tools/test/general.shard/create_config_test.dart b/packages/flutter_tools/test/general.shard/create_config_test.dart index 4d41ec9e965..bc48b2d998d 100644 --- a/packages/flutter_tools/test/general.shard/create_config_test.dart +++ b/packages/flutter_tools/test/general.shard/create_config_test.dart @@ -20,6 +20,18 @@ void main() { expect(isValidPackageName('Foo_bar'), false); }); + test('Suggests a valid Pub package name', () { + expect(potentialValidPackageName('92'), '_92'); + expect(potentialValidPackageName('a-b-c'), 'a_b_c'); + + + expect(potentialValidPackageName('Foo_bar'), 'foo_bar'); + expect(potentialValidPackageName('foo-_bar'), 'foo__bar'); + + expect(potentialValidPackageName('잘못된 이름'), isNull, reason: 'It should return null if it cannot find a valid name.'); + + }); + test('kWindowsDrivePattern', () { expect(CreateBase.kWindowsDrivePattern.hasMatch(r'D:\'), isFalse); expect(CreateBase.kWindowsDrivePattern.hasMatch(r'z:\'), isFalse);