Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
5 changes: 5 additions & 0 deletions packages/sucrase/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,15 @@ Then call `rollup` either via the [CLI](https://www.rollupjs.org/guide/en/#comma

The following [Sucrase options](https://github.com/alangpierce/sucrase#transforms) may be passed as options for this plugin:

- `disableESTransforms`
- `enableLegacyBabel5ModuleInterop`
- `enableLegacyTypeScriptModuleInterop`
- `injectCreateRequireForImportRequire`
- `jsxFragmentPragma`
- `jsxImportSource`
- `jsxPragma`
- `jsxRuntime`
- `preserveDynamicImport`
- `production`
- `transforms`

Expand Down
6 changes: 5 additions & 1 deletion packages/sucrase/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export default function sucrase(opts = {}) {
// eslint-disable-next-line consistent-return
resolveId(importee, importer) {
if (importer && /^[./]/.test(importee)) {
const resolved = path.resolve(importer ? path.dirname(importer) : process.cwd(), importee);
const resolved = path.resolve(path.dirname(importer), importee);
// resolve in the same order that TypeScript resolves modules
const resolvedFilenames = [
`${resolved}.ts`,
Expand Down Expand Up @@ -42,8 +42,12 @@ export default function sucrase(opts = {}) {

const result = transform(code, {
transforms: opts.transforms,
jsxRuntime: opts.jsxRuntime,
jsxImportSource: opts.jsxImportSource,
jsxPragma: opts.jsxPragma,
jsxFragmentPragma: opts.jsxFragmentPragma,
preserveDynamicImport: opts.preserveDynamicImport,
injectCreateRequireForImportRequire: opts.injectCreateRequireForImportRequire,
Comment on lines 44 to +50

Copilot AI Feb 13, 2026

Copy link

Choose a reason for hiding this comment

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

Newly supported Sucrase options are now forwarded to transform (jsxImportSource, preserveDynamicImport, injectCreateRequireForImportRequire), but there are no runtime tests asserting these options actually affect output. Add focused tests/fixtures for at least jsxImportSource (and ideally the other two) to prevent regressions where the options stop being passed through.

Copilot uses AI. Check for mistakes.
enableLegacyTypeScriptModuleInterop: opts.enableLegacyTypeScriptModuleInterop,
enableLegacyBabel5ModuleInterop: opts.enableLegacyBabel5ModuleInterop,
production: opts.production,
Expand Down
1 change: 1 addition & 0 deletions packages/sucrase/test/fixtures/jsx-runtime/example.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default () => <div id="foo">hello world</div>
4 changes: 4 additions & 0 deletions packages/sucrase/test/fixtures/jsx-runtime/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/* eslint-disable import/extensions */
import example from './example.jsx';

t.snapshot(example.toString());
14 changes: 7 additions & 7 deletions packages/sucrase/test/snapshots/test.js.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ Generated by [AVA](https://avajs.dev).

> Snapshot 1

'() => React.createElement(\'div\', { id: "foo", __self: undefined, __source: {fileName: _jsxFileName, lineNumber: 1}}, "hello world" )'
'() => React.createElement(\'div\', { id: "foo", __self: this, __source: {fileName: _jsxFileName, lineNumber: 1}}, "hello world" )'

## converts jsx with custom jsxPragma

> Snapshot 1

'() => FakeReactCreateElement(\'div\', { id: "foo", __self: undefined, __source: {fileName: _jsxFileName, lineNumber: 1}}, "hello world" )'
'() => FakeReactCreateElement(\'div\', { id: "foo", __self: this, __source: {fileName: _jsxFileName, lineNumber: 1}}, "hello world" )'

## converts typescript

Expand Down Expand Up @@ -54,20 +54,20 @@ Generated by [AVA](https://avajs.dev).

> Snapshot 1

'() => React.createElement(\'div\', { id: "foo", __self: undefined, __source: {fileName: _jsxFileName$4, lineNumber: 1}}, "hello world" )'
'() => React.createElement(\'div\', { id: "foo", __self: this, __source: {fileName: _jsxFileName$4, lineNumber: 1}}, "hello world" )'

> Snapshot 2

'() => React.createElement(\'div\', { id: "example-b", __self: undefined, __source: {fileName: _jsxFileName$3, lineNumber: 1}}, "hello world (a second time)" )'
'() => React.createElement(\'div\', { id: "example-b", __self: this, __source: {fileName: _jsxFileName$3, lineNumber: 1}}, "hello world (a second time)" )'

> Snapshot 3

'() => React.createElement(\'div\', { id: "foo", __self: undefined, __source: {fileName: _jsxFileName$2, lineNumber: 1}}, "hello world" )'
'() => React.createElement(\'div\', { id: "foo", __self: this, __source: {fileName: _jsxFileName$2, lineNumber: 1}}, "hello world" )'

> Snapshot 4

'() => React.createElement(\'div\', { id: "foo", __self: undefined, __source: {fileName: _jsxFileName$1, lineNumber: 1}}, "hello world" )'
'() => React.createElement(\'div\', { id: "foo", __self: this, __source: {fileName: _jsxFileName$1, lineNumber: 1}}, "hello world" )'

> Snapshot 5

'() => React.createElement(\'div\', { id: "foo", __self: undefined, __source: {fileName: _jsxFileName, lineNumber: 1}}, "hello world" )'
'() => React.createElement(\'div\', { id: "foo", __self: this, __source: {fileName: _jsxFileName, lineNumber: 1}}, "hello world" )'
Binary file modified packages/sucrase/test/snapshots/test.js.snap
Binary file not shown.
84 changes: 43 additions & 41 deletions packages/sucrase/test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,42 +14,56 @@ require('source-map-support').install();

process.chdir(__dirname);

test('converts jsx', async (t) => {
const bundle = await rollup({
input: 'fixtures/jsx/main.js',
plugins: [
sucrase({
transforms: ['jsx']
})
]
function getBundle(input, sucraseOptions, rollupOptions) {
return rollup({
input,
context: 'this',
Comment thread
shellscape marked this conversation as resolved.
plugins: [sucrase(sucraseOptions)],
...rollupOptions
});
}

test('calls without options', async (t) => {
const plugin = sucrase();
t.is(plugin.name, 'sucrase');
});

test('does not transform files excluded by filter', async (t) => {
const plugin = sucrase({ exclude: '**/*.ts', transforms: ['typescript'] });
const result = plugin.transform('const x: number = 1;', 'foo.ts');
t.is(result, null);
});

test('converts jsx', async (t) => {
const bundle = await getBundle('fixtures/jsx/main.js', { transforms: ['jsx'] });
t.plan(1);
return testBundle(t, bundle);
});

test('converts jsx with custom jsxPragma', async (t) => {
const bundle = await rollup({
input: 'fixtures/jsx/main.js',
plugins: [
sucrase({
transforms: ['jsx'],
jsxPragma: 'FakeReactCreateElement'
})
]
const bundle = await getBundle('fixtures/jsx/main.js', {
transforms: ['jsx'],
jsxPragma: 'FakeReactCreateElement'
});
t.plan(1);
return testBundle(t, bundle);
});

test('converts jsx with jsxRuntime automatic', async (t) => {
const bundle = await getBundle(
'fixtures/jsx-runtime/main.js',
{ transforms: ['jsx'], jsxRuntime: 'automatic' },
{ external: ['react/jsx-dev-runtime'] }
);
const { output } = await bundle.generate({ format: 'cjs', exports: 'auto' });
const [{ code }] = output;
// Check that the code uses the automatic runtime instead of React.createElement
t.regex(code, /require\(['"]react\/jsx-dev-runtime['"]\)/);
t.notRegex(code, /React\.createElement/);
});

test('converts typescript', async (t) => {
const bundle = await rollup({
input: 'fixtures/typescript/main.js',
plugins: [
sucrase({
transforms: ['typescript']
})
]
});
const bundle = await getBundle('fixtures/typescript/main.js', { transforms: ['typescript'] });
t.plan(4);
return testBundle(t, bundle);
});
Expand All @@ -60,9 +74,7 @@ if (process.platform !== 'win32') {
const bundle = await rollup({
input: 'fixtures/typescript-with-aliases/main.js',
plugins: [
sucrase({
transforms: ['typescript']
}),
sucrase({ transforms: ['typescript'] }),
alias({
entries: [
{
Expand All @@ -80,27 +92,17 @@ if (process.platform !== 'win32') {
}

test('resolves typescript directory imports', async (t) => {
const bundle = await rollup({
input: 'fixtures/typescript-resolve-directory/main.js',
plugins: [
sucrase({
transforms: ['typescript']
})
]
const bundle = await getBundle('fixtures/typescript-resolve-directory/main.js', {
transforms: ['typescript']
});
t.plan(2);

return testBundle(t, bundle);
});

test('converts typescript jsx ("tsx")', async (t) => {
const bundle = await rollup({
input: 'fixtures/typescript-with-tsx/main.js',
plugins: [
sucrase({
transforms: ['typescript', 'jsx']
})
]
const bundle = await getBundle('fixtures/typescript-with-tsx/main.js', {
transforms: ['typescript', 'jsx']
});
t.plan(5);

Expand Down
4 changes: 4 additions & 0 deletions packages/sucrase/test/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ const config: RollupOptions = {
enableLegacyTypeScriptModuleInterop: true,
jsxFragmentPragma: 'React.fragment',
jsxPragma: 'React',
jsxRuntime: 'automatic',
jsxImportSource: 'preact',
preserveDynamicImport: true,
injectCreateRequireForImportRequire: true,
production: true,
disableESTransforms: true,
transforms: ['jsx']
Expand Down
4 changes: 4 additions & 0 deletions packages/sucrase/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@ interface RollupSucraseOptions
extends Pick<
SucraseOptions,
| 'transforms'
| 'jsxRuntime'
| 'jsxImportSource'
| 'jsxPragma'
| 'jsxFragmentPragma'
| 'preserveDynamicImport'
| 'injectCreateRequireForImportRequire'
| 'enableLegacyTypeScriptModuleInterop'
| 'enableLegacyBabel5ModuleInterop'
| 'production'
Expand Down
Loading