Repository: rrousselGit/riverpod

Issue:
[riverpod_generator] ability to change "Provider" postix to something else
**Is your feature request related to a problem? Please describe.**

When using `riverpod_generator`, all providers are generated with the "Provider" postfix. For example:

```dart
@riverpod
Dio dio(DioRef ref) => Dio();
```

in the generated `.g.dart` file, this creates the following provider definition:
```dart
final dioProvider = AutoDisposeProvider<Dio>( ... );
```

Since reading https://github.com/rrousselGit/riverpod/issues/197, I got into the habit of calling my providers "Pods", so in my projects, this would be called `dioPod`, which is 5 letters shorter.

**Describe the solution you'd like**

A parameter in `build.yaml` to change the "Provider" postfix. For example:
```yaml
builders:
  riverpod_generator:
    options:
      providerPostfix: "pod"
```

This may be a niche problem, but it would allow me to transition to `riverpod_generator` with less code refactoring.


Discussion: Sounds good. It's a low priority for me though. If someone wants that, I'd suggest making a pull request. I'd be more than happy to review it
Thank you, I understand that it's a low priority.

This may sound obvious, but I realized that I could do:

```dart
@riverpod
Dio dio(DioRef ref) => Dio();

final dioPod = dioProvider;
```

Although this solution is quite fragile, as there are now two different ways to reference said provider. It would be nicer if somehow I could scope the original reference, but again, that would require modifying it's name and adding a `_` prefix to it.
It seems like scoping is possible!

If I create the method as private (with an underscore `_`), then the generated provider will also begin with an underscore. This way, I can ensure that `_dioProvider` is not referenced anywhere else in the application:

```dart
// create the method as private
@riverpod
Dio _dio(_DioRef ref) => Dio();

// create a non-private reference to the generated provider
final dioPod = _dioProvider;
```

It also works with Notifiers:
```dart
// create a private class
@riverpod
class _FilterController extends _$FilterController { ... }

// create a non-private reference to the generated provider
final filterPod = _filterControllerProvider;
```

Is this something I can rely on, or may it break in a future release?

Fix patch:
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index b1aa47ee29..40f2db1a8b 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -42,6 +42,7 @@ jobs:
           # TODO(rrousselGit) update riverpod_cli test setup to be supported by the CI
           # - packages/riverpod_cli
           - packages/riverpod_generator
+          - packages/riverpod_generator/integration/build_yaml
           # TODO(rrousselGit) update riverpod_graph test setup to be supported by the CI
           # - packages/riverpod_graph
           - packages/riverpod_lint
@@ -62,6 +63,11 @@ jobs:
         run: echo "PUB_CACHE="$HOME/.pub-cache"" >> $GITHUB_ENV
       - name: Install dependencies
         run: flutter pub get
+      - name: Install dependencies (integration/buid.yaml)
+        run: |
+          if test -d "integration/build_yaml"; then
+            flutter pub get integration/build_yaml
+          fi
 
       - name: Check format
         run: flutter format --set-exit-if-changed .
diff --git a/codecov.yml b/codecov.yml
index 66c249eb5c..fb6e9d11f4 100644
--- a/codecov.yml
+++ b/codecov.yml
@@ -1,5 +1,5 @@
 codecov:
-  require_ci_to_pass: yes
+  require_ci_to_pass: true
 
 coverage:
   precision: 2
@@ -21,8 +21,10 @@ ignore:
   - "**/*.g.dart"
   - "**/*.freezed.dart"
   - "packages/riverpod_cli"
+  - "packages/riverpod_generator"
+  - "packages/riverpod_lint"
 
 comment:
   layout: "reach,diff,flags,tree"
   behavior: default
