From 6a185530b04e49b79bad57caa320b4ff427b984b Mon Sep 17 00:00:00 2001 From: bestaxbot <300268469+bestaxbot@users.noreply.github.com> Date: Tue, 25 Aug 2026 00:25:28 +0000 Subject: [PATCH 1/3] fix(bestax-migrate): stop mislabeling RBC's own stylesheet as a third-party extension react-bulma-components/src/index.sass and its bundled v3 CSS matched EXTENSION_IMPORT's `\bbulma-` boundary check (the hyphen before "bulma" in "react-bulma-components" counts as a word boundary), so the source library's own stylesheet was reported as a third-party `bulma-components` extension and left untouched. Since deps.ts removes the package from package.json in the same run, the import then fails to resolve once the user installs. EXTENSION_IMPORT now requires the bulma-* package name to start at a specifier segment boundary. The library's own stylesheet import (bare or ~-prefixed src/index.sass, or the bundled dist CSS) is recognized and replaced per --css mode instead: bestax converges on the bestax bundle, bulma emits plain bulma/sass, and keep still swaps in bulma/sass (like the JS-side CSS pass already does for RBC's dead v3 CSS) with an explanatory TODO rather than leaving a known-broken import in place. Fixes #555 Co-authored-by: Alex Smith --- bestax-mcp/data/skills.json | 2 +- .../__tests__/styles.test.ts | 100 ++++++++++++++++++ .../sources/react-bulma-components/styles.ts | 55 +++++++++- .../migration/react-bulma-components.md | 14 ++- .../references/css-migration.md | 14 +++ 5 files changed, 178 insertions(+), 7 deletions(-) diff --git a/bestax-mcp/data/skills.json b/bestax-mcp/data/skills.json index f377465ad..d0d049c02 100644 --- a/bestax-mcp/data/skills.json +++ b/bestax-mcp/data/skills.json @@ -93,7 +93,7 @@ { "id": "css-migration", "file": "references/css-migration.md", - "bytes": 5679 + "bytes": 6725 }, { "id": "prop-map", "file": "references/prop-map.md", "bytes": 6363 }, { diff --git a/bestax-migrate/src/sources/react-bulma-components/__tests__/styles.test.ts b/bestax-migrate/src/sources/react-bulma-components/__tests__/styles.test.ts index 051b83c7a..68623393b 100644 --- a/bestax-migrate/src/sources/react-bulma-components/__tests__/styles.test.ts +++ b/bestax-migrate/src/sources/react-bulma-components/__tests__/styles.test.ts @@ -141,6 +141,106 @@ describe('transformStyles (.scss)', () => { expect(output).toContain('TODO(bestax-migrate)'); expect(todos).toHaveLength(1); }); + + describe("the source library's own stylesheet", () => { + it.each([ + [ + 'bare Sass entry point', + "@import 'react-bulma-components/src/index.sass';\n", + ], + [ + '~-prefixed Sass entry point', + "@import '~react-bulma-components/src/index.sass';\n", + ], + [ + 'bundled v3 CSS', + "@import 'react-bulma-components/dist/react-bulma-components.min.css';\n", + ], + ])( + 'is not mislabeled as a third-party extension (%s)', + (_label, source) => { + const { output, todos } = run('main.scss', source); + expect(output).not.toContain('third-party'); + expect(output).not.toContain('bulma-components'); + expect(todos.every(t => !t.message.includes('third-party'))).toBe(true); + expect(todos.every(t => !t.message.includes('bulma-components'))).toBe( + true + ); + } + ); + + it('bestax mode: rewrites the bare Sass entry point to the bestax bundle', () => { + const { output } = run( + 'main.scss', + "@import 'react-bulma-components/src/index.sass';\n" + ); + expect(output).toContain("@use '@allxsmith/bestax-bulma/scss/bestax';"); + expect(output).not.toContain('@import'); + expect(output).not.toContain('TODO'); + }); + + it('bestax mode: rewrites the ~-prefixed Sass entry point the same way', () => { + const { output } = run( + 'main.scss', + "@import '~react-bulma-components/src/index.sass';\n" + ); + expect(output).toContain("@use '@allxsmith/bestax-bulma/scss/bestax';"); + }); + + it('bestax mode: rewrites the bundled v3 CSS entry point the same way', () => { + const { output } = run( + 'main.scss', + "@import 'react-bulma-components/dist/react-bulma-components.min.css';\n" + ); + expect(output).toContain("@use '@allxsmith/bestax-bulma/scss/bestax';"); + }); + + it('bulma mode: rewrites to plain bulma/sass with no extras', () => { + const { output } = run( + 'main.scss', + "@import 'react-bulma-components/src/index.sass';\n", + 'bulma' + ); + expect(output).toContain("@use 'bulma/sass';"); + expect(output).not.toContain('extras'); + }); + + it('keep mode: still replaces the dead import, with an accurate TODO', () => { + const { output, todos } = run( + 'main.scss', + "@import 'react-bulma-components/src/index.sass';\n", + 'keep' + ); + expect(output).toContain("@use 'bulma/sass';"); + expect(output).toContain('TODO(bestax-migrate)'); + expect(output).not.toContain('@import'); + expect(todos[0].message).toContain('removed from dependencies'); + expect(todos[0].message).not.toContain('third-party'); + }); + + it('drops the now-redundant import when a real bulma root import already exists', () => { + const source = [ + "@import 'bulma/bulma';", + "@import 'react-bulma-components/src/index.sass';", + ].join('\n'); + const { output } = run('main.scss', source); + const bulmaUses = (output ?? '').match(/@use '[^']*bulma\/sass'/g) ?? []; + expect(bulmaUses).toHaveLength(1); + expect(output).not.toContain('react-bulma-components'); + }); + + it('still detects a genuine bulma-* extension alongside the RBC stylesheet', () => { + const source = [ + "@import 'react-bulma-components/src/index.sass';", + "@import 'bulma-checkradio/dist/css/bulma-checkradio.min.css';", + ].join('\n'); + const { output, todos } = run('main.scss', source); + expect(output).toContain('bulma-checkradio is a Bulma 0.9-era extension'); + expect(todos.some(t => t.message.includes('bulma-checkradio'))).toBe( + true + ); + }); + }); }); describe('transformStyles (.sass indented syntax)', () => { diff --git a/bestax-migrate/src/sources/react-bulma-components/styles.ts b/bestax-migrate/src/sources/react-bulma-components/styles.ts index 2d6483489..b3a5def2f 100644 --- a/bestax-migrate/src/sources/react-bulma-components/styles.ts +++ b/bestax-migrate/src/sources/react-bulma-components/styles.ts @@ -68,10 +68,23 @@ const OTHER_BULMA_IMPORT = /^\s*@import\s+['"][^'"]*bulma[^'"]*['"]/; /** * Third-party Bulma extension packages (`bulma-checkradio`, `bulma-switch`, * …) — 0.9-era add-ons whose v1 compatibility varies; several are covered - * by the bestax extras. + * by the bestax extras. The `bulma-` package name must start at a specifier + * segment boundary (right after the quote/`~`, or after a `/`) so this does + * not also match a name that merely *contains* `bulma-`, like + * `react-bulma-components` (see EXTENSION_IMPORT's own regression test). */ const EXTENSION_IMPORT = - /^\s*@import\s+['"][^'"]*\bbulma-([\w-]+?)(?:\/|\.|['"])/; + /^\s*@import\s+['"](?:~|[^'"]*\/)?bulma-([\w-]+?)(?:\/|\.|['"])/; + +/** + * The source library's own stylesheet (RBC v3's two documented setup + * paths — the bundled CSS and the "advanced" Sass entry point, bare or + * `~`-prefixed). This is not a third-party extension: it is the library + * being migrated away from, and `deps.ts` removes its package.json entry + * in the same run, so leaving the import in place breaks the Sass build. + */ +const RBC_STYLE_IMPORT = + /^(\s*)@import\s+(['"])(~)?react-bulma-components\/(?:src\/index\.(?:sass|scss)|dist\/react-bulma-components(?:\.min)?\.css)\2\s*;?\s*$/; /** Any `$name: value;` declaration (with or without `!default`). */ const VAR_DECL = /^\s*\$([\w-]+)\s*:\s*(.+?)\s*(!default)?\s*;\s*$/; @@ -121,6 +134,7 @@ export const transformStyles: StylesTransform = ( const out: string[] = []; let changed = false; let extrasAdded = source.includes('@allxsmith/bestax-bulma/scss'); + let rbcStyleEmitted = false; // Pass 1: find safe leading variable overrides and the first root import. const rootImportIndex = lines.findIndex(line => ROOT_IMPORT.test(line)); @@ -238,6 +252,43 @@ export const transformStyles: StylesTransform = ( continue; } + const rbcStyle = line.match(RBC_STYLE_IMPORT); + if (rbcStyle && !line.includes(TODO)) { + const indent = rbcStyle[1]; + if (rootImportIndex === -1 && !rbcStyleEmitted) { + // The library's own stylesheet never resolves post-migration — + // deps.ts removes react-bulma-components from package.json in the + // same run — so every mode replaces it with a real Bulma entry + // point rather than leaving a guaranteed-broken import; this + // mirrors how the JS-side CSS pass treats RBC's dead v3 bundled + // CSS even under `--css keep`. + if (cssMode === 'bestax') { + out.push(`${indent}@use '@allxsmith/bestax-bulma/scss/bestax';`); + extrasAdded = true; // the bundle already includes the extras + } else { + out.push(`${indent}@use 'bulma/sass';`); + } + if (cssMode === 'keep') { + out.push( + `${indent}// ${TODO}: replaced react-bulma-components's own stylesheet with @use 'bulma/sass' — its package.json entry is removed, so the old import no longer resolves; install bulma@^1 — see ${GUIDE}` + ); + report( + collector, + filePath, + i + 1, + 'sass', + "replaced react-bulma-components's stylesheet import with bulma/sass; the package is removed from dependencies, so the old import would not resolve" + ); + } + rbcStyleEmitted = true; + } + // Otherwise a real `bulma/…` root import already brings in Bulma (and, + // in bestax mode, the extras) elsewhere in this file — drop the now- + // redundant line entirely rather than importing Bulma twice. + changed = true; + continue; + } + if (OTHER_BULMA_IMPORT.test(line) && !line.includes(TODO)) { const extension = line.match(EXTENSION_IMPORT); if (extension) { diff --git a/docs/docs/guides/getting-started/migration/react-bulma-components.md b/docs/docs/guides/getting-started/migration/react-bulma-components.md index ea5e54f11..64366f7d8 100644 --- a/docs/docs/guides/getting-started/migration/react-bulma-components.md +++ b/docs/docs/guides/getting-started/migration/react-bulma-components.md @@ -60,8 +60,12 @@ in place: `@allxsmith/bestax-bulma/bestax.css` bundle (Bulma v1 + the bestax extras); SCSS files move from Bulma 0.9's `@import 'bulma/bulma'` + `$var !default` overrides to `@use 'bulma/sass' with ($var: …)` plus `@use '@allxsmith/bestax-bulma/scss/extras'`, and - the dead `_all` partial paths map onto the v1 module tree. Computed variables and - indented-syntax `.sass` files are flagged instead of guessed at. + the dead `_all` partial paths map onto the v1 module tree. react-bulma-components' own v3 + stylesheet entry point (`react-bulma-components/src/index.sass`, bare or `~`-prefixed) gets + the same treatment — it's the library being removed, not a third-party extension, so it + becomes `@use '@allxsmith/bestax-bulma/scss/bestax'` (or is dropped if the file already has + its own Bulma root import). Computed variables and indented-syntax `.sass` files are flagged + instead of guessed at. - **Dependencies** — the nearest `package.json` drops `react-bulma-components`, gains `@allxsmith/bestax-bulma`, moves `bulma` to `^1.0.4`, and swaps the dead `node-sass` for dart `sass`. The codemod never runs an install — do that yourself afterwards. @@ -123,8 +127,10 @@ npx skills add https://github.com/allxsmith/bestax --skill bestax-migrate The codemod maps the react-bulma-components **v4** API. v3-era patterns are detected and flagged rather than converted: bundled-CSS imports (`react-bulma-components/dist/react-bulma-components.min.css`) are rewritten to the Bulma v1 -stylesheet, and deep `react-bulma-components/lib/components/*` imports get a TODO pointing you -at the v4 named-import style first. +stylesheet, its Sass equivalent (`react-bulma-components/src/index.sass`, bare or +`~`-prefixed) is rewritten the same way in SCSS files, and deep +`react-bulma-components/lib/components/*` imports get a TODO pointing you at the v4 +named-import style first. ## Coming from a different library? diff --git a/skills/bestax-migrate/references/css-migration.md b/skills/bestax-migrate/references/css-migration.md index acbb4d015..9d5a9e215 100644 --- a/skills/bestax-migrate/references/css-migration.md +++ b/skills/bestax-migrate/references/css-migration.md @@ -38,6 +38,18 @@ finish what it flagged. **dart-sass ≥ 1.79** — the codemod's node-sass replacement installs that, but check bundler-pinned older versions (Parcel's sass transformer pins 1.66). + react-bulma-components' own v3-era stylesheet entry point — bare or `~`-prefixed + `react-bulma-components/src/index.sass`, or the bundled + `react-bulma-components/dist/react-bulma-components(.min).css` — is not a third-party + extension; it's the library being migrated away from, and (unless `--no-deps` is + passed) `package.json` no longer lists it, so the import can never resolve once + installed. Every `--css` mode replaces it rather than leaving a known-broken import: + `bestax` (default) emits `@use '@allxsmith/bestax-bulma/scss/bestax';`; `bulma` emits + plain `@use 'bulma/sass';`; `keep` emits the same plain `@use 'bulma/sass';` with a TODO + explaining the replacement (mirroring how the CSS-import pass treats RBC's dead v3 + bundled CSS even under `--css keep`). If the file already has its own `bulma/…` root + import, the now-redundant line is dropped instead of emitting a second one. + - **package.json**: `react-bulma-components` removed, `@allxsmith/bestax-bulma` added, `bulma` bumped to `^1.0.4` (or added when sources still import `bulma/…` directly), and dead `node-sass` replaced with dart `sass`. Run the package manager's install @@ -63,6 +75,8 @@ elements,form,components,grid,layout,helpers,themes}` with leaf partials like compatibility. Class-based usage (`className="is-checkradio"`) keeps needing the extension; usage that migrated to bestax components (Radio, Checkbox, the advanced form controls) is already styled by the bestax extras, so the import can go. + react-bulma-components' own stylesheet is never flagged this way (see above) — only + packages actually named `bulma-*` are. ## Choosing a CSS flavor (optional) From 036cf79130e1397df0e2e708d1d115bec217511c Mon Sep 17 00:00:00 2001 From: bestaxbot <300268469+bestaxbot@users.noreply.github.com> Date: Tue, 25 Aug 2026 01:16:49 +0000 Subject: [PATCH 2/3] fix(bestax-migrate): rewrite RBC stylesheet as a real Bulma root, folding vars MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses the four review findings on the RBC stylesheet handling: - Fold leading $var overrides above the RBC import into `@use 'bulma/sass' with (…)` instead of silently dropping them — the RBC import now participates in the same var-folding pass the `@import 'bulma/…'` root does. - Emit `@use 'bulma/sass'` (+ extras in bestax mode) rather than the hard-configured `scss/bestax` bundle, so a file that starts from RBC and one that starts from a bulma @import converge on the same shape and neither reconfigures an already-loaded `bulma/sass`. - Detect a pre-existing `@use` Bulma root in the file: keep it, add only the extras (bestax) or drop the redundant line (bulma/keep) — never a second namespace or a reconfigure. - Broaden RBC_STYLE_IMPORT to any `react-bulma-components/…` specifier (bare, ~-prefixed, relative node_modules, deep partials, extensionless), mirroring transform.ts, so no dead RBC stylesheet slips through to a broken build. - Thread the deps setting through so the keep-mode TODO/report no longer claim a package removal that `--no-deps` skips. Updates the skill reference and docs migration guide, regenerates the MCP index, and adds regression coverage for each case. Co-Authored-By: Claude Opus 4.8 --- bestax-mcp/data/skills.json | 2 +- bestax-migrate/src/cli.ts | 1 + .../__tests__/styles.test.ts | 100 +++++++++- .../sources/react-bulma-components/styles.ts | 181 +++++++++++------- bestax-migrate/src/types.ts | 7 + .../migration/react-bulma-components.md | 14 +- .../references/css-migration.md | 31 +-- 7 files changed, 250 insertions(+), 86 deletions(-) diff --git a/bestax-mcp/data/skills.json b/bestax-mcp/data/skills.json index d0d049c02..af20f2096 100644 --- a/bestax-mcp/data/skills.json +++ b/bestax-mcp/data/skills.json @@ -93,7 +93,7 @@ { "id": "css-migration", "file": "references/css-migration.md", - "bytes": 6725 + "bytes": 7457 }, { "id": "prop-map", "file": "references/prop-map.md", "bytes": 6363 }, { diff --git a/bestax-migrate/src/cli.ts b/bestax-migrate/src/cli.ts index 351adf4a5..34c04c1e4 100644 --- a/bestax-migrate/src/cli.ts +++ b/bestax-migrate/src/cli.ts @@ -116,6 +116,7 @@ function migrateFiles( output = source.transformStyles ? source.transformStyles(file, sourceText, collector, { cssMode: options.cssMode, + deps: options.deps, }) : null; } else { diff --git a/bestax-migrate/src/sources/react-bulma-components/__tests__/styles.test.ts b/bestax-migrate/src/sources/react-bulma-components/__tests__/styles.test.ts index 68623393b..0ff1c34c2 100644 --- a/bestax-migrate/src/sources/react-bulma-components/__tests__/styles.test.ts +++ b/bestax-migrate/src/sources/react-bulma-components/__tests__/styles.test.ts @@ -169,12 +169,16 @@ describe('transformStyles (.scss)', () => { } ); - it('bestax mode: rewrites the bare Sass entry point to the bestax bundle', () => { + it('bestax mode: rewrites the bare Sass entry point to bulma/sass + extras', () => { const { output } = run( 'main.scss', "@import 'react-bulma-components/src/index.sass';\n" ); - expect(output).toContain("@use '@allxsmith/bestax-bulma/scss/bestax';"); + expect(output).toContain("@use 'bulma/sass';"); + expect(output).toContain("@use '@allxsmith/bestax-bulma/scss/extras';"); + // Never the hard-configured bundle: it can't take the user's own theme + // vars and reconfiguring bulma/sass elsewhere in the build is a hard error. + expect(output).not.toContain('scss/bestax'); expect(output).not.toContain('@import'); expect(output).not.toContain('TODO'); }); @@ -184,7 +188,8 @@ describe('transformStyles (.scss)', () => { 'main.scss', "@import '~react-bulma-components/src/index.sass';\n" ); - expect(output).toContain("@use '@allxsmith/bestax-bulma/scss/bestax';"); + expect(output).toContain("@use 'bulma/sass';"); + expect(output).toContain("@use '@allxsmith/bestax-bulma/scss/extras';"); }); it('bestax mode: rewrites the bundled v3 CSS entry point the same way', () => { @@ -192,7 +197,94 @@ describe('transformStyles (.scss)', () => { 'main.scss', "@import 'react-bulma-components/dist/react-bulma-components.min.css';\n" ); - expect(output).toContain("@use '@allxsmith/bestax-bulma/scss/bestax';"); + expect(output).toContain("@use 'bulma/sass';"); + expect(output).toContain("@use '@allxsmith/bestax-bulma/scss/extras';"); + }); + + it('folds leading $var overrides above the RBC stylesheet into with (…)', () => { + const source = [ + '$primary: #ff6b35;', + "@import '~react-bulma-components/src/index.sass';", + ].join('\n'); + const { output } = run('theme.scss', source); + expect(output).toContain("@use 'bulma/sass' with ("); + expect(output).toContain('$primary: #ff6b35'); + expect(output).toContain("@use '@allxsmith/bestax-bulma/scss/extras';"); + expect(output).not.toContain('scss/bestax'); + }); + + it.each([ + [ + 'relative node_modules Sass path', + "@import '../../node_modules/react-bulma-components/src/index.sass';\n", + ], + [ + 'extensionless Sass entry point', + "@import 'react-bulma-components/src/index';\n", + ], + [ + 'deep component partial', + "@import 'react-bulma-components/src/components/navbar.sass';\n", + ], + ])( + 'rewrites the RBC stylesheet regardless of specifier shape (%s)', + (_l, source) => { + const { output } = run('main.scss', source); + expect(output).toContain('bulma/sass'); + expect(output).not.toContain('react-bulma-components'); + expect(output).not.toContain('convert to @use by hand'); + } + ); + + it('preserves the relative node_modules prefix on the rewritten root', () => { + const { output } = run( + 'deep/nested.scss', + "@import '../../node_modules/react-bulma-components/src/index.sass';\n" + ); + expect(output).toContain("@use '../../node_modules/bulma/sass';"); + expect(output).toContain( + "@use '../../node_modules/@allxsmith/bestax-bulma/src/scss/extras';" + ); + }); + + it('adds only the extras when the file already has its own @use bulma root', () => { + const source = [ + "@use 'bulma/sass';", + "@import 'react-bulma-components/src/index.sass';", + ].join('\n'); + const { output } = run('main.scss', source); + const bulmaRoots = (output ?? '').match(/@use '[^']*bulma\/sass'/g) ?? []; + expect(bulmaRoots).toHaveLength(1); // the existing one, not a second + expect(output).toContain("@use '@allxsmith/bestax-bulma/scss/extras';"); + expect(output).not.toContain('scss/bestax'); + expect(output).not.toContain('react-bulma-components'); + }); + + it('drops the RBC line entirely (no second root) with an existing @use root in bulma mode', () => { + const source = [ + "@use 'bulma/sass';", + "@import 'react-bulma-components/src/index.sass';", + ].join('\n'); + const { output } = run('main.scss', source, 'bulma'); + const bulmaRoots = (output ?? '').match(/@use '[^']*bulma\/sass'/g) ?? []; + expect(bulmaRoots).toHaveLength(1); + expect(output).not.toContain('extras'); + expect(output).not.toContain('react-bulma-components'); + }); + + it('keep mode under --no-deps does not claim the package was removed', () => { + const todos: TodoEntry[] = []; + const output = transformStyles( + 'main.scss', + "@import 'react-bulma-components/src/index.sass';\n", + { add: entry => todos.push(entry) }, + { cssMode: 'keep', deps: false } + ); + expect(output).toContain("@use 'bulma/sass';"); + expect(output).not.toContain('is removed'); + expect(output).not.toContain('entry is removed'); + expect(todos[0].message).not.toContain('removed from dependencies'); + expect(todos[0].message).toContain('--no-deps'); }); it('bulma mode: rewrites to plain bulma/sass with no extras', () => { diff --git a/bestax-migrate/src/sources/react-bulma-components/styles.ts b/bestax-migrate/src/sources/react-bulma-components/styles.ts index b3a5def2f..47871a3be 100644 --- a/bestax-migrate/src/sources/react-bulma-components/styles.ts +++ b/bestax-migrate/src/sources/react-bulma-components/styles.ts @@ -77,14 +77,28 @@ const EXTENSION_IMPORT = /^\s*@import\s+['"](?:~|[^'"]*\/)?bulma-([\w-]+?)(?:\/|\.|['"])/; /** - * The source library's own stylesheet (RBC v3's two documented setup - * paths — the bundled CSS and the "advanced" Sass entry point, bare or - * `~`-prefixed). This is not a third-party extension: it is the library - * being migrated away from, and `deps.ts` removes its package.json entry - * in the same run, so leaving the import in place breaks the Sass build. + * The source library's own stylesheet. This is not a third-party extension: + * it is the library being migrated away from, and `deps.ts` removes its + * package.json entry in the same run, so leaving the import in place breaks + * the Sass build. Any `react-bulma-components/…` specifier is dead the same + * way — the documented v3 setup paths (the bundled CSS, the "advanced" Sass + * entry point), but also deep partials and extensionless forms — so, like + * `transform.ts`, we match on the package prefix rather than enumerating + * shapes. The prefix may be bare, `~`-prefixed, or a relative node_modules + * path (the Parcel form `ROOT_IMPORT` also supports). */ const RBC_STYLE_IMPORT = - /^(\s*)@import\s+(['"])(~)?react-bulma-components\/(?:src\/index\.(?:sass|scss)|dist\/react-bulma-components(?:\.min)?\.css)\2\s*;?\s*$/; + /^(\s*)@import\s+(['"])((?:\.\.?\/)+node_modules\/|~)?react-bulma-components\/[^'"]*\2\s*;?\s*$/; + +/** + * A Bulma module root already pulled in via `@use` — the file's own + * `@use 'bulma/sass'` (any prefix, configured or not) or the bestax bundle + * (`scss/bestax`, which itself loads `bulma/sass with (…)`). When one is + * present we must not emit a second root: a duplicate `bulma/sass` namespace, + * or reconfiguring an already-loaded module, is a hard Sass error. + */ +const USE_BULMA_ROOT = + /^\s*@use\s+(['"])(?:~|(?:\.\.?\/)+node_modules\/)?(?:bulma\/sass|@allxsmith\/bestax-bulma\/(?:src\/)?scss\/bestax)\1/; /** Any `$name: value;` declaration (with or without `!default`). */ const VAR_DECL = /^\s*\$([\w-]+)\s*:\s*(.+?)\s*(!default)?\s*;\s*$/; @@ -134,15 +148,27 @@ export const transformStyles: StylesTransform = ( const out: string[] = []; let changed = false; let extrasAdded = source.includes('@allxsmith/bestax-bulma/scss'); - let rbcStyleEmitted = false; - // Pass 1: find safe leading variable overrides and the first root import. + // Pass 1: locate the file's Bulma root and the safe leading variable + // overrides that fold into it. A real `bulma/…` @import root wins; otherwise + // the RBC stylesheet, which we rewrite into a root the same way — so a file + // that starts from RBC and one that starts from a bulma @import converge on + // the identical shape. A pre-existing `@use` root means we create no new one. const rootImportIndex = lines.findIndex(line => ROOT_IMPORT.test(line)); + const rbcRootIndex = lines.findIndex( + line => RBC_STYLE_IMPORT.test(line) && !line.includes(TODO) + ); + const hasUseBulmaRoot = lines.some(line => USE_BULMA_ROOT.test(line)); + const foldTargetIndex = hasUseBulmaRoot + ? -1 + : rootImportIndex !== -1 + ? rootImportIndex + : rbcRootIndex; const foldableVars: Array<{ index: number; name: string; value: string }> = []; const unsafeVarLines: number[] = []; - if (rootImportIndex !== -1) { - for (let i = 0; i < rootImportIndex; i += 1) { + if (foldTargetIndex !== -1) { + for (let i = 0; i < foldTargetIndex; i += 1) { const line = lines[i]; const match = line.match(VAR_DECL); if (match && isFoldableValue(match[2])) { @@ -154,46 +180,58 @@ export const transformStyles: StylesTransform = ( } const folded = new Set(foldableVars.map(v => v.index)); + /** + * Emit a Bulma module root at `indent` (folding the leading var overrides + * gathered above into `with (…)`, flagging any unsafe ones), then, in + * bestax mode, the extras. `prefix` is a preserved relative-path prefix + * (raw-file toolchains resolve paths, not package specifiers) or ''. + */ + const emitBulmaRoot = ( + indent: string, + prefix: string, + lineNo: number + ): void => { + const bulmaSass = `${prefix}bulma/sass`; + if (foldableVars.length > 0) { + out.push(`${indent}@use '${bulmaSass}' with (`); + foldableVars.forEach(({ name, value }, index) => { + const comma = index < foldableVars.length - 1 ? ',' : ''; + out.push(`${indent} $${name}: ${value}${comma}`); + }); + out.push(`${indent});`); + } else { + out.push(`${indent}@use '${bulmaSass}';`); + } + if (unsafeVarLines.length > 0) { + out.push( + `${indent}// ${TODO}: the variable override(s) above use computed values; move them into the @use "bulma/sass" with (…) configuration by hand` + ); + report( + collector, + filePath, + lineNo, + 'sass', + 'variable overrides with computed values could not be folded into `with (…)`' + ); + } + if (cssMode === 'bestax' && !extrasAdded) { + out.push( + prefix + ? `${indent}@use '${prefix}@allxsmith/bestax-bulma/src/scss/extras';` + : `${indent}${EXTRAS_USE}` + ); + extrasAdded = true; + } + }; + for (let i = 0; i < lines.length; i += 1) { const line = lines[i]; if (i === rootImportIndex) { const rootMatch = line.match(ROOT_IMPORT); - const indent = rootMatch?.[1] ?? ''; - const bulmaSass = `${keptPrefix(rootMatch?.[3])}bulma/sass`; - if (foldableVars.length > 0) { - out.push(`${indent}@use '${bulmaSass}' with (`); - foldableVars.forEach(({ name, value }, index) => { - const comma = index < foldableVars.length - 1 ? ',' : ''; - out.push(`${indent} $${name}: ${value}${comma}`); - }); - out.push(`${indent});`); - } else { - out.push(`${indent}@use '${bulmaSass}';`); - } - if (unsafeVarLines.length > 0) { - out.push( - `${indent}// ${TODO}: the variable override(s) above use computed values; move them into the @use "bulma/sass" with (…) configuration by hand` - ); - report( - collector, - filePath, - i + 1, - 'sass', - 'variable overrides with computed values could not be folded into `with (…)`' - ); - } - if (cssMode === 'bestax' && !extrasAdded) { - // A path-prefixed root import means the toolchain resolves raw file - // paths, not package specifiers — point at the shipped file directly. - const extrasPrefix = keptPrefix(rootMatch?.[3]); - out.push( - extrasPrefix - ? `${indent}@use '${extrasPrefix}@allxsmith/bestax-bulma/src/scss/extras';` - : `${indent}${EXTRAS_USE}` - ); - extrasAdded = true; - } + // A path-prefixed root import means the toolchain resolves raw file + // paths, not package specifiers — point at the shipped files directly. + emitBulmaRoot(rootMatch?.[1] ?? '', keptPrefix(rootMatch?.[3]), i + 1); changed = true; continue; } @@ -255,36 +293,51 @@ export const transformStyles: StylesTransform = ( const rbcStyle = line.match(RBC_STYLE_IMPORT); if (rbcStyle && !line.includes(TODO)) { const indent = rbcStyle[1]; - if (rootImportIndex === -1 && !rbcStyleEmitted) { - // The library's own stylesheet never resolves post-migration — - // deps.ts removes react-bulma-components from package.json in the - // same run — so every mode replaces it with a real Bulma entry - // point rather than leaving a guaranteed-broken import; this - // mirrors how the JS-side CSS pass treats RBC's dead v3 bundled - // CSS even under `--css keep`. - if (cssMode === 'bestax') { - out.push(`${indent}@use '@allxsmith/bestax-bulma/scss/bestax';`); - extrasAdded = true; // the bundle already includes the extras - } else { - out.push(`${indent}@use 'bulma/sass';`); - } + const prefix = keptPrefix(rbcStyle[3]); + if (i === rbcRootIndex && rootImportIndex === -1 && !hasUseBulmaRoot) { + // The library's own stylesheet never resolves post-migration (deps.ts + // removes react-bulma-components in the same run), and it is this + // file's only Bulma root, so rewrite it into one — the same shape the + // @import root path emits, folding any leading var overrides. Emitting + // a real `bulma/sass` (+ extras) rather than the hard-configured + // bestax bundle keeps this convergent with the @import path and avoids + // reconfiguring `bulma/sass` if a themed root exists elsewhere. + emitBulmaRoot(indent, prefix, i + 1); if (cssMode === 'keep') { + // The replacement is unavoidable even in keep mode: RBC's own + // stylesheet is a v3 (Bulma 0.9) asset the migrated v1 components + // can't use. What changed depends on whether the manifest step ran. + const depsRan = options.deps !== false; + const detail = depsRan + ? 'its package.json entry is removed, so the old import no longer resolves; install bulma@^1' + : 'it targets Bulma 0.9, not the v1 your components now use; --no-deps kept the dependency, so install bulma@^1 alongside it'; out.push( - `${indent}// ${TODO}: replaced react-bulma-components's own stylesheet with @use 'bulma/sass' — its package.json entry is removed, so the old import no longer resolves; install bulma@^1 — see ${GUIDE}` + `${indent}// ${TODO}: replaced react-bulma-components's own stylesheet with @use 'bulma/sass' — ${detail} — see ${GUIDE}` ); report( collector, filePath, i + 1, 'sass', - "replaced react-bulma-components's stylesheet import with bulma/sass; the package is removed from dependencies, so the old import would not resolve" + depsRan + ? "replaced react-bulma-components's stylesheet import with bulma/sass; the package is removed from dependencies, so the old import would not resolve" + : "replaced react-bulma-components's stylesheet import with bulma/sass; it is a Bulma 0.9 asset the migrated v1 components can't use (--no-deps left the package in place)" ); } - rbcStyleEmitted = true; + } else if (cssMode === 'bestax' && !extrasAdded) { + // A Bulma root already exists in this file — a `bulma/…` @import we + // convert, or the file's own `@use` root. Keep it and add only the + // extras: never a second root, and never the configured bundle that + // would reconfigure an already-loaded module. + out.push( + prefix + ? `${indent}@use '${prefix}@allxsmith/bestax-bulma/src/scss/extras';` + : `${indent}${EXTRAS_USE}` + ); + extrasAdded = true; } - // Otherwise a real `bulma/…` root import already brings in Bulma (and, - // in bestax mode, the extras) elsewhere in this file — drop the now- - // redundant line entirely rather than importing Bulma twice. + // Otherwise (bulma/keep with a root already present) the line is + // redundant — drop it rather than importing Bulma twice. changed = true; continue; } diff --git a/bestax-migrate/src/types.ts b/bestax-migrate/src/types.ts index 703cffdb2..4a04bd3fd 100644 --- a/bestax-migrate/src/types.ts +++ b/bestax-migrate/src/types.ts @@ -101,6 +101,13 @@ export type CssMode = 'bestax' | 'bulma' | 'keep'; export interface TransformOptions { collector?: TodoCollector; cssMode?: CssMode; + /** + * Whether the run also updates package.json (false under `--no-deps`). + * The stylesheet transform's messaging depends on it: it may only claim a + * dependency was removed when the manifest step actually runs. Undefined is + * treated as the CLI default (deps on). + */ + deps?: boolean; [key: string]: unknown; } diff --git a/docs/docs/guides/getting-started/migration/react-bulma-components.md b/docs/docs/guides/getting-started/migration/react-bulma-components.md index 64366f7d8..9141df727 100644 --- a/docs/docs/guides/getting-started/migration/react-bulma-components.md +++ b/docs/docs/guides/getting-started/migration/react-bulma-components.md @@ -60,12 +60,14 @@ in place: `@allxsmith/bestax-bulma/bestax.css` bundle (Bulma v1 + the bestax extras); SCSS files move from Bulma 0.9's `@import 'bulma/bulma'` + `$var !default` overrides to `@use 'bulma/sass' with ($var: …)` plus `@use '@allxsmith/bestax-bulma/scss/extras'`, and - the dead `_all` partial paths map onto the v1 module tree. react-bulma-components' own v3 - stylesheet entry point (`react-bulma-components/src/index.sass`, bare or `~`-prefixed) gets - the same treatment — it's the library being removed, not a third-party extension, so it - becomes `@use '@allxsmith/bestax-bulma/scss/bestax'` (or is dropped if the file already has - its own Bulma root import). Computed variables and indented-syntax `.sass` files are flagged - instead of guessed at. + the dead `_all` partial paths map onto the v1 module tree. react-bulma-components' own + stylesheet (any `react-bulma-components/…` specifier — the v3 entry points bare, `~`- or + relative-`node_modules`-prefixed, plus deep partials) gets the same treatment — it's the + library being removed, not a third-party extension, so it is rewritten into that identical + `@use 'bulma/sass'` (+ extras) root, folding any leading `$var` overrides, rather than the + hard-configured `scss/bestax` bundle that couldn't take them. If the file already has its + own Bulma root the redundant line is dropped (the extras still added once). Computed + variables and indented-syntax `.sass` files are flagged instead of guessed at. - **Dependencies** — the nearest `package.json` drops `react-bulma-components`, gains `@allxsmith/bestax-bulma`, moves `bulma` to `^1.0.4`, and swaps the dead `node-sass` for dart `sass`. The codemod never runs an install — do that yourself afterwards. diff --git a/skills/bestax-migrate/references/css-migration.md b/skills/bestax-migrate/references/css-migration.md index 9d5a9e215..578ce2187 100644 --- a/skills/bestax-migrate/references/css-migration.md +++ b/skills/bestax-migrate/references/css-migration.md @@ -38,17 +38,26 @@ finish what it flagged. **dart-sass ≥ 1.79** — the codemod's node-sass replacement installs that, but check bundler-pinned older versions (Parcel's sass transformer pins 1.66). - react-bulma-components' own v3-era stylesheet entry point — bare or `~`-prefixed - `react-bulma-components/src/index.sass`, or the bundled - `react-bulma-components/dist/react-bulma-components(.min).css` — is not a third-party - extension; it's the library being migrated away from, and (unless `--no-deps` is - passed) `package.json` no longer lists it, so the import can never resolve once - installed. Every `--css` mode replaces it rather than leaving a known-broken import: - `bestax` (default) emits `@use '@allxsmith/bestax-bulma/scss/bestax';`; `bulma` emits - plain `@use 'bulma/sass';`; `keep` emits the same plain `@use 'bulma/sass';` with a TODO - explaining the replacement (mirroring how the CSS-import pass treats RBC's dead v3 - bundled CSS even under `--css keep`). If the file already has its own `bulma/…` root - import, the now-redundant line is dropped instead of emitting a second one. + react-bulma-components' own stylesheet — any `react-bulma-components/…` specifier, + bare, `~`-prefixed, or a relative `node_modules/` path, covering the documented v3 + entry points (`src/index.sass`, `dist/react-bulma-components(.min).css`) as well as + deep partials and extensionless forms — is not a third-party extension; it's the + library being migrated away from. It targets Bulma 0.9, not the v1 your components now + use, and (unless `--no-deps` is passed) `package.json` no longer lists it, so the + import can never resolve once installed. Every `--css` mode rewrites it into a real + Bulma root rather than leaving a known-broken import — the **same shape the + `@import 'bulma/…'` root path emits**, so a file that starts from RBC and one that + starts from a Bulma import converge: `bestax` (default) emits + `@use 'bulma/sass';` (folding any leading `$var` overrides above the import into + `with (…)`) plus `@use '@allxsmith/bestax-bulma/scss/extras';`; `bulma` emits plain + `@use 'bulma/sass';`; `keep` does the same with a TODO explaining the replacement + (worded to match whether `--no-deps` kept the package). It deliberately does **not** + emit the hard-configured `scss/bestax` bundle here — that bundle can't carry the + user's own theme vars, and reconfiguring `bulma/sass` when another file already + configures it is a hard Sass error. If the file already has its own `bulma/…` root + (a `@use 'bulma/sass'` of its own, or a Bulma `@import` the codemod converts), the RBC + line is dropped instead of emitting a second root; in `bestax` mode the extras are + added once alongside that existing root. - **package.json**: `react-bulma-components` removed, `@allxsmith/bestax-bulma` added, `bulma` bumped to `^1.0.4` (or added when sources still import `bulma/…` directly), From 7db47db794c6a8960718e0b12a163bd56d6cc8c2 Mon Sep 17 00:00:00 2001 From: bestaxbot <300268469+bestaxbot@users.noreply.github.com> Date: Tue, 25 Aug 2026 07:43:42 +0000 Subject: [PATCH 3/3] fix(bestax-migrate): flag dropped RBC deep partials instead of losing their CSS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a file already has a Bulma root and an RBC stylesheet import is removed, the drop is only safe for the library's own root/index stylesheet (`src/index`, the bundled `dist/*.css`, the bare specifier), which `bulma/sass` supersedes. A deep RBC partial (`src/components/navbar.sass`) can carry styles `bulma/sass` doesn't, so silently dropping it loses CSS — violating the package's "never a silent skip" rule. - Add RBC_ROOT_STYLESHEET to classify the root/index forms; a non-root RBC import removed beside an existing root now emits a `// TODO(bestax-migrate)` plus a report entry ("port any styles it carried beyond Bulma's own by hand"). - Restructure the RBC branch so the extras-once and partial-flag concerns are independent — a deep partial in bestax mode is flagged even when the extras were already added by the root rewrite. - Report the RBC root rewrite in bestax/bulma modes too (previously only keep mode reported), so the migration summary reflects the restructured root. - Cover the new behavior with tests; refine the "not mislabeled" assertion to guard against the third-party *extension* label rather than the package name. - Update css-migration.md and the docs migration guide, and regenerate the MCP index byte count. Co-Authored-By: Claude Opus 4.8 --- bestax-mcp/data/skills.json | 2 +- .../__tests__/styles.test.ts | 60 ++++++++++++++++- .../sources/react-bulma-components/styles.ts | 66 +++++++++++++++---- .../migration/react-bulma-components.md | 6 +- .../references/css-migration.md | 8 ++- 5 files changed, 121 insertions(+), 21 deletions(-) diff --git a/bestax-mcp/data/skills.json b/bestax-mcp/data/skills.json index 940a2dbe5..c7f6f6a0d 100644 --- a/bestax-mcp/data/skills.json +++ b/bestax-mcp/data/skills.json @@ -93,7 +93,7 @@ { "id": "css-migration", "file": "references/css-migration.md", - "bytes": 7616 + "bytes": 7999 }, { "id": "prop-map", "file": "references/prop-map.md", "bytes": 6363 }, { diff --git a/bestax-migrate/src/sources/react-bulma-components/__tests__/styles.test.ts b/bestax-migrate/src/sources/react-bulma-components/__tests__/styles.test.ts index 262cbaaaf..7225e67b8 100644 --- a/bestax-migrate/src/sources/react-bulma-components/__tests__/styles.test.ts +++ b/bestax-migrate/src/sources/react-bulma-components/__tests__/styles.test.ts @@ -231,10 +231,11 @@ describe('transformStyles (.scss)', () => { const { output, todos } = run('main.scss', source); expect(output).not.toContain('third-party'); expect(output).not.toContain('bulma-components'); + // The mislabel we guard against is calling the library's own root a + // third-party `bulma-components` *extension*; a report that names the + // package while rewriting its root is fine. expect(todos.every(t => !t.message.includes('third-party'))).toBe(true); - expect(todos.every(t => !t.message.includes('bulma-components'))).toBe( - true - ); + expect(todos.every(t => !t.message.includes('extension'))).toBe(true); } ); @@ -403,6 +404,59 @@ describe('transformStyles (.scss)', () => { expect(output).not.toContain('react-bulma-components'); }); + it('flags a dropped RBC deep partial instead of losing its CSS (bulma mode)', () => { + const source = [ + "@import 'bulma/bulma.sass';", + "@import 'react-bulma-components/src/components/navbar.sass';", + ].join('\n'); + const { output, todos } = run('main.scss', source, 'bulma'); + const bulmaRoots = (output ?? '').match(/@use '[^']*bulma\/sass'/g) ?? []; + expect(bulmaRoots).toHaveLength(1); + expect(output).not.toContain('react-bulma-components/src/components'); + expect(output).toContain('stylesheet partial'); + expect(todos.some(t => t.message.includes('partial dropped'))).toBe(true); + }); + + it('flags a second RBC deep partial in bestax mode (root + extras, partial not lost)', () => { + const source = [ + "@import 'react-bulma-components/src/index.sass';", + "@import 'react-bulma-components/src/components/tooltip.sass';", + ].join('\n'); + const { output, todos } = run('main.scss', source); + const bulmaRoots = (output ?? '').match(/@use '[^']*bulma\/sass'/g) ?? []; + expect(bulmaRoots).toHaveLength(1); + const extras = (output ?? '').match(/bestax-bulma\/scss\/extras/g) ?? []; + expect(extras).toHaveLength(1); + expect(output).not.toContain('react-bulma-components/src/components'); + expect(output).toContain('stylesheet partial'); + expect(todos.some(t => t.message.includes('partial dropped'))).toBe(true); + }); + + it('flags an RBC deep partial dropped beside the file’s own @use root (bestax mode)', () => { + const source = [ + "@use 'bulma/sass';", + "@import 'react-bulma-components/src/components/navbar.sass';", + ].join('\n'); + const { output, todos } = run('main.scss', source); + const bulmaRoots = (output ?? '').match(/@use '[^']*bulma\/sass'/g) ?? []; + expect(bulmaRoots).toHaveLength(1); + expect(output).toContain("@use '@allxsmith/bestax-bulma/scss/extras';"); + expect(output).toContain('stylesheet partial'); + expect(todos.some(t => t.message.includes('partial dropped'))).toBe(true); + }); + + it('does not flag the RBC root/index import when it is dropped as redundant', () => { + const source = [ + "@import 'bulma/bulma';", + "@import 'react-bulma-components/src/index.sass';", + ].join('\n'); + const { output, todos } = run('main.scss', source, 'bulma'); + expect(output).not.toContain('stylesheet partial'); + expect(todos.some(t => t.message.includes('partial dropped'))).toBe( + false + ); + }); + it('still detects a genuine bulma-* extension alongside the RBC stylesheet', () => { const source = [ "@import 'react-bulma-components/src/index.sass';", diff --git a/bestax-migrate/src/sources/react-bulma-components/styles.ts b/bestax-migrate/src/sources/react-bulma-components/styles.ts index 1e6a2211a..be21ffe6b 100644 --- a/bestax-migrate/src/sources/react-bulma-components/styles.ts +++ b/bestax-migrate/src/sources/react-bulma-components/styles.ts @@ -90,6 +90,19 @@ const EXTENSION_IMPORT = const RBC_STYLE_IMPORT = /^(\s*)@import\s+(['"])((?:\.\.?\/)+node_modules\/|~)?react-bulma-components\/[^'"]*\2\s*;?\s*$/; +/** + * The subset of RBC stylesheet imports that are the library's own *root*: the + * bare package specifier, the documented Sass entry point (`src/index`), and + * the bundled v3 CSS (`dist/react-bulma-components(.min).css`). These pull in + * the whole library, which `bulma/sass` supersedes — so when the file already + * has a Bulma root, dropping one of these loses nothing. A deep RBC partial + * (`src/components/navbar.sass`) is NOT a root: `bulma/sass` doesn't carry a + * given partial's styles, so removing one silently would drop CSS. We flag + * those instead (the package's "never a silent skip" rule). + */ +const RBC_ROOT_STYLESHEET = + /^\s*@import\s+(['"])(?:(?:\.\.?\/)+node_modules\/|~)?react-bulma-components(?:\/src\/index(?:\.s[ac]ss)?|\/dist\/react-bulma-components(?:\.min)?\.css)?\1\s*;?\s*$/; + /** * A Bulma module root already pulled in via `@use` — the file's own * `@use 'bulma/sass'` (any prefix, configured or not) or the bestax bundle @@ -405,21 +418,48 @@ export const transformStyles: StylesTransform = ( ? "replaced react-bulma-components's stylesheet import with bulma/sass; the package is removed from dependencies, so the old import would not resolve" : "replaced react-bulma-components's stylesheet import with bulma/sass; it is a Bulma 0.9 asset the migrated v1 components can't use (--no-deps left the package in place)" ); + } else { + // bestax/bulma modes rewrite the file's root without a TODO — still + // report it so the migration summary reflects the restructured root. + report( + collector, + filePath, + i + 1, + 'sass', + "replaced react-bulma-components's stylesheet import with a Bulma v1 @use root" + ); + } + } else { + // A Bulma root already covers this file (a `bulma/…` @import we + // convert, the file's own `@use` root, or an earlier RBC line we + // rewrote). In bestax mode keep that root and add only the extras — + // never a second root, never the configured bundle that would + // reconfigure an already-loaded module. + if (cssMode === 'bestax' && !extrasAdded) { + out.push( + prefix + ? `${indent}@use '${prefix}@allxsmith/bestax-bulma/src/scss/extras';` + : `${indent}${EXTRAS_USE}` + ); + extrasAdded = true; + } + // Dropping the RBC line is only safe for its root/index stylesheet, + // which `bulma/sass` supersedes. A deep RBC partial can carry styles + // `bulma/sass` doesn't, so removing it silently would lose CSS — flag + // it with a TODO + report entry instead (never a silent skip). + if (!RBC_ROOT_STYLESHEET.test(line)) { + out.push( + `${indent}// ${TODO}: dropped a react-bulma-components stylesheet partial that has no Bulma v1 root equivalent; port any styles it carried beyond Bulma's own by hand — see ${GUIDE}` + ); + report( + collector, + filePath, + i + 1, + 'sass', + 'react-bulma-components stylesheet partial dropped; port any styles it carried beyond Bulma’s own by hand' + ); } - } else if (cssMode === 'bestax' && !extrasAdded) { - // A Bulma root already exists in this file — a `bulma/…` @import we - // convert, or the file's own `@use` root. Keep it and add only the - // extras: never a second root, and never the configured bundle that - // would reconfigure an already-loaded module. - out.push( - prefix - ? `${indent}@use '${prefix}@allxsmith/bestax-bulma/src/scss/extras';` - : `${indent}${EXTRAS_USE}` - ); - extrasAdded = true; } - // Otherwise (bulma/keep with a root already present) the line is - // redundant — drop it rather than importing Bulma twice. changed = true; continue; } diff --git a/docs/docs/guides/getting-started/migration/react-bulma-components.md b/docs/docs/guides/getting-started/migration/react-bulma-components.md index 9141df727..6593e1002 100644 --- a/docs/docs/guides/getting-started/migration/react-bulma-components.md +++ b/docs/docs/guides/getting-started/migration/react-bulma-components.md @@ -66,8 +66,10 @@ in place: library being removed, not a third-party extension, so it is rewritten into that identical `@use 'bulma/sass'` (+ extras) root, folding any leading `$var` overrides, rather than the hard-configured `scss/bestax` bundle that couldn't take them. If the file already has its - own Bulma root the redundant line is dropped (the extras still added once). Computed - variables and indented-syntax `.sass` files are flagged instead of guessed at. + own Bulma root the redundant root/index line is dropped (the extras still added once); a + dropped RBC **deep partial** is flagged with a TODO instead, since `bulma/sass` may not + carry its styles. Computed variables and indented-syntax `.sass` files are flagged instead + of guessed at. - **Dependencies** — the nearest `package.json` drops `react-bulma-components`, gains `@allxsmith/bestax-bulma`, moves `bulma` to `^1.0.4`, and swaps the dead `node-sass` for dart `sass`. The codemod never runs an install — do that yourself afterwards. diff --git a/skills/bestax-migrate/references/css-migration.md b/skills/bestax-migrate/references/css-migration.md index 32aec868e..6882ea802 100644 --- a/skills/bestax-migrate/references/css-migration.md +++ b/skills/bestax-migrate/references/css-migration.md @@ -61,8 +61,12 @@ finish what it flagged. user's own theme vars, and reconfiguring `bulma/sass` when another file already configures it is a hard Sass error. If the file already has its own `bulma/…` root (a `@use 'bulma/sass'` of its own, or a Bulma `@import` the codemod converts), the RBC - line is dropped instead of emitting a second root; in `bestax` mode the extras are - added once alongside that existing root. + **root/index** line (`src/index`, the bundled `dist/*.css`, or the bare specifier) is + dropped instead of emitting a second root; in `bestax` mode the extras are added once + alongside that existing root. A dropped RBC **deep partial** (e.g. + `src/components/navbar.sass`) is different — `bulma/sass` doesn't necessarily carry a + given partial's styles, so it gets a `// TODO(bestax-migrate)` and a report entry + ("port any styles it carried beyond Bulma's own by hand") rather than vanishing silently. - **package.json**: `react-bulma-components` removed, `@allxsmith/bestax-bulma` added, `bulma` bumped to `^1.0.4` (or added when sources still import `bulma/…` directly),