Skip to content

feat(cli): bring the make:* generators up to the shapes magic apps write - #208

Merged
anilcancakir merged 7 commits into
masterfrom
feat/generators-full-set
Sep 27, 2026
Merged

anilcancakir merged 7 commits into
masterfrom
feat/generators-full-set

Conversation

@anilcancakir

Copy link
Copy Markdown
Member

What

Brings the artisan make:* generators up to the shapes magic apps actually write, so an agent or a developer can scaffold instead of hand-writing.

  • New make:resource <Model>: magic's make:model --all. It writes the model and factory, repository, create/update/delete actions, Store/Update requests, the resource form object, a --resource --actions controller, list and form views, and their tests. The run is all-or-nothing: every path is preflighted, and it prints the route lines rather than editing RouteServiceProvider.
  • New make:test --kind=controller|action|form|repository|request|view|unit, mirroring lib/ to test/. --test on make:controller, make:view, make:action, make:form, make:repository and make:request chains it in the same run.
  • Stubs rewritten:
    • make:controller implements SessionScoped, with opt-in --actions, --broadcasts, --timers and --validates mixins; --resource owns a RepositoryQuery (items, ensureFresh(), reload()).
    • make:view --stateful|--controller|--list|--form writes a MagicStatefulView<T>.
    • make:request writes a const FormRequest.
    • make:component writes the preview file only when the project keeps a preview catalogue (--preview / --no-preview override), and now writes a widget test.
  • Variants added:
    • make:action --kind=create|update|delete --model=<Model>: update upserts into the repository and delete evicts from it.
    • make:form --resource=<Model>
    • make:enum --wire
    • make:lang --from=<locale>
  • ActionRequestFailed is exported from package:magic/magic.dart, and the model stub gains a static fromMap.
  • Fixed:
    • make:model exits 1 on an existing model without --force.
    • make:model --all also writes the repository its resource controller reads.

No version bump; CHANGELOG entries sit under [Unreleased].

Why

The old controller stub returned widgets from a pre-state routing controller, the stateful view was a bare StatefulWidget, and the request stub was a plain class that neither MagicFormObject.request nor ValidatesRequests accepts. Apps (uptizm among them) had banned make:component and told agents not to trust a generated controller.

Breaking

The three BREAKING bullets in the CHANGELOG:

  • The regenerated controller and stateful-view shapes. make:view --stateful now needs its derived controller to exist.
  • The preview opt-out.
  • The ActionRequestFailed export, which clashes with an app's own class of that name.

Testing

  • dart format --set-exit-if-changed: clean.
  • flutter analyze: no issues.
  • flutter test: 2221 passed.
  • Every make:* command has tests.
  • flutter test --tags integration --run-skipped test/cli/integration: generates every make:* output into a scratch Flutter app and requires flutter analyze to report zero issues. It runs in CI as the new "Generated code analyzes" job.
  • Real run in uptizm: make:resource Probe wrote 21 files, analyze was clean, and 7 generated tests passed.

- make:controller --test returns the chained make:test exit code
- delete and update actions key the repository by the id's string form;
  update now writes the saved row into the repository
- the resource controller exposes reload(), and the resource form reloads
  it after a create so the new row reaches the list
- docs: magic-cli.md covers make:resource, make:repository, make:action,
  make:form, make:test and the new flags; skill and CHANGELOG corrected
- drop em dashes from the touched doc comments
@codecov

codecov Bot commented Sep 27, 2026 •

Copy link
Copy Markdown

@kodizm

kodizm Bot commented Sep 27, 2026

Copy link
Copy Markdown

Note

Kodizm (AI-generated). May contain mistakes; verify before acting.

Looks correct and safe to merge. Two small edge cases remain in the new file-writing paths.

Minor

lib/src/cli/commands/make_component_command.dart:207: data-loss. _writeMatchingTest writes test/ui/components/<name>/<name>_test.dart without checking whether that file already exists. Take make:component Avatar after the component folder was deleted but the filled-in test was kept: the command silently replaces that test. make:test refuses to overwrite without --force, and so does the component guard at line 110. This path should do the same.