-  require_changes: no
+  require_changes: false
diff --git a/packages/riverpod_generator/README.md b/packages/riverpod_generator/README.md
index 5bfd7db206..d7c135d942 100644
--- a/packages/riverpod_generator/README.md
+++ b/packages/riverpod_generator/README.md
@@ -156,6 +156,21 @@ class Home extends ConsumerWidget {
 }
 ```
 
+## Global configuration
+
+You can change provider name suffix in the build.yaml file:
+
+```yaml
+targets:
+  $default:
+    builders:
+      riverpod_generator:
+        options:
+          # Could be changed to "Pod", such that riverpod_generator
+          # would generate "countPod" instead of "countProvider"
+          provider_name_suffix: "Provider" # (default)
+```
+
 [family]: https://riverpod.dev/docs/concepts/modifiers/family
 [provider]: https://github.com/rrousselGit/provider
 [riverpod]: https://github.com/rrousselGit/riverpod
diff --git a/packages/riverpod_generator/integration/build_yaml/.gitignore b/packages/riverpod_generator/integration/build_yaml/.gitignore
new file mode 100644
index 0000000000..3c8a157278
--- /dev/null
+++ b/packages/riverpod_generator/integration/build_yaml/.gitignore
@@ -0,0 +1,6 @@
+# Files and directories created by pub.
+.dart_tool/
+.packages
+
+# Conventional directory for build output.
+build/
diff --git a/packages/riverpod_generator/integration/build_yaml/README.md b/packages/riverpod_generator/integration/build_yaml/README.md
new file mode 100644
index 0000000000..ab311a3271
--- /dev/null
+++ b/packages/riverpod_generator/integration/build_yaml/README.md
@@ -0,0 +1,23 @@
+# Pub
+
+Install needed global packages
+
+```bash
+cd riverpod
+dart pub global activate melos
+```
+
+Build the riverpod packages
+
+```bash
+fluttter pub get
+```
+
+## Start the tests
+
+```bash
+cd examples/build_yaml
+flutter pub run build_runner build
+
+flutter test
+```
diff --git a/packages/riverpod_generator/integration/build_yaml/build.yaml b/packages/riverpod_generator/integration/build_yaml/build.yaml
new file mode 100644
index 0000000000..7337d42a9e
--- /dev/null
+++ b/packages/riverpod_generator/integration/build_yaml/build.yaml
@@ -0,0 +1,6 @@
+targets:
+  $default:
+    builders:
+      riverpod_generator:
+        options:
+          provider_name_suffix: 'Pod'
\ No newline at end of file
diff --git a/packages/riverpod_generator/integration/build_yaml/lib/main.dart b/packages/riverpod_generator/integration/build_yaml/lib/main.dart
new file mode 100644
index 0000000000..9ece9457b7
--- /dev/null
+++ b/packages/riverpod_generator/integration/build_yaml/lib/main.dart
@@ -0,0 +1,29 @@
+import 'package:riverpod_annotation/riverpod_annotation.dart';
+
+part 'main.g.dart';
+
+@riverpod
+int count(CountRef ref) {
+  return 1;
+}
+
+@riverpod
+FutureOr<int> countFuture(CountFutureRef ref) {
+  return 1;
+}
+
+@riverpod
+class CountNotifier extends _$CountNotifier {
+  @override
+  int build() {
+    return 1;
+  }
+}
+
+@riverpod
+class CountAsyncNotifier extends _$CountAsyncNotifier {
+  @override
+  FutureOr<int> build() {
+    return 1;
+  }
+}
diff --git a/packages/riverpod_generator/integration/build_yaml/lib/main.g.dart b/packages/riverpod_generator/integration/build_yaml/lib/main.g.dart
new file mode 100644
index 0000000000..77a918cf3b
--- /dev/null
+++ b/packages/riverpod_generator/integration/build_yaml/lib/main.g.dart
@@ -0,0 +1,87 @@
+// GENERATED CODE - DO NOT MODIFY BY HAND
+
+part of 'main.dart';
+
+// **************************************************************************
+// RiverpodGenerator
+// **************************************************************************
+
+// ignore_for_file: avoid_private_typedef_functions, non_constant_identifier_names, subtype_of_sealed_class, invalid_use_of_internal_member, unused_element, constant_identifier_names, unnecessary_raw_strings, library_private_types_in_public_api
+
+/// Copied from Dart SDK
+class _SystemHash {
+  _SystemHash._();
+
+  static int combine(int hash, int value) {
+    // ignore: parameter_assignments
+    hash = 0x1fffffff & (hash + value);
+    // ignore: parameter_assignments
+    hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
+    return hash ^ (hash >> 6);
+  }
+
+  static int finish(int hash) {
+    // ignore: parameter_assignments
+    hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
+    // ignore: parameter_assignments
+    hash = hash ^ (hash >> 11);
+    return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
+  }
+}
+
+String _$CountNotifierHash() => r'a8dd7a66ee0002b8af657245c4affaa206fd99ec';
+
+/// See also [CountNotifier].
+final countNotifierPod = AutoDisposeNotifierProvider<CountNotifier, int>(
+  CountNotifier.new,
+  name: r'countNotifierPod',
+  debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
+      ? null
+      : _$CountNotifierHash,
+);
+typedef CountNotifierRef = AutoDisposeNotifierProviderRef<int>;
+
+abstract class _$CountNotifier extends AutoDisposeNotifier<int> {
+  @override
+  int build();
+}
+
+String _$CountAsyncNotifierHash() =>
+    r'2a7049d864bf396e44a5937b4001efb4774a5f29';
+
+/// See also [CountAsyncNotifier].
+final countAsyncNotifierPod =
+    AutoDisposeAsyncNotifierProvider<CountAsyncNotifier, int>(
+  CountAsyncNotifier.new,
+  name: r'countAsyncNotifierPod',
+  debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
+      ? null
+      : _$CountAsyncNotifierHash,
+);
+typedef CountAsyncNotifierRef = AutoDisposeAsyncNotifierProviderRef<int>;
+
+abstract class _$CountAsyncNotifier extends AutoDisposeAsyncNotifier<int> {
+  @override
+  FutureOr<int> build();
+}
+
+String _$countHash() => r'4c7e72b275767a60ece5e8662ab1e28f73cf7e44';
+
+/// See also [count].
+final countPod = AutoDisposeProvider<int>(
+  count,
+  name: r'countPod',
+  debugGetCreateSourceHash:
+      const bool.fromEnvironment('dart.vm.product') ? null : _$countHash,
+);
+typedef CountRef = AutoDisposeProviderRef<int>;
+String _$countFutureHash() => r'ec7cc31ce1c1a10607f1dcb35dd217acd2877729';
+
+/// See also [countFuture].
+final countFuturePod = AutoDisposeFutureProvider<int>(
+  countFuture,
+  name: r'countFuturePod',
+  debugGetCreateSourceHash:
+      const bool.fromEnvironment('dart.vm.product') ? null : _$countFutureHash,
+);
+typedef CountFutureRef = AutoDisposeFutureProviderRef<int>;
diff --git a/packages/riverpod_generator/integration/build_yaml/pubspec.yaml b/packages/riverpod_generator/integration/build_yaml/pubspec.yaml
new file mode 100644
index 0000000000..13c70da214
--- /dev/null
+++ b/packages/riverpod_generator/integration/build_yaml/pubspec.yaml
@@ -0,0 +1,16 @@
+name: build_yaml
+description: A sample command-line application.
+version: 1.0.0
+
+environment:
+  sdk: ">=2.18.4 <3.0.0"
+
+dependencies:
+  riverpod:
+  riverpod_annotation:
+
+dev_dependencies:
+  build_runner: ^2.3.2
+  build_verify: ^3.0.0
+  riverpod_generator:
+  test: ^1.16.0
diff --git a/packages/riverpod_generator/integration/build_yaml/pubspec_overrides.yaml b/packages/riverpod_generator/integration/build_yaml/pubspec_overrides.yaml
new file mode 100644
index 0000000000..e323b7f0b1
--- /dev/null
+++ b/packages/riverpod_generator/integration/build_yaml/pubspec_overrides.yaml
@@ -0,0 +1,8 @@
+# melos_managed_dependency_overrides: riverpod,riverpod_annotation,riverpod_generator
+dependency_overrides:
+  riverpod: 
+    path: ../../../riverpod
+  riverpod_annotation: 
+    path: ../../../riverpod_annotation
+  riverpod_generator: 
+    path: ../..
diff --git a/packages/riverpod_generator/lib/src/models.dart b/packages/riverpod_generator/lib/src/models.dart
index bf718c81cc..545c632137 100644
--- a/packages/riverpod_generator/lib/src/models.dart
+++ b/packages/riverpod_generator/lib/src/models.dart
@@ -16,6 +16,8 @@ enum ProviderType {
   asyncNotifier,
 }
 
+const _defaultProviderNameSuffix = 'Provider';
+
 class Data {
   Data.function({
     required this.rawName,
@@ -29,6 +31,7 @@ class Data {
     required this.providerDoc,
     required this.createElement,
     required this.createAst,
+    required this.buildYamlOptions,
   }) : notifierName = null;
 
   Data.notifier({
@@ -43,6 +46,7 @@ class Data {
     required this.providerDoc,
     required this.createElement,
     required this.createAst,
+    required this.buildYamlOptions,
   }) : functionName = null;
 
   final ExecutableElement createElement;
@@ -57,6 +61,7 @@ class Data {
   final List<ParameterElement> parameters;
   final bool keepAlive;
   final String providerDoc;
+  final BuildYamlOptions buildYamlOptions;
 
   String get hashFunctionName => '_\$${rawName}Hash';
 
@@ -68,13 +73,13 @@ class Data {
   /// foo -> fooProvider
   /// Foo -> fooProvider
   String get providerName {
-    return '${rawName.lowerFirst}Provider';
+    return '${rawName.lowerFirst}$_nameSuffix';
   }
 
   /// foo -> FooProvider
   /// Foo -> FooProvider
   String get providerTypeNameImpl {
-    return '${rawName.titled}Provider';
+    return '${rawName.titled}$_nameSuffix';
   }
 
   /// foo -> FooFamily
@@ -105,6 +110,9 @@ class Data {
 
   bool get isNotifier => functionName == null;
 
+  String get _nameSuffix =>
+      buildYamlOptions.providerNameSuffix ?? _defaultProviderNameSuffix;
+
   String notifierType({bool generics = true}) {
     final trailing = generics ? '<$valueDisplayType>' : '';
     final leading = keepAlive ? '' : 'AutoDispose';
@@ -253,6 +261,20 @@ class GlobalData {
   final ElementHash hash = ElementHash();
 }
 
+class BuildYamlOptions {
+  BuildYamlOptions({
+    this.providerNameSuffix,
+  });
+
+  factory BuildYamlOptions.fromMap(Map<String, dynamic> map) {
+    return BuildYamlOptions(
+      providerNameSuffix: map['provider_name_suffix'] as String?,
+    );
+  }
+
+  final String? providerNameSuffix;
+}
+
 extension on String {
   String get titled {
     return replaceFirstMapped(
diff --git a/packages/riverpod_generator/lib/src/riverpod_generator.dart b/packages/riverpod_generator/lib/src/riverpod_generator.dart
index b6b4c7eec8..912300f34b 100644
--- a/packages/riverpod_generator/lib/src/riverpod_generator.dart
+++ b/packages/riverpod_generator/lib/src/riverpod_generator.dart
@@ -22,9 +22,10 @@ const riverpodTypeChecker = TypeChecker.fromRuntime(Riverpod);
 @immutable
 // ignore: invalid_use_of_internal_member
 class RiverpodGenerator extends ParserGenerator<GlobalData, Data, Riverpod> {
-  RiverpodGenerator(this.configs);
+  RiverpodGenerator(Map<String, Object?> mapConfig)
+      : config = BuildYamlOptions.fromMap(mapConfig);
 
-  final Map<String, Object?> configs;
+  final BuildYamlOptions config;
 
   @override
   GlobalData parseGlobalData(LibraryElement library) {
@@ -78,6 +79,7 @@ class RiverpodGenerator extends ParserGenerator<GlobalData, Data, Riverpod> {
       parameters: element.parameters.skip(1).toList(),
       valueDisplayType:
           _getUserModelType(element).getDisplayString(withNullability: true),
+      buildYamlOptions: config,
     );
   }
 
@@ -129,6 +131,7 @@ class RiverpodGenerator extends ParserGenerator<GlobalData, Data, Riverpod> {
       parameters: buildMethod.parameters,
       valueDisplayType: _getUserModelType(buildMethod)
           .getDisplayString(withNullability: true),
+      buildYamlOptions: config,
     );
   }
 


Test patch:
diff --git a/packages/riverpod_generator/integration/build_yaml/test/build_yaml_test.dart b/packages/riverpod_generator/integration/build_yaml/test/build_yaml_test.dart
new file mode 100644
index 0000000000..f30c4eef41
--- /dev/null
+++ b/packages/riverpod_generator/integration/build_yaml/test/build_yaml_test.dart
@@ -0,0 +1,21 @@
+import 'package:build_verify/build_verify.dart';
+import 'package:build_yaml/main.dart';
+import 'package:test/test.dart';
+
+void main() {
+  test(
+    'ensure_build',
+    () => expectBuildClean(
+      packageRelativeDirectory:
+          'packages/riverpod_generator/integration/build_yaml',
+    ),
+    timeout: const Timeout(Duration(minutes: 1)),
+  );
+
+  test('provider names', () {
+    expect(countPod.name, 'countPod');
+    expect(countFuturePod.name, 'countFuturePod');
+    expect(countNotifierPod.name, 'countNotifierPod');
+    expect(countAsyncNotifierPod.name, 'countAsyncNotifierPod');
+  });
+}
diff --git a/packages/riverpod_generator/test/build_yaml_config_test.dart b/packages/riverpod_generator/test/build_yaml_config_test.dart
new file mode 100644
index 0000000000..df4665de41
--- /dev/null
+++ b/packages/riverpod_generator/test/build_yaml_config_test.dart
@@ -0,0 +1,10 @@
+import 'package:riverpod_generator/src/models.dart';
+import 'package:test/test.dart';
+
+void main() {
+  test('custom suffix', () async {
+    const map = {'provider_name_suffix': 'Pod'};
+    final options = BuildYamlOptions.fromMap(map);
+    expect(options.providerNameSuffix, 'Pod');
+  });
+}