From a4afdc7153a4d14da34d8de5d906a829fb52360f Mon Sep 17 00:00:00 2001 From: naporin0624 Date: Fri, 9 Feb 2024 17:10:47 +0900 Subject: [PATCH 01/77] chore(docs): fix glob pattern jest --- docs/snippets/common/portable-stories-jest-snapshot-test.js.mdx | 2 +- docs/snippets/common/portable-stories-jest-snapshot-test.ts.mdx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/snippets/common/portable-stories-jest-snapshot-test.js.mdx b/docs/snippets/common/portable-stories-jest-snapshot-test.js.mdx index 8a6f022a9492..4078691b055d 100644 --- a/docs/snippets/common/portable-stories-jest-snapshot-test.js.mdx +++ b/docs/snippets/common/portable-stories-jest-snapshot-test.js.mdx @@ -25,7 +25,7 @@ const compose = (entry) => { function getAllStoryFiles() { // Place the glob you want to match your stories files const storyFiles = glob.sync( - path.join(__dirname, 'stories/**/*.(stories|story).@(js|jsx|mjs|ts|tsx)'), + path.join(__dirname, 'stories/**/*.{stories,story}.{js,jsx,mjs,ts,tsx}'), ); return storyFiles.map((filePath) => { diff --git a/docs/snippets/common/portable-stories-jest-snapshot-test.ts.mdx b/docs/snippets/common/portable-stories-jest-snapshot-test.ts.mdx index 45bcd3d4f7f1..07bb7a277c60 100644 --- a/docs/snippets/common/portable-stories-jest-snapshot-test.ts.mdx +++ b/docs/snippets/common/portable-stories-jest-snapshot-test.ts.mdx @@ -33,7 +33,7 @@ const compose = (entry: StoryFile): ReturnType> function getAllStoryFiles() { // Place the glob you want to match your stories files const storyFiles = glob.sync( - path.join(__dirname, 'stories/**/*.(stories|story).@(js|jsx|mjs|ts|tsx)'), + path.join(__dirname, 'stories/**/*.{stories,story}.{js,jsx,mjs,ts,tsx}'), ); return storyFiles.map((filePath) => { From 11a848414e651bf44bce6abbf3c15d793cf6179b Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Fri, 9 Feb 2024 23:06:36 +0100 Subject: [PATCH 02/77] consolidate generate-sandboxes workflows into a single workflow and composite action --- .../generate-sandboxes-composite-action.yml | 58 ++++++++++++++++++ .github/workflows/generate-sandboxes-main.yml | 60 ------------------- .github/workflows/generate-sandboxes.yml | 34 +++++++++++ 3 files changed, 92 insertions(+), 60 deletions(-) create mode 100644 .github/actions/generate-sandboxes-composite-action.yml delete mode 100644 .github/workflows/generate-sandboxes-main.yml create mode 100644 .github/workflows/generate-sandboxes.yml diff --git a/.github/actions/generate-sandboxes-composite-action.yml b/.github/actions/generate-sandboxes-composite-action.yml new file mode 100644 index 000000000000..d47166c73ec4 --- /dev/null +++ b/.github/actions/generate-sandboxes-composite-action.yml @@ -0,0 +1,58 @@ +name: Generate and push sandboxes action +description: This is a composite action that generates sandboxes and pushes them to the storybookjs/sandboxes repository + +inputs: + destination-branch: + description: The destination branch to generate sandboxes to in the storybookjs/sandboxes repository + required: true + +defaults: + run: + shell: bash + working-directory: ./code + +runs: + using: "composite" + steps: + - uses: actions/setup-node@v3 + with: + node-version-file: ".nvmrc" + + - name: Setup git user + run: | + git config --global user.name "storybook-bot" + git config --global user.email "32066757+storybook-bot@users.noreply.github.com" + + - name: Install dependencies + working-directory: ./scripts + env: + YARN_ENABLE_IMMUTABLE_INSTALLS: false + run: node --experimental-modules ./check-dependencies.js + + - name: Compile Storybook libraries + run: yarn task --task compile --start-from=auto --no-link + + - name: Publish to local registry + run: yarn local-registry --publish + + - name: Run local registry + run: yarn local-registry --open & + + - name: Wait for registry + run: yarn wait-on tcp:127.0.0.1:6001 + + - name: Generate + env: + CLEANUP_SANDBOX_NODE_MODULES: true + run: yarn generate-sandboxes --local-registry + + - name: Publish + run: yarn publish-sandboxes --remote=https://storybook-bot:${{ secrets.PAT_STORYBOOK_BOT}}@github.com/storybookjs/sandboxes.git --push --branch=${{ inputs.destination-branch }} + + - name: The job has failed + if: ${{ failure() || cancelled() }} + env: + DISCORD_WEBHOOK: ${{ secrets.DISCORD_MONITORING_URL }} + uses: Ilshidur/action-discord@master + with: + args: "The generation of sandboxes in the **${{ inputs.destination-branch }}** branch has failed. [View Run](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})" diff --git a/.github/workflows/generate-sandboxes-main.yml b/.github/workflows/generate-sandboxes-main.yml deleted file mode 100644 index cc17376c57de..000000000000 --- a/.github/workflows/generate-sandboxes-main.yml +++ /dev/null @@ -1,60 +0,0 @@ -name: Generate and push sandboxes (main) - -on: - schedule: - - cron: '2 2 */1 * *' - workflow_dispatch: - # To test fixes on push rather than wait for the scheduling, do the following: - # 1. Uncomment the lines below and add your branch. - # push: - # branches: - # - - # 2. change the "ref" value to in the actions/checkout step below. - # 3. πŸ‘‰ DON'T FORGET TO UNDO THE VALUES BACK TO `main` BEFORE YOU MERGE YOUR CHANGES! - -jobs: - generate: - runs-on: ubuntu-latest - env: - YARN_ENABLE_IMMUTABLE_INSTALLS: false - CLEANUP_SANDBOX_NODE_MODULES: true - steps: - - uses: actions/checkout@v3 - with: - ref: main - - uses: actions/setup-node@v3 - with: - node-version-file: '.nvmrc' - - name: Setup git user - run: | - git config --global user.name "Storybook Bot" - git config --global user.email "bot@storybook.js.org" - - name: Install dependencies - run: | - cd ./scripts - node --experimental-modules ./check-dependencies.js - cd .. - - name: Compile Storybook libraries - run: yarn task --task compile --start-from=auto --no-link - - name: Publishing to local registry - run: yarn local-registry --publish - working-directory: ./code - - name: Running local registry - run: yarn local-registry --open & - working-directory: ./code - - name: Wait for registry - run: yarn wait-on tcp:127.0.0.1:6001 - working-directory: ./code - - name: Generate - run: yarn generate-sandboxes --local-registry - working-directory: ./code - - name: Publish - run: yarn publish-sandboxes --remote=https://storybook-bot:${{ secrets.PAT_STORYBOOK_BOT}}@github.com/storybookjs/sandboxes.git --push --branch=main - working-directory: ./code - - name: The job has failed - if: ${{ failure() || cancelled() }} - env: - DISCORD_WEBHOOK: ${{ secrets.DISCORD_MONITORING_URL }} - uses: Ilshidur/action-discord@master - with: - args: 'The generation of sandboxes in the **main** branch has failed. [View Run](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})' diff --git a/.github/workflows/generate-sandboxes.yml b/.github/workflows/generate-sandboxes.yml new file mode 100644 index 000000000000..dd80cefcb790 --- /dev/null +++ b/.github/workflows/generate-sandboxes.yml @@ -0,0 +1,34 @@ +name: Generate and push sandboxes + +on: + schedule: + - cron: "2 2 */1 * *" + workflow_dispatch: + # To test fixes on push rather than wait for the scheduling, do the following: + # 1. Uncomment the lines below and add your branch. + # push: + # branches: + # - + # 2. Change the "ref" value to in the actions/checkout step below. + # 3. Comment out the whole "generate-main" job starting at line 26 + # 3. πŸ‘‰ DON'T FORGET TO UNDO STEP 2 AND 3 BEFORE YOU MERGE YOUR CHANGES! + +jobs: + generate-next: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: next + - uses: .github/actions/generate-sandboxes-composite-action.yml + with: + destination-branch: next + generate-main: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: main + - uses: .github/actions/generate-sandboxes-composite-action.yml + with: + destination-branch: main From 81abd2ac5f5f5c0f6b2a1d65b1972650cf86949e Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Fri, 9 Feb 2024 23:08:06 +0100 Subject: [PATCH 03/77] temporarily test this branch as for sandbox generation --- .github/workflows/generate-sandboxes.yml | 26 ++++++++++++------------ 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/workflows/generate-sandboxes.yml b/.github/workflows/generate-sandboxes.yml index dd80cefcb790..af353f6b19aa 100644 --- a/.github/workflows/generate-sandboxes.yml +++ b/.github/workflows/generate-sandboxes.yml @@ -6,9 +6,9 @@ on: workflow_dispatch: # To test fixes on push rather than wait for the scheduling, do the following: # 1. Uncomment the lines below and add your branch. - # push: - # branches: - # - + push: + branches: + - jeppe/25922-ci-generation-of-sandboxes-fail-sometimes-on-prereleases # 2. Change the "ref" value to in the actions/checkout step below. # 3. Comment out the whole "generate-main" job starting at line 26 # 3. πŸ‘‰ DON'T FORGET TO UNDO STEP 2 AND 3 BEFORE YOU MERGE YOUR CHANGES! @@ -19,16 +19,16 @@ jobs: steps: - uses: actions/checkout@v4 with: - ref: next + ref: jeppe/25922-ci-generation-of-sandboxes-fail-sometimes-on-prereleases - uses: .github/actions/generate-sandboxes-composite-action.yml with: destination-branch: next - generate-main: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - ref: main - - uses: .github/actions/generate-sandboxes-composite-action.yml - with: - destination-branch: main + # generate-main: + # runs-on: ubuntu-latest + # steps: + # - uses: actions/checkout@v4 + # with: + # ref: main + # - uses: .github/actions/generate-sandboxes-composite-action.yml + # with: + # destination-branch: main From 658f715228ae08b5f7187e13ed94e40392c6447c Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Fri, 9 Feb 2024 23:09:11 +0100 Subject: [PATCH 04/77] correct syntax for local composite actions --- .github/workflows/generate-sandboxes.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/generate-sandboxes.yml b/.github/workflows/generate-sandboxes.yml index af353f6b19aa..a138a7ebe4ef 100644 --- a/.github/workflows/generate-sandboxes.yml +++ b/.github/workflows/generate-sandboxes.yml @@ -20,7 +20,7 @@ jobs: - uses: actions/checkout@v4 with: ref: jeppe/25922-ci-generation-of-sandboxes-fail-sometimes-on-prereleases - - uses: .github/actions/generate-sandboxes-composite-action.yml + - uses: ./.github/actions/generate-sandboxes-composite-action.yml with: destination-branch: next # generate-main: @@ -29,6 +29,6 @@ jobs: # - uses: actions/checkout@v4 # with: # ref: main - # - uses: .github/actions/generate-sandboxes-composite-action.yml + # - uses: ./.github/actions/generate-sandboxes-composite-action.yml # with: # destination-branch: main From a38557413a09dcdc0dafee7c1cf6c6f61a07c68b Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Fri, 9 Feb 2024 23:12:07 +0100 Subject: [PATCH 05/77] correcterer composite action syntax --- .github/workflows/generate-sandboxes.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/generate-sandboxes.yml b/.github/workflows/generate-sandboxes.yml index a138a7ebe4ef..0f6b5e992e7d 100644 --- a/.github/workflows/generate-sandboxes.yml +++ b/.github/workflows/generate-sandboxes.yml @@ -20,7 +20,7 @@ jobs: - uses: actions/checkout@v4 with: ref: jeppe/25922-ci-generation-of-sandboxes-fail-sometimes-on-prereleases - - uses: ./.github/actions/generate-sandboxes-composite-action.yml + - uses: ./.github/actions/generate-sandboxes-composite-action with: destination-branch: next # generate-main: @@ -29,6 +29,6 @@ jobs: # - uses: actions/checkout@v4 # with: # ref: main - # - uses: ./.github/actions/generate-sandboxes-composite-action.yml + # - uses: ./.github/actions/generate-sandboxes-composite-action # with: # destination-branch: main From 871e1b17f78721e05d67bde518c3e63879d48e09 Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Fri, 9 Feb 2024 23:16:08 +0100 Subject: [PATCH 06/77] correctest composite action syntax --- .../action.yml} | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) rename .github/actions/{generate-sandboxes-composite-action.yml => generate-sandboxes-composite-action/action.yml} (88%) diff --git a/.github/actions/generate-sandboxes-composite-action.yml b/.github/actions/generate-sandboxes-composite-action/action.yml similarity index 88% rename from .github/actions/generate-sandboxes-composite-action.yml rename to .github/actions/generate-sandboxes-composite-action/action.yml index d47166c73ec4..e2d84a2c283d 100644 --- a/.github/actions/generate-sandboxes-composite-action.yml +++ b/.github/actions/generate-sandboxes-composite-action/action.yml @@ -6,11 +6,6 @@ inputs: description: The destination branch to generate sandboxes to in the storybookjs/sandboxes repository required: true -defaults: - run: - shell: bash - working-directory: ./code - runs: using: "composite" steps: @@ -19,34 +14,42 @@ runs: node-version-file: ".nvmrc" - name: Setup git user + shell: bash run: | git config --global user.name "storybook-bot" git config --global user.email "32066757+storybook-bot@users.noreply.github.com" - name: Install dependencies + shell: bash working-directory: ./scripts env: - YARN_ENABLE_IMMUTABLE_INSTALLS: false + YARN_ENABLE_IMMUTABLE_INSTALLS: "false" run: node --experimental-modules ./check-dependencies.js - name: Compile Storybook libraries + shell: bash run: yarn task --task compile --start-from=auto --no-link - name: Publish to local registry + shell: bash run: yarn local-registry --publish - name: Run local registry + shell: bash run: yarn local-registry --open & - name: Wait for registry + shell: bash run: yarn wait-on tcp:127.0.0.1:6001 - name: Generate + shell: bash env: - CLEANUP_SANDBOX_NODE_MODULES: true + CLEANUP_SANDBOX_NODE_MODULES: "true" run: yarn generate-sandboxes --local-registry - name: Publish + shell: bash run: yarn publish-sandboxes --remote=https://storybook-bot:${{ secrets.PAT_STORYBOOK_BOT}}@github.com/storybookjs/sandboxes.git --push --branch=${{ inputs.destination-branch }} - name: The job has failed From bb0d0d0f7ea919118d275c0c10833ced6297db96 Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Fri, 9 Feb 2024 23:20:38 +0100 Subject: [PATCH 07/77] move secrets to workflow --- .../generate-sandboxes-composite-action/action.yml | 10 ++++++++-- .github/workflows/generate-sandboxes.yml | 7 +++++++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/.github/actions/generate-sandboxes-composite-action/action.yml b/.github/actions/generate-sandboxes-composite-action/action.yml index e2d84a2c283d..a4f0112731e7 100644 --- a/.github/actions/generate-sandboxes-composite-action/action.yml +++ b/.github/actions/generate-sandboxes-composite-action/action.yml @@ -5,6 +5,12 @@ inputs: destination-branch: description: The destination branch to generate sandboxes to in the storybookjs/sandboxes repository required: true + token: + description: The personal access token to use when authenticating with the destination repository + required: true + discord-url: + description: The Discord URL to use when reporting failures + required: true runs: using: "composite" @@ -50,12 +56,12 @@ runs: - name: Publish shell: bash - run: yarn publish-sandboxes --remote=https://storybook-bot:${{ secrets.PAT_STORYBOOK_BOT}}@github.com/storybookjs/sandboxes.git --push --branch=${{ inputs.destination-branch }} + run: yarn publish-sandboxes --remote=https://storybook-bot:${{ inputs.token }}@github.com/storybookjs/sandboxes.git --push --branch=${{ inputs.destination-branch }} - name: The job has failed if: ${{ failure() || cancelled() }} env: - DISCORD_WEBHOOK: ${{ secrets.DISCORD_MONITORING_URL }} + DISCORD_WEBHOOK: ${{ inputs.discord-url }} uses: Ilshidur/action-discord@master with: args: "The generation of sandboxes in the **${{ inputs.destination-branch }}** branch has failed. [View Run](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})" diff --git a/.github/workflows/generate-sandboxes.yml b/.github/workflows/generate-sandboxes.yml index 0f6b5e992e7d..942ad7527d42 100644 --- a/.github/workflows/generate-sandboxes.yml +++ b/.github/workflows/generate-sandboxes.yml @@ -15,6 +15,7 @@ on: jobs: generate-next: + name: Generate to next runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -23,7 +24,11 @@ jobs: - uses: ./.github/actions/generate-sandboxes-composite-action with: destination-branch: next + token: ${{ secrets.PAT_STORYBOOK_BOT }} + discord-url: ${{ secrets.DISCORD_MONITORING_URL }} + # generate-main: + # name: Generate to main # runs-on: ubuntu-latest # steps: # - uses: actions/checkout@v4 @@ -32,3 +37,5 @@ jobs: # - uses: ./.github/actions/generate-sandboxes-composite-action # with: # destination-branch: main + # token: ${{ secrets.PAT_STORYBOOK_BOT }} + # discord-url: ${{ secrets.DISCORD_MONITORING_URL }} From 02f624193347e4920a01fc9a2da5135efa979131 Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Fri, 9 Feb 2024 23:27:25 +0100 Subject: [PATCH 08/77] use regular workflow instead of composite action --- .../action.yml | 67 ------------------- .github/workflows/generate-sandboxes-next.yml | 60 ----------------- .github/workflows/generate-sandboxes.yml | 63 ++++++++++++----- 3 files changed, 46 insertions(+), 144 deletions(-) delete mode 100644 .github/actions/generate-sandboxes-composite-action/action.yml delete mode 100644 .github/workflows/generate-sandboxes-next.yml diff --git a/.github/actions/generate-sandboxes-composite-action/action.yml b/.github/actions/generate-sandboxes-composite-action/action.yml deleted file mode 100644 index a4f0112731e7..000000000000 --- a/.github/actions/generate-sandboxes-composite-action/action.yml +++ /dev/null @@ -1,67 +0,0 @@ -name: Generate and push sandboxes action -description: This is a composite action that generates sandboxes and pushes them to the storybookjs/sandboxes repository - -inputs: - destination-branch: - description: The destination branch to generate sandboxes to in the storybookjs/sandboxes repository - required: true - token: - description: The personal access token to use when authenticating with the destination repository - required: true - discord-url: - description: The Discord URL to use when reporting failures - required: true - -runs: - using: "composite" - steps: - - uses: actions/setup-node@v3 - with: - node-version-file: ".nvmrc" - - - name: Setup git user - shell: bash - run: | - git config --global user.name "storybook-bot" - git config --global user.email "32066757+storybook-bot@users.noreply.github.com" - - - name: Install dependencies - shell: bash - working-directory: ./scripts - env: - YARN_ENABLE_IMMUTABLE_INSTALLS: "false" - run: node --experimental-modules ./check-dependencies.js - - - name: Compile Storybook libraries - shell: bash - run: yarn task --task compile --start-from=auto --no-link - - - name: Publish to local registry - shell: bash - run: yarn local-registry --publish - - - name: Run local registry - shell: bash - run: yarn local-registry --open & - - - name: Wait for registry - shell: bash - run: yarn wait-on tcp:127.0.0.1:6001 - - - name: Generate - shell: bash - env: - CLEANUP_SANDBOX_NODE_MODULES: "true" - run: yarn generate-sandboxes --local-registry - - - name: Publish - shell: bash - run: yarn publish-sandboxes --remote=https://storybook-bot:${{ inputs.token }}@github.com/storybookjs/sandboxes.git --push --branch=${{ inputs.destination-branch }} - - - name: The job has failed - if: ${{ failure() || cancelled() }} - env: - DISCORD_WEBHOOK: ${{ inputs.discord-url }} - uses: Ilshidur/action-discord@master - with: - args: "The generation of sandboxes in the **${{ inputs.destination-branch }}** branch has failed. [View Run](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})" diff --git a/.github/workflows/generate-sandboxes-next.yml b/.github/workflows/generate-sandboxes-next.yml deleted file mode 100644 index 2c0b592d024f..000000000000 --- a/.github/workflows/generate-sandboxes-next.yml +++ /dev/null @@ -1,60 +0,0 @@ -name: Generate and push sandboxes (next) - -on: - schedule: - - cron: '2 2 */1 * *' - workflow_dispatch: - # To test fixes on push rather than wait for the scheduling, do the following: - # 1. Uncomment the lines below and add your branch. - # push: - # branches: - # - - # 2. change the "ref" value to in the actions/checkout step below. - # 3. πŸ‘‰ DON'T FORGET TO UNDO THE VALUES BACK TO `next` BEFORE YOU MERGE YOUR CHANGES! - -jobs: - generate: - runs-on: ubuntu-latest - env: - YARN_ENABLE_IMMUTABLE_INSTALLS: false - CLEANUP_SANDBOX_NODE_MODULES: true - steps: - - uses: actions/checkout@v3 - with: - ref: next - - uses: actions/setup-node@v3 - with: - node-version-file: '.nvmrc' - - name: Setup git user - run: | - git config --global user.name "Storybook Bot" - git config --global user.email "bot@storybook.js.org" - - name: Install dependencies - run: | - cd ./scripts - node --experimental-modules ./check-dependencies.js - cd .. - - name: Compile Storybook libraries - run: yarn task --task compile --start-from=auto --no-link - - name: Publishing to local registry - run: yarn local-registry --publish - working-directory: ./code - - name: Running local registry - run: yarn local-registry --open & - working-directory: ./code - - name: Wait for registry - run: yarn wait-on tcp:127.0.0.1:6001 - working-directory: ./code - - name: Generate - run: yarn generate-sandboxes --local-registry --debug - working-directory: ./code - - name: Publish - run: yarn publish-sandboxes --remote=https://storybook-bot:${{ secrets.PAT_STORYBOOK_BOT}}@github.com/storybookjs/sandboxes.git --push --branch=next - working-directory: ./code - - name: The job has failed - if: ${{ failure() || cancelled() }} - env: - DISCORD_WEBHOOK: ${{ secrets.DISCORD_MONITORING_URL }} - uses: Ilshidur/action-discord@master - with: - args: 'The generation of sandboxes in the **next** branch has failed. [View Run](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})' diff --git a/.github/workflows/generate-sandboxes.yml b/.github/workflows/generate-sandboxes.yml index 942ad7527d42..8c1af15b40ad 100644 --- a/.github/workflows/generate-sandboxes.yml +++ b/.github/workflows/generate-sandboxes.yml @@ -13,6 +13,14 @@ on: # 3. Comment out the whole "generate-main" job starting at line 26 # 3. πŸ‘‰ DON'T FORGET TO UNDO STEP 2 AND 3 BEFORE YOU MERGE YOUR CHANGES! +env: + YARN_ENABLE_IMMUTABLE_INSTALLS: "false" + CLEANUP_SANDBOX_NODE_MODULES: "true" + +defaults: + run: + working-directory: ./code + jobs: generate-next: name: Generate to next @@ -21,21 +29,42 @@ jobs: - uses: actions/checkout@v4 with: ref: jeppe/25922-ci-generation-of-sandboxes-fail-sometimes-on-prereleases - - uses: ./.github/actions/generate-sandboxes-composite-action + + - uses: actions/setup-node@v4 + with: + node-version-file: ".nvmrc" + + - name: Setup git user + run: | + git config --global user.name "storybook-bot" + git config --global user.email "32066757+storybook-bot@users.noreply.github.com" + + - name: Install dependencies + working-directory: ./scripts + run: node --experimental-modules ./check-dependencies.js + + - name: Compile Storybook libraries + run: yarn task --task compile --start-from=auto --no-link + + - name: Publish to local registry + run: yarn local-registry --publish + + - name: Run local registry + run: yarn local-registry --open & + + - name: Wait for registry + run: yarn wait-on tcp:127.0.0.1:6001 + + - name: Generate + run: yarn generate-sandboxes --local-registry + + - name: Publish + run: yarn publish-sandboxes --remote=https://storybook-bot:${{ secrets.PAT_STORYBOOK_BOT }}@github.com/storybookjs/sandboxes.git --push --branch=next + + - name: The job has failed + if: ${{ failure() || cancelled() }} + env: + DISCORD_WEBHOOK: ${{ secrets.DISCORD_MONITORING_URL }} + uses: Ilshidur/action-discord@master with: - destination-branch: next - token: ${{ secrets.PAT_STORYBOOK_BOT }} - discord-url: ${{ secrets.DISCORD_MONITORING_URL }} - - # generate-main: - # name: Generate to main - # runs-on: ubuntu-latest - # steps: - # - uses: actions/checkout@v4 - # with: - # ref: main - # - uses: ./.github/actions/generate-sandboxes-composite-action - # with: - # destination-branch: main - # token: ${{ secrets.PAT_STORYBOOK_BOT }} - # discord-url: ${{ secrets.DISCORD_MONITORING_URL }} + args: "The generation of sandboxes on the **next** branch has failed. [View Run](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})" From f1846015d018d27302942cc94a988db56c8f8ba1 Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Sat, 10 Feb 2024 00:09:13 +0100 Subject: [PATCH 09/77] Continue with publishing even if some sandboxes fail --- .github/workflows/generate-sandboxes.yml | 17 +++++-- scripts/sandbox/generate.ts | 57 +++++++++++++++++------- 2 files changed, 55 insertions(+), 19 deletions(-) diff --git a/.github/workflows/generate-sandboxes.yml b/.github/workflows/generate-sandboxes.yml index 8c1af15b40ad..643361e63143 100644 --- a/.github/workflows/generate-sandboxes.yml +++ b/.github/workflows/generate-sandboxes.yml @@ -1,4 +1,4 @@ -name: Generate and push sandboxes +name: Generate and publish sandboxes on: schedule: @@ -56,15 +56,24 @@ jobs: run: yarn wait-on tcp:127.0.0.1:6001 - name: Generate + id: generate run: yarn generate-sandboxes --local-registry - name: Publish + # publish sandboxes even if the generation fails, as some sandboxes might have been generated successfully + if: !cancelled() run: yarn publish-sandboxes --remote=https://storybook-bot:${{ secrets.PAT_STORYBOOK_BOT }}@github.com/storybookjs/sandboxes.git --push --branch=next - - name: The job has failed - if: ${{ failure() || cancelled() }} + - name: Report failure to Discord + if: failure() env: DISCORD_WEBHOOK: ${{ secrets.DISCORD_MONITORING_URL }} uses: Ilshidur/action-discord@master with: - args: "The generation of sandboxes on the **next** branch has failed. [View Run](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }})" + args: | + The generation of some or all sandboxes on the **next** branch has failed. + [View Job](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}/job/${{ github.job }}) + + ${{ steps.generate.outputs.failed-before-script-templates && format('The following templates failed to execute the before script:\n- {0}', steps.generate.outputs.failed-before-script-templates) || '' }} + + ${{ steps.generate.outputs.failed-before-script-templates && format('The following templates failed to initialize Storybook:\n- {0}', steps.generate.outputs.failed-init-templates) || '' }} diff --git a/scripts/sandbox/generate.ts b/scripts/sandbox/generate.ts index 27f17f8c7ad0..969247d6ba1d 100755 --- a/scripts/sandbox/generate.ts +++ b/scripts/sandbox/generate.ts @@ -27,6 +27,7 @@ import { REPROS_DIRECTORY, LOCAL_REGISTRY_URL, } from '../utils/constants'; +import { setOutput } from '@actions/core'; const sbInit = async ( cwd: string, @@ -148,7 +149,10 @@ const runGenerators = async ( const limit = pLimit(1); - await Promise.all( + const failedBeforeScriptTemplates: string[] = []; + const failedInitTemplates: string[] = []; + + await Promise.allSettled( generators.map(({ dirName, name, script, expected, env }) => limit(async () => { let flags: string[] = []; @@ -173,19 +177,26 @@ const runGenerators = async ( // Some tools refuse to run inside an existing directory and replace the contents, // where as others are very picky about what directories can be called. So we need to // handle different modes of operation. - if (script.includes('{{beforeDir}}')) { - const scriptWithBeforeDir = script.replaceAll('{{beforeDir}}', BEFORE_DIR_NAME); - await runCommand( - scriptWithBeforeDir, - { - cwd: createBaseDir, - timeout: SCRIPT_TIMEOUT, - }, - debug - ); - } else { - await ensureDir(createBeforeDir); - await runCommand(script, { cwd: createBeforeDir, timeout: SCRIPT_TIMEOUT }, debug); + try { + if (script.includes('{{beforeDir}}')) { + const scriptWithBeforeDir = script.replaceAll('{{beforeDir}}', BEFORE_DIR_NAME); + await runCommand( + scriptWithBeforeDir, + { + cwd: createBaseDir, + timeout: SCRIPT_TIMEOUT, + }, + debug + ); + } else { + await ensureDir(createBeforeDir); + await runCommand(script, { cwd: createBeforeDir, timeout: SCRIPT_TIMEOUT }, debug); + } + } catch (error) { + console.error(`❌ Failed to execute before-script for template: ${name}`); + console.error(error); + failedBeforeScriptTemplates.push(name); + return; } await localizeYarnConfigFiles(createBaseDir, createBeforeDir); @@ -196,7 +207,14 @@ const runGenerators = async ( // Make sure there are no git projects in the folder await remove(join(beforeDir, '.git')); - await addStorybook({ baseDir, localRegistry, flags, debug, env }); + try { + await addStorybook({ baseDir, localRegistry, flags, debug, env }); + } catch (error) { + console.error(`❌ Failed to add Storybook to template: ${name}`); + console.error(error); + failedInitTemplates.push(name); + return; + } await addDocumentation(baseDir, { name, dirName }); @@ -218,6 +236,15 @@ const runGenerators = async ( }) ) ); + + if (process.env.GITHUB_ACTIONS === 'true') { + if (failedBeforeScriptTemplates.length > 0) { + setOutput('failed-before-script-templates', failedBeforeScriptTemplates.join('\n- ')); + } + if (failedInitTemplates.length > 0) { + setOutput('failed-init-templates', failedInitTemplates.join('\n- ')); + } + } }; export const options = createOptions({ From 86c58958146617d044748cdd97f0a4dcb190da7c Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Sat, 10 Feb 2024 00:20:35 +0100 Subject: [PATCH 10/77] =?UTF-8?q?Yet=20Another=20Maddening=20Language?= =?UTF-8?q?=E2=84=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/generate-sandboxes.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/generate-sandboxes.yml b/.github/workflows/generate-sandboxes.yml index 643361e63143..339e6eb9d0c8 100644 --- a/.github/workflows/generate-sandboxes.yml +++ b/.github/workflows/generate-sandboxes.yml @@ -61,7 +61,7 @@ jobs: - name: Publish # publish sandboxes even if the generation fails, as some sandboxes might have been generated successfully - if: !cancelled() + if: ${{ !cancelled() }} run: yarn publish-sandboxes --remote=https://storybook-bot:${{ secrets.PAT_STORYBOOK_BOT }}@github.com/storybookjs/sandboxes.git --push --branch=next - name: Report failure to Discord From 11222151b69819c9d7e1cdd049b61f24cfccb3f3 Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Sat, 10 Feb 2024 00:23:02 +0100 Subject: [PATCH 11/77] randomly cause generation failures --- scripts/sandbox/generate.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/scripts/sandbox/generate.ts b/scripts/sandbox/generate.ts index 969247d6ba1d..ee0b952175a6 100755 --- a/scripts/sandbox/generate.ts +++ b/scripts/sandbox/generate.ts @@ -81,6 +81,9 @@ const addStorybook = async ({ const tmpDir = directory(); try { + if (Math.random() < 0.2) { + throw new Error('Blip Bloop random error in addStorybook'); + } await copy(beforeDir, tmpDir); const packageManager = JsPackageManagerFactory.getPackageManager({ force: 'yarn1' }, tmpDir); @@ -178,6 +181,9 @@ const runGenerators = async ( // where as others are very picky about what directories can be called. So we need to // handle different modes of operation. try { + if (Math.random() < 0.2) { + throw new Error('Blip Bloop random error when executing before-script'); + } if (script.includes('{{beforeDir}}')) { const scriptWithBeforeDir = script.replaceAll('{{beforeDir}}', BEFORE_DIR_NAME); await runCommand( From 78f122caed653f9e3a38b732a779d1eefba1696c Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Mon, 12 Feb 2024 12:22:01 +0100 Subject: [PATCH 12/77] simplify error handling, rethrow errors --- .github/workflows/generate-sandboxes.yml | 6 +- scripts/sandbox/generate.ts | 218 ++++++++++++++--------- 2 files changed, 136 insertions(+), 88 deletions(-) diff --git a/.github/workflows/generate-sandboxes.yml b/.github/workflows/generate-sandboxes.yml index 339e6eb9d0c8..a7d1ded22573 100644 --- a/.github/workflows/generate-sandboxes.yml +++ b/.github/workflows/generate-sandboxes.yml @@ -72,8 +72,4 @@ jobs: with: args: | The generation of some or all sandboxes on the **next** branch has failed. - [View Job](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}/job/${{ github.job }}) - - ${{ steps.generate.outputs.failed-before-script-templates && format('The following templates failed to execute the before script:\n- {0}', steps.generate.outputs.failed-before-script-templates) || '' }} - - ${{ steps.generate.outputs.failed-before-script-templates && format('The following templates failed to initialize Storybook:\n- {0}', steps.generate.outputs.failed-init-templates) || '' }} + [See the job summary for details](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}/job/${{ github.job }}) diff --git a/scripts/sandbox/generate.ts b/scripts/sandbox/generate.ts index ee0b952175a6..510b34b9a2b6 100755 --- a/scripts/sandbox/generate.ts +++ b/scripts/sandbox/generate.ts @@ -27,7 +27,14 @@ import { REPROS_DIRECTORY, LOCAL_REGISTRY_URL, } from '../utils/constants'; -import { setOutput } from '@actions/core'; +import * as ghActions from '@actions/core'; + +const isCI = process.env.GITHUB_ACTIONS === 'true'; + +const logError = isCI ? ghActions.error : console.error; + +class BeforeScriptExecutionError extends Error {} +class StorybookInitError extends Error {} const sbInit = async ( cwd: string, @@ -152,105 +159,150 @@ const runGenerators = async ( const limit = pLimit(1); - const failedBeforeScriptTemplates: string[] = []; - const failedInitTemplates: string[] = []; - - await Promise.allSettled( + const generationResults = await Promise.allSettled( generators.map(({ dirName, name, script, expected, env }) => limit(async () => { - let flags: string[] = []; - if (expected.renderer === '@storybook/html') flags = ['--type html']; - else if (expected.renderer === '@storybook/server') flags = ['--type server']; - - const time = process.hrtime(); - console.log(`🧬 Generating ${name}`); + try { + if (isCI) { + ghActions.startGroup(`Generating sandbox for ${name}`); + } - const baseDir = join(REPROS_DIRECTORY, dirName); - const beforeDir = join(baseDir, BEFORE_DIR_NAME); - await emptyDir(baseDir); + let flags: string[] = []; + if (expected.renderer === '@storybook/html') flags = ['--type html']; + else if (expected.renderer === '@storybook/server') flags = ['--type server']; - // We do the creation inside a temp dir to avoid yarn container problems - const createBaseDir = directory(); - if (!script.includes('pnp')) { - await setupYarn({ cwd: createBaseDir }); - } + const time = process.hrtime(); + console.log(`🧬 Generating ${name}`); - const createBeforeDir = join(createBaseDir, BEFORE_DIR_NAME); + const baseDir = join(REPROS_DIRECTORY, dirName); + const beforeDir = join(baseDir, BEFORE_DIR_NAME); + await emptyDir(baseDir); - // Some tools refuse to run inside an existing directory and replace the contents, - // where as others are very picky about what directories can be called. So we need to - // handle different modes of operation. - try { - if (Math.random() < 0.2) { - throw new Error('Blip Bloop random error when executing before-script'); + // We do the creation inside a temp dir to avoid yarn container problems + const createBaseDir = directory(); + if (!script.includes('pnp')) { + await setupYarn({ cwd: createBaseDir }); } - if (script.includes('{{beforeDir}}')) { - const scriptWithBeforeDir = script.replaceAll('{{beforeDir}}', BEFORE_DIR_NAME); - await runCommand( - scriptWithBeforeDir, - { - cwd: createBaseDir, - timeout: SCRIPT_TIMEOUT, - }, - debug - ); - } else { - await ensureDir(createBeforeDir); - await runCommand(script, { cwd: createBeforeDir, timeout: SCRIPT_TIMEOUT }, debug); - } - } catch (error) { - console.error(`❌ Failed to execute before-script for template: ${name}`); - console.error(error); - failedBeforeScriptTemplates.push(name); - return; - } - await localizeYarnConfigFiles(createBaseDir, createBeforeDir); - - // Now move the created before dir into it's final location and add storybook - await move(createBeforeDir, beforeDir); + const createBeforeDir = join(createBaseDir, BEFORE_DIR_NAME); + + // Some tools refuse to run inside an existing directory and replace the contents, + // where as others are very picky about what directories can be called. So we need to + // handle different modes of operation. + try { + if (Math.random() < 0.4) { + throw new Error('Blip Bloop random error when executing before-script'); + } + if (script.includes('{{beforeDir}}')) { + const scriptWithBeforeDir = script.replaceAll('{{beforeDir}}', BEFORE_DIR_NAME); + await runCommand( + scriptWithBeforeDir, + { + cwd: createBaseDir, + timeout: SCRIPT_TIMEOUT, + }, + debug + ); + } else { + await ensureDir(createBeforeDir); + await runCommand(script, { cwd: createBeforeDir, timeout: SCRIPT_TIMEOUT }, debug); + } + } catch (error) { + const message = `❌ Failed to execute before-script for template: ${name}`; + logError(message); + logError(error); + logError((error as any).stack); + throw new BeforeScriptExecutionError(message, { cause: error }); + } - // Make sure there are no git projects in the folder - await remove(join(beforeDir, '.git')); + await localizeYarnConfigFiles(createBaseDir, createBeforeDir); + + // Now move the created before dir into it's final location and add storybook + await move(createBeforeDir, beforeDir); + + // Make sure there are no git projects in the folder + await remove(join(beforeDir, '.git')); + + try { + if (Math.random() < 0.4) { + throw new Error('Blip Bloop random error when init storybook'); + } + await addStorybook({ baseDir, localRegistry, flags, debug, env }); + } catch (error) { + const message = `❌ Failed to initialize Storybook in template: ${name}`; + logError(message); + logError(error); + logError((error as any).stack); + throw new StorybookInitError(message, { + cause: error, + }); + } + if (Math.random() < 0.4) { + throw new Error('Blip Bloop random error anywhere'); + } + await addDocumentation(baseDir, { name, dirName }); + + // Remove node_modules to save space and avoid GH actions failing + // They're not uploaded to the git sandboxes repo anyway + if (process.env.CLEANUP_SANDBOX_NODE_MODULES) { + console.log(`πŸ—‘οΈ Removing ${join(beforeDir, 'node_modules')}`); + await remove(join(beforeDir, 'node_modules')); + console.log(`πŸ—‘οΈ Removing ${join(baseDir, AFTER_DIR_NAME, 'node_modules')}`); + await remove(join(baseDir, AFTER_DIR_NAME, 'node_modules')); + } - try { - await addStorybook({ baseDir, localRegistry, flags, debug, env }); + console.log( + `βœ… Created ${dirName} in ./${relative( + process.cwd(), + baseDir + )} successfully in ${prettyTime(process.hrtime(time))}` + ); } catch (error) { - console.error(`❌ Failed to add Storybook to template: ${name}`); - console.error(error); - failedInitTemplates.push(name); - return; - } - - await addDocumentation(baseDir, { name, dirName }); - - // Remove node_modules to save space and avoid GH actions failing - // They're not uploaded to the git sandboxes repo anyway - if (process.env.CLEANUP_SANDBOX_NODE_MODULES) { - console.log(`πŸ—‘οΈ Removing ${join(beforeDir, 'node_modules')}`); - await remove(join(beforeDir, 'node_modules')); - console.log(`πŸ—‘οΈ Removing ${join(baseDir, AFTER_DIR_NAME, 'node_modules')}`); - await remove(join(baseDir, AFTER_DIR_NAME, 'node_modules')); + throw error; + } finally { + if (isCI) { + ghActions.endGroup(); + } } - - console.log( - `βœ… Created ${dirName} in ./${relative( - process.cwd(), - baseDir - )} successfully in ${prettyTime(process.hrtime(time))}` - ); }) ) ); - if (process.env.GITHUB_ACTIONS === 'true') { - if (failedBeforeScriptTemplates.length > 0) { - setOutput('failed-before-script-templates', failedBeforeScriptTemplates.join('\n- ')); - } - if (failedInitTemplates.length > 0) { - setOutput('failed-init-templates', failedInitTemplates.join('\n- ')); - } + ghActions.summary.addHeading('Sandbox generation summary'); + + if (!generationResults.some((result) => result.status === 'rejected')) { + await ghActions.summary.addRaw('βœ… Success!').write(); + return; + } + + if (isCI) { + await ghActions.summary + .addRaw('Some sandboxes failed, see the action log for details') + .addTable([ + [ + { data: 'Template', header: true }, + { data: 'Result', header: true }, + ], + ...generationResults.map((result, index) => { + const template = generators[index].name; + if (result.status === 'fulfilled') { + return [template, '🟒 Pass']; + } + const generationError = (result as PromiseRejectedResult).reason as Error; + const errorCause = generationError.cause; + if (errorCause instanceof BeforeScriptExecutionError) { + return [template, 'πŸ”΄ Failed to execute before script']; + } else if (errorCause instanceof StorybookInitError) { + return [template, 'πŸ”΄ Failed to initialize Storybook']; + } else { + return [template, 'πŸ”΄ Failed with unknown error']; + } + }), + ]) + .write(); } + + throw new Error(`Some sandboxes failed to generate`); }; export const options = createOptions({ From b7eb43338b28f7f24fd7190d92c70de41c04ce3b Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Mon, 12 Feb 2024 13:02:17 +0100 Subject: [PATCH 13/77] fix error logging and summary generation --- .github/workflows/generate-sandboxes.yml | 2 +- scripts/sandbox/generate.ts | 45 +++++++++++++----------- 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/.github/workflows/generate-sandboxes.yml b/.github/workflows/generate-sandboxes.yml index a7d1ded22573..b3a875bcfb00 100644 --- a/.github/workflows/generate-sandboxes.yml +++ b/.github/workflows/generate-sandboxes.yml @@ -72,4 +72,4 @@ jobs: with: args: | The generation of some or all sandboxes on the **next** branch has failed. - [See the job summary for details](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}/job/${{ github.job }}) + [See the job summary for details](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) diff --git a/scripts/sandbox/generate.ts b/scripts/sandbox/generate.ts index 510b34b9a2b6..85a296f71f30 100755 --- a/scripts/sandbox/generate.ts +++ b/scripts/sandbox/generate.ts @@ -28,11 +28,10 @@ import { LOCAL_REGISTRY_URL, } from '../utils/constants'; import * as ghActions from '@actions/core'; +import dedent from 'ts-dedent'; const isCI = process.env.GITHUB_ACTIONS === 'true'; -const logError = isCI ? ghActions.error : console.error; - class BeforeScriptExecutionError extends Error {} class StorybookInitError extends Error {} @@ -164,7 +163,7 @@ const runGenerators = async ( limit(async () => { try { if (isCI) { - ghActions.startGroup(`Generating sandbox for ${name}`); + ghActions.startGroup(`${name} (${dirName})`); } let flags: string[] = []; @@ -208,10 +207,12 @@ const runGenerators = async ( await runCommand(script, { cwd: createBeforeDir, timeout: SCRIPT_TIMEOUT }, debug); } } catch (error) { - const message = `❌ Failed to execute before-script for template: ${name}`; - logError(message); - logError(error); - logError((error as any).stack); + const message = `❌ Failed to execute before-script for template: ${name} (${dirName})`; + if (isCI) { + ghActions.error(dedent`${message} + ${(error as any).stack}`); + } + console.error(error); throw new BeforeScriptExecutionError(message, { cause: error }); } @@ -229,10 +230,12 @@ const runGenerators = async ( } await addStorybook({ baseDir, localRegistry, flags, debug, env }); } catch (error) { - const message = `❌ Failed to initialize Storybook in template: ${name}`; - logError(message); - logError(error); - logError((error as any).stack); + const message = `❌ Failed to initialize Storybook in template: ${name} (${dirName})`; + if (isCI) { + ghActions.error(dedent`${message} + ${(error as any).stack}`); + } + console.error(error); throw new StorybookInitError(message, { cause: error, }); @@ -277,25 +280,25 @@ const runGenerators = async ( if (isCI) { await ghActions.summary - .addRaw('Some sandboxes failed, see the action log for details') + .addRaw('Some sandboxes failed, see the job log for detailed errors') .addTable([ [ - { data: 'Template', header: true }, + { data: 'Name', header: true }, + { data: 'Key', header: true }, { data: 'Result', header: true }, ], ...generationResults.map((result, index) => { - const template = generators[index].name; + const { name, dirName } = generators[index]; if (result.status === 'fulfilled') { - return [template, '🟒 Pass']; + return [name, dirName, '🟒 Pass']; } const generationError = (result as PromiseRejectedResult).reason as Error; - const errorCause = generationError.cause; - if (errorCause instanceof BeforeScriptExecutionError) { - return [template, 'πŸ”΄ Failed to execute before script']; - } else if (errorCause instanceof StorybookInitError) { - return [template, 'πŸ”΄ Failed to initialize Storybook']; + if (generationError instanceof BeforeScriptExecutionError) { + return [name, dirName, 'πŸ”΄ Failed to execute before script']; + } else if (generationError instanceof StorybookInitError) { + return [name, dirName, 'πŸ”΄ Failed to initialize Storybook']; } else { - return [template, 'πŸ”΄ Failed with unknown error']; + return [name, dirName, 'πŸ”΄ Failed with unknown error']; } }), ]) From c9e9d6242536edb2b7359671455dcc1af46e94f7 Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Mon, 12 Feb 2024 13:23:09 +0100 Subject: [PATCH 14/77] fix double error logging --- scripts/sandbox/generate.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/scripts/sandbox/generate.ts b/scripts/sandbox/generate.ts index 85a296f71f30..a3c88eb4eb5c 100755 --- a/scripts/sandbox/generate.ts +++ b/scripts/sandbox/generate.ts @@ -189,7 +189,7 @@ const runGenerators = async ( // where as others are very picky about what directories can be called. So we need to // handle different modes of operation. try { - if (Math.random() < 0.4) { + if (Math.random() < 0.2) { throw new Error('Blip Bloop random error when executing before-script'); } if (script.includes('{{beforeDir}}')) { @@ -211,8 +211,10 @@ const runGenerators = async ( if (isCI) { ghActions.error(dedent`${message} ${(error as any).stack}`); + } else { + console.error(message); + console.error(error); } - console.error(error); throw new BeforeScriptExecutionError(message, { cause: error }); } @@ -225,7 +227,7 @@ const runGenerators = async ( await remove(join(beforeDir, '.git')); try { - if (Math.random() < 0.4) { + if (Math.random() < 0.2) { throw new Error('Blip Bloop random error when init storybook'); } await addStorybook({ baseDir, localRegistry, flags, debug, env }); @@ -234,8 +236,10 @@ const runGenerators = async ( if (isCI) { ghActions.error(dedent`${message} ${(error as any).stack}`); + } else { + console.error(message); + console.error(error); } - console.error(error); throw new StorybookInitError(message, { cause: error, }); @@ -366,7 +370,7 @@ if (esMain(import.meta.url)) { .action((optionValues) => { generate(optionValues) .catch((e) => { - console.trace(e); + console.error(e); process.exit(1); }) .then(() => { From 57cbc5ece4f192a09e0a20591cbfc268db0b11b8 Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Mon, 12 Feb 2024 14:25:01 +0100 Subject: [PATCH 15/77] support partial publishing to sandboxes repo --- .github/workflows/generate-sandboxes.yml | 2 +- scripts/sandbox/generate.ts | 6 +++--- scripts/sandbox/publish.ts | 27 +++++++++++++++--------- 3 files changed, 21 insertions(+), 14 deletions(-) diff --git a/.github/workflows/generate-sandboxes.yml b/.github/workflows/generate-sandboxes.yml index b3a875bcfb00..774cd297c571 100644 --- a/.github/workflows/generate-sandboxes.yml +++ b/.github/workflows/generate-sandboxes.yml @@ -62,7 +62,7 @@ jobs: - name: Publish # publish sandboxes even if the generation fails, as some sandboxes might have been generated successfully if: ${{ !cancelled() }} - run: yarn publish-sandboxes --remote=https://storybook-bot:${{ secrets.PAT_STORYBOOK_BOT }}@github.com/storybookjs/sandboxes.git --push --branch=next + run: yarn publish-sandboxes --remote=https://storybook-bot:${{ secrets.PAT_STORYBOOK_BOT }}@github.com/storybookjs/sandboxes.git --push --branch=jeppe/experiment-partial-generation - name: Report failure to Discord if: failure() diff --git a/scripts/sandbox/generate.ts b/scripts/sandbox/generate.ts index a3c88eb4eb5c..dd77b4ee8574 100755 --- a/scripts/sandbox/generate.ts +++ b/scripts/sandbox/generate.ts @@ -189,7 +189,7 @@ const runGenerators = async ( // where as others are very picky about what directories can be called. So we need to // handle different modes of operation. try { - if (Math.random() < 0.2) { + if (Math.random() < 0.6) { throw new Error('Blip Bloop random error when executing before-script'); } if (script.includes('{{beforeDir}}')) { @@ -227,7 +227,7 @@ const runGenerators = async ( await remove(join(beforeDir, '.git')); try { - if (Math.random() < 0.2) { + if (Math.random() < 0.6) { throw new Error('Blip Bloop random error when init storybook'); } await addStorybook({ baseDir, localRegistry, flags, debug, env }); @@ -244,7 +244,7 @@ const runGenerators = async ( cause: error, }); } - if (Math.random() < 0.4) { + if (Math.random() < 0.6) { throw new Error('Blip Bloop random error anywhere'); } await addDocumentation(baseDir, { name, dirName }); diff --git a/scripts/sandbox/publish.ts b/scripts/sandbox/publish.ts index e4307690efdd..99323c3a2420 100755 --- a/scripts/sandbox/publish.ts +++ b/scripts/sandbox/publish.ts @@ -1,14 +1,15 @@ import program from 'commander'; -import { join } from 'path'; +import { join, relative } from 'path'; import { existsSync } from 'fs'; import * as tempy from 'tempy'; -import { copy, emptyDir, readdir, remove, stat, writeFile } from 'fs-extra'; +import { copy, emptyDir, remove, writeFile } from 'fs-extra'; import { execaCommand } from 'execa'; import { getTemplatesData, renderTemplate } from './utils/template'; // eslint-disable-next-line import/no-cycle import { commitAllToGit } from './utils/git'; import { REPROS_DIRECTORY } from '../utils/constants'; +import { glob } from 'glob'; export const logger = console; @@ -31,15 +32,21 @@ const publish = async (options: PublishOptions & { tmpFolder: string }) => { // otherwise old files will stick around and result inconsistent states logger.log(`πŸ—‘ Delete existing template dirs from clone`); - const files = await Promise.all( - ( - await readdir(REPROS_DIRECTORY) - ).map(async (f) => ({ path: f, stats: await stat(join(REPROS_DIRECTORY, f)) })) - ); + + // empty all existing directories for sandboxes that have a successful after-storybook directory await Promise.all( - files - .filter(({ stats, path }) => stats.isDirectory && !path.startsWith('.')) - .map(async ({ path }) => emptyDir(join(tmpFolder, path))) + // find all successfully generated after-storybook directories + // eg. /home/repros/react-vite/default-ts/after-storybook + (await glob(join(REPROS_DIRECTORY, '**', 'after-storybook'))).map((dir) => { + // get their path relative to the source 'repros' directory + // eg. ./react-vite/default-ts/after-storybook + const pathRelativeToSource = relative(REPROS_DIRECTORY, dir); + // get the actual path to the corresponding sandbox directory in the clone + // eg. /home/sandboxes-clone/react-vite/default-ts + const sandboxDirectoryToEmpty = join(tmpFolder, pathRelativeToSource, '..'); + console.log({ pathRelativeToSource, sandboxDirectoryToEmpty }); + return emptyDir(sandboxDirectoryToEmpty); + }) ); logger.log(`🚚 Moving template files into the repository`); From 1e8eaa4583a1727599e8c7bb5153c309ac101937 Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Tue, 13 Feb 2024 09:49:09 +0100 Subject: [PATCH 16/77] publish based on the presence of a README.md --- scripts/sandbox/publish.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/scripts/sandbox/publish.ts b/scripts/sandbox/publish.ts index 99323c3a2420..fc5d6b6db5a6 100755 --- a/scripts/sandbox/publish.ts +++ b/scripts/sandbox/publish.ts @@ -1,5 +1,5 @@ import program from 'commander'; -import { join, relative } from 'path'; +import { dirname, join, relative } from 'path'; import { existsSync } from 'fs'; import * as tempy from 'tempy'; import { copy, emptyDir, remove, writeFile } from 'fs-extra'; @@ -35,16 +35,16 @@ const publish = async (options: PublishOptions & { tmpFolder: string }) => { // empty all existing directories for sandboxes that have a successful after-storybook directory await Promise.all( - // find all successfully generated after-storybook directories - // eg. /home/repros/react-vite/default-ts/after-storybook - (await glob(join(REPROS_DIRECTORY, '**', 'after-storybook'))).map((dir) => { - // get their path relative to the source 'repros' directory + // find all successfully generated after-storybook/README.md files + // eg. /home/repros/react-vite/default-ts/after-storybook/README.md + // README.md being the last fil generated, thus representing a successful generation + (await glob(join(REPROS_DIRECTORY, '**', 'after-storybook/README.md'))).map((readmePath) => { + // get the after-storybook path relative to the source 'repros' directory // eg. ./react-vite/default-ts/after-storybook - const pathRelativeToSource = relative(REPROS_DIRECTORY, dir); + const pathRelativeToSource = relative(REPROS_DIRECTORY, dirname(readmePath)); // get the actual path to the corresponding sandbox directory in the clone // eg. /home/sandboxes-clone/react-vite/default-ts const sandboxDirectoryToEmpty = join(tmpFolder, pathRelativeToSource, '..'); - console.log({ pathRelativeToSource, sandboxDirectoryToEmpty }); return emptyDir(sandboxDirectoryToEmpty); }) ); From fce6818d61b1e21d9235625e19def339c2ae04fa Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Tue, 13 Feb 2024 09:49:36 +0100 Subject: [PATCH 17/77] lower fake error threshold --- scripts/sandbox/generate.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/sandbox/generate.ts b/scripts/sandbox/generate.ts index dd77b4ee8574..91a4fd2fccd5 100755 --- a/scripts/sandbox/generate.ts +++ b/scripts/sandbox/generate.ts @@ -189,7 +189,7 @@ const runGenerators = async ( // where as others are very picky about what directories can be called. So we need to // handle different modes of operation. try { - if (Math.random() < 0.6) { + if (Math.random() < 0.2) { throw new Error('Blip Bloop random error when executing before-script'); } if (script.includes('{{beforeDir}}')) { @@ -227,7 +227,7 @@ const runGenerators = async ( await remove(join(beforeDir, '.git')); try { - if (Math.random() < 0.6) { + if (Math.random() < 0.2) { throw new Error('Blip Bloop random error when init storybook'); } await addStorybook({ baseDir, localRegistry, flags, debug, env }); @@ -244,7 +244,7 @@ const runGenerators = async ( cause: error, }); } - if (Math.random() < 0.6) { + if (Math.random() < 0.2) { throw new Error('Blip Bloop random error anywhere'); } await addDocumentation(baseDir, { name, dirName }); From 6b1be49c6b807939b6a940c0cf00b6ab7b7d6461 Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Tue, 13 Feb 2024 09:50:19 +0100 Subject: [PATCH 18/77] remove fake errors --- scripts/sandbox/generate.ts | 9 --------- 1 file changed, 9 deletions(-) diff --git a/scripts/sandbox/generate.ts b/scripts/sandbox/generate.ts index 91a4fd2fccd5..a28bbd6963f2 100755 --- a/scripts/sandbox/generate.ts +++ b/scripts/sandbox/generate.ts @@ -189,9 +189,6 @@ const runGenerators = async ( // where as others are very picky about what directories can be called. So we need to // handle different modes of operation. try { - if (Math.random() < 0.2) { - throw new Error('Blip Bloop random error when executing before-script'); - } if (script.includes('{{beforeDir}}')) { const scriptWithBeforeDir = script.replaceAll('{{beforeDir}}', BEFORE_DIR_NAME); await runCommand( @@ -227,9 +224,6 @@ const runGenerators = async ( await remove(join(beforeDir, '.git')); try { - if (Math.random() < 0.2) { - throw new Error('Blip Bloop random error when init storybook'); - } await addStorybook({ baseDir, localRegistry, flags, debug, env }); } catch (error) { const message = `❌ Failed to initialize Storybook in template: ${name} (${dirName})`; @@ -244,9 +238,6 @@ const runGenerators = async ( cause: error, }); } - if (Math.random() < 0.2) { - throw new Error('Blip Bloop random error anywhere'); - } await addDocumentation(baseDir, { name, dirName }); // Remove node_modules to save space and avoid GH actions failing From cea38444efa47fe291fe9cfddb1b255790951f05 Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Tue, 13 Feb 2024 12:31:57 +0100 Subject: [PATCH 19/77] =?UTF-8?q?actually=20remove=20fake=20errors=20?= =?UTF-8?q?=F0=9F=A4=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/sandbox/generate.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/scripts/sandbox/generate.ts b/scripts/sandbox/generate.ts index a28bbd6963f2..c313117987b5 100755 --- a/scripts/sandbox/generate.ts +++ b/scripts/sandbox/generate.ts @@ -87,9 +87,6 @@ const addStorybook = async ({ const tmpDir = directory(); try { - if (Math.random() < 0.2) { - throw new Error('Blip Bloop random error in addStorybook'); - } await copy(beforeDir, tmpDir); const packageManager = JsPackageManagerFactory.getPackageManager({ force: 'yarn1' }, tmpDir); From 1c3713eb6c54a5f66a0b55b1220b2edbfec57b5d Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Tue, 13 Feb 2024 21:28:14 +0100 Subject: [PATCH 20/77] always cleanup node_modules, don't collapse sandbox logs --- scripts/sandbox/generate.ts | 42 ++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/scripts/sandbox/generate.ts b/scripts/sandbox/generate.ts index c313117987b5..4e8f4bae1f4f 100755 --- a/scripts/sandbox/generate.ts +++ b/scripts/sandbox/generate.ts @@ -158,20 +158,15 @@ const runGenerators = async ( const generationResults = await Promise.allSettled( generators.map(({ dirName, name, script, expected, env }) => limit(async () => { + const baseDir = join(REPROS_DIRECTORY, dirName); + const beforeDir = join(baseDir, BEFORE_DIR_NAME); try { - if (isCI) { - ghActions.startGroup(`${name} (${dirName})`); - } - let flags: string[] = []; if (expected.renderer === '@storybook/html') flags = ['--type html']; else if (expected.renderer === '@storybook/server') flags = ['--type server']; const time = process.hrtime(); - console.log(`🧬 Generating ${name}`); - - const baseDir = join(REPROS_DIRECTORY, dirName); - const beforeDir = join(baseDir, BEFORE_DIR_NAME); + console.log(`🧬 Generating ${name} (${{ dirName }})`); await emptyDir(baseDir); // We do the creation inside a temp dir to avoid yarn container problems @@ -237,17 +232,8 @@ const runGenerators = async ( } await addDocumentation(baseDir, { name, dirName }); - // Remove node_modules to save space and avoid GH actions failing - // They're not uploaded to the git sandboxes repo anyway - if (process.env.CLEANUP_SANDBOX_NODE_MODULES) { - console.log(`πŸ—‘οΈ Removing ${join(beforeDir, 'node_modules')}`); - await remove(join(beforeDir, 'node_modules')); - console.log(`πŸ—‘οΈ Removing ${join(baseDir, AFTER_DIR_NAME, 'node_modules')}`); - await remove(join(baseDir, AFTER_DIR_NAME, 'node_modules')); - } - console.log( - `βœ… Created ${dirName} in ./${relative( + `βœ… Generated ${name} (${dirName}) in ./${relative( process.cwd(), baseDir )} successfully in ${prettyTime(process.hrtime(time))}` @@ -255,8 +241,13 @@ const runGenerators = async ( } catch (error) { throw error; } finally { - if (isCI) { - ghActions.endGroup(); + // Remove node_modules to save space and avoid GH actions failing + // They're not uploaded to the git sandboxes repo anyway + if (process.env.CLEANUP_SANDBOX_NODE_MODULES) { + console.log(`πŸ—‘οΈ Removing ${join(beforeDir, 'node_modules')}`); + await remove(join(beforeDir, 'node_modules')); + console.log(`πŸ—‘οΈ Removing ${join(baseDir, AFTER_DIR_NAME, 'node_modules')}`); + await remove(join(baseDir, AFTER_DIR_NAME, 'node_modules')); } } }) @@ -281,17 +272,20 @@ const runGenerators = async ( ], ...generationResults.map((result, index) => { const { name, dirName } = generators[index]; + const row = [name, `\`${dirName}\``]; if (result.status === 'fulfilled') { - return [name, dirName, '🟒 Pass']; + row.push('🟒 Pass'); + return row; } const generationError = (result as PromiseRejectedResult).reason as Error; if (generationError instanceof BeforeScriptExecutionError) { - return [name, dirName, 'πŸ”΄ Failed to execute before script']; + row.push('πŸ”΄ Failed to execute before script'); } else if (generationError instanceof StorybookInitError) { - return [name, dirName, 'πŸ”΄ Failed to initialize Storybook']; + row.push('πŸ”΄ Failed to initialize Storybook'); } else { - return [name, dirName, 'πŸ”΄ Failed with unknown error']; + row.push('πŸ”΄ Failed with unknown error'); } + return row; }), ]) .write(); From 01962f352935bba1cd3fc7ce52873a7edc6caa6f Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Tue, 13 Feb 2024 21:28:39 +0100 Subject: [PATCH 21/77] remove test variables from generate workflow, add job for main --- .github/workflows/generate-sandboxes.yml | 66 +++++++++++++++++++++--- 1 file changed, 59 insertions(+), 7 deletions(-) diff --git a/.github/workflows/generate-sandboxes.yml b/.github/workflows/generate-sandboxes.yml index 774cd297c571..88dc9e21bb41 100644 --- a/.github/workflows/generate-sandboxes.yml +++ b/.github/workflows/generate-sandboxes.yml @@ -6,12 +6,12 @@ on: workflow_dispatch: # To test fixes on push rather than wait for the scheduling, do the following: # 1. Uncomment the lines below and add your branch. - push: - branches: - - jeppe/25922-ci-generation-of-sandboxes-fail-sometimes-on-prereleases + # push: + # branches: + # - # 2. Change the "ref" value to in the actions/checkout step below. - # 3. Comment out the whole "generate-main" job starting at line 26 - # 3. πŸ‘‰ DON'T FORGET TO UNDO STEP 2 AND 3 BEFORE YOU MERGE YOUR CHANGES! + # 3. Comment out the whole "generate-main" job starting at line 77 + # 4. πŸ‘‰ DON'T FORGET TO UNDO THE STEPS BEFORE YOU MERGE YOUR CHANGES! env: YARN_ENABLE_IMMUTABLE_INSTALLS: "false" @@ -28,7 +28,7 @@ jobs: steps: - uses: actions/checkout@v4 with: - ref: jeppe/25922-ci-generation-of-sandboxes-fail-sometimes-on-prereleases + ref: next - uses: actions/setup-node@v4 with: @@ -62,7 +62,7 @@ jobs: - name: Publish # publish sandboxes even if the generation fails, as some sandboxes might have been generated successfully if: ${{ !cancelled() }} - run: yarn publish-sandboxes --remote=https://storybook-bot:${{ secrets.PAT_STORYBOOK_BOT }}@github.com/storybookjs/sandboxes.git --push --branch=jeppe/experiment-partial-generation + run: yarn publish-sandboxes --remote=https://storybook-bot:${{ secrets.PAT_STORYBOOK_BOT }}@github.com/storybookjs/sandboxes.git --push --branch=next - name: Report failure to Discord if: failure() @@ -73,3 +73,55 @@ jobs: args: | The generation of some or all sandboxes on the **next** branch has failed. [See the job summary for details](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) + + generate-main: + name: Generate to main + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + ref: main + + - uses: actions/setup-node@v4 + with: + node-version-file: ".nvmrc" + + - name: Setup git user + run: | + git config --global user.name "storybook-bot" + git config --global user.email "32066757+storybook-bot@users.noreply.github.com" + + - name: Install dependencies + working-directory: ./scripts + run: node --experimental-modules ./check-dependencies.js + + - name: Compile Storybook libraries + run: yarn task --task compile --start-from=auto --no-link + + - name: Publish to local registry + run: yarn local-registry --publish + + - name: Run local registry + run: yarn local-registry --open & + + - name: Wait for registry + run: yarn wait-on tcp:127.0.0.1:6001 + + - name: Generate + id: generate + run: yarn generate-sandboxes --local-registry + + - name: Publish + # publish sandboxes even if the generation fails, as some sandboxes might have been generated successfully + if: ${{ !cancelled() }} + run: yarn publish-sandboxes --remote=https://storybook-bot:${{ secrets.PAT_STORYBOOK_BOT }}@github.com/storybookjs/sandboxes.git --push --branch=main + + - name: Report failure to Discord + if: failure() + env: + DISCORD_WEBHOOK: ${{ secrets.DISCORD_MONITORING_URL }} + uses: Ilshidur/action-discord@master + with: + args: | + The generation of some or all sandboxes on the **main** branch has failed. + [See the job summary for details](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) From 43deb5f2ab9c3553daf6fccd0a4bc5ffdc76b6b5 Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Tue, 13 Feb 2024 21:37:01 +0100 Subject: [PATCH 22/77] only write summary in CI --- scripts/sandbox/generate.ts | 65 ++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 29 deletions(-) diff --git a/scripts/sandbox/generate.ts b/scripts/sandbox/generate.ts index 4e8f4bae1f4f..410d49373d93 100755 --- a/scripts/sandbox/generate.ts +++ b/scripts/sandbox/generate.ts @@ -254,42 +254,49 @@ const runGenerators = async ( ) ); + const hasGenerationErrors = generationResults.some((result) => result.status === 'rejected'); + + if (!isCI) { + if (hasGenerationErrors) { + throw new Error(`Some sandboxes failed to generate`); + } + return; + } + ghActions.summary.addHeading('Sandbox generation summary'); - if (!generationResults.some((result) => result.status === 'rejected')) { + if (!hasGenerationErrors) { await ghActions.summary.addRaw('βœ… Success!').write(); return; } - if (isCI) { - await ghActions.summary - .addRaw('Some sandboxes failed, see the job log for detailed errors') - .addTable([ - [ - { data: 'Name', header: true }, - { data: 'Key', header: true }, - { data: 'Result', header: true }, - ], - ...generationResults.map((result, index) => { - const { name, dirName } = generators[index]; - const row = [name, `\`${dirName}\``]; - if (result.status === 'fulfilled') { - row.push('🟒 Pass'); - return row; - } - const generationError = (result as PromiseRejectedResult).reason as Error; - if (generationError instanceof BeforeScriptExecutionError) { - row.push('πŸ”΄ Failed to execute before script'); - } else if (generationError instanceof StorybookInitError) { - row.push('πŸ”΄ Failed to initialize Storybook'); - } else { - row.push('πŸ”΄ Failed with unknown error'); - } + await ghActions.summary + .addRaw('Some sandboxes failed, see the job log for detailed errors') + .addTable([ + [ + { data: 'Name', header: true }, + { data: 'Key', header: true }, + { data: 'Result', header: true }, + ], + ...generationResults.map((result, index) => { + const { name, dirName } = generators[index]; + const row = [name, `\`${dirName}\``]; + if (result.status === 'fulfilled') { + row.push('🟒 Pass'); return row; - }), - ]) - .write(); - } + } + const generationError = (result as PromiseRejectedResult).reason as Error; + if (generationError instanceof BeforeScriptExecutionError) { + row.push('πŸ”΄ Failed to execute before script'); + } else if (generationError instanceof StorybookInitError) { + row.push('πŸ”΄ Failed to initialize Storybook'); + } else { + row.push('πŸ”΄ Failed with unknown error'); + } + return row; + }), + ]) + .write(); throw new Error(`Some sandboxes failed to generate`); }; From d8e40ace46938dc5f22813c15d4d7266d78d6261 Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Tue, 13 Feb 2024 21:45:08 +0100 Subject: [PATCH 23/77] typo --- scripts/sandbox/publish.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/sandbox/publish.ts b/scripts/sandbox/publish.ts index fc5d6b6db5a6..334e8a9177eb 100755 --- a/scripts/sandbox/publish.ts +++ b/scripts/sandbox/publish.ts @@ -37,7 +37,7 @@ const publish = async (options: PublishOptions & { tmpFolder: string }) => { await Promise.all( // find all successfully generated after-storybook/README.md files // eg. /home/repros/react-vite/default-ts/after-storybook/README.md - // README.md being the last fil generated, thus representing a successful generation + // README.md being the last file generated, thus representing a successful generation (await glob(join(REPROS_DIRECTORY, '**', 'after-storybook/README.md'))).map((readmePath) => { // get the after-storybook path relative to the source 'repros' directory // eg. ./react-vite/default-ts/after-storybook From 249276b860be1354d523f940076a3ae609f113be Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Fri, 23 Feb 2024 13:25:04 +0100 Subject: [PATCH 24/77] support new way of mounting components in svelte 5 --- code/renderers/svelte/package.json | 11 +- .../svelte/src/createSvelte5Props.svelte.js | 12 ++ code/renderers/svelte/src/render.ts | 161 ++++++++++++------ .../svelte/templates/PreviewRender.svelte | 36 ++-- code/yarn.lock | 91 ++++++++-- 5 files changed, 227 insertions(+), 84 deletions(-) create mode 100644 code/renderers/svelte/src/createSvelte5Props.svelte.js diff --git a/code/renderers/svelte/package.json b/code/renderers/svelte/package.json index d7efba34d699..03a0f1da6664 100644 --- a/code/renderers/svelte/package.json +++ b/code/renderers/svelte/package.json @@ -32,7 +32,8 @@ "./package.json": "./package.json", "./templates/HOC.svelte": "./templates/HOC.svelte", "./templates/PreviewRender.svelte": "./templates/PreviewRender.svelte", - "./templates/SlotDecorator.svelte": "./templates/SlotDecorator.svelte" + "./templates/SlotDecorator.svelte": "./templates/SlotDecorator.svelte", + "./internal/createSvelte5Props": "./src/createSvelte5Props.svelte.js" }, "main": "dist/index.js", "module": "dist/index.mjs", @@ -62,14 +63,14 @@ "type-fest": "~2.19" }, "devDependencies": { - "@sveltejs/vite-plugin-svelte": "^3.0.1", + "@sveltejs/vite-plugin-svelte": "^3.0.2", "expect-type": "^0.15.0", - "svelte": "^5.0.0-next.28", - "svelte-check": "^3.6.1", + "svelte": "^5.0.0-next.65", + "svelte-check": "^3.6.4", "typescript": "^5.3.2" }, "peerDependencies": { - "svelte": "^4.0.0 || ^5.0.0-next.16" + "svelte": "^4.0.0 || ^5.0.0-next.65" }, "engines": { "node": ">=18.0.0" diff --git a/code/renderers/svelte/src/createSvelte5Props.svelte.js b/code/renderers/svelte/src/createSvelte5Props.svelte.js new file mode 100644 index 000000000000..bef729413204 --- /dev/null +++ b/code/renderers/svelte/src/createSvelte5Props.svelte.js @@ -0,0 +1,12 @@ +/** + * Turns an object into reactive props in Svelte 5. + * Needs to be in a separate .svelte.js file to ensure Svelte + * compiles it. + * @template TProps + * @param {TProps} data - The data to create Svelte 5 props from. + * @returns {TProps} - The created Svelte 5 props. + */ +export const createSvelte5Props = (data) => { + const props = $state(data); + return props; +}; diff --git a/code/renderers/svelte/src/render.ts b/code/renderers/svelte/src/render.ts index 514b3128ed21..c9925d56e0ca 100644 --- a/code/renderers/svelte/src/render.ts +++ b/code/renderers/svelte/src/render.ts @@ -1,50 +1,30 @@ import type { RenderContext, ArgsStoryFn } from '@storybook/types'; import { RESET_STORY_ARGS } from '@storybook/core-events'; -// ! DO NOT change this PreviewRender import to a relative path, it will break it. -// ! A relative import will be compiled at build time, and Svelte will be unable to -// ! render the component together with the user's Svelte components -// ! importing from @storybook/svelte will make sure that it is compiled at runtime -// ! with the same bundle as the user's Svelte components +// ! DO NOT change these PreviewRender and createSvelte5Props imports to relative paths, it will break them. +// ! Relative imports will be compiled at build time by tsup, but we need Svelte to compile them +// ! when compiling the rest of the Svelte files. // eslint-disable-next-line import/no-extraneous-dependencies import PreviewRender from '@storybook/svelte/templates/PreviewRender.svelte'; +// @ts-expect-error Don't know why TS doesn't pick up the types export here +import { createSvelte5Props } from '@storybook/svelte/internal/createSvelte5Props'; + import { addons } from '@storybook/preview-api'; import * as svelte from 'svelte'; +import { VERSION as SVELTE_VERSION } from 'svelte/compiler'; import type { SvelteRenderer } from './types'; -const componentsByDomElement = new Map< - SvelteRenderer['canvasElement'], - any // ReturnType depends on the version of Svelte v4 or v5 ->(); - -function teardown(canvasElement: SvelteRenderer['canvasElement']) { - if (!componentsByDomElement.has(canvasElement)) { - return; - } - - componentsByDomElement.get(canvasElement)!.$destroy(); - - canvasElement.innerHTML = ''; - componentsByDomElement.delete(canvasElement); -} +const IS_SVELTE_V4 = Number(SVELTE_VERSION[0]) >= 4; -/** - * Mount the PreviewRender component to the provided canvasElement - * Either using the Svelte v4 or v5 API - */ -function createRoot(target: HTMLElement, props: any) { - if ((svelte as any).createRoot) { - // Svelte v5 - return (svelte as any).createRoot(PreviewRender, { - target, - props, - }); +export function renderToCanvas( + renderContext: RenderContext, + canvasElement: SvelteRenderer['canvasElement'] +) { + if (IS_SVELTE_V4) { + return renderToCanvasV4(renderContext, canvasElement); + } else { + return renderToCanvasV5(renderContext, canvasElement); } - // Svelte v4 - return new (PreviewRender as any)({ - target, - props, - }); } /** @@ -55,16 +35,21 @@ function createRoot(target: HTMLElement, props: any) { * * We listen for the RESET_STORY_ARGS event and store the storyId to be reset * We then use this in the renderToCanvas function to force remount the story + * + * This is only necessary in Svelte v4 */ const storyIdsToRemountFromResetArgsEvent = new Set(); -addons.getChannel().on(RESET_STORY_ARGS, ({ storyId }) => { - storyIdsToRemountFromResetArgsEvent.add(storyId); -}); +if (IS_SVELTE_V4) { + addons.getChannel().on(RESET_STORY_ARGS, ({ storyId }) => { + storyIdsToRemountFromResetArgsEvent.add(storyId); + }); +} +const componentsByDomElementV4 = new Map(); -export function renderToCanvas( +function renderToCanvasV4( { storyFn, - kind, + title, name, showMain, showError, @@ -73,43 +58,117 @@ export function renderToCanvas( }: RenderContext, canvasElement: SvelteRenderer['canvasElement'] ) { - const existingComponent = componentsByDomElement.get(canvasElement); + function unmount(canvasElementToUnmount: SvelteRenderer['canvasElement']) { + if (!componentsByDomElementV4.has(canvasElementToUnmount)) { + return; + } + componentsByDomElementV4.get(canvasElementToUnmount)!.$destroy(); + componentsByDomElementV4.delete(canvasElementToUnmount); + canvasElementToUnmount.innerHTML = ''; + } + const existingComponent = componentsByDomElementV4.get(canvasElement); let remount = forceRemount; - if (storyIdsToRemountFromResetArgsEvent.has(storyContext.id)) { remount = true; storyIdsToRemountFromResetArgsEvent.delete(storyContext.id); } if (remount) { - teardown(canvasElement); + unmount(canvasElement); } if (!existingComponent || remount) { - const createdComponent = createRoot(canvasElement, { + const mountedComponent = new PreviewRender({ + target: canvasElement, + props: { + storyFn, + storyContext, + name, + title, + showError, + }, + }); + componentsByDomElementV4.set(canvasElement, mountedComponent); + } else { + existingComponent.$set({ + storyFn, + storyContext, + name, + title, + showError, + }); + } + + showMain(); + + // unmount the component when the story changes + return () => { + unmount(canvasElement); + }; +} + +const componentsByDomElementV5 = new Map< + SvelteRenderer['canvasElement'], + { mountedComponent: ReturnType<(typeof svelte)['mount']>; props: RenderContext } +>(); + +function renderToCanvasV5( + { + storyFn, + title, + name, + showMain, + showError, + storyContext, + forceRemount, + }: RenderContext, + canvasElement: SvelteRenderer['canvasElement'] +) { + function unmount(canvasElementToUnmount: SvelteRenderer['canvasElement']) { + const { mountedComponent } = componentsByDomElementV5.get(canvasElementToUnmount) ?? {}; + if (!mountedComponent) { + return; + } + svelte.unmount(mountedComponent); + componentsByDomElementV5.delete(canvasElementToUnmount); + } + + const existingComponent = componentsByDomElementV5.get(canvasElement); + + if (forceRemount) { + unmount(canvasElement); + } + + if (!existingComponent || forceRemount) { + const props = createSvelte5Props({ storyFn, storyContext, name, - kind, + title, showError, }); - componentsByDomElement.set(canvasElement, createdComponent); + const mountedComponent = svelte.mount(PreviewRender, { + target: canvasElement, + props, + }); + componentsByDomElementV5.set(canvasElement, { mountedComponent, props }); } else { - existingComponent.$set({ + // We need to mutate the existing props for Svelte reactivity to work, we can't just re-assign them + Object.assign(existingComponent.props, { storyFn, storyContext, name, - kind, + title, showError, }); } showMain(); - // teardown the component when the story changes + // unmount the component when the story changes return () => { - teardown(canvasElement); + unmount(canvasElement); }; } diff --git a/code/renderers/svelte/templates/PreviewRender.svelte b/code/renderers/svelte/templates/PreviewRender.svelte index 581aa4d78e05..b2900a0ddb24 100644 --- a/code/renderers/svelte/templates/PreviewRender.svelte +++ b/code/renderers/svelte/templates/PreviewRender.svelte @@ -3,7 +3,7 @@ import { dedent } from 'ts-dedent'; export let name; - export let kind; + export let title; export let storyFn; export let showError; export let storyContext; @@ -17,22 +17,22 @@ on, } = storyFn(); - let firstTime = true; - - // the first time we don't want to call storyFn two times so we just return the values - // we already have from the previous call. If storyFn changes this function will run - // again but this time firstTime will be false - function getStoryFnValue(storyFn){ - if(firstTime){ - firstTime = false; - return { - Component, - props, - on, - } - } - return storyFn(); - } + let firstTime = true; + + // the first time we don't want to call storyFn two times so we just return the values + // we already have from the previous call. If storyFn changes this function will run + // again but this time firstTime will be false + function getStoryFnValue(storyFn) { + if (firstTime) { + firstTime = false; + return { + Component, + props, + on, + }; + } + return storyFn(); + } // reactive, re-render on storyFn change $: ({ Component, props = {}, on } = getStoryFnValue(storyFn)); @@ -45,7 +45,7 @@ if (!Component) { showError({ - title: `Expecting a Svelte component from the story: "${name}" of "${kind}".`, + title: `Expecting a Svelte component from the story: "${name}" of "${title}".`, description: dedent` Did you forget to return the Svelte component configuration from the story? Use "() => ({ Component: YourComponent, props: {} })" diff --git a/code/yarn.lock b/code/yarn.lock index 07c7d2bd6b0e..5d66006d503e 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -6676,16 +6676,16 @@ __metadata: "@storybook/global": "npm:^5.0.0" "@storybook/preview-api": "workspace:*" "@storybook/types": "workspace:*" - "@sveltejs/vite-plugin-svelte": "npm:^3.0.1" + "@sveltejs/vite-plugin-svelte": "npm:^3.0.2" expect-type: "npm:^0.15.0" - svelte: "npm:^5.0.0-next.28" - svelte-check: "npm:^3.6.1" + svelte: "npm:^5.0.0-next.65" + svelte-check: "npm:^3.6.4" sveltedoc-parser: "npm:^4.2.1" ts-dedent: "npm:^2.0.0" type-fest: "npm:~2.19" typescript: "npm:^5.3.2" peerDependencies: - svelte: ^4.0.0 || ^5.0.0-next.16 + svelte: ^4.0.0 || ^5.0.0-next.65 languageName: unknown linkType: soft @@ -6919,7 +6919,7 @@ __metadata: languageName: node linkType: hard -"@sveltejs/vite-plugin-svelte-inspector@npm:^2.0.0-next.0 || ^2.0.0": +"@sveltejs/vite-plugin-svelte-inspector@npm:^2.0.0, @sveltejs/vite-plugin-svelte-inspector@npm:^2.0.0-next.0 || ^2.0.0": version: 2.0.0 resolution: "@sveltejs/vite-plugin-svelte-inspector@npm:2.0.0" dependencies: @@ -6950,6 +6950,24 @@ __metadata: languageName: node linkType: hard +"@sveltejs/vite-plugin-svelte@npm:^3.0.2": + version: 3.0.2 + resolution: "@sveltejs/vite-plugin-svelte@npm:3.0.2" + dependencies: + "@sveltejs/vite-plugin-svelte-inspector": "npm:^2.0.0" + debug: "npm:^4.3.4" + deepmerge: "npm:^4.3.1" + kleur: "npm:^4.1.5" + magic-string: "npm:^0.30.5" + svelte-hmr: "npm:^0.15.3" + vitefu: "npm:^0.2.5" + peerDependencies: + svelte: ^4.0.0 || ^5.0.0-next.0 + vite: ^5.0.0 + checksum: 7150877f61b65a51d55916fccacb7851859b0aab9c7e4f591c98b6775a7e55f5410cc854add4c427f99978f115a92ac75f116a813b67814cc7801daac1b78439 + languageName: node + linkType: hard + "@swc/helpers@npm:0.5.2": version: 0.5.2 resolution: "@swc/helpers@npm:0.5.2" @@ -7432,6 +7450,13 @@ __metadata: languageName: node linkType: hard +"@types/estree@npm:^1.0.5": + version: 1.0.5 + resolution: "@types/estree@npm:1.0.5" + checksum: b3b0e334288ddb407c7b3357ca67dbee75ee22db242ca7c56fe27db4e1a31989cb8af48a84dd401deb787fe10cc6b2ab1ee82dc4783be87ededbe3d53c79c70d + languageName: node + linkType: hard + "@types/express-serve-static-core@npm:*, @types/express-serve-static-core@npm:^4.17.33": version: 4.17.37 resolution: "@types/express-serve-static-core@npm:4.17.37" @@ -9266,6 +9291,15 @@ __metadata: languageName: node linkType: hard +"acorn-typescript@npm:^1.4.13": + version: 1.4.13 + resolution: "acorn-typescript@npm:1.4.13" + peerDependencies: + acorn: ">=8.9.0" + checksum: f2f17cf03379d63beeb007f0feea02cebbd9af261f6b5619ea7345b177bd7a5f99752927cbf652baa3fc97962ae4561592093ab0a1c3e00ca4f354ba23c557ae + languageName: node + linkType: hard + "acorn-walk@npm:^7.2.0": version: 7.2.0 resolution: "acorn-walk@npm:7.2.0" @@ -9305,6 +9339,15 @@ __metadata: languageName: node linkType: hard +"acorn@npm:^8.11.3": + version: 8.11.3 + resolution: "acorn@npm:8.11.3" + bin: + acorn: bin/acorn + checksum: 3ff155f8812e4a746fee8ecff1f227d527c4c45655bb1fad6347c3cb58e46190598217551b1500f18542d2bbe5c87120cb6927f5a074a59166fbdd9468f0a299 + languageName: node + linkType: hard + "address@npm:^1.0.1": version: 1.2.2 resolution: "address@npm:1.2.2" @@ -17871,7 +17914,7 @@ __metadata: languageName: node linkType: hard -"is-reference@npm:^3.0.0, is-reference@npm:^3.0.1": +"is-reference@npm:^3.0.0, is-reference@npm:^3.0.1, is-reference@npm:^3.0.2": version: 3.0.2 resolution: "is-reference@npm:3.0.2" dependencies: @@ -27088,9 +27131,9 @@ __metadata: languageName: node linkType: hard -"svelte-check@npm:^3.6.1": - version: 3.6.2 - resolution: "svelte-check@npm:3.6.2" +"svelte-check@npm:^3.6.4": + version: 3.6.4 + resolution: "svelte-check@npm:3.6.4" dependencies: "@jridgewell/trace-mapping": "npm:^0.3.17" chokidar: "npm:^3.4.1" @@ -27104,7 +27147,7 @@ __metadata: svelte: ^3.55.0 || ^4.0.0-next.0 || ^4.0.0 || ^5.0.0-next.0 bin: svelte-check: bin/svelte-check - checksum: 3f389df29268d4df9b561d0b206566e827af84923c70150b2dadfd407bcbdaccbfd561bd8b93884597de62477d62826ff1a5108854641078b692130441a49a55 + checksum: acbcc04c8c6ab7baee7ccf36ca134dcabe49fae103aa92661e7f80e01216623363fb794fec9a3f794f7003d55629373567ff485925dc33272f48cea63e7b2452 languageName: node linkType: hard @@ -27233,6 +27276,27 @@ __metadata: languageName: node linkType: hard +"svelte@npm:^5.0.0-next.65": + version: 5.0.0-next.65 + resolution: "svelte@npm:5.0.0-next.65" + dependencies: + "@ampproject/remapping": "npm:^2.2.1" + "@jridgewell/sourcemap-codec": "npm:^1.4.15" + "@types/estree": "npm:^1.0.5" + acorn: "npm:^8.11.3" + acorn-typescript: "npm:^1.4.13" + aria-query: "npm:^5.3.0" + axobject-query: "npm:^4.0.0" + esm-env: "npm:^1.0.0" + esrap: "npm:^1.2.1" + is-reference: "npm:^3.0.2" + locate-character: "npm:^3.0.0" + magic-string: "npm:^0.30.5" + zimmerframe: "npm:^1.1.2" + checksum: 6a686847f887d2871eabce4888916cba6aec5bae924a76fd01f4098db1c0053d4e5d6434070d0a048eac75eaddd4fd40e3fae625a0253464f7baa6b0f147f209 + languageName: node + linkType: hard + "sveltedoc-parser@npm:^4.2.1": version: 4.3.1 resolution: "sveltedoc-parser@npm:4.3.1" @@ -30261,6 +30325,13 @@ __metadata: languageName: node linkType: hard +"zimmerframe@npm:^1.1.2": + version: 1.1.2 + resolution: "zimmerframe@npm:1.1.2" + checksum: 8f693609c31cbb4449db223acd61661bc93b73e615f9db6fb8c86d4ceea84ca54cbbeebcf53cf74c22a1f923b92abd18e97988a5e175c76b6ab17238e5593a9d + languageName: node + linkType: hard + "zod@npm:^3.22.2": version: 3.22.4 resolution: "zod@npm:3.22.4" From f37524b8e07bf104dc758ac484a932fc38e80b89 Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Mon, 26 Feb 2024 08:51:54 +0100 Subject: [PATCH 25/77] move and cleanup Svelte components --- code/frameworks/svelte-webpack5/src/typings.d.ts | 5 ++--- code/renderers/svelte/package.json | 5 ++--- .../{templates => src/components}/PreviewRender.svelte | 0 .../{templates => src/components}/SlotDecorator.svelte | 0 code/renderers/svelte/src/decorators.ts | 3 +-- code/renderers/svelte/src/render.ts | 3 +-- code/renderers/svelte/templates/HOC.svelte | 7 ------- 7 files changed, 6 insertions(+), 17 deletions(-) rename code/renderers/svelte/{templates => src/components}/PreviewRender.svelte (100%) rename code/renderers/svelte/{templates => src/components}/SlotDecorator.svelte (100%) delete mode 100644 code/renderers/svelte/templates/HOC.svelte diff --git a/code/frameworks/svelte-webpack5/src/typings.d.ts b/code/frameworks/svelte-webpack5/src/typings.d.ts index 48e7ba6228fd..153f6ec1f9ce 100644 --- a/code/frameworks/svelte-webpack5/src/typings.d.ts +++ b/code/frameworks/svelte-webpack5/src/typings.d.ts @@ -1,3 +1,2 @@ -declare module '@storybook/svelte/templates/SlotDecorator.svelte'; -declare module '@storybook/svelte/templates/PreviewRender.svelte'; -declare module '@storybook/svelte/templates/HOC.svelte'; +declare module '@storybook/svelte/internal/SlotDecorator.svelte'; +declare module '@storybook/svelte/internal/PreviewRender.svelte'; diff --git a/code/renderers/svelte/package.json b/code/renderers/svelte/package.json index 03a0f1da6664..6fdccc844d86 100644 --- a/code/renderers/svelte/package.json +++ b/code/renderers/svelte/package.json @@ -30,9 +30,8 @@ "./dist/entry-preview.mjs": "./dist/entry-preview.mjs", "./dist/entry-preview-docs.mjs": "./dist/entry-preview-docs.mjs", "./package.json": "./package.json", - "./templates/HOC.svelte": "./templates/HOC.svelte", - "./templates/PreviewRender.svelte": "./templates/PreviewRender.svelte", - "./templates/SlotDecorator.svelte": "./templates/SlotDecorator.svelte", + "./internal/PreviewRender.svelte": "./src/components/PreviewRender.svelte", + "./internal/SlotDecorator.svelte": "./src/components/SlotDecorator.svelte", "./internal/createSvelte5Props": "./src/createSvelte5Props.svelte.js" }, "main": "dist/index.js", diff --git a/code/renderers/svelte/templates/PreviewRender.svelte b/code/renderers/svelte/src/components/PreviewRender.svelte similarity index 100% rename from code/renderers/svelte/templates/PreviewRender.svelte rename to code/renderers/svelte/src/components/PreviewRender.svelte diff --git a/code/renderers/svelte/templates/SlotDecorator.svelte b/code/renderers/svelte/src/components/SlotDecorator.svelte similarity index 100% rename from code/renderers/svelte/templates/SlotDecorator.svelte rename to code/renderers/svelte/src/components/SlotDecorator.svelte diff --git a/code/renderers/svelte/src/decorators.ts b/code/renderers/svelte/src/decorators.ts index 07fb1753b56d..58ca0f7ea229 100644 --- a/code/renderers/svelte/src/decorators.ts +++ b/code/renderers/svelte/src/decorators.ts @@ -5,8 +5,7 @@ import { sanitizeStoryContextUpdate } from '@storybook/preview-api'; // ! render the component together with the user's Svelte components // ! importing from @storybook/svelte will make sure that it is compiled at runtime // ! with the same bundle as the user's Svelte components -// eslint-disable-next-line import/no-extraneous-dependencies -import SlotDecorator from '@storybook/svelte/templates/SlotDecorator.svelte'; +import SlotDecorator from '@storybook/svelte/internal/SlotDecorator.svelte'; import type { SvelteRenderer } from './types'; /** diff --git a/code/renderers/svelte/src/render.ts b/code/renderers/svelte/src/render.ts index c9925d56e0ca..c828fe831834 100644 --- a/code/renderers/svelte/src/render.ts +++ b/code/renderers/svelte/src/render.ts @@ -3,8 +3,7 @@ import { RESET_STORY_ARGS } from '@storybook/core-events'; // ! DO NOT change these PreviewRender and createSvelte5Props imports to relative paths, it will break them. // ! Relative imports will be compiled at build time by tsup, but we need Svelte to compile them // ! when compiling the rest of the Svelte files. -// eslint-disable-next-line import/no-extraneous-dependencies -import PreviewRender from '@storybook/svelte/templates/PreviewRender.svelte'; +import PreviewRender from '@storybook/svelte/internal/PreviewRender.svelte'; // @ts-expect-error Don't know why TS doesn't pick up the types export here import { createSvelte5Props } from '@storybook/svelte/internal/createSvelte5Props'; diff --git a/code/renderers/svelte/templates/HOC.svelte b/code/renderers/svelte/templates/HOC.svelte deleted file mode 100644 index 0b6c3618701e..000000000000 --- a/code/renderers/svelte/templates/HOC.svelte +++ /dev/null @@ -1,7 +0,0 @@ - - - \ No newline at end of file From 1b17dfee562a85be19013071f1d7703b945d9b2a Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Mon, 26 Feb 2024 09:10:06 +0100 Subject: [PATCH 26/77] comment improvements --- .../svelte/src/createSvelte5Props.svelte.js | 1 + code/renderers/svelte/src/decorators.ts | 12 +++++++----- code/renderers/svelte/src/render.ts | 8 +++++--- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/code/renderers/svelte/src/createSvelte5Props.svelte.js b/code/renderers/svelte/src/createSvelte5Props.svelte.js index bef729413204..bbefc19bbf43 100644 --- a/code/renderers/svelte/src/createSvelte5Props.svelte.js +++ b/code/renderers/svelte/src/createSvelte5Props.svelte.js @@ -2,6 +2,7 @@ * Turns an object into reactive props in Svelte 5. * Needs to be in a separate .svelte.js file to ensure Svelte * compiles it. + * As proposed in https://github.com/sveltejs/svelte/issues/9827#issuecomment-1845589616 * @template TProps * @param {TProps} data - The data to create Svelte 5 props from. * @returns {TProps} - The created Svelte 5 props. diff --git a/code/renderers/svelte/src/decorators.ts b/code/renderers/svelte/src/decorators.ts index 58ca0f7ea229..657fa91ff28e 100644 --- a/code/renderers/svelte/src/decorators.ts +++ b/code/renderers/svelte/src/decorators.ts @@ -1,10 +1,12 @@ import type { DecoratorFunction, StoryContext, LegacyStoryFn } from '@storybook/types'; import { sanitizeStoryContextUpdate } from '@storybook/preview-api'; -// ! DO NOT change this SlotDecorator import to a relative path, it will break it. -// ! A relative import will be compiled at build time, and Svelte will be unable to -// ! render the component together with the user's Svelte components -// ! importing from @storybook/svelte will make sure that it is compiled at runtime -// ! with the same bundle as the user's Svelte components +/* +! DO NOT change this SlotDecorator import to a relative path, it will break it. +! A relative import will be compiled at build time, and Svelte will be unable to +! render the component together with the user's Svelte components +! importing from @storybook/svelte will make sure that it is compiled at runtime +! with the same bundle as the user's Svelte components +*/ import SlotDecorator from '@storybook/svelte/internal/SlotDecorator.svelte'; import type { SvelteRenderer } from './types'; diff --git a/code/renderers/svelte/src/render.ts b/code/renderers/svelte/src/render.ts index c828fe831834..f8875a13e815 100644 --- a/code/renderers/svelte/src/render.ts +++ b/code/renderers/svelte/src/render.ts @@ -1,8 +1,10 @@ import type { RenderContext, ArgsStoryFn } from '@storybook/types'; import { RESET_STORY_ARGS } from '@storybook/core-events'; -// ! DO NOT change these PreviewRender and createSvelte5Props imports to relative paths, it will break them. -// ! Relative imports will be compiled at build time by tsup, but we need Svelte to compile them -// ! when compiling the rest of the Svelte files. +/* +! DO NOT change these PreviewRender and createSvelte5Props imports to relative paths, it will break them. +! Relative imports will be compiled at build time by tsup, but we need Svelte to compile them +! when compiling the rest of the Svelte files. +*/ import PreviewRender from '@storybook/svelte/internal/PreviewRender.svelte'; // @ts-expect-error Don't know why TS doesn't pick up the types export here import { createSvelte5Props } from '@storybook/svelte/internal/createSvelte5Props'; From a3bfcbb2511b4f8e226ce4099f8f0f61649878b1 Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Mon, 26 Feb 2024 14:47:52 +0100 Subject: [PATCH 27/77] =?UTF-8?q?Fix=20Svelte=20version=20check.=20?= =?UTF-8?q?=F0=9F=A4=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- code/renderers/svelte/src/render.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/renderers/svelte/src/render.ts b/code/renderers/svelte/src/render.ts index f8875a13e815..3b22469af003 100644 --- a/code/renderers/svelte/src/render.ts +++ b/code/renderers/svelte/src/render.ts @@ -15,7 +15,7 @@ import { VERSION as SVELTE_VERSION } from 'svelte/compiler'; import type { SvelteRenderer } from './types'; -const IS_SVELTE_V4 = Number(SVELTE_VERSION[0]) >= 4; +const IS_SVELTE_V4 = Number(SVELTE_VERSION[0]) <= 4; export function renderToCanvas( renderContext: RenderContext, From 80cb9ec4ea11e7874a808a71e92bcc3069d703fb Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Mon, 26 Feb 2024 14:48:58 +0100 Subject: [PATCH 28/77] fix internal unbundled file references --- code/renderers/svelte/package.json | 9 ++++---- .../svelte/scripts/copy-unbundled-to-dist.ts | 23 +++++++++++++++++++ 2 files changed, 28 insertions(+), 4 deletions(-) create mode 100644 code/renderers/svelte/scripts/copy-unbundled-to-dist.ts diff --git a/code/renderers/svelte/package.json b/code/renderers/svelte/package.json index 6fdccc844d86..c26cf76409f3 100644 --- a/code/renderers/svelte/package.json +++ b/code/renderers/svelte/package.json @@ -30,16 +30,15 @@ "./dist/entry-preview.mjs": "./dist/entry-preview.mjs", "./dist/entry-preview-docs.mjs": "./dist/entry-preview-docs.mjs", "./package.json": "./package.json", - "./internal/PreviewRender.svelte": "./src/components/PreviewRender.svelte", - "./internal/SlotDecorator.svelte": "./src/components/SlotDecorator.svelte", - "./internal/createSvelte5Props": "./src/createSvelte5Props.svelte.js" + "./internal/PreviewRender.svelte": "./dist/components/PreviewRender.svelte", + "./internal/SlotDecorator.svelte": "./dist/components/SlotDecorator.svelte", + "./internal/createSvelte5Props": "./dist/createSvelte5Props.svelte.js" }, "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/index.d.ts", "files": [ "dist/**/*", - "templates/**/*", "template/cli/**/*", "README.md", "*.js", @@ -64,6 +63,7 @@ "devDependencies": { "@sveltejs/vite-plugin-svelte": "^3.0.2", "expect-type": "^0.15.0", + "fs-extra": "^11.1.0", "svelte": "^5.0.0-next.65", "svelte-check": "^3.6.4", "typescript": "^5.3.2" @@ -78,6 +78,7 @@ "access": "public" }, "bundler": { + "post": "./scripts/copy-unbundled-to-dist.ts", "entries": [ "./src/index.ts", "./src/preset.ts", diff --git a/code/renderers/svelte/scripts/copy-unbundled-to-dist.ts b/code/renderers/svelte/scripts/copy-unbundled-to-dist.ts new file mode 100644 index 000000000000..a82964679960 --- /dev/null +++ b/code/renderers/svelte/scripts/copy-unbundled-to-dist.ts @@ -0,0 +1,23 @@ +import { copy } from 'fs-extra'; +import { join } from 'path'; + +const src = join(__dirname, '..', 'src'); +const dist = join(__dirname, '..', 'dist'); + +// relative to src directory +const PATHS_TO_COPY = ['createSvelte5Props.svelte.js', 'components']; + +const run = async () => { + console.log('Copying unbundled files to dist...'); + await Promise.all( + PATHS_TO_COPY.map((pathToCopy) => + copy(join(src, pathToCopy), join(dist, pathToCopy), { overwrite: true }) + ) + ); + console.log('Done!'); +}; + +run().catch((e) => { + console.error(e); + process.exitCode = 1; +}); From 2d5f1f55f46cc6b0e6d307db77f2760cf6c13dc5 Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Mon, 26 Feb 2024 14:49:31 +0100 Subject: [PATCH 29/77] pin Svelte 5 version to next.65 --- code/frameworks/svelte-vite/package.json | 4 +- code/frameworks/svelte-webpack5/package.json | 2 +- code/frameworks/sveltekit/package.json | 2 +- code/package.json | 2 +- code/presets/svelte-webpack/package.json | 2 +- code/yarn.lock | 49 +++----------------- 6 files changed, 13 insertions(+), 48 deletions(-) diff --git a/code/frameworks/svelte-vite/package.json b/code/frameworks/svelte-vite/package.json index 78d2347568ed..dc6da57aad4b 100644 --- a/code/frameworks/svelte-vite/package.json +++ b/code/frameworks/svelte-vite/package.json @@ -58,13 +58,13 @@ "devDependencies": { "@sveltejs/vite-plugin-svelte": "^3.0.1", "@types/node": "^18.0.0", - "svelte": "^5.0.0-next.28", + "svelte": "^5.0.0-next.65", "typescript": "^5.3.2", "vite": "^4.0.0" }, "peerDependencies": { "@sveltejs/vite-plugin-svelte": "^2.0.0 || ^3.0.0", - "svelte": "^4.0.0 || ^5.0.0-next.16", + "svelte": "^4.0.0 || ^5.0.0-next.65", "vite": "^4.0.0 || ^5.0.0" }, "engines": { diff --git a/code/frameworks/svelte-webpack5/package.json b/code/frameworks/svelte-webpack5/package.json index eebe0738192b..a6e32e26c4f1 100644 --- a/code/frameworks/svelte-webpack5/package.json +++ b/code/frameworks/svelte-webpack5/package.json @@ -58,7 +58,7 @@ "typescript": "^5.3.2" }, "peerDependencies": { - "svelte": "^4.0.0 || ^5.0.0-next.16", + "svelte": "^4.0.0 || ^5.0.0-next.65", "svelte-loader": "*" }, "engines": { diff --git a/code/frameworks/sveltekit/package.json b/code/frameworks/sveltekit/package.json index 4c451ff5e4d7..44c0db39e4a9 100644 --- a/code/frameworks/sveltekit/package.json +++ b/code/frameworks/sveltekit/package.json @@ -64,7 +64,7 @@ "vite": "^4.0.0" }, "peerDependencies": { - "svelte": "^4.0.0 || ^5.0.0-next.16", + "svelte": "^4.0.0 || ^5.0.0-next.65", "vite": "^4.0.0 || ^5.0.0" }, "engines": { diff --git a/code/package.json b/code/package.json index 1d6e075439ea..4a7377133993 100644 --- a/code/package.json +++ b/code/package.json @@ -212,7 +212,7 @@ "react-dom": "^18.2.0", "semver": "^7.3.7", "serve-static": "^1.14.1", - "svelte": "^5.0.0-next.28", + "svelte": "^5.0.0-next.65", "trash": "^7.0.0", "ts-dedent": "^2.0.0", "ts-node": "^10.9.1", diff --git a/code/presets/svelte-webpack/package.json b/code/presets/svelte-webpack/package.json index 008078d8721c..dcb985c2737e 100644 --- a/code/presets/svelte-webpack/package.json +++ b/code/presets/svelte-webpack/package.json @@ -75,7 +75,7 @@ "typescript": "^5.3.2" }, "peerDependencies": { - "svelte": "^4.0.0 || ^5.0.0-next.16", + "svelte": "^4.0.0 || ^5.0.0-next.65", "svelte-loader": "*" }, "engines": { diff --git a/code/yarn.lock b/code/yarn.lock index 5d66006d503e..ba606272fc36 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -6230,7 +6230,7 @@ __metadata: ts-dedent: "npm:^2.0.0" typescript: "npm:^5.3.2" peerDependencies: - svelte: ^4.0.0 || ^5.0.0-next.16 + svelte: ^4.0.0 || ^5.0.0-next.65 svelte-loader: "*" languageName: unknown linkType: soft @@ -6536,7 +6536,7 @@ __metadata: react-dom: "npm:^18.2.0" semver: "npm:^7.3.7" serve-static: "npm:^1.14.1" - svelte: "npm:^5.0.0-next.28" + svelte: "npm:^5.0.0-next.65" trash: "npm:^7.0.0" ts-dedent: "npm:^2.0.0" ts-node: "npm:^10.9.1" @@ -6636,7 +6636,7 @@ __metadata: "@sveltejs/vite-plugin-svelte": "npm:^3.0.1" "@types/node": "npm:^18.0.0" magic-string: "npm:^0.30.0" - svelte: "npm:^5.0.0-next.28" + svelte: "npm:^5.0.0-next.65" svelte-preprocess: "npm:^5.1.1" sveltedoc-parser: "npm:^4.2.1" ts-dedent: "npm:^2.2.0" @@ -6644,7 +6644,7 @@ __metadata: vite: "npm:^4.0.0" peerDependencies: "@sveltejs/vite-plugin-svelte": ^2.0.0 || ^3.0.0 - svelte: ^4.0.0 || ^5.0.0-next.16 + svelte: ^4.0.0 || ^5.0.0-next.65 vite: ^4.0.0 || ^5.0.0 languageName: unknown linkType: soft @@ -6661,7 +6661,7 @@ __metadata: svelte-loader: "npm:^3.1.9" typescript: "npm:^5.3.2" peerDependencies: - svelte: ^4.0.0 || ^5.0.0-next.16 + svelte: ^4.0.0 || ^5.0.0-next.65 svelte-loader: "*" languageName: unknown linkType: soft @@ -6678,6 +6678,7 @@ __metadata: "@storybook/types": "workspace:*" "@sveltejs/vite-plugin-svelte": "npm:^3.0.2" expect-type: "npm:^0.15.0" + fs-extra: "npm:^11.1.0" svelte: "npm:^5.0.0-next.65" svelte-check: "npm:^3.6.4" sveltedoc-parser: "npm:^4.2.1" @@ -6701,7 +6702,7 @@ __metadata: typescript: "npm:^5.3.2" vite: "npm:^4.0.0" peerDependencies: - svelte: ^4.0.0 || ^5.0.0-next.16 + svelte: ^4.0.0 || ^5.0.0-next.65 vite: ^4.0.0 || ^5.0.0 languageName: unknown linkType: soft @@ -9282,15 +9283,6 @@ __metadata: languageName: node linkType: hard -"acorn-typescript@npm:^1.4.11": - version: 1.4.12 - resolution: "acorn-typescript@npm:1.4.12" - peerDependencies: - acorn: ">=8.9.0" - checksum: a3b33ed0dc321e3364da507a3decec96423736384068c88fea5ea57aeae864ea115a6c4a20b3ace71b75f4901b0657bec82d83aab30a8ad0dfc4bfc0d8337546 - languageName: node - linkType: hard - "acorn-typescript@npm:^1.4.13": version: 1.4.13 resolution: "acorn-typescript@npm:1.4.13" @@ -27256,26 +27248,6 @@ __metadata: languageName: node linkType: hard -"svelte@npm:^5.0.0-next.28": - version: 5.0.0-next.28 - resolution: "svelte@npm:5.0.0-next.28" - dependencies: - "@ampproject/remapping": "npm:^2.2.1" - "@jridgewell/sourcemap-codec": "npm:^1.4.15" - acorn: "npm:^8.10.0" - acorn-typescript: "npm:^1.4.11" - aria-query: "npm:^5.3.0" - axobject-query: "npm:^4.0.0" - esm-env: "npm:^1.0.0" - esrap: "npm:^1.2.1" - is-reference: "npm:^3.0.1" - locate-character: "npm:^3.0.0" - magic-string: "npm:^0.30.4" - zimmerframe: "npm:^1.1.0" - checksum: d309cd3d1a9fe16c67a626af867288b02f6e7c49311c851aeb0f36feb5ab9603ca5594338fb933dbbada41b26faea6dcef52ed6ab3e86f54626545e53059eb28 - languageName: node - linkType: hard - "svelte@npm:^5.0.0-next.65": version: 5.0.0-next.65 resolution: "svelte@npm:5.0.0-next.65" @@ -30318,13 +30290,6 @@ __metadata: languageName: node linkType: hard -"zimmerframe@npm:^1.1.0": - version: 1.1.0 - resolution: "zimmerframe@npm:1.1.0" - checksum: dffe3f555bb000176ed9c7577e0fb0c3eddeceb6df9bb3ff870995bac3a51b40fab5443bd3dc47ce91c1f8ecf07282742efb80771ae6a088edc0340bb217f93d - languageName: node - linkType: hard - "zimmerframe@npm:^1.1.2": version: 1.1.2 resolution: "zimmerframe@npm:1.1.2" From b9247ec4e34dadc798c6a99e2485cd8e049f3e57 Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Mon, 26 Feb 2024 14:58:35 +0100 Subject: [PATCH 30/77] add Svelte prerelease sandbox back to CI --- .circleci/config.yml | 10 +++++----- code/lib/cli/src/sandbox-templates.ts | 1 + 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index b212c825ddc2..0d3340694846 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -706,22 +706,22 @@ workflows: requires: - build - create-sandboxes: - parallelism: 34 + parallelism: 35 requires: - build # - smoke-test-sandboxes: # disabled for now # requires: # - create-sandboxes - build-sandboxes: - parallelism: 34 + parallelism: 35 requires: - create-sandboxes - chromatic-sandboxes: - parallelism: 31 + parallelism: 32 requires: - build-sandboxes - e2e-production: - parallelism: 29 + parallelism: 30 requires: - build-sandboxes - e2e-dev: @@ -729,7 +729,7 @@ workflows: requires: - create-sandboxes - test-runner-production: - parallelism: 29 + parallelism: 30 requires: - build-sandboxes diff --git a/code/lib/cli/src/sandbox-templates.ts b/code/lib/cli/src/sandbox-templates.ts index e1395b81156f..182e49798148 100644 --- a/code/lib/cli/src/sandbox-templates.ts +++ b/code/lib/cli/src/sandbox-templates.ts @@ -626,6 +626,7 @@ export const daily: TemplateKey[] = [ 'vue-cli/default-js', 'lit-vite/default-js', 'svelte-kit/skeleton-js', + 'svelte-kit/prerelease-ts', 'svelte-vite/default-js', 'nextjs/13-ts', 'nextjs/default-js', From 982be2deac6c8b3295126737de40f1f88e014a7c Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Mon, 26 Feb 2024 16:20:34 +0100 Subject: [PATCH 31/77] bring back fix for resetting story args in Svelte 5 --- code/renderers/svelte/src/render.ts | 21 ++++++++++-------- .../svelte/template/stories/args.stories.js | 22 +++++++++++-------- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/code/renderers/svelte/src/render.ts b/code/renderers/svelte/src/render.ts index 3b22469af003..28552379bf90 100644 --- a/code/renderers/svelte/src/render.ts +++ b/code/renderers/svelte/src/render.ts @@ -36,15 +36,12 @@ export function renderToCanvas( * * We listen for the RESET_STORY_ARGS event and store the storyId to be reset * We then use this in the renderToCanvas function to force remount the story - * - * This is only necessary in Svelte v4 */ const storyIdsToRemountFromResetArgsEvent = new Set(); -if (IS_SVELTE_V4) { - addons.getChannel().on(RESET_STORY_ARGS, ({ storyId }) => { - storyIdsToRemountFromResetArgsEvent.add(storyId); - }); -} +addons.getChannel().on(RESET_STORY_ARGS, ({ storyId }) => { + storyIdsToRemountFromResetArgsEvent.add(storyId); +}); + const componentsByDomElementV4 = new Map(); function renderToCanvasV4( @@ -137,11 +134,17 @@ function renderToCanvasV5( const existingComponent = componentsByDomElementV5.get(canvasElement); - if (forceRemount) { + let remount = forceRemount; + if (storyIdsToRemountFromResetArgsEvent.has(storyContext.id)) { + remount = true; + storyIdsToRemountFromResetArgsEvent.delete(storyContext.id); + } + + if (remount) { unmount(canvasElement); } - if (!existingComponent || forceRemount) { + if (!existingComponent || remount) { const props = createSvelte5Props({ storyFn, storyContext, diff --git a/code/renderers/svelte/template/stories/args.stories.js b/code/renderers/svelte/template/stories/args.stories.js index 7ecee85a982c..493b5519e6e2 100644 --- a/code/renderers/svelte/template/stories/args.stories.js +++ b/code/renderers/svelte/template/stories/args.stories.js @@ -14,14 +14,16 @@ export default { }; export const RemountOnResetStoryArgs = { - play: async ({ canvasElement, id }) => { + play: async ({ canvasElement, id, step }) => { const canvas = await within(canvasElement); const channel = addons.getChannel(); - // Just to ensure the story is always in a clean state from the beginning, not really part of the test - await channel.emit(RESET_STORY_ARGS, { storyId: id }); - await new Promise((resolve) => { - channel.once(STORY_RENDERED, resolve); + await step('Reset story args', async () => { + // Just to ensure the story is always in a clean state from the beginning, not really part of the test + await channel.emit(RESET_STORY_ARGS, { storyId: id }); + await new Promise((resolve) => { + channel.once(STORY_RENDERED, resolve); + }); }); const button = await canvas.getByRole('button'); await expect(button).toHaveTextContent('You clicked: 0'); @@ -29,16 +31,18 @@ export const RemountOnResetStoryArgs = { await userEvent.click(button); await expect(button).toHaveTextContent('You clicked: 1'); - await channel.emit(UPDATE_STORY_ARGS, { storyId: id, updatedArgs: { text: 'Changed' } }); - await new Promise((resolve) => { - channel.once(STORY_RENDERED, resolve); + await step("Update story args with { text: 'Changed' }", async () => { + await channel.emit(UPDATE_STORY_ARGS, { storyId: id, updatedArgs: { text: 'Changed' } }); + await new Promise((resolve) => { + channel.once(STORY_RENDERED, resolve); + }); }); await expect(button).toHaveTextContent('Changed: 1'); // expect that all state and args are reset after RESET_STORY_ARGS because Svelte needs to remount the component // most other renderers would have 'You clicked: 1' here because they don't remount the component // if this doesn't fully remount it would be 'undefined: 1' because undefined args are used as is in Svelte, and the state is kept - await channel.emit(RESET_STORY_ARGS, { storyId: id }); + await step('Reset story args', () => channel.emit(RESET_STORY_ARGS, { storyId: id })); await waitFor(async () => expect(await within(canvasElement).getByRole('button')).toHaveTextContent('You clicked: 0') ); From d3f533f6fb8d00eb661a9583f55edd2e897dba2b Mon Sep 17 00:00:00 2001 From: Jeppe Reinhold Date: Mon, 26 Feb 2024 23:37:23 +0100 Subject: [PATCH 32/77] Don't expose 'count' state in Button example component as a prop --- .../svelte/template/stories/views/ButtonJavaScript.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/renderers/svelte/template/stories/views/ButtonJavaScript.svelte b/code/renderers/svelte/template/stories/views/ButtonJavaScript.svelte index 23af7eaac0f0..800ee79de0f4 100644 --- a/code/renderers/svelte/template/stories/views/ButtonJavaScript.svelte +++ b/code/renderers/svelte/template/stories/views/ButtonJavaScript.svelte @@ -15,7 +15,7 @@ /** * Displays the count */ - export let count = 0; + let count = 0; /** * Button text From 1d5e9f8d179ef19175d2c2bb6bc3ba8a9d511e35 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Thu, 29 Feb 2024 11:44:19 +0100 Subject: [PATCH 33/77] filter docgen import resolution files to only JS --- code/frameworks/react-vite/package.json | 3 +- .../react-vite/src/plugins/docgen-resolver.ts | 60 +++++++++++++++++++ .../react-vite/src/plugins/react-docgen.ts | 19 ++++-- code/yarn.lock | 5 +- 4 files changed, 78 insertions(+), 9 deletions(-) create mode 100644 code/frameworks/react-vite/src/plugins/docgen-resolver.ts diff --git a/code/frameworks/react-vite/package.json b/code/frameworks/react-vite/package.json index b502a6fe4e48..e560d1eacb8a 100644 --- a/code/frameworks/react-vite/package.json +++ b/code/frameworks/react-vite/package.json @@ -52,7 +52,8 @@ "@storybook/builder-vite": "workspace:*", "@storybook/react": "workspace:*", "magic-string": "^0.30.0", - "react-docgen": "^7.0.0" + "react-docgen": "^7.0.0", + "resolve": "^1.22.8" }, "devDependencies": { "@types/node": "^18.0.0", diff --git a/code/frameworks/react-vite/src/plugins/docgen-resolver.ts b/code/frameworks/react-vite/src/plugins/docgen-resolver.ts new file mode 100644 index 000000000000..176dcb7f6467 --- /dev/null +++ b/code/frameworks/react-vite/src/plugins/docgen-resolver.ts @@ -0,0 +1,60 @@ +import { extname } from 'path'; +import resolve from 'resolve'; + +export class ReactDocgenResolveError extends Error { + // the magic string that react-docgen uses to check if a module is ignored + readonly code = 'MODULE_NOT_FOUND'; + + constructor(filename: string) { + super(`'${filename}' was ignored by react-docgen.`); + } +} + +/* The below code was copied from: + * https://github.com/reactjs/react-docgen/blob/df2daa8b6f0af693ecc3c4dc49f2246f60552bcb/packages/react-docgen/src/importer/makeFsImporter.ts#L14-L63 + * because it wasn't exported from the react-docgen package. + */ + +// These extensions are sorted by priority +// resolve() will check for files in the order these extensions are sorted +const RESOLVE_EXTENSIONS = ['.js', '.ts', '.tsx', '.mjs', '.cjs', '.mts', '.cts', '.jsx']; + +export function defaultLookupModule(filename: string, basedir: string): string { + const resolveOptions = { + basedir, + extensions: RESOLVE_EXTENSIONS, + // we do not need to check core modules as we cannot import them anyway + includeCoreModules: false, + }; + + try { + return resolve.sync(filename, resolveOptions); + } catch (error) { + const ext = extname(filename); + let newFilename: string; + + // if we try to import a JavaScript file it might be that we are actually pointing to + // a TypeScript file. This can happen in ES modules as TypeScript requires to import other + // TypeScript files with .js extensions + // https://www.typescriptlang.org/docs/handbook/esm-node.html#type-in-packagejson-and-new-extensions + switch (ext) { + case '.js': + case '.mjs': + case '.cjs': + newFilename = `${filename.slice(0, -2)}ts`; + break; + + case '.jsx': + newFilename = `${filename.slice(0, -3)}tsx`; + break; + default: + throw error; + } + + return resolve.sync(newFilename, { + ...resolveOptions, + // we already know that there is an extension at this point, so no need to check other extensions + extensions: [], + }); + } +} diff --git a/code/frameworks/react-vite/src/plugins/react-docgen.ts b/code/frameworks/react-vite/src/plugins/react-docgen.ts index 5be555fbd081..b56075efe777 100644 --- a/code/frameworks/react-vite/src/plugins/react-docgen.ts +++ b/code/frameworks/react-vite/src/plugins/react-docgen.ts @@ -1,4 +1,4 @@ -import path from 'path'; +import path, { join } from 'path'; import { createFilter } from '@rollup/pluginutils'; import type { Documentation } from 'react-docgen'; import { @@ -6,18 +6,18 @@ import { parse, builtinHandlers as docgenHandlers, builtinResolvers as docgenResolver, - builtinImporters as docgenImporters, + makeFsImporter, } from 'react-docgen'; import MagicString from 'magic-string'; import type { PluginOption } from 'vite'; import actualNameHandler from './docgen-handlers/actualNameHandler'; +import { ReactDocgenResolveError, defaultLookupModule } from './docgen-resolver'; type DocObj = Documentation & { actualName: string }; // TODO: None of these are able to be overridden, so `default` is aspirational here. const defaultHandlers = Object.values(docgenHandlers).map((handler) => handler); const defaultResolver = new docgenResolver.FindExportedDefinitionsResolver(); -const defaultImporter = docgenImporters.fsImporter; const handlers = [...defaultHandlers, actualNameHandler]; type Options = { @@ -36,14 +36,21 @@ export function reactDocgen({ name: 'storybook:react-docgen-plugin', enforce: 'pre', async transform(src: string, id: string) { - const relPath = path.relative(cwd, id); - if (!filter(relPath)) return; + if (!filter(path.relative(cwd, id))) { + return; + } try { const docgenResults = parse(src, { resolver: defaultResolver, handlers, - importer: defaultImporter, + importer: makeFsImporter((filename, basedir) => { + if (!filter(path.relative(cwd, join(basedir, filename)))) { + throw new ReactDocgenResolveError(filename); + } + + return defaultLookupModule(filename, basedir); + }), filename: id, }) as DocObj[]; const s = new MagicString(src); diff --git a/code/yarn.lock b/code/yarn.lock index c0338dabe0c4..7450ad6886f4 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -6491,6 +6491,7 @@ __metadata: "@types/node": "npm:^18.0.0" magic-string: "npm:^0.30.0" react-docgen: "npm:^7.0.0" + resolve: "npm:^1.22.8" typescript: "npm:^5.3.2" vite: "npm:^4.0.0" peerDependencies: @@ -25657,7 +25658,7 @@ __metadata: languageName: node linkType: hard -"resolve@npm:1.22.8, resolve@npm:^1.10.0, resolve@npm:^1.13.1, resolve@npm:^1.14.2, resolve@npm:^1.15.1, resolve@npm:^1.17.0, resolve@npm:^1.19.0, resolve@npm:^1.22.1, resolve@npm:^1.22.4, resolve@npm:^1.4.0": +"resolve@npm:1.22.8, resolve@npm:^1.10.0, resolve@npm:^1.13.1, resolve@npm:^1.14.2, resolve@npm:^1.15.1, resolve@npm:^1.17.0, resolve@npm:^1.19.0, resolve@npm:^1.22.1, resolve@npm:^1.22.4, resolve@npm:^1.22.8, resolve@npm:^1.4.0": version: 1.22.8 resolution: "resolve@npm:1.22.8" dependencies: @@ -25683,7 +25684,7 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@npm%3A1.22.8#optional!builtin, resolve@patch:resolve@npm%3A^1.10.0#optional!builtin, resolve@patch:resolve@npm%3A^1.13.1#optional!builtin, resolve@patch:resolve@npm%3A^1.14.2#optional!builtin, resolve@patch:resolve@npm%3A^1.15.1#optional!builtin, resolve@patch:resolve@npm%3A^1.17.0#optional!builtin, resolve@patch:resolve@npm%3A^1.19.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.1#optional!builtin, resolve@patch:resolve@npm%3A^1.22.4#optional!builtin, resolve@patch:resolve@npm%3A^1.4.0#optional!builtin": +"resolve@patch:resolve@npm%3A1.22.8#optional!builtin, resolve@patch:resolve@npm%3A^1.10.0#optional!builtin, resolve@patch:resolve@npm%3A^1.13.1#optional!builtin, resolve@patch:resolve@npm%3A^1.14.2#optional!builtin, resolve@patch:resolve@npm%3A^1.15.1#optional!builtin, resolve@patch:resolve@npm%3A^1.17.0#optional!builtin, resolve@patch:resolve@npm%3A^1.19.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.1#optional!builtin, resolve@patch:resolve@npm%3A^1.22.4#optional!builtin, resolve@patch:resolve@npm%3A^1.22.8#optional!builtin, resolve@patch:resolve@npm%3A^1.4.0#optional!builtin": version: 1.22.8 resolution: "resolve@patch:resolve@npm%3A1.22.8#optional!builtin::version=1.22.8&hash=c3c19d" dependencies: From 7246a179ec91178caab30212e9f641b0981c9ac6 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Thu, 29 Feb 2024 13:20:30 +0100 Subject: [PATCH 34/77] making a little simplification, see if it causes a regression too --- code/frameworks/react-vite/src/plugins/react-docgen.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/frameworks/react-vite/src/plugins/react-docgen.ts b/code/frameworks/react-vite/src/plugins/react-docgen.ts index b56075efe777..4eac1709c870 100644 --- a/code/frameworks/react-vite/src/plugins/react-docgen.ts +++ b/code/frameworks/react-vite/src/plugins/react-docgen.ts @@ -45,7 +45,7 @@ export function reactDocgen({ resolver: defaultResolver, handlers, importer: makeFsImporter((filename, basedir) => { - if (!filter(path.relative(cwd, join(basedir, filename)))) { + if (!filename.match(/\.(mjs|tsx?|jsx?)$/)) { throw new ReactDocgenResolveError(filename); } From dd3ba902d1c4b6e6375c8a6e8ef3399e957359dd Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Thu, 29 Feb 2024 13:31:52 +0100 Subject: [PATCH 35/77] fix --- code/frameworks/react-vite/src/plugins/react-docgen.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/frameworks/react-vite/src/plugins/react-docgen.ts b/code/frameworks/react-vite/src/plugins/react-docgen.ts index 4eac1709c870..4e9388d7df90 100644 --- a/code/frameworks/react-vite/src/plugins/react-docgen.ts +++ b/code/frameworks/react-vite/src/plugins/react-docgen.ts @@ -1,4 +1,4 @@ -import path, { join } from 'path'; +import path from 'path'; import { createFilter } from '@rollup/pluginutils'; import type { Documentation } from 'react-docgen'; import { From 686867f6d014346b64d375a91ef041cc9bf8fd31 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Thu, 29 Feb 2024 14:03:00 +0100 Subject: [PATCH 36/77] fix issue with files without extension --- code/frameworks/react-vite/src/plugins/react-docgen.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/code/frameworks/react-vite/src/plugins/react-docgen.ts b/code/frameworks/react-vite/src/plugins/react-docgen.ts index 4e9388d7df90..d4b88fa6efab 100644 --- a/code/frameworks/react-vite/src/plugins/react-docgen.ts +++ b/code/frameworks/react-vite/src/plugins/react-docgen.ts @@ -45,11 +45,13 @@ export function reactDocgen({ resolver: defaultResolver, handlers, importer: makeFsImporter((filename, basedir) => { - if (!filename.match(/\.(mjs|tsx?|jsx?)$/)) { + const result = defaultLookupModule(filename, basedir); + + if (!result.match(/\.(mjs|tsx?|jsx?)$/)) { throw new ReactDocgenResolveError(filename); } - return defaultLookupModule(filename, basedir); + return result; }), filename: id, }) as DocObj[]; From 5fa9f5be2a7af34a6cd1e650055e44bcb74b42cf Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Thu, 29 Feb 2024 14:48:04 +0100 Subject: [PATCH 37/77] add regression test for import of css file --- .../template/stories/docgen-components/imported.module.css | 3 +++ .../stories/docgen-components/ts-function-component/input.tsx | 4 ++++ 2 files changed, 7 insertions(+) create mode 100644 code/renderers/react/template/stories/docgen-components/imported.module.css diff --git a/code/renderers/react/template/stories/docgen-components/imported.module.css b/code/renderers/react/template/stories/docgen-components/imported.module.css new file mode 100644 index 000000000000..a15c877ac01f --- /dev/null +++ b/code/renderers/react/template/stories/docgen-components/imported.module.css @@ -0,0 +1,3 @@ +.foo { + color: red; +} diff --git a/code/renderers/react/template/stories/docgen-components/ts-function-component/input.tsx b/code/renderers/react/template/stories/docgen-components/ts-function-component/input.tsx index 9f0c2598ff07..8c9ee7a45d35 100644 --- a/code/renderers/react/template/stories/docgen-components/ts-function-component/input.tsx +++ b/code/renderers/react/template/stories/docgen-components/ts-function-component/input.tsx @@ -1,6 +1,8 @@ import React from 'react'; import { imported } from '../imported'; +// @ts-expect-error (css import not supported in TS) +import styles from '../imported.module.css'; const local = 'local-value'; @@ -26,6 +28,7 @@ interface PropsWriterProps { importedReference?: string; globalReference?: any; stringGlobalName?: string; + myClass: typeof styles.foo; } /** @@ -47,6 +50,7 @@ PropsWriter.defaultProps = { importedReference: imported, globalReference: Date, stringGlobalName: 'top', + myClass: styles.foo, }; export const component = PropsWriter; From 0d52b8058dbf3ad89e35f3dfa735f3c32b5c4a77 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Thu, 29 Feb 2024 15:03:33 +0100 Subject: [PATCH 38/77] remove it --- .../stories/docgen-components/ts-function-component/input.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/code/renderers/react/template/stories/docgen-components/ts-function-component/input.tsx b/code/renderers/react/template/stories/docgen-components/ts-function-component/input.tsx index 8c9ee7a45d35..f7fef63ace91 100644 --- a/code/renderers/react/template/stories/docgen-components/ts-function-component/input.tsx +++ b/code/renderers/react/template/stories/docgen-components/ts-function-component/input.tsx @@ -1,7 +1,6 @@ import React from 'react'; import { imported } from '../imported'; -// @ts-expect-error (css import not supported in TS) import styles from '../imported.module.css'; const local = 'local-value'; From 6a6e4cffa4e3f0c7e86fd24534bdb3a07f27dda8 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Thu, 29 Feb 2024 15:15:41 +0100 Subject: [PATCH 39/77] fix --- .../stories/docgen-components/ts-function-component/input.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/renderers/react/template/stories/docgen-components/ts-function-component/input.tsx b/code/renderers/react/template/stories/docgen-components/ts-function-component/input.tsx index f7fef63ace91..193c2e2c71ae 100644 --- a/code/renderers/react/template/stories/docgen-components/ts-function-component/input.tsx +++ b/code/renderers/react/template/stories/docgen-components/ts-function-component/input.tsx @@ -1,6 +1,8 @@ import React from 'react'; import { imported } from '../imported'; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore (css import not supported in TS) import styles from '../imported.module.css'; const local = 'local-value'; From 470ff2344b0e58ba4035aab23a79080c15b3cd00 Mon Sep 17 00:00:00 2001 From: jonniebigodes Date: Thu, 29 Feb 2024 14:30:28 +0000 Subject: [PATCH 40/77] Docs: Snippets fix testing package imports --- .../common/my-component-play-function-with-canvas.js.mdx | 2 +- docs/snippets/react/login-form-with-play-function.ts-4-9.mdx | 4 +--- docs/snippets/react/login-form-with-play-function.ts.mdx | 4 +--- docs/snippets/svelte/login-form-with-play-function.js.mdx | 3 +-- docs/snippets/svelte/login-form-with-play-function.ts-4-9.mdx | 3 +-- docs/snippets/svelte/login-form-with-play-function.ts.mdx | 3 +-- .../my-component-play-function-with-canvas.js.mdx | 2 +- 7 files changed, 7 insertions(+), 14 deletions(-) diff --git a/docs/snippets/common/my-component-play-function-with-canvas.js.mdx b/docs/snippets/common/my-component-play-function-with-canvas.js.mdx index 26ec005f70fa..a5da1d3eed5f 100644 --- a/docs/snippets/common/my-component-play-function-with-canvas.js.mdx +++ b/docs/snippets/common/my-component-play-function-with-canvas.js.mdx @@ -1,7 +1,7 @@ ```js // MyComponent.stories.js|jsx -import { getByRole, userEvent, within } from '@storybook/testing-library'; +import { userEvent, within } from '@storybook/test'; import { MyComponent } from './MyComponent'; diff --git a/docs/snippets/react/login-form-with-play-function.ts-4-9.mdx b/docs/snippets/react/login-form-with-play-function.ts-4-9.mdx index d6a86876817c..84dffad550b1 100644 --- a/docs/snippets/react/login-form-with-play-function.ts-4-9.mdx +++ b/docs/snippets/react/login-form-with-play-function.ts-4-9.mdx @@ -3,9 +3,7 @@ import type { Meta, StoryObj } from '@storybook/react'; -import { within, userEvent } from '@storybook/testing-library'; - -import { expect } from '@storybook/test'; +import { userEvent, within, expect } from '@storybook/test'; import { LoginForm } from './LoginForm'; diff --git a/docs/snippets/react/login-form-with-play-function.ts.mdx b/docs/snippets/react/login-form-with-play-function.ts.mdx index f31a2a8fcbe2..de6854f0e180 100644 --- a/docs/snippets/react/login-form-with-play-function.ts.mdx +++ b/docs/snippets/react/login-form-with-play-function.ts.mdx @@ -3,9 +3,7 @@ import type { Meta, StoryObj } from '@storybook/react'; -import { within, userEvent } from '@storybook/testing-library'; - -import { expect } from '@storybook/test'; +import { userEvent, within, expect } from '@storybook/test'; import { LoginForm } from './LoginForm'; diff --git a/docs/snippets/svelte/login-form-with-play-function.js.mdx b/docs/snippets/svelte/login-form-with-play-function.js.mdx index e65f60e9a3cb..4408fc6261a0 100644 --- a/docs/snippets/svelte/login-form-with-play-function.js.mdx +++ b/docs/snippets/svelte/login-form-with-play-function.js.mdx @@ -1,8 +1,7 @@ ```js // LoginForm.stories.js -import { userEvent, within } from '@storybook/testing-library'; -import { expect } from '@storybook/test'; +import { expect, userEvent, within } from '@storybook/test'; import LoginForm from './LoginForm.svelte'; diff --git a/docs/snippets/svelte/login-form-with-play-function.ts-4-9.mdx b/docs/snippets/svelte/login-form-with-play-function.ts-4-9.mdx index 265d8fa36b9d..b975337dc799 100644 --- a/docs/snippets/svelte/login-form-with-play-function.ts-4-9.mdx +++ b/docs/snippets/svelte/login-form-with-play-function.ts-4-9.mdx @@ -2,8 +2,7 @@ // LoginForm.stories.ts import type { Meta, StoryObj } from '@storybook/svelte'; -import { userEvent, within } from '@storybook/testing-library'; -import { expect } from '@storybook/test'; +import { expect, userEvent, within } from '@storybook/test'; import LoginForm from './LoginForm.svelte'; diff --git a/docs/snippets/svelte/login-form-with-play-function.ts.mdx b/docs/snippets/svelte/login-form-with-play-function.ts.mdx index ff5891c617d8..24bcd6c1d41a 100644 --- a/docs/snippets/svelte/login-form-with-play-function.ts.mdx +++ b/docs/snippets/svelte/login-form-with-play-function.ts.mdx @@ -2,8 +2,7 @@ // LoginForm.stories.ts import type { Meta, StoryObj } from '@storybook/svelte'; -import { userEvent, within } from '@storybook/testing-library'; -import { expect } from '@storybook/test'; +import { expect, userEvent, within } from '@storybook/test'; import LoginForm from './LoginForm.svelte'; diff --git a/docs/snippets/web-components/my-component-play-function-with-canvas.js.mdx b/docs/snippets/web-components/my-component-play-function-with-canvas.js.mdx index 2ed5c0bec08d..d3812d7d1af0 100644 --- a/docs/snippets/web-components/my-component-play-function-with-canvas.js.mdx +++ b/docs/snippets/web-components/my-component-play-function-with-canvas.js.mdx @@ -1,7 +1,7 @@ ```js // MyComponent.stories.js -import { getByRole, userEvent, within } from '@storybook/testing-library'; +import { userEvent, within } from '@storybook/test'; export default { component: 'demo-my-component', From cea28271e0ff055b6060f97f8452604a443aed2e Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Thu, 29 Feb 2024 15:46:06 +0100 Subject: [PATCH 41/77] fix for webpack as well! --- .../src/loaders/react-docgen-loader.ts | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/code/presets/react-webpack/src/loaders/react-docgen-loader.ts b/code/presets/react-webpack/src/loaders/react-docgen-loader.ts index fd22ca12bf5d..d9cf24dc5aa6 100644 --- a/code/presets/react-webpack/src/loaders/react-docgen-loader.ts +++ b/code/presets/react-webpack/src/loaders/react-docgen-loader.ts @@ -2,7 +2,7 @@ import { parse, builtinResolvers as docgenResolver, builtinHandlers as docgenHandlers, - builtinImporters as docgenImporters, + makeFsImporter, ERROR_CODES, utils, } from 'react-docgen'; @@ -11,6 +11,11 @@ import type { LoaderContext } from 'webpack'; import type { Handler, NodePath, babelTypes as t, Documentation } from 'react-docgen'; import { logger } from '@storybook/node-logger'; +import { + ReactDocgenResolveError, + defaultLookupModule, +} from '../../../../frameworks/react-vite/src/plugins/docgen-resolver'; + const { getNameOrValue, isReactForwardRefCall } = utils; const actualNameHandler: Handler = function actualNameHandler(documentation, componentDefinition) { @@ -54,7 +59,6 @@ type DocObj = Documentation & { actualName: string }; const defaultHandlers = Object.values(docgenHandlers).map((handler) => handler); const defaultResolver = new docgenResolver.FindExportedDefinitionsResolver(); -const defaultImporter = docgenImporters.fsImporter; const handlers = [...defaultHandlers, actualNameHandler]; export default async function reactDocgenLoader( @@ -71,7 +75,15 @@ export default async function reactDocgenLoader( filename: this.resourcePath, resolver: defaultResolver, handlers, - importer: defaultImporter, + importer: makeFsImporter((filename, basedir) => { + const result = defaultLookupModule(filename, basedir); + + if (!result.match(/\.(mjs|tsx?|jsx?)$/)) { + throw new ReactDocgenResolveError(filename); + } + + return result; + }), babelOptions: { babelrc: false, configFile: false, From b7cdb946802ab83dbfe5baab23d56a375a7013f3 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Thu, 29 Feb 2024 15:54:58 +0100 Subject: [PATCH 42/77] Fix addon compatibility check error reporting in storybook dev --- .../cli/src/doctor/getIncompatibleAddons.ts | 82 ------------------- .../getIncompatibleStorybookPackages.ts | 2 +- 2 files changed, 1 insertion(+), 83 deletions(-) delete mode 100644 code/lib/cli/src/doctor/getIncompatibleAddons.ts diff --git a/code/lib/cli/src/doctor/getIncompatibleAddons.ts b/code/lib/cli/src/doctor/getIncompatibleAddons.ts deleted file mode 100644 index e46297e94087..000000000000 --- a/code/lib/cli/src/doctor/getIncompatibleAddons.ts +++ /dev/null @@ -1,82 +0,0 @@ -import type { StorybookConfig } from '@storybook/types'; -import type { SemVer } from 'semver'; -import semver from 'semver'; -import { getAddonNames } from '../automigrate/helpers/mainConfigFile'; -import { JsPackageManagerFactory } from '@storybook/core-common'; - -export const getIncompatibleAddons = async ( - mainConfig: StorybookConfig, - packageManager = JsPackageManagerFactory.getPackageManager() -) => { - // TODO: Keep this up to date with https://github.com/storybookjs/storybook/issues/20529 in case more addons get added - const incompatibleList = { - '@storybook/addon-knobs': '6.4.0', - '@storybook/addon-postcss': '2.0.0', - 'storybook-addon-next-router': '4.0.2', - 'storybook-addon-outline': '1.4.2', // (deprecated) - '@storybook/addon-info': '5.3.21', - 'storybook-addon-designs': '6.3.1', - 'storybook-addon-next': '1.7.0', // (deprecated)' - 'storybook-docs-toc': '1.7.0', - '@storybook/addon-google-analytics': '6.2.9', - 'storybook-addon-pseudo-states': '1.15.5', - 'storybook-dark-mode': '2.1.1', - 'storybook-addon-gatsby': '0.0.5', - '@etchteam/storybook-addon-css-variables-theme': '1.4.0', - '@storybook/addon-cssresources': '6.2.9', - 'storybook-addon-grid': '0.3.1', - 'storybook-multilevel-sort': '1.2.0', - 'storybook-addon-i18next': '1.3.0', - 'storybook-source-link': '2.0.8', - 'babel-plugin-storybook-csf-title': '2.1.0', - '@urql/storybook-addon': '2.0.1', - 'storybook-addon-intl': '2.4.1', - 'storybook-addon-mock': '3.2.0', - '@chakra-ui/storybook-addon': '4.0.16', - 'storybook-mobile-addon': '1.0.2', - '@storybook/addon-queryparams': '6.2.9', - }; - - const addons = getAddonNames(mainConfig).filter( - (addon): addon is keyof typeof incompatibleList => addon in incompatibleList - ); - - const dependencies = await packageManager.getAllDependencies(); - const storybookPackages = Object.keys(dependencies).filter((dep) => dep.includes('storybook')); - - const packagesToCheck = [...new Set([...addons, ...storybookPackages])]; - - const addonVersions = await Promise.all( - packagesToCheck.map( - async (addon) => - ({ - name: addon, - version: await packageManager.getPackageVersion(addon), - }) as { name: keyof typeof incompatibleList; version: string } - ) - ); - - if (addonVersions.length === 0) { - return []; - } - - const incompatibleAddons: { name: string; version: string }[] = []; - addonVersions.forEach(({ name, version: installedVersion }) => { - if (installedVersion === null) { - return; - } - - const addonVersion = incompatibleList[name]; - try { - if ( - semver.lte(semver.coerce(installedVersion) as SemVer, semver.coerce(addonVersion) as SemVer) - ) { - incompatibleAddons.push({ name, version: installedVersion }); - } - } catch (err) { - // we tried our best but if we can't compare, we just no-op for that addon - } - }); - - return incompatibleAddons; -}; diff --git a/code/lib/cli/src/doctor/getIncompatibleStorybookPackages.ts b/code/lib/cli/src/doctor/getIncompatibleStorybookPackages.ts index d481fae93c82..d27694136074 100644 --- a/code/lib/cli/src/doctor/getIncompatibleStorybookPackages.ts +++ b/code/lib/cli/src/doctor/getIncompatibleStorybookPackages.ts @@ -88,7 +88,7 @@ export const getIncompatibleStorybookPackages = async ( const allDeps = await packageManager.getAllDependencies(); const storybookLikeDeps = Object.keys(allDeps).filter((dep) => dep.includes('storybook')); - if (storybookLikeDeps.length === 0) { + if (storybookLikeDeps.length === 0 && !context.skipErrors) { throw new Error('No Storybook dependencies found in the package.json'); } From 4d24ee07b96b178c78ffa3e1501fddc98349f7ff Mon Sep 17 00:00:00 2001 From: Valentin Palkovic Date: Thu, 29 Feb 2024 16:25:56 +0100 Subject: [PATCH 43/77] Resolve vite config from project root instead of cwd --- .../cli/src/automigrate/fixes/vite-config-file.ts | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/code/lib/cli/src/automigrate/fixes/vite-config-file.ts b/code/lib/cli/src/automigrate/fixes/vite-config-file.ts index 6325b71ad062..c74c7f378373 100644 --- a/code/lib/cli/src/automigrate/fixes/vite-config-file.ts +++ b/code/lib/cli/src/automigrate/fixes/vite-config-file.ts @@ -4,6 +4,7 @@ import findUp from 'find-up'; import { getFrameworkPackageName } from '../helpers/mainConfigFile'; import { frameworkToRenderer } from '../../helpers'; import { frameworkPackages } from '@storybook/core-common'; +import path from 'path'; interface ViteConfigFileRunOptions { plugins: string[]; @@ -15,13 +16,11 @@ export const viteConfigFile = { versionRange: ['<8.0.0-beta.3', '>=8.0.0-beta.3'], - async check({ mainConfig, packageManager }) { - let isViteConfigFileFound = !!(await findUp([ - 'vite.config.js', - 'vite.config.mjs', - 'vite.config.cjs', - 'vite.config.ts', - ])); + async check({ mainConfig, packageManager, mainConfigPath }) { + let isViteConfigFileFound = !!(await findUp( + ['vite.config.js', 'vite.config.mjs', 'vite.config.cjs', 'vite.config.ts'], + { cwd: mainConfigPath ? path.join(mainConfigPath, '..') : process.cwd() } + )); const rendererToVitePluginMap: Record = { preact: '@preact/preset-vite', From 899ba75db383b8745d6d5514b1f2226d41614522 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Thu, 29 Feb 2024 20:11:37 +0100 Subject: [PATCH 44/77] make use of RESOLVE_EXTENSIONS as requested --- .../react-vite/src/plugins/docgen-resolver.ts | 2 +- .../react-vite/src/plugins/react-docgen.ts | 12 ++++++++---- .../react-webpack/src/loaders/react-docgen-loader.ts | 7 ++++--- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/code/frameworks/react-vite/src/plugins/docgen-resolver.ts b/code/frameworks/react-vite/src/plugins/docgen-resolver.ts index 176dcb7f6467..9e6d798384a5 100644 --- a/code/frameworks/react-vite/src/plugins/docgen-resolver.ts +++ b/code/frameworks/react-vite/src/plugins/docgen-resolver.ts @@ -17,7 +17,7 @@ export class ReactDocgenResolveError extends Error { // These extensions are sorted by priority // resolve() will check for files in the order these extensions are sorted -const RESOLVE_EXTENSIONS = ['.js', '.ts', '.tsx', '.mjs', '.cjs', '.mts', '.cts', '.jsx']; +export const RESOLVE_EXTENSIONS = ['.js', '.ts', '.tsx', '.mjs', '.cjs', '.mts', '.cts', '.jsx']; export function defaultLookupModule(filename: string, basedir: string): string { const resolveOptions = { diff --git a/code/frameworks/react-vite/src/plugins/react-docgen.ts b/code/frameworks/react-vite/src/plugins/react-docgen.ts index d4b88fa6efab..8ef7a1159aaf 100644 --- a/code/frameworks/react-vite/src/plugins/react-docgen.ts +++ b/code/frameworks/react-vite/src/plugins/react-docgen.ts @@ -11,7 +11,11 @@ import { import MagicString from 'magic-string'; import type { PluginOption } from 'vite'; import actualNameHandler from './docgen-handlers/actualNameHandler'; -import { ReactDocgenResolveError, defaultLookupModule } from './docgen-resolver'; +import { + RESOLVE_EXTENSIONS, + ReactDocgenResolveError, + defaultLookupModule, +} from './docgen-resolver'; type DocObj = Documentation & { actualName: string }; @@ -47,11 +51,11 @@ export function reactDocgen({ importer: makeFsImporter((filename, basedir) => { const result = defaultLookupModule(filename, basedir); - if (!result.match(/\.(mjs|tsx?|jsx?)$/)) { - throw new ReactDocgenResolveError(filename); + if (RESOLVE_EXTENSIONS.find((ext) => result.endsWith(ext)) === undefined) { + return result; } - return result; + throw new ReactDocgenResolveError(filename); }), filename: id, }) as DocObj[]; diff --git a/code/presets/react-webpack/src/loaders/react-docgen-loader.ts b/code/presets/react-webpack/src/loaders/react-docgen-loader.ts index d9cf24dc5aa6..073ef5893f56 100644 --- a/code/presets/react-webpack/src/loaders/react-docgen-loader.ts +++ b/code/presets/react-webpack/src/loaders/react-docgen-loader.ts @@ -12,6 +12,7 @@ import type { Handler, NodePath, babelTypes as t, Documentation } from 'react-do import { logger } from '@storybook/node-logger'; import { + RESOLVE_EXTENSIONS, ReactDocgenResolveError, defaultLookupModule, } from '../../../../frameworks/react-vite/src/plugins/docgen-resolver'; @@ -78,11 +79,11 @@ export default async function reactDocgenLoader( importer: makeFsImporter((filename, basedir) => { const result = defaultLookupModule(filename, basedir); - if (!result.match(/\.(mjs|tsx?|jsx?)$/)) { - throw new ReactDocgenResolveError(filename); + if (RESOLVE_EXTENSIONS.find((ext) => result.endsWith(ext)) === undefined) { + return result; } - return result; + throw new ReactDocgenResolveError(filename); }), babelOptions: { babelrc: false, From ef36c364c266e8712b1c48678c1e76325bf352e9 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Thu, 29 Feb 2024 20:55:14 +0100 Subject: [PATCH 45/77] add dependency --- code/presets/react-webpack/package.json | 1 + code/yarn.lock | 1 + 2 files changed, 2 insertions(+) diff --git a/code/presets/react-webpack/package.json b/code/presets/react-webpack/package.json index c2cc403a16ec..a79480cf13dc 100644 --- a/code/presets/react-webpack/package.json +++ b/code/presets/react-webpack/package.json @@ -74,6 +74,7 @@ "fs-extra": "^11.1.0", "magic-string": "^0.30.5", "react-docgen": "^7.0.0", + "resolve": "^1.22.8", "semver": "^7.3.7", "webpack": "5" }, diff --git a/code/yarn.lock b/code/yarn.lock index 7450ad6886f4..039c28a0c940 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -6343,6 +6343,7 @@ __metadata: fs-extra: "npm:^11.1.0" magic-string: "npm:^0.30.5" react-docgen: "npm:^7.0.0" + resolve: "npm:^1.22.8" semver: "npm:^7.3.7" typescript: "npm:^5.3.2" webpack: "npm:5" From 463d4887cc0fe7666d768a0759c736968ad2ea90 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Thu, 29 Feb 2024 21:00:32 +0100 Subject: [PATCH 46/77] duplicated to code to prevent ugly import --- .../react-vite/src/plugins/docgen-resolver.ts | 1 + .../src/loaders/docgen-resolver.ts | 61 +++++++++++++++++++ .../src/loaders/react-docgen-loader.ts | 2 +- 3 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 code/presets/react-webpack/src/loaders/docgen-resolver.ts diff --git a/code/frameworks/react-vite/src/plugins/docgen-resolver.ts b/code/frameworks/react-vite/src/plugins/docgen-resolver.ts index 9e6d798384a5..e0b577fbcbee 100644 --- a/code/frameworks/react-vite/src/plugins/docgen-resolver.ts +++ b/code/frameworks/react-vite/src/plugins/docgen-resolver.ts @@ -13,6 +13,7 @@ export class ReactDocgenResolveError extends Error { /* The below code was copied from: * https://github.com/reactjs/react-docgen/blob/df2daa8b6f0af693ecc3c4dc49f2246f60552bcb/packages/react-docgen/src/importer/makeFsImporter.ts#L14-L63 * because it wasn't exported from the react-docgen package. + * watch out: when updating this code, also update the code in code/presets/react-webpack/src/loaders/docgen-resolver.ts */ // These extensions are sorted by priority diff --git a/code/presets/react-webpack/src/loaders/docgen-resolver.ts b/code/presets/react-webpack/src/loaders/docgen-resolver.ts new file mode 100644 index 000000000000..fc86496fab9e --- /dev/null +++ b/code/presets/react-webpack/src/loaders/docgen-resolver.ts @@ -0,0 +1,61 @@ +import { extname } from 'path'; +import resolve from 'resolve'; + +export class ReactDocgenResolveError extends Error { + // the magic string that react-docgen uses to check if a module is ignored + readonly code = 'MODULE_NOT_FOUND'; + + constructor(filename: string) { + super(`'${filename}' was ignored by react-docgen.`); + } +} + +/* The below code was copied from: + * https://github.com/reactjs/react-docgen/blob/df2daa8b6f0af693ecc3c4dc49f2246f60552bcb/packages/react-docgen/src/importer/makeFsImporter.ts#L14-L63 + * because it wasn't exported from the react-docgen package. + * watch out: when updating this code, also update the code in code/frameworks/react-vite/src/plugins/docgen-resolver.ts + */ + +// These extensions are sorted by priority +// resolve() will check for files in the order these extensions are sorted +export const RESOLVE_EXTENSIONS = ['.js', '.ts', '.tsx', '.mjs', '.cjs', '.mts', '.cts', '.jsx']; + +export function defaultLookupModule(filename: string, basedir: string): string { + const resolveOptions = { + basedir, + extensions: RESOLVE_EXTENSIONS, + // we do not need to check core modules as we cannot import them anyway + includeCoreModules: false, + }; + + try { + return resolve.sync(filename, resolveOptions); + } catch (error) { + const ext = extname(filename); + let newFilename: string; + + // if we try to import a JavaScript file it might be that we are actually pointing to + // a TypeScript file. This can happen in ES modules as TypeScript requires to import other + // TypeScript files with .js extensions + // https://www.typescriptlang.org/docs/handbook/esm-node.html#type-in-packagejson-and-new-extensions + switch (ext) { + case '.js': + case '.mjs': + case '.cjs': + newFilename = `${filename.slice(0, -2)}ts`; + break; + + case '.jsx': + newFilename = `${filename.slice(0, -3)}tsx`; + break; + default: + throw error; + } + + return resolve.sync(newFilename, { + ...resolveOptions, + // we already know that there is an extension at this point, so no need to check other extensions + extensions: [], + }); + } +} diff --git a/code/presets/react-webpack/src/loaders/react-docgen-loader.ts b/code/presets/react-webpack/src/loaders/react-docgen-loader.ts index 073ef5893f56..81fa0b335a58 100644 --- a/code/presets/react-webpack/src/loaders/react-docgen-loader.ts +++ b/code/presets/react-webpack/src/loaders/react-docgen-loader.ts @@ -15,7 +15,7 @@ import { RESOLVE_EXTENSIONS, ReactDocgenResolveError, defaultLookupModule, -} from '../../../../frameworks/react-vite/src/plugins/docgen-resolver'; +} from './docgen-resolver'; const { getNameOrValue, isReactForwardRefCall } = utils; From da5ee529f0a4b7480fd5a9306e42355fcba8c255 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Thu, 29 Feb 2024 21:09:07 +0100 Subject: [PATCH 47/77] added extra extensions --- .../react-vite/src/plugins/docgen-resolver.ts | 15 ++++++++++++++- .../react-webpack/src/loaders/docgen-resolver.ts | 15 ++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/code/frameworks/react-vite/src/plugins/docgen-resolver.ts b/code/frameworks/react-vite/src/plugins/docgen-resolver.ts index e0b577fbcbee..ab0fda807cf8 100644 --- a/code/frameworks/react-vite/src/plugins/docgen-resolver.ts +++ b/code/frameworks/react-vite/src/plugins/docgen-resolver.ts @@ -18,7 +18,20 @@ export class ReactDocgenResolveError extends Error { // These extensions are sorted by priority // resolve() will check for files in the order these extensions are sorted -export const RESOLVE_EXTENSIONS = ['.js', '.ts', '.tsx', '.mjs', '.cjs', '.mts', '.cts', '.jsx']; +export const RESOLVE_EXTENSIONS = [ + '.js', + '.cts', // These were originally not in the code, I added them + '.mts', // These were originally not in the code, I added them + '.ctsx', // These were originally not in the code, I added them + '.mtsx', // These were originally not in the code, I added them + '.ts', + '.tsx', + '.mjs', + '.cjs', + '.mts', + '.cts', + '.jsx', +]; export function defaultLookupModule(filename: string, basedir: string): string { const resolveOptions = { diff --git a/code/presets/react-webpack/src/loaders/docgen-resolver.ts b/code/presets/react-webpack/src/loaders/docgen-resolver.ts index fc86496fab9e..71e2bde5d742 100644 --- a/code/presets/react-webpack/src/loaders/docgen-resolver.ts +++ b/code/presets/react-webpack/src/loaders/docgen-resolver.ts @@ -18,7 +18,20 @@ export class ReactDocgenResolveError extends Error { // These extensions are sorted by priority // resolve() will check for files in the order these extensions are sorted -export const RESOLVE_EXTENSIONS = ['.js', '.ts', '.tsx', '.mjs', '.cjs', '.mts', '.cts', '.jsx']; +export const RESOLVE_EXTENSIONS = [ + '.js', + '.cts', // These were originally not in the code, I added them + '.mts', // These were originally not in the code, I added them + '.ctsx', // These were originally not in the code, I added them + '.mtsx', // These were originally not in the code, I added them + '.ts', + '.tsx', + '.mjs', + '.cjs', + '.mts', + '.cts', + '.jsx', +]; export function defaultLookupModule(filename: string, basedir: string): string { const resolveOptions = { From 70ee50f155412703026059adc978980090ae2759 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Thu, 29 Feb 2024 21:22:17 +0100 Subject: [PATCH 48/77] fix filter logic --- code/frameworks/react-vite/src/plugins/react-docgen.ts | 2 +- code/presets/react-webpack/src/loaders/react-docgen-loader.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/code/frameworks/react-vite/src/plugins/react-docgen.ts b/code/frameworks/react-vite/src/plugins/react-docgen.ts index 8ef7a1159aaf..9d2242ce2654 100644 --- a/code/frameworks/react-vite/src/plugins/react-docgen.ts +++ b/code/frameworks/react-vite/src/plugins/react-docgen.ts @@ -51,7 +51,7 @@ export function reactDocgen({ importer: makeFsImporter((filename, basedir) => { const result = defaultLookupModule(filename, basedir); - if (RESOLVE_EXTENSIONS.find((ext) => result.endsWith(ext)) === undefined) { + if (RESOLVE_EXTENSIONS.find((ext) => result.endsWith(ext))) { return result; } diff --git a/code/presets/react-webpack/src/loaders/react-docgen-loader.ts b/code/presets/react-webpack/src/loaders/react-docgen-loader.ts index 81fa0b335a58..12ab911fd546 100644 --- a/code/presets/react-webpack/src/loaders/react-docgen-loader.ts +++ b/code/presets/react-webpack/src/loaders/react-docgen-loader.ts @@ -79,7 +79,7 @@ export default async function reactDocgenLoader( importer: makeFsImporter((filename, basedir) => { const result = defaultLookupModule(filename, basedir); - if (RESOLVE_EXTENSIONS.find((ext) => result.endsWith(ext)) === undefined) { + if (RESOLVE_EXTENSIONS.find((ext) => result.endsWith(ext))) { return result; } From ea40ff899fb300dff73de8e108ee6108c4bb1200 Mon Sep 17 00:00:00 2001 From: Valentin Palkovic Date: Fri, 1 Mar 2024 09:51:32 +0100 Subject: [PATCH 49/77] Handle TypeScript path aliases in react-docgen loader --- code/frameworks/react-vite/package.json | 5 +- .../src/plugins/react-docgen.test.ts | 52 +++++++++++++++++++ .../react-vite/src/plugins/react-docgen.ts | 52 +++++++++++++++---- code/frameworks/react-vite/src/preset.ts | 2 +- code/presets/react-webpack/package.json | 2 + .../src/loaders/react-docgen-loader.test.ts | 52 +++++++++++++++++++ .../src/loaders/react-docgen-loader.ts | 52 +++++++++++++++---- code/yarn.lock | 7 ++- 8 files changed, 201 insertions(+), 23 deletions(-) create mode 100644 code/frameworks/react-vite/src/plugins/react-docgen.test.ts create mode 100644 code/presets/react-webpack/src/loaders/react-docgen-loader.test.ts diff --git a/code/frameworks/react-vite/package.json b/code/frameworks/react-vite/package.json index b16bfeeaecb1..a413f6b4786e 100644 --- a/code/frameworks/react-vite/package.json +++ b/code/frameworks/react-vite/package.json @@ -50,10 +50,13 @@ "@joshwooding/vite-plugin-react-docgen-typescript": "0.3.0", "@rollup/pluginutils": "^5.0.2", "@storybook/builder-vite": "workspace:*", + "@storybook/node-logger": "workspace:*", "@storybook/react": "workspace:*", + "find-up": "^5.0.0", "magic-string": "^0.30.0", "react-docgen": "^7.0.0", - "resolve": "^1.22.8" + "resolve": "^1.22.8", + "tsconfig-paths": "^4.2.0" }, "devDependencies": { "@types/node": "^18.0.0", diff --git a/code/frameworks/react-vite/src/plugins/react-docgen.test.ts b/code/frameworks/react-vite/src/plugins/react-docgen.test.ts new file mode 100644 index 000000000000..1fed686198b9 --- /dev/null +++ b/code/frameworks/react-vite/src/plugins/react-docgen.test.ts @@ -0,0 +1,52 @@ +import { getReactDocgenImporter } from './react-docgen'; +import { describe, it, expect, vi } from 'vitest'; + +const reactDocgenMock = vi.hoisted(() => { + return { + makeFsImporter: vi.fn().mockImplementation((fn) => fn), + }; +}); + +const reactDocgenResolverMock = vi.hoisted(() => { + return { + defaultLookupModule: vi.fn(), + }; +}); + +vi.mock('./docgen-resolver', async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + defaultLookupModule: reactDocgenResolverMock.defaultLookupModule, + }; +}); + +vi.mock('react-docgen', async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + makeFsImporter: reactDocgenMock.makeFsImporter, + }; +}); + +describe('getReactDocgenImporter function', () => { + it('should not map the request if a tsconfig path mapping is not available', () => { + const filename = './src/components/Button.tsx'; + const basedir = '/src'; + const imported = getReactDocgenImporter(undefined); + reactDocgenResolverMock.defaultLookupModule.mockImplementation((filen: string) => filen); + const result = (imported as any)(filename, basedir); + expect(result).toBe(filename); + }); + + it('should map the request', () => { + const mappedFile = './mapped-file.tsx'; + const matchPath = vi.fn().mockReturnValue(mappedFile); + const filename = './src/components/Button.tsx'; + const basedir = '/src'; + const imported = getReactDocgenImporter(matchPath); + reactDocgenResolverMock.defaultLookupModule.mockImplementation((filen: string) => filen); + const result = (imported as any)(filename, basedir); + expect(result).toBe(mappedFile); + }); +}); diff --git a/code/frameworks/react-vite/src/plugins/react-docgen.ts b/code/frameworks/react-vite/src/plugins/react-docgen.ts index 9d2242ce2654..c59861e4ff43 100644 --- a/code/frameworks/react-vite/src/plugins/react-docgen.ts +++ b/code/frameworks/react-vite/src/plugins/react-docgen.ts @@ -10,12 +10,15 @@ import { } from 'react-docgen'; import MagicString from 'magic-string'; import type { PluginOption } from 'vite'; +import * as TsconfigPaths from 'tsconfig-paths'; +import findUp from 'find-up'; import actualNameHandler from './docgen-handlers/actualNameHandler'; import { RESOLVE_EXTENSIONS, ReactDocgenResolveError, defaultLookupModule, } from './docgen-resolver'; +import { logger } from '@storybook/node-logger'; type DocObj = Documentation & { actualName: string }; @@ -29,13 +32,27 @@ type Options = { exclude?: string | RegExp | (string | RegExp)[]; }; -export function reactDocgen({ +export async function reactDocgen({ include = /\.(mjs|tsx?|jsx?)$/, exclude = [/node_modules\/.*/], -}: Options = {}): PluginOption { +}: Options = {}): Promise { const cwd = process.cwd(); const filter = createFilter(include, exclude); + const tsconfigPath = await findUp('tsconfig.json', { cwd }); + const tsconfig = TsconfigPaths.loadConfig(tsconfigPath); + + let matchPath: TsconfigPaths.MatchPath | undefined; + + if (tsconfig.resultType === 'success') { + logger.info('Using tsconfig paths for react-docgen'); + matchPath = TsconfigPaths.createMatchPath(tsconfig.absoluteBaseUrl, tsconfig.paths, [ + 'browser', + 'module', + 'main', + ]); + } + return { name: 'storybook:react-docgen-plugin', enforce: 'pre', @@ -48,15 +65,7 @@ export function reactDocgen({ const docgenResults = parse(src, { resolver: defaultResolver, handlers, - importer: makeFsImporter((filename, basedir) => { - const result = defaultLookupModule(filename, basedir); - - if (RESOLVE_EXTENSIONS.find((ext) => result.endsWith(ext))) { - return result; - } - - throw new ReactDocgenResolveError(filename); - }), + importer: getReactDocgenImporter(matchPath), filename: id, }) as DocObj[]; const s = new MagicString(src); @@ -83,3 +92,24 @@ export function reactDocgen({ }, }; } + +export function getReactDocgenImporter(matchPath: TsconfigPaths.MatchPath | undefined) { + return makeFsImporter((filename, basedir) => { + const mappedFilenameByPaths = (() => { + if (matchPath) { + const match = matchPath(filename); + return match || filename; + } else { + return filename; + } + })(); + + const result = defaultLookupModule(mappedFilenameByPaths, basedir); + + if (RESOLVE_EXTENSIONS.find((ext) => result.endsWith(ext))) { + return result; + } + + throw new ReactDocgenResolveError(filename); + }); +} diff --git a/code/frameworks/react-vite/src/preset.ts b/code/frameworks/react-vite/src/preset.ts index 35a83a306ce0..cbdde0f61a07 100644 --- a/code/frameworks/react-vite/src/preset.ts +++ b/code/frameworks/react-vite/src/preset.ts @@ -43,7 +43,7 @@ export const viteFinal: StorybookConfig['viteFinal'] = async (config, { presets // Needs to run before the react plugin, so add to the front plugins.unshift( // If react-docgen is specified, use it for everything, otherwise only use it for non-typescript files - reactDocgen({ + await reactDocgen({ include: reactDocgenOption === 'react-docgen' ? /\.(mjs|tsx?|jsx?)$/ : /\.(mjs|jsx?)$/, }) ); diff --git a/code/presets/react-webpack/package.json b/code/presets/react-webpack/package.json index a79480cf13dc..5cec6e7be6af 100644 --- a/code/presets/react-webpack/package.json +++ b/code/presets/react-webpack/package.json @@ -71,11 +71,13 @@ "@storybook/react-docgen-typescript-plugin": "1.0.6--canary.9.0c3f3b7.0", "@types/node": "^18.0.0", "@types/semver": "^7.3.4", + "find-up": "^5.0.0", "fs-extra": "^11.1.0", "magic-string": "^0.30.5", "react-docgen": "^7.0.0", "resolve": "^1.22.8", "semver": "^7.3.7", + "tsconfig-paths": "^4.2.0", "webpack": "5" }, "devDependencies": { diff --git a/code/presets/react-webpack/src/loaders/react-docgen-loader.test.ts b/code/presets/react-webpack/src/loaders/react-docgen-loader.test.ts new file mode 100644 index 000000000000..cb017a7469b7 --- /dev/null +++ b/code/presets/react-webpack/src/loaders/react-docgen-loader.test.ts @@ -0,0 +1,52 @@ +import { getReactDocgenImporter } from './react-docgen-loader'; +import { describe, it, expect, vi } from 'vitest'; + +const reactDocgenMock = vi.hoisted(() => { + return { + makeFsImporter: vi.fn().mockImplementation((fn) => fn), + }; +}); + +const reactDocgenResolverMock = vi.hoisted(() => { + return { + defaultLookupModule: vi.fn(), + }; +}); + +vi.mock('./docgen-resolver', async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + defaultLookupModule: reactDocgenResolverMock.defaultLookupModule, + }; +}); + +vi.mock('react-docgen', async (importOriginal) => { + const actual = await importOriginal(); + return { + ...actual, + makeFsImporter: reactDocgenMock.makeFsImporter, + }; +}); + +describe('getReactDocgenImporter function', () => { + it('should not map the request if a tsconfig path mapping is not available', () => { + const filename = './src/components/Button.tsx'; + const basedir = '/src'; + const imported = getReactDocgenImporter(undefined); + reactDocgenResolverMock.defaultLookupModule.mockImplementation((filen: string) => filen); + const result = (imported as any)(filename, basedir); + expect(result).toBe(filename); + }); + + it('should map the request', () => { + const mappedFile = './mapped-file.tsx'; + const matchPath = vi.fn().mockReturnValue(mappedFile); + const filename = './src/components/Button.tsx'; + const basedir = '/src'; + const imported = getReactDocgenImporter(matchPath); + reactDocgenResolverMock.defaultLookupModule.mockImplementation((filen: string) => filen); + const result = (imported as any)(filename, basedir); + expect(result).toBe(mappedFile); + }); +}); diff --git a/code/presets/react-webpack/src/loaders/react-docgen-loader.ts b/code/presets/react-webpack/src/loaders/react-docgen-loader.ts index 12ab911fd546..15b71f19bfd5 100644 --- a/code/presets/react-webpack/src/loaders/react-docgen-loader.ts +++ b/code/presets/react-webpack/src/loaders/react-docgen-loader.ts @@ -6,6 +6,8 @@ import { ERROR_CODES, utils, } from 'react-docgen'; +import * as TsconfigPaths from 'tsconfig-paths'; +import findUp from 'find-up'; import MagicString from 'magic-string'; import type { LoaderContext } from 'webpack'; import type { Handler, NodePath, babelTypes as t, Documentation } from 'react-docgen'; @@ -62,6 +64,9 @@ const defaultHandlers = Object.values(docgenHandlers).map((handler) => handler); const defaultResolver = new docgenResolver.FindExportedDefinitionsResolver(); const handlers = [...defaultHandlers, actualNameHandler]; +let tsconfigPathsInitialized = false; +let matchPath: TsconfigPaths.MatchPath | undefined; + export default async function reactDocgenLoader( this: LoaderContext<{ debug: boolean }>, source: string @@ -71,20 +76,28 @@ export default async function reactDocgenLoader( const options = this.getOptions() || {}; const { debug = false } = options; + if (!tsconfigPathsInitialized) { + const tsconfigPath = await findUp('tsconfig.json', { cwd: process.cwd() }); + const tsconfig = TsconfigPaths.loadConfig(tsconfigPath); + + if (tsconfig.resultType === 'success') { + logger.info('Using tsconfig paths for react-docgen'); + matchPath = TsconfigPaths.createMatchPath(tsconfig.absoluteBaseUrl, tsconfig.paths, [ + 'browser', + 'module', + 'main', + ]); + } + + tsconfigPathsInitialized = true; + } + try { const docgenResults = parse(source, { filename: this.resourcePath, resolver: defaultResolver, handlers, - importer: makeFsImporter((filename, basedir) => { - const result = defaultLookupModule(filename, basedir); - - if (RESOLVE_EXTENSIONS.find((ext) => result.endsWith(ext))) { - return result; - } - - throw new ReactDocgenResolveError(filename); - }), + importer: getReactDocgenImporter(matchPath), babelOptions: { babelrc: false, configFile: false, @@ -122,3 +135,24 @@ export default async function reactDocgenLoader( } } } + +export function getReactDocgenImporter(matchingPath: TsconfigPaths.MatchPath | undefined) { + return makeFsImporter((filename, basedir) => { + const mappedFilenameByPaths = (() => { + if (matchingPath) { + const match = matchingPath(filename); + return match || filename; + } else { + return filename; + } + })(); + + const result = defaultLookupModule(mappedFilenameByPaths, basedir); + + if (RESOLVE_EXTENSIONS.find((ext) => result.endsWith(ext))) { + return result; + } + + throw new ReactDocgenResolveError(filename); + }); +} diff --git a/code/yarn.lock b/code/yarn.lock index 039c28a0c940..dfbdf6fca037 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -6340,11 +6340,13 @@ __metadata: "@storybook/react-docgen-typescript-plugin": "npm:1.0.6--canary.9.0c3f3b7.0" "@types/node": "npm:^18.0.0" "@types/semver": "npm:^7.3.4" + find-up: "npm:^5.0.0" fs-extra: "npm:^11.1.0" magic-string: "npm:^0.30.5" react-docgen: "npm:^7.0.0" resolve: "npm:^1.22.8" semver: "npm:^7.3.7" + tsconfig-paths: "npm:^4.2.0" typescript: "npm:^5.3.2" webpack: "npm:5" peerDependencies: @@ -6488,11 +6490,14 @@ __metadata: "@joshwooding/vite-plugin-react-docgen-typescript": "npm:0.3.0" "@rollup/pluginutils": "npm:^5.0.2" "@storybook/builder-vite": "workspace:*" + "@storybook/node-logger": "workspace:*" "@storybook/react": "workspace:*" "@types/node": "npm:^18.0.0" + find-up: "npm:^5.0.0" magic-string: "npm:^0.30.0" react-docgen: "npm:^7.0.0" resolve: "npm:^1.22.8" + tsconfig-paths: "npm:^4.2.0" typescript: "npm:^5.3.2" vite: "npm:^4.0.0" peerDependencies: @@ -28381,7 +28386,7 @@ __metadata: languageName: node linkType: hard -"tsconfig-paths@npm:^4.0.0, tsconfig-paths@npm:^4.1.2": +"tsconfig-paths@npm:^4.0.0, tsconfig-paths@npm:^4.1.2, tsconfig-paths@npm:^4.2.0": version: 4.2.0 resolution: "tsconfig-paths@npm:4.2.0" dependencies: From 12495e5027803c1838335b63b1784b4dab520d3e Mon Sep 17 00:00:00 2001 From: Valentin Palkovic Date: Fri, 1 Mar 2024 14:41:56 +0100 Subject: [PATCH 50/77] Setup prompt type for automigration --- code/lib/cli/src/automigrate/fixes/vite-config-file.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/lib/cli/src/automigrate/fixes/vite-config-file.ts b/code/lib/cli/src/automigrate/fixes/vite-config-file.ts index c74c7f378373..6a8dd9ec0e02 100644 --- a/code/lib/cli/src/automigrate/fixes/vite-config-file.ts +++ b/code/lib/cli/src/automigrate/fixes/vite-config-file.ts @@ -16,6 +16,8 @@ export const viteConfigFile = { versionRange: ['<8.0.0-beta.3', '>=8.0.0-beta.3'], + promptType: 'notification', + async check({ mainConfig, packageManager, mainConfigPath }) { let isViteConfigFileFound = !!(await findUp( ['vite.config.js', 'vite.config.mjs', 'vite.config.cjs', 'vite.config.ts'], From c3335f7dec8368a1ad203d59e9fef542bcc2c7f6 Mon Sep 17 00:00:00 2001 From: Michael Shilman Date: Sat, 2 Mar 2024 08:24:59 +0800 Subject: [PATCH 51/77] Onboarding: Fix manager dist reference --- code/addons/onboarding/preset.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/addons/onboarding/preset.js b/code/addons/onboarding/preset.js index 2c7ea670f4a6..87f1602c2f26 100644 --- a/code/addons/onboarding/preset.js +++ b/code/addons/onboarding/preset.js @@ -1,5 +1,5 @@ function managerEntries(entry = []) { - return [...entry, require.resolve('./dist/manager.mjs')]; + return [...entry, require.resolve('./dist/manager.js')]; } module.exports = { From 2d75e1fd15f21f6817ead1e6baffce95566f10fe Mon Sep 17 00:00:00 2001 From: storybook-bot <32066757+storybook-bot@users.noreply.github.com> Date: Sat, 2 Mar 2024 00:53:52 +0000 Subject: [PATCH 52/77] Write changelog for 8.0.0-rc.1 [skip ci] --- CHANGELOG.prerelease.md | 6 ++++++ code/package.json | 3 ++- docs/versions/next.json | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.prerelease.md b/CHANGELOG.prerelease.md index bd3066ba9728..6e9e1eb4ba44 100644 --- a/CHANGELOG.prerelease.md +++ b/CHANGELOG.prerelease.md @@ -1,3 +1,9 @@ +## 8.0.0-rc.1 + +- CLI: Fix addon compatibility check error reporting in storybook dev - [#26258](https://github.com/storybookjs/storybook/pull/26258), thanks [@yannbf](https://github.com/yannbf)! +- Onboarding: Fix manager dist reference - [#26282](https://github.com/storybookjs/storybook/pull/26282), thanks [@shilman](https://github.com/shilman)! +- ReactVite: Docgen ignore un-parsable files - [#26254](https://github.com/storybookjs/storybook/pull/26254), thanks [@ndelangen](https://github.com/ndelangen)! + ## 8.0.0-rc.0 Bumping 8.0.0-beta.6 to 8.0.0-rc.0. Please refer to the changelogs of previous beta releases. diff --git a/code/package.json b/code/package.json index 071cf4a60003..3f0d826438ec 100644 --- a/code/package.json +++ b/code/package.json @@ -294,5 +294,6 @@ "Dependency Upgrades" ] ] - } + }, + "deferredNextVersion": "8.0.0-rc.1" } diff --git a/docs/versions/next.json b/docs/versions/next.json index 7e6974b261e7..a1c6e9350e50 100644 --- a/docs/versions/next.json +++ b/docs/versions/next.json @@ -1 +1 @@ -{"version":"8.0.0-rc.0","info":{"plain":"Bumping 8.0.0-beta.6 to 8.0.0-rc.0. Please refer to the changelogs of previous beta releases."}} +{"version":"8.0.0-rc.1","info":{"plain":"- CLI: Fix addon compatibility check error reporting in storybook dev - [#26258](https://github.com/storybookjs/storybook/pull/26258), thanks [@yannbf](https://github.com/yannbf)!\n- Onboarding: Fix manager dist reference - [#26282](https://github.com/storybookjs/storybook/pull/26282), thanks [@shilman](https://github.com/shilman)!\n- ReactVite: Docgen ignore un-parsable files - [#26254](https://github.com/storybookjs/storybook/pull/26254), thanks [@ndelangen](https://github.com/ndelangen)!"}} From 2b48135c376b04ab28fa77c342f535fc242df6b2 Mon Sep 17 00:00:00 2001 From: Michael Shilman Date: Sat, 2 Mar 2024 09:20:07 +0800 Subject: [PATCH 53/77] Controls: Fix type summary --- code/ui/blocks/src/components/ArgsTable/ArgRow.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/code/ui/blocks/src/components/ArgsTable/ArgRow.tsx b/code/ui/blocks/src/components/ArgsTable/ArgRow.tsx index d6e2c73ad905..8f6b6f2c5f99 100644 --- a/code/ui/blocks/src/components/ArgsTable/ArgRow.tsx +++ b/code/ui/blocks/src/components/ArgsTable/ArgRow.tsx @@ -76,12 +76,18 @@ const StyledTd = styled.td<{ expandable: boolean }>(({ theme, expandable }) => ( paddingLeft: expandable ? '40px !important' : '20px !important', })); +const toSummary = (value: any) => { + if (!value) return value; + const val = typeof value === 'string' ? value : value.name; + return { summary: val }; +}; + export const ArgRow: FC = (props) => { const [isHovered, setIsHovered] = useState(false); const { row, updateArgs, compact, expandable, initialExpandedArgs } = props; const { name, description } = row; const table = (row.table || {}) as TableAnnotation; - const type = table.type || row.type; + const type = table.type || toSummary(row.type); const defaultValue = table.defaultValue || row.defaultValue; const required = row.type?.required; const hasDescription = description != null && description !== ''; From 68f1b28e83b04763469f561648d01dba7606664b Mon Sep 17 00:00:00 2001 From: storybook-bot <32066757+storybook-bot@users.noreply.github.com> Date: Sat, 2 Mar 2024 01:25:45 +0000 Subject: [PATCH 54/77] Bump version from "8.0.0-rc.0" to "8.0.0-rc.1" [skip ci] --- code/addons/a11y/package.json | 2 +- code/addons/actions/package.json | 2 +- code/addons/backgrounds/package.json | 2 +- code/addons/controls/package.json | 2 +- code/addons/docs/package.json | 2 +- code/addons/essentials/package.json | 2 +- code/addons/gfm/package.json | 2 +- code/addons/highlight/package.json | 2 +- code/addons/interactions/package.json | 2 +- code/addons/jest/package.json | 2 +- code/addons/links/package.json | 2 +- code/addons/measure/package.json | 2 +- code/addons/onboarding/package.json | 2 +- code/addons/outline/package.json | 2 +- code/addons/storysource/package.json | 2 +- code/addons/themes/package.json | 2 +- code/addons/toolbars/package.json | 2 +- code/addons/viewport/package.json | 2 +- code/builders/builder-manager/package.json | 2 +- code/builders/builder-vite/package.json | 2 +- code/builders/builder-webpack5/package.json | 2 +- code/frameworks/angular/package.json | 2 +- code/frameworks/ember/package.json | 2 +- code/frameworks/html-vite/package.json | 2 +- code/frameworks/html-webpack5/package.json | 2 +- code/frameworks/nextjs/package.json | 2 +- code/frameworks/preact-vite/package.json | 2 +- code/frameworks/preact-webpack5/package.json | 2 +- code/frameworks/react-vite/package.json | 2 +- code/frameworks/react-webpack5/package.json | 2 +- code/frameworks/server-webpack5/package.json | 2 +- code/frameworks/svelte-vite/package.json | 2 +- code/frameworks/svelte-webpack5/package.json | 2 +- code/frameworks/sveltekit/package.json | 2 +- code/frameworks/vue3-vite/package.json | 2 +- code/frameworks/vue3-webpack5/package.json | 2 +- .../web-components-vite/package.json | 2 +- .../web-components-webpack5/package.json | 2 +- code/lib/channels/package.json | 2 +- code/lib/cli-sb/package.json | 2 +- code/lib/cli-storybook/package.json | 2 +- code/lib/cli/package.json | 2 +- code/lib/client-logger/package.json | 2 +- code/lib/codemod/package.json | 2 +- code/lib/core-common/package.json | 2 +- code/lib/core-common/src/versions.ts | 160 +++++++++--------- code/lib/core-events/package.json | 2 +- code/lib/core-server/package.json | 2 +- code/lib/core-webpack/package.json | 2 +- code/lib/csf-plugin/package.json | 2 +- code/lib/csf-tools/package.json | 2 +- code/lib/docs-tools/package.json | 2 +- code/lib/instrumenter/package.json | 2 +- code/lib/manager-api/package.json | 2 +- code/lib/manager-api/src/version.ts | 2 +- code/lib/node-logger/package.json | 2 +- code/lib/preview-api/package.json | 2 +- code/lib/preview/package.json | 2 +- code/lib/react-dom-shim/package.json | 2 +- code/lib/router/package.json | 2 +- code/lib/source-loader/package.json | 2 +- code/lib/telemetry/package.json | 2 +- code/lib/test/package.json | 2 +- code/lib/theming/package.json | 2 +- code/lib/types/package.json | 2 +- code/package.json | 5 +- code/presets/create-react-app/package.json | 2 +- code/presets/html-webpack/package.json | 2 +- code/presets/preact-webpack/package.json | 2 +- code/presets/react-webpack/package.json | 2 +- code/presets/server-webpack/package.json | 2 +- code/presets/svelte-webpack/package.json | 2 +- code/presets/vue3-webpack/package.json | 2 +- code/renderers/html/package.json | 2 +- code/renderers/preact/package.json | 2 +- code/renderers/react/package.json | 2 +- code/renderers/server/package.json | 2 +- code/renderers/svelte/package.json | 2 +- code/renderers/vue3/package.json | 2 +- code/renderers/web-components/package.json | 2 +- code/ui/blocks/package.json | 2 +- code/ui/components/package.json | 2 +- code/ui/manager/package.json | 2 +- 83 files changed, 163 insertions(+), 164 deletions(-) diff --git a/code/addons/a11y/package.json b/code/addons/a11y/package.json index e7057ee37c7d..ebae68256c87 100644 --- a/code/addons/a11y/package.json +++ b/code/addons/a11y/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-a11y", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Test component compliance with web accessibility standards", "keywords": [ "a11y", diff --git a/code/addons/actions/package.json b/code/addons/actions/package.json index c1a55b717379..bc89e2f5e5c7 100644 --- a/code/addons/actions/package.json +++ b/code/addons/actions/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-actions", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Get UI feedback when an action is performed on an interactive element", "keywords": [ "storybook", diff --git a/code/addons/backgrounds/package.json b/code/addons/backgrounds/package.json index 1d9cba4d0338..4fbdfc5c027c 100644 --- a/code/addons/backgrounds/package.json +++ b/code/addons/backgrounds/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-backgrounds", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Switch backgrounds to view components in different settings", "keywords": [ "addon", diff --git a/code/addons/controls/package.json b/code/addons/controls/package.json index edf0f1d8aca9..588947d02c70 100644 --- a/code/addons/controls/package.json +++ b/code/addons/controls/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-controls", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Interact with component inputs dynamically in the Storybook UI", "keywords": [ "addon", diff --git a/code/addons/docs/package.json b/code/addons/docs/package.json index afe403d9e813..a159c03063b6 100644 --- a/code/addons/docs/package.json +++ b/code/addons/docs/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-docs", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Document component usage and properties in Markdown", "keywords": [ "addon", diff --git a/code/addons/essentials/package.json b/code/addons/essentials/package.json index c792492511e3..61dbf507bbb1 100644 --- a/code/addons/essentials/package.json +++ b/code/addons/essentials/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-essentials", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Curated addons to bring out the best of Storybook", "keywords": [ "addon", diff --git a/code/addons/gfm/package.json b/code/addons/gfm/package.json index f618ecf6effd..5491ba3a58e4 100644 --- a/code/addons/gfm/package.json +++ b/code/addons/gfm/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-mdx-gfm", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "GitHub Flavored Markdown in Storybook", "keywords": [ "addon", diff --git a/code/addons/highlight/package.json b/code/addons/highlight/package.json index 5347386529e5..28f331bf4dc8 100644 --- a/code/addons/highlight/package.json +++ b/code/addons/highlight/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-highlight", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Highlight DOM nodes within your stories", "keywords": [ "storybook-addons", diff --git a/code/addons/interactions/package.json b/code/addons/interactions/package.json index b05d3c512d42..daece4716036 100644 --- a/code/addons/interactions/package.json +++ b/code/addons/interactions/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-interactions", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Automate, test and debug user interactions", "keywords": [ "storybook-addons", diff --git a/code/addons/jest/package.json b/code/addons/jest/package.json index 28c2c343acba..3b194968932c 100644 --- a/code/addons/jest/package.json +++ b/code/addons/jest/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-jest", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "React storybook addon that show component jest report", "keywords": [ "addon", diff --git a/code/addons/links/package.json b/code/addons/links/package.json index 9cfea47205a5..d1777a65aa4d 100644 --- a/code/addons/links/package.json +++ b/code/addons/links/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-links", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Link stories together to build demos and prototypes with your UI components", "keywords": [ "addon", diff --git a/code/addons/measure/package.json b/code/addons/measure/package.json index c33c07fd2bb0..2d23660bdac2 100644 --- a/code/addons/measure/package.json +++ b/code/addons/measure/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-measure", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Inspect layouts by visualizing the box model", "keywords": [ "storybook-addons", diff --git a/code/addons/onboarding/package.json b/code/addons/onboarding/package.json index cef855f5c780..057221c7df4e 100644 --- a/code/addons/onboarding/package.json +++ b/code/addons/onboarding/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-onboarding", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Storybook Addon Onboarding - Introduces a new onboarding experience", "keywords": [ "storybook-addons", diff --git a/code/addons/outline/package.json b/code/addons/outline/package.json index 5afe3e8023c9..a0a1ff61ab03 100644 --- a/code/addons/outline/package.json +++ b/code/addons/outline/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-outline", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Outline all elements with CSS to help with layout placement and alignment", "keywords": [ "storybook-addons", diff --git a/code/addons/storysource/package.json b/code/addons/storysource/package.json index a24b842f279e..c9fc3680601d 100644 --- a/code/addons/storysource/package.json +++ b/code/addons/storysource/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-storysource", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "View a story’s source code to see how it works and paste into your app", "keywords": [ "addon", diff --git a/code/addons/themes/package.json b/code/addons/themes/package.json index 6af4ca76727a..c28b3426d2e1 100644 --- a/code/addons/themes/package.json +++ b/code/addons/themes/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-themes", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Switch between multiple themes for you components in Storybook", "keywords": [ "css", diff --git a/code/addons/toolbars/package.json b/code/addons/toolbars/package.json index 047f7e002a34..f9aa8edb217e 100644 --- a/code/addons/toolbars/package.json +++ b/code/addons/toolbars/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-toolbars", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Create your own toolbar items that control story rendering", "keywords": [ "addon", diff --git a/code/addons/viewport/package.json b/code/addons/viewport/package.json index 42f34b72834f..55459bde0a95 100644 --- a/code/addons/viewport/package.json +++ b/code/addons/viewport/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/addon-viewport", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Build responsive components by adjusting Storybook’s viewport size and orientation", "keywords": [ "addon", diff --git a/code/builders/builder-manager/package.json b/code/builders/builder-manager/package.json index 03f53e5dd368..e892d2dbf0e9 100644 --- a/code/builders/builder-manager/package.json +++ b/code/builders/builder-manager/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/builder-manager", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Storybook manager builder", "keywords": [ "storybook" diff --git a/code/builders/builder-vite/package.json b/code/builders/builder-vite/package.json index f4ed850b8034..b1dd337500cb 100644 --- a/code/builders/builder-vite/package.json +++ b/code/builders/builder-vite/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/builder-vite", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "A plugin to run and build Storybooks with Vite", "homepage": "https://github.com/storybookjs/storybook/tree/next/code/builders/builder-vite/#readme", "bugs": { diff --git a/code/builders/builder-webpack5/package.json b/code/builders/builder-webpack5/package.json index e42617eed5d2..09e2717e316a 100644 --- a/code/builders/builder-webpack5/package.json +++ b/code/builders/builder-webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/builder-webpack5", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Storybook framework-agnostic API", "keywords": [ "storybook" diff --git a/code/frameworks/angular/package.json b/code/frameworks/angular/package.json index de20986e3618..b58cb37738cf 100644 --- a/code/frameworks/angular/package.json +++ b/code/frameworks/angular/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/angular", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Storybook for Angular: Develop Angular components in isolation with hot reloading.", "keywords": [ "storybook", diff --git a/code/frameworks/ember/package.json b/code/frameworks/ember/package.json index 70c68121930b..f279db33b3ed 100644 --- a/code/frameworks/ember/package.json +++ b/code/frameworks/ember/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/ember", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Storybook for Ember: Develop Ember Component in isolation with Hot Reloading.", "homepage": "https://github.com/storybookjs/storybook/tree/next/code/frameworks/ember", "bugs": { diff --git a/code/frameworks/html-vite/package.json b/code/frameworks/html-vite/package.json index dd35f7ee8983..c4004391a219 100644 --- a/code/frameworks/html-vite/package.json +++ b/code/frameworks/html-vite/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/html-vite", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Storybook for HTML and Vite: Develop HTML in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/html-webpack5/package.json b/code/frameworks/html-webpack5/package.json index fa8386b9071f..81cc4e41b756 100644 --- a/code/frameworks/html-webpack5/package.json +++ b/code/frameworks/html-webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/html-webpack5", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Storybook for HTML: View HTML snippets in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/nextjs/package.json b/code/frameworks/nextjs/package.json index 42c3eb78d060..73b56bd55c4b 100644 --- a/code/frameworks/nextjs/package.json +++ b/code/frameworks/nextjs/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/nextjs", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Storybook for Next.js", "keywords": [ "storybook", diff --git a/code/frameworks/preact-vite/package.json b/code/frameworks/preact-vite/package.json index 0b5819bd04f5..e059321937b6 100644 --- a/code/frameworks/preact-vite/package.json +++ b/code/frameworks/preact-vite/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preact-vite", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Storybook for Preact and Vite: Develop Preact components in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/preact-webpack5/package.json b/code/frameworks/preact-webpack5/package.json index b58ce7ede06a..1bfffc99ab65 100644 --- a/code/frameworks/preact-webpack5/package.json +++ b/code/frameworks/preact-webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preact-webpack5", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Storybook for Preact: Develop Preact Component in isolation.", "keywords": [ "storybook" diff --git a/code/frameworks/react-vite/package.json b/code/frameworks/react-vite/package.json index 43a88fdc2838..1d3cfc67a144 100644 --- a/code/frameworks/react-vite/package.json +++ b/code/frameworks/react-vite/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/react-vite", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Storybook for React and Vite: Develop React components in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/react-webpack5/package.json b/code/frameworks/react-webpack5/package.json index f91e1ecb1b1a..448905c2a899 100644 --- a/code/frameworks/react-webpack5/package.json +++ b/code/frameworks/react-webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/react-webpack5", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Storybook for React: Develop React Component in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/server-webpack5/package.json b/code/frameworks/server-webpack5/package.json index 6ea2a36ce6a8..8b00bc35433d 100644 --- a/code/frameworks/server-webpack5/package.json +++ b/code/frameworks/server-webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/server-webpack5", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Storybook for Server: View HTML snippets from a server in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/svelte-vite/package.json b/code/frameworks/svelte-vite/package.json index 17c1e07bd414..6af6bc742f3a 100644 --- a/code/frameworks/svelte-vite/package.json +++ b/code/frameworks/svelte-vite/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/svelte-vite", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Storybook for Svelte and Vite: Develop Svelte components in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/svelte-webpack5/package.json b/code/frameworks/svelte-webpack5/package.json index dbb884b0ed44..7dccdc501e4a 100644 --- a/code/frameworks/svelte-webpack5/package.json +++ b/code/frameworks/svelte-webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/svelte-webpack5", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Storybook for Svelte: Develop Svelte Component in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/sveltekit/package.json b/code/frameworks/sveltekit/package.json index e6f043e0b74c..cc3d8ca57b87 100644 --- a/code/frameworks/sveltekit/package.json +++ b/code/frameworks/sveltekit/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/sveltekit", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Storybook for SvelteKit", "keywords": [ "storybook", diff --git a/code/frameworks/vue3-vite/package.json b/code/frameworks/vue3-vite/package.json index 60fd9c7e67e0..ad452ade8d46 100644 --- a/code/frameworks/vue3-vite/package.json +++ b/code/frameworks/vue3-vite/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/vue3-vite", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Storybook for Vue3 and Vite: Develop Vue3 components in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/vue3-webpack5/package.json b/code/frameworks/vue3-webpack5/package.json index 1774e6739735..6b6504531dbf 100644 --- a/code/frameworks/vue3-webpack5/package.json +++ b/code/frameworks/vue3-webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/vue3-webpack5", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Storybook for Vue 3: Develop Vue 3 Components in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/web-components-vite/package.json b/code/frameworks/web-components-vite/package.json index 4c274ca128fc..c4151a92ca89 100644 --- a/code/frameworks/web-components-vite/package.json +++ b/code/frameworks/web-components-vite/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/web-components-vite", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Storybook for web-components and Vite: Develop Web Components in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/frameworks/web-components-webpack5/package.json b/code/frameworks/web-components-webpack5/package.json index 83e6f47fc808..7e0ab8ec6130 100644 --- a/code/frameworks/web-components-webpack5/package.json +++ b/code/frameworks/web-components-webpack5/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/web-components-webpack5", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Storybook for web-components: View web components snippets in isolation with Hot Reloading.", "keywords": [ "lit", diff --git a/code/lib/channels/package.json b/code/lib/channels/package.json index 4157290b916e..6abecbb236fc 100644 --- a/code/lib/channels/package.json +++ b/code/lib/channels/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/channels", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "", "keywords": [ "storybook" diff --git a/code/lib/cli-sb/package.json b/code/lib/cli-sb/package.json index 589235ac4c83..fb2741dc33a2 100644 --- a/code/lib/cli-sb/package.json +++ b/code/lib/cli-sb/package.json @@ -1,6 +1,6 @@ { "name": "sb", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Storybook CLI", "keywords": [ "storybook" diff --git a/code/lib/cli-storybook/package.json b/code/lib/cli-storybook/package.json index 14dff4e67c38..f4e2319a57cb 100644 --- a/code/lib/cli-storybook/package.json +++ b/code/lib/cli-storybook/package.json @@ -1,6 +1,6 @@ { "name": "storybook", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Storybook CLI", "keywords": [ "storybook" diff --git a/code/lib/cli/package.json b/code/lib/cli/package.json index ef6648b7bdac..ed8b9f90bcf6 100644 --- a/code/lib/cli/package.json +++ b/code/lib/cli/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/cli", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Storybook's CLI - install, dev, build, upgrade, and more", "keywords": [ "cli", diff --git a/code/lib/client-logger/package.json b/code/lib/client-logger/package.json index ce0c6e8651de..f5f6f32ed843 100644 --- a/code/lib/client-logger/package.json +++ b/code/lib/client-logger/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/client-logger", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "", "keywords": [ "storybook" diff --git a/code/lib/codemod/package.json b/code/lib/codemod/package.json index 51e18e91ef1e..0e4154e0db74 100644 --- a/code/lib/codemod/package.json +++ b/code/lib/codemod/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/codemod", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "A collection of codemod scripts written with JSCodeshift", "keywords": [ "storybook" diff --git a/code/lib/core-common/package.json b/code/lib/core-common/package.json index c40b6c3569d8..169977d00655 100644 --- a/code/lib/core-common/package.json +++ b/code/lib/core-common/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/core-common", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Storybook framework-agnostic API", "keywords": [ "storybook" diff --git a/code/lib/core-common/src/versions.ts b/code/lib/core-common/src/versions.ts index eb304c7d984a..346f3d272c65 100644 --- a/code/lib/core-common/src/versions.ts +++ b/code/lib/core-common/src/versions.ts @@ -1,83 +1,83 @@ // auto generated file, do not edit export default { - '@storybook/addon-a11y': '8.0.0-rc.0', - '@storybook/addon-actions': '8.0.0-rc.0', - '@storybook/addon-backgrounds': '8.0.0-rc.0', - '@storybook/addon-controls': '8.0.0-rc.0', - '@storybook/addon-docs': '8.0.0-rc.0', - '@storybook/addon-essentials': '8.0.0-rc.0', - '@storybook/addon-highlight': '8.0.0-rc.0', - '@storybook/addon-interactions': '8.0.0-rc.0', - '@storybook/addon-jest': '8.0.0-rc.0', - '@storybook/addon-links': '8.0.0-rc.0', - '@storybook/addon-mdx-gfm': '8.0.0-rc.0', - '@storybook/addon-measure': '8.0.0-rc.0', - '@storybook/addon-onboarding': '8.0.0-rc.0', - '@storybook/addon-outline': '8.0.0-rc.0', - '@storybook/addon-storysource': '8.0.0-rc.0', - '@storybook/addon-themes': '8.0.0-rc.0', - '@storybook/addon-toolbars': '8.0.0-rc.0', - '@storybook/addon-viewport': '8.0.0-rc.0', - '@storybook/angular': '8.0.0-rc.0', - '@storybook/blocks': '8.0.0-rc.0', - '@storybook/builder-manager': '8.0.0-rc.0', - '@storybook/builder-vite': '8.0.0-rc.0', - '@storybook/builder-webpack5': '8.0.0-rc.0', - '@storybook/channels': '8.0.0-rc.0', - '@storybook/cli': '8.0.0-rc.0', - '@storybook/client-logger': '8.0.0-rc.0', - '@storybook/codemod': '8.0.0-rc.0', - '@storybook/components': '8.0.0-rc.0', - '@storybook/core-common': '8.0.0-rc.0', - '@storybook/core-events': '8.0.0-rc.0', - '@storybook/core-server': '8.0.0-rc.0', - '@storybook/core-webpack': '8.0.0-rc.0', - '@storybook/csf-plugin': '8.0.0-rc.0', - '@storybook/csf-tools': '8.0.0-rc.0', - '@storybook/docs-tools': '8.0.0-rc.0', - '@storybook/ember': '8.0.0-rc.0', - '@storybook/html': '8.0.0-rc.0', - '@storybook/html-vite': '8.0.0-rc.0', - '@storybook/html-webpack5': '8.0.0-rc.0', - '@storybook/instrumenter': '8.0.0-rc.0', - '@storybook/manager': '8.0.0-rc.0', - '@storybook/manager-api': '8.0.0-rc.0', - '@storybook/nextjs': '8.0.0-rc.0', - '@storybook/node-logger': '8.0.0-rc.0', - '@storybook/preact': '8.0.0-rc.0', - '@storybook/preact-vite': '8.0.0-rc.0', - '@storybook/preact-webpack5': '8.0.0-rc.0', - '@storybook/preset-create-react-app': '8.0.0-rc.0', - '@storybook/preset-html-webpack': '8.0.0-rc.0', - '@storybook/preset-preact-webpack': '8.0.0-rc.0', - '@storybook/preset-react-webpack': '8.0.0-rc.0', - '@storybook/preset-server-webpack': '8.0.0-rc.0', - '@storybook/preset-svelte-webpack': '8.0.0-rc.0', - '@storybook/preset-vue3-webpack': '8.0.0-rc.0', - '@storybook/preview': '8.0.0-rc.0', - '@storybook/preview-api': '8.0.0-rc.0', - '@storybook/react': '8.0.0-rc.0', - '@storybook/react-dom-shim': '8.0.0-rc.0', - '@storybook/react-vite': '8.0.0-rc.0', - '@storybook/react-webpack5': '8.0.0-rc.0', - '@storybook/router': '8.0.0-rc.0', - '@storybook/server': '8.0.0-rc.0', - '@storybook/server-webpack5': '8.0.0-rc.0', - '@storybook/source-loader': '8.0.0-rc.0', - '@storybook/svelte': '8.0.0-rc.0', - '@storybook/svelte-vite': '8.0.0-rc.0', - '@storybook/svelte-webpack5': '8.0.0-rc.0', - '@storybook/sveltekit': '8.0.0-rc.0', - '@storybook/telemetry': '8.0.0-rc.0', - '@storybook/test': '8.0.0-rc.0', - '@storybook/theming': '8.0.0-rc.0', - '@storybook/types': '8.0.0-rc.0', - '@storybook/vue3': '8.0.0-rc.0', - '@storybook/vue3-vite': '8.0.0-rc.0', - '@storybook/vue3-webpack5': '8.0.0-rc.0', - '@storybook/web-components': '8.0.0-rc.0', - '@storybook/web-components-vite': '8.0.0-rc.0', - '@storybook/web-components-webpack5': '8.0.0-rc.0', - sb: '8.0.0-rc.0', - storybook: '8.0.0-rc.0', + '@storybook/addon-a11y': '8.0.0-rc.1', + '@storybook/addon-actions': '8.0.0-rc.1', + '@storybook/addon-backgrounds': '8.0.0-rc.1', + '@storybook/addon-controls': '8.0.0-rc.1', + '@storybook/addon-docs': '8.0.0-rc.1', + '@storybook/addon-essentials': '8.0.0-rc.1', + '@storybook/addon-highlight': '8.0.0-rc.1', + '@storybook/addon-interactions': '8.0.0-rc.1', + '@storybook/addon-jest': '8.0.0-rc.1', + '@storybook/addon-links': '8.0.0-rc.1', + '@storybook/addon-mdx-gfm': '8.0.0-rc.1', + '@storybook/addon-measure': '8.0.0-rc.1', + '@storybook/addon-onboarding': '8.0.0-rc.1', + '@storybook/addon-outline': '8.0.0-rc.1', + '@storybook/addon-storysource': '8.0.0-rc.1', + '@storybook/addon-themes': '8.0.0-rc.1', + '@storybook/addon-toolbars': '8.0.0-rc.1', + '@storybook/addon-viewport': '8.0.0-rc.1', + '@storybook/angular': '8.0.0-rc.1', + '@storybook/blocks': '8.0.0-rc.1', + '@storybook/builder-manager': '8.0.0-rc.1', + '@storybook/builder-vite': '8.0.0-rc.1', + '@storybook/builder-webpack5': '8.0.0-rc.1', + '@storybook/channels': '8.0.0-rc.1', + '@storybook/cli': '8.0.0-rc.1', + '@storybook/client-logger': '8.0.0-rc.1', + '@storybook/codemod': '8.0.0-rc.1', + '@storybook/components': '8.0.0-rc.1', + '@storybook/core-common': '8.0.0-rc.1', + '@storybook/core-events': '8.0.0-rc.1', + '@storybook/core-server': '8.0.0-rc.1', + '@storybook/core-webpack': '8.0.0-rc.1', + '@storybook/csf-plugin': '8.0.0-rc.1', + '@storybook/csf-tools': '8.0.0-rc.1', + '@storybook/docs-tools': '8.0.0-rc.1', + '@storybook/ember': '8.0.0-rc.1', + '@storybook/html': '8.0.0-rc.1', + '@storybook/html-vite': '8.0.0-rc.1', + '@storybook/html-webpack5': '8.0.0-rc.1', + '@storybook/instrumenter': '8.0.0-rc.1', + '@storybook/manager': '8.0.0-rc.1', + '@storybook/manager-api': '8.0.0-rc.1', + '@storybook/nextjs': '8.0.0-rc.1', + '@storybook/node-logger': '8.0.0-rc.1', + '@storybook/preact': '8.0.0-rc.1', + '@storybook/preact-vite': '8.0.0-rc.1', + '@storybook/preact-webpack5': '8.0.0-rc.1', + '@storybook/preset-create-react-app': '8.0.0-rc.1', + '@storybook/preset-html-webpack': '8.0.0-rc.1', + '@storybook/preset-preact-webpack': '8.0.0-rc.1', + '@storybook/preset-react-webpack': '8.0.0-rc.1', + '@storybook/preset-server-webpack': '8.0.0-rc.1', + '@storybook/preset-svelte-webpack': '8.0.0-rc.1', + '@storybook/preset-vue3-webpack': '8.0.0-rc.1', + '@storybook/preview': '8.0.0-rc.1', + '@storybook/preview-api': '8.0.0-rc.1', + '@storybook/react': '8.0.0-rc.1', + '@storybook/react-dom-shim': '8.0.0-rc.1', + '@storybook/react-vite': '8.0.0-rc.1', + '@storybook/react-webpack5': '8.0.0-rc.1', + '@storybook/router': '8.0.0-rc.1', + '@storybook/server': '8.0.0-rc.1', + '@storybook/server-webpack5': '8.0.0-rc.1', + '@storybook/source-loader': '8.0.0-rc.1', + '@storybook/svelte': '8.0.0-rc.1', + '@storybook/svelte-vite': '8.0.0-rc.1', + '@storybook/svelte-webpack5': '8.0.0-rc.1', + '@storybook/sveltekit': '8.0.0-rc.1', + '@storybook/telemetry': '8.0.0-rc.1', + '@storybook/test': '8.0.0-rc.1', + '@storybook/theming': '8.0.0-rc.1', + '@storybook/types': '8.0.0-rc.1', + '@storybook/vue3': '8.0.0-rc.1', + '@storybook/vue3-vite': '8.0.0-rc.1', + '@storybook/vue3-webpack5': '8.0.0-rc.1', + '@storybook/web-components': '8.0.0-rc.1', + '@storybook/web-components-vite': '8.0.0-rc.1', + '@storybook/web-components-webpack5': '8.0.0-rc.1', + sb: '8.0.0-rc.1', + storybook: '8.0.0-rc.1', }; diff --git a/code/lib/core-events/package.json b/code/lib/core-events/package.json index 8d2fcc7de97a..03a63f346e27 100644 --- a/code/lib/core-events/package.json +++ b/code/lib/core-events/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/core-events", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Event names used in storybook core", "keywords": [ "storybook" diff --git a/code/lib/core-server/package.json b/code/lib/core-server/package.json index d00c78ec22b6..663facee0635 100644 --- a/code/lib/core-server/package.json +++ b/code/lib/core-server/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/core-server", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Storybook framework-agnostic API", "keywords": [ "storybook" diff --git a/code/lib/core-webpack/package.json b/code/lib/core-webpack/package.json index f9675ac7f7a6..46f38e226ea1 100644 --- a/code/lib/core-webpack/package.json +++ b/code/lib/core-webpack/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/core-webpack", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Storybook framework-agnostic API", "keywords": [ "storybook" diff --git a/code/lib/csf-plugin/package.json b/code/lib/csf-plugin/package.json index de3f29bc395a..c447831f6657 100644 --- a/code/lib/csf-plugin/package.json +++ b/code/lib/csf-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/csf-plugin", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Enrich CSF files via static analysis", "keywords": [ "storybook" diff --git a/code/lib/csf-tools/package.json b/code/lib/csf-tools/package.json index 908f50b5816f..5a32a79f9453 100644 --- a/code/lib/csf-tools/package.json +++ b/code/lib/csf-tools/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/csf-tools", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Parse and manipulate CSF and Storybook config files", "keywords": [ "storybook" diff --git a/code/lib/docs-tools/package.json b/code/lib/docs-tools/package.json index 6dd8e6b0378c..06e103124ee1 100644 --- a/code/lib/docs-tools/package.json +++ b/code/lib/docs-tools/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/docs-tools", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Shared utility functions for frameworks to implement docs", "keywords": [ "storybook" diff --git a/code/lib/instrumenter/package.json b/code/lib/instrumenter/package.json index 7776051f6845..32c7c06686a8 100644 --- a/code/lib/instrumenter/package.json +++ b/code/lib/instrumenter/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/instrumenter", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "", "keywords": [ "storybook" diff --git a/code/lib/manager-api/package.json b/code/lib/manager-api/package.json index d4a46f9b543e..a790395da7a3 100644 --- a/code/lib/manager-api/package.json +++ b/code/lib/manager-api/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/manager-api", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Core Storybook Manager API & Context", "keywords": [ "storybook" diff --git a/code/lib/manager-api/src/version.ts b/code/lib/manager-api/src/version.ts index 277e71b47e44..156fd9c6a94a 100644 --- a/code/lib/manager-api/src/version.ts +++ b/code/lib/manager-api/src/version.ts @@ -1 +1 @@ -export const version = '8.0.0-rc.0'; +export const version = '8.0.0-rc.1'; diff --git a/code/lib/node-logger/package.json b/code/lib/node-logger/package.json index 53221fcadf30..12672e9c0278 100644 --- a/code/lib/node-logger/package.json +++ b/code/lib/node-logger/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/node-logger", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "", "keywords": [ "storybook" diff --git a/code/lib/preview-api/package.json b/code/lib/preview-api/package.json index 2ce58b60d381..75d64c9a87b8 100644 --- a/code/lib/preview-api/package.json +++ b/code/lib/preview-api/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preview-api", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "", "keywords": [ "storybook" diff --git a/code/lib/preview/package.json b/code/lib/preview/package.json index 46e5268ce14d..cea251ed2dad 100644 --- a/code/lib/preview/package.json +++ b/code/lib/preview/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preview", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "", "keywords": [ "storybook" diff --git a/code/lib/react-dom-shim/package.json b/code/lib/react-dom-shim/package.json index b52b16c6676c..417322b679f2 100644 --- a/code/lib/react-dom-shim/package.json +++ b/code/lib/react-dom-shim/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/react-dom-shim", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "", "keywords": [ "storybook" diff --git a/code/lib/router/package.json b/code/lib/router/package.json index f36dbb2ea0cf..28bc6525c2d2 100644 --- a/code/lib/router/package.json +++ b/code/lib/router/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/router", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Core Storybook Router", "keywords": [ "storybook" diff --git a/code/lib/source-loader/package.json b/code/lib/source-loader/package.json index 79599a15b4ef..634c33cf3d8c 100644 --- a/code/lib/source-loader/package.json +++ b/code/lib/source-loader/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/source-loader", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Source loader", "keywords": [ "lib", diff --git a/code/lib/telemetry/package.json b/code/lib/telemetry/package.json index 0aa31581984d..bacd55a2207c 100644 --- a/code/lib/telemetry/package.json +++ b/code/lib/telemetry/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/telemetry", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Telemetry logging for crash reports and usage statistics", "keywords": [ "storybook" diff --git a/code/lib/test/package.json b/code/lib/test/package.json index e458d9df8022..5258ec216e55 100644 --- a/code/lib/test/package.json +++ b/code/lib/test/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/test", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "", "keywords": [ "storybook" diff --git a/code/lib/theming/package.json b/code/lib/theming/package.json index 6d35da27de96..dc6f964b604e 100644 --- a/code/lib/theming/package.json +++ b/code/lib/theming/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/theming", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Core Storybook Components", "keywords": [ "storybook" diff --git a/code/lib/types/package.json b/code/lib/types/package.json index d3b9a9685708..96f6089b73dc 100644 --- a/code/lib/types/package.json +++ b/code/lib/types/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/types", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Core Storybook TS Types", "keywords": [ "storybook" diff --git a/code/package.json b/code/package.json index 3f0d826438ec..a1e4e3953e1e 100644 --- a/code/package.json +++ b/code/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/root", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "private": true, "description": "Storybook root", "homepage": "https://storybook.js.org/", @@ -294,6 +294,5 @@ "Dependency Upgrades" ] ] - }, - "deferredNextVersion": "8.0.0-rc.1" + } } diff --git a/code/presets/create-react-app/package.json b/code/presets/create-react-app/package.json index 7f5a708d578a..5275fade6100 100644 --- a/code/presets/create-react-app/package.json +++ b/code/presets/create-react-app/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preset-create-react-app", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Storybook for Create React App preset", "keywords": [ "storybook" diff --git a/code/presets/html-webpack/package.json b/code/presets/html-webpack/package.json index 4ec37f3917a5..c85346ee246a 100644 --- a/code/presets/html-webpack/package.json +++ b/code/presets/html-webpack/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preset-html-webpack", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Storybook for HTML: View HTML snippets in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/presets/preact-webpack/package.json b/code/presets/preact-webpack/package.json index a55d8938b8d7..0edddb4d473d 100644 --- a/code/presets/preact-webpack/package.json +++ b/code/presets/preact-webpack/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preset-preact-webpack", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Storybook for Preact: Develop Preact Component in isolation.", "keywords": [ "storybook" diff --git a/code/presets/react-webpack/package.json b/code/presets/react-webpack/package.json index 8654c9934571..bb7d68782f68 100644 --- a/code/presets/react-webpack/package.json +++ b/code/presets/react-webpack/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preset-react-webpack", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Storybook for React: Develop React Component in isolation with Hot Reloading", "keywords": [ "storybook" diff --git a/code/presets/server-webpack/package.json b/code/presets/server-webpack/package.json index e4156c9429ec..0c57f088153d 100644 --- a/code/presets/server-webpack/package.json +++ b/code/presets/server-webpack/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preset-server-webpack", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Storybook for Server: View HTML snippets from a server in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/presets/svelte-webpack/package.json b/code/presets/svelte-webpack/package.json index 0a60ecd47035..8e174bae7e10 100644 --- a/code/presets/svelte-webpack/package.json +++ b/code/presets/svelte-webpack/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preset-svelte-webpack", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Storybook for Svelte: Develop Svelte Component in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/presets/vue3-webpack/package.json b/code/presets/vue3-webpack/package.json index 2b68be009e5a..774e7247eafb 100644 --- a/code/presets/vue3-webpack/package.json +++ b/code/presets/vue3-webpack/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preset-vue3-webpack", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Storybook for Vue 3: Develop Vue 3 Components in isolation with Hot Reloading.", "keywords": [ "storybook" diff --git a/code/renderers/html/package.json b/code/renderers/html/package.json index fe260db27f71..ce6c017145aa 100644 --- a/code/renderers/html/package.json +++ b/code/renderers/html/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/html", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Storybook HTML renderer", "keywords": [ "storybook" diff --git a/code/renderers/preact/package.json b/code/renderers/preact/package.json index 4f6664fe7cc8..685eb8e50aaa 100644 --- a/code/renderers/preact/package.json +++ b/code/renderers/preact/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/preact", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Storybook Preact renderer", "keywords": [ "storybook" diff --git a/code/renderers/react/package.json b/code/renderers/react/package.json index 34f768ba1096..de60e151b77c 100644 --- a/code/renderers/react/package.json +++ b/code/renderers/react/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/react", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Storybook React renderer", "keywords": [ "storybook" diff --git a/code/renderers/server/package.json b/code/renderers/server/package.json index 8981a651a312..f4c892e2a87a 100644 --- a/code/renderers/server/package.json +++ b/code/renderers/server/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/server", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Storybook Server renderer", "keywords": [ "storybook" diff --git a/code/renderers/svelte/package.json b/code/renderers/svelte/package.json index 70c43a4169e2..abe9ca50ab14 100644 --- a/code/renderers/svelte/package.json +++ b/code/renderers/svelte/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/svelte", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Storybook Svelte renderer", "keywords": [ "storybook" diff --git a/code/renderers/vue3/package.json b/code/renderers/vue3/package.json index 1db67d97fcb5..ec3d8037453a 100644 --- a/code/renderers/vue3/package.json +++ b/code/renderers/vue3/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/vue3", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Storybook Vue 3 renderer", "keywords": [ "storybook" diff --git a/code/renderers/web-components/package.json b/code/renderers/web-components/package.json index 85bddd3cd0e5..fcd133473b18 100644 --- a/code/renderers/web-components/package.json +++ b/code/renderers/web-components/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/web-components", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Storybook web-components renderer", "keywords": [ "lit", diff --git a/code/ui/blocks/package.json b/code/ui/blocks/package.json index 55d5532341db..c48cbadc893a 100644 --- a/code/ui/blocks/package.json +++ b/code/ui/blocks/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/blocks", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Storybook Doc Blocks", "keywords": [ "storybook" diff --git a/code/ui/components/package.json b/code/ui/components/package.json index 17d3cc5c2519..248ed68c73c5 100644 --- a/code/ui/components/package.json +++ b/code/ui/components/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/components", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Core Storybook Components", "keywords": [ "storybook" diff --git a/code/ui/manager/package.json b/code/ui/manager/package.json index 5d95ba8af64e..b13135e4eb4f 100644 --- a/code/ui/manager/package.json +++ b/code/ui/manager/package.json @@ -1,6 +1,6 @@ { "name": "@storybook/manager", - "version": "8.0.0-rc.0", + "version": "8.0.0-rc.1", "description": "Core Storybook UI", "keywords": [ "storybook" From 3f766bf200005ac60fee8d3fc7bf017772bf3792 Mon Sep 17 00:00:00 2001 From: 43081j <43081j@users.noreply.github.com> Date: Sat, 2 Mar 2024 12:40:01 +0000 Subject: [PATCH 55/77] chore: upgrade recast This updates recast (patch version) to pull in a recent update which trims down the dependency tree/footprint. --- code/lib/codemod/package.json | 2 +- code/lib/csf-tools/package.json | 2 +- code/yarn.lock | 24 ++++++++++++++++-- scripts/package.json | 2 +- scripts/yarn.lock | 44 +++++++++++---------------------- 5 files changed, 39 insertions(+), 35 deletions(-) diff --git a/code/lib/codemod/package.json b/code/lib/codemod/package.json index 0e4154e0db74..cdb05de5da4d 100644 --- a/code/lib/codemod/package.json +++ b/code/lib/codemod/package.json @@ -67,7 +67,7 @@ "jscodeshift": "^0.15.1", "lodash": "^4.17.21", "prettier": "^3.1.1", - "recast": "^0.23.1", + "recast": "^0.23.5", "tiny-invariant": "^1.3.1" }, "devDependencies": { diff --git a/code/lib/csf-tools/package.json b/code/lib/csf-tools/package.json index 5a32a79f9453..9004d3e3beae 100644 --- a/code/lib/csf-tools/package.json +++ b/code/lib/csf-tools/package.json @@ -49,7 +49,7 @@ "@storybook/csf": "^0.1.2", "@storybook/types": "workspace:*", "fs-extra": "^11.1.0", - "recast": "^0.23.1", + "recast": "^0.23.5", "ts-dedent": "^2.0.0" }, "devDependencies": { diff --git a/code/yarn.lock b/code/yarn.lock index 039c28a0c940..b5e38b978738 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -5671,7 +5671,7 @@ __metadata: mdast-util-mdx-jsx: "npm:^3.0.0" mdast-util-mdxjs-esm: "npm:^2.0.1" prettier: "npm:^3.1.1" - recast: "npm:^0.23.1" + recast: "npm:^0.23.5" remark: "npm:^15.0.1" remark-mdx: "npm:^3.0.0" tiny-invariant: "npm:^1.3.1" @@ -5872,7 +5872,7 @@ __metadata: "@types/js-yaml": "npm:^4.0.5" fs-extra: "npm:^11.1.0" js-yaml: "npm:^4.1.0" - recast: "npm:^0.23.1" + recast: "npm:^0.23.5" ts-dedent: "npm:^2.0.0" typescript: "npm:^5.3.2" languageName: unknown @@ -24989,6 +24989,19 @@ __metadata: languageName: node linkType: hard +"recast@npm:^0.23.5": + version: 0.23.5 + resolution: "recast@npm:0.23.5" + dependencies: + ast-types: "npm:^0.16.1" + esprima: "npm:~4.0.0" + source-map: "npm:~0.6.1" + tiny-invariant: "npm:^1.3.3" + tslib: "npm:^2.0.1" + checksum: 21dc93910d12c71da77072afc3d5d4cdf97783776842efa6fd2cd7c2798d3622ace5d2f05ca5133141ef93de8a0512cbe191fe835f325bd1722f186fe449d11a + languageName: node + linkType: hard + "redent@npm:^3.0.0": version: 3.0.0 resolution: "redent@npm:3.0.0" @@ -28020,6 +28033,13 @@ __metadata: languageName: node linkType: hard +"tiny-invariant@npm:^1.3.3": + version: 1.3.3 + resolution: "tiny-invariant@npm:1.3.3" + checksum: 65af4a07324b591a059b35269cd696aba21bef2107f29b9f5894d83cc143159a204b299553435b03874ebb5b94d019afa8b8eff241c8a4cfee95872c2e1c1c4a + languageName: node + linkType: hard + "tiny-warning@npm:^1.0.2": version: 1.0.3 resolution: "tiny-warning@npm:1.0.3" diff --git a/scripts/package.json b/scripts/package.json index 52d2013ec288..af4682a9ccd9 100644 --- a/scripts/package.json +++ b/scripts/package.json @@ -160,7 +160,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "read-pkg-up": "^7.0.1", - "recast": "^0.23.1", + "recast": "^0.23.5", "remark": "^14.0.3", "remark-cli": "^12.0.0", "remark-lint": "^9.1.2", diff --git a/scripts/yarn.lock b/scripts/yarn.lock index fd8ab47be372..c87d27c84be7 100644 --- a/scripts/yarn.lock +++ b/scripts/yarn.lock @@ -2800,7 +2800,7 @@ __metadata: react: "npm:^18.2.0" react-dom: "npm:^18.2.0" read-pkg-up: "npm:^7.0.1" - recast: "npm:^0.23.1" + recast: "npm:^0.23.5" remark: "npm:^14.0.3" remark-cli: "npm:^12.0.0" remark-lint: "npm:^9.1.2" @@ -4490,19 +4490,6 @@ __metadata: languageName: node linkType: hard -"assert@npm:^2.0.0": - version: 2.1.0 - resolution: "assert@npm:2.1.0" - dependencies: - call-bind: "npm:^1.0.2" - is-nan: "npm:^1.3.2" - object-is: "npm:^1.1.5" - object.assign: "npm:^4.1.4" - util: "npm:^0.12.5" - checksum: 7271a5da883c256a1fa690677bf1dd9d6aa882139f2bed1cd15da4f9e7459683e1da8e32a203d6cc6767e5e0f730c77a9532a87b896b4b0af0dd535f668775f0 - languageName: node - linkType: hard - "assertion-error@npm:^1.1.0": version: 1.1.0 resolution: "assertion-error@npm:1.1.0" @@ -8943,16 +8930,6 @@ __metadata: languageName: node linkType: hard -"is-nan@npm:^1.3.2": - version: 1.3.2 - resolution: "is-nan@npm:1.3.2" - dependencies: - call-bind: "npm:^1.0.0" - define-properties: "npm:^1.1.3" - checksum: 8bfb286f85763f9c2e28ea32e9127702fe980ffd15fa5d63ade3be7786559e6e21355d3625dd364c769c033c5aedf0a2ed3d4025d336abf1b9241e3d9eddc5b0 - languageName: node - linkType: hard - "is-natural-number@npm:^4.0.1": version: 4.0.1 resolution: "is-natural-number@npm:4.0.1" @@ -12752,16 +12729,16 @@ __metadata: languageName: node linkType: hard -"recast@npm:^0.23.1": - version: 0.23.4 - resolution: "recast@npm:0.23.4" +"recast@npm:^0.23.5": + version: 0.23.5 + resolution: "recast@npm:0.23.5" dependencies: - assert: "npm:^2.0.0" ast-types: "npm:^0.16.1" esprima: "npm:~4.0.0" source-map: "npm:~0.6.1" + tiny-invariant: "npm:^1.3.3" tslib: "npm:^2.0.1" - checksum: d719633be8029e28f23b8191d4a525c5dbdac721792ab3cb5e9dfcf1694fb93f3c147b186916195a9c7fa0711f1e4990ba457cdcee02faed3899d4a80da1bd1f + checksum: 21dc93910d12c71da77072afc3d5d4cdf97783776842efa6fd2cd7c2798d3622ace5d2f05ca5133141ef93de8a0512cbe191fe835f325bd1722f186fe449d11a languageName: node linkType: hard @@ -14583,6 +14560,13 @@ __metadata: languageName: node linkType: hard +"tiny-invariant@npm:^1.3.3": + version: 1.3.3 + resolution: "tiny-invariant@npm:1.3.3" + checksum: 65af4a07324b591a059b35269cd696aba21bef2107f29b9f5894d83cc143159a204b299553435b03874ebb5b94d019afa8b8eff241c8a4cfee95872c2e1c1c4a + languageName: node + linkType: hard + "tinybench@npm:^2.5.1": version: 2.5.1 resolution: "tinybench@npm:2.5.1" @@ -15437,7 +15421,7 @@ __metadata: languageName: node linkType: hard -"util@npm:^0.12.4, util@npm:^0.12.5": +"util@npm:^0.12.4": version: 0.12.5 resolution: "util@npm:0.12.5" dependencies: From bb8590c9b7d59cfd047be62632eb8e20ca299a9e Mon Sep 17 00:00:00 2001 From: Valentin Palkovic Date: Fri, 1 Mar 2024 14:48:19 +0100 Subject: [PATCH 56/77] Add type-safetyness to Fix type --- code/lib/cli/src/automigrate/types.ts | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/code/lib/cli/src/automigrate/types.ts b/code/lib/cli/src/automigrate/types.ts index 36b4bac18c47..d8cc9f06af3e 100644 --- a/code/lib/cli/src/automigrate/types.ts +++ b/code/lib/cli/src/automigrate/types.ts @@ -27,9 +27,8 @@ export interface RunOptions { */ export type Prompt = 'auto' | 'manual' | 'notification'; -export interface Fix { +type BaseFix = { id: string; - promptType?: Prompt | ((result: ResultType) => Promise | Prompt); /** * The from/to version range of Storybook that this fix applies to. The strings are semver ranges. * The versionRange will only be checked if the automigration is part of an upgrade. @@ -38,8 +37,23 @@ export interface Fix { versionRange: [from: string, to: string]; check: (options: CheckOptions) => Promise; prompt: (result: ResultType) => string; - run?: (options: RunOptions) => Promise; -} +}; + +type PromptType = + | T + | ((result: ResultType) => Promise | Prompt); + +export type Fix = ( + | { + promptType?: PromptType; + run: (options: RunOptions) => Promise; + } + | { + promptType: PromptType; + run?: never; + } +) & + BaseFix; export type FixId = string; From fbbf22d5945301d54bf7500e9a685805dd4367b8 Mon Sep 17 00:00:00 2001 From: Valentin Palkovic Date: Mon, 4 Mar 2024 09:16:41 +0100 Subject: [PATCH 57/77] Add missing isUpgrade parameter to automigrate function --- code/lib/cli/src/automigrate/index.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/lib/cli/src/automigrate/index.ts b/code/lib/cli/src/automigrate/index.ts index b0864a7071c6..8a84476b5e93 100644 --- a/code/lib/cli/src/automigrate/index.ts +++ b/code/lib/cli/src/automigrate/index.ts @@ -111,6 +111,7 @@ export const automigrate = async ({ renderer: rendererPackage, skipInstall, hideMigrationSummary = false, + isUpgrade, }: AutofixOptions): Promise<{ fixResults: Record; preCheckFailure?: PreCheckFailure; @@ -142,6 +143,7 @@ export const automigrate = async ({ mainConfigPath, storybookVersion, beforeVersion, + isUpgrade, dryRun, yes, }); From 9f0bc7db7e57b830f21311a2b7ea97ff56a476e7 Mon Sep 17 00:00:00 2001 From: Valentin Palkovic Date: Mon, 4 Mar 2024 10:29:57 +0100 Subject: [PATCH 58/77] Add @storybook/addons automigration --- .../src/automigrate/fixes/addon-postcss.ts | 2 +- .../src/automigrate/fixes/addons-api.test.ts | 44 ++++++++++++++++++ .../cli/src/automigrate/fixes/addons-api.ts | 45 +++++++++++++++++++ code/lib/cli/src/automigrate/fixes/index.ts | 2 + 4 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 code/lib/cli/src/automigrate/fixes/addons-api.test.ts create mode 100644 code/lib/cli/src/automigrate/fixes/addons-api.ts diff --git a/code/lib/cli/src/automigrate/fixes/addon-postcss.ts b/code/lib/cli/src/automigrate/fixes/addon-postcss.ts index 7978e545a1c5..f8d134183c0b 100644 --- a/code/lib/cli/src/automigrate/fixes/addon-postcss.ts +++ b/code/lib/cli/src/automigrate/fixes/addon-postcss.ts @@ -29,7 +29,7 @@ export const addonPostCSS: Fix = { return dedent` ${chalk.bold( 'Attention' - )}: We've detected that you're using the following package which are incompatible with Storybook 8 and beyond: + )}: We've detected that you're using the following package which is incompatible with Storybook 8 and beyond: - ${chalk.cyan(`@storybook/addon-postcss`)} diff --git a/code/lib/cli/src/automigrate/fixes/addons-api.test.ts b/code/lib/cli/src/automigrate/fixes/addons-api.test.ts new file mode 100644 index 000000000000..2bae14386d3b --- /dev/null +++ b/code/lib/cli/src/automigrate/fixes/addons-api.test.ts @@ -0,0 +1,44 @@ +import { addonsAPI } from './addons-api'; +import type { StorybookConfig } from '@storybook/types'; +import type { JsPackageManager } from '@storybook/core-common'; +import { expect, describe, it } from 'vitest'; + +const checkAddonsAPI = async ({ + packageManager, + mainConfig = {}, + storybookVersion = '7.0.0', +}: { + packageManager?: Partial; + mainConfig?: Partial; + storybookVersion?: string; +}) => { + return addonsAPI.check({ + packageManager: packageManager as any, + storybookVersion, + mainConfig: mainConfig as any, + }); +}; + +describe('check function', () => { + it('should return { usesAddonsAPI: true } if @storybook/addons is installed', async () => { + await expect( + checkAddonsAPI({ + packageManager: { + getAllDependencies: async () => ({ + '@storybook/addons': '6.0.0', + }), + }, + }) + ).resolves.toEqual({ usesAddonsAPI: true }); + }); + + it('should return null if @storybook/addons is not installed', async () => { + await expect( + checkAddonsAPI({ + packageManager: { + getAllDependencies: async () => ({}), + }, + }) + ).resolves.toBeNull(); + }); +}); diff --git a/code/lib/cli/src/automigrate/fixes/addons-api.ts b/code/lib/cli/src/automigrate/fixes/addons-api.ts new file mode 100644 index 000000000000..f193898aa82f --- /dev/null +++ b/code/lib/cli/src/automigrate/fixes/addons-api.ts @@ -0,0 +1,45 @@ +import chalk from 'chalk'; +import { dedent } from 'ts-dedent'; +import type { Fix } from '../types'; + +interface AddonsAPIRunOptions { + usesAddonsAPI: boolean; +} + +export const addonsAPI: Fix = { + id: 'addons-api', + + versionRange: ['<8', '>=8'], + + promptType: 'notification', + + async check({ packageManager }) { + const allDependencies = await packageManager.getAllDependencies(); + const usesAddonsAPI = !!allDependencies['@storybook/addons']; + + if (!usesAddonsAPI) { + return null; + } + + return { usesAddonsAPI: true }; + }, + + prompt() { + return dedent` + ${chalk.bold( + 'Attention' + )}: We've detected that you're using the following package which is removed in Storybook 8 and beyond: + + - ${chalk.cyan(`@storybook/addons`)} + + This package has been deprecated and replaced with ${chalk.cyan( + `@storybook/preview-api` + )} and ${chalk.cyan(`@storybook/manager-api`)}. + + You can find more information about the new addons API in the migration guide: + ${chalk.yellow( + 'https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#new-addons-api' + )} + `; + }, +}; diff --git a/code/lib/cli/src/automigrate/fixes/index.ts b/code/lib/cli/src/automigrate/fixes/index.ts index 91ba9a27927f..17b3d4942be1 100644 --- a/code/lib/cli/src/automigrate/fixes/index.ts +++ b/code/lib/cli/src/automigrate/fixes/index.ts @@ -23,12 +23,14 @@ import { storyshotsMigration } from './storyshots-migration'; import { removeArgtypesRegex } from './remove-argtypes-regex'; import { webpack5CompilerSetup } from './webpack5-compiler-setup'; import { removeJestTestingLibrary } from './remove-jest-testing-library'; +import { addonsAPI } from './addons-api'; import { mdx1to3 } from './mdx-1-to-3'; import { addonPostCSS } from './addon-postcss'; export * from '../types'; export const allFixes: Fix[] = [ + addonsAPI, newFrameworks, cra5, webpack5, From eb28dad8d0506e1ef73c109ea4eef636f781d936 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Thu, 29 Feb 2024 11:00:53 +0100 Subject: [PATCH 59/77] Portable stories: Make canvasElement optional in the play function --- MIGRATION.md | 76 +++++++++--- code/lib/preview-api/src/index.ts | 1 + .../store/csf/portable-stories.test.ts | 65 ++++++---- .../src/modules/store/csf/portable-stories.ts | 102 ++++++++++++---- code/lib/types/src/modules/composedStory.ts | 30 ++--- .../portable-stories.test.tsx.snap | 115 ++++++++++++------ .../src/__test__/portable-stories.test.tsx | 15 ++- ...rtable-stories.ts => portable-stories.tsx} | 11 ++ .../portable-stories.test.ts.snap | 106 ++++++++++------ .../composeStories/portable-stories.test.ts | 4 +- code/renderers/vue3/src/portable-stories.ts | 17 ++- 11 files changed, 378 insertions(+), 164 deletions(-) rename code/renderers/react/src/{portable-stories.ts => portable-stories.tsx} (94%) diff --git a/MIGRATION.md b/MIGRATION.md index 202962c2cf7f..c51ddba6347e 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -1,7 +1,9 @@

Migration

- [From version 7.x to 8.0.0](#from-version-7x-to-800) - - [Type change in `composeStories` API](#type-change-in-composestories-api) + - [Portable stories](#portable-stories) + - [Type change in `composeStories` API](#type-change-in-composestories-api) + - [The context in the play function is now optional](#the-context-in-the-play-function-is-now-optional) - [Tab addons are now routed to a query parameter](#tab-addons-are-now-routed-to-a-query-parameter) - [Default keyboard shortcuts changed](#default-keyboard-shortcuts-changed) - [Manager addons are now rendered with React 18](#manager-addons-are-now-rendered-with-react-18) @@ -86,17 +88,17 @@ - [Tab addons cannot manually route, Tool addons can filter their visibility via tabId](#tab-addons-cannot-manually-route-tool-addons-can-filter-their-visibility-via-tabid) - [Removed `config` preset](#removed-config-preset-1) - [From version 7.5.0 to 7.6.0](#from-version-750-to-760) - - [CommonJS with Vite is deprecated](#commonjs-with-vite-is-deprecated) - - [Using implicit actions during rendering is deprecated](#using-implicit-actions-during-rendering-is-deprecated) - - [typescript.skipBabel deprecated](#typescriptskipbabel-deprecated) - - [Primary doc block accepts of prop](#primary-doc-block-accepts-of-prop) - - [Addons no longer need a peer dependency on React](#addons-no-longer-need-a-peer-dependency-on-react) + - [CommonJS with Vite is deprecated](#commonjs-with-vite-is-deprecated) + - [Using implicit actions during rendering is deprecated](#using-implicit-actions-during-rendering-is-deprecated) + - [typescript.skipBabel deprecated](#typescriptskipbabel-deprecated) + - [Primary doc block accepts of prop](#primary-doc-block-accepts-of-prop) + - [Addons no longer need a peer dependency on React](#addons-no-longer-need-a-peer-dependency-on-react) - [From version 7.4.0 to 7.5.0](#from-version-740-to-750) - - [`storyStoreV6` and `storiesOf` is deprecated](#storystorev6-and-storiesof-is-deprecated) - - [`storyIndexers` is replaced with `experimental_indexers`](#storyindexers-is-replaced-with-experimental_indexers) + - [`storyStoreV6` and `storiesOf` is deprecated](#storystorev6-and-storiesof-is-deprecated) + - [`storyIndexers` is replaced with `experimental_indexers`](#storyindexers-is-replaced-with-experimental_indexers) - [From version 7.0.0 to 7.2.0](#from-version-700-to-720) - - [Addon API is more type-strict](#addon-api-is-more-type-strict) - - [Addon-controls hideNoControlsWarning parameter is deprecated](#addon-controls-hidenocontrolswarning-parameter-is-deprecated) + - [Addon API is more type-strict](#addon-api-is-more-type-strict) + - [Addon-controls hideNoControlsWarning parameter is deprecated](#addon-controls-hidenocontrolswarning-parameter-is-deprecated) - [From version 6.5.x to 7.0.0](#from-version-65x-to-700) - [7.0 breaking changes](#70-breaking-changes) - [Dropped support for Node 15 and below](#dropped-support-for-node-15-and-below) @@ -122,7 +124,7 @@ - [Deploying build artifacts](#deploying-build-artifacts) - [Dropped support for file URLs](#dropped-support-for-file-urls) - [Serving with nginx](#serving-with-nginx) - - [Ignore story files from node\_modules](#ignore-story-files-from-node_modules) + - [Ignore story files from node_modules](#ignore-story-files-from-node_modules) - [7.0 Core changes](#70-core-changes) - [7.0 feature flags removed](#70-feature-flags-removed) - [Story context is prepared before for supporting fine grained updates](#story-context-is-prepared-before-for-supporting-fine-grained-updates) @@ -136,7 +138,7 @@ - [Addon-interactions: Interactions debugger is now default](#addon-interactions-interactions-debugger-is-now-default) - [7.0 Vite changes](#70-vite-changes) - [Vite builder uses Vite config automatically](#vite-builder-uses-vite-config-automatically) - - [Vite cache moved to node\_modules/.cache/.vite-storybook](#vite-cache-moved-to-node_modulescachevite-storybook) + - [Vite cache moved to node_modules/.cache/.vite-storybook](#vite-cache-moved-to-node_modulescachevite-storybook) - [7.0 Webpack changes](#70-webpack-changes) - [Webpack4 support discontinued](#webpack4-support-discontinued) - [Babel mode v7 exclusively](#babel-mode-v7-exclusively) @@ -186,7 +188,7 @@ - [Dropped addon-docs manual babel configuration](#dropped-addon-docs-manual-babel-configuration) - [Dropped addon-docs manual configuration](#dropped-addon-docs-manual-configuration) - [Autoplay in docs](#autoplay-in-docs) - - [Removed STORYBOOK\_REACT\_CLASSES global](#removed-storybook_react_classes-global) + - [Removed STORYBOOK_REACT_CLASSES global](#removed-storybook_react_classes-global) - [7.0 Deprecations and default changes](#70-deprecations-and-default-changes) - [storyStoreV7 enabled by default](#storystorev7-enabled-by-default) - [`Story` type deprecated](#story-type-deprecated) @@ -401,7 +403,9 @@ ## From version 7.x to 8.0.0 -### Type change in `composeStories` API +### Portable stories + +#### Type change in `composeStories` API There is a TypeScript type change in the `play` function returned from `composeStories` or `composeStory` in `@storybook/react` or `@storybook/vue3`, where before it was always defined, now it is potentially undefined. This means that you might have to make a small change in your code, such as: @@ -418,6 +422,49 @@ await Primary.play!(...) // if you want a runtime error when the play function d There are plans to make the type of the play function be inferred based on your imported story's play function in a near future, so the types will be 100% accurate. +#### The context in the play function is now optional + +When reusing a story that has a play function, you don't have to pass the context anymore, not even the `canvasElement`. The context is built-in and if you don't pass overrides, it will still be present. It is still possible to pass overrides to the context, if you'd like. + +```tsx +const { Primary } = composeStories(stories); +test("load and render", async () => { + const { container } = render(); + // before: + await Primary.play({ canvasElement: container, ...ArgsOrWhateverElse }); + + // after: + await Primary.play(); +}); +``` + +In order for this to be possible, the portable stories API now adds a wrapper to your stories with a unique id based on your story id, such as: + +```html +
+ +
+``` + +This means that if you take DOM snapshots of your stories, they will be affected and you will have to update them. + +The id calculation is based on different heuristics based on your Meta title and Story name. When using `composeStories`, the id can be inferred automatically. However, when using `composeStory` and your story does not explicitly have a `storyName` property, the story name can't be inferred automatically. As a result, its name will be "Unnamed Story", resulting in a wrapper id like `"#storybook-story-button--unnamed-story"`. If the id matters to you and you want to fix it, you have to specify the `exportsName` property like so: + +```ts +test("snapshots the story with custom id", () => { + const Primary = composeStory( + stories.Primary, + stories.default, + undefined, + // If you do not want the `unnamed-story` id, you have to pass the name of the story as a parameter + "Primary" + ); + + const { baseElement } = render(); + expect(baseElement).toMatchSnapshot(); +}); +``` + ### Tab addons are now routed to a query parameter The URL of a tab used to be: `http://localhost:6006/?path=/my-addon-tab/my-story`. @@ -556,7 +603,6 @@ This means https://github.com/IanVS/vite-plugin-turbosnap is no longer necessary Now that both Vite and Webpack support the `preview-stats.json` file, the flag has been renamed. The old flag will continue to work. - ### Implicit actions can not be used during rendering (for example in the play function) In Storybook 7, we inferred if the component accepts any action props, diff --git a/code/lib/preview-api/src/index.ts b/code/lib/preview-api/src/index.ts index e47cdaa0a0dd..63d45114dc23 100644 --- a/code/lib/preview-api/src/index.ts +++ b/code/lib/preview-api/src/index.ts @@ -56,6 +56,7 @@ export { filterArgTypes, sanitizeStoryContextUpdate, setProjectAnnotations, + getPortableStoryWrapperId, inferControls, userOrAutoTitleFromSpecifier, userOrAutoTitle, diff --git a/code/lib/preview-api/src/modules/store/csf/portable-stories.test.ts b/code/lib/preview-api/src/modules/store/csf/portable-stories.test.ts index af775f27360b..54e82553757f 100644 --- a/code/lib/preview-api/src/modules/store/csf/portable-stories.test.ts +++ b/code/lib/preview-api/src/modules/store/csf/portable-stories.test.ts @@ -1,10 +1,18 @@ // @vitest-environment node import { describe, expect, vi, it } from 'vitest'; -import { composeStory, composeStories } from './portable-stories'; +import type { + ComponentAnnotations as Meta, + StoryAnnotationsOrFn as Story, + Store_CSFExports, +} from '@storybook/types'; + +import { composeStory, composeStories, setProjectAnnotations } from './portable-stories'; + +type StoriesModule = Store_CSFExports & Record; // Most integration tests for this functionality are located under renderers/react describe('composeStory', () => { - const meta = { + const meta: Meta = { title: 'Button', parameters: { firstAddon: true, @@ -15,13 +23,26 @@ describe('composeStory', () => { }, }; - it('should return story with composed args and parameters', () => { - const Story = () => {}; - Story.args = { primary: true }; - Story.parameters = { + it('should return story with composed annotations from story, meta and project', () => { + const decoratorFromProjectAnnotations = vi.fn((StoryFn) => StoryFn()); + const decoratorFromStoryAnnotations = vi.fn((StoryFn) => StoryFn()); + setProjectAnnotations([ + { + parameters: { injected: true }, + globalTypes: { + locale: { defaultValue: 'en' }, + }, + decorators: [decoratorFromProjectAnnotations], + }, + ]); + + const Story: Story = { + render: () => {}, + args: { primary: true }, parameters: { secondAddon: true, }, + decorators: [decoratorFromStoryAnnotations], }; const composedStory = composeStory(Story, meta); @@ -29,28 +50,22 @@ describe('composeStory', () => { expect(composedStory.parameters).toEqual( expect.objectContaining({ ...Story.parameters, ...meta.parameters }) ); + + composedStory(); + + expect(decoratorFromProjectAnnotations).toHaveBeenCalled(); + expect(decoratorFromStoryAnnotations).toHaveBeenCalled(); }); it('should compose with a play function', async () => { const spy = vi.fn(); - const Story = () => {}; + const Story: Story = () => {}; Story.args = { primary: true, }; Story.play = async (context: any) => { spy(context); }; - - const composedStory = composeStory(Story, meta); - await composedStory.play!({ canvasElement: null }); - expect(spy).toHaveBeenCalledWith( - expect.objectContaining({ - args: { - ...Story.args, - ...meta.args, - }, - }) - ); }); it('should throw an error if Story is undefined', () => { @@ -62,7 +77,7 @@ describe('composeStory', () => { describe('Id of the story', () => { it('is exposed correctly when composeStories is used', () => { - const module = { + const module: StoriesModule = { default: { title: 'Example/Button', }, @@ -72,7 +87,7 @@ describe('composeStory', () => { expect(Primary.id).toBe('example-button--csf-3-primary'); }); it('is exposed correctly when composeStory is used and exportsName is passed', () => { - const module = { + const module: StoriesModule = { default: { title: 'Example/Button', }, @@ -83,7 +98,7 @@ describe('composeStory', () => { }); it("is not unique when composeStory is used and exportsName isn't passed", () => { const Primary = composeStory({ render: () => {} }, {}); - expect(Primary.id).toContain('unknown'); + expect(Primary.id).toContain('composedstory--unnamed-story'); }); }); }); @@ -93,7 +108,7 @@ describe('composeStories', () => { const defaultAnnotations = { render: () => '' }; it('should call composeStoryFn with stories', () => { const composeStorySpy = vi.fn((v) => v); - const module = { + const module: StoriesModule = { default: { title: 'Button', }, @@ -118,7 +133,7 @@ describe('composeStories', () => { it('should not call composeStoryFn for non-story exports', () => { const composeStorySpy = vi.fn((v) => v); - const module = { + const module: StoriesModule = { default: { title: 'Button', excludeStories: /Data/, @@ -131,7 +146,7 @@ describe('composeStories', () => { describe('non-story exports', () => { it('should filter non-story exports with excludeStories', () => { - const StoryModuleWithNonStoryExports = { + const StoryModuleWithNonStoryExports: StoriesModule = { default: { title: 'Some/Component', excludeStories: /.*Data/, @@ -149,7 +164,7 @@ describe('composeStories', () => { }); it('should filter non-story exports with includeStories', () => { - const StoryModuleWithNonStoryExports = { + const StoryModuleWithNonStoryExports: StoriesModule = { default: { title: 'Some/Component', includeStories: /.*Story/, diff --git a/code/lib/preview-api/src/modules/store/csf/portable-stories.ts b/code/lib/preview-api/src/modules/store/csf/portable-stories.ts index 91e4cdc365e1..6f24b2933cdf 100644 --- a/code/lib/preview-api/src/modules/store/csf/portable-stories.ts +++ b/code/lib/preview-api/src/modules/store/csf/portable-stories.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/naming-convention */ import { isExportStory } from '@storybook/csf'; import type { Renderer, @@ -12,7 +13,7 @@ import type { Parameters, ComposedStoryFn, StrictArgTypes, - ComposedStoryPlayContext, + PlayFunctionContext, } from '@storybook/types'; import { HooksContext } from '../../../addons'; @@ -22,9 +23,14 @@ import { normalizeStory } from './normalizeStory'; import { normalizeComponentAnnotations } from './normalizeComponentAnnotations'; import { getValuesFromArgTypes } from './getValuesFromArgTypes'; import { normalizeProjectAnnotations } from './normalizeProjectAnnotations'; +import { normalizeArrays } from './normalizeArrays'; let GLOBAL_STORYBOOK_PROJECT_ANNOTATIONS = composeConfigs([]); +export function getPortableStoryWrapperId(storyId: string) { + return `storybook-story-${storyId}`; +} + export function setProjectAnnotations( projectAnnotations: ProjectAnnotations | ProjectAnnotations[] ) { @@ -32,6 +38,46 @@ export function setProjectAnnotations( GLOBAL_STORYBOOK_PROJECT_ANNOTATIONS = composeConfigs(annotations); } +// TODO: we don't have any utility that merges two sets of annotations (e.g. two project annotations) +// this should be elsewhere, probably reused +function mergeAnnotations( + firstAnnotations: ProjectAnnotations, + secondAnnotations: ProjectAnnotations +) { + return { + ...firstAnnotations, + ...secondAnnotations, + args: { + ...firstAnnotations.args, + ...secondAnnotations.args, + }, + argTypes: { + ...firstAnnotations.argTypes, + ...secondAnnotations.argTypes, + }, + parameters: { + ...firstAnnotations.parameters, + ...secondAnnotations.parameters, + }, + decorators: [ + ...normalizeArrays(firstAnnotations.decorators), + ...normalizeArrays(secondAnnotations.decorators), + ], + loaders: [ + ...normalizeArrays(firstAnnotations.loaders), + ...normalizeArrays(secondAnnotations.loaders), + ], + argsEnhancers: [ + ...normalizeArrays(firstAnnotations.argsEnhancers), + ...normalizeArrays(secondAnnotations.argsEnhancers), + ], + argTypesEnhancers: [ + ...normalizeArrays(firstAnnotations.argTypesEnhancers), + ...normalizeArrays(secondAnnotations.argTypesEnhancers), + ], + }; +} + export function composeStory( storyAnnotations: LegacyStoryAnnotationsOrFn, componentAnnotations: ComponentAnnotations, @@ -43,6 +89,12 @@ export function composeStory; + } + // @TODO: Support auto title componentAnnotations.title = componentAnnotations.title ?? 'ComposedStory'; @@ -54,7 +106,7 @@ export function composeStory( storyName, @@ -62,10 +114,9 @@ export function composeStory({ - ...projectAnnotations, - ...defaultConfig, - }); + const normalizedProjectAnnotations = normalizeProjectAnnotations( + mergeAnnotations(projectAnnotations, defaultConfig) + ); const story = prepareStory( normalizedStory, @@ -77,7 +128,10 @@ export function composeStory = { hooks: new HooksContext(), - globals: defaultGlobals, + globals: { + ...defaultGlobals, + ...projectAnnotations.globals, + }, args: { ...story.initialArgs }, viewMode: 'story', loaded: {}, @@ -86,28 +140,35 @@ export function composeStory>) => + story.playFunction!({ + ...context, + ...extraContext, + // if canvasElement is not provided, we default to the root element, which comes from a decorator + // the decorator has to be implemented in the defaultAnnotations of each integrator of portable stories + canvasElement: + extraContext?.canvasElement ?? + globalThis.document?.getElementById(getPortableStoryWrapperId(context.id)), + }) + : undefined; + const composedStory: ComposedStoryFn> = Object.assign( - (extraArgs?: Partial) => { - const finalContext: StoryContext = { - ...context, - args: { ...context.initialArgs, ...extraArgs }, + function storyFn(extraArgs?: Partial) { + context.args = { + ...context.initialArgs, + ...extraArgs, }; - return story.unboundStoryFn(prepareContext(finalContext)); + return story.unboundStoryFn(prepareContext(context)); }, { + id: story.id, storyName, args: story.initialArgs as Partial, parameters: story.parameters as Parameters, argTypes: story.argTypes as StrictArgTypes, - id: story.id, - play: story.playFunction - ? ((async (extraContext: ComposedStoryPlayContext) => - story.playFunction!({ - ...context, - ...extraContext, - })) as unknown as ComposedStoryPlayFn>) - : undefined, + play: playFunction as ComposedStoryPlayFn | undefined, } ); @@ -119,7 +180,6 @@ export function composeStories( globalConfig: ProjectAnnotations, composeStoryFn: ComposeStoryFn ) { - // eslint-disable-next-line @typescript-eslint/naming-convention const { default: meta, __esModule, __namedExportsOrder, ...stories } = storiesImport; const composedStories = Object.entries(stories).reduce((storiesMap, [exportsName, story]) => { if (!isExportStory(exportsName, meta)) { diff --git a/code/lib/types/src/modules/composedStory.ts b/code/lib/types/src/modules/composedStory.ts index 5ce61bc678e8..b7051a699b7f 100644 --- a/code/lib/types/src/modules/composedStory.ts +++ b/code/lib/types/src/modules/composedStory.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import type { Renderer, StoryId, StrictArgTypes } from '@storybook/csf'; +import type { PlayFunction, Renderer, StoryId, StrictArgTypes } from '@storybook/csf'; import type { AnnotatedStoryFn, @@ -9,7 +9,6 @@ import type { Parameters, StoryAnnotations, StoryAnnotationsOrFn, - StoryContext, } from './csf'; import type { ProjectAnnotations } from './story'; @@ -22,23 +21,6 @@ export type Store_CSFExports) // or PrimaryButton() - * PrimaryButton.play({ canvasElement: container }) - */ -export type ComposedStoryPlayContext = Partial< - StoryContext & Pick, 'canvasElement'> ->; - -export type ComposedStoryPlayFn = ( - context: ComposedStoryPlayContext -) => Promise | void; - /** * A story function with partial args, used internally by composeStory */ @@ -48,6 +30,14 @@ export type PartialArgsStoryFn = T extends (...args: infer P) => infer R + ? (...args: { [K in keyof P]?: Partial }) => R + : never; + +export type ComposedStoryPlayFn< + TRenderer extends Renderer = Renderer, + TArgs = Args, +> = MakeAllParametersOptional>>; /** * A story that got recomposed for portable stories, containing all the necessary data to be rendered in external environments */ @@ -55,9 +45,9 @@ export type ComposedStoryFn< TRenderer extends Renderer = Renderer, TArgs = Args, > = PartialArgsStoryFn & { - play: ComposedStoryPlayFn | undefined; args: TArgs; id: StoryId; + play?: ComposedStoryPlayFn; storyName: string; parameters: Parameters; argTypes: StrictArgTypes; diff --git a/code/renderers/react/src/__test__/__snapshots__/portable-stories.test.tsx.snap b/code/renderers/react/src/__test__/__snapshots__/portable-stories.test.tsx.snap index 2b92b1d68424..3f40e5446d0b 100644 --- a/code/renderers/react/src/__test__/__snapshots__/portable-stories.test.tsx.snap +++ b/code/renderers/react/src/__test__/__snapshots__/portable-stories.test.tsx.snap @@ -3,12 +3,17 @@ exports[`Renders CSF2Secondary story 1`] = `
- + +
`; @@ -16,12 +21,17 @@ exports[`Renders CSF2Secondary story 1`] = ` exports[`Renders CSF2StoryWithLocale story 1`] = `
- + +
`; @@ -29,12 +39,17 @@ exports[`Renders CSF2StoryWithLocale story 1`] = ` exports[`Renders CSF2StoryWithParamsAndDecorator story 1`] = `
- + +
`; @@ -42,12 +57,17 @@ exports[`Renders CSF2StoryWithParamsAndDecorator story 1`] = ` exports[`Renders CSF3Button story 1`] = `
- + +
`; @@ -55,18 +75,23 @@ exports[`Renders CSF3Button story 1`] = ` exports[`Renders CSF3ButtonWithRender story 1`] = `
-
-

- I am a custom render function -

- +
+
+

+ I am a custom render function +

+ +
@@ -75,9 +100,14 @@ exports[`Renders CSF3ButtonWithRender story 1`] = ` exports[`Renders CSF3InputFieldFilled story 1`] = `
- +
+ +
`; @@ -85,12 +115,17 @@ exports[`Renders CSF3InputFieldFilled story 1`] = ` exports[`Renders CSF3Primary story 1`] = `
- + +
`; diff --git a/code/renderers/react/src/__test__/portable-stories.test.tsx b/code/renderers/react/src/__test__/portable-stories.test.tsx index afa0b70142e4..f137424fff0b 100644 --- a/code/renderers/react/src/__test__/portable-stories.test.tsx +++ b/code/renderers/react/src/__test__/portable-stories.test.tsx @@ -58,7 +58,7 @@ describe('projectAnnotations', () => { expect(buttonElement).not.toBeNull(); }); - it('renders with custom projectAnnotations via composeStory params', () => { + it('renders with custom globals from projectAnnotations via composeStory params', () => { const WithPortugueseText = composeStory(stories.CSF2StoryWithLocale, stories.default, { globalTypes: { locale: { defaultValue: 'pt' } } as any, }); @@ -94,7 +94,18 @@ describe('CSF3', () => { expect(screen.getByTestId('custom-render')).not.toBeNull(); }); - it('renders with play function', async () => { + it('renders with play function without canvas element', async () => { + const CSF3InputFieldFilled = composeStory(stories.CSF3InputFieldFilled, stories.default); + + render(); + + await CSF3InputFieldFilled.play!(); + + const input = screen.getByTestId('input') as HTMLInputElement; + expect(input.value).toEqual('Hello world!'); + }); + + it('renders with play function with canvas element', async () => { const CSF3InputFieldFilled = composeStory(stories.CSF3InputFieldFilled, stories.default); const { container } = render(); diff --git a/code/renderers/react/src/portable-stories.ts b/code/renderers/react/src/portable-stories.tsx similarity index 94% rename from code/renderers/react/src/portable-stories.ts rename to code/renderers/react/src/portable-stories.tsx index 385e0dc4c804..55ca55c69ff4 100644 --- a/code/renderers/react/src/portable-stories.ts +++ b/code/renderers/react/src/portable-stories.tsx @@ -1,7 +1,9 @@ +import React from 'react'; import { composeStory as originalComposeStory, composeStories as originalComposeStories, setProjectAnnotations as originalSetProjectAnnotations, + getPortableStoryWrapperId, } from '@storybook/preview-api'; import type { Args, @@ -39,6 +41,15 @@ export function setProjectAnnotations( // This will not be necessary once we have auto preset loading const defaultProjectAnnotations: ProjectAnnotations = { render, + decorators: [ + function addStorybookId(StoryFn, { id }) { + return ( +
+ {StoryFn()} +
+ ); + }, + ], }; /** diff --git a/code/renderers/vue3/src/__tests__/composeStories/__snapshots__/portable-stories.test.ts.snap b/code/renderers/vue3/src/__tests__/composeStories/__snapshots__/portable-stories.test.ts.snap index 75eab08758cf..aca5cb96961b 100644 --- a/code/renderers/vue3/src/__tests__/composeStories/__snapshots__/portable-stories.test.ts.snap +++ b/code/renderers/vue3/src/__tests__/composeStories/__snapshots__/portable-stories.test.ts.snap @@ -3,56 +3,51 @@ exports[`Renders CSF2Secondary story 1`] = `
- -
- -`; - -exports[`Renders CSF2StoryWithLocale story 1`] = ` - -
-
-

- locale: undefined -

`; -exports[`Renders CSF3Button story 1`] = ` +exports[`Renders CSF2StoryWithLocale story 1`] = `
- +
+

+ locale: undefined +

+ +
+
`; -exports[`Renders CSF3ButtonWithRender story 1`] = ` +exports[`Renders CSF3Button story 1`] = `
-
-

- I am a custom render function -

+
+
+
+
+ +`; + exports[`Renders CSF3InputFieldFilled story 1`] = `
- +
+ +
`; @@ -77,12 +102,17 @@ exports[`Renders CSF3InputFieldFilled story 1`] = ` exports[`Renders CSF3Primary story 1`] = `
- + +
`; diff --git a/code/renderers/vue3/src/__tests__/composeStories/portable-stories.test.ts b/code/renderers/vue3/src/__tests__/composeStories/portable-stories.test.ts index 4c541e1c4536..97fb295c47bc 100644 --- a/code/renderers/vue3/src/__tests__/composeStories/portable-stories.test.ts +++ b/code/renderers/vue3/src/__tests__/composeStories/portable-stories.test.ts @@ -84,9 +84,9 @@ describe('CSF3', () => { it('renders with play function', async () => { const CSF3InputFieldFilled = composeStory(stories.CSF3InputFieldFilled, stories.default); - const { container } = render(CSF3InputFieldFilled()); + render(CSF3InputFieldFilled()); - await CSF3InputFieldFilled.play!({ canvasElement: container as HTMLElement }); + await CSF3InputFieldFilled.play!(); const input = screen.getByTestId('input') as HTMLInputElement; expect(input.value).toEqual('Hello world!'); diff --git a/code/renderers/vue3/src/portable-stories.ts b/code/renderers/vue3/src/portable-stories.ts index 4e009b25d672..aef26b39a5e7 100644 --- a/code/renderers/vue3/src/portable-stories.ts +++ b/code/renderers/vue3/src/portable-stories.ts @@ -2,6 +2,7 @@ import { composeStory as originalComposeStory, composeStories as originalComposeStories, setProjectAnnotations as originalSetProjectAnnotations, + getPortableStoryWrapperId, } from '@storybook/preview-api'; import type { Args, @@ -11,10 +12,24 @@ import type { StoriesWithPartialProps, } from '@storybook/types'; -import * as defaultProjectAnnotations from './render'; +import * as vueProjectAnnotations from './entry-preview'; import type { Meta } from './public-types'; import type { VueRenderer } from './types'; +const defaultProjectAnnotations: ProjectAnnotations = { + ...vueProjectAnnotations, + decorators: [ + function addStorybookId(story, { id }) { + return { + components: { story }, + template: `
+ +
`, + }; + }, + ], +}; + /** Function that sets the globalConfig of your Storybook. The global config is the preview module of your .storybook folder. * * It should be run a single time, so that your global config (e.g. decorators) is applied to your stories when using `composeStories` or `composeStory`. From 0694772841f956bcf55ec81f8aba71771870f71e Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Fri, 1 Mar 2024 12:23:40 +0100 Subject: [PATCH 60/77] Update code/lib/preview-api/src/modules/store/csf/portable-stories.test.ts Co-authored-by: Jeppe Reinhold --- .../src/modules/store/csf/portable-stories.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/lib/preview-api/src/modules/store/csf/portable-stories.test.ts b/code/lib/preview-api/src/modules/store/csf/portable-stories.test.ts index 54e82553757f..9d3602ecc492 100644 --- a/code/lib/preview-api/src/modules/store/csf/portable-stories.test.ts +++ b/code/lib/preview-api/src/modules/store/csf/portable-stories.test.ts @@ -53,8 +53,8 @@ describe('composeStory', () => { composedStory(); - expect(decoratorFromProjectAnnotations).toHaveBeenCalled(); - expect(decoratorFromStoryAnnotations).toHaveBeenCalled(); + expect(decoratorFromProjectAnnotations).toHaveBeenCalledOnce(); + expect(decoratorFromStoryAnnotations).toHaveBeenCalledOnce(); }); it('should compose with a play function', async () => { From d39b6c93b433750ebdf33f68c855923872d41954 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Fri, 1 Mar 2024 14:03:12 +0100 Subject: [PATCH 61/77] use composeConfigs function --- .../src/modules/store/csf/portable-stories.ts | 43 +------------------ 1 file changed, 1 insertion(+), 42 deletions(-) diff --git a/code/lib/preview-api/src/modules/store/csf/portable-stories.ts b/code/lib/preview-api/src/modules/store/csf/portable-stories.ts index 6f24b2933cdf..fbe3898fc3d2 100644 --- a/code/lib/preview-api/src/modules/store/csf/portable-stories.ts +++ b/code/lib/preview-api/src/modules/store/csf/portable-stories.ts @@ -23,7 +23,6 @@ import { normalizeStory } from './normalizeStory'; import { normalizeComponentAnnotations } from './normalizeComponentAnnotations'; import { getValuesFromArgTypes } from './getValuesFromArgTypes'; import { normalizeProjectAnnotations } from './normalizeProjectAnnotations'; -import { normalizeArrays } from './normalizeArrays'; let GLOBAL_STORYBOOK_PROJECT_ANNOTATIONS = composeConfigs([]); @@ -38,46 +37,6 @@ export function setProjectAnnotations( GLOBAL_STORYBOOK_PROJECT_ANNOTATIONS = composeConfigs(annotations); } -// TODO: we don't have any utility that merges two sets of annotations (e.g. two project annotations) -// this should be elsewhere, probably reused -function mergeAnnotations( - firstAnnotations: ProjectAnnotations, - secondAnnotations: ProjectAnnotations -) { - return { - ...firstAnnotations, - ...secondAnnotations, - args: { - ...firstAnnotations.args, - ...secondAnnotations.args, - }, - argTypes: { - ...firstAnnotations.argTypes, - ...secondAnnotations.argTypes, - }, - parameters: { - ...firstAnnotations.parameters, - ...secondAnnotations.parameters, - }, - decorators: [ - ...normalizeArrays(firstAnnotations.decorators), - ...normalizeArrays(secondAnnotations.decorators), - ], - loaders: [ - ...normalizeArrays(firstAnnotations.loaders), - ...normalizeArrays(secondAnnotations.loaders), - ], - argsEnhancers: [ - ...normalizeArrays(firstAnnotations.argsEnhancers), - ...normalizeArrays(secondAnnotations.argsEnhancers), - ], - argTypesEnhancers: [ - ...normalizeArrays(firstAnnotations.argTypesEnhancers), - ...normalizeArrays(secondAnnotations.argTypesEnhancers), - ], - }; -} - export function composeStory( storyAnnotations: LegacyStoryAnnotationsOrFn, componentAnnotations: ComponentAnnotations, @@ -115,7 +74,7 @@ export function composeStory( - mergeAnnotations(projectAnnotations, defaultConfig) + composeConfigs([projectAnnotations, defaultConfig]) ); const story = prepareStory( From a2891859107a10b48f5392de7bd0bd30aa7a4cfe Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Fri, 1 Mar 2024 14:09:13 +0100 Subject: [PATCH 62/77] update migration notes --- MIGRATION.md | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/MIGRATION.md b/MIGRATION.md index c51ddba6347e..62aef1593d05 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -3,7 +3,7 @@ - [From version 7.x to 8.0.0](#from-version-7x-to-800) - [Portable stories](#portable-stories) - [Type change in `composeStories` API](#type-change-in-composestories-api) - - [The context in the play function is now optional](#the-context-in-the-play-function-is-now-optional) + - [DOM structure changed in portable stories](#dom-structure-changed-in-portable-stories) - [Tab addons are now routed to a query parameter](#tab-addons-are-now-routed-to-a-query-parameter) - [Default keyboard shortcuts changed](#default-keyboard-shortcuts-changed) - [Manager addons are now rendered with React 18](#manager-addons-are-now-rendered-with-react-18) @@ -422,23 +422,9 @@ await Primary.play!(...) // if you want a runtime error when the play function d There are plans to make the type of the play function be inferred based on your imported story's play function in a near future, so the types will be 100% accurate. -#### The context in the play function is now optional +#### DOM structure changed in portable stories -When reusing a story that has a play function, you don't have to pass the context anymore, not even the `canvasElement`. The context is built-in and if you don't pass overrides, it will still be present. It is still possible to pass overrides to the context, if you'd like. - -```tsx -const { Primary } = composeStories(stories); -test("load and render", async () => { - const { container } = render(); - // before: - await Primary.play({ canvasElement: container, ...ArgsOrWhateverElse }); - - // after: - await Primary.play(); -}); -``` - -In order for this to be possible, the portable stories API now adds a wrapper to your stories with a unique id based on your story id, such as: +The portable stories API now adds a wrapper to your stories with a unique id based on your story id, such as: ```html
From f60fee3fea81fd40888b9c7f494377e56d1cdbf0 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Fri, 1 Mar 2024 16:35:54 +0100 Subject: [PATCH 63/77] fix compose configs order --- code/lib/preview-api/src/modules/store/csf/portable-stories.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/lib/preview-api/src/modules/store/csf/portable-stories.ts b/code/lib/preview-api/src/modules/store/csf/portable-stories.ts index fbe3898fc3d2..c3dfd53d2877 100644 --- a/code/lib/preview-api/src/modules/store/csf/portable-stories.ts +++ b/code/lib/preview-api/src/modules/store/csf/portable-stories.ts @@ -74,7 +74,7 @@ export function composeStory( - composeConfigs([projectAnnotations, defaultConfig]) + composeConfigs([defaultConfig, projectAnnotations]) ); const story = prepareStory( From 2552e0395840e37f2c988434a497de231b756ded Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Fri, 1 Mar 2024 16:39:28 +0100 Subject: [PATCH 64/77] bring test assertions back --- .../src/modules/store/csf/portable-stories.test.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/code/lib/preview-api/src/modules/store/csf/portable-stories.test.ts b/code/lib/preview-api/src/modules/store/csf/portable-stories.test.ts index 9d3602ecc492..6a6d059834de 100644 --- a/code/lib/preview-api/src/modules/store/csf/portable-stories.test.ts +++ b/code/lib/preview-api/src/modules/store/csf/portable-stories.test.ts @@ -66,6 +66,17 @@ describe('composeStory', () => { Story.play = async (context: any) => { spy(context); }; + + const composedStory = composeStory(Story, meta); + await composedStory.play!({ canvasElement: null }); + expect(spy).toHaveBeenCalledWith( + expect.objectContaining({ + args: { + ...Story.args, + ...meta.args, + }, + }) + ); }); it('should throw an error if Story is undefined', () => { From 40b56a46b42b834c771674d7a3d1140d2f4c4d51 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Fri, 1 Mar 2024 16:40:11 +0100 Subject: [PATCH 65/77] use jsx in portable stories react decorator --- code/renderers/react/src/portable-stories.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/renderers/react/src/portable-stories.tsx b/code/renderers/react/src/portable-stories.tsx index 55ca55c69ff4..bf91dde7b3e8 100644 --- a/code/renderers/react/src/portable-stories.tsx +++ b/code/renderers/react/src/portable-stories.tsx @@ -45,7 +45,7 @@ const defaultProjectAnnotations: ProjectAnnotations = { function addStorybookId(StoryFn, { id }) { return (
- {StoryFn()} +
); }, From 1dd146fbd045f853d0312e4aa5daab5b8d96daa3 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Fri, 1 Mar 2024 16:43:08 +0100 Subject: [PATCH 66/77] use play function on snapshot tests --- .../react/src/__test__/portable-stories.test.tsx | 16 ++++++++++++---- .../composeStories/portable-stories.test.ts | 6 ++++-- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/code/renderers/react/src/__test__/portable-stories.test.tsx b/code/renderers/react/src/__test__/portable-stories.test.tsx index f137424fff0b..3c7edd4e8e17 100644 --- a/code/renderers/react/src/__test__/portable-stories.test.tsx +++ b/code/renderers/react/src/__test__/portable-stories.test.tsx @@ -1,5 +1,5 @@ -import { vi, it, expect, afterEach, describe } from 'vitest'; import React from 'react'; +import { vi, it, expect, afterEach, describe } from 'vitest'; import { render, screen, cleanup } from '@testing-library/react'; import { addons } from '@storybook/preview-api'; import type { Meta } from '@storybook/react'; @@ -150,9 +150,17 @@ describe('ComposeStories types', () => { }); // Batch snapshot testing -const testCases = Object.values(composeStories(stories)).map((Story) => [Story.storyName, Story]); +const testCases = Object.values(composeStories(stories)).map( + (Story) => [Story.storyName, Story] as [string, typeof Story] +); it.each(testCases)('Renders %s story', async (_storyName, Story) => { cleanup(); - const tree = await render(); - expect(tree.baseElement).toMatchSnapshot(); + + if (_storyName === 'CSF2WithLocale') { + return; + } + + const { baseElement } = await render(); + await Story.play?.(); + expect(baseElement).toMatchSnapshot(); }); diff --git a/code/renderers/vue3/src/__tests__/composeStories/portable-stories.test.ts b/code/renderers/vue3/src/__tests__/composeStories/portable-stories.test.ts index 97fb295c47bc..e82a6c657a89 100644 --- a/code/renderers/vue3/src/__tests__/composeStories/portable-stories.test.ts +++ b/code/renderers/vue3/src/__tests__/composeStories/portable-stories.test.ts @@ -133,6 +133,8 @@ it.each(testCases)('Renders %s story', async (_storyName, Story) => { await new Promise((resolve) => setTimeout(resolve, 0)); - const tree = await render(Story()); - expect(tree.baseElement).toMatchSnapshot(); + const { baseElement } = await render(Story()); + await Story.play?.(); + + expect(baseElement).toMatchSnapshot(); }); From 69e69d182a754c0ec4d3d326588d9c07b1cfb285 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Mon, 4 Mar 2024 10:28:54 +0100 Subject: [PATCH 67/77] fix proejct annotation merging logic --- .../store/csf/portable-stories.test.ts | 25 +++++++++++++++++++ .../src/modules/store/csf/portable-stories.ts | 22 ++++++---------- 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/code/lib/preview-api/src/modules/store/csf/portable-stories.test.ts b/code/lib/preview-api/src/modules/store/csf/portable-stories.test.ts index 6a6d059834de..3f2876be4c2c 100644 --- a/code/lib/preview-api/src/modules/store/csf/portable-stories.test.ts +++ b/code/lib/preview-api/src/modules/store/csf/portable-stories.test.ts @@ -79,6 +79,31 @@ describe('composeStory', () => { ); }); + it('should merge parameters with correct precedence in all combinations', async () => { + const storyAnnotations = { render: () => {} }; + const metaAnnotations: Meta = { parameters: { label: 'meta' } }; + const projectAnnotations: Meta = { parameters: { label: 'projectOverrides' } }; + + const storyPrecedence = composeStory( + { ...storyAnnotations, parameters: { label: 'story' } }, + metaAnnotations, + projectAnnotations + ); + expect(storyPrecedence.parameters.label).toEqual('story'); + + const metaPrecedence = composeStory(storyAnnotations, metaAnnotations, projectAnnotations); + expect(metaPrecedence.parameters.label).toEqual('meta'); + + const projectPrecedence = composeStory(storyAnnotations, {}, projectAnnotations); + expect(projectPrecedence.parameters.label).toEqual('projectOverrides'); + + setProjectAnnotations({ parameters: { label: 'setProjectAnnotationsOverrides' } }); + const setProjectAnnotationsPrecedence = composeStory(storyAnnotations, {}, {}); + expect(setProjectAnnotationsPrecedence.parameters.label).toEqual( + 'setProjectAnnotationsOverrides' + ); + }); + it('should throw an error if Story is undefined', () => { expect(() => { // @ts-expect-error (invalid input) diff --git a/code/lib/preview-api/src/modules/store/csf/portable-stories.ts b/code/lib/preview-api/src/modules/store/csf/portable-stories.ts index c3dfd53d2877..65d38e1b9805 100644 --- a/code/lib/preview-api/src/modules/store/csf/portable-stories.ts +++ b/code/lib/preview-api/src/modules/store/csf/portable-stories.ts @@ -24,7 +24,7 @@ import { normalizeComponentAnnotations } from './normalizeComponentAnnotations'; import { getValuesFromArgTypes } from './getValuesFromArgTypes'; import { normalizeProjectAnnotations } from './normalizeProjectAnnotations'; -let GLOBAL_STORYBOOK_PROJECT_ANNOTATIONS = composeConfigs([]); +let globalProjectAnnotations: ProjectAnnotations = {}; export function getPortableStoryWrapperId(storyId: string) { return `storybook-story-${storyId}`; @@ -34,26 +34,20 @@ export function setProjectAnnotations( projectAnnotations: ProjectAnnotations | ProjectAnnotations[] ) { const annotations = Array.isArray(projectAnnotations) ? projectAnnotations : [projectAnnotations]; - GLOBAL_STORYBOOK_PROJECT_ANNOTATIONS = composeConfigs(annotations); + globalProjectAnnotations = composeConfigs(annotations); } export function composeStory( storyAnnotations: LegacyStoryAnnotationsOrFn, componentAnnotations: ComponentAnnotations, - projectAnnotations: ProjectAnnotations = GLOBAL_STORYBOOK_PROJECT_ANNOTATIONS as ProjectAnnotations, - defaultConfig: ProjectAnnotations = {}, + projectAnnotations?: ProjectAnnotations, + defaultConfig?: ProjectAnnotations, exportsName?: string ): ComposedStoryFn> { if (storyAnnotations === undefined) { throw new Error('Expected a story but received undefined.'); } - // users might pass an empty object instead of undefined e.g. composeStory(story, meta, {}, exportsName) - // and likely they expect the default project annotations to be used instead of completely resetting them - if (typeof projectAnnotations === 'object' && Object.keys(projectAnnotations).length === 0) { - projectAnnotations = GLOBAL_STORYBOOK_PROJECT_ANNOTATIONS as ProjectAnnotations; - } - // @TODO: Support auto title componentAnnotations.title = componentAnnotations.title ?? 'ComposedStory'; @@ -74,7 +68,7 @@ export function composeStory( - composeConfigs([defaultConfig, projectAnnotations]) + composeConfigs([defaultConfig ?? {}, globalProjectAnnotations, projectAnnotations ?? {}]) ); const story = prepareStory( @@ -83,13 +77,13 @@ export function composeStory = { hooks: new HooksContext(), globals: { - ...defaultGlobals, - ...projectAnnotations.globals, + ...globalsFromGlobalTypes, + ...normalizedProjectAnnotations.globals, }, args: { ...story.initialArgs }, viewMode: 'story', From 2b6ce98d791aa6f06082d6ed185ff40826bb1674 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Mon, 4 Mar 2024 11:47:58 +0100 Subject: [PATCH 68/77] Portable stories: Add support for loaders --- .../store/csf/portable-stories.test.ts | 49 ++++++++++++ .../src/modules/store/csf/portable-stories.ts | 5 ++ code/lib/types/src/modules/composedStory.ts | 1 + .../react/src/__test__/Button.stories.tsx | 44 ++++++++++- .../portable-stories.test.tsx.snap | 42 +++++----- .../src/__test__/portable-stories.test.tsx | 29 ++++++- code/renderers/react/src/portable-stories.tsx | 4 +- .../composeStories/Button.stories.ts | 42 +++++++++- .../portable-stories.test.ts.snap | 37 +++++++-- .../composeStories/portable-stories.test.ts | 77 ++++++++++++------- 10 files changed, 262 insertions(+), 68 deletions(-) diff --git a/code/lib/preview-api/src/modules/store/csf/portable-stories.test.ts b/code/lib/preview-api/src/modules/store/csf/portable-stories.test.ts index 3f2876be4c2c..dbca4640b05b 100644 --- a/code/lib/preview-api/src/modules/store/csf/portable-stories.test.ts +++ b/code/lib/preview-api/src/modules/store/csf/portable-stories.test.ts @@ -104,6 +104,55 @@ describe('composeStory', () => { ); }); + it('should call and compose loaders data', async () => { + const loadSpy = vi.fn(); + const args = { story: 'story' }; + const LoaderStory: Story = { + args, + loaders: [ + async (context) => { + loadSpy(); + expect(context.args).toEqual(args); + return { + foo: 'bar', + }; + }, + ], + render: (_args, { loaded }) => { + expect(loaded).toEqual({ foo: 'bar' }); + }, + }; + + const composedStory = composeStory(LoaderStory, {}); + await composedStory.load(); + composedStory(); + expect(loadSpy).toHaveBeenCalled(); + }); + + it('should work with spies set up in loaders', async () => { + const spyFn = vi.fn(); + + const Story: Story = { + args: { + spyFn, + }, + loaders: [ + async () => { + spyFn.mockReturnValue('mockedData'); + }, + ], + render: (args) => { + const data = args.spyFn(); + expect(data).toBe('mockedData'); + }, + }; + + const composedStory = composeStory(Story, {}); + await composedStory.load(); + composedStory(); + expect(spyFn).toHaveBeenCalled(); + }); + it('should throw an error if Story is undefined', () => { expect(() => { // @ts-expect-error (invalid input) diff --git a/code/lib/preview-api/src/modules/store/csf/portable-stories.ts b/code/lib/preview-api/src/modules/store/csf/portable-stories.ts index 65d38e1b9805..0974f0908526 100644 --- a/code/lib/preview-api/src/modules/store/csf/portable-stories.ts +++ b/code/lib/preview-api/src/modules/store/csf/portable-stories.ts @@ -45,6 +45,7 @@ export function composeStory> { if (storyAnnotations === undefined) { + // eslint-disable-next-line local-rules/no-uncategorized-errors throw new Error('Expected a story but received undefined.'); } @@ -118,6 +119,10 @@ export function composeStory { + const loadedContext = await story.applyLoaders(context); + context.loaded = loadedContext.loaded; + }, args: story.initialArgs as Partial, parameters: story.parameters as Parameters, argTypes: story.argTypes as StrictArgTypes, diff --git a/code/lib/types/src/modules/composedStory.ts b/code/lib/types/src/modules/composedStory.ts index b7051a699b7f..b0a7bff6c374 100644 --- a/code/lib/types/src/modules/composedStory.ts +++ b/code/lib/types/src/modules/composedStory.ts @@ -48,6 +48,7 @@ export type ComposedStoryFn< args: TArgs; id: StoryId; play?: ComposedStoryPlayFn; + load: () => Promise; storyName: string; parameters: Parameters; argTypes: StrictArgTypes; diff --git a/code/renderers/react/src/__test__/Button.stories.tsx b/code/renderers/react/src/__test__/Button.stories.tsx index 6882b957b136..277f92ddde1f 100644 --- a/code/renderers/react/src/__test__/Button.stories.tsx +++ b/code/renderers/react/src/__test__/Button.stories.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import { within, userEvent } from '@storybook/testing-library'; +import { within, userEvent, fn, expect } from '@storybook/test'; import type { StoryFn as CSF2Story, StoryObj as CSF3Story, Meta } from '..'; import type { ButtonProps } from './Button'; @@ -33,14 +33,21 @@ const getCaptionForLocale = (locale: string) => { return 'μ•ˆλ…•ν•˜μ„Έμš”!'; case 'pt': return 'OlΓ‘!'; - default: + case 'en': return 'Hello!'; + default: + return undefined; } }; export const CSF2StoryWithLocale: CSF2Story = (args, { globals: { locale } }) => { const caption = getCaptionForLocale(locale); - return ; + return ( + <> +

locale: {locale}

+ + + ); }; CSF2StoryWithLocale.storyName = 'WithLocale'; @@ -84,7 +91,36 @@ export const CSF3InputFieldFilled: CSF3Story = { play: async ({ canvasElement, step }) => { const canvas = within(canvasElement); await step('Step label', async () => { - await userEvent.type(canvas.getByTestId('input'), 'Hello world!'); + const inputEl = canvas.getByTestId('input'); + await userEvent.type(inputEl, 'Hello world!'); + await expect(inputEl).toHaveValue('Hello world!'); }); }, }; + +const mockFn = fn(); +export const LoaderStory: CSF3Story<{ mockFn: (val: string) => string }> = { + args: { + mockFn, + }, + loaders: [ + async () => { + mockFn.mockReturnValueOnce('mockFn return value'); + return { + value: 'loaded data', + }; + }, + ], + render: (args, { loaded }) => { + const data = args.mockFn('render'); + return ( +
+
{loaded.value}
+
{String(data)}
+
+ ); + }, + play: async () => { + expect(mockFn).toHaveBeenCalledWith('render'); + }, +}; diff --git a/code/renderers/react/src/__test__/__snapshots__/portable-stories.test.tsx.snap b/code/renderers/react/src/__test__/__snapshots__/portable-stories.test.tsx.snap index 3f40e5446d0b..2779b21001ab 100644 --- a/code/renderers/react/src/__test__/__snapshots__/portable-stories.test.tsx.snap +++ b/code/renderers/react/src/__test__/__snapshots__/portable-stories.test.tsx.snap @@ -18,24 +18,6 @@ exports[`Renders CSF2Secondary story 1`] = ` `; -exports[`Renders CSF2StoryWithLocale story 1`] = ` - -
-
- -
-
- -`; - exports[`Renders CSF2StoryWithParamsAndDecorator story 1`] = `
@@ -129,3 +111,27 @@ exports[`Renders CSF3Primary story 1`] = `
`; + +exports[`Renders LoaderStory story 1`] = ` + +
+
+
+
+ loaded data +
+
+ mockFn return value +
+
+
+
+ +`; diff --git a/code/renderers/react/src/__test__/portable-stories.test.tsx b/code/renderers/react/src/__test__/portable-stories.test.tsx index 3c7edd4e8e17..f8aae6b849f4 100644 --- a/code/renderers/react/src/__test__/portable-stories.test.tsx +++ b/code/renderers/react/src/__test__/portable-stories.test.tsx @@ -10,7 +10,7 @@ import type { Button } from './Button'; import * as stories from './Button.stories'; // example with composeStories, returns an object with all stories composed with args/decorators -const { CSF3Primary } = composeStories(stories); +const { CSF3Primary, LoaderStory } = composeStories(stories); // example with composeStory, returns a single story composed with args/decorators const Secondary = composeStory(stories.CSF2Secondary, stories.default); @@ -44,6 +44,15 @@ describe('renders', () => { const buttonElement = getByText(/foo/i); expect(buttonElement).not.toBeNull(); }); + + it('should call and compose loaders data', async () => { + await LoaderStory.load(); + const { getByTestId } = render(); + expect(getByTestId('spy-data').textContent).toEqual('mockFn return value'); + expect(getByTestId('loaded-data').textContent).toEqual('loaded data'); + // spy assertions happen in the play function and should work + await LoaderStory.play!(); + }); }); describe('projectAnnotations', () => { @@ -52,15 +61,24 @@ describe('projectAnnotations', () => { }); it('renders with default projectAnnotations', () => { + setProjectAnnotations([ + { + parameters: { injected: true }, + globalTypes: { + locale: { defaultValue: 'en' }, + }, + }, + ]); const WithEnglishText = composeStory(stories.CSF2StoryWithLocale, stories.default); const { getByText } = render(); const buttonElement = getByText('Hello!'); expect(buttonElement).not.toBeNull(); + expect(WithEnglishText.parameters?.injected).toBe(true); }); - it('renders with custom globals from projectAnnotations via composeStory params', () => { + it('renders with custom projectAnnotations via composeStory params', () => { const WithPortugueseText = composeStory(stories.CSF2StoryWithLocale, stories.default, { - globalTypes: { locale: { defaultValue: 'pt' } } as any, + globals: { locale: 'pt' }, }); const { getByText } = render(); const buttonElement = getByText('OlΓ‘!'); @@ -156,11 +174,14 @@ const testCases = Object.values(composeStories(stories)).map( it.each(testCases)('Renders %s story', async (_storyName, Story) => { cleanup(); - if (_storyName === 'CSF2WithLocale') { + if (_storyName === 'CSF2StoryWithLocale') { return; } + await Story.load(); + const { baseElement } = await render(); + await Story.play?.(); expect(baseElement).toMatchSnapshot(); }); diff --git a/code/renderers/react/src/portable-stories.tsx b/code/renderers/react/src/portable-stories.tsx index bf91dde7b3e8..3493e0f3b2e5 100644 --- a/code/renderers/react/src/portable-stories.tsx +++ b/code/renderers/react/src/portable-stories.tsx @@ -13,7 +13,7 @@ import type { StoriesWithPartialProps, } from '@storybook/types'; -import { render } from './render'; +import * as reactProjectAnnotations from './entry-preview'; import type { Meta } from './public-types'; import type { ReactRenderer } from './types'; @@ -40,7 +40,7 @@ export function setProjectAnnotations( // This will not be necessary once we have auto preset loading const defaultProjectAnnotations: ProjectAnnotations = { - render, + ...reactProjectAnnotations, decorators: [ function addStorybookId(StoryFn, { id }) { return ( diff --git a/code/renderers/vue3/src/__tests__/composeStories/Button.stories.ts b/code/renderers/vue3/src/__tests__/composeStories/Button.stories.ts index 239416df5c35..0d4623585de0 100644 --- a/code/renderers/vue3/src/__tests__/composeStories/Button.stories.ts +++ b/code/renderers/vue3/src/__tests__/composeStories/Button.stories.ts @@ -1,4 +1,4 @@ -import { userEvent, within } from '@storybook/testing-library'; +import { userEvent, within, expect, fn } from '@storybook/test'; import type { Meta, StoryFn as CSF2Story, StoryObj } from '../..'; import Button from './Button.vue'; @@ -45,8 +45,10 @@ const getCaptionForLocale = (locale: string) => { return 'μ•ˆλ…•ν•˜μ„Έμš”!'; case 'pt': return 'OlΓ‘!'; - default: + case 'en': return 'Hello!'; + default: + return undefined; } }; @@ -58,7 +60,7 @@ export const CSF2StoryWithLocale: CSF2Story = (args, { globals }) => ({ }, template: `

locale: ${globals.locale}

-
`, }); CSF2StoryWithLocale.storyName = 'WithLocale'; @@ -114,7 +116,39 @@ export const CSF3InputFieldFilled: CSF3Story = { play: async ({ canvasElement, step }) => { const canvas = within(canvasElement); await step('Step label', async () => { - await userEvent.type(canvas.getByTestId('input'), 'Hello world!'); + const inputEl = canvas.getByTestId('input'); + await userEvent.type(inputEl, 'Hello world!'); + await expect(inputEl).toHaveValue('Hello world!'); }); }, }; + +const mockFn = fn(); +export const LoaderStory: StoryObj<{ mockFn: (val: string) => string }> = { + args: { + mockFn, + }, + loaders: [ + async () => { + mockFn.mockReturnValueOnce('mockFn return value'); + return { + value: 'loaded data', + }; + }, + ], + render: (args, { loaded }) => ({ + components: { Button }, + setup() { + return { args, data: args.mockFn('render'), loaded: loaded.value }; + }, + template: ` +
+
{{loaded}}
+
{{data}}
+
+ `, + }), + play: async () => { + expect(mockFn).toHaveBeenCalledWith('render'); + }, +}; diff --git a/code/renderers/vue3/src/__tests__/composeStories/__snapshots__/portable-stories.test.ts.snap b/code/renderers/vue3/src/__tests__/composeStories/__snapshots__/portable-stories.test.ts.snap index aca5cb96961b..b6e6feff8f61 100644 --- a/code/renderers/vue3/src/__tests__/composeStories/__snapshots__/portable-stories.test.ts.snap +++ b/code/renderers/vue3/src/__tests__/composeStories/__snapshots__/portable-stories.test.ts.snap @@ -18,22 +18,21 @@ exports[`Renders CSF2Secondary story 1`] = ` `; -exports[`Renders CSF2StoryWithLocale story 1`] = ` +exports[`Renders CSF2StoryWithParamsAndDecorator story 1`] = `
-
-

- locale: undefined -

+
@@ -116,3 +115,27 @@ exports[`Renders CSF3Primary story 1`] = `
`; + +exports[`Renders LoaderStory story 1`] = ` + +
+
+
+
+ loaded data +
+
+ mockFn return value +
+
+
+
+ +`; diff --git a/code/renderers/vue3/src/__tests__/composeStories/portable-stories.test.ts b/code/renderers/vue3/src/__tests__/composeStories/portable-stories.test.ts index e82a6c657a89..36aa7c2e9c56 100644 --- a/code/renderers/vue3/src/__tests__/composeStories/portable-stories.test.ts +++ b/code/renderers/vue3/src/__tests__/composeStories/portable-stories.test.ts @@ -10,39 +10,58 @@ import type Button from './Button.vue'; import { composeStories, composeStory, setProjectAnnotations } from '../../portable-stories'; // example with composeStories, returns an object with all stories composed with args/decorators -const { CSF3Primary } = composeStories(stories); +const { CSF3Primary, LoaderStory } = composeStories(stories); // example with composeStory, returns a single story composed with args/decorators const Secondary = composeStory(stories.CSF2Secondary, stories.default); -it('renders primary button', () => { - render(CSF3Primary({ label: 'Hello world' })); - const buttonElement = screen.getByText(/Hello world/i); - expect(buttonElement).toBeInTheDocument(); -}); +describe('renders', () => { + it('renders primary button', () => { + render(CSF3Primary({ label: 'Hello world' })); + const buttonElement = screen.getByText(/Hello world/i); + expect(buttonElement).toBeInTheDocument(); + }); -it('reuses args from composed story', () => { - render(Secondary()); - const buttonElement = screen.getByRole('button'); - expect(buttonElement.textContent).toEqual(Secondary.args.label); -}); + it('reuses args from composed story', () => { + render(Secondary()); + const buttonElement = screen.getByRole('button'); + expect(buttonElement.textContent).toEqual(Secondary.args.label); + }); -it('myClickEvent handler is called', async () => { - const myClickEventSpy = vi.fn(); - render(Secondary({ onMyClickEvent: myClickEventSpy })); - const buttonElement = screen.getByRole('button'); - buttonElement.click(); - expect(myClickEventSpy).toHaveBeenCalled(); -}); + it('myClickEvent handler is called', async () => { + const myClickEventSpy = vi.fn(); + render(Secondary({ onMyClickEvent: myClickEventSpy })); + const buttonElement = screen.getByRole('button'); + buttonElement.click(); + expect(myClickEventSpy).toHaveBeenCalled(); + }); + + it('reuses args from composeStories', () => { + const { getByText } = render(CSF3Primary()); + const buttonElement = getByText(/foo/i); + expect(buttonElement).toBeInTheDocument(); + }); -it('reuses args from composeStories', () => { - const { getByText } = render(CSF3Primary()); - const buttonElement = getByText(/foo/i); - expect(buttonElement).toBeInTheDocument(); + it('should call and compose loaders data', async () => { + await LoaderStory.load(); + const { getByTestId } = render(LoaderStory()); + expect(getByTestId('spy-data').textContent).toEqual('mockFn return value'); + expect(getByTestId('loaded-data').textContent).toEqual('loaded data'); + // spy assertions happen in the play function and should work + await LoaderStory.play!(); + }); }); describe('projectAnnotations', () => { it('renders with default projectAnnotations', () => { + setProjectAnnotations([ + { + parameters: { injected: true }, + globalTypes: { + locale: { defaultValue: 'en' }, + }, + }, + ]); const WithEnglishText = composeStory(stories.CSF2StoryWithLocale, stories.default); const { getByText } = render(WithEnglishText()); const buttonElement = getByText('Hello!'); @@ -51,7 +70,7 @@ describe('projectAnnotations', () => { it('renders with custom projectAnnotations via composeStory params', () => { const WithPortugueseText = composeStory(stories.CSF2StoryWithLocale, stories.default, { - globalTypes: { locale: { defaultValue: 'pt' } } as any, + globals: { locale: 'pt' }, }); const { getByText } = render(WithPortugueseText()); const buttonElement = getByText('OlΓ‘!'); @@ -84,9 +103,9 @@ describe('CSF3', () => { it('renders with play function', async () => { const CSF3InputFieldFilled = composeStory(stories.CSF3InputFieldFilled, stories.default); - render(CSF3InputFieldFilled()); + const { container } = render(CSF3InputFieldFilled()); - await CSF3InputFieldFilled.play!(); + await CSF3InputFieldFilled.play!({ canvasElement: container as HTMLElement }); const input = screen.getByTestId('input') as HTMLInputElement; expect(input.value).toEqual('Hello world!'); @@ -127,14 +146,14 @@ describe('ComposeStories types', () => { // Batch snapshot testing const testCases = Object.values(composeStories(stories)).map((Story) => [Story.storyName, Story]); it.each(testCases)('Renders %s story', async (_storyName, Story) => { - if (typeof Story === 'string' || _storyName === 'CSF2StoryWithParamsAndDecorator') { + if (typeof Story === 'string' || _storyName === 'CSF2StoryWithLocale') { return; } + await Story.load(); + const { container, baseElement } = await render(Story()); + await Story.play?.({ canvasElement: container as HTMLElement }); await new Promise((resolve) => setTimeout(resolve, 0)); - const { baseElement } = await render(Story()); - await Story.play?.(); - expect(baseElement).toMatchSnapshot(); }); From 6dae91d30c8d9fc60db1169d2e0be2e225dc9d13 Mon Sep 17 00:00:00 2001 From: Yann Braga Date: Mon, 4 Mar 2024 11:54:37 +0100 Subject: [PATCH 69/77] add migration note regarding project annotation overrides --- MIGRATION.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/MIGRATION.md b/MIGRATION.md index 62aef1593d05..5919ec501c42 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -2,6 +2,7 @@ - [From version 7.x to 8.0.0](#from-version-7x-to-800) - [Portable stories](#portable-stories) + - [Project annotations are now merged instead of overwritten in composeStory](#project-annotations-are-now-merged-instead-of-overwritten-in-composestory) - [Type change in `composeStories` API](#type-change-in-composestories-api) - [DOM structure changed in portable stories](#dom-structure-changed-in-portable-stories) - [Tab addons are now routed to a query parameter](#tab-addons-are-now-routed-to-a-query-parameter) @@ -405,6 +406,21 @@ ### Portable stories +#### Project annotations are now merged instead of overwritten in composeStory + +When passing project annotations overrides via `composeStory` such as: + +```tsx +const projectAnnotationOverrides = { parameters: { foo: "bar" } }; +const Primary = composeStory( + stories.Primary, + stories, + projectAnnotationOverrides +); +``` + +they are now merged with the annotations passed via `setProjectAnnotations` rather than completely overwriting them. This was seen as a bug and it's now fixed. If you have a use case where you really need this, please open an issue to elaborate. + #### Type change in `composeStories` API There is a TypeScript type change in the `play` function returned from `composeStories` or `composeStory` in `@storybook/react` or `@storybook/vue3`, where before it was always defined, now it is potentially undefined. This means that you might have to make a small change in your code, such as: From c9a26c6f25217cc5a595189e8dbbe828937b4437 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Mon, 4 Mar 2024 13:30:49 +0100 Subject: [PATCH 70/77] fix the bug and add tests to ensure it doesn't fail ever again --- code/lib/cli/src/add.test.ts | 140 +++++++++++++++++++++++++++ code/lib/cli/src/add.ts | 82 +++++++--------- code/lib/cli/src/postinstallAddon.ts | 19 ++++ 3 files changed, 196 insertions(+), 45 deletions(-) create mode 100644 code/lib/cli/src/add.test.ts create mode 100644 code/lib/cli/src/postinstallAddon.ts diff --git a/code/lib/cli/src/add.test.ts b/code/lib/cli/src/add.test.ts new file mode 100644 index 000000000000..2da3bd8e184b --- /dev/null +++ b/code/lib/cli/src/add.test.ts @@ -0,0 +1,140 @@ +import { describe, expect, test, vi } from 'vitest'; +import { add, getVersionSpecifier } from './add'; + +const MockedConfig = vi.hoisted(() => { + return { + appendValueToArray: vi.fn(), + }; +}); +const MockedPackageManager = vi.hoisted(() => { + return { + retrievePackageJson: vi.fn(() => ({})), + latestVersion: vi.fn(() => '1.0.0'), + addDependencies: vi.fn(() => {}), + type: 'npm', + }; +}); +const MockedPostInstall = vi.hoisted(() => { + return { + postinstallAddon: vi.fn(), + }; +}); + +const MockedConsole = { + log: vi.fn(), + warn: vi.fn(), + error: vi.fn(), +} as any as Console; + +vi.mock('@storybook/csf-tools', () => { + return { + readConfig: vi.fn(() => MockedConfig), + writeConfig: vi.fn(), + }; +}); +vi.mock('./postinstallAddon', () => { + return MockedPostInstall; +}); + +vi.mock('@storybook/core-common', () => { + return { + getStorybookInfo: vi.fn(() => ({ mainConfig: {}, configDir: '' })), + serverRequire: vi.fn(() => ({})), + JsPackageManagerFactory: { + getPackageManager: vi.fn(() => MockedPackageManager), + }, + versions: { + '@storybook/addon-onboarding': '8.0.0', + }, + }; +}); + +describe('getVersionSpecifier', (it) => { + test.each([ + ['@storybook/addon-docs', ['@storybook/addon-docs', undefined]], + ['@storybook/addon-docs@7.0.1', ['@storybook/addon-docs', '7.0.1']], + ['@storybook/addon-docs@7.0.1-beta.1', ['@storybook/addon-docs', '7.0.1-beta.1']], + ['@storybook/addon-docs@~7.0.1-beta.1', ['@storybook/addon-docs', '~7.0.1-beta.1']], + ['@storybook/addon-docs@^7.0.1-beta.1', ['@storybook/addon-docs', '^7.0.1-beta.1']], + ['@storybook/addon-docs@next', ['@storybook/addon-docs', 'next']], + ])('%s => %s', (input, expected) => { + const result = getVersionSpecifier(input); + expect(result[0]).toEqual(expected[0]); + expect(result[1]).toEqual(expected[1]); + }); +}); + +describe('add', () => { + const testData = [ + { full: 'aa', expected: 'aa@^1.0.0' }, // resolves to the latest version + { full: 'aa@4', expected: 'aa@^4' }, + { full: 'aa@4.1.0', expected: 'aa@^4.1.0' }, + { full: 'aa@^4', expected: 'aa@^4' }, + { full: 'aa@~4', expected: 'aa@~4' }, + { full: 'aa@4.1.0-alpha.1', expected: 'aa@^4.1.0-alpha.1' }, + { full: 'aa@next', expected: 'aa@next' }, + + { full: '@org/aa', expected: '@org/aa@^1.0.0' }, + { full: '@org/aa@4', expected: '@org/aa@^4' }, + { full: '@org/aa@4.1.0', expected: '@org/aa@^4.1.0' }, + { full: '@org/aa@4.1.0-alpha.1', expected: '@org/aa@^4.1.0-alpha.1' }, + { full: '@org/aa@next', expected: '@org/aa@next' }, + + { full: '@storybook/addon-onboarding@~4', expected: '@storybook/addon-onboarding@~4' }, + { full: '@storybook/addon-onboarding@next', expected: '@storybook/addon-onboarding@next' }, + { full: '@storybook/addon-onboarding', expected: '@storybook/addon-onboarding@^8.0.0' }, // takes it from the versions file + ]; + + test.each(testData)('$full', async ({ full, expected }) => { + const [input] = getVersionSpecifier(full); + + await add(full, { packageManager: 'npm', skipPostinstall: true }, MockedConsole); + + expect(MockedConfig.appendValueToArray).toHaveBeenCalledWith( + expect.arrayContaining(['addons']), + input + ); + + expect(MockedPackageManager.addDependencies).toHaveBeenCalledWith( + { installAsDevDependencies: true }, + [expected] + ); + }); +}); + +describe('add (extra)', () => { + test('not warning when installing the correct version of storybook', async () => { + await add( + '@storybook/addon-onboarding', + { packageManager: 'npm', skipPostinstall: true }, + MockedConsole + ); + + expect(MockedConsole.warn).not.toHaveBeenCalledWith( + `The version of @storybook/addon-onboarding you are installing is not the same as the version of Storybook you are using. This may lead to unexpected behavior.` + ); + }); + test('warning when installing a specific version of storybook', async () => { + await add( + '@storybook/addon-onboarding@2.0.0', + { packageManager: 'npm', skipPostinstall: true }, + MockedConsole + ); + + expect(MockedConsole.warn).toHaveBeenCalledWith( + `The version of @storybook/addon-onboarding you are installing is not the same as the version of Storybook you are using. This may lead to unexpected behavior.` + ); + }); + + test('postInstall', async () => { + await add( + '@storybook/addon-onboarding', + { packageManager: 'npm', skipPostinstall: false }, + MockedConsole + ); + + expect(MockedPostInstall.postinstallAddon).toHaveBeenCalledWith('@storybook/addon-onboarding', { + packageManager: 'npm', + }); + }); +}); diff --git a/code/lib/cli/src/add.ts b/code/lib/cli/src/add.ts index 0321ec966fd7..a19249ddb453 100644 --- a/code/lib/cli/src/add.ts +++ b/code/lib/cli/src/add.ts @@ -1,44 +1,31 @@ import { getStorybookInfo, serverRequire, - getCoercedStorybookVersion, - isCorePackage, JsPackageManagerFactory, + versions, type PackageManagerName, } from '@storybook/core-common'; import { readConfig, writeConfig } from '@storybook/csf-tools'; import { isAbsolute, join } from 'path'; import SemVer from 'semver'; import dedent from 'ts-dedent'; +import { postinstallAddon } from './postinstallAddon'; -const logger = console; - -interface PostinstallOptions { +export interface PostinstallOptions { packageManager: PackageManagerName; } -const postinstallAddon = async (addonName: string, options: PostinstallOptions) => { - try { - const modulePath = require.resolve(`${addonName}/postinstall`, { paths: [process.cwd()] }); - - const postinstall = require(modulePath); - - try { - logger.log(`Running postinstall script for ${addonName}`); - await postinstall(options); - } catch (e) { - logger.error(`Error running postinstall script for ${addonName}`); - logger.error(e); - } - } catch (e) { - // no postinstall script - } -}; - -const getVersionSpecifier = (addon: string) => { - const groups = /^(...*)@(.*)$/.exec(addon); +/** + * Extract the addon name and version specifier from the input string + * @param addon - the input string + * @returns [addonName, versionSpecifier] + * @example + * getVersionSpecifier('@storybook/addon-docs@7.0.1') => ['@storybook/addon-docs', '7.0.1'] + */ +export const getVersionSpecifier = (addon: string) => { + const groups = /^(@{0,1}[^@]+)(?:@(.+))?$/.exec(addon); if (groups) { - return [groups[0], groups[2]] as const; + return [groups[1], groups[2]] as const; } return [addon, undefined] as const; }; @@ -71,9 +58,11 @@ const checkInstalled = (addonName: string, main: any) => { */ export async function add( addon: string, - options: { packageManager: PackageManagerName; skipPostinstall: boolean } + options: { packageManager: PackageManagerName; skipPostinstall: boolean }, + logger = console ) { const { packageManager: pkgMgr } = options; + const [addonName, inputVersion] = getVersionSpecifier(addon); const packageManager = JsPackageManagerFactory.getPackageManager({ force: pkgMgr }); const packageJson = await packageManager.retrievePackageJson(); @@ -85,38 +74,38 @@ export async function add( `); } - if (checkInstalled(addon, requireMain(configDir))) { - throw new Error(dedent` - Addon ${addon} is already installed; we skipped adding it to your ${mainConfig}. - `); - } - - const [addonName, versionSpecifier] = getVersionSpecifier(addon); - if (!mainConfig) { logger.error('Unable to find storybook main.js config'); return; } + + if (checkInstalled(addonName, requireMain(configDir))) { + throw new Error(dedent` + Addon ${addonName} is already installed; we skipped adding it to your ${mainConfig}. + `); + } + const main = await readConfig(mainConfig); logger.log(`Verifying ${addonName}`); - const latestVersion = await packageManager.latestVersion(addonName); - if (!latestVersion) { - logger.error(`Unknown addon ${addonName}`); - } - // add to package.json + const storybookVersion = versions[addonName as keyof typeof versions] as string | undefined; const isStorybookAddon = addonName.startsWith('@storybook/'); - const isAddonFromCore = isCorePackage(addonName); - const storybookVersion = await getCoercedStorybookVersion(packageManager); - const version = versionSpecifier || (isAddonFromCore ? storybookVersion : latestVersion); + const version = + inputVersion || storybookVersion || (await packageManager.latestVersion(addonName)); + + if (storybookVersion && version !== storybookVersion) { + logger.warn( + `The version of ${addonName} you are installing is not the same as the version of Storybook you are using. This may lead to unexpected behavior.` + ); + } - const addonWithVersion = SemVer.valid(version) + const addonWithVersion = isValidVersion(version) ? `${addonName}@^${version}` : `${addonName}@${version}`; + logger.log(`Installing ${addonWithVersion}`); await packageManager.addDependencies({ installAsDevDependencies: true }, [addonWithVersion]); - // add to main.js logger.log(`Adding '${addon}' to main.js addons field.`); main.appendValueToArray(['addons'], addonName); await writeConfig(main); @@ -125,3 +114,6 @@ export async function add( await postinstallAddon(addonName, { packageManager: packageManager.type }); } } +function isValidVersion(version: string) { + return SemVer.valid(version) || version.match(/^\d+$/); +} diff --git a/code/lib/cli/src/postinstallAddon.ts b/code/lib/cli/src/postinstallAddon.ts new file mode 100644 index 000000000000..50719c29e29c --- /dev/null +++ b/code/lib/cli/src/postinstallAddon.ts @@ -0,0 +1,19 @@ +import type { PostinstallOptions } from './add'; + +export const postinstallAddon = async (addonName: string, options: PostinstallOptions) => { + try { + const modulePath = require.resolve(`${addonName}/postinstall`, { paths: [process.cwd()] }); + + const postinstall = require(modulePath); + + try { + console.log(`Running postinstall script for ${addonName}`); + await postinstall(options); + } catch (e) { + console.error(`Error running postinstall script for ${addonName}`); + console.error(e); + } + } catch (e) { + // no postinstall script + } +}; From 8f07e61ef02b3aa752da91576cf016367beaa454 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Mon, 4 Mar 2024 14:02:07 +0100 Subject: [PATCH 71/77] fixes --- code/lib/cli/src/add.test.ts | 25 ++++++++++++++----------- code/lib/cli/src/add.ts | 21 +++++++++++++++------ 2 files changed, 29 insertions(+), 17 deletions(-) diff --git a/code/lib/cli/src/add.test.ts b/code/lib/cli/src/add.test.ts index 2da3bd8e184b..16d86d7c6851 100644 --- a/code/lib/cli/src/add.test.ts +++ b/code/lib/cli/src/add.test.ts @@ -43,8 +43,9 @@ vi.mock('@storybook/core-common', () => { JsPackageManagerFactory: { getPackageManager: vi.fn(() => MockedPackageManager), }, + getCoercedStorybookVersion: vi.fn(() => '8.0.0'), versions: { - '@storybook/addon-onboarding': '8.0.0', + 'storybook/addon-docs': '^8.0.0', }, }; }); @@ -80,9 +81,9 @@ describe('add', () => { { full: '@org/aa@4.1.0-alpha.1', expected: '@org/aa@^4.1.0-alpha.1' }, { full: '@org/aa@next', expected: '@org/aa@next' }, - { full: '@storybook/addon-onboarding@~4', expected: '@storybook/addon-onboarding@~4' }, - { full: '@storybook/addon-onboarding@next', expected: '@storybook/addon-onboarding@next' }, - { full: '@storybook/addon-onboarding', expected: '@storybook/addon-onboarding@^8.0.0' }, // takes it from the versions file + { full: 'storybook/addon-docs@~4', expected: 'storybook/addon-docs@~4' }, + { full: 'storybook/addon-docs@next', expected: 'storybook/addon-docs@next' }, + { full: 'storybook/addon-docs', expected: 'storybook/addon-docs@^8.0.0' }, // takes it from the versions file ]; test.each(testData)('$full', async ({ full, expected }) => { @@ -105,35 +106,37 @@ describe('add', () => { describe('add (extra)', () => { test('not warning when installing the correct version of storybook', async () => { await add( - '@storybook/addon-onboarding', + 'storybook/addon-docs', { packageManager: 'npm', skipPostinstall: true }, MockedConsole ); expect(MockedConsole.warn).not.toHaveBeenCalledWith( - `The version of @storybook/addon-onboarding you are installing is not the same as the version of Storybook you are using. This may lead to unexpected behavior.` + expect.stringContaining(`is not the same as the version of Storybook you are using.`) ); }); - test('warning when installing a specific version of storybook', async () => { + test('warning when installing a core addon mismatching version of storybook', async () => { await add( - '@storybook/addon-onboarding@2.0.0', + 'storybook/addon-docs@2.0.0', { packageManager: 'npm', skipPostinstall: true }, MockedConsole ); expect(MockedConsole.warn).toHaveBeenCalledWith( - `The version of @storybook/addon-onboarding you are installing is not the same as the version of Storybook you are using. This may lead to unexpected behavior.` + expect.stringContaining( + `The version of storybook/addon-docs you are installing is not the same as the version of Storybook you are using. This may lead to unexpected behavior.` + ) ); }); test('postInstall', async () => { await add( - '@storybook/addon-onboarding', + 'storybook/addon-docs', { packageManager: 'npm', skipPostinstall: false }, MockedConsole ); - expect(MockedPostInstall.postinstallAddon).toHaveBeenCalledWith('@storybook/addon-onboarding', { + expect(MockedPostInstall.postinstallAddon).toHaveBeenCalledWith('storybook/addon-docs', { packageManager: 'npm', }); }); diff --git a/code/lib/cli/src/add.ts b/code/lib/cli/src/add.ts index a19249ddb453..a0ddcdbf7cb7 100644 --- a/code/lib/cli/src/add.ts +++ b/code/lib/cli/src/add.ts @@ -2,8 +2,9 @@ import { getStorybookInfo, serverRequire, JsPackageManagerFactory, - versions, + getCoercedStorybookVersion, type PackageManagerName, + versions, } from '@storybook/core-common'; import { readConfig, writeConfig } from '@storybook/csf-tools'; import { isAbsolute, join } from 'path'; @@ -45,6 +46,8 @@ const checkInstalled = (addonName: string, main: any) => { return !!existingAddon; }; +const isCoreAddon = (addonName: string) => !!versions[addonName as keyof typeof versions]; + /** * Install the given addon package and add it to main.js * @@ -88,10 +91,16 @@ export async function add( const main = await readConfig(mainConfig); logger.log(`Verifying ${addonName}`); - const storybookVersion = versions[addonName as keyof typeof versions] as string | undefined; - const isStorybookAddon = addonName.startsWith('@storybook/'); - const version = - inputVersion || storybookVersion || (await packageManager.latestVersion(addonName)); + const storybookVersion = await getCoercedStorybookVersion(packageManager); + + let version = inputVersion; + + if (!version && isCoreAddon(addonName) && storybookVersion) { + version = storybookVersion; + } + if (!version) { + version = await packageManager.latestVersion(addonName); + } if (storybookVersion && version !== storybookVersion) { logger.warn( @@ -110,7 +119,7 @@ export async function add( main.appendValueToArray(['addons'], addonName); await writeConfig(main); - if (!options.skipPostinstall && isStorybookAddon) { + if (!options.skipPostinstall && isCoreAddon(addonName)) { await postinstallAddon(addonName, { packageManager: packageManager.type }); } } From eacdd37e2b02846c98883a4f1b241a6058a718d0 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Mon, 4 Mar 2024 14:08:49 +0100 Subject: [PATCH 72/77] rename for clarity --- code/lib/cli/src/add.test.ts | 42 ++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/code/lib/cli/src/add.test.ts b/code/lib/cli/src/add.test.ts index 16d86d7c6851..868d0ff7057d 100644 --- a/code/lib/cli/src/add.test.ts +++ b/code/lib/cli/src/add.test.ts @@ -67,33 +67,33 @@ describe('getVersionSpecifier', (it) => { describe('add', () => { const testData = [ - { full: 'aa', expected: 'aa@^1.0.0' }, // resolves to the latest version - { full: 'aa@4', expected: 'aa@^4' }, - { full: 'aa@4.1.0', expected: 'aa@^4.1.0' }, - { full: 'aa@^4', expected: 'aa@^4' }, - { full: 'aa@~4', expected: 'aa@~4' }, - { full: 'aa@4.1.0-alpha.1', expected: 'aa@^4.1.0-alpha.1' }, - { full: 'aa@next', expected: 'aa@next' }, - - { full: '@org/aa', expected: '@org/aa@^1.0.0' }, - { full: '@org/aa@4', expected: '@org/aa@^4' }, - { full: '@org/aa@4.1.0', expected: '@org/aa@^4.1.0' }, - { full: '@org/aa@4.1.0-alpha.1', expected: '@org/aa@^4.1.0-alpha.1' }, - { full: '@org/aa@next', expected: '@org/aa@next' }, - - { full: 'storybook/addon-docs@~4', expected: 'storybook/addon-docs@~4' }, - { full: 'storybook/addon-docs@next', expected: 'storybook/addon-docs@next' }, - { full: 'storybook/addon-docs', expected: 'storybook/addon-docs@^8.0.0' }, // takes it from the versions file + { input: 'aa', expected: 'aa@^1.0.0' }, // resolves to the latest version + { input: 'aa@4', expected: 'aa@^4' }, + { input: 'aa@4.1.0', expected: 'aa@^4.1.0' }, + { input: 'aa@^4', expected: 'aa@^4' }, + { input: 'aa@~4', expected: 'aa@~4' }, + { input: 'aa@4.1.0-alpha.1', expected: 'aa@^4.1.0-alpha.1' }, + { input: 'aa@next', expected: 'aa@next' }, + + { input: '@org/aa', expected: '@org/aa@^1.0.0' }, + { input: '@org/aa@4', expected: '@org/aa@^4' }, + { input: '@org/aa@4.1.0', expected: '@org/aa@^4.1.0' }, + { input: '@org/aa@4.1.0-alpha.1', expected: '@org/aa@^4.1.0-alpha.1' }, + { input: '@org/aa@next', expected: '@org/aa@next' }, + + { input: 'storybook/addon-docs@~4', expected: 'storybook/addon-docs@~4' }, + { input: 'storybook/addon-docs@next', expected: 'storybook/addon-docs@next' }, + { input: 'storybook/addon-docs', expected: 'storybook/addon-docs@^8.0.0' }, // takes it from the versions file ]; - test.each(testData)('$full', async ({ full, expected }) => { - const [input] = getVersionSpecifier(full); + test.each(testData)('$full', async ({ input, expected }) => { + const [packageName] = getVersionSpecifier(input); - await add(full, { packageManager: 'npm', skipPostinstall: true }, MockedConsole); + await add(input, { packageManager: 'npm', skipPostinstall: true }, MockedConsole); expect(MockedConfig.appendValueToArray).toHaveBeenCalledWith( expect.arrayContaining(['addons']), - input + packageName ); expect(MockedPackageManager.addDependencies).toHaveBeenCalledWith( From 2d66683bf127e6d347b7dd555bcd3b0a49958ff8 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Mon, 4 Mar 2024 14:10:06 +0100 Subject: [PATCH 73/77] cleanup --- code/lib/cli/src/add.test.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/code/lib/cli/src/add.test.ts b/code/lib/cli/src/add.test.ts index 868d0ff7057d..b7bcf5b93ac5 100644 --- a/code/lib/cli/src/add.test.ts +++ b/code/lib/cli/src/add.test.ts @@ -19,7 +19,6 @@ const MockedPostInstall = vi.hoisted(() => { postinstallAddon: vi.fn(), }; }); - const MockedConsole = { log: vi.fn(), warn: vi.fn(), @@ -35,7 +34,6 @@ vi.mock('@storybook/csf-tools', () => { vi.mock('./postinstallAddon', () => { return MockedPostInstall; }); - vi.mock('@storybook/core-common', () => { return { getStorybookInfo: vi.fn(() => ({ mainConfig: {}, configDir: '' })), From be683bf8bc01ba945eb2072ab6bbec0ba3ab0d34 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Mon, 4 Mar 2024 14:16:52 +0100 Subject: [PATCH 74/77] use hasOwn, which is type-safe, no need for casting --- code/lib/cli/src/add.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/lib/cli/src/add.ts b/code/lib/cli/src/add.ts index a0ddcdbf7cb7..cc56b3f5695d 100644 --- a/code/lib/cli/src/add.ts +++ b/code/lib/cli/src/add.ts @@ -46,7 +46,7 @@ const checkInstalled = (addonName: string, main: any) => { return !!existingAddon; }; -const isCoreAddon = (addonName: string) => !!versions[addonName as keyof typeof versions]; +const isCoreAddon = (addonName: string) => Object.hasOwn(versions, addonName); /** * Install the given addon package and add it to main.js From 320fd3decd4400805634ef20e9f2bd234c1c9ae9 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Mon, 4 Mar 2024 16:14:12 +0100 Subject: [PATCH 75/77] found a flaw thanks to review from valentin --- code/lib/cli/src/add.test.ts | 31 +++++++++++++++++++++---------- code/lib/cli/src/add.ts | 2 +- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/code/lib/cli/src/add.test.ts b/code/lib/cli/src/add.test.ts index b7bcf5b93ac5..4dc12eb48986 100644 --- a/code/lib/cli/src/add.test.ts +++ b/code/lib/cli/src/add.test.ts @@ -43,7 +43,7 @@ vi.mock('@storybook/core-common', () => { }, getCoercedStorybookVersion: vi.fn(() => '8.0.0'), versions: { - 'storybook/addon-docs': '^8.0.0', + '@storybook/addon-docs': '^8.0.0', }, }; }); @@ -79,12 +79,12 @@ describe('add', () => { { input: '@org/aa@4.1.0-alpha.1', expected: '@org/aa@^4.1.0-alpha.1' }, { input: '@org/aa@next', expected: '@org/aa@next' }, - { input: 'storybook/addon-docs@~4', expected: 'storybook/addon-docs@~4' }, - { input: 'storybook/addon-docs@next', expected: 'storybook/addon-docs@next' }, - { input: 'storybook/addon-docs', expected: 'storybook/addon-docs@^8.0.0' }, // takes it from the versions file + { input: '@storybook/addon-docs@~4', expected: '@storybook/addon-docs@~4' }, + { input: '@storybook/addon-docs@next', expected: '@storybook/addon-docs@next' }, + { input: '@storybook/addon-docs', expected: '@storybook/addon-docs@^8.0.0' }, // takes it from the versions file ]; - test.each(testData)('$full', async ({ input, expected }) => { + test.each(testData)('$input', async ({ input, expected }) => { const [packageName] = getVersionSpecifier(input); await add(input, { packageManager: 'npm', skipPostinstall: true }, MockedConsole); @@ -104,7 +104,18 @@ describe('add', () => { describe('add (extra)', () => { test('not warning when installing the correct version of storybook', async () => { await add( - 'storybook/addon-docs', + '@storybook/addon-docs', + { packageManager: 'npm', skipPostinstall: true }, + MockedConsole + ); + + expect(MockedConsole.warn).not.toHaveBeenCalledWith( + expect.stringContaining(`is not the same as the version of Storybook you are using.`) + ); + }); + test('not warning when installing unrelated package', async () => { + await add( + '@storybook/addon-docs', { packageManager: 'npm', skipPostinstall: true }, MockedConsole ); @@ -115,26 +126,26 @@ describe('add (extra)', () => { }); test('warning when installing a core addon mismatching version of storybook', async () => { await add( - 'storybook/addon-docs@2.0.0', + '@storybook/addon-docs@2.0.0', { packageManager: 'npm', skipPostinstall: true }, MockedConsole ); expect(MockedConsole.warn).toHaveBeenCalledWith( expect.stringContaining( - `The version of storybook/addon-docs you are installing is not the same as the version of Storybook you are using. This may lead to unexpected behavior.` + `The version of @storybook/addon-docs you are installing is not the same as the version of Storybook you are using. This may lead to unexpected behavior.` ) ); }); test('postInstall', async () => { await add( - 'storybook/addon-docs', + '@storybook/addon-docs', { packageManager: 'npm', skipPostinstall: false }, MockedConsole ); - expect(MockedPostInstall.postinstallAddon).toHaveBeenCalledWith('storybook/addon-docs', { + expect(MockedPostInstall.postinstallAddon).toHaveBeenCalledWith('@storybook/addon-docs', { packageManager: 'npm', }); }); diff --git a/code/lib/cli/src/add.ts b/code/lib/cli/src/add.ts index cc56b3f5695d..19a4b552fcc0 100644 --- a/code/lib/cli/src/add.ts +++ b/code/lib/cli/src/add.ts @@ -102,7 +102,7 @@ export async function add( version = await packageManager.latestVersion(addonName); } - if (storybookVersion && version !== storybookVersion) { + if (isCoreAddon(addonName) && version !== storybookVersion) { logger.warn( `The version of ${addonName} you are installing is not the same as the version of Storybook you are using. This may lead to unexpected behavior.` ); From b6b98eb9912727d8de135b96e2ea3d3e85ae96da Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Mon, 4 Mar 2024 16:16:43 +0100 Subject: [PATCH 76/77] change package name for test --- code/lib/cli/src/add.test.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/code/lib/cli/src/add.test.ts b/code/lib/cli/src/add.test.ts index 4dc12eb48986..3025da275e49 100644 --- a/code/lib/cli/src/add.test.ts +++ b/code/lib/cli/src/add.test.ts @@ -114,11 +114,7 @@ describe('add (extra)', () => { ); }); test('not warning when installing unrelated package', async () => { - await add( - '@storybook/addon-docs', - { packageManager: 'npm', skipPostinstall: true }, - MockedConsole - ); + await add('aa', { packageManager: 'npm', skipPostinstall: true }, MockedConsole); expect(MockedConsole.warn).not.toHaveBeenCalledWith( expect.stringContaining(`is not the same as the version of Storybook you are using.`) From dc07edd92d94164690e619b0d5322c9e89ddb15e Mon Sep 17 00:00:00 2001 From: Valentin Palkovic Date: Tue, 5 Mar 2024 09:02:46 +0100 Subject: [PATCH 77/77] Update minimum Node.js version requirement --- code/lib/cli/bin/index.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/lib/cli/bin/index.js b/code/lib/cli/bin/index.js index 7131e95a311d..af7869a6e043 100755 --- a/code/lib/cli/bin/index.js +++ b/code/lib/cli/bin/index.js @@ -1,8 +1,8 @@ #!/usr/bin/env node -const majorNodeVersion = parseInt(process.version.toString().replace('v', '').split('.')[0], 10); -if (majorNodeVersion < 16) { - console.error('To run storybook you need to have node 16 or higher'); +const majorNodeVersion = parseInt(process.versions.node, 10); +if (majorNodeVersion < 18) { + console.error('To run Storybook you need to have Node.js 18 or higher'); process.exit(1); }