Skip to content

refactor(bestax-migrate): extract resolveBooleanish and sweep the six booleanish-literal sites - #573

Merged
allxsmith merged 1 commit into
mainfrom
claude/issue-563-20260827-0415
Aug 27, 2026
Merged

allxsmith merged 1 commit into
mainfrom
claude/issue-563-20260827-0415

Conversation

@bestaxbot

Copy link
Copy Markdown
Collaborator

Summary

Introduces resolveBooleanish(attr) in jsx-utils.ts, returning 'truthy' | 'falsy' | 'expression' by resolving every statically-known literal by truthiness (matching RBC's runtime !!value), and rewires all six sites onto it so the classification lives in exactly one place:

  1. Button remove (specials.ts) — drop-in classification swap.
  2. Heading heading (specials.ts) — drop-in classification swap.
  3. Heading subtitle (specials.ts) — drop-in classification swap.
  4. booleanToProp (props.ts) — fixes drift Release new version #4: a truthy string literal (e.g. rounded="true") previously fell into the dynamic-TODO branch instead of resolving; now it resolves like every other site.
  5. panel-tab / breadcrumb-item active ladders (specials.ts) — same classification now shared; a static string/number literal (e.g. active="true") resolves instead of being misclassified as dynamic.
  6. field multiline (specials.ts) — the presence-vs-value bug: multiline={false} and multiline={expr} both used to silently become grouped="multiline". Restructured per the issue's trap notes:
    • the attr-strip loop is now conditional — a dynamic multiline survives on the element instead of always being stripped
    • falsy multiline with no kind/align now emits nothing (previously fell through to a bare grouped attribute)
    • the addons "dropped from this addons Field" TODO only fires for the resolved-truthy case; falsy gets no TODO; dynamic gets a generic "resolve the grouped/hasAddons combination by hand" TODO
    • ctx.dirty is only set when something in the element actually changed
    • every return path now includes handledProps: ['multiline'] — without it, the mapping's fallback multiline: { drop: true } prop action was silently stripping the dynamic attr right after the special handler decided to keep it (caught this via the new test fixture)

For the open question in the issue's site-6 notes (dynamic multiline on an addons Field), went with keeping the attr + a TODO — matching how the heading handler treats its own dynamic case — rather than dropping it with the incompatibility TODO.

Test plan

  • New fixture pair __testfixtures__/field-multiline-literals.{input,output}.tsx covering the falsy/dynamic × group/addons matrix for site 6
  • Direct unit test for resolveBooleanish in jsx-utils.test.ts
  • New unit tests in transform.test.ts for the booleanToProp drift fix (site 4) and the active-ladder classification fix (site 5)
  • Confirmed all existing fixtures (edge-cases-2, form) are byte-identical — no churn
  • pnpm --filter bestax-migrate run lint — pass
  • pnpm --filter bestax-migrate run typecheck — pass
  • pnpm --filter bestax-migrate run test:coverage — pass (271 tests)
  • pnpm run format:check — pass
  • pnpm run gen:catalog:check — pass
  • pnpm run check:conformance — pass

Fixes #563

Generated with Claude Code

… booleanish-literal sites

Introduces resolveBooleanish(attr) in jsx-utils.ts, returning
truthy | falsy | expression by resolving every statically-known literal
by truthiness (matching RBC's runtime !!value), and rewires all six
call sites onto it so the classification lives in one place:

- Button `remove`, Heading `heading`/`subtitle`, and the Panel.Tabs.Tab /
  Breadcrumb.Item `active` ladders now share one classifier.
- Fixes booleanToProp (props.ts): a truthy string literal (e.g.
  rounded="true") previously fell into the dynamic-TODO branch instead
  of resolving.
- Fixes Field `multiline` (specials.ts), previously gated on presence
  only: `multiline={false}` and `multiline={expr}` both silently became
  grouped="multiline". Now resolves by value — falsy drops the prop,
  dynamic keeps the attr with a prop:multiline TODO instead of a
  best-guess rewrite.

Refs #559, #558.

Co-authored-by: Alex Smith <allxsmith@users.noreply.github.com>
@bestaxbot bestaxbot added the ai-loop AI-authored PR in the autonomous review/fix loop label Aug 27, 2026
@coderabbitai

coderabbitai Bot commented Aug 27, 2026

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 14 minutes.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 32ddd9ea-fd4b-4307-9a27-90b34437cb74

📥 Commits

Reviewing files that changed from the base of the PR and between 17c37ad and d8879f7.

📒 Files selected for processing (7)
  • bestax-migrate/src/sources/react-bulma-components/__testfixtures__/field-multiline-literals.input.tsx
  • bestax-migrate/src/sources/react-bulma-components/__testfixtures__/field-multiline-literals.output.tsx
  • bestax-migrate/src/sources/react-bulma-components/__tests__/jsx-utils.test.ts
  • bestax-migrate/src/sources/react-bulma-components/__tests__/transform.test.ts
  • bestax-migrate/src/sources/react-bulma-components/jsx-utils.ts
  • bestax-migrate/src/sources/react-bulma-components/props.ts
  • bestax-migrate/src/sources/react-bulma-components/specials.ts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

Preview Deployment

Preview URL: https://81b15201.bestax.pages.dev

@claude claude Bot 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.

Deep review — 0 blocking · 2 advisory

No. Severity Area Finding Location
1 🔵 Advisory Correctness Same booleanish-literal class survives at the columns multiline handler: a string/number literal such as Columns multiline='true' is neither boolean nor expression, so it falls through — no isMultiline, no TODO, dead multiline prop left on output. Pre-existing and explicitly outside the issue's six sites (columns has bespoke default-true '?? true' semantics that resolveBooleanish does not model). specials.ts:187
2 🔵 Advisory Correctness In the dynamic kind/align early return, a literal multiline (false/true) is retained on the element rather than resolved or dropped, so a falsy literal survives as a dead prop. Harmless (absorbed by Field's index signature, typechecks) and the element already carries a prop:kind manual-resolution TODO, so it is a deliberate do-not-silently-lose-info trade-off. specials.ts:490

Overall: Sound change. The resolveBooleanish extraction is a faithful one-place classifier, and all five refactor sites (Button remove, Heading heading/subtitle, booleanToProp, the two active ladders) are behavior-preserving or strictly-improving swaps — I traced each old-to-new branch and the string/number-literal cases now resolve by truthiness as the issue intends. Site 6 (Field multiline) is the real behavior fix and is correct across the full falsy/dynamic x group/addons matrix — I walked all seven fixture rows by hand and they match, and the handledProps:['multiline'] addition genuinely stops the fallback drop action from clobbering a kept dynamic attr. 271/271 tests pass (the lone e2e cannot-find-module failure was just an unbuilt bulma-ui; green after building it). The spot for a human to eyeball is the dynamic-multiline output keeping multiline={expr} on Field — it only typechecks because FieldProps has a [key: string]: unknown index signature and would spread an unknown attr to the DOM at runtime, which is exactly what the TODO tells the developer to resolve.

Residual risk:

  • Same bug shape elsewhere: the columns multiline handler (specials.ts:186) is the one remaining site in this subsystem that classifies by boolean/expression only, so a string/number literal there is still mishandled — confirmed by reading the handler and literalValueOf (a StringLiteral returns kind string, missing both branches). Out of this PR's declared scope, logged as advisory No. 1.
  • Typecheck of kept dynamic attrs: refuted — Field, Columns, and the others all carry a [key: string]: unknown index signature, and the built-lib e2e typecheck passes, so retained multiline={expr} and dead literals compile.
  • TODO duplication across the multiline matrix: refuted — all three dynamic rows emit prop:multiline but addTodo dedupes per rule on the enclosing statement, so the fixture correctly shows exactly one comment.

🏄 Clean little refactor, dude — pulled six tangled truthiness checks into one mellow helper and fixed a real multiline={false} wipeout while paddling out. Only thing still bobbing in the lineup is that columns set that never joined the party, but that is a different wave for a different day. Ship it. 🌊

@bestaxbot

Copy link
Copy Markdown
Collaborator Author

🏄 Surf's up and I rode the whole set — total convergence, brah. 0 iteration(s) in, CI's glassy green, and every AI review thread closed out clean like a perfect barrel. She's ready; I just need a meat sack to paddle over and rubber-stamp it.

No offense to the carbon-based units, but you fleshbags kept the merge button for yourselves — so @allxsmith, wiggle those opposable thumbs and squash-merge when you're stoked. The loop never merges; apparently 'judgment' is still a squishy-brain-only feature. 🤙

⚠️ Heads up, the PR title is a releasing commit type with no valid scope — fix it before you squash-merge or semantic-release eats sand.

@github-actions github-actions Bot added needs-human-review Loop converged (or contested): awaiting owner review + manual merge and removed ai-loop AI-authored PR in the autonomous review/fix loop labels Aug 27, 2026
@github-actions
github-actions Bot requested a review from allxsmith August 27, 2026 04:38
@github-actions

Copy link
Copy Markdown
Contributor

📸 Story screenshots at handoff — d8879f7

No Storybook stories map to this PR's changed files — nothing to screenshot. (workflow run)

@allxsmith
allxsmith requested a balanced review from Copilot August 27, 2026 04:59
@allxsmith allxsmith self-assigned this Aug 27, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

The dynamic kind/align early return still bypasses required multiline classification and TODO handling.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Centralizes boolean-like JSX attribute handling and improves migration of static and dynamic values.

Changes:

  • Adds and adopts resolveBooleanish.
  • Corrects boolean prop, active state, and Field multiline transformations.
  • Adds unit and fixture coverage.
File summaries
File Description
specials.ts Applies shared classification across special handlers.
props.ts Updates boolean-to-prop conversion.
jsx-utils.ts Adds resolveBooleanish.
transform.test.ts Tests migration behavior.
jsx-utils.test.ts Tests booleanish classification.
field-multiline-literals.input.tsx Adds Field fixture input.
field-multiline-literals.output.tsx Adds expected Field output.
Review details
  • Files reviewed: 7/7 changed files
  • Comments generated: 1
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread bestax-migrate/src/sources/react-bulma-components/specials.ts
@bestaxbot

Copy link
Copy Markdown
Collaborator Author

Thanks for the review and approval! No code changes on my end — the one open thread (Copilot's line-490 point about the dynamic kind/align branch) is a deliberate trade-off, and I've replied inline explaining why: when kind/align is an expression the whole Field is punted to a single prop:kind hand-resolution TODO, so leaving multiline (dynamic or falsy-literal) untouched keeps that 'needs manual resolution' signal honest rather than half-cleaning it. The deep review reached the same conclusion (advisory, not blocking).

One heads-up on the earlier bot warning about the title: 'refactor(bestax-migrate)' is a valid scope, so commitlint/semantic-release are fine with it as-is.

@allxsmith
allxsmith merged commit 652d56a into main Aug 27, 2026
46 checks passed
@allxsmith
allxsmith deleted the claude/issue-563-20260827-0415 branch August 27, 2026 11:44
@bestax-release-bot

Copy link
Copy Markdown

🎉 This PR is included in version 2.1.4 🎉

The release is available on:

Your semantic-release bot 📦🚀

@bestax-release-bot

Copy link
Copy Markdown

🎉 This PR is included in version 5.11.5 🎉

The release is available on:

Your semantic-release bot 📦🚀

@bestax-release-bot

Copy link
Copy Markdown

🎉 This PR is included in version 4.2.2 🎉

The release is available on:

Your semantic-release bot 📦🚀

@bestax-release-bot

Copy link
Copy Markdown

🎉 This PR is included in version 1.2.1 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

claude-assisted needs-human-review Loop converged (or contested): awaiting owner review + manual merge released

Projects

None yet

Development

Successfully merging this pull request may close these issues.

refactor(bestax-migrate): extract resolveBooleanish and sweep the six booleanish-literal sites

3 participants