Skip to content

feat: design-first CLI (design:sync/lint, previews:refresh, make:component)#102

Open
anilcancakir wants to merge 3 commits into
masterfrom
feat/design-first-component-system
Open

feat: design-first CLI (design:sync/lint, previews:refresh, make:component)#102
anilcancakir wants to merge 3 commits into
masterfrom
feat/design-first-component-system

Conversation

@anilcancakir

Copy link
Copy Markdown
Contributor

Adds 4 CLI commands: design:sync/design:lint (DESIGN.md -> wind theme: 17 semantic aliases + brand MaterialColor, WCAG contrast lint), previews:refresh (atomic codegen of a previewEntries() function) and make:component (4-file atomic component scaffold + chain). No build_runner. analyze 0, 1234 tests, coverage >80%, pub publish --dry-run clean.

Cross-repo: this design-first component system spans 5 repos. Land in dependency order: wind (WindRecipe + 5 primitives) first, then magic (design:sync/lint, previews:refresh, make:component) and magic_devtools (preview catalog) which consume wind, then magic_starter (component library + view rewrite), then magic_example (consumer app). Branches are all feat/design-first-component-system. Verified locally end-to-end (analyze 0, full suites green, real-browser e2e of the /preview catalog, release-strip confirmed).

Add two magic CLI commands. previews:refresh scans a configurable dir for
*.preview.dart files, validates one public *Preview class each, fails fast
on slug collisions, sorts deterministically, and atomically writes a
_previews.g.dart that returns List<PreviewEntry> from a previewEntries()
function (never a top-level const, per sdk#33920) importing PreviewEntry
from magic_devtools. make:component scaffolds the canonical 4-file atomic
component folder from stubs (variant axes or WindSlotRecipe via --slots)
then chains previews:refresh. Mirrors the artisan codegen substrate; no
build_runner, no CliBundleCache.purge.
design:sync parses a DESIGN.md (YAML front-matter, single-file dark:
overlay per color role, {group.token} ref resolution) and emits a wind
theme source: a Map<String,String> aliases map keyed by the 17 Step 7
property-prefixed semantic roles (bg-surface, text-fg, border-color-border,
...) with arbitrary-hex light + dark values, plus a brand primary
MaterialColor with a generated 50-900 ramp. Output is drop-in compatible
with MagicStarterTokens.defaultAliases; atomic write, idempotent.
design:lint ports 6 rules (broken-ref, missing-primary, unknown-key with
the dark: overlay whitelisted, section-order, orphaned-tokens, WCAG 4.5:1
contrast via a greenfield sRGB-luminance helper).
Name make:component / previews:refresh / design:sync / design:lint in the
README CLI row and the magic-framework SKILL.md CLI section + reference
index, so the design-first workflow is discoverable.
Copilot AI review requested due to automatic review settings June 25, 2026 22:53

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR adds a “design-first” workflow to Magic’s artisan plugin by introducing new CLI commands for DESIGN.md-driven Wind theming, preview catalog codegen, and atomic component scaffolding, along with tests and documentation updates across the repo.

Changes:

  • Add design:sync / design:lint commands backed by a shared DesignMdParser + WCAG contrast helper.
  • Add previews:refresh command plus _previews.g.dart generation utilities.
  • Add make:component generator (4-file atomic component folder) and new stubs, chaining previews:refresh.

Reviewed changes

Copilot reviewed 24 out of 24 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
test/cli/helpers/design_md_parser_test.dart Adds unit coverage for DESIGN.md parsing, reference resolution, and WCAG contrast helper.
test/cli/commands/previews_refresh_command_test.dart Tests preview discovery + deterministic index generation + atomic write behavior.
test/cli/commands/make_component_command_test.dart Tests component scaffolding outputs, variants/slots options, and chained previews refresh.
test/cli/commands/design_sync_command_test.dart Verifies generated Wind theme output (aliases + MaterialColor) and atomic/idempotent behavior.
test/cli/commands/design_lint_command_test.dart Tests lint rules: broken refs, contrast warnings, schema typo detection, section ordering.
skills/magic-framework/SKILL.md Updates skill version and documents the new design-first CLI commands.
skills/magic-framework/references/cli-commands.md Extends CLI reference with make:component / previews:refresh / design:* docs.
README.md Updates the Magic CLI feature blurb to include design-first commands.
lib/src/cli/magic_artisan_provider.dart Registers the new commands in the artisan provider.
lib/src/cli/helpers/previews_index_writer.dart Implements preview scanning, deterministic rendering, and atomic index writing.
lib/src/cli/helpers/magic_stub_loader.dart Adds loadFrom() to support explicit stub dir override (testing seam).
lib/src/cli/helpers/design_md_parser.dart Introduces DESIGN.md front matter parsing, reference resolution, section extraction, and contrast helper.
lib/src/cli/commands/previews_refresh_command.dart Adds the previews:refresh command wiring the index writer into artisan.
lib/src/cli/commands/make_component_command.dart Adds make:component generator with stub-based 4-file output + command chaining.
lib/src/cli/commands/design_sync_command.dart Adds design:sync to emit Wind theme aliases + brand MaterialColor from DESIGN.md.
lib/src/cli/commands/design_lint_command.dart Adds design:lint with findings model, rules, and reporting/exit behavior.
doc/packages/magic-cli.md Documents the new commands and the DESIGN.md format in the CLI package docs.
CHANGELOG.md Adds Unreleased entries describing the new commands and workflow.
assets/stubs/preview.stub Adds preview stub used by make:component.
assets/stubs/component.stub Adds component widget stub (single recipe).
assets/stubs/component.slots.stub Adds component widget stub (slot-based recipe).
assets/stubs/component.slot_recipe.stub Adds slot-based recipe stub.
assets/stubs/component.recipe.stub Adds single-recipe stub.
assets/stubs/component_index.stub Adds folder-local barrel stub (exports component + recipe only).

Comment on lines +365 to +373
switch (finding.severity) {
case _Severity.error:
errors++;
ctx.output.error('$prefix${finding.message}');
case _Severity.warning:
ctx.output.warning('$prefix${finding.message}');
case _Severity.info:
ctx.output.info('$prefix${finding.message}');
}
Comment on lines +27 to +28
/// `design:lint`: validates a `DESIGN.md` against six rules ported from the
/// design.md reference linter, adapted to the wind-flavored superset.
);
}

