Deprecated props removal codemod

Migrates the deprecated props that were removed in v3 to their replacements, scoped to the component that owned each prop:

table
ComponentBeforeAfter
ButtonisErrorisCritical
ButtonisDangerisCritical
LinkisErrorisCritical
FiltersClearAllButtonisErrorisCritical
DropdownMenuItemisDangerisCritical
DropdownMenuCheckboxItemisDangerisCritical
DropdownMenuSubTriggerisDangerisCritical
DropdownMenuTriggerButtonisDangerisCritical
FiltersAddButtonisDangerisCritical
DataTableHeaderFiltersButtonisDangerisCritical
DataTableHeaderSaveViewButtonisDangerisCritical
PopoverTriggerButtonisDangerisCritical
SnackbarisErrorvariant="critical"
Snackbarvariant="error"variant="critical"
Popovercontentdescription
Bannervariant="warning"variant="caution"
Bannervariant="error"variant="critical"

There are two transforms — one for React (.tsx/.ts/.jsx/.js) and one for Ember (.gts/.gjs/.hbs). Run whichever apply to your app.

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 deprecated-props-removal react --dry ./src
pnx @customerio/pluma-cli@latest upgrade --codemod deprecated-props-removal ember --dry ./app

# Then apply for real
pnx @customerio/pluma-cli@latest upgrade --codemod deprecated-props-removal react ./src
pnx @customerio/pluma-cli@latest upgrade --codemod deprecated-props-removal ember ./app ./addon

Both frameworks accept --dry / -d. The React path also forwards standard jscodeshift flags, so -p prints transformed output.

What gets matched

React. Only JSX elements whose tag resolves (via the import in the same file) to one of the components in the table above from @customerio/pluma-components/react (or the bare @customerio/pluma-components entry). Aliased imports (import { Button as B } from …) are handled. A local component that wasn't imported from Pluma is left alone.

  • The attribute renames (isError/isDangerisCritical, contentdescription) rewrite the attribute name regardless of value.
  • The Banner and Snackbar variant value renames handle inline literals (variant="warning", variant={'error'}) and result-position literals (branches of a ?:, the right-hand side of ?? / || / &&).
  • Snackbar's isError is converted to variant="critical" only when it's statically true (isError / isError={true}) and no variant is already set on the element.

Ember. Only the Pluma-prefixed element nodes of the components in the table above are touched (<PlumaButton …>, <PlumaDropdownMenuItem …>, …), following the same rules with @-prefixed args (@isError, @isDanger, @content, @variant).

Manual migration — isDanger object keys

The transforms only rewrite JSX attributes / Ember args, so isDanger used as an object key is left alone — most commonly useConfirmationModal({ isDanger: true }) / ConfirmationModal data configs (the only way that component receives the prop) and DataTable action configs (actions={[{ label: 'Delete', isDanger: true }]}). Rename those keys to isCritical by hand; TypeScript flags every affected site once the package is upgraded.

Manual migration — DataTable sorting

This codemod does not touch DataTable sorting. Two deprecated sorting APIs were removed in v3, and both are structural reshapes rather than mechanical renames, so they must be migrated by hand:

  1. The { id, desc } object form of the sorting prop is gone. Wrap it in a value key:

    - sorting={{ id: 'name', desc: false }}
    + sorting={{ value: { id: 'name', desc: false } }}
  2. The top-level onSortingChange prop is gone. Move the callback into the sorting object as onChange:

    - sorting={{ id: 'name', desc: false }}
    - onSortingChange={handleSort}
    + sorting={{ value: { id: 'name', desc: false }, onChange: handleSort, isManual: false }}

The equivalent Ember args (@sorting={{hash id="name" desc=false}} and @onSortingChange) migrate the same way, using @sorting={{hash value=(hash id="name" desc=false) onChange=this.handleSort isManual=false}}.

Warnings — values that need manual review

Both transforms print a summary listing anything they recognized but couldn't rewrite safely:

  • A Banner or Snackbar variant that comes from a dynamic expression, identifier, {{this.x}}, {{@arg}}, or unknown helper call.
  • A Snackbar isError that isn't statically true (e.g. isError={isError}, @isError={{@hasError}}) or where a variant is already present.

They're reported (not auto-rewritten) so you can migrate them by hand.

Working on the codemod itself

The React/Ember transform engines and reporting are shared across the attribute-rename codemods under ../../_shared/; this codemod is a thin config wrapper. 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).