Skip to content

feat: DI - Added first-class Dependency Injection support to FlutterInit with a new wizard option and generated code wiring.#21

Open
noeljabraham wants to merge 2 commits intoArjun544:mainfrom
noeljabraham:feature/dependency_injection
Open

feat: DI - Added first-class Dependency Injection support to FlutterInit with a new wizard option and generated code wiring.#21
noeljabraham wants to merge 2 commits intoArjun544:mainfrom
noeljabraham:feature/dependency_injection

Conversation

@noeljabraham
Copy link
Copy Markdown

@noeljabraham noeljabraham commented Apr 19, 2026

[. ] - Introduced dependencyInjection config option with values: none, get_it.
[. ] - Added DI selection UI in the Misc step and surfaced it in Review & Generate.
[ .] - Wired DI flag through generator context (usesGetItDi) so templates can branch correctly.
[. ] - Added generated DI bootstrap file: lib/src/di/service_locator.dart.
[ .] - App startup now initializes DI via initDependencies() in main.dart.
[. ] - Added conditional get_it dependency in generated pubspec.yaml.
[. ] - Refactored templates to use createAuthRepository() instead of direct AuthRepositoryImpl() construction, enabling centralized DI wiring.
[. ] - Updated docs/config reference and generated README to include DI strategy.
[. ] - Added package info metadata for get_it in the wizard info panel.

Summary by CodeRabbit

New Features

  • Added dependency injection configuration option with "None" and "GetIt" as selectable strategies
  • Dependency injection selection now appears in the configuration wizard and review step
  • GetIt package is automatically included when selected

Documentation

  • Updated project README template to display the selected dependency injection approach

@vercel
Copy link
Copy Markdown

vercel bot commented Apr 19, 2026

@noeljabraham is attempting to deploy a commit to the arjun544's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 19, 2026

Warning

Rate limit exceeded

@noeljabraham has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 46 minutes and 24 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 46 minutes and 24 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3769acae-88e3-408f-9a38-bce77a170a3b

📥 Commits

Reviewing files that changed from the base of the PR and between a2a4061 and 646cd73.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (1)
  • app/lib/generator/index.ts
📝 Walkthrough

Walkthrough

Introduces GetIt dependency injection support to the Flutter scaffold generator. Adds dependencyInjection configuration option with "none" and "get_it" choices, wizard UI for DI selection, schema validation, and templates for service locator initialization and repository wiring across auth components.

Changes

Cohort / File(s) Summary
Configuration & Schema
app/lib/config/schema.ts, docs/configuration.md
Added dependencyInjectionSchema enum, DependencyInjectionStyle type, dependencyInjectionOptions array, and integrated into scaffoldConfigSchema with default value "none".
Wizard UI Components
app/components/wizard/PackageInfoPanel.tsx, app/components/wizard/steps/MiscStep.tsx, app/components/wizard/steps/GenerateStep.tsx
Added GetIt package entry to package selector; added "Dependency Injection" UI section with radio button selection and info button; added DI summary row to review step.
Generator Context
app/lib/generator/index.ts
Extended TemplateContext.flags with usesGetItDi boolean flag, conditionally set based on config.dependencyInjection === "get_it".
Template: Core Setup
templates/flutter/base/lib/main.dart.hbs, templates/flutter/base/pubspec.yaml.hbs, templates/flutter/base/README.md.hbs
Added await initDependencies() call in main; conditionally included get_it: ^8.0.3 dependency; added "Dependency injection" to README content list.
Template: Service Locator DI
templates/flutter/base/lib/src/di/service_locator.dart.hbs, templates/flutter/base/lib/src/imports/core_imports.dart.hbs
New service locator template with GetIt instance, initDependencies() async initializer for lazy singleton registration, and createAuthRepository() factory function; exported from core imports.
Template: State Management & Routing Integration
templates/flutter/base/lib/src/routing/(isGetX)@app_bindings.dart.hbs, templates/flutter/base/lib/src/shared/wrappers/state_wrapper.dart.hbs
Updated GetX bindings and state wrapper to call createAuthRepository() instead of direct AuthRepositoryImpl() instantiation.
Template: Auth Feature Implementation
templates/flutter/partials/features/auth/auth_repository_impl.hbs, templates/flutter/partials/features/auth/auth_logic.hbs, templates/flutter/partials/features/auth/session_provider.hbs, templates/flutter/partials/features/auth/forgot_password_screen.hbs, templates/flutter/partials/features/auth/login_screen.hbs, templates/flutter/partials/features/auth/signup_screen.hbs
Made AuthRepositoryImpl accept injected AuthService via constructor; updated auth logic, session providers, and screen instantiations to use createAuthRepository() factory function.