final yaml = loadYaml(frontMatter);
Comment on lines +211 to +229
var inFrontMatter = false;
var seenFirstDelimiter = false;

for (final line in lines) {
final trimmed = line.trim();
if (trimmed == '---' && !seenFirstDelimiter && headings.isEmpty) {
inFrontMatter = !inFrontMatter;
seenFirstDelimiter = false;
continue;
}
if (trimmed == '---' && inFrontMatter) {
inFrontMatter = false;
continue;
}
if (inFrontMatter) continue;

final match = RegExp(r'^##\s+(.+)$').firstMatch(line);
if (match != null) headings.add(match.group(1)!.trim());
}
Comment on lines +182 to +185
final outputPath = p.join(previewsDir.path, '_previews.g.dart');
final tmpPath = '$outputPath.tmp';
File(tmpPath).writeAsStringSync(renderPreviewsIndex(discovered));
File(tmpPath).renameSync(outputPath);
Comment on lines +118 to +120
final tmpPath = '$outputPath.tmp';
File(tmpPath).writeAsStringSync(source);
File(tmpPath).renameSync(outputPath);

### `dart run magic:artisan design:lint`

Validates a `DESIGN.md` against six rules: broken-ref (error), missing-primary, unknown-key (the `dark:` overlay is never flagged), section-order, missing-sections, orphaned-tokens, and contrast-ratio (WCAG AA 4.5:1 on component bg/text pairs). Exits nonzero only on an error-severity finding.
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.

2 participants