Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bestax-mcp/data/skills.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@
{
"id": "css-migration",
"file": "references/css-migration.md",
"bytes": 5679
"bytes": 7457
},
{ "id": "prop-map", "file": "references/prop-map.md", "bytes": 6363 },
{
Expand Down
1 change: 1 addition & 0 deletions bestax-migrate/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ function migrateFiles(
output = source.transformStyles
? source.transformStyles(file, sourceText, collector, {
cssMode: options.cssMode,
deps: options.deps,
})
: null;
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,198 @@ 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 bulma/sass + extras', () => {
const { output } = run(
'main.scss',
"@import 'react-bulma-components/src/index.sass';\n"
);
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');
});

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 'bulma/sass';");
expect(output).toContain("@use '@allxsmith/bestax-bulma/scss/extras';");
});

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 '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', () => {
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)', () => {
Expand Down
Loading
Loading