LabelIcon → Coin codemod

Migrates the removed LabelIcon component to Coin with a child Icon. LabelIcon was a thin wrapper that rendered a single Icon inside a colored circle/square; Coin is the general-purpose replacement and takes the icon as a child.

// Before
<LabelIcon name="user" color="blue" size="md" />

// After
<Coin colorVariant="blue" size="md">
  <Icon name="user" />
</Coin>

Prop mapping

table
LabelIconCoinNotes
namechild <Icon name>Moved onto the child Icon.
labelchild <Icon label>Moved onto the child Icon.
colorcolorVariantSame value set (redgrey); only the prop name changes.
shape="square"shape="rounded-square"shape="circle" is unchanged.
size (omitted)size="sm"LabelIcon defaulted to sm; Coin defaults to md. The codemod adds an explicit size="sm" so appearance is preserved.
size="sm"/"md"size="sm"/"md"Passed through unchanged.
other propskept on CoinBox passthrough props (className, as, spacing, …) stay put.

Running it

Run it through the Pluma CLI from inside your consuming app. Always start with a dry run to review the diff and warning summary before applying:

# from the root of your consuming app

# Dry run first (no writes; per-file diff printed inline)
pnx @customerio/pluma-cli@latest upgrade --codemod label-icon-to-coin react --dry ./src
pnx @customerio/pluma-cli@latest upgrade --codemod label-icon-to-coin ember --dry ./app

# Then apply for real
pnx @customerio/pluma-cli@latest upgrade --codemod label-icon-to-coin react ./src
pnx @customerio/pluma-cli@latest upgrade --codemod label-icon-to-coin ember ./app ./addon

Both frameworks accept --dry / -d. The React path also forwards standard jscodeshift flags.

What gets matched

React. JSX elements whose tag resolves (via the import in the same file) to LabelIcon from @customerio/pluma-components/react (or the bare @customerio/pluma-components entry). The import specifier is rewritten to Coin, an Icon import is added if missing, and aliased imports (import { LabelIcon as X } from …) are handled.

Ember. <PlumaLabelIcon …> element nodes in .gts/.gjs/.hbs templates are rewritten to <PlumaCoin …> with a child <PlumaIcon …>.

Manual steps

  • Strict-mode Ember imports. In .gts/.gjs files that import PlumaLabelIcon, update the import by hand: replace PlumaLabelIcon with PlumaCoin and add PlumaIcon. The codemod only rewrites template contents, not module imports (classic .hbs templates resolve these globally and need no import change).
  • size="lg". LabelIcon rendered an xl icon at size="lg"; Coin renders an lg icon at size="lg". If you relied on the larger icon, set the child Icon size explicitly.
  • Dynamic shape. A shape value the codemod can't read as a literal is reported (not rewritten) because Coin uses rounded-square where LabelIcon used square. Update those by hand.

Warnings — values that need manual review

Both transforms print a summary listing dynamic shape values and any LabelIcon with no name (which can't be wrapped in an Icon automatically).

Working on the codemod itself

The React transform is a bespoke jscodeshift transform; the Ember transform is built on @codemod-utils/ast-template and reuses the shared CLI runner under ../../_shared/. There's a test suite under tests/:

pnpm --filter @customerio/pluma-cli run test:transforms

It uses Node's built-in test runner (node --test).