flutter_2yaml 0.6.0
flutter_2yaml: ^0.6.0 copied to clipboard
Convert Flutter widget files into compact YAML optimized for LLM token consumption, and back again. Pipe syntax, CSS-like shorthands, arrow callbacks.
0.6.0 #
Correctness release. Every item below is a bug that silently dropped or corrupted
information; each is covered by a regression test in test/regression_test.dart.
Forward (Dart → YAML) — silent data loss fixed #
- Hex colors —
Color(0xFF123456)producedbg: Color, losing the value entirely. Now emits#123456, and keeps a non-opaque alpha channel as#AARRGGBB. Applies to const and non-const forms alike. if/elsechildren — a conditional child with anelsebranch lost both its condition and the alternative. Conditions are now emitted for complex children too, and the alternative is written as anelse:branch.- Non-const
EdgeInsets— thep/px/pyshorthands only fired onconst EdgeInsets…; a bareEdgeInsets.symmetric(...)lost its numbers. All forms are now recognised, plusEdgeInsets.zeroandfromLTRB. EdgeInsets.symmetricwith both axes emitted the malformedmx: 16, my, dropping the vertical value (a split-on-=bug).- Theme-based text styles —
Text('x', style: Theme.of(context).textTheme.y)dropped the style. Kept now, asstyle: theme.y. - Single-word string literals —
Text('Home')became the unquotedText: Home, indistinguishable from the identifierText: title, so it came back as an undefined identifier. String literals are now quoted. - Multiple widget classes per file — only the first was converted and the
rest discarded. Every class is now emitted, as one
----separated document each (DartFileAnalyzer.analyzeAll,YamlGenerator.generateAll). switchinbuild()— produced nobuild:key at all. Both switch expressions and switch statements now become aswitch(...)node with onecase/defaultarm per branch.- Named children lists —
actions,items,tabsand friends were merged into the genericchildrenlist, so anAppBar's actions reversed into achildren:argument it does not have. Each keeps its own slot now. - Generic widget classes kept their name but lost their type parameters.
- Unrepresentable expressions (a
_buildBody(context)build body, a non-widget child) were dropped; they are now preserved verbatim asexpr:. - Argument values are no longer summarised into invalid Dart — a call's
arguments used to be rewritten as the placeholder
(...), and string literals inside them lost their quotes. InputDecorationwas flattened onto its parent as if it were aBoxDecoration, inventing named arguments the widget does not declare.this.-constructor parameters now carry the type of the field they initialise.- Helper methods on a
StatelessWidgetare captured at--level full, which is what "all methods" promised. - Enums and typedefs the widget refers to are carried at
--level full, so a widget that switches on a local enum still compiles after a round trip.
Reverse (YAML → Dart) — invalid output fixed #
- Named slots emitted empty arguments —
appBar: ,,title: ,,icon: ,andbuilder: ,were produced for the converter's own forward output, a hard syntax error on any screen with an AppBar or a list builder. Slot keys are now parsed as child slots instead of value-less properties. for-inelements generatedfor(child: ProductCard(...)); spreads were dropped silently. Both now emit valid collection elements, and the documented keyword-lessfor(item in items)form is made valid Dart.- Single-child
Row/Column/Stackreversed toRow(child: …), a parameter those widgets do not have. EdgeInsetsdouble-wrapping producedpadding: EdgeInsets.all(EdgeInsets.symmetric(...)).pyleaked as a bare argument when paired withpx.t/l/r/b/gap/runGapwere never expanded, reaching the output in abbreviated form as arguments no widget declares.bg: gradient(...)on a Container becamecolor: Colors.gradient(...).screen.*andtheme.*were emitted verbatim, andscreen.wcould land inside aconstconstructor.- Quoted hex colors (
bg: "#123456", which YAML often requires because#starts a comment) becameColors."#123456". - Lossy lifecycle summaries were emitted as code —
set _x;,controller.close(...);,conditional logic;— none of which parses. They are now emitted as comments, and anavigate:summary becomes a realNavigatorcall. - Custom methods were emitted as
@override void _onTap() { super._onTap(); }— an override of nothing calling a member that does not exist. They now keep their parameters and return type. - Opaque callback bodies produced
validator: () => (...); they now become a valid empty lambda of the right arity. - Inline brace syntax dropped nested widgets and arrow callbacks, so the
documented
AppBar: { title: Text: "Home" | 20 | bold }and{ onPressed → add(), child: Icon: add }were copied into the output as garbage. - An
Iconcarrying a callback vanished entirely. It is now generated as the widget that can carry one — anIconButtonforonPressed, otherwise aGestureDetector. constis no longer guessed for arbitrary zero-argument widgets; it is emitted only where the const constructor is known to exist.- Contradictory shorthands can no longer emit the same named argument twice.
- Empty named lists (
items: []) are preserved rather than dropped.
Documentation #
- The token-savings claim is now the measured range (40-65%, ~50% average at the default level) rather than 50-70%.
- New Known Limitations section stating plainly what the format does not carry: summarised method bodies, multi-statement callback bodies, field mutability, and non-enum/typedef top-level code.
- Documented
else:branches, named child slots,switcharms, theexpr:escape hatch,---multi-class documents, generics anddeclarations:.
Packaging and pub.flutter-io.cn score #
Diagnosed the 120/160 pub score by reading pana's own scoring rules, and fixed every deduction:
- Description length — at 210 characters the description tripped pana's "description too long" check (the limit is 180). A single non-URL pubspec issue zeroes the whole 10-point subsection rather than deducting from it, which is the entire 20/30 in "Follow Dart file conventions".
- Static analysis — the correctness rewrite above removed the four warnings
(two
unnecessary_cast, twounused_import) that capped this section at 30/50. They only surface underpackage:lints/core.yaml, which is what pana analyses with; the package's ownrecommended+ strict-* options reported them differently, sodart analyzealone never showed them as warnings. analyzerdependency — bumped from^7.4.5to^14.0.0so the constraint admits the latest release. This raises the minimum Dart SDK from 3.8 to 3.11, which analyzer 14 requires. Migrated the AST usage accordingly:NamedExpression→NamedArgument(withToken nameandargumentExpression),ArgumentList.argumentsnow yieldingArgumentrather thanExpression,ClassDeclaration.members→body.members,ClassDeclaration.name/typeParameters→namePart.*,NamedType.name2→name, and the removal ofDefaultFormalParameter/SimpleFormalParameterin favour ofFormalParameter.defaultClauseandRegularFormalParameter.
Verified #
dart analyze: clean.dart format: clean. Test suite: 110 tests (was 65).dart pub outdated: no outdated direct dependencies.dart pub downgradefollowed bydart analyzeis clean, so the dependency lower bounds hold.- Every fixture in this repo round-trips Dart → YAML → Dart at
--level fullinto code that passesflutter analyzewith zero errors (previously 11 errors plus unparseable output).
0.5.0 #
- Component reference tags — new
<ComponentName:Key=Value>syntax for referencing figma2flutter plugin components in YAML - Component tags are parsed by the reverse converter and output as
const Text('ComponentName (Variant)')placeholder widgets - Warning (not error) printed when component tags are detected: "Full component resolution requires the figma2flutter MCP server"
_componentRefinternal metadata stored on placeholder nodes for future MCP integration- Arrow callbacks in
# →comments no longer misinterpreted as widget callbacks - Internal
_prefixed properties skipped by the Dart generator - Supports all variant patterns:
<B-NavBar:Status=Home, Mode=Light>,<Tab Menu:Type=Active, Style=Solid>,<WOWR Card List:Type=WO>,<ComponentName>(no variants)
0.4.1 #
- Reverse codegen: Container BoxDecoration —
bg,br,border,shadow,gradientproperties on Container are now collected into a singledecoration: BoxDecoration(...)instead of emitting raw properties - Per-corner border radius —
br: {tl: 24, tr: 24, bl: 0, br: 0}now generatesBorderRadius.only(topLeft: Radius.circular(24), topRight: Radius.circular(24))instead of invalidBorderRadius.circular({...}) - Border shorthand expansion —
border: {c: #121212, w: 1}now generatesBorder.all(color: Color(0xFF121212), width: 1) - Shadow offset fix —
shadow: {c: black, blur: 3, offset: Offset(0, 1)}no longer crashes on nested commas insideOffset(); now uses paren-aware splitting - figma2flutter compatibility — reverse codegen validated against real Figma plugin YAML output (full pages with Stack, Positioned, per-corner radii, shadows, borders)
0.4.0 #
- Forward conversion hardened — full Scaffold support with named children
- Named children model:
appBar,drawer,floatingActionButton,bottomNavigationBar,endDrawer,bottomSheet,leading,title,icon,labelall properly nested - Expanded children list detection:
slivers,items,destinations - SpreadElement support in children lists (
...items) - ForElement support in children lists (
for (x in list) Widget()) - Ternary expression support (
condition ? WidgetA : WidgetB) ListView.builder/GridView.builderitemBuilder pattern extraction- BoxDecoration complete:
shape,border,imageextraction added - Border.all shorthand:
Border.all(color: black, width: 2)→border: {c: black, w: 2} - Positioned widget shorthand:
top/left/right/bottom→t/l/r/b - TextStyle complete:
wordSpacing,height,decorationColor,decorationStyle,decorationThickness,overflow - Icons prefix stripped:
Icons.menu→menu,Icons.search→search double.infinity→full- Wrap spacing shorthand:
spacing→gap,runSpacing→runGap - Theme.of(context) shorthand: →
theme.textTheme.headline - MediaQuery shorthand: →
screen.w,screen.h - Multiple positional argument support with indexed tracking
- Complex screen test fixture with full Scaffold + AppBar + Drawer + FAB + BottomNav
0.3.0 #
- Reverse conversion: YAML → Dart via
flutter_2yaml reverse <path.yaml> - Full round-trip support:
.dart→.yaml→.dartwith idiomatic output - YAML parser with pipe syntax, arrow notation, parenthetical alignment parsing
- Dart code generator producing properly formatted Flutter code
- Automatic
constpropagation,super.keyconstructors,@overrideannotations - Reverse expansion of all shorthands (bg → backgroundColor, p → EdgeInsets.all, etc.)
- State class skeleton generation for StatefulWidget
- Lifecycle method generation with proper
super.calls - Directory-level reverse conversion with
--recursivesupport - Programmatic API:
YamlParser,DartGenerator,ReverseConverter
0.2.0 #
- Breaking: Unified Compact Format — complete output format overhaul
- Pipe syntax for Text, Image, Icon widgets (
Text: "Hello" | 20 | bold | white) - CSS-like property shorthands (
bg,br,p,px,py,h,w) - Arrow callback notation (
onPressed → handleTap()) - Parenthetical alignment (
Column(center),Row(spaceBetween)) - Color shorthand (
Colors.blue→blue) - Dimension shorthand (
200x200,w: full) - Auto-detect state management (GetX, Riverpod, Bloc, Provider)
- Auto-classify
page:vswidget:based on Scaffold presence - Compact inline state format (
state: [isLoading: bool = true]) - EdgeInsets shorthand (
EdgeInsets.all(16)→p: 16) - BoxDecoration shorthand (bg, br, shadow, gradient)
- Support for ConsumerWidget, GetView, and other framework base classes
0.1.0 #
- Initial release
- Convert Flutter StatelessWidget and StatefulWidget files to YAML
- Three verbosity levels: minimal, standard, full
- CLI support for single file and directory conversion
- Watch mode for automatic regeneration on file changes
- Configurable output directory