Sequence Diagram

sequenceDiagram
    participant App as App Startup
    participant Config as AppConfig
    participant DI as initDependencies()
    participant SL as ServiceLocator
    participant Auth as AuthService
    participant Repo as AuthRepository

    App->>Config: await AppConfig.init()
    Config-->>App: ✓ Config ready
    
    alt usesGetItDi enabled
        App->>DI: await initDependencies()
        DI->>SL: GetIt.instance
        SL->>Auth: Register AuthService singleton
        Auth-->>SL: ✓ Registered
        SL->>Repo: Register AuthRepository singleton<br/>(with AuthService dependency)
        Repo-->>SL: ✓ Registered
        DI-->>App: ✓ DI initialized
    end
    
    App->>App: runApp(MyApp)
    App->>Repo: createAuthRepository()
    alt usesGetItDi
        Repo->>SL: sl<AuthRepository>()
        SL-->>Repo: Return singleton instance
    else
        Repo->>Repo: AuthRepositoryImpl(authService: AuthService.instance)
    end
    Repo-->>App: AuthRepository ready
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

  • More fixes #15: Modifies PACKAGE_INFO mapping in PackageInfoPanel.tsx to add multiple package entries; this PR adds the get_it entry to the same structure.
  • Bug fixes #9: Updates templates/flutter/base/lib/main.dart.hbs initialization logic; both PRs modify the same template file for app startup sequencing.

Poem

🐰 Hopping through the code with glee,
GetIt brings dependency spree,
Service locators, clean and bright,
Injecting auth with pure delight!
No more singletons tangled tight, 🎉

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the main feature: adding first-class DI support to FlutterInit with a wizard option and generated code wiring, which aligns with the substantial changes across config schema, UI, templates, and documentation.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (2)
templates/flutter/base/lib/main.dart.hbs (1)

26-26: Coupling note: unconditional call requires the function to always exist.

