diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b4e90f3..baff016 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -54,9 +54,44 @@ jobs: - name: Test run: pnpm run test + test-babel7: + timeout-minutes: 20 + runs-on: ubuntu-latest + name: 'Test: babel 7 compat' + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Install pnpm + uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0 + + - name: Set node version to 24 + uses: actions/setup-node@v6 + with: + node-version: 24 + cache: 'pnpm' + + - name: Override @babel/core to v7 + run: yq -i '.overrides."@babel/core" = "^7.29.0"' pnpm-workspace.yaml + + - name: Install deps + run: pnpm install --no-frozen-lockfile + + - name: Install @babel/core v7 types + run: pnpm add -Dw @types/babel__core@^7.20.5 + + - name: Build + run: pnpm run build + + - name: Test + run: pnpm run test + + - name: Lint (type check) + run: pnpm run lint + test-passed: if: (!cancelled() && !failure()) - needs: test + needs: [test, test-babel7] runs-on: ubuntu-latest name: Build & Test Passed or Skipped steps: @@ -64,7 +99,7 @@ jobs: test-failed: if: (!cancelled() && failure()) - needs: test + needs: [test, test-babel7] runs-on: ubuntu-latest name: Build & Test Failed steps: diff --git a/packages/babel/src/babelCompat.ts b/packages/babel/src/babelCompat.ts new file mode 100644 index 0000000..6497c78 --- /dev/null +++ b/packages/babel/src/babelCompat.ts @@ -0,0 +1,37 @@ +/** + * A type compatibility layer for Babel 7 and 8. + */ + +export * from '@babel/core' + +import * as babel from '@babel/core' + +// https://github.com/type-challenges/type-challenges/issues/29285 +type IsAny = boolean extends (T extends never ? true : false) ? true : false + +// @ts-ignore -- InputOptions doesn't exist in Babel 7 +type InputOptions8 = babel.InputOptions +// @ts-ignore -- PresetItem doesn't exist in Babel 7 +type PresetItem8 = babel.PresetItem +// @ts-ignore -- PluginObject doesn't exist in Babel 7 +type PluginObject8 = babel.PluginObject +// @ts-ignore -- FileResult doesn't exist in Babel 7 +type FileResult8 = babel.FileResult + +// @ts-ignore -- TransformOptions doesn't exist in Babel 8 +type TransformOptions = babel.TransformOptions +// @ts-ignore -- PluginObj doesn't exist in Babel 8 +type PluginObj = babel.PluginObj +// @ts-ignore -- BabelFileResult doesn't exist in Babel 8 +type BabelFileResult = babel.BabelFileResult + +export type InputOptions = IsAny extends false ? InputOptions8 : TransformOptions +export type PresetItem = IsAny extends false ? PresetItem8 : babel.PluginItem +export type PluginObject = + IsAny> extends false ? PluginObject8 : PluginObj +export type FileResult = IsAny extends false ? FileResult8 : BabelFileResult + +export const loadOptionsAsync: ( + options?: InputOptions, + // oxlint-disable-next-line typescript/no-unsafe-type-assertion +) => Promise = (babel as any).loadOptionsAsync diff --git a/packages/babel/src/filter.ts b/packages/babel/src/filter.ts index 1b706d5..6d85243 100644 --- a/packages/babel/src/filter.ts +++ b/packages/babel/src/filter.ts @@ -1,7 +1,7 @@ import type { HookFilter, GeneralHookFilter, ModuleTypeFilter } from 'rolldown' import type { ResolvedPluginOptions } from './options' import type { RolldownBabelPresetItem, RolldownBabelPreset } from './rolldownPreset' -import type { InputOptions } from '@babel/core' +import type { InputOptions } from './babelCompat' import { arrayify } from './utils' type ConfigApplicableTest = Exclude diff --git a/packages/babel/src/index.test.ts b/packages/babel/src/index.test.ts index 86b2d77..8475f24 100644 --- a/packages/babel/src/index.test.ts +++ b/packages/babel/src/index.test.ts @@ -1,11 +1,12 @@ import { assert, describe, expect, test } from 'vitest' import babelPlugin from './index.ts' -import * as babel from '@babel/core' +import * as babel from './babelCompat.ts' import { rolldown, type OutputChunk } from 'rolldown' import { build as viteBuild, createBuilder, type Rollup } from 'vite' import path from 'node:path' import { collectOptimizeDepsInclude, type PluginOptions } from './options.ts' import type { RolldownBabelPreset } from './rolldownPreset.ts' +import { stripVTControlCharacters } from 'node:util' test('plugin works', async () => { const result = await build('foo.js', 'export const result = foo', { @@ -226,7 +227,7 @@ test('wrapPluginVisitorMethod wraps visitor calls', async () => { const result = await build('foo.js', 'export const result = foo', { plugins: [identifierReplaceBabelPlugin('foo', true)], wrapPluginVisitorMethod(_pluginAlias, _visitorType, callback) { - return function (this, p, state) { + return function (this: any, p, state) { wrapCalled = true return callback.call(this, p, state) } @@ -553,7 +554,7 @@ test('babel syntax error produces enhanced error message', async () => { const err = await build('foo.js', 'export const = ;', { plugins: [identifierReplaceBabelPlugin('foo', true)], }).catch((e) => e) - const normalized = err.message + const normalized = stripVTControlCharacters(err.message) .replace(/\r\n/g, '\n') .replace(/(?:[A-Z]:)?[\\/][^\s:]+[\\/](?=foo\.js)/gi, '/') .replace(/\n {4,}at .+/g, '') diff --git a/packages/babel/src/index.ts b/packages/babel/src/index.ts index a030d0f..63db079 100644 --- a/packages/babel/src/index.ts +++ b/packages/babel/src/index.ts @@ -7,7 +7,7 @@ import { resolveOptions, type PluginOptions, } from './options.ts' -import * as babel from '@babel/core' +import * as babel from './babelCompat.ts' import type { PartialEnvironment, PresetConversionContext } from './rolldownPreset.ts' import { calculatePluginFilters } from './filter.ts' import type { ResolvedConfig, Plugin as VitePlugin } from 'vite' diff --git a/packages/babel/src/options.ts b/packages/babel/src/options.ts index 8bec7d7..cbf1ad0 100644 --- a/packages/babel/src/options.ts +++ b/packages/babel/src/options.ts @@ -1,4 +1,4 @@ -import * as babel from '@babel/core' +import * as babel from './babelCompat' import type { ResolvedConfig } from 'vite' import { compilePresetFilter, diff --git a/packages/babel/src/rolldownPreset.test.ts b/packages/babel/src/rolldownPreset.test.ts index 7499b8f..e0e5d39 100644 --- a/packages/babel/src/rolldownPreset.test.ts +++ b/packages/babel/src/rolldownPreset.test.ts @@ -11,7 +11,7 @@ import type { PresetConversionContext, RolldownBabelPreset, } from './rolldownPreset.ts' -import type * as babel from '@babel/core' +import type * as babel from './babelCompat.ts' import type { ResolvedConfig } from 'vite' const presetA: babel.PresetItem = () => ({ plugins: [] }) diff --git a/packages/babel/src/rolldownPreset.ts b/packages/babel/src/rolldownPreset.ts index 01c6c47..7937b14 100644 --- a/packages/babel/src/rolldownPreset.ts +++ b/packages/babel/src/rolldownPreset.ts @@ -1,4 +1,4 @@ -import * as babel from '@babel/core' +import * as babel from './babelCompat.ts' import type { GeneralHookFilter, ModuleTypeFilter } from 'rolldown' import type { ResolvedConfig, Plugin as VitePlugin } from 'vite' import picomatch from 'picomatch'