lib/src/cli/commands/make_lang_command.dart:121: correctness. jsonDecode isn't guarded. Before this PR, make:lang tr never read another file. Now, if assets/lang/en.json is malformed, it fails with an uncaught FormatException stack trace instead of printing an error and exiting 1.

Tests

The new generators and flags have command tests under test/cli/commands/. The generated output is also compiled by test/cli/integration/generated_code_analyzes_test.dart. I found no test for the two edge cases above.

CI

  • Lint & Test: success
  • Generated code analyzes: success
  • Internal Links & Anchors: success
  • codecov/patch: success (96.91% of the diff covered)
  • External Links: skipped
  • Auto-merge Dependabot: skipped

What I checked:

  • make:resource preflight: the paths it checks for each generator (request, form, controller, view, repository, action and matching-test) match the paths those generators actually write, so the all-or-nothing check is sound.
  • Force handling: --force still skips the files it keeps (model and factory).
  • make:model: exiting 1 on an existing model, and adding the repository before the --resource controller, both match the CHANGELOG.
  • Not opened: the remaining stubs and docs, beyond the skill's version bump.

@anilcancakir

Copy link
Copy Markdown
Member Author

Both Minors fixed in b5f6241, each with a test that failed before the fix:

  • make_component_command.dart:207: the matching test path is now checked in the same preflight as the component file (make_component_command.dart:116-121). A kept test without --force fails the run with exit 1 before anything is written; --force overwrites it. Tests: refuses a kept test without --force and writes nothing and --force overwrites a kept test in test/cli/commands/make_component_command_test.dart. While there, a pubspec.yaml with no name: now skips the test with a warning instead of throwing on the as String cast.
  • make_lang_command.dart:121: a FormatException from the source file is caught in handle. It prints Cannot copy en.json: it is not valid JSON (...), exits 1, and writes no target. Test: returns 1 naming the source when it is not valid JSON in test/cli/commands/make_lang_command_test.dart.

Gates: dart format clean, flutter analyze no issues, flutter test test/cli 364 passed, integration test passed. CHANGELOG entries updated.

@kodizm please re-review.

@kodizm

kodizm Bot commented Sep 27, 2026

Copy link
Copy Markdown

Note

Kodizm (AI-generated). May contain mistakes; verify before acting.

Both earlier Minors are fixed in b5f6241, and I found nothing new. This looks ready to merge.

This is an incremental review of the commits since 59ccc43, which means b5f6241.

What I checked:

  • make_component_command.dart:116-121: the kept-test check runs straight after the component-file guard. It uses the same --force gate and exits before any stub is written, so a refused run leaves the tree untouched. _matchingTestPath is now the single source for both the check and the write, so the two paths cannot drift apart.
  • The name: cast: the loose as String cast is gone. A pubspec with no name now warns instead of throwing. The command is only registered in magic_artisan_provider.dart, so no other generator depends on the old behaviour.
  • make_lang_command.dart:98-106: the FormatException is caught in handle before writeFile, so a malformed source writes no target and exits 1. Non-object JSON still falls back to {}, as before.
  • CHANGELOG: the entries under [Unreleased] are updated for both fixes, as the post-change sync in CLAUDE.md requires.

Tests

There are new tests for each fix:

  • make_component_command_test.dart: refuses a kept test without --force and writes nothing and --force overwrites a kept test
  • make_lang_command_test.dart: returns 1 naming the source when it is not valid JSON

CI

  • Lint & Test: success
  • Generated code analyzes: success
  • Internal Links & Anchors: success
  • codecov/patch: success (96.76% of the diff covered)
  • External Links: skipped
  • Auto-merge low-risk Dependabot PRs: skipped

@anilcancakir
anilcancakir merged commit ce8a8c2 into master Sep 27, 2026
7 checks passed
@anilcancakir anilcancakir mentioned this pull request Sep 27, 2026
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