Replaces Pluma's Flex / PlumaFlex with Stack / InlineStack (PlumaStack /
PlumaInlineStack), remapping the alignment props onto the axis they belong to
and updating the import.
Flex exposes the raw flexbox model, so alignment is named after the main and
cross axes — which swap meaning when the direction changes. Stack and
InlineStack fix the direction and name the axes after the writing mode, so
alignInline and alignBlock mean the same thing everywhere.
This is the bulk counterpart to the pluma/prefer-stack-over-flex lint rule. The
rule keeps new Flex out of a codebase; this clears the existing ones.
Dry run first — both transforms report every element they skip, and that list is the manual-review queue.
Then apply:
| Flex | direction="column" → Stack | direction="row" or absent → InlineStack |
|---|---|---|
alignItems | alignInline | alignBlock |
justifyContent | alignBlock | alignInline |
direction is removed. gap, columnGap, rowGap, and every other Box
sprinkle carry over unchanged — Stack and InlineStack forward them to Box exactly
as Flex does.
A converted column also gains an explicit alignInline="start" when it had no
alignItems, because Flex defaults its cross axis to start while Stack
defaults alignInline to stretch. Without it the conversion would silently
change the layout.
The import is updated in place: the replacement is added to the existing Pluma
import (or as a sibling subpath import, matching how the file already imports
Pluma), and Flex is removed once nothing else references it.
Each of these is skipped with a warning naming the file and the reason. Other elements in the same file still convert.
direction that is not a literal "row" or "column" — a dynamic value, or
row-reverse / column-reverse, which neither component supports.wrap on a column: Stack has no wrap. A wrapping column usually wants Grid.flexWrap on a column: Flex overwrites it with its own wrap, so it is inert
today, and Stack would let it take effect.alignBlock or alignInline written on the Flex itself: they do nothing
there, but the replacement would honour them.flexDirection: ignored by both replacements.@unsafe_props — propsProxy falls back to it for
any argument not passed explicitly, so it can carry direction unseen.alignItems value cannot be read statically: Flex drops an
undefined prop and falls back to start, where Stack would fall back to
stretch, so the default cannot be carried over blind.import { PlumaFlex as Row } in Ember): the template tag no
longer names the component, so the file is reported for a manual change.{{#let x as |PlumaStack|}}.
Adding the import would clash with that binding, or the converted element would
resolve to it instead of the Pluma component.Flex itself is shadowed, block params included.
Elements are matched by tag name, so there is no way to tell Pluma's component
from the other one.Flex from Pluma more than once. Only one
of those imports would be rewritten, leaving the other converted at the use site
but still importing Flex..gts/.gjs file whose JavaScript cannot be parsed, since
the import cannot be read or updated. In practice this means files that are not
really JavaScript, such as an Ember blueprint holding <%= %> placeholders.Run with --dry first. Both transforms report every skipped element, so the
warning list is the manual-review queue. After applying, pluma/prefer-stack-over-flex
will still flag whatever was skipped, so lint output and the warning list should
agree.
Run your formatter afterwards. The Ember transform preserves template formatting exactly, but the React one reprints the enclosing JSX through recast, which reindents it — the same behaviour as the other React codemods here. Formatting the touched files keeps the diff to the change itself.