await initDependencies() is invoked unconditionally, which assumes service_locator.dart.hbs is always generated and always exposes initDependencies() (with the body gated by flags.usesGetItDi). That matches the current template, but if service_locator.dart.hbs is ever made conditional on flags.usesGetItDi, this call site will break the build for the none path. Consider either keeping the template unconditional (current design) or gating this call with {{#if flags.usesGetItDi}} to make the coupling explicit.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@templates/flutter/base/lib/main.dart.hbs` at line 26, The unconditional call
to initDependencies() couples this template to service_locator.dart.hbs; guard
the invocation with the feature flag by wrapping the call in the template
conditional {{`#if` flags.usesGetItDi}}...{{/if}} so the call to
initDependencies() only exists when service_locator.dart.hbs (and its exported
initDependencies function) is generated; reference initDependencies() and
service_locator.dart.hbs when making the change.
templates/flutter/base/lib/src/di/service_locator.dart.hbs (1)

10-22: Minor: empty initDependencies() when DI is disabled.

When flags.usesGetItDi is false the body collapses to an empty async function that main.dart still awaits. It's harmless, but you could either:

  • only emit initDependencies() (and its await call in main.dart) when DI is enabled, or
  • keep it unconditional as an intentional future-proof hook and add a one-line comment noting that.

Also consider registering AuthService by constructing the type directly (e.g., () => AuthService()) rather than () => AuthService.instance, otherwise you're just wrapping an existing singleton in GetIt and both AuthService.instance and sl<AuthService>() remain live references — not incorrect, just redundant.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@templates/flutter/base/lib/src/di/service_locator.dart.hbs` around lines 10 -
22, The generated initDependencies() becomes an empty async function when
flags.usesGetItDi is false; either stop emitting initDependencies() (and its
await in main.dart) when flags.usesGetItDi is false, or keep it always emitted
but add a one-line comment inside to clarify it is an intentional no-op hook;
additionally, when registering AuthService in the block guarded by
flags.usesGetItDi prefer registering a new instance (use () => AuthService())
instead of wrapping AuthService.instance to avoid keeping two live singleton
references—update the registration lines for AuthService and keep the
AuthRepository registration using AuthRepositoryImpl(authService:
sl<AuthService>()) as-is.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/components/wizard/steps/MiscStep.tsx`:
- Around line 249-279: The info <button> is nested inside the <label>, which is
invalid and breaks a11y; refactor the map so each option is a wrapper <div> (or
other non-interactive container) that contains a <label> scoped only to the
RadioGroupItem and its text (use dependencyInjectionOptions and
RadioGroupItem/option.label/option.description), and place the info button
(HugeiconsIcon with InformationCircleIcon) as a sibling element outside the
<label>; keep the existing onClick handler that calls setSelectedItem but ensure
the button still calls e.preventDefault()/e.stopPropagation() so it doesn't
toggle the radio, and preserve the original conditional className logic that
uses config.dependencyInjection to maintain the visual selected state; move the
key={option.value} to the outer wrapper so list keys remain stable.

In `@templates/flutter/base/pubspec.yaml.hbs`:
- Around line 28-33: The get_it dependency is incorrectly listed under the
"State Management" section and uses an outdated constraint; when
flags.usesGetItDi is true, remove the get_it: ^8.0.3 entry from under the State
Management block and instead add a new commented section "# Dependency
Injection" (or similar) where you include get_it with an updated constraint (at
least ^9.0.0, e.g., ^9.0.0 or ^9.2.1); update the Handlebars template around the
conditional (flags.usesGetItDi) so the get_it line is emitted under that new
section rather than next to fpdart/equatable.

In `@templates/flutter/partials/features/auth/auth_logic.hbs`:
- Around line 7-9: The top comment is incorrect: it claims the provider returns
a single instance of AuthRepositoryImpl, but authRepositoryProvider actually
returns createAuthRepository() which may resolve via GetIt and not necessarily
AuthRepositoryImpl; update the comment above authRepositoryProvider to remove
the guarantee of AuthRepositoryImpl and instead state that the provider exposes
an AuthRepository resolved by createAuthRepository() (which may use GetIt).

In `@templates/flutter/partials/features/auth/forgot_password_screen.hbs`:
- Around line 46-47: The template currently sets authStore to null when
flags.usesFlutterHooks is false which causes a null dereference on
authStore.isLoading; change the conditional so you emit two distinct
declarations: when flags.usesFlutterHooks is true generate a memoized store
(useMemoized(() => AuthStore(repository: createAuthRepository()), [])) and when
false generate a plain instance (AuthStore(repository: createAuthRepository()));
ensure the variable name authStore remains the same so subsequent references
like authStore.isLoading compile.

In `@templates/flutter/partials/features/auth/login_screen.hbs`:
- Around line 51-52: The template currently renders authStore as null when
flags.usesFlutterHooks is false because the inline comment breaks the
expression; change the conditional so authStore is always initialized: if
flags.usesFlutterHooks render useMemoized(() => AuthStore(repository:
createAuthRepository()), []), else render AuthStore(repository:
createAuthRepository()); remove the inline comment that caused the null and
ensure usages like isLoading and handleLogin (which reference authStore) work
with the non-null AuthStore instance.

In `@templates/flutter/partials/features/auth/signup_screen.hbs`:
- Around line 56-57: The template currently emits invalid Dart when MobX is
enabled but Flutter Hooks are disabled by assigning authStore to null; instead,
change the template logic around authStore so that when flags.usesFlutterHooks
is true you keep the existing useMemoized invocation, and when false you
instantiate AuthStore directly (AuthStore(repository: createAuthRepository()));
ensure subsequent usages like authStore.isLoading and other authStore references
work with the instantiated AuthStore; update the conditional in
signup_screen.hbs (and mirror the same change in login_screen.hbs and
forgot_password_screen.hbs) to branch between useMemoized(...) and new
AuthStore(...) rather than null.

---

Nitpick comments:
In `@templates/flutter/base/lib/main.dart.hbs`:
- Line 26: The unconditional call to initDependencies() couples this template to
service_locator.dart.hbs; guard the invocation with the feature flag by wrapping
the call in the template conditional {{`#if` flags.usesGetItDi}}...{{/if}} so the
call to initDependencies() only exists when service_locator.dart.hbs (and its
exported initDependencies function) is generated; reference initDependencies()
and service_locator.dart.hbs when making the change.

In `@templates/flutter/base/lib/src/di/service_locator.dart.hbs`:
- Around line 10-22: The generated initDependencies() becomes an empty async
function when flags.usesGetItDi is false; either stop emitting
initDependencies() (and its await in main.dart) when flags.usesGetItDi is false,
or keep it always emitted but add a one-line comment inside to clarify it is an
intentional no-op hook; additionally, when registering AuthService in the block
guarded by flags.usesGetItDi prefer registering a new instance (use () =>
AuthService()) instead of wrapping AuthService.instance to avoid keeping two
live singleton references—update the registration lines for AuthService and keep
the AuthRepository registration using AuthRepositoryImpl(authService:
sl<AuthService>()) as-is.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2c5a91b9-2e99-401d-9922-fef41fe8dc88

📥 Commits

Reviewing files that changed from the base of the PR and between 084c1fc and a2a4061.

📒 Files selected for processing (19)
  • app/components/wizard/PackageInfoPanel.tsx
  • app/components/wizard/steps/GenerateStep.tsx
  • app/components/wizard/steps/MiscStep.tsx
  • app/lib/config/schema.ts
  • app/lib/generator/index.ts
  • docs/configuration.md
  • templates/flutter/base/README.md.hbs
  • templates/flutter/base/lib/main.dart.hbs
  • templates/flutter/base/lib/src/di/service_locator.dart.hbs
  • templates/flutter/base/lib/src/imports/core_imports.dart.hbs
  • templates/flutter/base/lib/src/routing/(isGetX)@app_bindings.dart.hbs
  • templates/flutter/base/lib/src/shared/wrappers/state_wrapper.dart.hbs
  • templates/flutter/base/pubspec.yaml.hbs
  • templates/flutter/partials/features/auth/auth_logic.hbs
  • templates/flutter/partials/features/auth/auth_repository_impl.hbs
  • templates/flutter/partials/features/auth/forgot_password_screen.hbs
  • templates/flutter/partials/features/auth/login_screen.hbs
  • templates/flutter/partials/features/auth/session_provider.hbs
  • templates/flutter/partials/features/auth/signup_screen.hbs

Comment on lines +249 to +279
{dependencyInjectionOptions.map((option) => (
<label
key={option.value}
className={cn(
"flex items-center justify-between rounded-xl border p-3 cursor-pointer transition-all duration-200",
config.dependencyInjection === option.value
? "border-primary/50 bg-primary/5 shadow-md shadow-primary/5 ring-1 ring-primary/20"
: "border-border/40 bg-card/30 hover:bg-card/50 hover:border-primary/20"
)}
>
<div className="flex items-center gap-3">
<RadioGroupItem value={option.value} className="text-primary border-primary" />
<div className="space-y-1">
<span className="text-sm font-semibold text-foreground/90">{option.label}</span>
<p className="text-xs text-muted-foreground">{option.description}</p>
</div>
</div>
<button
type="button"
onClick={(e) => {
e.preventDefault()
e.stopPropagation()
setSelectedItem(option.value)
}}
className="p-1.5 rounded-full hover:bg-primary/20 text-muted-foreground hover:text-primary transition-colors focus:outline-hidden cursor-pointer"
title="View details"
>
<HugeiconsIcon icon={InformationCircleIcon} size={18} />
</button>
</label>
))}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Avoid nesting a <button> inside a <label> (invalid HTML / a11y).

The HTML spec disallows interactive descendants other than a single labelable control inside <label>. Nesting the info <button> inside the label can trigger accessibility warnings and inconsistent click behavior across browsers (some will still activate the radio even with preventDefault/stopPropagation). Prefer a sibling layout: wrap the row in a <div> and keep the <label> scoped to the radio + text only.

♻️ Proposed refactor
-                        {dependencyInjectionOptions.map((option) => (
-                            <label
-                                key={option.value}
-                                className={cn(
-                                    "flex items-center justify-between rounded-xl border p-3 cursor-pointer transition-all duration-200",
-                                    config.dependencyInjection === option.value
-                                        ? "border-primary/50 bg-primary/5 shadow-md shadow-primary/5 ring-1 ring-primary/20"
-                                        : "border-border/40 bg-card/30 hover:bg-card/50 hover:border-primary/20"
-                                )}
-                            >
-                                <div className="flex items-center gap-3">
-                                    <RadioGroupItem value={option.value} className="text-primary border-primary" />
-                                    <div className="space-y-1">
-                                        <span className="text-sm font-semibold text-foreground/90">{option.label}</span>
-                                        <p className="text-xs text-muted-foreground">{option.description}</p>
-                                    </div>
-                                </div>
-                                <button
-                                    type="button"
-                                    onClick={(e) => {
-                                        e.preventDefault()
-                                        e.stopPropagation()
-                                        setSelectedItem(option.value)
-                                    }}
-                                    className="p-1.5 rounded-full hover:bg-primary/20 text-muted-foreground hover:text-primary transition-colors focus:outline-hidden cursor-pointer"
-                                    title="View details"
-                                >
-                                    <HugeiconsIcon icon={InformationCircleIcon} size={18} />
-                                </button>
-                            </label>
-                        ))}
+                        {dependencyInjectionOptions.map((option) => {
+                            const id = `di-${option.value}`
+                            const selected = config.dependencyInjection === option.value
+                            return (
+                                <div
+                                    key={option.value}
+                                    className={cn(
+                                        "flex items-center justify-between rounded-xl border p-3 transition-all duration-200",
+                                        selected
+                                            ? "border-primary/50 bg-primary/5 shadow-md shadow-primary/5 ring-1 ring-primary/20"
+                                            : "border-border/40 bg-card/30 hover:bg-card/50 hover:border-primary/20"
+                                    )}
+                                >
+                                    <label htmlFor={id} className="flex items-center gap-3 cursor-pointer flex-1">
+                                        <RadioGroupItem id={id} value={option.value} className="text-primary border-primary" />
+                                        <div className="space-y-1">
+                                            <span className="text-sm font-semibold text-foreground/90">{option.label}</span>
+                                            <p className="text-xs text-muted-foreground">{option.description}</p>
+                                        </div>
+                                    </label>
+                                    <button
+                                        type="button"
+                                        aria-label={`View details for ${option.label}`}
+                                        onClick={() => setSelectedItem(option.value)}
+                                        className="p-1.5 rounded-full hover:bg-primary/20 text-muted-foreground hover:text-primary transition-colors focus:outline-hidden cursor-pointer"
+                                        title="View details"
+                                    >
+                                        <HugeiconsIcon icon={InformationCircleIcon} size={18} />
+                                    </button>
+                                </div>
+                            )
+                        })}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{dependencyInjectionOptions.map((option) => (
<label
key={option.value}
className={cn(
"flex items-center justify-between rounded-xl border p-3 cursor-pointer transition-all duration-200",
config.dependencyInjection === option.value
? "border-primary/50 bg-primary/5 shadow-md shadow-primary/5 ring-1 ring-primary/20"
: "border-border/40 bg-card/30 hover:bg-card/50 hover:border-primary/20"
)}
>
<div className="flex items-center gap-3">
<RadioGroupItem value={option.value} className="text-primary border-primary" />
<div className="space-y-1">
<span className="text-sm font-semibold text-foreground/90">{option.label}</span>
<p className="text-xs text-muted-foreground">{option.description}</p>
</div>
</div>
<button
type="button"
onClick={(e) => {
e.preventDefault()
e.stopPropagation()
setSelectedItem(option.value)
}}
className="p-1.5 rounded-full hover:bg-primary/20 text-muted-foreground hover:text-primary transition-colors focus:outline-hidden cursor-pointer"
title="View details"
>
<HugeiconsIcon icon={InformationCircleIcon} size={18} />
</button>
</label>
))}
{dependencyInjectionOptions.map((option) => {
const id = `di-${option.value}`
const selected = config.dependencyInjection === option.value
return (
<div
key={option.value}
className={cn(
"flex items-center justify-between rounded-xl border p-3 transition-all duration-200",
selected
? "border-primary/50 bg-primary/5 shadow-md shadow-primary/5 ring-1 ring-primary/20"
: "border-border/40 bg-card/30 hover:bg-card/50 hover:border-primary/20"
)}
>
<label htmlFor={id} className="flex items-center gap-3 cursor-pointer flex-1">
<RadioGroupItem id={id} value={option.value} className="text-primary border-primary" />
<div className="space-y-1">
<span className="text-sm font-semibold text-foreground/90">{option.label}</span>
<p className="text-xs text-muted-foreground">{option.description}</p>
</div>
</label>
<button
type="button"
aria-label={`View details for ${option.label}`}
onClick={() => setSelectedItem(option.value)}
className="p-1.5 rounded-full hover:bg-primary/20 text-muted-foreground hover:text-primary transition-colors focus:outline-hidden cursor-pointer"
title="View details"
>
<HugeiconsIcon icon={InformationCircleIcon} size={18} />
</button>
</div>
)
})}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/components/wizard/steps/MiscStep.tsx` around lines 249 - 279, The info
<button> is nested inside the <label>, which is invalid and breaks a11y;
refactor the map so each option is a wrapper <div> (or other non-interactive
container) that contains a <label> scoped only to the RadioGroupItem and its
text (use dependencyInjectionOptions and
RadioGroupItem/option.label/option.description), and place the info button
(HugeiconsIcon with InformationCircleIcon) as a sibling element outside the
<label>; keep the existing onClick handler that calls setSelectedItem but ensure
the button still calls e.preventDefault()/e.stopPropagation() so it doesn't
toggle the radio, and preserve the original conditional className logic that
uses config.dependencyInjection to maintain the visual selected state; move the
key={option.value} to the outer wrapper so list keys remain stable.

Comment on lines 28 to +33
# State Management
fpdart: ^1.2.0
equatable: ^2.0.7
{{#if flags.usesGetItDi}}
get_it: ^8.0.3
{{/if}}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

🌐 Web query:

What is the latest stable version of the get_it Dart/Flutter package on pub.dev?

💡 Result:

The latest stable version of the get_it Dart/Flutter package on pub.dev is 9.2.1.

Citations:


Move get_it to a dedicated "Dependency Injection" section and update version constraint.

get_it is a DI/service-locator package, not a state management library. Grouping it under # State Management is misleading. Additionally, the version constraint ^8.0.3 is outdated; the latest stable version is 9.2.1. Update to at least ^9.0.0.

♻️ Proposed fix
   # State Management
   fpdart: ^1.2.0
   equatable: ^2.0.7
-  {{`#if` flags.usesGetItDi}}
-  get_it: ^8.0.3
-  {{/if}}
   {{`#if` flags.usesFlutterHooks}}
   flutter_hooks: ^0.20.5
   {{/if}}
@@
   {{`#if` flags.isMobX}}
   mobx: ^2.6.0
   flutter_mobx: ^2.3.0
   {{/if}}
+
+  # Dependency Injection
+  {{`#if` flags.usesGetItDi}}
+  get_it: ^9.0.0
+  {{/if}}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@templates/flutter/base/pubspec.yaml.hbs` around lines 28 - 33, The get_it
dependency is incorrectly listed under the "State Management" section and uses
an outdated constraint; when flags.usesGetItDi is true, remove the get_it:
^8.0.3 entry from under the State Management block and instead add a new
commented section "# Dependency Injection" (or similar) where you include get_it
with an updated constraint (at least ^9.0.0, e.g., ^9.0.0 or ^9.2.1); update the
Handlebars template around the conditional (flags.usesGetItDi) so the get_it
line is emitted under that new section rather than next to fpdart/equatable.

Comment on lines 7 to +9
// Provides the single instance of AuthRepositoryImpl
final authRepositoryProvider = Provider<AuthRepository>((ref) {
return AuthRepositoryImpl();
return createAuthRepository();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Update the stale repository comment.

This provider no longer guarantees an AuthRepositoryImpl; with GetIt enabled it resolves through createAuthRepository().

📝 Proposed comment update
-// Provides the single instance of AuthRepositoryImpl 
+// Provides the configured AuthRepository instance.
 final authRepositoryProvider = Provider<AuthRepository>((ref) {
   return createAuthRepository();
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Provides the single instance of AuthRepositoryImpl
final authRepositoryProvider = Provider<AuthRepository>((ref) {
return AuthRepositoryImpl();
return createAuthRepository();
// Provides the configured AuthRepository instance.
final authRepositoryProvider = Provider<AuthRepository>((ref) {
return createAuthRepository();
});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@templates/flutter/partials/features/auth/auth_logic.hbs` around lines 7 - 9,
The top comment is incorrect: it claims the provider returns a single instance
of AuthRepositoryImpl, but authRepositoryProvider actually returns
createAuthRepository() which may resolve via GetIt and not necessarily
AuthRepositoryImpl; update the comment above authRepositoryProvider to remove
the guarantee of AuthRepositoryImpl and instead state that the provider exposes
an AuthRepository resolved by createAuthRepository() (which may use GetIt).

Comment on lines +46 to 47
final authStore = {{#if flags.usesFlutterHooks}}useMemoized{{else}}null; // Add your MobX store here{{/if}}(() => AuthStore(repository: createAuthRepository()), []);
final isLoading = authStore.isLoading;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

find . -name "forgot_password_screen.hbs" -type f

Repository: Arjun544/flutter_init

Length of output: 134


🏁 Script executed:

cat -n ./templates/flutter/partials/features/auth/forgot_password_screen.hbs

Repository: Arjun544/flutter_init

Length of output: 16534


Fix MobX code generation when Flutter Hooks are disabled.

The non-hooks MobX code path has a critical bug: the template assigns null to authStore on line 46, then attempts to dereference it on line 47 with authStore.isLoading. This generates invalid Dart that fails at compile time.

When flags.usesFlutterHooks is false, line 46 currently renders as:

final authStore = null; // Add your MobX store here(...);

The template should separate the conditional to generate valid code for both paths:

Template fix
 {{else if flags.isMobX}}
-    final authStore = {{`#if` flags.usesFlutterHooks}}useMemoized{{else}}null; // Add your MobX store here{{/if}}(() => AuthStore(repository: createAuthRepository()), []);
+    {{`#if` flags.usesFlutterHooks}}
+    final authStore = useMemoized(() => AuthStore(repository: createAuthRepository()), []);
+    {{else}}
+    final authStore = AuthStore(repository: createAuthRepository());
+    {{/if}}
     final isLoading = authStore.isLoading;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
final authStore = {{#if flags.usesFlutterHooks}}useMemoized{{else}}null; // Add your MobX store here{{/if}}(() => AuthStore(repository: createAuthRepository()), []);
final isLoading = authStore.isLoading;
{{else if flags.isMobX}}
{{`#if` flags.usesFlutterHooks}}
final authStore = useMemoized(() => AuthStore(repository: createAuthRepository()), []);
{{else}}
final authStore = AuthStore(repository: createAuthRepository());
{{/if}}
final isLoading = authStore.isLoading;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@templates/flutter/partials/features/auth/forgot_password_screen.hbs` around
lines 46 - 47, The template currently sets authStore to null when
flags.usesFlutterHooks is false which causes a null dereference on
authStore.isLoading; change the conditional so you emit two distinct
declarations: when flags.usesFlutterHooks is true generate a memoized store
(useMemoized(() => AuthStore(repository: createAuthRepository()), [])) and when
false generate a plain instance (AuthStore(repository: createAuthRepository()));
ensure the variable name authStore remains the same so subsequent references
like authStore.isLoading compile.

Comment on lines +51 to 52
final authStore = {{#if flags.usesFlutterHooks}}useMemoized{{else}}null; // Add your MobX store here{{/if}}(() => AuthStore(repository: createAuthRepository()), []);
final isLoading = authStore.isLoading;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

find . -name "login_screen.hbs" -type f

Repository: Arjun544/flutter_init

Length of output: 124


🏁 Script executed:

cat -n ./templates/flutter/partials/features/auth/login_screen.hbs

Repository: Arjun544/flutter_init

Length of output: 35200


Fix MobX generation when Flutter Hooks are disabled.

When MobX is used without Flutter Hooks, the template renders authStore as null due to an inline comment that consumes the function initialization. This causes a null dereference on line 52 when accessing authStore.isLoading and again at line 105 in the handleLogin function.

🐛 Proposed template fix
 {{else if flags.isMobX}}
     // In a real app, MobX stores might be provided via Provider/GetIt.
     // Here we use a locally created memoized instance for the template.
-    final authStore = {{`#if` flags.usesFlutterHooks}}useMemoized{{else}}null; // Add your MobX store here{{/if}}(() => AuthStore(repository: createAuthRepository()), []);
+    {{`#if` flags.usesFlutterHooks}}
+    final authStore = useMemoized(() => AuthStore(repository: createAuthRepository()), []);
+    {{else}}
+    final authStore = AuthStore(repository: createAuthRepository());
+    {{/if}}
     final isLoading = authStore.isLoading;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
final authStore = {{#if flags.usesFlutterHooks}}useMemoized{{else}}null; // Add your MobX store here{{/if}}(() => AuthStore(repository: createAuthRepository()), []);
final isLoading = authStore.isLoading;
{{`#if` flags.usesFlutterHooks}}
final authStore = useMemoized(() => AuthStore(repository: createAuthRepository()), []);
{{else}}
final authStore = AuthStore(repository: createAuthRepository());
{{/if}}
final isLoading = authStore.isLoading;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@templates/flutter/partials/features/auth/login_screen.hbs` around lines 51 -
52, The template currently renders authStore as null when flags.usesFlutterHooks
is false because the inline comment breaks the expression; change the
conditional so authStore is always initialized: if flags.usesFlutterHooks render
useMemoized(() => AuthStore(repository: createAuthRepository()), []), else
render AuthStore(repository: createAuthRepository()); remove the inline comment
that caused the null and ensure usages like isLoading and handleLogin (which
reference authStore) work with the non-null AuthStore instance.

Comment on lines +56 to 57
final authStore = {{#if flags.usesFlutterHooks}}useMemoized{{else}}null; // Add your MobX store here{{/if}}(() => AuthStore(repository: createAuthRepository()), []);
final isLoading = authStore.isLoading;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Find MobX template branches that render `authStore` as null when hooks are disabled.

rg -n -C2 '\{\{`#if` flags\.usesFlutterHooks\}\}useMemoized\{\{else\}\}null; // Add your MobX store here\{\{/if\}\}' templates/flutter/partials/features/auth

Repository: Arjun544/flutter_init

Length of output: 2084


🏁 Script executed:

# Read the signup_screen.hbs file around the problematic lines to understand context
cat -n templates/flutter/partials/features/auth/signup_screen.hbs | sed -n '50,65p'

Repository: Arjun544/flutter_init

Length of output: 972


🏁 Script executed:

# Read the login_screen.hbs file around the problematic lines
cat -n templates/flutter/partials/features/auth/login_screen.hbs | sed -n '45,60p'

Repository: Arjun544/flutter_init

Length of output: 1118


🏁 Script executed:

# Read the forgot_password_screen.hbs file around the problematic lines
cat -n templates/flutter/partials/features/auth/forgot_password_screen.hbs | sed -n '40,55p'

Repository: Arjun544/flutter_init

Length of output: 972


🏁 Script executed:

# Check if there are any other similar patterns with null assignments in auth templates
rg -n 'null; //' templates/flutter/partials/features/auth

Repository: Arjun544/flutter_init

Length of output: 768


Fix MobX generation when Flutter Hooks are disabled in all auth screens.

For isMobX without hooks, the template renders invalid syntax: final authStore = null; followed by authStore.isLoading, causing compilation failure. This affects signup_screen.hbs (line 56), login_screen.hbs (line 51), and forgot_password_screen.hbs (line 46).

Restructure these templates to properly instantiate AuthStore when hooks are disabled, following the pattern already used in the NoneState branches:

🐛 Proposed template fix (apply to all 3 auth screens)
 {{else if flags.isMobX}}
-    final authStore = {{`#if` flags.usesFlutterHooks}}useMemoized{{else}}null; // Add your MobX store here{{/if}}(() => AuthStore(repository: createAuthRepository()), []);
+    {{`#if` flags.usesFlutterHooks}}
+    final authStore = useMemoized(() => AuthStore(repository: createAuthRepository()), []);
+    {{else}}
+    final authStore = AuthStore(repository: createAuthRepository());
+    {{/if}}
     final isLoading = authStore.isLoading;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
final authStore = {{#if flags.usesFlutterHooks}}useMemoized{{else}}null; // Add your MobX store here{{/if}}(() => AuthStore(repository: createAuthRepository()), []);
final isLoading = authStore.isLoading;
{{`#if` flags.usesFlutterHooks}}
final authStore = useMemoized(() => AuthStore(repository: createAuthRepository()), []);
{{else}}
final authStore = AuthStore(repository: createAuthRepository());
{{/if}}
final isLoading = authStore.isLoading;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@templates/flutter/partials/features/auth/signup_screen.hbs` around lines 56 -
57, The template currently emits invalid Dart when MobX is enabled but Flutter
Hooks are disabled by assigning authStore to null; instead, change the template
logic around authStore so that when flags.usesFlutterHooks is true you keep the
existing useMemoized invocation, and when false you instantiate AuthStore
directly (AuthStore(repository: createAuthRepository())); ensure subsequent
usages like authStore.isLoading and other authStore references work with the
instantiated AuthStore; update the conditional in signup_screen.hbs (and mirror
the same change in login_screen.hbs and forgot_password_screen.hbs) to branch
between useMemoized(...) and new AuthStore(...) rather than null.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant