Repository navigation
docs(bulma-ui): generate the elements API pages (3/4) - #422
Conversation
Lands the tooling for generating the derivable parts of docs/docs/api, with no page generated yet: MANAGED_CATEGORIES and ORDERED_CATEGORIES both start empty and grow one category per follow-up, so the 87 page diffs stay reviewable instead of arriving as one 199-file change. Four regions per page, delimited by `<!-- bestax:generated <id> -->` markers — `overview` (the component's TSDoc summary), `import` (the public barrel), `props` (the `<X>Props` interfaces via the TypeScript compiler API) and `cssvars` (a new section parsed from the SCSS). Everything outside a marker pair is hand-written and preserved byte-for-byte; deleting a pair opts that region out, and `docs-section-order` makes that visible rather than silent. Three choices keep the output reading as hand-written rather than as typedoc: own members only, with the one catch-all `...` row the pages already wrote by hand; types from AST source text, never `checker.typeToString`, which expands `(typeof validColors)[number]` into 19 literals; and wide colour unions rendered as a link to the existing Valid values page. CI gates live in check-conformance.mjs, which already runs in CI, rather than a new workflow step: `docs-generated` recomputes each managed page in memory and diffs, `docs-section-order` holds the order and marker presence. Both were verified by tampering. Also closes two gate gaps this tooling exposed. `pnpm all` ran `turbo run format:check`, which only runs the per-package scripts — none cover `scripts/`, `docs/scripts/` or any `.md`; CI runs the root script, which does, so CI could be red while `pnpm all` was green. And nothing linted `scripts/` at all. `all` now calls the root format check and `lint` also runs eslint over `scripts` and `docs/scripts`; verified by planting an unused variable. Two review aids ship alongside, both one-shot and both used to validate the migration that follows: `check-docs-parity.mjs` fails on any prop, default, description word, code span, URL, live example or prose line that a generated page drops relative to its hand-written self, and `check-docs-wording.mjs` buckets every previously-documented prop by how its description changed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011c6ipfvBsYgF3Jf91ZzSr7
First categories through the generator, plus `helpers/` reordered but not
generated — four of its six pages document hooks with `## API` and no `## Props`
at all, and `config.md`/`theme.md` keep their hand-written tables (theme.md's
Props section is a ~350-line prose sub-API, not a table).
`@property` blocks move onto the interface members as inline TSDoc, so a
description is verifiable by position and reaches users' editors and the shipped
.d.ts. Descriptions were seeded FROM the docs pages, not the other way round:
the hand-written tables are consistently the richer text, and the page stays
authoritative wherever the two disagree.
Component TSDoc summaries were likewise seeded from the pages — the existing ones
("Bulma Hero component root.", "Container component for Bulma.") were worse than
the prose they would have replaced. That text ships in the .d.ts, so read the
`component-catalog.md` diff: it is the canary for this step.
Verified: check-docs-parity reports 0 losses across all 87 pages; the generator
is idempotent.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011c6ipfvBsYgF3Jf91ZzSr7
30 pages. Two fixes to the extractor that this category forced, both found by check-docs-parity rather than by reading pages: - Heritage through `Omit`/`Pick` and imported (alias) symbols. `LinkButtonProps extends Omit<ButtonProps, …>` resolved the symbol of `Omit` — a lib type — so all 14 of its inherited props landed in the catch-all row instead of a table. - `Table`'s six sub-components are imported rather than declared locally, so the page rendered no sub-tables at all and the cell components' props vanished. Props the old tables documented but no interface declares (`href` on Link, `value` on ListItem, the `<ol>` attributes on OrderedList, `skeleton` from the helper props) are parked as `@extraProp`, carrying their type and default. That keeps the page's information in the source, where the rest of it now lives. `Button`'s component JSDoc was attached to an unrelated `const` rather than to `Button`, so its summary never reached the page; moved. Verified: 0 parity losses across all 87 pages; of the 215 previously-documented props on these pages, 178 read identically and 37 keep their sentence with more appended — none replaced. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011c6ipfvBsYgF3Jf91ZzSr7
|
Warning Review limit reached
Next review available in: 46 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (67)
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. Comment |
|
@coderabbitai full review Generated by Claude Code |
|
✅ Action performedFull review finished. Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 59 minutes. |
`scripts/gen-component-catalog.mjs` carried a copy of the catalog preamble predating #365, so regenerating deleted 21 lines of shipped guidance: the per-component value-union warning, where to find the installed `.d.ts`, the `Skeleton` helper-prop exception, which sub-component families accept helper props, and the custom-component composition spine. The checked-in `component-catalog.md` still had #365's text, so `gen:catalog:check` regenerated it shorter and failed `git diff --exit-code` — this is why Build and Test is red on this PR. Restores the generator to main's version. The catalog now regenerates byte-identical to the committed file. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
`scripts/gen-component-catalog.mjs` carried a copy of the catalog preamble predating #365, so regenerating deleted 21 lines of shipped guidance: the per-component value-union warning, where to find the installed `.d.ts`, the `Skeleton` helper-prop exception, which sub-component families accept helper props, and the custom-component composition spine. This branch regenerated the catalog with that stale generator, committing the loss into a shipped skill artifact. Restores the generator to main's version and regenerates; the preamble matches main again and the component one-liners are unaffected. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
`scripts/gen-component-catalog.mjs` carried a copy of the catalog preamble predating #365, so regenerating deleted 21 lines of shipped guidance: the per-component value-union warning, where to find the installed `.d.ts`, the `Skeleton` helper-prop exception, which sub-component families accept helper props, and the custom-component composition spine. This branch regenerated the catalog with that stale generator, committing the loss into a shipped skill artifact. Restores the generator to main's version and regenerates; the preamble matches main again and the component one-liners are unaffected. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
| ### Thead / Tbody / Tfoot | ||
|
|
||
| | Prop | Type | Default | Description | | ||
| | ----------- | ----------------------------------------- | ------- | ------------------------------------------------ | | ||
| | `className` | `string` | — | Additional CSS classes. | | ||
| | `children` | `ReactNode` | — | Section content (typically `Tr` rows). | | ||
| | ... | All standard props and Bulma helper props | | (See [Helper Props](../helpers/usebulmaclasses)) | | ||
|
|
||
| ### Tr | ||
|
|
||
| | Prop | Type | Default | Description | | ||
| | ------------ | ----------------------------------------- | ------- | ------------------------------------------------ | | ||
| | `className` | `string` | — | Additional CSS classes. | | ||
| | `isSelected` | `boolean` | — | Adds Bulma's `is-selected` class. | | ||
| | `color` | `TableColor` | — | Bulma color modifier for the row. | | ||
| | `children` | `ReactNode` | — | Row content (typically `Th`/`Td`). | | ||
| | ... | All standard props and Bulma helper props | | (See [Helper Props](../helpers/usebulmaclasses)) | | ||
|
|
||
| ### Th | ||
|
|
||
| | Prop | Type | Default | Description | | ||
| | ----------- | ----------------------------------------- | ------- | ------------------------------------------------ | | ||
| | `className` | `string` | — | Additional CSS classes. | | ||
| | `isAligned` | `'left' \| 'right' \| 'centered'` | — | Text alignment. | | ||
| | `width` | `string \| number` | — | Cell width (e.g., `'100px'`, `100`). | | ||
| | `color` | `TableColor` | — | Bulma color modifier for the header cell. | | ||
| | `children` | `ReactNode` | — | Header cell content. | | ||
| | ... | All standard props and Bulma helper props | | (See [Helper Props](../helpers/usebulmaclasses)) | | ||
|
|
||
| ### Td | ||
|
|
||
| | Prop | Type | Default | Description | | ||
| | ----------- | ----------------------------------------- | ------- | ------------------------------------------------ | | ||
| | `className` | `string` | — | Additional CSS classes. | | ||
| | `color` | `TableColor` | — | Bulma color modifier for the cell. | | ||
| | `children` | `ReactNode` | — | Cell content. | | ||
| | ... | All standard props and Bulma helper props | | (See [Helper Props](../helpers/usebulmaclasses)) | | ||
|
|
There was a problem hiding this comment.
Duplicate sub-component prop tables render on the published Table page — 🟡 Minor · Correctness
What: The generated props region already emits full tables for every sub-component (Table.Thead, Table.Tbody, Table.Tfoot, Table.Tr, Table.Th, Table.Td) inside the marker pair. These hand-written ### Thead / Tbody / Tfoot, ### Tr, ### Th, ### Td tables sit below the `` marker, so per the region rules (docs/CLAUDE.md: "prose below the closing marker is preserved") they are kept verbatim — producing a second, stale copy of the same props under the single `## Props` section.
Why it matters: Readers see each cell/row/section documented twice, and the two copies disagree — e.g. generated Table.Tr gives isSelected a default of false (line 312) while this copy shows — (line 364); the generated Table.Th isAligned description is fuller than the duplicate's "Text alignment." The duplicate is unmanaged, so it silently drifts as the interfaces change. check-docs-parity/conformance treat extra content as non-losses, so this passed CI.
Fix: Delete the stale hand-written tables; the generated block is the source of truth.
| ### Thead / Tbody / Tfoot | |
| | Prop | Type | Default | Description | | |
| | ----------- | ----------------------------------------- | ------- | ------------------------------------------------ | | |
| | `className` | `string` | — | Additional CSS classes. | | |
| | `children` | `ReactNode` | — | Section content (typically `Tr` rows). | | |
| | ... | All standard props and Bulma helper props | | (See [Helper Props](../helpers/usebulmaclasses)) | | |
| ### Tr | |
| | Prop | Type | Default | Description | | |
| | ------------ | ----------------------------------------- | ------- | ------------------------------------------------ | | |
| | `className` | `string` | — | Additional CSS classes. | | |
| | `isSelected` | `boolean` | — | Adds Bulma's `is-selected` class. | | |
| | `color` | `TableColor` | — | Bulma color modifier for the row. | | |
| | `children` | `ReactNode` | — | Row content (typically `Th`/`Td`). | | |
| | ... | All standard props and Bulma helper props | | (See [Helper Props](../helpers/usebulmaclasses)) | | |
| ### Th | |
| | Prop | Type | Default | Description | | |
| | ----------- | ----------------------------------------- | ------- | ------------------------------------------------ | | |
| | `className` | `string` | — | Additional CSS classes. | | |
| | `isAligned` | `'left' \| 'right' \| 'centered'` | — | Text alignment. | | |
| | `width` | `string \| number` | — | Cell width (e.g., `'100px'`, `100`). | | |
| | `color` | `TableColor` | — | Bulma color modifier for the header cell. | | |
| | `children` | `ReactNode` | — | Header cell content. | | |
| | ... | All standard props and Bulma helper props | | (See [Helper Props](../helpers/usebulmaclasses)) | | |
| ### Td | |
| | Prop | Type | Default | Description | | |
| | ----------- | ----------------------------------------- | ------- | ------------------------------------------------ | | |
| | `className` | `string` | — | Additional CSS classes. | | |
| | `color` | `TableColor` | — | Bulma color modifier for the cell. | | |
| | `children` | `ReactNode` | — | Cell content. | | |
| | ... | All standard props and Bulma helper props | | (See [Helper Props](../helpers/usebulmaclasses)) | |
Note: same defect on figure.md
figure.md has the identical issue — a ### Figure.Caption Props table below the close marker duplicating the generated Figure.Caption table. Fixed in a separate comment there.
| ### Figure.Caption Props | ||
|
|
||
| | Prop | Type | Default | Description | | ||
| | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | ------------------------------------------------ | | ||
| | `className` | `string` | — | Additional CSS classes. | | ||
| | `textColor` | `'primary'` \| `'link'` \| `'info'` \| `'success'` \| `'warning'` \| `'danger'` \| `'black'` \| `'black-bis'` \| `'black-ter'` \| `'grey-darker'` \| `'grey-dark'` \| `'grey'` \| `'grey-light'` \| `'grey-lighter'` \| `'white'` \| `'light'` \| `'dark'` \| `'inherit'` \| `'current'` | — | Text color helper. | | ||
| | `bgColor` | `'primary'` \| `'link'` \| `'info'` \| `'success'` \| `'warning'` \| `'danger'` \| `'black'` \| `'black-bis'` \| `'black-ter'` \| `'grey-darker'` \| `'grey-dark'` \| `'grey'` \| `'grey-light'` \| `'grey-lighter'` \| `'white'` \| `'light'` \| `'dark'` \| `'inherit'` \| `'current'` | — | Background color helper. | | ||
| | `children` | `React.ReactNode` | — | Caption text to render. | | ||
| | ... | All standard `<figcaption>` and Bulma helper props | | (See [Helper Props](../helpers/usebulmaclasses)) | |
There was a problem hiding this comment.
Duplicate Figure.Caption prop table renders on the published Figure page — 🟡 Minor · Correctness
What: The generated props region already documents Figure.Caption in full (lines 174–182, inside the marker pair). This hand-written ### Figure.Caption Props table sits below ``, so it's preserved verbatim and appears as a second, unmanaged copy under the same ## Props heading.
Why it matters: The caption's props are shown twice with divergent detail (the generated copy links to the shared Bulma-color type; this copy inlines the full color union and different descriptions), and the stale copy will drift as FigureCaptionProps changes. Same root cause as the table.md duplication — the migration didn't remove the pre-existing manual sub-component tables when the generator began emitting them.
Fix: Delete the stale table (and its ### Figure.Caption Props heading); the generated block owns it.
| ### Figure.Caption Props | |
| | Prop | Type | Default | Description | | |
| | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | ------------------------------------------------ | | |
| | `className` | `string` | — | Additional CSS classes. | | |
| | `textColor` | `'primary'` \| `'link'` \| `'info'` \| `'success'` \| `'warning'` \| `'danger'` \| `'black'` \| `'black-bis'` \| `'black-ter'` \| `'grey-darker'` \| `'grey-dark'` \| `'grey'` \| `'grey-light'` \| `'grey-lighter'` \| `'white'` \| `'light'` \| `'dark'` \| `'inherit'` \| `'current'` | — | Text color helper. | | |
| | `bgColor` | `'primary'` \| `'link'` \| `'info'` \| `'success'` \| `'warning'` \| `'danger'` \| `'black'` \| `'black-bis'` \| `'black-ter'` \| `'grey-darker'` \| `'grey-dark'` \| `'grey'` \| `'grey-light'` \| `'grey-lighter'` \| `'white'` \| `'light'` \| `'dark'` \| `'inherit'` \| `'current'` | — | Background color helper. | | |
| | `children` | `React.ReactNode` | — | Caption text to render. | | |
| | ... | All standard `<figcaption>` and Bulma helper props | | (See [Helper Props](../helpers/usebulmaclasses)) | |
There was a problem hiding this comment.
Deep review — 2 blocking · 0 advisory
| # | Severity | Area | Finding | Location |
|---|---|---|---|---|
| 1 | 🟡 Minor | Correctness | Generated sub-component prop tables are duplicated by stale hand-written tables left below the props close marker |
docs/docs/api/elements/table.md:351 |
| 2 | 🟡 Minor | Correctness | Same defect: Figure.Caption props table duplicated below the close marker |
docs/docs/api/elements/figure.md:186 |
Overall: The change is sound. All 36 .tsx edits are provably comment-only — the single non-comment line is the semantically-identical relocation of const validButtonColors in Button.tsx, so there is zero runtime risk. The extractor claims (Omit/alias heritage, cross-module Table subs) live in the stacked base, and their downstream effect verifies here: LinkButton now tables its 14 inherited props and the Button summary reaches its page. The one real issue is on the two sub-component pages (Table, Figure): the generator now emits the sub-component tables inside the markers, but the pre-existing manual sub-component tables below the close marker were never removed, so each renders twice — with disagreeing values (e.g. Table.Tr isSelected default false vs —). The human should focus there; deleting the four stale Table sections and the one stale Figure.Caption section resolves it. pnpm all and check-docs-parity do not catch this because extra content is not a "loss."
Residual risk:
- Other pages carrying the same duplication? — Refuted. Swept all 30 element pages for prop-table headers: every page has exactly 1 except
table.md(11) andfigure.md(3), both flagged; no page has a stray table above the open marker either. - A
.tsxedit that silently changes behavior? — Refuted. Filtered every added/removed non-comment line across all 36 files; the only hit is thevalidButtonColorsmove, which is order-independent (theconstis used later, initializer unchanged). - Skills catalog gone stale from the changed Overview sentences? — Refuted. The committed
component-catalog.mdalready carries the new one-liners for all sampled components (Button, Link, Table, Content, OrderedList, SubTitle, Skeleton); tree is clean, sogen:catalog:checkstays green.
🏄 Clean set, brah — 30 pages roll in smooth and the source edits are pure comment foam, no runtime undertow. Just two gnarly double-exposures on the Table and Figure breaks where the old tables did not wipe out. Sweep those duplicates and this one is totally cruisable.
Found by comparing every generated page against its origin/main original in a
browser, and against the interfaces the tables claim to describe.
- Bare alias names where the hand-written tables had real types. A one-member
"union" (`type CellSpanValue = number`) was never a union node, and a union
naming another alias (`BulmaFixedGridColsProp = BulmaFixedGridCols |
'auto'`) failed the all-members-simple test. Both fell through to the bare
name with no `**Types:**` footnote, so cell.md's `colSpan`/`rowSpan` said
`CellSpanValue` where main said `number`, and grid.md's `fixedCols` was
opaque beside five siblings expanded to `0 | … | 12` in the same table.
Member aliases now resolve to a fixpoint.
- `children` synthesized for components that never render it. The row was
emitted for any interface with a DOM base, but inheriting `children` is not
rendering it: Divider spreads onto `<hr>`, so the row documented the one
thing React throws on ("hr is a void element tag and must neither have
`children`…"), and Icon always supplies its own JSX children, so anything
passed is silently dropped. Emitted only where the implementation names
`children`; the catch-all row still covers pass-through cases.
- Sub-components dropped when their props are an inline DOM type rather than a
named `*Props` interface. `Navbar.Divider` and `Pagination.Ellipsis` were
omitted from the generated Subcomponents lists entirely — which is why both
pages still carried a hand-written duplicate list. They are now listed (with
no table, since they add no props of their own).
- `never` and `false | true` merged from the branches of a discriminated
union. slider.md rendered `minDistance` as `never | number` and `range` as
`false | true`; the forbidding branch's `never` is noise standing where the
reader needs a type.
Verified: generator idempotent, all ten conformance checks green,
check-docs-parity still reports 0 prop/default/description losses across all
87 pages.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
`table.md` and `figure.md` still carried their pre-migration sub-component tables immediately after the generated block, so every sub-component was documented twice with disagreeing values — `isSelected` defaulted to `false` in the generated table and `—` in the legacy copy, and figure's stale `Figure.Caption Props` still dumped the 19-member colour union inline that this migration exists to remove. The generated tables supersede both. `delete.md`, `divider.md` and `icon.md` lose a synthesized `children` row for props those components do not render — `<hr>` throws on children and `Icon` overrides them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
Picks up the extractor fix from the base branch. `cell.md`'s `colSpan` and `rowSpan` go back to `number` — they had regressed to a bare `CellSpanValue`, which aliases exactly `number` and so told the reader strictly less. `grid.md`'s `fixedCols` expands to `0 | … | 12 | 'auto'` instead of a bare `BulmaFixedGridColsProp`; it was the only opaque cell in a table whose five sibling props were already fully expanded. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
Review — all 30 elements pages verified against main in a browserBuilt Zero prop losses across all 30 pages, and every Fixed and pushed here
The extractor gate that fixes this lives on #420; this branch carries the regenerated pages. 10/10 conformance, parity still 0 prop losses. Remaining on these pages — @claude, details and the rest of the list are on #420
Generated by Claude Code |
|
Claude finished @allxsmith's task in 6m 35s —— View job Remaining items from the review — resolved 2 of 3, 1 needs a design call
Fixed and pushed (
|
… Helper Props Three elements (Divider/hr, Pre, Progress) fell back to the generic "HTML" label because DOM_ELEMENT_LABELS had no entry for their concrete interfaces. Separately, skeleton.md's catch-all row linked to Helper Props even though SkeletonProps doesn't extend BulmaClassesProps and Skeleton never calls useBulmaClasses — catchAllRow() now reports whether BulmaClassesProps is actually in the heritage, and the generator only renders the link when it is. Co-authored-by: Alex Smith <allxsmith@users.noreply.github.com>
|
@coderabbitai full review Generated by Claude Code |
|
✅ Action performedFull review finished. Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 59 minutes. |
`scripts/lib/props-extract.mjs` and `scripts/gen-api-docs.mjs` are shared by
every branch here, so landing the `DOM_ELEMENT_LABELS` additions and the
`catchAll -> {text, helpers}` change on #422 alone left #420 and #421 without
them and made #423 — which is stacked above #422 — revert them. Same file,
same content, applied across the stack so the tip is consistent.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
`scripts/lib/props-extract.mjs` and `scripts/gen-api-docs.mjs` are shared by
every branch here, so landing the `DOM_ELEMENT_LABELS` additions and the
`catchAll -> {text, helpers}` change on #422 alone left #420 and #421 without
them and made #423 — which is stacked above #422 — revert them. Same file,
same content, applied across the stack so the tip is consistent.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
`scripts/lib/props-extract.mjs` and `scripts/gen-api-docs.mjs` are shared by
every branch here, so landing the `DOM_ELEMENT_LABELS` additions and the
`catchAll -> {text, helpers}` change on #422 alone left #420 and #421 without
them and made #423 — which is stacked above #422 — revert them. Same file,
same content, applied across the stack so the tip is consistent.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
|
Picked up 8a6e640 — the One stacking hazard worth flagging, now handled: Regenerating on #423 turned up that the Helper Props mislink was wider than the elements pages — General note for this stack: a fix to anything under Generated by Claude Code |
**The helper-props shortcut swallowed the DOM base.** `classifyTypeNode` tested `/BulmaClassesProps/` against the whole node's source text, so it fired for `Omit<React.HTMLAttributes<HTMLElement>, keyof BulmaClassesProps>` — where the name appears as the omit KEY LIST, not as the base being omitted. It returned before the `Omit` branch below could unwrap `React.HTMLAttributes<HTMLElement>`, so `HTMLElement` never reached `catchAllRow` and the catch-all lost its "All standard HTML attributes" half. That is the mechanism behind the menu.md (4 tables) and dropdown.md (2) regression against main. Matched structurally now: the node itself must name `BulmaClassesProps`, or be an `Omit`/`Pick` whose first type argument does. **`impliedFalse` applied to controlled-mode booleans.** An optional `boolean` with no destructured default is documented as `false`, which is right for a flag and wrong for a controlled prop, where `undefined` is what selects UNCONTROLLED mode. `collapse.md` claimed `open` defaults to `false` while its own description says "If provided, component is controlled" — two statements that cannot both hold. A prop whose description says it controls the component now keeps an empty Default. **`pnpm all` never ran the widened lint.** `all` invoked `turbo run … lint` directly; `turbo.json` declares no `//#lint` root task and only bulma-ui, create-bestax and bestax-migrate define one (each scoped to its own `src`), so `eslint scripts docs/scripts` — which exists only in the ROOT `lint` script — was skipped. That is the same "pnpm all green, CI red" gap this stack fixed for `format:check`, left in place for `lint`; CI caught it only because `ci.yml` runs `pnpm run lint` as its own step. Routed through `pnpm run lint`, and verified by planting an unused variable in `scripts/`. Verified: generator idempotent, ten of ten conformance checks green, `gen:catalog:check` exits 0, and the 87-page cell-by-cell diff against main is unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
**The helper-props shortcut swallowed the DOM base.** `classifyTypeNode` tested `/BulmaClassesProps/` against the whole node's source text, so it fired for `Omit<React.HTMLAttributes<HTMLElement>, keyof BulmaClassesProps>` — where the name appears as the omit KEY LIST, not as the base being omitted. It returned before the `Omit` branch below could unwrap `React.HTMLAttributes<HTMLElement>`, so `HTMLElement` never reached `catchAllRow` and the catch-all lost its "All standard HTML attributes" half. That is the mechanism behind the menu.md (4 tables) and dropdown.md (2) regression against main. Matched structurally now: the node itself must name `BulmaClassesProps`, or be an `Omit`/`Pick` whose first type argument does. **`impliedFalse` applied to controlled-mode booleans.** An optional `boolean` with no destructured default is documented as `false`, which is right for a flag and wrong for a controlled prop, where `undefined` is what selects UNCONTROLLED mode. `collapse.md` claimed `open` defaults to `false` while its own description says "If provided, component is controlled" — two statements that cannot both hold. A prop whose description says it controls the component now keeps an empty Default. **`pnpm all` never ran the widened lint.** `all` invoked `turbo run … lint` directly; `turbo.json` declares no `//#lint` root task and only bulma-ui, create-bestax and bestax-migrate define one (each scoped to its own `src`), so `eslint scripts docs/scripts` — which exists only in the ROOT `lint` script — was skipped. That is the same "pnpm all green, CI red" gap this stack fixed for `format:check`, left in place for `lint`; CI caught it only because `ci.yml` runs `pnpm run lint` as its own step. Routed through `pnpm run lint`, and verified by planting an unused variable in `scripts/`. Verified: generator idempotent, ten of ten conformance checks green, `gen:catalog:check` exits 0, and the 87-page cell-by-cell diff against main is unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
**The helper-props shortcut swallowed the DOM base.** `classifyTypeNode` tested `/BulmaClassesProps/` against the whole node's source text, so it fired for `Omit<React.HTMLAttributes<HTMLElement>, keyof BulmaClassesProps>` — where the name appears as the omit KEY LIST, not as the base being omitted. It returned before the `Omit` branch below could unwrap `React.HTMLAttributes<HTMLElement>`, so `HTMLElement` never reached `catchAllRow` and the catch-all lost its "All standard HTML attributes" half. That is the mechanism behind the menu.md (4 tables) and dropdown.md (2) regression against main. Matched structurally now: the node itself must name `BulmaClassesProps`, or be an `Omit`/`Pick` whose first type argument does. **`impliedFalse` applied to controlled-mode booleans.** An optional `boolean` with no destructured default is documented as `false`, which is right for a flag and wrong for a controlled prop, where `undefined` is what selects UNCONTROLLED mode. `collapse.md` claimed `open` defaults to `false` while its own description says "If provided, component is controlled" — two statements that cannot both hold. A prop whose description says it controls the component now keeps an empty Default. **`pnpm all` never ran the widened lint.** `all` invoked `turbo run … lint` directly; `turbo.json` declares no `//#lint` root task and only bulma-ui, create-bestax and bestax-migrate define one (each scoped to its own `src`), so `eslint scripts docs/scripts` — which exists only in the ROOT `lint` script — was skipped. That is the same "pnpm all green, CI red" gap this stack fixed for `format:check`, left in place for `lint`; CI caught it only because `ci.yml` runs `pnpm run lint` as its own step. Routed through `pnpm run lint`, and verified by planting an unused variable in `scripts/`. Verified: generator idempotent, ten of ten conformance checks green, `gen:catalog:check` exits 0, and the 87-page cell-by-cell diff against main is unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
There was a problem hiding this comment.
Deep review — 0 blocking · 2 advisory
| # | Severity | Area | Finding | Location |
|---|---|---|---|---|
| 1 | 🔵 Advisory | Robustness | namesChildren matches any children identifier in the impl (incl. an unrelated node.children access), so a future component could get a spurious synthesized children row |
scripts/lib/props-extract.mjs:299 |
| 2 | 🔵 Advisory | Robustness | controlled default-suppression is a broad /\bcontrolled\b/i text match — a boolean prop that merely mentions "controlled" in prose would silently lose its synthesized false default |
scripts/lib/props-extract.mjs:927 |
Overall: The change is sound. The extractor edits are careful, heavily commented with the exact regression each guards against, and — crucially — fail loud rather than silently degrading (the alias fixpoint throws instead of emitting bare names). I could not run node/pnpm in this sandbox, so I verified against the committed generated output instead: every claim in the PR body checks out against the real source. The riskiest surface is props-extract.mjs, where wrong-but-present output (as opposed to missing output) escapes the parity gate — so I traced the highest-leverage paths by hand (Omit/Pick heritage, cross-module subs, the catchAll.helpers split, namesChildren). All landed correctly. A human should focus first on props-extract.mjs and skim linkbutton.md/table.md/skeleton.md, which exercise the three trickiest new branches.
Residual risk:
- A helper-props link wrongly dropped by the new structural
isHelperscheck. Refuted: of all regenerated element pages, exactly one (skeleton.md) lost "Bulma helper props", andSkeleton.tsxgenuinely extends onlyReact.HTMLAttributes<HTMLDivElement>— nouseBulmaClasses. Every component that reaches helpers transitively (e.g.LinkButtonviaOmit<ButtonProps>) still shows the link. - A
childrenrow emitted for a void element (the Divider bug shape) elsewhere. Refuted: cross-checked all void-ish elements — Icon/Divider/Delete carry nochildrenidentifier and get no row; Progress/Image declarechildrenas their own interface member (legitimate). No synthesized false positives in the set. - The alias fixpoint cutting off mid-resolution and degrading to bare names. Refuted: it throws on residual progress rather than degrading, the committed docs generated cleanly (they match the extractor), and repo chains settle in 2 rounds against a bound of 8.
🏄 Chill, clean set, brah — the extractor's paddling straight through gnarly Omit/alias breaks that used to wipe it out, and every wave I dropped in on came up glassy. Two little ripples on the horizon, but nothing that'll close out the lineup. Send it.
Resolves the conflict in `scripts/check-conformance.mjs`, and restores a conformance check this branch had deleted. `style-mapping-sync` (#350) — the check that pins the inline-style → helper-prop mapping across its three deliberate copies and verifies every prop it names really exists in `bulma-ui/src` — is present at this branch's own merge base (69f9fe7) and on main, but absent from the branch: the header entry, the `MAPPING_FILES` constant, `checkStyleMappingSync` and its `CHECKS` registration were all dropped. Nothing in the PR description mentions removing it, and merging as-is would have deleted a live gate from the repo. Restored verbatim from main. The visible conflict was only the header comment block, where main had added `style-mapping-sync` and `publishable-manifests` entries — the deletion itself merged silently, which is why it was worth looking past the conflict markers. Also picks up main's `publishable-manifests` check (#412) and #442's test-deploy split. All twelve conformance checks now run and pass; the two removals that remain against main are deliberate and documented: `basename` (now unused) and `registerVarsKeys`, which moved to `scripts/lib/scss-vars.mjs` so the API-docs generator shares one SCSS parser. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
Bulma's `.level.is-mobile` sets `display: flex; flex-direction: row` (`bulma/sass/layout/level.scss:27-30`) — it keeps the level HORIZONTAL on mobile. A level without it stacks vertically below tablet. The description said the opposite: "Enables mobile layout (stacks vertically on mobile)", and the Usage prose repeated it. The wording is pre-existing on main, in both the props table and the prose, so this stack did not introduce it. It matters here because the migration seeds TSDoc from the doc pages, which launders a page-level error into the shipped `.d.ts` and users' editor tooltips — a wider blast radius than the page alone. Corrected at the source, so the generated row follows, and in the hand-written Usage paragraph. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
Round 4 — 0 blocking, and both advisories answered with measurementsThanks for attacking the two things I asked you to attack. One held, one didn't, and I'd rather record both. Refuted by your own check — Advisory 2, the
All three are genuinely controlled props, so there are zero false positives today. Two of them ( The fragility you describe is real but latent: a future plain flag whose prose happens to say "controlled" would silently lose its Advisory 1, Also on this branch since your review: main had moved and the stack had gone stale. Merging main down surfaced that the stack had deleted the Generated by Claude Code |
|
@claude deep review again — head is now Since your review:
Please focus on:
On advisories: short and actionable, please. Skip anything that only records what the sandbox blocked from running — I run the full gate locally each round and report it, so those notes displace signal. Generated by Claude Code |
|
Claude encountered an error after 7m 3s —— View job Deep review in progress — head
|
|
@claude one correction before you start — you are not actually blocked from executing things.
Use the aliases:
Your review said "wrong-but-present output escapes the parity gate, so I traced the highest-leverage paths by hand" — that reasoning was right, and it's exactly why running the generator matters: Only If a command still gets denied, name it and I'll get it allowlisted. Generated by Claude Code |
|
Claude finished @allxsmith's task in 4m 41s —— View job Deep review — head
|
CI caught this and it is my regression, not a pre-existing one: main's `theme.md` passes `prettier --check` at its real path. Removing the stray four-backtick fence pair around "Theme with Styling" took out a fence that was load-bearing. The outer ```` closed the inner ```tsx block (a longer fence closes a shorter one), so deleting the pair left the StyledTheme example unterminated — it swallowed the "### Nested Themes" heading and the block after it, and `prettier --check` failed on the file. Closing the ```tsx block explicitly gives the structure the section was always meant to have: the heading renders as a heading and each example is its own closed block. `pnpm run format:check` is green across the repo. Worth recording how this got through: I ran typecheck, lint, tests and the docs build locally but not the ROOT `format:check` — which is exactly the "pnpm all green, CI red" gap this stack exists to close, and the gap only closed for `lint` two commits ago. The root format check is in my gate from here. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
Fourth instance of the same silent-deletion pattern, found by the deep review on #420. `docs/CLAUDE.md`'s "LLM docs pipeline" section documented `scripts/flatten-llms-tabs.mjs`; this stack swapped in the `strip-generated-markers.mjs` paragraph in its place rather than alongside it. The script is not dead. It is still the FIRST step in docs' build chain (`docusaurus build && node scripts/flatten-llms-tabs.mjs && node scripts/strip-generated-markers.mjs`), still covered by `flatten-llms-tabs.test.mjs`, and does something unrelated to what displaced it — flattening `<PackageManagerTabs>`/`<Tabs>` MDX so the JSX does not land verbatim in `llms.txt`/`llms-full.txt`. Nothing else in the repo documented it, so a reader had no way to learn it exists or why it cannot be a Docusaurus plugin. Both steps are now described in the order the chain runs them. Same mechanism as the `gen-component-catalog.mjs` preamble, the manifest downgrades and the deleted `style-mapping-sync` check: a replacement where an addition was meant, with no conflict to force a second look. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
…420) * docs: add the API page generator, its CI gates and review aids Lands the tooling for generating the derivable parts of docs/docs/api, with no page generated yet: MANAGED_CATEGORIES and ORDERED_CATEGORIES both start empty and grow one category per follow-up, so the 87 page diffs stay reviewable instead of arriving as one 199-file change. Four regions per page, delimited by `<!-- bestax:generated <id> -->` markers — `overview` (the component's TSDoc summary), `import` (the public barrel), `props` (the `<X>Props` interfaces via the TypeScript compiler API) and `cssvars` (a new section parsed from the SCSS). Everything outside a marker pair is hand-written and preserved byte-for-byte; deleting a pair opts that region out, and `docs-section-order` makes that visible rather than silent. Three choices keep the output reading as hand-written rather than as typedoc: own members only, with the one catch-all `...` row the pages already wrote by hand; types from AST source text, never `checker.typeToString`, which expands `(typeof validColors)[number]` into 19 literals; and wide colour unions rendered as a link to the existing Valid values page. CI gates live in check-conformance.mjs, which already runs in CI, rather than a new workflow step: `docs-generated` recomputes each managed page in memory and diffs, `docs-section-order` holds the order and marker presence. Both were verified by tampering. Also closes two gate gaps this tooling exposed. `pnpm all` ran `turbo run format:check`, which only runs the per-package scripts — none cover `scripts/`, `docs/scripts/` or any `.md`; CI runs the root script, which does, so CI could be red while `pnpm all` was green. And nothing linted `scripts/` at all. `all` now calls the root format check and `lint` also runs eslint over `scripts` and `docs/scripts`; verified by planting an unused variable. Two review aids ship alongside, both one-shot and both used to validate the migration that follows: `check-docs-parity.mjs` fails on any prop, default, description word, code span, URL, live example or prose line that a generated page drops relative to its hand-written self, and `check-docs-wording.mjs` buckets every previously-documented prop by how its description changed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011c6ipfvBsYgF3Jf91ZzSr7 * chore: restore the component-catalog preamble this stack reverted `scripts/gen-component-catalog.mjs` carried a copy of the catalog preamble predating #365, so regenerating deleted 21 lines of shipped guidance: the per-component value-union warning, where to find the installed `.d.ts`, the `Skeleton` helper-prop exception, which sub-component families accept helper props, and the custom-component composition spine. The checked-in `component-catalog.md` still had #365's text, so `gen:catalog:check` regenerated it shorter and failed `git diff --exit-code` — this is why Build and Test is red on this PR. Restores the generator to main's version. The catalog now regenerates byte-identical to the committed file. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ * fix(docs): correct four prop-table defects in the API page extractor Found by comparing every generated page against its origin/main original in a browser, and against the interfaces the tables claim to describe. - Bare alias names where the hand-written tables had real types. A one-member "union" (`type CellSpanValue = number`) was never a union node, and a union naming another alias (`BulmaFixedGridColsProp = BulmaFixedGridCols | 'auto'`) failed the all-members-simple test. Both fell through to the bare name with no `**Types:**` footnote, so cell.md's `colSpan`/`rowSpan` said `CellSpanValue` where main said `number`, and grid.md's `fixedCols` was opaque beside five siblings expanded to `0 | … | 12` in the same table. Member aliases now resolve to a fixpoint. - `children` synthesized for components that never render it. The row was emitted for any interface with a DOM base, but inheriting `children` is not rendering it: Divider spreads onto `<hr>`, so the row documented the one thing React throws on ("hr is a void element tag and must neither have `children`…"), and Icon always supplies its own JSX children, so anything passed is silently dropped. Emitted only where the implementation names `children`; the catch-all row still covers pass-through cases. - Sub-components dropped when their props are an inline DOM type rather than a named `*Props` interface. `Navbar.Divider` and `Pagination.Ellipsis` were omitted from the generated Subcomponents lists entirely — which is why both pages still carried a hand-written duplicate list. They are now listed (with no table, since they add no props of their own). - `never` and `false | true` merged from the branches of a discriminated union. slider.md rendered `minDistance` as `never | number` and `range` as `false | true`; the forbidding branch's `never` is noise standing where the reader needs a type. Verified: generator idempotent, all ten conformance checks green, check-docs-parity still reports 0 prop/default/description losses across all 87 pages. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ * fix(docs): carry the catch-all fix through the rest of the stack `scripts/lib/props-extract.mjs` and `scripts/gen-api-docs.mjs` are shared by every branch here, so landing the `DOM_ELEMENT_LABELS` additions and the `catchAll -> {text, helpers}` change on #422 alone left #420 and #421 without them and made #423 — which is stacked above #422 — revert them. Same file, same content, applied across the stack so the tip is consistent. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ * fix(docs): expand DateFormatOption instead of leaving a bare alias The three datetime pages had regressed from main's `string | Intl.DateTimeFormatOptions` to a bare `DateFormatOption`, which is declared in `form/_pickerInternals/` and is not exported from the barrel — so a reader could neither import it nor look it up, and no `**Types:**` footnote covered it either. A union member naming a type the alias index cannot resolve (`Intl.DateTimeFormatOptions` is a qualified name, not an indexed identifier) now falls back to its own source text. Blast radius is exactly the three `format` cells; no other page changes. Found by an exhaustive cell-by-cell diff of all 87 generated pages against their origin/main originals, which also settles the rest: one genuine prop row lost across the whole migration (`card.md`'s `m`/`p`), and every remaining type or default difference is either an improvement over drifted prose or a bare alias that does carry a footnote. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ * fix(docs): rebase the manifests onto main and address the review findings **Manifests.** These branches were cut before 19 commits landed on main and were never refreshed, so relative to their OWN merge base they downgraded `@commitlint/cli` 21.2.1→21.0.2, `@commitlint/config-conventional` 21.2.0→21.0.2, `@semantic-release/github` 12.0.9→12.0.2, `semantic-release` 25.0.8→25.0.2, `prettier` 3.9.6→3.9.4, `react`/`react-dom` 19.2.8→19.2.3, `@docusaurus/*` 3.10.2→3.9.2 and `@fortawesome/fontawesome-free` 7.3.1→7.2.0 — and dropped docs' `"test": "node --test \"scripts/*.test.mjs\""`, silently disabling the `flatten-llms-tabs` tests #408 added. Because the branches modify those lines rather than merely trailing main, a merge would have carried the downgrades in. `package.json`, `docs/package.json` and `pnpm-lock.yaml` are now main's, with only this stack's own script additions re-applied on top: `gen:api-sources`, `gen:api-docs`, `gen:api-docs:check`, `gen`, the `lint` widening over `scripts` and `docs/scripts`, the root `format:check` fix in `all`, and the marker-stripping step chained after the llms flattener. The stack adds no dependency of its own, so main's lockfile is exactly right. **Review findings.** From the CodeRabbit and Claude deep reviews on #421/#422: - The alias fixpoint resolved the mixed unions and the `indirect` renames in two separate passes, so a mixed union naming a forward-only alias — or a rename pointing at a mixed alias — stayed opaque forever. Both reviewers flagged it independently. The two now interleave in one bounded fixpoint. - `rendersChildren` matched `/\bchildren\b/` against raw source text, which counts the word in a comment or an unrelated string. It is an AST walk now. - Six `gapSize*` props on `Columns.tsx` carried TWO JSDoc blocks — the migration stacked the new one on top of the old instead of replacing it, so dead comments shipped in the `.d.ts`. Collapsed, keeping the tie-break clause the first block had and the page had lost. - A small local interface named in a type cell now renders its object shape: `icontext.md`'s `items` goes back to main's `{ iconProps: IconProps; text?: string }[]` from a bare `IconTextItem`, and `slider.md`'s `marks` improves on both to `{ value: number; label?: React.ReactNode }[]`. Neither interface is exported from the barrel, so the bare name was unlookupable. - Two pre-existing `helpers/` defects, relocated by this stack's reorder and worth fixing while the pages are open: a stray four-backtick fence in `theme.md` trapped the "Theme with Styling" heading and its example inside a code block, and `usebulmaclasses.md` claimed a `className` the example never passes and `has-text-info-mobile` for `color: 'link'`. Both refactors are behaviour-preserving: the generator emits byte-identical output for them today. Verified: generator idempotent, ten of ten conformance checks green, `gen:catalog:check` exits 0, docs build clean, bulma-ui typecheck/lint/tests pass, and the 87-page cell-by-cell diff against main is unchanged at one lost prop row. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ * fix(docs): restore bestax-migrate's manifest and the lockfile from main Rebasing the root and docs manifests left `bestax-migrate/package.json` behind, and regenerating the lockfile against it reintroduced a stale entry: the branch still lists `@allxsmith/bestax-bulma` under `dependencies`, where #412/#417 moved it to `devDependencies`, and is missing the `prepack`/`postpack` pack-manifest hooks those PRs added. The branch never modified that file — it only trails main — so taking main's copy is a clean fast-forward. `pnpm-lock.yaml` is now byte-identical to main's and `pnpm install --frozen-lockfile` succeeds against it, which is the check CI runs. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ * fix(docs): fail the alias fixpoint instead of degrading to bare names The deep review on #421 flagged that the alias-resolution fixpoint degrades silently: if a chain needs more than the round bound, the survivors fall back to a bare name plus a `**Types:**` footnote rather than the expansion, and nothing says so. Running out of rounds is a different condition from settling. An alias that genuinely cannot expand stops making progress and the loop exits clean — that path is unchanged. But if the bound cuts the loop off while it is still resolving, the survivors render as bare identifiers, which is the exact regression this generator exists to prevent. That case now throws, naming the unresolved aliases. The bound is a named constant (`ALIAS_FIXPOINT_ROUNDS`) so the error can point at it. Chains in this repo settle in two rounds; the bound only exists to stop a mutually-recursive pair spinning. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ * fix(docs): make the marker stripper fail instead of no-opping silently The deep review asked whether this step fails loudly when it matches nothing. It did not — it logged "removed 0 marker(s) from 0 file(s)" and exited 0. That is the one failure this step exists to prevent. Its own header records why it is a build step and not a plugin: the first attempt was a `postBuild` hook, `postBuild` runs under `Promise.all`, it raced ahead of docusaurus-plugin-llms and silently found nothing to strip. A quiet no-op here ships ~600 markers into llms-full.txt and every per-page `.md` twin with a green build. Stripping nothing is only correct when there was nothing to strip, so the check compares against the SOURCE pages: zero stripped AND zero markers in docs/docs/api is the legitimate "no managed categories yet" state (which is this branch, with MANAGED_CATEGORIES empty). Zero stripped while the source carries markers means the built markdown moved, the marker format changed, or the ordering regressed — that now exits 1 and says which. Also answers the other half of the question: the glob only ever reaches `.md` files plus llms.txt / llms-full.txt, so it cannot touch built HTML. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ * fix(docs): correct three defects the #420 deep review found **The helper-props shortcut swallowed the DOM base.** `classifyTypeNode` tested `/BulmaClassesProps/` against the whole node's source text, so it fired for `Omit<React.HTMLAttributes<HTMLElement>, keyof BulmaClassesProps>` — where the name appears as the omit KEY LIST, not as the base being omitted. It returned before the `Omit` branch below could unwrap `React.HTMLAttributes<HTMLElement>`, so `HTMLElement` never reached `catchAllRow` and the catch-all lost its "All standard HTML attributes" half. That is the mechanism behind the menu.md (4 tables) and dropdown.md (2) regression against main. Matched structurally now: the node itself must name `BulmaClassesProps`, or be an `Omit`/`Pick` whose first type argument does. **`impliedFalse` applied to controlled-mode booleans.** An optional `boolean` with no destructured default is documented as `false`, which is right for a flag and wrong for a controlled prop, where `undefined` is what selects UNCONTROLLED mode. `collapse.md` claimed `open` defaults to `false` while its own description says "If provided, component is controlled" — two statements that cannot both hold. A prop whose description says it controls the component now keeps an empty Default. **`pnpm all` never ran the widened lint.** `all` invoked `turbo run … lint` directly; `turbo.json` declares no `//#lint` root task and only bulma-ui, create-bestax and bestax-migrate define one (each scoped to its own `src`), so `eslint scripts docs/scripts` — which exists only in the ROOT `lint` script — was skipped. That is the same "pnpm all green, CI red" gap this stack fixed for `format:check`, left in place for `lint`; CI caught it only because `ci.yml` runs `pnpm run lint` as its own step. Routed through `pnpm run lint`, and verified by planting an unused variable in `scripts/`. Verified: generator idempotent, ten of ten conformance checks green, `gen:catalog:check` exits 0, and the 87-page cell-by-cell diff against main is unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ * fix(docs): close the theme.md fence my earlier edit left open CI caught this and it is my regression, not a pre-existing one: main's `theme.md` passes `prettier --check` at its real path. Removing the stray four-backtick fence pair around "Theme with Styling" took out a fence that was load-bearing. The outer ```` closed the inner ```tsx block (a longer fence closes a shorter one), so deleting the pair left the StyledTheme example unterminated — it swallowed the "### Nested Themes" heading and the block after it, and `prettier --check` failed on the file. Closing the ```tsx block explicitly gives the structure the section was always meant to have: the heading renders as a heading and each example is its own closed block. `pnpm run format:check` is green across the repo. Worth recording how this got through: I ran typecheck, lint, tests and the docs build locally but not the ROOT `format:check` — which is exactly the "pnpm all green, CI red" gap this stack exists to close, and the gap only closed for `lint` two commits ago. The root format check is in my gate from here. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ * docs: restore the flatten-llms-tabs description this stack replaced Fourth instance of the same silent-deletion pattern, found by the deep review on #420. `docs/CLAUDE.md`'s "LLM docs pipeline" section documented `scripts/flatten-llms-tabs.mjs`; this stack swapped in the `strip-generated-markers.mjs` paragraph in its place rather than alongside it. The script is not dead. It is still the FIRST step in docs' build chain (`docusaurus build && node scripts/flatten-llms-tabs.mjs && node scripts/strip-generated-markers.mjs`), still covered by `flatten-llms-tabs.test.mjs`, and does something unrelated to what displaced it — flattening `<PackageManagerTabs>`/`<Tabs>` MDX so the JSX does not land verbatim in `llms.txt`/`llms-full.txt`. Nothing else in the repo documented it, so a reader had no way to learn it exists or why it cannot be a Docusaurus plugin. Both steps are now described in the order the chain runs them. Same mechanism as the `gen-component-catalog.mjs` preamble, the manifest downgrades and the deleted `style-mapping-sync` check: a replacement where an addition was meant, with no conflict to force a second look. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ --------- Co-authored-by: Claude <noreply@anthropic.com>
…#421) * docs: add the API page generator, its CI gates and review aids Lands the tooling for generating the derivable parts of docs/docs/api, with no page generated yet: MANAGED_CATEGORIES and ORDERED_CATEGORIES both start empty and grow one category per follow-up, so the 87 page diffs stay reviewable instead of arriving as one 199-file change. Four regions per page, delimited by `<!-- bestax:generated <id> -->` markers — `overview` (the component's TSDoc summary), `import` (the public barrel), `props` (the `<X>Props` interfaces via the TypeScript compiler API) and `cssvars` (a new section parsed from the SCSS). Everything outside a marker pair is hand-written and preserved byte-for-byte; deleting a pair opts that region out, and `docs-section-order` makes that visible rather than silent. Three choices keep the output reading as hand-written rather than as typedoc: own members only, with the one catch-all `...` row the pages already wrote by hand; types from AST source text, never `checker.typeToString`, which expands `(typeof validColors)[number]` into 19 literals; and wide colour unions rendered as a link to the existing Valid values page. CI gates live in check-conformance.mjs, which already runs in CI, rather than a new workflow step: `docs-generated` recomputes each managed page in memory and diffs, `docs-section-order` holds the order and marker presence. Both were verified by tampering. Also closes two gate gaps this tooling exposed. `pnpm all` ran `turbo run format:check`, which only runs the per-package scripts — none cover `scripts/`, `docs/scripts/` or any `.md`; CI runs the root script, which does, so CI could be red while `pnpm all` was green. And nothing linted `scripts/` at all. `all` now calls the root format check and `lint` also runs eslint over `scripts` and `docs/scripts`; verified by planting an unused variable. Two review aids ship alongside, both one-shot and both used to validate the migration that follows: `check-docs-parity.mjs` fails on any prop, default, description word, code span, URL, live example or prose line that a generated page drops relative to its hand-written self, and `check-docs-wording.mjs` buckets every previously-documented prop by how its description changed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011c6ipfvBsYgF3Jf91ZzSr7 * docs(bulma-ui): generate the layout, columns and grid API pages First categories through the generator, plus `helpers/` reordered but not generated — four of its six pages document hooks with `## API` and no `## Props` at all, and `config.md`/`theme.md` keep their hand-written tables (theme.md's Props section is a ~350-line prose sub-API, not a table). `@property` blocks move onto the interface members as inline TSDoc, so a description is verifiable by position and reaches users' editors and the shipped .d.ts. Descriptions were seeded FROM the docs pages, not the other way round: the hand-written tables are consistently the richer text, and the page stays authoritative wherever the two disagree. Component TSDoc summaries were likewise seeded from the pages — the existing ones ("Bulma Hero component root.", "Container component for Bulma.") were worse than the prose they would have replaced. That text ships in the .d.ts, so read the `component-catalog.md` diff: it is the canary for this step. Verified: check-docs-parity reports 0 losses across all 87 pages; the generator is idempotent. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011c6ipfvBsYgF3Jf91ZzSr7 * chore: restore the component-catalog preamble this stack reverted `scripts/gen-component-catalog.mjs` carried a copy of the catalog preamble predating #365, so regenerating deleted 21 lines of shipped guidance: the per-component value-union warning, where to find the installed `.d.ts`, the `Skeleton` helper-prop exception, which sub-component families accept helper props, and the custom-component composition spine. The checked-in `component-catalog.md` still had #365's text, so `gen:catalog:check` regenerated it shorter and failed `git diff --exit-code` — this is why Build and Test is red on this PR. Restores the generator to main's version. The catalog now regenerates byte-identical to the committed file. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ * chore: restore the component-catalog preamble this stack reverted `scripts/gen-component-catalog.mjs` carried a copy of the catalog preamble predating #365, so regenerating deleted 21 lines of shipped guidance: the per-component value-union warning, where to find the installed `.d.ts`, the `Skeleton` helper-prop exception, which sub-component families accept helper props, and the custom-component composition spine. This branch regenerated the catalog with that stale generator, committing the loss into a shipped skill artifact. Restores the generator to main's version and regenerates; the preamble matches main again and the component one-liners are unaffected. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ * fix(docs): correct four prop-table defects in the API page extractor Found by comparing every generated page against its origin/main original in a browser, and against the interfaces the tables claim to describe. - Bare alias names where the hand-written tables had real types. A one-member "union" (`type CellSpanValue = number`) was never a union node, and a union naming another alias (`BulmaFixedGridColsProp = BulmaFixedGridCols | 'auto'`) failed the all-members-simple test. Both fell through to the bare name with no `**Types:**` footnote, so cell.md's `colSpan`/`rowSpan` said `CellSpanValue` where main said `number`, and grid.md's `fixedCols` was opaque beside five siblings expanded to `0 | … | 12` in the same table. Member aliases now resolve to a fixpoint. - `children` synthesized for components that never render it. The row was emitted for any interface with a DOM base, but inheriting `children` is not rendering it: Divider spreads onto `<hr>`, so the row documented the one thing React throws on ("hr is a void element tag and must neither have `children`…"), and Icon always supplies its own JSX children, so anything passed is silently dropped. Emitted only where the implementation names `children`; the catch-all row still covers pass-through cases. - Sub-components dropped when their props are an inline DOM type rather than a named `*Props` interface. `Navbar.Divider` and `Pagination.Ellipsis` were omitted from the generated Subcomponents lists entirely — which is why both pages still carried a hand-written duplicate list. They are now listed (with no table, since they add no props of their own). - `never` and `false | true` merged from the branches of a discriminated union. slider.md rendered `minDistance` as `never | number` and `range` as `false | true`; the forbidding branch's `never` is noise standing where the reader needs a type. Verified: generator idempotent, all ten conformance checks green, check-docs-parity still reports 0 prop/default/description losses across all 87 pages. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ * fix(docs): regenerate the grid pages with the corrected type cells Picks up the extractor fix from the base branch. `cell.md`'s `colSpan` and `rowSpan` go back to `number` — they had regressed to a bare `CellSpanValue`, which aliases exactly `number` and so told the reader strictly less. `grid.md`'s `fixedCols` expands to `0 | … | 12 | 'auto'` instead of a bare `BulmaFixedGridColsProp`; it was the only opaque cell in a table whose five sibling props were already fully expanded. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ * fix(docs): carry the catch-all fix through the rest of the stack `scripts/lib/props-extract.mjs` and `scripts/gen-api-docs.mjs` are shared by every branch here, so landing the `DOM_ELEMENT_LABELS` additions and the `catchAll -> {text, helpers}` change on #422 alone left #420 and #421 without them and made #423 — which is stacked above #422 — revert them. Same file, same content, applied across the stack so the tip is consistent. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ * fix(docs): carry the catch-all fix through the rest of the stack `scripts/lib/props-extract.mjs` and `scripts/gen-api-docs.mjs` are shared by every branch here, so landing the `DOM_ELEMENT_LABELS` additions and the `catchAll -> {text, helpers}` change on #422 alone left #420 and #421 without them and made #423 — which is stacked above #422 — revert them. Same file, same content, applied across the stack so the tip is consistent. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ * fix(docs): expand DateFormatOption instead of leaving a bare alias The three datetime pages had regressed from main's `string | Intl.DateTimeFormatOptions` to a bare `DateFormatOption`, which is declared in `form/_pickerInternals/` and is not exported from the barrel — so a reader could neither import it nor look it up, and no `**Types:**` footnote covered it either. A union member naming a type the alias index cannot resolve (`Intl.DateTimeFormatOptions` is a qualified name, not an indexed identifier) now falls back to its own source text. Blast radius is exactly the three `format` cells; no other page changes. Found by an exhaustive cell-by-cell diff of all 87 generated pages against their origin/main originals, which also settles the rest: one genuine prop row lost across the whole migration (`card.md`'s `m`/`p`), and every remaining type or default difference is either an improvement over drifted prose or a bare alias that does carry a footnote. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ * fix(docs): expand DateFormatOption instead of leaving a bare alias The three datetime pages had regressed from main's `string | Intl.DateTimeFormatOptions` to a bare `DateFormatOption`, which is declared in `form/_pickerInternals/` and is not exported from the barrel — so a reader could neither import it nor look it up, and no `**Types:**` footnote covered it either. A union member naming a type the alias index cannot resolve (`Intl.DateTimeFormatOptions` is a qualified name, not an indexed identifier) now falls back to its own source text. Blast radius is exactly the three `format` cells; no other page changes. Found by an exhaustive cell-by-cell diff of all 87 generated pages against their origin/main originals, which also settles the rest: one genuine prop row lost across the whole migration (`card.md`'s `m`/`p`), and every remaining type or default difference is either an improvement over drifted prose or a bare alias that does carry a footnote. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ * fix(docs): rebase the manifests onto main and address the review findings **Manifests.** These branches were cut before 19 commits landed on main and were never refreshed, so relative to their OWN merge base they downgraded `@commitlint/cli` 21.2.1→21.0.2, `@commitlint/config-conventional` 21.2.0→21.0.2, `@semantic-release/github` 12.0.9→12.0.2, `semantic-release` 25.0.8→25.0.2, `prettier` 3.9.6→3.9.4, `react`/`react-dom` 19.2.8→19.2.3, `@docusaurus/*` 3.10.2→3.9.2 and `@fortawesome/fontawesome-free` 7.3.1→7.2.0 — and dropped docs' `"test": "node --test \"scripts/*.test.mjs\""`, silently disabling the `flatten-llms-tabs` tests #408 added. Because the branches modify those lines rather than merely trailing main, a merge would have carried the downgrades in. `package.json`, `docs/package.json` and `pnpm-lock.yaml` are now main's, with only this stack's own script additions re-applied on top: `gen:api-sources`, `gen:api-docs`, `gen:api-docs:check`, `gen`, the `lint` widening over `scripts` and `docs/scripts`, the root `format:check` fix in `all`, and the marker-stripping step chained after the llms flattener. The stack adds no dependency of its own, so main's lockfile is exactly right. **Review findings.** From the CodeRabbit and Claude deep reviews on #421/#422: - The alias fixpoint resolved the mixed unions and the `indirect` renames in two separate passes, so a mixed union naming a forward-only alias — or a rename pointing at a mixed alias — stayed opaque forever. Both reviewers flagged it independently. The two now interleave in one bounded fixpoint. - `rendersChildren` matched `/\bchildren\b/` against raw source text, which counts the word in a comment or an unrelated string. It is an AST walk now. - Six `gapSize*` props on `Columns.tsx` carried TWO JSDoc blocks — the migration stacked the new one on top of the old instead of replacing it, so dead comments shipped in the `.d.ts`. Collapsed, keeping the tie-break clause the first block had and the page had lost. - A small local interface named in a type cell now renders its object shape: `icontext.md`'s `items` goes back to main's `{ iconProps: IconProps; text?: string }[]` from a bare `IconTextItem`, and `slider.md`'s `marks` improves on both to `{ value: number; label?: React.ReactNode }[]`. Neither interface is exported from the barrel, so the bare name was unlookupable. - Two pre-existing `helpers/` defects, relocated by this stack's reorder and worth fixing while the pages are open: a stray four-backtick fence in `theme.md` trapped the "Theme with Styling" heading and its example inside a code block, and `usebulmaclasses.md` claimed a `className` the example never passes and `has-text-info-mobile` for `color: 'link'`. Both refactors are behaviour-preserving: the generator emits byte-identical output for them today. Verified: generator idempotent, ten of ten conformance checks green, `gen:catalog:check` exits 0, docs build clean, bulma-ui typecheck/lint/tests pass, and the 87-page cell-by-cell diff against main is unchanged at one lost prop row. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ * fix(docs): rebase the manifests onto main and address the review findings **Manifests.** These branches were cut before 19 commits landed on main and were never refreshed, so relative to their OWN merge base they downgraded `@commitlint/cli` 21.2.1→21.0.2, `@commitlint/config-conventional` 21.2.0→21.0.2, `@semantic-release/github` 12.0.9→12.0.2, `semantic-release` 25.0.8→25.0.2, `prettier` 3.9.6→3.9.4, `react`/`react-dom` 19.2.8→19.2.3, `@docusaurus/*` 3.10.2→3.9.2 and `@fortawesome/fontawesome-free` 7.3.1→7.2.0 — and dropped docs' `"test": "node --test \"scripts/*.test.mjs\""`, silently disabling the `flatten-llms-tabs` tests #408 added. Because the branches modify those lines rather than merely trailing main, a merge would have carried the downgrades in. `package.json`, `docs/package.json` and `pnpm-lock.yaml` are now main's, with only this stack's own script additions re-applied on top: `gen:api-sources`, `gen:api-docs`, `gen:api-docs:check`, `gen`, the `lint` widening over `scripts` and `docs/scripts`, the root `format:check` fix in `all`, and the marker-stripping step chained after the llms flattener. The stack adds no dependency of its own, so main's lockfile is exactly right. **Review findings.** From the CodeRabbit and Claude deep reviews on #421/#422: - The alias fixpoint resolved the mixed unions and the `indirect` renames in two separate passes, so a mixed union naming a forward-only alias — or a rename pointing at a mixed alias — stayed opaque forever. Both reviewers flagged it independently. The two now interleave in one bounded fixpoint. - `rendersChildren` matched `/\bchildren\b/` against raw source text, which counts the word in a comment or an unrelated string. It is an AST walk now. - Six `gapSize*` props on `Columns.tsx` carried TWO JSDoc blocks — the migration stacked the new one on top of the old instead of replacing it, so dead comments shipped in the `.d.ts`. Collapsed, keeping the tie-break clause the first block had and the page had lost. - A small local interface named in a type cell now renders its object shape: `icontext.md`'s `items` goes back to main's `{ iconProps: IconProps; text?: string }[]` from a bare `IconTextItem`, and `slider.md`'s `marks` improves on both to `{ value: number; label?: React.ReactNode }[]`. Neither interface is exported from the barrel, so the bare name was unlookupable. - Two pre-existing `helpers/` defects, relocated by this stack's reorder and worth fixing while the pages are open: a stray four-backtick fence in `theme.md` trapped the "Theme with Styling" heading and its example inside a code block, and `usebulmaclasses.md` claimed a `className` the example never passes and `has-text-info-mobile` for `color: 'link'`. Both refactors are behaviour-preserving: the generator emits byte-identical output for them today. Verified: generator idempotent, ten of ten conformance checks green, `gen:catalog:check` exits 0, docs build clean, bulma-ui typecheck/lint/tests pass, and the 87-page cell-by-cell diff against main is unchanged at one lost prop row. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ * fix(docs): restore bestax-migrate's manifest and the lockfile from main Rebasing the root and docs manifests left `bestax-migrate/package.json` behind, and regenerating the lockfile against it reintroduced a stale entry: the branch still lists `@allxsmith/bestax-bulma` under `dependencies`, where #412/#417 moved it to `devDependencies`, and is missing the `prepack`/`postpack` pack-manifest hooks those PRs added. The branch never modified that file — it only trails main — so taking main's copy is a clean fast-forward. `pnpm-lock.yaml` is now byte-identical to main's and `pnpm install --frozen-lockfile` succeeds against it, which is the check CI runs. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ * fix(docs): restore bestax-migrate's manifest and the lockfile from main Rebasing the root and docs manifests left `bestax-migrate/package.json` behind, and regenerating the lockfile against it reintroduced a stale entry: the branch still lists `@allxsmith/bestax-bulma` under `dependencies`, where #412/#417 moved it to `devDependencies`, and is missing the `prepack`/`postpack` pack-manifest hooks those PRs added. The branch never modified that file — it only trails main — so taking main's copy is a clean fast-forward. `pnpm-lock.yaml` is now byte-identical to main's and `pnpm install --frozen-lockfile` succeeds against it, which is the check CI runs. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ * fix(docs): fail the alias fixpoint instead of degrading to bare names The deep review on #421 flagged that the alias-resolution fixpoint degrades silently: if a chain needs more than the round bound, the survivors fall back to a bare name plus a `**Types:**` footnote rather than the expansion, and nothing says so. Running out of rounds is a different condition from settling. An alias that genuinely cannot expand stops making progress and the loop exits clean — that path is unchanged. But if the bound cuts the loop off while it is still resolving, the survivors render as bare identifiers, which is the exact regression this generator exists to prevent. That case now throws, naming the unresolved aliases. The bound is a named constant (`ALIAS_FIXPOINT_ROUNDS`) so the error can point at it. Chains in this repo settle in two rounds; the bound only exists to stop a mutually-recursive pair spinning. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ * fix(docs): make the marker stripper fail instead of no-opping silently The deep review asked whether this step fails loudly when it matches nothing. It did not — it logged "removed 0 marker(s) from 0 file(s)" and exited 0. That is the one failure this step exists to prevent. Its own header records why it is a build step and not a plugin: the first attempt was a `postBuild` hook, `postBuild` runs under `Promise.all`, it raced ahead of docusaurus-plugin-llms and silently found nothing to strip. A quiet no-op here ships ~600 markers into llms-full.txt and every per-page `.md` twin with a green build. Stripping nothing is only correct when there was nothing to strip, so the check compares against the SOURCE pages: zero stripped AND zero markers in docs/docs/api is the legitimate "no managed categories yet" state (which is this branch, with MANAGED_CATEGORIES empty). Zero stripped while the source carries markers means the built markdown moved, the marker format changed, or the ordering regressed — that now exits 1 and says which. Also answers the other half of the question: the glob only ever reaches `.md` files plus llms.txt / llms-full.txt, so it cannot touch built HTML. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ * fix(docs): correct three defects the #420 deep review found **The helper-props shortcut swallowed the DOM base.** `classifyTypeNode` tested `/BulmaClassesProps/` against the whole node's source text, so it fired for `Omit<React.HTMLAttributes<HTMLElement>, keyof BulmaClassesProps>` — where the name appears as the omit KEY LIST, not as the base being omitted. It returned before the `Omit` branch below could unwrap `React.HTMLAttributes<HTMLElement>`, so `HTMLElement` never reached `catchAllRow` and the catch-all lost its "All standard HTML attributes" half. That is the mechanism behind the menu.md (4 tables) and dropdown.md (2) regression against main. Matched structurally now: the node itself must name `BulmaClassesProps`, or be an `Omit`/`Pick` whose first type argument does. **`impliedFalse` applied to controlled-mode booleans.** An optional `boolean` with no destructured default is documented as `false`, which is right for a flag and wrong for a controlled prop, where `undefined` is what selects UNCONTROLLED mode. `collapse.md` claimed `open` defaults to `false` while its own description says "If provided, component is controlled" — two statements that cannot both hold. A prop whose description says it controls the component now keeps an empty Default. **`pnpm all` never ran the widened lint.** `all` invoked `turbo run … lint` directly; `turbo.json` declares no `//#lint` root task and only bulma-ui, create-bestax and bestax-migrate define one (each scoped to its own `src`), so `eslint scripts docs/scripts` — which exists only in the ROOT `lint` script — was skipped. That is the same "pnpm all green, CI red" gap this stack fixed for `format:check`, left in place for `lint`; CI caught it only because `ci.yml` runs `pnpm run lint` as its own step. Routed through `pnpm run lint`, and verified by planting an unused variable in `scripts/`. Verified: generator idempotent, ten of ten conformance checks green, `gen:catalog:check` exits 0, and the 87-page cell-by-cell diff against main is unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ * fix(docs): correct three defects the #420 deep review found **The helper-props shortcut swallowed the DOM base.** `classifyTypeNode` tested `/BulmaClassesProps/` against the whole node's source text, so it fired for `Omit<React.HTMLAttributes<HTMLElement>, keyof BulmaClassesProps>` — where the name appears as the omit KEY LIST, not as the base being omitted. It returned before the `Omit` branch below could unwrap `React.HTMLAttributes<HTMLElement>`, so `HTMLElement` never reached `catchAllRow` and the catch-all lost its "All standard HTML attributes" half. That is the mechanism behind the menu.md (4 tables) and dropdown.md (2) regression against main. Matched structurally now: the node itself must name `BulmaClassesProps`, or be an `Omit`/`Pick` whose first type argument does. **`impliedFalse` applied to controlled-mode booleans.** An optional `boolean` with no destructured default is documented as `false`, which is right for a flag and wrong for a controlled prop, where `undefined` is what selects UNCONTROLLED mode. `collapse.md` claimed `open` defaults to `false` while its own description says "If provided, component is controlled" — two statements that cannot both hold. A prop whose description says it controls the component now keeps an empty Default. **`pnpm all` never ran the widened lint.** `all` invoked `turbo run … lint` directly; `turbo.json` declares no `//#lint` root task and only bulma-ui, create-bestax and bestax-migrate define one (each scoped to its own `src`), so `eslint scripts docs/scripts` — which exists only in the ROOT `lint` script — was skipped. That is the same "pnpm all green, CI red" gap this stack fixed for `format:check`, left in place for `lint`; CI caught it only because `ci.yml` runs `pnpm run lint` as its own step. Routed through `pnpm run lint`, and verified by planting an unused variable in `scripts/`. Verified: generator idempotent, ten of ten conformance checks green, `gen:catalog:check` exits 0, and the 87-page cell-by-cell diff against main is unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ * fix(bulma-ui): correct the inverted Level.isMobile description Bulma's `.level.is-mobile` sets `display: flex; flex-direction: row` (`bulma/sass/layout/level.scss:27-30`) — it keeps the level HORIZONTAL on mobile. A level without it stacks vertically below tablet. The description said the opposite: "Enables mobile layout (stacks vertically on mobile)", and the Usage prose repeated it. The wording is pre-existing on main, in both the props table and the prose, so this stack did not introduce it. It matters here because the migration seeds TSDoc from the doc pages, which launders a page-level error into the shipped `.d.ts` and users' editor tooltips — a wider blast radius than the page alone. Corrected at the source, so the generated row follows, and in the hand-written Usage paragraph. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ * fix(docs): close the theme.md fence my earlier edit left open CI caught this and it is my regression, not a pre-existing one: main's `theme.md` passes `prettier --check` at its real path. Removing the stray four-backtick fence pair around "Theme with Styling" took out a fence that was load-bearing. The outer ```` closed the inner ```tsx block (a longer fence closes a shorter one), so deleting the pair left the StyledTheme example unterminated — it swallowed the "### Nested Themes" heading and the block after it, and `prettier --check` failed on the file. Closing the ```tsx block explicitly gives the structure the section was always meant to have: the heading renders as a heading and each example is its own closed block. `pnpm run format:check` is green across the repo. Worth recording how this got through: I ran typecheck, lint, tests and the docs build locally but not the ROOT `format:check` — which is exactly the "pnpm all green, CI red" gap this stack exists to close, and the gap only closed for `lint` two commits ago. The root format check is in my gate from here. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ * docs: restore the flatten-llms-tabs description this stack replaced Fourth instance of the same silent-deletion pattern, found by the deep review on #420. `docs/CLAUDE.md`'s "LLM docs pipeline" section documented `scripts/flatten-llms-tabs.mjs`; this stack swapped in the `strip-generated-markers.mjs` paragraph in its place rather than alongside it. The script is not dead. It is still the FIRST step in docs' build chain (`docusaurus build && node scripts/flatten-llms-tabs.mjs && node scripts/strip-generated-markers.mjs`), still covered by `flatten-llms-tabs.test.mjs`, and does something unrelated to what displaced it — flattening `<PackageManagerTabs>`/`<Tabs>` MDX so the JSX does not land verbatim in `llms.txt`/`llms-full.txt`. Nothing else in the repo documented it, so a reader had no way to learn it exists or why it cannot be a Docusaurus plugin. Both steps are now described in the order the chain runs them. Same mechanism as the `gen-component-catalog.mjs` preamble, the manifest downgrades and the deleted `style-mapping-sync` check: a replacement where an addition was meant, with no conflict to force a second look. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ --------- Co-authored-by: Claude <noreply@anthropic.com>
# Conflicts: # scripts/lib/api-sources.mjs
Preview DeploymentPreview URL: https://89ff8dc2.bestax.pages.dev |
* docs: add the API page generator, its CI gates and review aids
Lands the tooling for generating the derivable parts of docs/docs/api, with no
page generated yet: MANAGED_CATEGORIES and ORDERED_CATEGORIES both start empty
and grow one category per follow-up, so the 87 page diffs stay reviewable
instead of arriving as one 199-file change.
Four regions per page, delimited by `<!-- bestax:generated <id> -->` markers —
`overview` (the component's TSDoc summary), `import` (the public barrel),
`props` (the `<X>Props` interfaces via the TypeScript compiler API) and
`cssvars` (a new section parsed from the SCSS). Everything outside a marker pair
is hand-written and preserved byte-for-byte; deleting a pair opts that region
out, and `docs-section-order` makes that visible rather than silent.
Three choices keep the output reading as hand-written rather than as typedoc:
own members only, with the one catch-all `...` row the pages already wrote by
hand; types from AST source text, never `checker.typeToString`, which expands
`(typeof validColors)[number]` into 19 literals; and wide colour unions rendered
as a link to the existing Valid values page.
CI gates live in check-conformance.mjs, which already runs in CI, rather than a
new workflow step: `docs-generated` recomputes each managed page in memory and
diffs, `docs-section-order` holds the order and marker presence. Both were
verified by tampering.
Also closes two gate gaps this tooling exposed. `pnpm all` ran
`turbo run format:check`, which only runs the per-package scripts — none cover
`scripts/`, `docs/scripts/` or any `.md`; CI runs the root script, which does, so
CI could be red while `pnpm all` was green. And nothing linted `scripts/` at
all. `all` now calls the root format check and `lint` also runs eslint over
`scripts` and `docs/scripts`; verified by planting an unused variable.
Two review aids ship alongside, both one-shot and both used to validate the
migration that follows: `check-docs-parity.mjs` fails on any prop, default,
description word, code span, URL, live example or prose line that a generated
page drops relative to its hand-written self, and `check-docs-wording.mjs`
buckets every previously-documented prop by how its description changed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011c6ipfvBsYgF3Jf91ZzSr7
* docs(bulma-ui): generate the layout, columns and grid API pages
First categories through the generator, plus `helpers/` reordered but not
generated — four of its six pages document hooks with `## API` and no `## Props`
at all, and `config.md`/`theme.md` keep their hand-written tables (theme.md's
Props section is a ~350-line prose sub-API, not a table).
`@property` blocks move onto the interface members as inline TSDoc, so a
description is verifiable by position and reaches users' editors and the shipped
.d.ts. Descriptions were seeded FROM the docs pages, not the other way round:
the hand-written tables are consistently the richer text, and the page stays
authoritative wherever the two disagree.
Component TSDoc summaries were likewise seeded from the pages — the existing ones
("Bulma Hero component root.", "Container component for Bulma.") were worse than
the prose they would have replaced. That text ships in the .d.ts, so read the
`component-catalog.md` diff: it is the canary for this step.
Verified: check-docs-parity reports 0 losses across all 87 pages; the generator
is idempotent.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011c6ipfvBsYgF3Jf91ZzSr7
* docs(bulma-ui): generate the elements API pages
30 pages. Two fixes to the extractor that this category forced, both found by
check-docs-parity rather than by reading pages:
- Heritage through `Omit`/`Pick` and imported (alias) symbols. `LinkButtonProps
extends Omit<ButtonProps, …>` resolved the symbol of `Omit` — a lib type — so
all 14 of its inherited props landed in the catch-all row instead of a table.
- `Table`'s six sub-components are imported rather than declared locally, so the
page rendered no sub-tables at all and the cell components' props vanished.
Props the old tables documented but no interface declares (`href` on Link,
`value` on ListItem, the `<ol>` attributes on OrderedList, `skeleton` from the
helper props) are parked as `@extraProp`, carrying their type and default. That
keeps the page's information in the source, where the rest of it now lives.
`Button`'s component JSDoc was attached to an unrelated `const` rather than to
`Button`, so its summary never reached the page; moved.
Verified: 0 parity losses across all 87 pages; of the 215 previously-documented
props on these pages, 178 read identically and 37 keep their sentence with more
appended — none replaced.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011c6ipfvBsYgF3Jf91ZzSr7
* docs(bulma-ui): generate the components and form API pages
The last 41 pages, completing the migration: all 87 now share one section order
and one table shape.
Four extractor fixes this pair forced, each found by check-docs-parity:
- Props types that are type ALIASES, not interfaces. `ControlProps` and
`SliderProps` are unions, and treating a props type as necessarily an interface
rendered both pages with no table at all — 42 props.
- Defaults destructured in the function body rather than the parameter (`Slider`,
`TimeInputBase`), and defaults belonging to a base module a thin wrapper
renders (`TimeInput` -> `TimeInputBase`). `editable` read as `false` on
timeinput.md where the source says `true`.
- Type cells no longer show a bare alias name: short unions inline, long ones get
a `**Types:**` footnote built from the alias's own TSDoc.
- `**Subcomponents:**` renders each sub's summary sentence, which the pages
carried and a bare name list dropped; a sub with its own page is linked rather
than restated.
Two pages needed a hand edit first: tabs.md and taginput.md had prose sitting
BETWEEN prop tables, where the marker design has nowhere to put it.
Verified across all 87 pages: 0 parity losses, and of 1083 previously-documented
props 953 read identically, 117 keep their sentence with more appended, 12 have
it intact inside a longer one, 1 changed (a comma).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011c6ipfvBsYgF3Jf91ZzSr7
* chore: restore the component-catalog preamble this stack reverted
`scripts/gen-component-catalog.mjs` carried a copy of the catalog preamble
predating #365, so regenerating deleted 21 lines of shipped guidance: the
per-component value-union warning, where to find the installed `.d.ts`, the
`Skeleton` helper-prop exception, which sub-component families accept helper
props, and the custom-component composition spine.
The checked-in `component-catalog.md` still had #365's text, so
`gen:catalog:check` regenerated it shorter and failed `git diff --exit-code` —
this is why Build and Test is red on this PR.
Restores the generator to main's version. The catalog now regenerates
byte-identical to the committed file.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
* chore: restore the component-catalog preamble this stack reverted
`scripts/gen-component-catalog.mjs` carried a copy of the catalog preamble
predating #365, so regenerating deleted 21 lines of shipped guidance: the
per-component value-union warning, where to find the installed `.d.ts`, the
`Skeleton` helper-prop exception, which sub-component families accept helper
props, and the custom-component composition spine.
This branch regenerated the catalog with that stale generator, committing the
loss into a shipped skill artifact. Restores the generator to main's version
and regenerates; the preamble matches main again and the component one-liners
are unaffected.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
* chore: restore the component-catalog preamble this stack reverted
`scripts/gen-component-catalog.mjs` carried a copy of the catalog preamble
predating #365, so regenerating deleted 21 lines of shipped guidance: the
per-component value-union warning, where to find the installed `.d.ts`, the
`Skeleton` helper-prop exception, which sub-component families accept helper
props, and the custom-component composition spine.
This branch regenerated the catalog with that stale generator, committing the
loss into a shipped skill artifact. Restores the generator to main's version
and regenerates; the preamble matches main again and the component one-liners
are unaffected.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
* chore: restore the component-catalog preamble this stack reverted
`scripts/gen-component-catalog.mjs` carried a copy of the catalog preamble
predating #365, so regenerating deleted 21 lines of shipped guidance: the
per-component value-union warning, where to find the installed `.d.ts`, the
`Skeleton` helper-prop exception, which sub-component families accept helper
props, and the custom-component composition spine.
This branch regenerated the catalog with that stale generator, committing the
loss into a shipped skill artifact. Restores the generator to main's version
and regenerates; the preamble matches main again and the component one-liners
are unaffected.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
* fix(docs): correct four prop-table defects in the API page extractor
Found by comparing every generated page against its origin/main original in a
browser, and against the interfaces the tables claim to describe.
- Bare alias names where the hand-written tables had real types. A one-member
"union" (`type CellSpanValue = number`) was never a union node, and a union
naming another alias (`BulmaFixedGridColsProp = BulmaFixedGridCols |
'auto'`) failed the all-members-simple test. Both fell through to the bare
name with no `**Types:**` footnote, so cell.md's `colSpan`/`rowSpan` said
`CellSpanValue` where main said `number`, and grid.md's `fixedCols` was
opaque beside five siblings expanded to `0 | … | 12` in the same table.
Member aliases now resolve to a fixpoint.
- `children` synthesized for components that never render it. The row was
emitted for any interface with a DOM base, but inheriting `children` is not
rendering it: Divider spreads onto `<hr>`, so the row documented the one
thing React throws on ("hr is a void element tag and must neither have
`children`…"), and Icon always supplies its own JSX children, so anything
passed is silently dropped. Emitted only where the implementation names
`children`; the catch-all row still covers pass-through cases.
- Sub-components dropped when their props are an inline DOM type rather than a
named `*Props` interface. `Navbar.Divider` and `Pagination.Ellipsis` were
omitted from the generated Subcomponents lists entirely — which is why both
pages still carried a hand-written duplicate list. They are now listed (with
no table, since they add no props of their own).
- `never` and `false | true` merged from the branches of a discriminated
union. slider.md rendered `minDistance` as `never | number` and `range` as
`false | true`; the forbidding branch's `never` is noise standing where the
reader needs a type.
Verified: generator idempotent, all ten conformance checks green,
check-docs-parity still reports 0 prop/default/description losses across all
87 pages.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
* fix(docs): drop the stale duplicate tables the elements pages kept
`table.md` and `figure.md` still carried their pre-migration sub-component
tables immediately after the generated block, so every sub-component was
documented twice with disagreeing values — `isSelected` defaulted to `false`
in the generated table and `—` in the legacy copy, and figure's stale
`Figure.Caption Props` still dumped the 19-member colour union inline that
this migration exists to remove. The generated tables supersede both.
`delete.md`, `divider.md` and `icon.md` lose a synthesized `children` row for
props those components do not render — `<hr>` throws on children and `Icon`
overrides them.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
* fix(docs): regenerate the grid pages with the corrected type cells
Picks up the extractor fix from the base branch. `cell.md`'s `colSpan` and
`rowSpan` go back to `number` — they had regressed to a bare `CellSpanValue`,
which aliases exactly `number` and so told the reader strictly less. `grid.md`'s
`fixedCols` expands to `0 | … | 12 | 'auto'` instead of a bare
`BulmaFixedGridColsProp`; it was the only opaque cell in a table whose five
sibling props were already fully expanded.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
* fix(bulma-ui): stop three props tables documenting props the components reject
Found by comparing each generated page against its origin/main original in a
browser and against the interface it claims to describe.
`@extraProp` tags placed on the wrong interface published props that do not
exist. `RateProps` carried `index`, `isActive` and `isHovered` — fields of
`RateIconProps`, the object handed to `customIcon`, which `Rate` never
destructures; `CarouselProps` carried `active`, which belongs to
`CarouselItemProps`. Passing either lands an unknown attribute on the root
element and React warns. Both sets are already documented correctly in their
own sub-tables.
`DateTimeInput`'s three `@extraProp` tags omitted the `{type}` braces, so
`name`, `form` and `required` rendered with an empty Type cell and `required`
lost its default — the `DateInput` and `TimeInput` siblings had them.
Also restores prose the pages carried and the source TSDoc had lost, so the
generated Subcomponents bullets keep it: the `Panel.Icon` "accepts all Icon
props" note, `Navbar.Divider` and `Pagination.Ellipsis`'s descriptions, and
the five `Sidebar.*` summaries. Per this stack's own rule, where the page and
the comment disagree the page is authoritative.
Section order restored to Accessibility → Related on `collapse`, `loading`,
`tooltip` and `switch`, which had it inverted against the other 83 pages, and
the stale duplicate blocks removed from `navbar`, `panel`, `pagination` and
`sidebar` — `sidebar` was emitting duplicate heading anchors, which broke its
table of contents and deep links.
Verified: generator idempotent, ten of ten conformance checks green, docs
build clean, bulma-ui typecheck/lint/tests pass.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
* fix(docs): add missing DOM_ELEMENT_LABELS entries and stop mislinking Helper Props
Three elements (Divider/hr, Pre, Progress) fell back to the generic "HTML"
label because DOM_ELEMENT_LABELS had no entry for their concrete interfaces.
Separately, skeleton.md's catch-all row linked to Helper Props even though
SkeletonProps doesn't extend BulmaClassesProps and Skeleton never calls
useBulmaClasses — catchAllRow() now reports whether BulmaClassesProps is
actually in the heritage, and the generator only renders the link when it is.
Co-authored-by: Alex Smith <allxsmith@users.noreply.github.com>
* fix(docs): carry the catch-all fix through the rest of the stack
`scripts/lib/props-extract.mjs` and `scripts/gen-api-docs.mjs` are shared by
every branch here, so landing the `DOM_ELEMENT_LABELS` additions and the
`catchAll -> {text, helpers}` change on #422 alone left #420 and #421 without
them and made #423 — which is stacked above #422 — revert them. Same file,
same content, applied across the stack so the tip is consistent.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
* fix(docs): carry the catch-all fix through the rest of the stack
`scripts/lib/props-extract.mjs` and `scripts/gen-api-docs.mjs` are shared by
every branch here, so landing the `DOM_ELEMENT_LABELS` additions and the
`catchAll -> {text, helpers}` change on #422 alone left #420 and #421 without
them and made #423 — which is stacked above #422 — revert them. Same file,
same content, applied across the stack so the tip is consistent.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
* fix(docs): carry the catch-all fix through the rest of the stack
`scripts/lib/props-extract.mjs` and `scripts/gen-api-docs.mjs` are shared by
every branch here, so landing the `DOM_ELEMENT_LABELS` additions and the
`catchAll -> {text, helpers}` change on #422 alone left #420 and #421 without
them and made #423 — which is stacked above #422 — revert them. Same file,
same content, applied across the stack so the tip is consistent.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
* fix(docs): expand DateFormatOption instead of leaving a bare alias
The three datetime pages had regressed from main's
`string | Intl.DateTimeFormatOptions` to a bare `DateFormatOption`, which is
declared in `form/_pickerInternals/` and is not exported from the barrel — so a
reader could neither import it nor look it up, and no `**Types:**` footnote
covered it either.
A union member naming a type the alias index cannot resolve
(`Intl.DateTimeFormatOptions` is a qualified name, not an indexed identifier)
now falls back to its own source text. Blast radius is exactly the three
`format` cells; no other page changes.
Found by an exhaustive cell-by-cell diff of all 87 generated pages against
their origin/main originals, which also settles the rest: one genuine prop row
lost across the whole migration (`card.md`'s `m`/`p`), and every remaining type
or default difference is either an improvement over drifted prose or a bare
alias that does carry a footnote.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
* fix(docs): expand DateFormatOption instead of leaving a bare alias
The three datetime pages had regressed from main's
`string | Intl.DateTimeFormatOptions` to a bare `DateFormatOption`, which is
declared in `form/_pickerInternals/` and is not exported from the barrel — so a
reader could neither import it nor look it up, and no `**Types:**` footnote
covered it either.
A union member naming a type the alias index cannot resolve
(`Intl.DateTimeFormatOptions` is a qualified name, not an indexed identifier)
now falls back to its own source text. Blast radius is exactly the three
`format` cells; no other page changes.
Found by an exhaustive cell-by-cell diff of all 87 generated pages against
their origin/main originals, which also settles the rest: one genuine prop row
lost across the whole migration (`card.md`'s `m`/`p`), and every remaining type
or default difference is either an improvement over drifted prose or a bare
alias that does carry a footnote.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
* fix(docs): expand DateFormatOption instead of leaving a bare alias
The three datetime pages had regressed from main's
`string | Intl.DateTimeFormatOptions` to a bare `DateFormatOption`, which is
declared in `form/_pickerInternals/` and is not exported from the barrel — so a
reader could neither import it nor look it up, and no `**Types:**` footnote
covered it either.
A union member naming a type the alias index cannot resolve
(`Intl.DateTimeFormatOptions` is a qualified name, not an indexed identifier)
now falls back to its own source text. Blast radius is exactly the three
`format` cells; no other page changes.
Found by an exhaustive cell-by-cell diff of all 87 generated pages against
their origin/main originals, which also settles the rest: one genuine prop row
lost across the whole migration (`card.md`'s `m`/`p`), and every remaining type
or default difference is either an improvement over drifted prose or a bare
alias that does carry a footnote.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
* fix(docs): expand DateFormatOption instead of leaving a bare alias
The three datetime pages had regressed from main's
`string | Intl.DateTimeFormatOptions` to a bare `DateFormatOption`, which is
declared in `form/_pickerInternals/` and is not exported from the barrel — so a
reader could neither import it nor look it up, and no `**Types:**` footnote
covered it either.
A union member naming a type the alias index cannot resolve
(`Intl.DateTimeFormatOptions` is a qualified name, not an indexed identifier)
now falls back to its own source text. Blast radius is exactly the three
`format` cells; no other page changes.
Found by an exhaustive cell-by-cell diff of all 87 generated pages against
their origin/main originals, which also settles the rest: one genuine prop row
lost across the whole migration (`card.md`'s `m`/`p`), and every remaining type
or default difference is either an improvement over drifted prose or a bare
alias that does carry a footnote.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
* fix(docs): rebase the manifests onto main and address the review findings
**Manifests.** These branches were cut before 19 commits landed on main and
were never refreshed, so relative to their OWN merge base they downgraded
`@commitlint/cli` 21.2.1→21.0.2, `@commitlint/config-conventional` 21.2.0→21.0.2,
`@semantic-release/github` 12.0.9→12.0.2, `semantic-release` 25.0.8→25.0.2,
`prettier` 3.9.6→3.9.4, `react`/`react-dom` 19.2.8→19.2.3, `@docusaurus/*`
3.10.2→3.9.2 and `@fortawesome/fontawesome-free` 7.3.1→7.2.0 — and dropped
docs' `"test": "node --test \"scripts/*.test.mjs\""`, silently disabling the
`flatten-llms-tabs` tests #408 added. Because the branches modify those lines
rather than merely trailing main, a merge would have carried the downgrades in.
`package.json`, `docs/package.json` and `pnpm-lock.yaml` are now main's, with
only this stack's own script additions re-applied on top: `gen:api-sources`,
`gen:api-docs`, `gen:api-docs:check`, `gen`, the `lint` widening over `scripts`
and `docs/scripts`, the root `format:check` fix in `all`, and the
marker-stripping step chained after the llms flattener. The stack adds no
dependency of its own, so main's lockfile is exactly right.
**Review findings.** From the CodeRabbit and Claude deep reviews on #421/#422:
- The alias fixpoint resolved the mixed unions and the `indirect` renames in
two separate passes, so a mixed union naming a forward-only alias — or a
rename pointing at a mixed alias — stayed opaque forever. Both reviewers
flagged it independently. The two now interleave in one bounded fixpoint.
- `rendersChildren` matched `/\bchildren\b/` against raw source text, which
counts the word in a comment or an unrelated string. It is an AST walk now.
- Six `gapSize*` props on `Columns.tsx` carried TWO JSDoc blocks — the
migration stacked the new one on top of the old instead of replacing it, so
dead comments shipped in the `.d.ts`. Collapsed, keeping the tie-break
clause the first block had and the page had lost.
- A small local interface named in a type cell now renders its object shape:
`icontext.md`'s `items` goes back to main's `{ iconProps: IconProps; text?:
string }[]` from a bare `IconTextItem`, and `slider.md`'s `marks` improves on
both to `{ value: number; label?: React.ReactNode }[]`. Neither interface is
exported from the barrel, so the bare name was unlookupable.
- Two pre-existing `helpers/` defects, relocated by this stack's reorder and
worth fixing while the pages are open: a stray four-backtick fence in
`theme.md` trapped the "Theme with Styling" heading and its example inside a
code block, and `usebulmaclasses.md` claimed a `className` the example never
passes and `has-text-info-mobile` for `color: 'link'`.
Both refactors are behaviour-preserving: the generator emits byte-identical
output for them today. Verified: generator idempotent, ten of ten conformance
checks green, `gen:catalog:check` exits 0, docs build clean, bulma-ui
typecheck/lint/tests pass, and the 87-page cell-by-cell diff against main is
unchanged at one lost prop row.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
* fix(docs): rebase the manifests onto main and address the review findings
**Manifests.** These branches were cut before 19 commits landed on main and
were never refreshed, so relative to their OWN merge base they downgraded
`@commitlint/cli` 21.2.1→21.0.2, `@commitlint/config-conventional` 21.2.0→21.0.2,
`@semantic-release/github` 12.0.9→12.0.2, `semantic-release` 25.0.8→25.0.2,
`prettier` 3.9.6→3.9.4, `react`/`react-dom` 19.2.8→19.2.3, `@docusaurus/*`
3.10.2→3.9.2 and `@fortawesome/fontawesome-free` 7.3.1→7.2.0 — and dropped
docs' `"test": "node --test \"scripts/*.test.mjs\""`, silently disabling the
`flatten-llms-tabs` tests #408 added. Because the branches modify those lines
rather than merely trailing main, a merge would have carried the downgrades in.
`package.json`, `docs/package.json` and `pnpm-lock.yaml` are now main's, with
only this stack's own script additions re-applied on top: `gen:api-sources`,
`gen:api-docs`, `gen:api-docs:check`, `gen`, the `lint` widening over `scripts`
and `docs/scripts`, the root `format:check` fix in `all`, and the
marker-stripping step chained after the llms flattener. The stack adds no
dependency of its own, so main's lockfile is exactly right.
**Review findings.** From the CodeRabbit and Claude deep reviews on #421/#422:
- The alias fixpoint resolved the mixed unions and the `indirect` renames in
two separate passes, so a mixed union naming a forward-only alias — or a
rename pointing at a mixed alias — stayed opaque forever. Both reviewers
flagged it independently. The two now interleave in one bounded fixpoint.
- `rendersChildren` matched `/\bchildren\b/` against raw source text, which
counts the word in a comment or an unrelated string. It is an AST walk now.
- Six `gapSize*` props on `Columns.tsx` carried TWO JSDoc blocks — the
migration stacked the new one on top of the old instead of replacing it, so
dead comments shipped in the `.d.ts`. Collapsed, keeping the tie-break
clause the first block had and the page had lost.
- A small local interface named in a type cell now renders its object shape:
`icontext.md`'s `items` goes back to main's `{ iconProps: IconProps; text?:
string }[]` from a bare `IconTextItem`, and `slider.md`'s `marks` improves on
both to `{ value: number; label?: React.ReactNode }[]`. Neither interface is
exported from the barrel, so the bare name was unlookupable.
- Two pre-existing `helpers/` defects, relocated by this stack's reorder and
worth fixing while the pages are open: a stray four-backtick fence in
`theme.md` trapped the "Theme with Styling" heading and its example inside a
code block, and `usebulmaclasses.md` claimed a `className` the example never
passes and `has-text-info-mobile` for `color: 'link'`.
Both refactors are behaviour-preserving: the generator emits byte-identical
output for them today. Verified: generator idempotent, ten of ten conformance
checks green, `gen:catalog:check` exits 0, docs build clean, bulma-ui
typecheck/lint/tests pass, and the 87-page cell-by-cell diff against main is
unchanged at one lost prop row.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
* fix(docs): rebase the manifests onto main and address the review findings
**Manifests.** These branches were cut before 19 commits landed on main and
were never refreshed, so relative to their OWN merge base they downgraded
`@commitlint/cli` 21.2.1→21.0.2, `@commitlint/config-conventional` 21.2.0→21.0.2,
`@semantic-release/github` 12.0.9→12.0.2, `semantic-release` 25.0.8→25.0.2,
`prettier` 3.9.6→3.9.4, `react`/`react-dom` 19.2.8→19.2.3, `@docusaurus/*`
3.10.2→3.9.2 and `@fortawesome/fontawesome-free` 7.3.1→7.2.0 — and dropped
docs' `"test": "node --test \"scripts/*.test.mjs\""`, silently disabling the
`flatten-llms-tabs` tests #408 added. Because the branches modify those lines
rather than merely trailing main, a merge would have carried the downgrades in.
`package.json`, `docs/package.json` and `pnpm-lock.yaml` are now main's, with
only this stack's own script additions re-applied on top: `gen:api-sources`,
`gen:api-docs`, `gen:api-docs:check`, `gen`, the `lint` widening over `scripts`
and `docs/scripts`, the root `format:check` fix in `all`, and the
marker-stripping step chained after the llms flattener. The stack adds no
dependency of its own, so main's lockfile is exactly right.
**Review findings.** From the CodeRabbit and Claude deep reviews on #421/#422:
- The alias fixpoint resolved the mixed unions and the `indirect` renames in
two separate passes, so a mixed union naming a forward-only alias — or a
rename pointing at a mixed alias — stayed opaque forever. Both reviewers
flagged it independently. The two now interleave in one bounded fixpoint.
- `rendersChildren` matched `/\bchildren\b/` against raw source text, which
counts the word in a comment or an unrelated string. It is an AST walk now.
- Six `gapSize*` props on `Columns.tsx` carried TWO JSDoc blocks — the
migration stacked the new one on top of the old instead of replacing it, so
dead comments shipped in the `.d.ts`. Collapsed, keeping the tie-break
clause the first block had and the page had lost.
- A small local interface named in a type cell now renders its object shape:
`icontext.md`'s `items` goes back to main's `{ iconProps: IconProps; text?:
string }[]` from a bare `IconTextItem`, and `slider.md`'s `marks` improves on
both to `{ value: number; label?: React.ReactNode }[]`. Neither interface is
exported from the barrel, so the bare name was unlookupable.
- Two pre-existing `helpers/` defects, relocated by this stack's reorder and
worth fixing while the pages are open: a stray four-backtick fence in
`theme.md` trapped the "Theme with Styling" heading and its example inside a
code block, and `usebulmaclasses.md` claimed a `className` the example never
passes and `has-text-info-mobile` for `color: 'link'`.
Both refactors are behaviour-preserving: the generator emits byte-identical
output for them today. Verified: generator idempotent, ten of ten conformance
checks green, `gen:catalog:check` exits 0, docs build clean, bulma-ui
typecheck/lint/tests pass, and the 87-page cell-by-cell diff against main is
unchanged at one lost prop row.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
* fix(docs): rebase the manifests onto main and address the review findings
**Manifests.** These branches were cut before 19 commits landed on main and
were never refreshed, so relative to their OWN merge base they downgraded
`@commitlint/cli` 21.2.1→21.0.2, `@commitlint/config-conventional` 21.2.0→21.0.2,
`@semantic-release/github` 12.0.9→12.0.2, `semantic-release` 25.0.8→25.0.2,
`prettier` 3.9.6→3.9.4, `react`/`react-dom` 19.2.8→19.2.3, `@docusaurus/*`
3.10.2→3.9.2 and `@fortawesome/fontawesome-free` 7.3.1→7.2.0 — and dropped
docs' `"test": "node --test \"scripts/*.test.mjs\""`, silently disabling the
`flatten-llms-tabs` tests #408 added. Because the branches modify those lines
rather than merely trailing main, a merge would have carried the downgrades in.
`package.json`, `docs/package.json` and `pnpm-lock.yaml` are now main's, with
only this stack's own script additions re-applied on top: `gen:api-sources`,
`gen:api-docs`, `gen:api-docs:check`, `gen`, the `lint` widening over `scripts`
and `docs/scripts`, the root `format:check` fix in `all`, and the
marker-stripping step chained after the llms flattener. The stack adds no
dependency of its own, so main's lockfile is exactly right.
**Review findings.** From the CodeRabbit and Claude deep reviews on #421/#422:
- The alias fixpoint resolved the mixed unions and the `indirect` renames in
two separate passes, so a mixed union naming a forward-only alias — or a
rename pointing at a mixed alias — stayed opaque forever. Both reviewers
flagged it independently. The two now interleave in one bounded fixpoint.
- `rendersChildren` matched `/\bchildren\b/` against raw source text, which
counts the word in a comment or an unrelated string. It is an AST walk now.
- Six `gapSize*` props on `Columns.tsx` carried TWO JSDoc blocks — the
migration stacked the new one on top of the old instead of replacing it, so
dead comments shipped in the `.d.ts`. Collapsed, keeping the tie-break
clause the first block had and the page had lost.
- A small local interface named in a type cell now renders its object shape:
`icontext.md`'s `items` goes back to main's `{ iconProps: IconProps; text?:
string }[]` from a bare `IconTextItem`, and `slider.md`'s `marks` improves on
both to `{ value: number; label?: React.ReactNode }[]`. Neither interface is
exported from the barrel, so the bare name was unlookupable.
- Two pre-existing `helpers/` defects, relocated by this stack's reorder and
worth fixing while the pages are open: a stray four-backtick fence in
`theme.md` trapped the "Theme with Styling" heading and its example inside a
code block, and `usebulmaclasses.md` claimed a `className` the example never
passes and `has-text-info-mobile` for `color: 'link'`.
Both refactors are behaviour-preserving: the generator emits byte-identical
output for them today. Verified: generator idempotent, ten of ten conformance
checks green, `gen:catalog:check` exits 0, docs build clean, bulma-ui
typecheck/lint/tests pass, and the 87-page cell-by-cell diff against main is
unchanged at one lost prop row.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
* fix(docs): restore bestax-migrate's manifest and the lockfile from main
Rebasing the root and docs manifests left `bestax-migrate/package.json` behind,
and regenerating the lockfile against it reintroduced a stale entry: the branch
still lists `@allxsmith/bestax-bulma` under `dependencies`, where #412/#417
moved it to `devDependencies`, and is missing the `prepack`/`postpack`
pack-manifest hooks those PRs added.
The branch never modified that file — it only trails main — so taking main's
copy is a clean fast-forward. `pnpm-lock.yaml` is now byte-identical to main's
and `pnpm install --frozen-lockfile` succeeds against it, which is the check CI
runs.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
* fix(docs): restore bestax-migrate's manifest and the lockfile from main
Rebasing the root and docs manifests left `bestax-migrate/package.json` behind,
and regenerating the lockfile against it reintroduced a stale entry: the branch
still lists `@allxsmith/bestax-bulma` under `dependencies`, where #412/#417
moved it to `devDependencies`, and is missing the `prepack`/`postpack`
pack-manifest hooks those PRs added.
The branch never modified that file — it only trails main — so taking main's
copy is a clean fast-forward. `pnpm-lock.yaml` is now byte-identical to main's
and `pnpm install --frozen-lockfile` succeeds against it, which is the check CI
runs.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
* fix(docs): restore bestax-migrate's manifest and the lockfile from main
Rebasing the root and docs manifests left `bestax-migrate/package.json` behind,
and regenerating the lockfile against it reintroduced a stale entry: the branch
still lists `@allxsmith/bestax-bulma` under `dependencies`, where #412/#417
moved it to `devDependencies`, and is missing the `prepack`/`postpack`
pack-manifest hooks those PRs added.
The branch never modified that file — it only trails main — so taking main's
copy is a clean fast-forward. `pnpm-lock.yaml` is now byte-identical to main's
and `pnpm install --frozen-lockfile` succeeds against it, which is the check CI
runs.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
* fix(docs): restore bestax-migrate's manifest and the lockfile from main
Rebasing the root and docs manifests left `bestax-migrate/package.json` behind,
and regenerating the lockfile against it reintroduced a stale entry: the branch
still lists `@allxsmith/bestax-bulma` under `dependencies`, where #412/#417
moved it to `devDependencies`, and is missing the `prepack`/`postpack`
pack-manifest hooks those PRs added.
The branch never modified that file — it only trails main — so taking main's
copy is a clean fast-forward. `pnpm-lock.yaml` is now byte-identical to main's
and `pnpm install --frozen-lockfile` succeeds against it, which is the check CI
runs.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
* fix(docs): fail the alias fixpoint instead of degrading to bare names
The deep review on #421 flagged that the alias-resolution fixpoint degrades
silently: if a chain needs more than the round bound, the survivors fall back
to a bare name plus a `**Types:**` footnote rather than the expansion, and
nothing says so.
Running out of rounds is a different condition from settling. An alias that
genuinely cannot expand stops making progress and the loop exits clean — that
path is unchanged. But if the bound cuts the loop off while it is still
resolving, the survivors render as bare identifiers, which is the exact
regression this generator exists to prevent. That case now throws, naming the
unresolved aliases.
The bound is a named constant (`ALIAS_FIXPOINT_ROUNDS`) so the error can point
at it. Chains in this repo settle in two rounds; the bound only exists to stop
a mutually-recursive pair spinning.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
* fix(docs): make the marker stripper fail instead of no-opping silently
The deep review asked whether this step fails loudly when it matches nothing.
It did not — it logged "removed 0 marker(s) from 0 file(s)" and exited 0.
That is the one failure this step exists to prevent. Its own header records
why it is a build step and not a plugin: the first attempt was a `postBuild`
hook, `postBuild` runs under `Promise.all`, it raced ahead of
docusaurus-plugin-llms and silently found nothing to strip. A quiet no-op here
ships ~600 markers into llms-full.txt and every per-page `.md` twin with a
green build.
Stripping nothing is only correct when there was nothing to strip, so the
check compares against the SOURCE pages: zero stripped AND zero markers in
docs/docs/api is the legitimate "no managed categories yet" state (which is
this branch, with MANAGED_CATEGORIES empty). Zero stripped while the source
carries markers means the built markdown moved, the marker format changed, or
the ordering regressed — that now exits 1 and says which.
Also answers the other half of the question: the glob only ever reaches `.md`
files plus llms.txt / llms-full.txt, so it cannot touch built HTML.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
* fix(docs): correct three defects the #420 deep review found
**The helper-props shortcut swallowed the DOM base.** `classifyTypeNode` tested
`/BulmaClassesProps/` against the whole node's source text, so it fired for
`Omit<React.HTMLAttributes<HTMLElement>, keyof BulmaClassesProps>` — where the
name appears as the omit KEY LIST, not as the base being omitted. It returned
before the `Omit` branch below could unwrap `React.HTMLAttributes<HTMLElement>`,
so `HTMLElement` never reached `catchAllRow` and the catch-all lost its "All
standard HTML attributes" half. That is the mechanism behind the menu.md (4
tables) and dropdown.md (2) regression against main. Matched structurally now:
the node itself must name `BulmaClassesProps`, or be an `Omit`/`Pick` whose
first type argument does.
**`impliedFalse` applied to controlled-mode booleans.** An optional `boolean`
with no destructured default is documented as `false`, which is right for a
flag and wrong for a controlled prop, where `undefined` is what selects
UNCONTROLLED mode. `collapse.md` claimed `open` defaults to `false` while its
own description says "If provided, component is controlled" — two statements
that cannot both hold. A prop whose description says it controls the component
now keeps an empty Default.
**`pnpm all` never ran the widened lint.** `all` invoked `turbo run … lint`
directly; `turbo.json` declares no `//#lint` root task and only bulma-ui,
create-bestax and bestax-migrate define one (each scoped to its own `src`), so
`eslint scripts docs/scripts` — which exists only in the ROOT `lint` script —
was skipped. That is the same "pnpm all green, CI red" gap this stack fixed for
`format:check`, left in place for `lint`; CI caught it only because `ci.yml`
runs `pnpm run lint` as its own step. Routed through `pnpm run lint`, and
verified by planting an unused variable in `scripts/`.
Verified: generator idempotent, ten of ten conformance checks green,
`gen:catalog:check` exits 0, and the 87-page cell-by-cell diff against main is
unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
* fix(docs): correct three defects the #420 deep review found
**The helper-props shortcut swallowed the DOM base.** `classifyTypeNode` tested
`/BulmaClassesProps/` against the whole node's source text, so it fired for
`Omit<React.HTMLAttributes<HTMLElement>, keyof BulmaClassesProps>` — where the
name appears as the omit KEY LIST, not as the base being omitted. It returned
before the `Omit` branch below could unwrap `React.HTMLAttributes<HTMLElement>`,
so `HTMLElement` never reached `catchAllRow` and the catch-all lost its "All
standard HTML attributes" half. That is the mechanism behind the menu.md (4
tables) and dropdown.md (2) regression against main. Matched structurally now:
the node itself must name `BulmaClassesProps`, or be an `Omit`/`Pick` whose
first type argument does.
**`impliedFalse` applied to controlled-mode booleans.** An optional `boolean`
with no destructured default is documented as `false`, which is right for a
flag and wrong for a controlled prop, where `undefined` is what selects
UNCONTROLLED mode. `collapse.md` claimed `open` defaults to `false` while its
own description says "If provided, component is controlled" — two statements
that cannot both hold. A prop whose description says it controls the component
now keeps an empty Default.
**`pnpm all` never ran the widened lint.** `all` invoked `turbo run … lint`
directly; `turbo.json` declares no `//#lint` root task and only bulma-ui,
create-bestax and bestax-migrate define one (each scoped to its own `src`), so
`eslint scripts docs/scripts` — which exists only in the ROOT `lint` script —
was skipped. That is the same "pnpm all green, CI red" gap this stack fixed for
`format:check`, left in place for `lint`; CI caught it only because `ci.yml`
runs `pnpm run lint` as its own step. Routed through `pnpm run lint`, and
verified by planting an unused variable in `scripts/`.
Verified: generator idempotent, ten of ten conformance checks green,
`gen:catalog:check` exits 0, and the 87-page cell-by-cell diff against main is
unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
* fix(docs): correct three defects the #420 deep review found
**The helper-props shortcut swallowed the DOM base.** `classifyTypeNode` tested
`/BulmaClassesProps/` against the whole node's source text, so it fired for
`Omit<React.HTMLAttributes<HTMLElement>, keyof BulmaClassesProps>` — where the
name appears as the omit KEY LIST, not as the base being omitted. It returned
before the `Omit` branch below could unwrap `React.HTMLAttributes<HTMLElement>`,
so `HTMLElement` never reached `catchAllRow` and the catch-all lost its "All
standard HTML attributes" half. That is the mechanism behind the menu.md (4
tables) and dropdown.md (2) regression against main. Matched structurally now:
the node itself must name `BulmaClassesProps`, or be an `Omit`/`Pick` whose
first type argument does.
**`impliedFalse` applied to controlled-mode booleans.** An optional `boolean`
with no destructured default is documented as `false`, which is right for a
flag and wrong for a controlled prop, where `undefined` is what selects
UNCONTROLLED mode. `collapse.md` claimed `open` defaults to `false` while its
own description says "If provided, component is controlled" — two statements
that cannot both hold. A prop whose description says it controls the component
now keeps an empty Default.
**`pnpm all` never ran the widened lint.** `all` invoked `turbo run … lint`
directly; `turbo.json` declares no `//#lint` root task and only bulma-ui,
create-bestax and bestax-migrate define one (each scoped to its own `src`), so
`eslint scripts docs/scripts` — which exists only in the ROOT `lint` script —
was skipped. That is the same "pnpm all green, CI red" gap this stack fixed for
`format:check`, left in place for `lint`; CI caught it only because `ci.yml`
runs `pnpm run lint` as its own step. Routed through `pnpm run lint`, and
verified by planting an unused variable in `scripts/`.
Verified: generator idempotent, ten of ten conformance checks green,
`gen:catalog:check` exits 0, and the 87-page cell-by-cell diff against main is
unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
* fix(docs): correct three defects the #420 deep review found
**The helper-props shortcut swallowed the DOM base.** `classifyTypeNode` tested
`/BulmaClassesProps/` against the whole node's source text, so it fired for
`Omit<React.HTMLAttributes<HTMLElement>, keyof BulmaClassesProps>` — where the
name appears as the omit KEY LIST, not as the base being omitted. It returned
before the `Omit` branch below could unwrap `React.HTMLAttributes<HTMLElement>`,
so `HTMLElement` never reached `catchAllRow` and the catch-all lost its "All
standard HTML attributes" half. That is the mechanism behind the menu.md (4
tables) and dropdown.md (2) regression against main. Matched structurally now:
the node itself must name `BulmaClassesProps`, or be an `Omit`/`Pick` whose
first type argument does.
**`impliedFalse` applied to controlled-mode booleans.** An optional `boolean`
with no destructured default is documented as `false`, which is right for a
flag and wrong for a controlled prop, where `undefined` is what selects
UNCONTROLLED mode. `collapse.md` claimed `open` defaults to `false` while its
own description says "If provided, component is controlled" — two statements
that cannot both hold. A prop whose description says it controls the component
now keeps an empty Default.
**`pnpm all` never ran the widened lint.** `all` invoked `turbo run … lint`
directly; `turbo.json` declares no `//#lint` root task and only bulma-ui,
create-bestax and bestax-migrate define one (each scoped to its own `src`), so
`eslint scripts docs/scripts` — which exists only in the ROOT `lint` script —
was skipped. That is the same "pnpm all green, CI red" gap this stack fixed for
`format:check`, left in place for `lint`; CI caught it only because `ci.yml`
runs `pnpm run lint` as its own step. Routed through `pnpm run lint`, and
verified by planting an unused variable in `scripts/`.
Verified: generator idempotent, ten of ten conformance checks green,
`gen:catalog:check` exits 0, and the 87-page cell-by-cell diff against main is
unchanged.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
* fix(bulma-ui): correct the inverted Level.isMobile description
Bulma's `.level.is-mobile` sets `display: flex; flex-direction: row`
(`bulma/sass/layout/level.scss:27-30`) — it keeps the level HORIZONTAL on
mobile. A level without it stacks vertically below tablet. The description said
the opposite: "Enables mobile layout (stacks vertically on mobile)", and the
Usage prose repeated it.
The wording is pre-existing on main, in both the props table and the prose, so
this stack did not introduce it. It matters here because the migration seeds
TSDoc from the doc pages, which launders a page-level error into the shipped
`.d.ts` and users' editor tooltips — a wider blast radius than the page alone.
Corrected at the source, so the generated row follows, and in the hand-written
Usage paragraph.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
* fix(docs): close the theme.md fence my earlier edit left open
CI caught this and it is my regression, not a pre-existing one: main's
`theme.md` passes `prettier --check` at its real path.
Removing the stray four-backtick fence pair around "Theme with Styling" took
out a fence that was load-bearing. The outer ```` closed the inner ```tsx
block (a longer fence closes a shorter one), so deleting the pair left the
StyledTheme example unterminated — it swallowed the "### Nested Themes"
heading and the block after it, and `prettier --check` failed on the file.
Closing the ```tsx block explicitly gives the structure the section was always
meant to have: the heading renders as a heading and each example is its own
closed block. `pnpm run format:check` is green across the repo.
Worth recording how this got through: I ran typecheck, lint, tests and the docs
build locally but not the ROOT `format:check` — which is exactly the "pnpm all
green, CI red" gap this stack exists to close, and the gap only closed for
`lint` two commits ago. The root format check is in my gate from here.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
* docs: restore the flatten-llms-tabs description this stack replaced
Fourth instance of the same silent-deletion pattern, found by the deep review
on #420. `docs/CLAUDE.md`'s "LLM docs pipeline" section documented
`scripts/flatten-llms-tabs.mjs`; this stack swapped in the
`strip-generated-markers.mjs` paragraph in its place rather than alongside it.
The script is not dead. It is still the FIRST step in docs' build chain
(`docusaurus build && node scripts/flatten-llms-tabs.mjs && node
scripts/strip-generated-markers.mjs`), still covered by
`flatten-llms-tabs.test.mjs`, and does something unrelated to what displaced
it — flattening `<PackageManagerTabs>`/`<Tabs>` MDX so the JSX does not land
verbatim in `llms.txt`/`llms-full.txt`. Nothing else in the repo documented it,
so a reader had no way to learn it exists or why it cannot be a Docusaurus
plugin.
Both steps are now described in the order the chain runs them.
Same mechanism as the `gen-component-catalog.mjs` preamble, the manifest
downgrades and the deleted `style-mapping-sync` check: a replacement where an
addition was meant, with no conflict to force a second look.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
* chore: remove the one-shot migration scripts now the migration has landed
Four scripts, 1,890 lines, invoked by nothing — not `package.json`, not
`ci.yml`, not `check-conformance.mjs`, and not any `.md`:
scripts/check-docs-parity.mjs 421
scripts/check-docs-wording.mjs 197
scripts/migrate-api-pages.mjs 490
scripts/codemod-property-tsdoc.mjs 782
`check-docs-parity.mjs` said so itself: "This is a migration tool, not
permanent CI: once the migration lands, `origin/main` becomes the new baseline
and `docs-generated` in check-conformance.mjs holds the line instead." With all
seven categories now migrated, that is exactly where things stand.
Two reasons this is more than tidying. #420 widened `lint` to cover `scripts/`,
so these would be linted and prettier-checked on every CI run and carried
through every eslint/prettier/Node upgrade for no ongoing value. And after
merge they would not fail, they would mislead: `check-docs-parity` defaults to
`--base=origin/main`, so it would diff main against itself and report "0 losses
across 87 pages" — a check that reads as evidence while proving nothing.
Ran one final time before deletion, as the last regression check on the
generated pages: 6 prose flags across 2 files, all previously reviewed and
intentional — navbar's `**Key Subcomponents:**` heading, superseded by the
generated list that now includes `Navbar.Divider`, and sidebar's five "Accepts
all standard <X> HTML attributes" lines, whose element names now live in the
generated sub-tables' catch-all rows.
Nothing else references them; git history keeps them if a future category ever
needs re-migrating.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XkrYiLeAnyLBSa3KSweWJ
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Alex Smith <allxsmith@users.noreply.github.com>
|
🎉 This PR is included in version 4.0.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |
|
🎉 This PR is included in version 2.0.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |
|
🎉 This PR is included in version 5.8.1 🎉 The release is available on: Your semantic-release bot 📦🚀 |
|
🎉 This PR is included in version 1.0.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |

Pull Request
Description
30 pages. Two fixes to the extractor that this category forced — both found by
check-docs-parity, not by reading pages:Omit/Pickand imported (alias) symbols.LinkButtonProps extends Omit<ButtonProps, …>resolved the symbol ofOmit— a lib type — so all 14 of its inherited props landed in the catch-all row instead of a table. An imported base arrives as an alias symbol whosedeclarationsare the import specifier, not the interface, sogetAliasedSymbol()is now followed.Table's six sub-components are imported rather than declared locally, so the page rendered no sub-tables at all andThead/Tbody/Tfoot/Tr/Th/Td's props vanished. Cross-module subs now resolve through the barrel.Props the old tables documented but no interface declares —
href/target/relon Link,valueon ListItem, the<ol>attributes on OrderedList,skeletonfrom the helper props — are parked as@extraProp, carrying their type and default. Lossless by construction, and it puts the text in the source where the rest of it now lives.Button's component JSDoc was attached to an unrelatedconst validButtonColorsrather than toButton, so its summary never reached the page. Moved.Verification
check-docs-parity— 0 losses across all 87 pagescheck-docs-wording, restricted to these pages: of 215 previously-documented props, 178 read identically and 37 keep their sentence with more appended. None replaced.pnpm allgreenRelated Issue(s)
Refs #399
Type of Change
Affected packages:
@allxsmith/bestax-bulma) — comments only, plus theButtonJSDoc relocation@allxsmith/bestax-docs)Checklist
Additional Context
elements/block.mdis the page that exposed why a phased rollout is worse than either order applied consistently — it still had Props near the top whilelayout/had moved it down. From this PR its category is uniform with the rest.Generated by Claude Code