diff --git a/.changeset/tidy-beans-smile.md b/.changeset/tidy-beans-smile.md new file mode 100644 index 00000000000..627d1d9ef34 --- /dev/null +++ b/.changeset/tidy-beans-smile.md @@ -0,0 +1,5 @@ +--- +'react-docgen': patch +--- + +Support Babel 8 dependency overrides for parsing and traversal, including TypeScript generic props, inherited interfaces, function types, and mapped types. Preserve Babel 7 compatibility. diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a6a023e8df2..e56fd706e21 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,16 +15,35 @@ env: jobs: tests: strategy: + fail-fast: false matrix: - node: ["20.9.0", "22", "24", "25"] - os: ["ubuntu"] + babel: ['7', '8'] + node: ['20.9.0', '22', '24', '25'] + os: ['ubuntu'] + exclude: + # Keep Node.js 20 support for Babel 7; Babel 8 requires a newer Node.js. + - babel: '8' + node: '20.9.0' include: + - os: ubuntu + node: '22.18.0' + babel: '8' - os: macos - node: "24" + node: '24' + babel: '7' + - os: macos + node: '24' + babel: '8' + - os: windows + node: '24' + babel: '7' - os: windows - node: "24" + node: '24' + babel: '8' - name: Tests (Node.js v${{ matrix.node }}, ${{ matrix.os }}) + name: + Tests (Babel ${{ matrix.babel }}, Node.js v${{ matrix.node }}, ${{ + matrix.os }}) runs-on: ${{ matrix.os }}-latest steps: @@ -38,26 +57,43 @@ jobs: uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 with: node-version: ${{ matrix.node }} - cache: "pnpm" + cache: 'pnpm' - name: Install dependencies run: pnpm install --frozen-lockfile + # Compile against the declared Babel 7 types before testing each runtime. + - name: Build packages + run: pnpm build + + - name: Install Babel 8 runtime + if: "${{ matrix.babel == '8' }}" + run: + pnpm --filter react-docgen add --save-exact @babel/core@8.0.1 + @babel/traverse@8.0.4 @babel/types@8.0.4 + + - name: Check consumer declarations + run: pnpm --filter react-docgen exec tsc -p tests/types/tsconfig.json + - name: Unit tests with coverage - if: "${{ matrix.node == env.NODE_VERSION }}" - run: pnpm test -- --coverage + if: '${{ matrix.node == env.NODE_VERSION }}' + run: + pnpm --filter react-docgen --filter @react-docgen/cli --parallel + --no-bail test --coverage - name: Unit tests - if: "${{ matrix.node != env.NODE_VERSION }}" - run: pnpm test + if: '${{ matrix.node != env.NODE_VERSION }}' + run: + pnpm --filter react-docgen --filter @react-docgen/cli --parallel + --no-bail test - name: Upload coverage - if: "${{ matrix.node == env.NODE_VERSION }}" + if: '${{ matrix.node == env.NODE_VERSION }}' continue-on-error: true uses: coverallsapp/github-action@5cbfd81b66ca5d10c19b062c04de0199c215fb6e # v2 with: parallel: true - flag-name: test-${{ matrix.os }} + flag-name: test-babel-${{ matrix.babel }}-${{ matrix.os }} finish: needs: tests @@ -85,7 +121,7 @@ jobs: uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 with: node-version: lts/* - cache: "pnpm" + cache: 'pnpm' - name: Install dependencies run: pnpm install --frozen-lockfile @@ -108,7 +144,7 @@ jobs: uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 with: node-version: lts/* - cache: "pnpm" + cache: 'pnpm' - name: Install dependencies run: pnpm install --frozen-lockfile diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7b34655b005..919841b8444 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,25 +1,54 @@ # Contributing to react-docgen + We want to make contributing to this project as easy and transparent as possible. ## Our Development Process -The majority of development on react-docgen will occur through GitHub. Accordingly, -the process for contributing will follow standard GitHub protocol. + +The majority of development on react-docgen will occur through GitHub. +Accordingly, the process for contributing will follow standard GitHub protocol. ## Pull Requests + We actively welcome your pull requests. + 1. Fork the repo and create your branch from `main`. 2. If you've added code that should be tested, add tests 3. If you've changed APIs, update the documentation. 4. Ensure the test suite passes. 5. Make sure your code lints and typechecks. +## Babel compatibility tests + +CI runs all library and CLI tests separately with Babel 7 and Babel 8. Both runs +build with the declared Babel 7 dependencies first. The Babel 8 run then +replaces the runtime dependencies, including those used by CLI subprocesses. +This checks runtime compatibility, not compilation with Babel 8 types. + +To reproduce the Babel 8 run in a clean checkout: + +Use Node.js 22.18.0 or newer on the 22.x line, or Node.js 24.11.0 or newer. + +```sh +pnpm install --frozen-lockfile +pnpm build +pnpm --filter react-docgen add --save-exact @babel/core@8.0.1 @babel/traverse@8.0.4 @babel/types@8.0.4 +pnpm --filter react-docgen --filter @react-docgen/cli --parallel --no-bail test --coverage +``` + +The install command changes `packages/react-docgen/package.json` and +`pnpm-lock.yaml`. After testing, restore those two files and run +`pnpm install --frozen-lockfile` to return to Babel 7. + ## Issues + We use GitHub issues to track public bugs. Please ensure your description is clear and has sufficient instructions to be able to reproduce the issue. ## License -react-docgen is [MIT licensed](https://github.com/reactjs/react-docgen/blob/master/LICENSE). -By contributing to react-docgen, you agree that your contributions will be licensed -under its MIT license. +react-docgen is +[MIT licensed](https://github.com/reactjs/react-docgen/blob/master/LICENSE). + +By contributing to react-docgen, you agree that your contributions will be +licensed under its MIT license. diff --git a/packages/react-docgen-cli/tests/integration/utils/withFixture.ts b/packages/react-docgen-cli/tests/integration/utils/withFixture.ts index 73b8fd3c042..7e7780e19e8 100644 --- a/packages/react-docgen-cli/tests/integration/utils/withFixture.ts +++ b/packages/react-docgen-cli/tests/integration/utils/withFixture.ts @@ -24,6 +24,8 @@ export default async function withFixture( async function run(args: readonly string[]) { return execaNode(cliBinary, args, { cwd: tempDir, + // Pinned browser data ages independently of the CLI behavior under test. + env: { BROWSERSLIST_IGNORE_OLD_DATA: 'true' }, lines: false, reject: false, }); diff --git a/packages/react-docgen/package.json b/packages/react-docgen/package.json index 493c1f129ed..16114d780c1 100644 --- a/packages/react-docgen/package.json +++ b/packages/react-docgen/package.json @@ -44,6 +44,7 @@ "@babel/types": "^7.28.2", "@types/babel__core": "^7.20.5", "@types/babel__traverse": "^7.20.7", + "@types/convert-source-map": "^2.0.3", "@types/doctrine": "^0.0.9", "@types/resolve": "^1.20.2", "doctrine": "^3.0.0", diff --git a/packages/react-docgen/src/FileState.ts b/packages/react-docgen/src/FileState.ts index 239a533e673..e08370f8dd8 100644 --- a/packages/react-docgen/src/FileState.ts +++ b/packages/react-docgen/src/FileState.ts @@ -3,13 +3,13 @@ import babelTraverse, { NodePath } from '@babel/traverse'; import type { File, Node, Program } from '@babel/types'; import type { Importer, ImportPath } from './importer/index.js'; import babelParse from './babelParser.js'; -import type { TransformOptions } from '@babel/core'; +import type { Config } from './config.js'; // Workaround while babel is not a proper ES module const traverse = babelTraverse.default ?? (babelTraverse as never); export default class FileState { - opts: TransformOptions; + opts: NonNullable; path: NodePath; ast: File; scope: Scope; @@ -39,7 +39,7 @@ export default class FileState { }; constructor( - options: TransformOptions, + options: NonNullable, { code, ast, importer }: { code: string; ast: File; importer: Importer }, ) { this.opts = options; diff --git a/packages/react-docgen/src/__tests__/parserCompatibility-test.ts b/packages/react-docgen/src/__tests__/parserCompatibility-test.ts new file mode 100644 index 00000000000..c7e91239747 --- /dev/null +++ b/packages/react-docgen/src/__tests__/parserCompatibility-test.ts @@ -0,0 +1,139 @@ +import { version } from '@babel/core'; +import { parse } from '../main.js'; +import { expect, test } from 'vitest'; + +test('parses components', () => { + const result = parse('export function Button() { return