diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 63f79fa10..75ca2dfb9 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,48 +1,12 @@ # Contributing -## Requirements - -Before getting started, ensure your system has access to the following tools: - -- [Node.js](https://nodejs.org/) -- [Rustup](https://rustup.rs/) -- [pnpm](https://pnpm.io/) - -## Getting started - -```sh -# Install dependencies -pnpm install - -# Install Rust toolchain and WASM targets -rustup default stable -rustup target add wasm32-wasip1-threads - -# Build the project -pnpm build -``` - -## Development workflow - -During development, you can run tests in watch mode: - -```sh -pnpm tdd -``` - -The `playgrounds` directory contains example projects you can use to test your changes. To start the Vite playground, use: - -```sh -pnpm build && pnpm vite -``` - ## Bug fixes If you've found a bug in Tailwind that you'd like to fix, [submit a pull request](https://github.com/tailwindlabs/tailwindcss/pulls) with your changes. Include a helpful description of the problem and how your changes address it, and provide tests so we can verify the fix works as expected. ## New features -If there's a new feature you'd like to see added to Tailwind, [share your idea with us](https://github.com/tailwindlabs/tailwindcss/discussions/new?category=ideas) in our discussion forum to get it on our radar as something to consider for a future release before starting work on it. +If there's a new feature you'd like to see added to Tailwind, [share your idea with us](https://github.com/tailwindlabs/tailwindcss/discussions/new?category=ideas) in our discussion forum to get it on our radar as something to consider for a future release. **Please note that we don't often accept pull requests for new features.** Adding a new feature to Tailwind requires us to think through the entire problem ourselves to make sure we agree with the proposed API, which means the feature needs to be high on our own priority list for us to be able to give it the attention it needs. @@ -50,7 +14,7 @@ If you open a pull request for a new feature, we're likely to close it not becau ## Coding standards -Our code formatting rules are defined in the `"prettier"` section of [package.json](https://github.com/tailwindlabs/tailwindcss/blob/main/package.json). You can check your code against these standards by running: +Our code formatting rules are defined in the `"prettier"` section of [package.json](https://github.com/tailwindcss/tailwindcss/blob/next/package.json). You can check your code against these standards by running: ```sh pnpm run lint @@ -64,40 +28,10 @@ pnpm run format ## Running tests -You can run the TypeScript and Rust test suites using the following command: +You can run the test suite using the following commands: ```sh -pnpm test +pnpm build && pnpm test ``` -To run the integration tests, use: - -```sh -pnpm build && pnpm test:integrations -``` - -Additionally, some features require testing in browsers (i.e. to ensure CSS variable resolution works as expected). These can be run via: - -```sh -pnpm build && pnpm test:ui -``` - -Please ensure that all tests are passing when submitting a pull request. If you're adding new features to Tailwind CSS, always include tests. - -After a successful build, you can also use the npm package tarballs created inside the `dist/` folder to install your build in other local projects. - -## Pull request process - -When submitting a pull request: - -- Ensure the pull request title and description explain the changes you made and why you made them. -- Include a test plan section that outlines how you tested your contributions. We do not accept contributions without tests. -- Ensure all tests pass. You can add the tag `[ci-all]` in your pull request description to run the test suites across all platforms. - -When a pull request is created, Tailwind CSS maintainers will be notified automatically. - -## Communication - -- **GitHub discussions**: For feature ideas and general questions -- **GitHub issues**: For bug reports -- **GitHub pull requests**: For code contributions +Please ensure that the tests are passing when submitting a pull request. If you're adding new features to Tailwind, please include tests. diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index 848c851b1..000000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1 +0,0 @@ -custom: ['https://tailwindcss.com/sponsor'] diff --git a/.github/ISSUE_TEMPLATE/bug-report.md b/.github/ISSUE_TEMPLATE/bug-report.md deleted file mode 100644 index 1b8a310c6..000000000 --- a/.github/ISSUE_TEMPLATE/bug-report.md +++ /dev/null @@ -1,39 +0,0 @@ ---- -name: Bug report -about: If you've already asked for help with a problem and confirmed something is broken with Tailwind CSS itself, create a bug report. -title: '' -labels: '' -assignees: '' ---- - - - -**What version of Tailwind CSS are you using?** - -For example: v4.0.6 - -**What build tool (or framework if it abstracts the build tool) are you using?** - -For example: postcss-cli 11.0.0, Next.js 15.1.7, Vite 6.1.0 - -**What version of Node.js are you using?** - -For example: v20.0.0 - -**What browser are you using?** - -For example: Chrome, Safari, or N/A - -**What operating system are you using?** - -For example: macOS, Windows - -**Reproduction URL** - -A Tailwind Play link or public GitHub repo that includes a minimal reproduction of the bug. **Please do not link to your actual project**, what we need instead is a _minimal_ reproduction in a fresh project without any unnecessary code. This means it doesn't matter if your real project is private/confidential, since we want a link to a separate, isolated reproduction anyways. - -A reproduction is **required** when filing an issue — any issue opened without a reproduction will be closed and you'll be asked to create a new issue that includes a reproduction. We're a small team and we can't keep up with the volume of issues we receive if we need to reproduce each issue from scratch ourselves. - -**Describe your issue** - -Describe the problem you're seeing, any important steps to reproduce and what behavior you expect instead. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 10ee9a6b8..58166a010 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -6,6 +6,9 @@ contact_links: - name: Feature Request url: https://github.com/tailwindlabs/tailwindcss/discussions/new?category=ideas about: 'Suggest any ideas you have using our discussion forums.' + - name: Bug Report + url: https://github.com/tailwindlabs/tailwindcss/issues/new?body=%3C%21--%20Please%20provide%20all%20of%20the%20information%20requested%20below.%20We%27re%20a%20small%20team%20and%20without%20all%20of%20this%20information%20it%27s%20not%20possible%20for%20us%20to%20help%20and%20your%20bug%20report%20will%20be%20closed.%20--%3E%0A%0A%2A%2AWhat%20version%20of%20Tailwind%20CSS%20are%20you%20using%3F%2A%2A%0A%0AFor%20example%3A%20v2.0.4%0A%0A%2A%2AWhat%20build%20tool%20%28or%20framework%20if%20it%20abstracts%20the%20build%20tool%29%20are%20you%20using%3F%2A%2A%0A%0AFor%20example%3A%20postcss-cli%208.3.1%2C%20Next.js%2010.0.9%2C%20webpack%205.28.0%0A%0A%2A%2AWhat%20version%20of%20Node.js%20are%20you%20using%3F%2A%2A%0A%0AFor%20example%3A%20v12.0.0%0A%0A%2A%2AWhat%20browser%20are%20you%20using%3F%2A%2A%0A%0AFor%20example%3A%20Chrome%2C%20Safari%2C%20or%20N%2FA%0A%0A%2A%2AWhat%20operating%20system%20are%20you%20using%3F%2A%2A%0A%0AFor%20example%3A%20macOS%2C%20Windows%0A%0A%2A%2AReproduction%20URL%2A%2A%0A%0AA%20Tailwind%20Play%20link%20or%20public%20GitHub%20repo%20that%20includes%20a%20minimal%20reproduction%20of%20the%20bug.%20%2A%2APlease%20do%20not%20link%20to%20your%20actual%20project%2A%2A%2C%20what%20we%20need%20instead%20is%20a%20_minimal_%20reproduction%20in%20a%20fresh%20project%20without%20any%20unnecessary%20code.%20This%20means%20it%20doesn%27t%20matter%20if%20your%20real%20project%20is%20private%2Fconfidential%2C%20since%20we%20want%20a%20link%20to%20a%20separate%2C%20isolated%20reproduction%20anyways.%0A%0AA%20reproduction%20is%20%2A%2Arequired%2A%2A%20when%20filing%20an%20issue%20%E2%80%94%20any%20issue%20opened%20without%20a%20reproduction%20will%20be%20closed%20and%20you%27ll%20be%20asked%20to%20create%20a%20new%20issue%20that%20includes%20a%20reproduction.%20We%27re%20a%20small%20team%20and%20we%20can%27t%20keep%20up%20with%20the%20volume%20of%20issues%20we%20receive%20if%20we%20need%20to%20reproduce%20each%20issue%20from%20scratch%20ourselves.%0A%0A%2A%2ADescribe%20your%20issue%2A%2A%0A%0ADescribe%20the%20problem%20you%27re%20seeing%2C%20any%20important%20steps%20to%20reproduce%20and%20what%20behavior%20you%20expect%20instead. + about: If you've already asked for help with a problem and confirmed something is broken with Tailwind CSS itself, create a bug report. - name: Documentation Issue url: https://github.com/tailwindlabs/tailwindcss.com about: 'For documentation issues, suggest changes on our documentation repository.' diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index aa0793aa3..ce7fafb97 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -4,26 +4,8 @@ **Please ask first before starting work on any significant new features.** -It's never a fun experience to have your pull request declined after investing a lot of time and effort into a new feature. To avoid this from happening, we request that contributors create a discussion to first discuss any significant new features. +It's never a fun experience to have your pull request declined after investing a lot of time and effort into a new feature. To avoid this from happening, we request that contributors create an issue to first discuss any significant new features. This includes things like adding new utilities, creating new at-rules, or adding new component examples to the documentation. -For more info, check out the contributing guide: - -https://github.com/tailwindlabs/tailwindcss/blob/main/.github/CONTRIBUTING.md - ---> - -## Summary - - - -## Test plan - - diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5ae59e80f..54512c071 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,24 +2,18 @@ name: CI on: push: - branches: [main] + branches: [next] pull_request: permissions: contents: read -env: - NODE_VERSION: 24 - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - jobs: tests: strategy: fail-fast: false matrix: + node-version: [20] runner: - name: Windows os: windows-latest @@ -27,19 +21,17 @@ jobs: - name: Linux os: namespace-profile-default - # Playwright 1.62+ dropped WebKit support for macOS 14, and hangs - # instead of failing when launching WebKit on a macos-14 runner. - name: macOS - os: macos-15 + os: macos-14 # Exclude windows and macos from being built on feature branches - run-all: - - ${{ github.ref == 'refs/heads/main' || contains(github.event.pull_request.body, '[ci-all]') || github.event.pull_request.user.login == 'depfu[bot]' }} + on-next-branch: + - ${{ github.ref == 'refs/heads/next' }} exclude: - - run-all: false + - on-next-branch: false runner: name: Windows - - run-all: false + - on-next-branch: false runner: name: macOS @@ -49,21 +41,21 @@ jobs: name: ${{ matrix.runner.name }} steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - with: - persist-credentials: false - - uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9 + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 - - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 with: - node-version: ${{ env.NODE_VERSION }} + node-version: ${{ matrix.node-version }} + cache: 'pnpm' # Cargo already skips downloading dependencies if they already exist - name: Cache cargo - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 + uses: actions/cache@v4 with: path: | + ~/.cargo/bin/ ~/.cargo/registry/index/ ~/.cargo/registry/cache/ ~/.cargo/git/db/ @@ -72,25 +64,17 @@ jobs: # Cache the `oxide` Rust build - name: Cache oxide build - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 + uses: actions/cache@v4 with: path: | + ./target/ ./crates/node/*.node - ./crates/node/*.wasm - ./crates/node/index.d.ts ./crates/node/index.js - ./crates/node/browser.js - ./crates/node/tailwindcss-oxide.wasi-browser.js - ./crates/node/tailwindcss-oxide.wasi.cjs - ./crates/node/wasi-worker-browser.mjs - ./crates/node/wasi-worker.mjs + ./crates/node/index.d.ts key: ${{ runner.os }}-oxide-${{ hashFiles('./crates/**/*') }} - - name: Setup WASM target - run: rustup target add wasm32-wasip1-threads - - name: Install dependencies - run: pnpm install --frozen-lockfile + run: pnpm install - name: Build run: pnpm run build @@ -112,13 +96,9 @@ jobs: - name: Run Playwright tests run: npm run test:ui - notify: - if: ${{ always() && github.ref == 'refs/heads/main' && needs.tests.result == 'failure' }} - needs: tests - runs-on: ubuntu-latest - steps: - name: Notify Discord - uses: discord-actions/message@5c7149c81a83146e5d01f142be1bf87a61831c4d # v2 + if: failure() && github.ref == 'refs/heads/next' + uses: discord-actions/message@v2 with: webhookUrl: ${{ secrets.DISCORD_WEBHOOK_URL }} - message: 'The [most recent ${{ github.workflow }} workflow](<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}>) on the `main` branch has failed.' + message: 'The [most recent build](<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}>) on the `next` branch has failed.' diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 457c38424..d61223ae7 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -2,24 +2,19 @@ name: Integration Tests on: push: - branches: [main] + branches: [next] pull_request: permissions: contents: read -env: - NODE_VERSION: 24 - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - jobs: tests: strategy: fail-fast: false matrix: + node-version: [20] + runner: - name: Windows os: windows-latest @@ -35,17 +30,15 @@ jobs: - vite - cli - postcss - - oxide - - webpack # Exclude windows and macos from being built on feature branches - run-all: - - ${{ github.ref == 'refs/heads/main' || contains(github.event.pull_request.body, '[ci-all]') }} + on-next-branch: + - ${{ github.ref == 'refs/heads/next' }} exclude: - - run-all: false + - on-next-branch: false runner: name: Windows - - run-all: false + - on-next-branch: false runner: name: macOS @@ -55,25 +48,21 @@ jobs: name: ${{ matrix.runner.name }} / ${{ matrix.integration }} steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - with: - persist-credentials: false - - uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9 + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 - - run: | - git config --global user.name "github-actions[bot]" - git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com" - - - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v4 with: - node-version: ${{ env.NODE_VERSION }} + node-version: ${{ matrix.node-version }} + cache: 'pnpm' # Cargo already skips downloading dependencies if they already exist - name: Cache cargo - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 + uses: actions/cache@v4 with: path: | + ~/.cargo/bin/ ~/.cargo/registry/index/ ~/.cargo/registry/cache/ ~/.cargo/git/db/ @@ -82,23 +71,15 @@ jobs: # Cache the `oxide` Rust build - name: Cache oxide build - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5 + uses: actions/cache@v4 with: path: | + ./target/ ./crates/node/*.node - ./crates/node/*.wasm - ./crates/node/index.d.ts ./crates/node/index.js - ./crates/node/browser.js - ./crates/node/tailwindcss-oxide.wasi-browser.js - ./crates/node/tailwindcss-oxide.wasi.cjs - ./crates/node/wasi-worker-browser.mjs - ./crates/node/wasi-worker.mjs + ./crates/node/index.d.ts key: ${{ runner.os }}-oxide-${{ hashFiles('./crates/**/*') }} - - name: Setup WASM target - run: rustup target add wasm32-wasip1-threads - - name: Install dependencies run: pnpm install @@ -113,13 +94,9 @@ jobs: env: GITHUB_WORKSPACE: ${{ github.workspace }} - notify: - if: ${{ always() && github.ref == 'refs/heads/main' && needs.tests.result == 'failure' }} - needs: tests - runs-on: ubuntu-latest - steps: - name: Notify Discord - uses: discord-actions/message@5c7149c81a83146e5d01f142be1bf87a61831c4d # v2 + if: failure() && github.ref == 'refs/heads/next' + uses: discord-actions/message@v2 with: webhookUrl: ${{ secrets.DISCORD_WEBHOOK_URL }} - message: 'The [most recent ${{ github.workflow }} workflow](<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}>) on the `main` branch has failed.' + message: 'The [most recent build](<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}>) on the `next` branch has failed.' diff --git a/.github/workflows/prepare-release.yml b/.github/workflows/prepare-release.yml index 24e829afd..0c4979b2b 100644 --- a/.github/workflows/prepare-release.yml +++ b/.github/workflows/prepare-release.yml @@ -2,306 +2,21 @@ name: Prepare Release on: workflow_dispatch: - inputs: - dry_run: - description: Skip creating the draft GitHub release - required: false - default: true - type: boolean - push: - tags: - - 'v*' env: - APP_NAME: tailwindcss-oxide - NODE_VERSION: 24 - PNPM_VERSION: '11.9.0' - OXIDE_LOCATION: ./crates/node + CI: true permissions: contents: read -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - jobs: build: + runs-on: macos-12 + timeout-minutes: 15 + strategy: matrix: - include: - # Windows - - os: windows-latest - target: x86_64-pc-windows-msvc - - os: windows-latest - target: aarch64-pc-windows-msvc - # macOS - - os: macos-latest - target: x86_64-apple-darwin - strip: strip -x # Must use -x on macOS. This produces larger results on linux. - - os: macos-latest - target: aarch64-apple-darwin - page-size: 14 - strip: strip -x # Must use -x on macOS. This produces larger results on linux. - # Android - - os: ubuntu-latest - target: aarch64-linux-android - strip: ${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip - - os: ubuntu-latest - target: armv7-linux-androideabi - strip: ${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip - # Linux - - os: ubuntu-latest - target: x86_64-unknown-linux-gnu - strip: strip - build-flags: --use-napi-cross - - os: ubuntu-latest - target: aarch64-unknown-linux-gnu - strip: aarch64-linux-gnu-strip - build-flags: --use-napi-cross - - os: ubuntu-latest - target: armv7-unknown-linux-gnueabihf - strip: arm-linux-gnueabihf-strip - build-flags: --use-napi-cross - - os: ubuntu-latest - target: aarch64-unknown-linux-musl - strip-zig: true - build-flags: -x - - os: ubuntu-latest - target: x86_64-unknown-linux-musl - strip: strip - build-flags: -x - - name: Build ${{ matrix.target }} (oxide) - runs-on: ${{ matrix.os }} - timeout-minutes: 15 - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - with: - persist-credentials: false - - uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9 - with: - version: ${{ env.PNPM_VERSION }} - - - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 - with: - node-version: ${{ env.NODE_VERSION }} - package-manager-cache: false - - - name: Install gcc-arm-linux-gnueabihf - if: ${{ matrix.target == 'armv7-unknown-linux-gnueabihf' }} - run: | - sudo apt-get update - sudo apt-get install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf -y - - - name: Install binutils-aarch64-linux-gnu - if: ${{ matrix.target == 'aarch64-unknown-linux-gnu' }} - run: | - sudo apt-get update - sudo apt-get install binutils-aarch64-linux-gnu -y - - - uses: mlugg/setup-zig@d1434d08867e3ee9daa34448df10607b98908d29 # v2 - if: ${{ contains(matrix.target, 'musl') }} - with: - version: 0.14.1 - use-cache: false - - - name: Install cargo-zigbuild - uses: taiki-e/install-action@65851e10cd6c377f11a60e600abc07cb08643468 # v2 - if: ${{ contains(matrix.target, 'musl') }} - env: - GITHUB_TOKEN: ${{ github.token }} - with: - tool: cargo-zigbuild - - - name: Setup rust target - run: rustup target add ${{ matrix.target }} - - - name: Install dependencies - run: pnpm install --ignore-scripts --frozen-lockfile --filter=!./playgrounds/* - - - name: Build release - run: pnpm run --filter ${{ env.OXIDE_LOCATION }} build:platform --target=${{ matrix.target }} ${{ matrix.build-flags }} - env: - RUST_TARGET: ${{ matrix.target }} - JEMALLOC_SYS_WITH_LG_PAGE: ${{ matrix.page-size }} - - - name: Strip debug symbols # https://github.com/rust-lang/rust/issues/46034 - if: ${{ matrix.strip || matrix.strip-zig }} - env: - STRIP_COMMAND: ${{ matrix.strip }} - STRIP_ZIG: ${{ matrix.strip-zig }} - run: | - if [ "$STRIP_ZIG" = "true" ]; then - for file in ${{ env.OXIDE_LOCATION }}/*.node; do - zig objcopy --strip-all "$file" "$file.stripped" - mv "$file.stripped" "$file" - done - exit 0 - fi - - eval "$STRIP_COMMAND ${{ env.OXIDE_LOCATION }}/*.node" - - - name: Upload artifacts - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - with: - name: bindings-${{ matrix.target }} - path: ${{ env.OXIDE_LOCATION }}/*.node - - build-freebsd: - name: Build x86_64-unknown-freebsd (OXIDE) - runs-on: ubuntu-latest - timeout-minutes: 15 - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - with: - persist-credentials: false - - name: Build FreeBSD - uses: cross-platform-actions/action@cdc9ee69ef84a5f2e59c9058335d9c57bcb4ac86 # v0.25.0 - env: - DEBUG: napi:* - RUSTUP_HOME: /usr/local/rustup - CARGO_HOME: /usr/local/cargo - RUSTUP_IO_THREADS: 1 - RUST_TARGET: x86_64-unknown-freebsd - with: - operating_system: freebsd - version: '14.0' - memory: 13G - cpu_count: 3 - environment_variables: 'DEBUG RUSTUP_IO_THREADS' - shell: bash - run: | - sudo pkg install -y -f curl node libnghttp2 npm - sudo npm install -g pnpm@${{ env.PNPM_VERSION }} --unsafe-perm=true - curl -sSf https://static.rust-lang.org/rustup/archive/1.27.1/x86_64-unknown-freebsd/rustup-init --output rustup-init - chmod +x rustup-init - ./rustup-init -y --profile minimal - source "$HOME/.cargo/env" - pnpm install --ignore-scripts --frozen-lockfile --filter=!./playgrounds/* || true - echo "~~~~ rustc --version ~~~~" - rustc --version - echo "~~~~ node -v ~~~~" - node -v - echo "~~~~ pnpm --version ~~~~" - pnpm --version - pnpm run --filter ${{ env.OXIDE_LOCATION }} build:platform - strip -x ${{ env.OXIDE_LOCATION }}/*.node - ls -la ${{ env.OXIDE_LOCATION }} - - name: Upload artifacts - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - with: - name: bindings-x86_64-unknown-freebsd - path: ${{ env.OXIDE_LOCATION }}/*.node - - prepare: - runs-on: macos-14 - timeout-minutes: 15 - name: Build and release Tailwind CSS - - permissions: - contents: write # Required for creating releases - - needs: - - build - - build-freebsd + node-version: [16] steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - with: - fetch-depth: 20 - persist-credentials: false - - - run: git fetch --tags -f - - - name: Resolve version - id: vars - run: | - echo "TAG_NAME=$(git describe --tags --abbrev=0)" >> $GITHUB_ENV - - - uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9 - with: - version: ${{ env.PNPM_VERSION }} - - - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 - with: - node-version: ${{ env.NODE_VERSION }} - registry-url: 'https://registry.npmjs.org' - package-manager-cache: false - - - name: Setup WASM target - run: rustup target add wasm32-wasip1-threads - - - name: Install dependencies - run: pnpm --filter=!./playgrounds/* install --frozen-lockfile - - - name: Download artifacts - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7 - with: - path: ${{ env.OXIDE_LOCATION }} - - - name: Move artifacts - run: | - cd ${{ env.OXIDE_LOCATION }} - cp bindings-x86_64-pc-windows-msvc/* ./npm/win32-x64-msvc/ - cp bindings-aarch64-pc-windows-msvc/* ./npm/win32-arm64-msvc/ - cp bindings-x86_64-apple-darwin/* ./npm/darwin-x64/ - cp bindings-aarch64-apple-darwin/* ./npm/darwin-arm64/ - cp bindings-aarch64-linux-android/* ./npm/android-arm64/ - cp bindings-armv7-linux-androideabi/* ./npm/android-arm-eabi/ - cp bindings-aarch64-unknown-linux-gnu/* ./npm/linux-arm64-gnu/ - cp bindings-aarch64-unknown-linux-musl/* ./npm/linux-arm64-musl/ - cp bindings-armv7-unknown-linux-gnueabihf/* ./npm/linux-arm-gnueabihf/ - cp bindings-x86_64-unknown-linux-gnu/* ./npm/linux-x64-gnu/ - cp bindings-x86_64-unknown-linux-musl/* ./npm/linux-x64-musl/ - cp bindings-x86_64-unknown-freebsd/* ./npm/freebsd-x64/ - - - name: Build Tailwind CSS - run: pnpm run build - env: - FEATURES_ENV: stable - - - name: Run pre-publish optimizations scripts - run: node ./scripts/pre-publish-optimizations.mjs - - - name: Lock pre-release versions - run: node ./scripts/lock-pre-release-versions.mjs - - - name: Get release notes - run: | - RELEASE_NOTES=$(node ./scripts/release-notes.mjs) - echo "RELEASE_NOTES<> $GITHUB_ENV - echo "$RELEASE_NOTES" >> $GITHUB_ENV - echo "EOF" >> $GITHUB_ENV - - - name: Upload standalone artifacts - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - with: - name: tailwindcss-standalone - path: packages/@tailwindcss-standalone/dist/ - - - name: Upload npm package tarballs - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - with: - name: npm-package-tarballs - path: dist/*.tgz - - - name: Prepare GitHub Release - if: ${{ !inputs.dry_run }} - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - gh release create "${TAG_NAME}" \ - --draft \ - --title "${TAG_NAME}" \ - --notes "${RELEASE_NOTES}" \ - packages/@tailwindcss-standalone/dist/sha256sums.txt \ - packages/@tailwindcss-standalone/dist/tailwindcss-linux-arm64 \ - packages/@tailwindcss-standalone/dist/tailwindcss-linux-arm64-musl \ - packages/@tailwindcss-standalone/dist/tailwindcss-linux-x64 \ - packages/@tailwindcss-standalone/dist/tailwindcss-linux-x64-musl \ - packages/@tailwindcss-standalone/dist/tailwindcss-macos-arm64 \ - packages/@tailwindcss-standalone/dist/tailwindcss-macos-x64 \ - packages/@tailwindcss-standalone/dist/tailwindcss-windows-x64.exe + - run: echo "stub" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2c957d3af..64abf817a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,34 +1,22 @@ name: Release on: - push: - branches: [main] - release: - types: [published] workflow_dispatch: inputs: - channel: - description: Release channel to publish - required: true - default: insiders - type: choice - options: - - insiders - - release + release_channel: + description: 'Release channel' + required: false + default: 'next' + type: string permissions: contents: read env: APP_NAME: tailwindcss-oxide - NODE_VERSION: 24 - PNPM_VERSION: '11.9.0' + NODE_VERSION: 20 OXIDE_LOCATION: ./crates/node -concurrency: - group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.ref }} - cancel-in-progress: true - jobs: build: strategy: @@ -58,207 +46,163 @@ jobs: - os: ubuntu-latest target: x86_64-unknown-linux-gnu strip: strip - build-flags: --use-napi-cross + container: + image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian - os: ubuntu-latest target: aarch64-unknown-linux-gnu - strip: aarch64-linux-gnu-strip - build-flags: --use-napi-cross + strip: llvm-strip + container: + image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian-aarch64 - os: ubuntu-latest target: armv7-unknown-linux-gnueabihf - strip: arm-linux-gnueabihf-strip - build-flags: --use-napi-cross + strip: llvm-strip + container: + image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian-zig - os: ubuntu-latest target: aarch64-unknown-linux-musl - strip-zig: true - build-flags: -x + strip: aarch64-linux-musl-strip + download: true + container: + image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-alpine - os: ubuntu-latest target: x86_64-unknown-linux-musl strip: strip - build-flags: -x + download: true + container: + image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-alpine - name: Build ${{ matrix.target }} (oxide) + name: Build ${{ matrix.target }} (OXIDE) runs-on: ${{ matrix.os }} + container: ${{ matrix.container }} timeout-minutes: 15 steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - with: - persist-credentials: false - - uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9 - with: - version: ${{ env.PNPM_VERSION }} + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 + uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} - package-manager-cache: false + cache: 'pnpm' - - name: Install gcc-arm-linux-gnueabihf - if: ${{ matrix.target == 'armv7-unknown-linux-gnueabihf' }} - run: | - sudo apt-get update - sudo apt-get install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf -y - - - name: Install binutils-aarch64-linux-gnu - if: ${{ matrix.target == 'aarch64-unknown-linux-gnu' }} - run: | - sudo apt-get update - sudo apt-get install binutils-aarch64-linux-gnu -y - - - uses: mlugg/setup-zig@d1434d08867e3ee9daa34448df10607b98908d29 # v2 - if: ${{ contains(matrix.target, 'musl') }} + # Cargo already skips downloading dependencies if they already exist + - name: Cache cargo + uses: actions/cache@v4 with: - version: 0.14.1 - use-cache: false + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + target/ + key: ${{ runner.os }}-${{ matrix.target }}-cargo-${{ hashFiles('**/Cargo.lock') }} - - name: Install cargo-zigbuild - uses: taiki-e/install-action@65851e10cd6c377f11a60e600abc07cb08643468 # v2 - if: ${{ contains(matrix.target, 'musl') }} - env: - GITHUB_TOKEN: ${{ github.token }} + # Cache the `oxide` Rust build + - name: Cache oxide build + uses: actions/cache@v4 with: - tool: cargo-zigbuild + path: | + ./oxide/target/ + ./crates/node/*.node + ./crates/node/index.js + ./crates/node/index.d.ts + key: ${{ runner.os }}-${{ matrix.target }}-oxide-${{ hashFiles('./crates/**/*') }} + + - name: Install Node.JS + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + + - name: Install Rust (Stable) + if: ${{ matrix.download }} + run: | + rustup default stable - name: Setup rust target run: rustup target add ${{ matrix.target }} - name: Install dependencies - run: pnpm install --ignore-scripts --frozen-lockfile --filter=!./playgrounds/* + run: pnpm install --ignore-scripts --filter=!./playgrounds/* - name: Build release - run: pnpm run --filter ${{ env.OXIDE_LOCATION }} build:platform --target=${{ matrix.target }} ${{ matrix.build-flags }} + run: pnpm run --filter ${{ env.OXIDE_LOCATION }} build env: RUST_TARGET: ${{ matrix.target }} JEMALLOC_SYS_WITH_LG_PAGE: ${{ matrix.page-size }} - name: Strip debug symbols # https://github.com/rust-lang/rust/issues/46034 - if: ${{ matrix.strip || matrix.strip-zig }} - env: - STRIP_COMMAND: ${{ matrix.strip }} - STRIP_ZIG: ${{ matrix.strip-zig }} - run: | - if [ "$STRIP_ZIG" = "true" ]; then - for file in ${{ env.OXIDE_LOCATION }}/*.node; do - zig objcopy --strip-all "$file" "$file.stripped" - mv "$file.stripped" "$file" - done - exit 0 - fi - - eval "$STRIP_COMMAND ${{ env.OXIDE_LOCATION }}/*.node" + if: ${{ matrix.strip }} + run: ${{ matrix.strip }} ${{ env.OXIDE_LOCATION }}/*.node - name: Upload artifacts - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 + uses: actions/upload-artifact@v4 with: name: bindings-${{ matrix.target }} path: ${{ env.OXIDE_LOCATION }}/*.node - build-freebsd: - name: Build x86_64-unknown-freebsd (OXIDE) - runs-on: ubuntu-latest - timeout-minutes: 15 - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - with: - persist-credentials: false - - name: Build FreeBSD - uses: cross-platform-actions/action@cdc9ee69ef84a5f2e59c9058335d9c57bcb4ac86 # v0.25.0 - env: - DEBUG: napi:* - RUSTUP_HOME: /usr/local/rustup - CARGO_HOME: /usr/local/cargo - RUSTUP_IO_THREADS: 1 - RUST_TARGET: x86_64-unknown-freebsd - with: - operating_system: freebsd - version: '14.0' - memory: 13G - cpu_count: 3 - environment_variables: 'DEBUG RUSTUP_IO_THREADS' - shell: bash - run: | - sudo pkg install -y -f curl node libnghttp2 npm - sudo npm install -g pnpm@${{ env.PNPM_VERSION }} --unsafe-perm=true - curl -sSf https://static.rust-lang.org/rustup/archive/1.27.1/x86_64-unknown-freebsd/rustup-init --output rustup-init - chmod +x rustup-init - ./rustup-init -y --profile minimal - source "$HOME/.cargo/env" - echo "~~~~ rustc --version ~~~~" - rustc --version - echo "~~~~ node -v ~~~~" - node -v - echo "~~~~ pnpm --version ~~~~" - pnpm --version - pnpm install --ignore-scripts --frozen-lockfile --filter=!./playgrounds/* || true - pnpm run --filter ${{ env.OXIDE_LOCATION }} build:platform - strip -x ${{ env.OXIDE_LOCATION }}/*.node - ls -la ${{ env.OXIDE_LOCATION }} - - name: Upload artifacts - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 - with: - name: bindings-x86_64-unknown-freebsd - path: ${{ env.OXIDE_LOCATION }}/*.node - release: runs-on: macos-14 timeout-minutes: 15 - name: Build and publish Tailwind CSS + name: Build and release Tailwind CSS permissions: - contents: read + contents: write # for softprops/action-gh-release to create GitHub release # https://docs.npmjs.com/generating-provenance-statements#publishing-packages-with-provenance-via-github-actions id-token: write needs: - build - - build-freebsd steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + - uses: actions/checkout@v4 with: + fetch-tags: true fetch-depth: 20 - persist-credentials: false - - uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9 - with: - version: ${{ env.PNPM_VERSION }} + - run: git fetch --tags -f + + - name: Resolve version + id: vars + run: | + echo "TAG_NAME=$(git describe --tags --abbrev=0)" >> $GITHUB_ENV + + - uses: pnpm/action-setup@v4 - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6 + uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} + cache: 'pnpm' registry-url: 'https://registry.npmjs.org' - package-manager-cache: false - # npm trusted publishing validates the caller workflow filename, so all npm publishes live here. - # This workflow rebuilds the publish artifacts instead of depending on prepare-release.yml. - - name: Resolve release metadata - env: - INPUT_CHANNEL: ${{ github.event.inputs.channel || '' }} - run: | - if [[ "${{ github.event_name }}" == "release" || "$INPUT_CHANNEL" == "release" ]]; then - release_channel=$(node ./scripts/release-channel.js) + # Cargo already skips downloading dependencies if they already exist + - name: Cache cargo + uses: actions/cache@v4 + with: + path: | + ~/.cargo/bin/ + ~/.cargo/registry/index/ + ~/.cargo/registry/cache/ + ~/.cargo/git/db/ + target/ + key: ${{ runner.os }}-${{ matrix.target }}-cargo-${{ hashFiles('**/Cargo.lock') }} - echo "RELEASE_KIND=release" >> $GITHUB_ENV - echo "RELEASE_CHANNEL=$release_channel" >> $GITHUB_ENV - echo "FEATURES_ENV=stable" >> $GITHUB_ENV - else - sha_short=$(git rev-parse --short HEAD) - - echo "RELEASE_KIND=insiders" >> $GITHUB_ENV - echo "RELEASE_CHANNEL=insiders" >> $GITHUB_ENV - echo "SHA_SHORT=$sha_short" >> $GITHUB_ENV - echo "INSIDERS_VERSION=0.0.0-insiders.$sha_short" >> $GITHUB_ENV - fi - - - name: Setup WASM target - run: rustup target add wasm32-wasip1-threads + # Cache the `oxide` Rust build + - name: Cache oxide build + uses: actions/cache@v4 + with: + path: | + ./oxide/target/ + ./crates/node/*.node + ./crates/node/index.js + ./crates/node/index.d.ts + key: ${{ runner.os }}-${{ matrix.target }}-oxide-${{ hashFiles('./crates/**/*') }} - name: Install dependencies - run: pnpm --filter=!./playgrounds/* install --frozen-lockfile + run: pnpm --filter=!./playgrounds/* install - name: Download artifacts - uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7 + uses: actions/download-artifact@v4 with: path: ${{ env.OXIDE_LOCATION }} @@ -276,83 +220,52 @@ jobs: cp bindings-armv7-unknown-linux-gnueabihf/* ./npm/linux-arm-gnueabihf/ cp bindings-x86_64-unknown-linux-gnu/* ./npm/linux-x64-gnu/ cp bindings-x86_64-unknown-linux-musl/* ./npm/linux-x64-musl/ - cp bindings-x86_64-unknown-freebsd/* ./npm/freebsd-x64/ - - - name: 'Version based on commit: ${{ env.INSIDERS_VERSION }}' - if: env.RELEASE_KIND == 'insiders' - run: pnpm run version-packages ${INSIDERS_VERSION} - name: Build Tailwind CSS - if: env.RELEASE_KIND == 'insiders' run: pnpm run build - - name: Build Tailwind CSS - if: env.RELEASE_KIND == 'release' - run: pnpm run build - env: - FEATURES_ENV: ${{ env.FEATURES_ENV }} - - name: Run pre-publish optimizations scripts run: node ./scripts/pre-publish-optimizations.mjs - name: Lock pre-release versions run: node ./scripts/lock-pre-release-versions.mjs - - name: Upload npm package tarballs - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 + - name: Get release notes + run: | + RELEASE_NOTES=$(node ./scripts/release-notes.mjs) + echo "RELEASE_NOTES<> $GITHUB_ENV + echo "$RELEASE_NOTES" >> $GITHUB_ENV + echo "EOF" >> $GITHUB_ENV + + - name: Upload Standalone Artifacts + uses: actions/upload-artifact@v4 with: - name: npm-package-tarballs - path: dist/*.tgz + name: tailwindcss-standalone + path: packages/@tailwindcss-standalone/dist/ - name: Publish - run: | - pnpm --recursive --filter="!@tailwindcss/oxide-wasm32-wasi" publish --tag ${RELEASE_CHANNEL} --no-git-checks - # The wasm package needs a special npm config that isn't read when pnpm --recursive is used - pushd crates/node/npm/wasm32-wasi; pnpm publish --tag ${RELEASE_CHANNEL} --no-git-checks --config.node-linker=hoisted; popd; - - - name: Trigger Tailwind Play update - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 - with: - github-token: ${{ secrets.TAILWIND_PLAY_TOKEN }} - script: | - await github.rest.actions.createWorkflowDispatch({ - owner: 'tailwindlabs', - repo: 'upgrades', - ref: 'main', - workflow_id: 'upgrade-tailwindcss.yml' - }) - - notify: - if: ${{ always() && (needs.build.result == 'failure' || needs.build-freebsd.result == 'failure' || needs.release.result == 'failure') }} - needs: - - build - - build-freebsd - - release - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 - with: - persist-credentials: false - - - name: Resolve release label - id: release + run: pnpm --recursive publish --tag ${{ inputs.release_channel }} --no-git-checks env: - INPUT_CHANNEL: ${{ github.event.inputs.channel || '' }} - RELEASE_TAG: ${{ github.event.release.tag_name || '' }} - run: | - if [[ "${{ github.event_name }}" == "release" ]]; then - tag_name="${RELEASE_TAG:-${GITHUB_REF_NAME}}" - echo "label=release ${tag_name}" >> $GITHUB_OUTPUT - elif [[ "$INPUT_CHANNEL" == "release" ]]; then - version=$(node -p "require('./packages/tailwindcss/package.json').version") - echo "label=release v${version}" >> $GITHUB_OUTPUT - else - sha_short=$(git rev-parse --short HEAD) - echo "label=insiders release 0.0.0-insiders.${sha_short}" >> $GITHUB_OUTPUT - fi + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - - name: Notify Discord - uses: discord-actions/message@5c7149c81a83146e5d01f142be1bf87a61831c4d # v2 + - name: Alias packages to `latest` + if: ${{ inputs.release_channel == "next" }} + run: | + npm dist-tag add @tailwindcss/upgrade@${{ env.TAG_NAME }} latest + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + + - name: Release + uses: softprops/action-gh-release@v2 with: - webhookUrl: ${{ secrets.DISCORD_WEBHOOK_URL }} - message: 'The [most recent ${{ github.workflow }} workflow](<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}>) for `${{ steps.release.outputs.label }}` has failed.' + draft: true + tag_name: ${{ env.TAG_NAME }} + body: | + ${{ env.RELEASE_NOTES }} + files: | + packages/@tailwindcss-standalone/dist/sha256sums.txt + packages/@tailwindcss-standalone/dist/tailwindcss-linux-arm64 + packages/@tailwindcss-standalone/dist/tailwindcss-linux-x64 + packages/@tailwindcss-standalone/dist/tailwindcss-macos-arm64 + packages/@tailwindcss-standalone/dist/tailwindcss-macos-x64 + packages/@tailwindcss-standalone/dist/tailwindcss-windows-x64.exe diff --git a/.gitignore b/.gitignore index bbac7d227..9d75bba27 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,4 @@ playwright-report/ blob-report/ playwright/.cache/ target/ -.debug/ +.debug diff --git a/.npmrc b/.npmrc new file mode 100644 index 000000000..ded82e2f6 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +auto-install-peers = true diff --git a/.prettierignore b/.prettierignore index 4f50b932f..3de4530dd 100644 --- a/.prettierignore +++ b/.prettierignore @@ -4,6 +4,5 @@ pnpm-lock.yaml target/ crates/node/index.d.ts crates/node/index.js -crates/ignore/ .next .fingerprint diff --git a/CHANGELOG.md b/CHANGELOG.md index e5e6f6f89..a6787ae2d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,896 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -### Added - -- Add `@tailwindcss/turbopack` package to run Tailwind CSS with Next.js ([20367](https://github.com/tailwindlabs/tailwindcss/pull/20367)) - -### Fixed - -- Ensure watch mode detects changes to symlinked `@source` files whose real paths aren't otherwise scanned ([#20356](https://github.com/tailwindlabs/tailwindcss/pull/20356)) -- Ensure custom variants using `@scope` wrap the generated utilities instead of nesting inside them ([#20369](https://github.com/tailwindlabs/tailwindcss/pull/20369)) -- Fix flattening of `@scope` at-rules ([#20369](https://github.com/tailwindlabs/tailwindcss/pull/20369)) -- Fix standalone declarations in `@scope`, wrap them in `:where(:scope)` ([#20369](https://github.com/tailwindlabs/tailwindcss/pull/20369)) -- Always emit a space for empty fallback values in CSS variables (e.g. `var(--tw-blur,)` → `var(--tw-blur, )`) ([#20373](https://github.com/tailwindlabs/tailwindcss/pull/20373)) -- Canonicalization: convert arbitrary breakpoint and container query variants to named equivalents (e.g. `max-[64rem]` → `max-lg`) ([#20380](https://github.com/tailwindlabs/tailwindcss/pull/20380)) -- Prevent `@tailwindcss/vite` from crashing on every edit under Vite's experimental `bundledDev` mode ([#20379](https://github.com/tailwindlabs/tailwindcss/pull/20379)) -- Ensure `@tailwindcss/oxide` falls back to WASM on platforms without native bindings ([#20383](https://github.com/tailwindlabs/tailwindcss/pull/20383)) -- Detect classes in Ruby percent literals using angle brackets or custom delimiters (e.g. `%w`, `%w|flex|`), including in Slim and Haml templates ([#20387](https://github.com/tailwindlabs/tailwindcss/pull/20387)) -- Preserve whitespace in `--default(…)` values in custom functional utilities (e.g. `--default(box alphabetic)` no longer becomes `boxalphabetic`) ([#20392](https://github.com/tailwindlabs/tailwindcss/pull/20392)) -- Don't scan gitignored directories (e.g. `node_modules` and `.git`) when the project uses a safelist-style `.gitignore` (e.g. `/*` followed by `!/…` negations) ([#20397](https://github.com/tailwindlabs/tailwindcss/pull/20397)) -- Ensure root `theme('…')` namespace lookups in JavaScript plugins and config files return the full namespace object instead of the value of its `DEFAULT` key ([#20399](https://github.com/tailwindlabs/tailwindcss/pull/20399)) -- Skip ignored directories entirely when computing watch globs (`scanner.globs`), instead of walking their full contents on every rebuild ([#20408](https://github.com/tailwindlabs/tailwindcss/pull/20408)) -- Oxide: drop invalid UTF-8 candidates ([#20389](https://github.com/tailwindlabs/tailwindcss/pull/20389)) -- `@tailwindcss/vite` no longer forces a full page reload for external files (e.g.: `.php` files) ([#20414](https://github.com/tailwindlabs/tailwindcss/issues/20414)) -- Canonicalization: don't merge utilities that reference different theme variables set to CSS-wide keywords like `unset` ([#20417](https://github.com/tailwindlabs/tailwindcss/pull/20417)) -- Don't generate utilities when a modifier is used that would otherwise be silently ignored (e.g. `rounded-sm/[5]`, `shadow-sm/foo`, `stroke-2/50`) ([#20419](https://github.com/tailwindlabs/tailwindcss/pull/20419)) -- Only normalize top-level `and`, `or`, and `not` keywords in `supports-[…]` variants (e.g. `selector(a: not (.foo))` → `selector(a:not(.foo))`) ([#20420](https://github.com/tailwindlabs/tailwindcss/pull/20420)) -- Don't warn about Angular's `::ng-deep` and `:host-context()` when optimizing CSS ([#20434](https://github.com/tailwindlabs/tailwindcss/pull/20434)) -- Don't generate CSS for candidates containing an empty additional modifier (e.g. `bg-red-500/50/` and `group-hover/foo//bar:flex`) ([#20466](https://github.com/tailwindlabs/tailwindcss/pull/20466)) -- Sort `min-*`, `max-*`, and container query variants with decimal values numerically (e.g. `min-[40.25rem]` before `min-[40.5rem]`) ([#20512](https://github.com/tailwindlabs/tailwindcss/pull/20512)) -- Ensure CSS comments ending with `\*/` are closed correctly instead of swallowing the CSS that follows (e.g. `/* C:\temp\*/`) ([#20508](https://github.com/tailwindlabs/tailwindcss/pull/20508)) -- Improve style invalidation performance of `group-*` and `peer-*` variants ([#20513](https://github.com/tailwindlabs/tailwindcss/pull/20513)) - -## [4.3.3] - 2026-07-16 - -### Fixed - -- Support `--watch --poll[=ms]` in `@tailwindcss/cli` when filesystem events are unreliable or unavailable ([#20297](https://github.com/tailwindlabs/tailwindcss/pull/20297)) -- Canonicalization: match arbitrary hex colors against theme colors case-insensitively (e.g. `bg-[#fff]` and `bg-[#FFF]` → `bg-white`) ([#20298](https://github.com/tailwindlabs/tailwindcss/pull/20298)) -- Prevent Preflight from overriding Firefox's native `iframe:focus-visible` outline styles ([#20292](https://github.com/tailwindlabs/tailwindcss/pull/20292)) -- Ensure `theme('colors.foo')` in JS plugins resolves correctly when both `--color-foo` and `--color-foo-bar` exist ([#20299](https://github.com/tailwindlabs/tailwindcss/pull/20299)) -- Ensure fractional opacity modifiers work with named shadow sizes like `shadow-sm/12.5`, `text-shadow-sm/12.5`, `drop-shadow-sm/12.5`, and `inset-shadow-sm/12.5` ([#20302](https://github.com/tailwindlabs/tailwindcss/pull/20302)) -- Parse selectors like `[data-foo]div` as two selectors instead of one ([#20303](https://github.com/tailwindlabs/tailwindcss/pull/20303)) -- Ensure `@tailwindcss/postcss` rebuilds when a preprocessor like Sass changes the input CSS without changing the input file on disk ([#20310](https://github.com/tailwindlabs/tailwindcss/pull/20310)) -- Ensure CSS nesting is handled even when Lightning CSS isn't run, such as in `@tailwindcss/browser` and Tailwind Play ([#20124](https://github.com/tailwindlabs/tailwindcss/pull/20124)) -- Prevent achromatic theme colors from shifting hue when mixed in polar color spaces like `oklch` ([#20314](https://github.com/tailwindlabs/tailwindcss/pull/20314)) -- Ensure `--spacing(0)` is optimized to `0px` instead of `0` so it remains a `` when used in `calc(…)` ([#20319](https://github.com/tailwindlabs/tailwindcss/pull/20319)) -- Load `@parcel/watcher` only when needed in `@tailwindcss/cli --watch` mode, so one-off builds and `--watch --poll` work when `@parcel/watcher` can't be loaded ([#20325](https://github.com/tailwindlabs/tailwindcss/pull/20325)) -- Use explicit platform fonts instead of `system-ui` and `ui-sans-serif` so CJK text respects the page's `lang` attribute on Windows ([#20318](https://github.com/tailwindlabs/tailwindcss/pull/20318)) -- Prevent `@tailwindcss/upgrade` from rewriting ignored files when run from a subdirectory ([#20329](https://github.com/tailwindlabs/tailwindcss/pull/20329)) -- Ensure earlier `@source` rules pointing to nested files are scanned when later `@source` rules point to files in parent folders ([#20335](https://github.com/tailwindlabs/tailwindcss/pull/20335)) -- Prevent `@tailwindcss/vite` from triggering full page reloads when scanned files are processed by Vite but haven't been loaded as modules yet ([#20336](https://github.com/tailwindlabs/tailwindcss/pull/20336)) - -## [4.3.2] - 2026-06-26 - -### Fixed - -- Support bare spacing values for `auto-rows-*` and `auto-cols-*` utilities (e.g. `auto-rows-12` and `auto-cols-16`) ([#20229](https://github.com/tailwindlabs/tailwindcss/pull/20229)) -- Prevent `@tailwindcss/cli` in `--watch` mode from crashing on Windows when `@source` points to a directory that doesn't exist ([#20242](https://github.com/tailwindlabs/tailwindcss/pull/20242)) -- Prevent `@tailwindcss/vite` from crashing in Deno v2.8.x when `context.parentURL` is not a valid URL ([#20245](https://github.com/tailwindlabs/tailwindcss/pull/20245)) -- Ensure `@tailwindcss/cli` in `--watch` mode rebuilds when the input CSS file changes in an ignored directory ([#20246](https://github.com/tailwindlabs/tailwindcss/pull/20246)) -- Allow `@variant` rules used in `addBase(…)` to use custom variants defined later ([#20247](https://github.com/tailwindlabs/tailwindcss/pull/20247)) -- Prevent `@tailwindcss/vite` from crashing during HMR when scanned files or directories are deleted ([#20259](https://github.com/tailwindlabs/tailwindcss/pull/20259)) -- Generate `font-size` instead of `color` declarations for `text-[--spacing(…)]` ([#20260](https://github.com/tailwindlabs/tailwindcss/pull/20260)) -- Prevent `@source` patterns from scanning unrelated sibling files and folders ([#20263](https://github.com/tailwindlabs/tailwindcss/pull/20263)) -- Extract class candidates adjacent to Template Toolkit delimiters like `%]…[%` in `.tt`, `.tt2`, and `.tx` files ([#20269](https://github.com/tailwindlabs/tailwindcss/pull/20269)) -- Extract class candidates from conditional Maud syntax like `p.text-black[condition]` ([#20269](https://github.com/tailwindlabs/tailwindcss/pull/20269)) -- Prevent `@position-try` rules from triggering unknown at-rule warnings when optimizing CSS ([#20277](https://github.com/tailwindlabs/tailwindcss/pull/20277)) -- Support class suggestions for named opacity modifiers from `--opacity` theme values ([#20287](https://github.com/tailwindlabs/tailwindcss/pull/20287)) -- Prevent type errors in `@tailwindcss/postcss` when used with newer PostCSS patch releases ([#20289](https://github.com/tailwindlabs/tailwindcss/pull/20289)) - -## [4.3.1] - 2026-06-12 - -### Added - -- Add `--silent` option to suppress output in `@tailwindcss/cli` ([#20100](https://github.com/tailwindlabs/tailwindcss/pull/20100)) - -### Fixed - -- Remove deprecation warnings by using `Module#registerHooks` instead of `Module#register` on Node 26+ ([#20028](https://github.com/tailwindlabs/tailwindcss/pull/20028)) -- Canonicalization: don't crash when plugin utilities throw for unsupported values ([#20052](https://github.com/tailwindlabs/tailwindcss/pull/20052)) -- Allow `@apply` to be used with CSS mixins ([#19427](https://github.com/tailwindlabs/tailwindcss/pull/19427)) -- Ensure `not-*` correctly negates `@container` queries, including `style(…)` queries ([#20059](https://github.com/tailwindlabs/tailwindcss/pull/20059)) -- Ensure `drop-shadow-*` color utilities work with custom shadow values containing `calc(…)` ([#20080](https://github.com/tailwindlabs/tailwindcss/pull/20080)) -- Fix 'Sourcemap is likely to be incorrect' warnings when using `@tailwindcss/vite` ([#20103](https://github.com/tailwindlabs/tailwindcss/pull/20103)) -- Ensure `@tailwindcss/webpack` can be installed in Rspack projects without requiring `webpack` as a peer dependency ([#20027](https://github.com/tailwindlabs/tailwindcss/pull/20027)) -- Canonicalization: don't suggest invalid `calc(…)` expressions (e.g. `px-[calc(1rem+0px)]` → `px-[calc(1rem+0)]`) ([#20127](https://github.com/tailwindlabs/tailwindcss/pull/20127)) -- Canonicalization: avoid suggesting large spacing-scale values for arbitrary lengths (e.g. `left-[99999px]` → `left-[99999px]`, not `left-24999.75`) ([#20130](https://github.com/tailwindlabs/tailwindcss/pull/20130)) -- Ensure `@tailwindcss/cli` in `--watch` mode recovers when a tracked dependency is deleted and restored ([#20137](https://github.com/tailwindlabs/tailwindcss/pull/20137)) -- Ensure standalone `@tailwindcss/cli` binaries are ignored when scanning for class candidates ([#20139](https://github.com/tailwindlabs/tailwindcss/pull/20139)) -- Ensure class candidates are extracted from Twig `addClass(…)` and `removeClass(…)` calls ([#20198](https://github.com/tailwindlabs/tailwindcss/pull/20198)) -- Don't crash in the Ruby or Vue preprocessors when scanning files containing invalid UTF-8 bytes ([#19588](https://github.com/tailwindlabs/tailwindcss/pull/19588)) -- Allow `@variant` to be used inside `addBase` ([#19480](https://github.com/tailwindlabs/tailwindcss/pull/19480)) -- Ensure `@source` globs with symlinks are preserved ([#20203](https://github.com/tailwindlabs/tailwindcss/pull/20203)) -- Ensure later `@source` rules can re-include files excluded by earlier `@source not` rules ([#20203](https://github.com/tailwindlabs/tailwindcss/pull/20203)) -- Upgrade: don't migrate empty class rules to invalid `@utility` rules ([#20205](https://github.com/tailwindlabs/tailwindcss/pull/20205)) -- Ensure transitions between `inset-shadow-none` and other inset shadows work correctly ([#20208](https://github.com/tailwindlabs/tailwindcss/pull/20208)) -- Ensure explicitly referenced `@source` directories are scanned even when ignored by git ([#20214](https://github.com/tailwindlabs/tailwindcss/pull/20214)) -- Ensure `@source` globs ending in `**/*` preserve dynamic path segments to avoid scanning too many files ([#20217](https://github.com/tailwindlabs/tailwindcss/pull/20217)) -- Canonicalization: don't fold `calc(…)` divisions when the result would require high precision (e.g. `w-[calc(100%/3.5)]` → `w-[calc(100%/3.5)]`, not `w-[28.571428571428573%]`) ([#20221](https://github.com/tailwindlabs/tailwindcss/pull/20221)) -- Serve ESM type declarations to ESM importers of `@tailwindcss/postcss` ([#20228](https://github.com/tailwindlabs/tailwindcss/pull/20228)) - -### Changed - -- Generate `0` instead of `calc(var(--spacing) * 0)` for spacing utilities like `m-0` and `left-0` ([#20196](https://github.com/tailwindlabs/tailwindcss/pull/20196)) -- Generate `var(--spacing)` instead of `calc(var(--spacing) * 1)` for spacing utilities like `m-1` and `left-1` ([#20196](https://github.com/tailwindlabs/tailwindcss/pull/20196)) - -## [4.3.0] - 2026-05-08 - -### Added - -- Add `@container-size` utility ([#18901](https://github.com/tailwindlabs/tailwindcss/pull/18901)) -- Add `scrollbar-{auto,thin,none}` utilities for `scrollbar-width`, and `scrollbar-thumb-*` / `scrollbar-track-*` color utilities for `scrollbar-color` ([#19981](https://github.com/tailwindlabs/tailwindcss/pull/19981), [#20019](https://github.com/tailwindlabs/tailwindcss/pull/20019)) -- Add `scrollbar-gutter-*` utilities ([#20018](https://github.com/tailwindlabs/tailwindcss/pull/20018)) -- Add `zoom-*` utilities ([#20020](https://github.com/tailwindlabs/tailwindcss/pull/20020)) -- Add `tab-*` utilities ([#20022](https://github.com/tailwindlabs/tailwindcss/pull/20022)) -- Allow using `@variant` with stacked variants (e.g. `@variant hover:focus { … }`) ([#19996](https://github.com/tailwindlabs/tailwindcss/pull/19996)) -- Allow using `@variant` with compound variants (e.g. `@variant hover, focus { … }`) ([#19996](https://github.com/tailwindlabs/tailwindcss/pull/19996)) -- Support `--default(…)` in `--value(…)` and `--modifier(…)` for functional `@utility` definitions ([#19989](https://github.com/tailwindlabs/tailwindcss/pull/19989)) - -### Fixed - -- Ensure `@plugin` resolves package JavaScript entries instead of browser CSS entries when using `@tailwindcss/vite` ([#19949](https://github.com/tailwindlabs/tailwindcss/pull/19949)) -- Fix relative `@import` and `@plugin` paths resolving from the wrong directory when using `@tailwindcss/vite` ([#19965](https://github.com/tailwindlabs/tailwindcss/pull/19965)) -- Ensure CSS files containing `@variant` are processed by `@tailwindcss/vite` ([#19966](https://github.com/tailwindlabs/tailwindcss/pull/19966)) -- Resolve imports relative to `base` when `result.opts.from` is not provided when using `@tailwindcss/postcss` ([#19980](https://github.com/tailwindlabs/tailwindcss/pull/19980)) -- Canonicalization: preserve significant `_` whitespace in arbitrary values ([#19986](https://github.com/tailwindlabs/tailwindcss/pull/19986)) -- Canonicalization: add parentheses when removing whitespace from arbitrary values would hurt readability (e.g. `w-[calc(100%---spacing(60))]` → `w-[calc(100%-(--spacing(60)))]`) ([#19986](https://github.com/tailwindlabs/tailwindcss/pull/19986)) -- Canonicalization: preserve the original unit in arbitrary values instead of normalizing to base units (e.g. `-mt-[20in]` → `mt-[-20in]`, not `mt-[-1920px]`) ([#19988](https://github.com/tailwindlabs/tailwindcss/pull/19988)) -- Canonicalization: migrate arbitrary `:has()` variants from `[&:has(…)]` to `has-[…]` ([#19991](https://github.com/tailwindlabs/tailwindcss/pull/19991)) -- Upgrade: don’t migrate inline `style` attributes (e.g. `style="flex-grow: 1"` → `style="flex-grow: 1"`, not `style="grow: 1"`) ([#19918](https://github.com/tailwindlabs/tailwindcss/pull/19918)) -- Allow multiple `@utility` definitions with the same name but different value types ([#19777](https://github.com/tailwindlabs/tailwindcss/pull/19777)) -- Export missing `PluginWithConfig` type from `tailwindcss/plugin` to fix errors when inferring plugin config types ([#19707](https://github.com/tailwindlabs/tailwindcss/pull/19707)) -- Ensure `start` and `end` legacy utilities without values do not generate CSS ([#20003](https://github.com/tailwindlabs/tailwindcss/pull/20003)) -- Ensure `--value(…)` is required in functional `@utility` definitions ([#20005](https://github.com/tailwindlabs/tailwindcss/pull/20005)) -- Canonicalization: preserve required whitespace around operators in negated arbitrary values (e.g. `-left-[(var(--a)+var(--b))]`) ([#20011](https://github.com/tailwindlabs/tailwindcss/pull/20011)) - -## [4.2.4] - 2026-04-21 - -### Fixed - -- Ensure imports in `@import` and `@plugin` still resolve correctly when using Vite aliases in `@tailwindcss/vite` ([#19947](https://github.com/tailwindlabs/tailwindcss/pull/19947)) - -## [4.2.3] - 2026-04-20 - -### Fixed - -- Canonicalization: improve canonicalization for `tracking-*` utilities by preferring non-negative utilities (e.g. `-tracking-tighter` → `tracking-wider`) ([#19827](https://github.com/tailwindlabs/tailwindcss/pull/19827)) -- Fix crash due to invalid characters in candidate (exceeding valid unicode code point range) ([#19829](https://github.com/tailwindlabs/tailwindcss/pull/19829)) -- Ensure query params in imports are considered unique resources when using `@tailwindcss/webpack` ([#19723](https://github.com/tailwindlabs/tailwindcss/pull/19723)) -- Canonicalization: collapse arbitrary values into shorthand utilities (e.g. `px-[1.2rem] py-[1.2rem]` → `p-[1.2rem]`) ([#19837](https://github.com/tailwindlabs/tailwindcss/pull/19837)) -- Canonicalization: collapse `border-{t,b}-*` into `border-y-*`, `border-{l,r}-*` into `border-x-*`, and `border-{t,r,b,l}-*` into `border-*` ([#19842](https://github.com/tailwindlabs/tailwindcss/pull/19842)) -- Canonicalization: collapse `scroll-m{t,b}-*` into `scroll-my-*`, `scroll-m{l,r}-*` into `scroll-mx-*`, and `scroll-m{t,r,b,l}-*` into `scroll-m-*` ([#19842](https://github.com/tailwindlabs/tailwindcss/pull/19842)) -- Canonicalization: collapse `scroll-p{t,b}-*` into `scroll-py-*`, `scroll-p{l,r}-*` into `scroll-px-*`, and `scroll-p{t,r,b,l}-*` into `scroll-p-*` ([#19842](https://github.com/tailwindlabs/tailwindcss/pull/19842)) -- Canonicalization: collapse `overflow-{x,y}-*` into `overflow-*` ([#19842](https://github.com/tailwindlabs/tailwindcss/pull/19842)) -- Canonicalization: collapse `overscroll-{x,y}-*` into `overscroll-*` ([#19842](https://github.com/tailwindlabs/tailwindcss/pull/19842)) -- Read from `--placeholder-color` instead of `--background-color` for `placeholder-*` utilities ([#19843](https://github.com/tailwindlabs/tailwindcss/pull/19843)) -- Upgrade: ensure files are not emptied out when killing the upgrade process while it's running ([#19846](https://github.com/tailwindlabs/tailwindcss/pull/19846)) -- Upgrade: use `config.content` when migrating from Tailwind CSS v3 to Tailwind CSS v4 ([#19846](https://github.com/tailwindlabs/tailwindcss/pull/19846)) -- Upgrade: never migrate files that are ignored by git ([#19846](https://github.com/tailwindlabs/tailwindcss/pull/19846)) -- Add `.env` and `.env.*` to default ignored content files ([#19846](https://github.com/tailwindlabs/tailwindcss/pull/19846)) -- Canonicalization: migrate `overflow-ellipsis` into `text-ellipsis` ([#19849](https://github.com/tailwindlabs/tailwindcss/pull/19849)) -- Canonicalization: migrate `start-full` → `inset-s-full`, `start-auto` → `inset-s-auto`, `start-px` → `inset-s-px`, and `start-` → `inset-s-` as well as negative versions ([#19849](https://github.com/tailwindlabs/tailwindcss/pull/19849)) -- Canonicalization: migrate `end-full` → `inset-e-full`, `end-auto` → `inset-e-auto`, `end-px` → `inset-e-px`, and `end-` → `inset-e-` as well as negative versions ([#19849](https://github.com/tailwindlabs/tailwindcss/pull/19849)) -- Canonicalization: move the `-` sign inside the arbitrary value `-left-[9rem]` → `left-[-9rem]` ([#19858](https://github.com/tailwindlabs/tailwindcss/pull/19858)) -- Canonicalization: move the `-` sign outside the arbitrary value `ml-[calc(-1*var(--width))]` → `-ml-(--width)` ([#19858](https://github.com/tailwindlabs/tailwindcss/pull/19858)) -- Improve performance when scanning JSONL / NDJSON files ([#19862](https://github.com/tailwindlabs/tailwindcss/pull/19862)) -- Support `NODE_PATH` environment variable in standalone CLI ([#19617](https://github.com/tailwindlabs/tailwindcss/pull/19617)) - -## [4.2.2] - 2026-03-18 - -### Fixed - -- Don't crash when candidates contain prototype properties like `row-constructor` ([#19725](https://github.com/tailwindlabs/tailwindcss/pull/19725)) -- Canonicalize `calc(var(--spacing)*…)` expressions into `--spacing(…)` ([#19769](https://github.com/tailwindlabs/tailwindcss/pull/19769)) -- Fix crash in canonicalization step when handling utilities containing `@property` at-rules (e.g. `shadow-sm border`) ([#19727](https://github.com/tailwindlabs/tailwindcss/pull/19727)) -- Skip full reload for server only modules scanned by client CSS when using `@tailwindcss/vite` ([#19745](https://github.com/tailwindlabs/tailwindcss/pull/19745)) -- Add support for Vite 8 in `@tailwindcss/vite` ([#19790](https://github.com/tailwindlabs/tailwindcss/pull/19790)) -- Improve canonicalization for bare values exceeding default spacing scale suggestions (e.g. `w-1234 h-1234` → `size-1234`) ([#19809](https://github.com/tailwindlabs/tailwindcss/pull/19809)) -- Fix canonicalization resulting in empty list (e.g. `w-5 h-5 size-5` → `''` instead of `size-5`) ([#19812](https://github.com/tailwindlabs/tailwindcss/pull/19812)) -- Resolve tsconfig paths to allow for `@import '@/path/to/file';` when using `@tailwindcss/vite` ([#19803](https://github.com/tailwindlabs/tailwindcss/pull/19803)) - -## [4.2.1] - 2026-02-23 - -### Fixed - -- Allow trailing dash in functional utility names for backwards compatibility ([#19696](https://github.com/tailwindlabs/tailwindcss/pull/19696)) -- Properly detect classes containing `.` characters within curly braces in MDX files ([#19711](https://github.com/tailwindlabs/tailwindcss/pull/19711)) - -## [4.2.0] - 2026-02-18 - -### Added - -- Add mauve, olive, mist, and taupe color palettes to the default theme ([#19627](https://github.com/tailwindlabs/tailwindcss/pull/19627)) -- Add `@tailwindcss/webpack` package to run Tailwind CSS as a webpack plugin ([#19610](https://github.com/tailwindlabs/tailwindcss/pull/19610)) -- Add `pbs-*` and `pbe-*` utilities for `padding-block-start` and `padding-block-end` ([#19601](https://github.com/tailwindlabs/tailwindcss/pull/19601)) -- Add `mbs-*` and `mbe-*` utilities for `margin-block-start` and `margin-block-end` ([#19601](https://github.com/tailwindlabs/tailwindcss/pull/19601)) -- Add `scroll-pbs-*` and `scroll-pbe-*` utilities for `scroll-padding-block-start` and `scroll-padding-block-end` ([#19601](https://github.com/tailwindlabs/tailwindcss/pull/19601)) -- Add `scroll-mbs-*` and `scroll-mbe-*` utilities for `scroll-margin-block-start` and `scroll-margin-block-end` ([#19601](https://github.com/tailwindlabs/tailwindcss/pull/19601)) -- Add `border-bs-*` and `border-be-*` utilities for `border-block-start` and `border-block-end` ([#19601](https://github.com/tailwindlabs/tailwindcss/pull/19601)) -- Add `inline-*`, `min-inline-*`, `max-inline-*` utilities for `inline-size`, `min-inline-size`, and `max-inline-size` ([#19612](https://github.com/tailwindlabs/tailwindcss/pull/19612)) -- Add `block-*`, `min-block-*`, `max-block-*` utilities for `block-size`, `min-block-size`, and `max-block-size` ([#19612](https://github.com/tailwindlabs/tailwindcss/pull/19612)) -- Add `inset-s-*`, `inset-e-*`, `inset-bs-*`, `inset-be-*` utilities for `inset-inline-start`, `inset-inline-end`, `inset-block-start`, and `inset-block-end` ([#19613](https://github.com/tailwindlabs/tailwindcss/pull/19613)) -- Add `font-features-*` utility for `font-feature-settings` ([#19623](https://github.com/tailwindlabs/tailwindcss/pull/19623)) - -### Fixed - -- Prevent double `@supports` wrapper for `color-mix` values ([#19450](https://github.com/tailwindlabs/tailwindcss/pull/19450)) -- Allow whitespace around `@source inline()` argument ([#19461](https://github.com/tailwindlabs/tailwindcss/pull/19461)) -- Emit comment when source maps are saved to files when using `@tailwindcss/cli` ([#19447](https://github.com/tailwindlabs/tailwindcss/pull/19447)) -- Detect utilities containing capital letters followed by numbers ([#19465](https://github.com/tailwindlabs/tailwindcss/pull/19465)) -- Fix class extraction for Rails' strict locals ([#19525](https://github.com/tailwindlabs/tailwindcss/pull/19525)) -- Align `@utility` name validation with Oxide scanner rules ([#19524](https://github.com/tailwindlabs/tailwindcss/pull/19524)) -- Fix infinite loop when using `@variant` inside `@custom-variant` ([#19633](https://github.com/tailwindlabs/tailwindcss/pull/19633)) -- Allow multiples of `.25` in `aspect-*` fractions (e.g. `aspect-8.5/11`) ([#19688](https://github.com/tailwindlabs/tailwindcss/pull/19688)) -- Ensure changes to external files listed via `@source` trigger a full page reload when using `@tailwindcss/vite` ([#19670](https://github.com/tailwindlabs/tailwindcss/pull/19670)) -- Improve performance of Oxide scanner in bigger projects by reducing file system walks ([#19632](https://github.com/tailwindlabs/tailwindcss/pull/19632)) -- Ensure import aliases in Astro v5 work without crashing when using `@tailwindcss/vite` ([#19677](https://github.com/tailwindlabs/tailwindcss/issues/19677)) -- Allow escape characters in `@utility` names to improve support with formatters such as Biome ([#19626](https://github.com/tailwindlabs/tailwindcss/pull/19626)) -- Fix incorrect canonicalization results when canonicalizing multiple times ([#19675](https://github.com/tailwindlabs/tailwindcss/pull/19675)) -- Add `.jj` to default ignored content directories ([#19687](https://github.com/tailwindlabs/tailwindcss/pull/19687)) - -### Deprecated - -- Deprecate `start-*` and `end-*` utilities in favor of `inset-s-*` and `inset-e-*` utilities ([#19613](https://github.com/tailwindlabs/tailwindcss/pull/19613)) - -## [4.1.18] - 2025-12-11 - -### Fixed - -- Ensure validation of `source(…)` happens relative to the file it is in ([#19274](https://github.com/tailwindlabs/tailwindcss/pull/19274)) -- Include filename and line numbers in CSS parse errors ([#19282](https://github.com/tailwindlabs/tailwindcss/pull/19282)) -- Skip comments in Ruby files when checking for class names ([#19243](https://github.com/tailwindlabs/tailwindcss/pull/19243)) -- Skip over arbitrary property utilities with a top-level `!` in the value ([#19243](https://github.com/tailwindlabs/tailwindcss/pull/19243)) -- Support environment API in `@tailwindcss/vite` ([#18970](https://github.com/tailwindlabs/tailwindcss/pull/18970)) -- Preserve case of theme keys from JS configs and plugins ([#19337](https://github.com/tailwindlabs/tailwindcss/pull/19337)) -- Write source maps correctly on the CLI when using `--watch` ([#19373](https://github.com/tailwindlabs/tailwindcss/pull/19373)) -- Handle special defaults (like `ringColor.DEFAULT`) in JS configs ([#19348](https://github.com/tailwindlabs/tailwindcss/pull/19348)) -- Improve backwards compatibility for `content` theme key from JS configs ([#19381](https://github.com/tailwindlabs/tailwindcss/pull/19381)) -- Upgrade: Handle `future` and `experimental` config keys ([#19344](https://github.com/tailwindlabs/tailwindcss/pull/19344)) -- Try to canonicalize any arbitrary utility to a bare value ([#19379](https://github.com/tailwindlabs/tailwindcss/pull/19379)) -- Validate candidates similarly to Oxide ([#19397](https://github.com/tailwindlabs/tailwindcss/pull/19397)) -- Canonicalization: combine `text-*` and `leading-*` classes ([#19396](https://github.com/tailwindlabs/tailwindcss/pull/19396)) -- Correctly handle duplicate CLI arguments ([#19416](https://github.com/tailwindlabs/tailwindcss/pull/19416)) -- Don’t emit color-mix fallback rules inside `@keyframes` ([#19419](https://github.com/tailwindlabs/tailwindcss/pull/19419)) -- CLI: Don't hang when output is `/dev/stdout` ([#19421](https://github.com/tailwindlabs/tailwindcss/pull/19421)) - -## [3.4.19] - 2025-12-10 - -### Fixed - -- Don’t break `sibling-*()` functions when used inside `calc(…)` ([#19335](https://github.com/tailwindlabs/tailwindcss/pull/19335)) - -## [4.1.17] - 2025-11-06 - -### Fixed - -- Substitute `@variant` inside legacy JS APIs ([#19263](https://github.com/tailwindlabs/tailwindcss/pull/19263)) -- Prevent occasional crash on Windows when loaded into a worker thread ([#19242](https://github.com/tailwindlabs/tailwindcss/pull/19242)) - -## [4.1.16] - 2025-10-23 - -### Fixed - -- Discard candidates with an empty data type ([#19172](https://github.com/tailwindlabs/tailwindcss/pull/19172)) -- Fix canonicalization of arbitrary variants with attribute selectors ([#19176](https://github.com/tailwindlabs/tailwindcss/pull/19176)) -- Fix invalid colors due to nested `&` ([#19184](https://github.com/tailwindlabs/tailwindcss/pull/19184)) -- Improve canonicalization for `& > :pseudo` and `& :pseudo` arbitrary variants ([#19178](https://github.com/tailwindlabs/tailwindcss/pull/19178)) - -## [4.1.15] - 2025-10-20 - -### Fixed - -- Fix Safari devtools rendering issue due to `color-mix` fallback ([#19069](https://github.com/tailwindlabs/tailwindcss/pull/19069)) -- Suppress Lightning CSS warnings about `:deep`, `:slotted`, and `:global` ([#19094](https://github.com/tailwindlabs/tailwindcss/pull/19094)) -- Fix resolving theme keys when starting with the name of another theme key in JS configs and plugins ([#19097](https://github.com/tailwindlabs/tailwindcss/pull/19097)) -- Allow named groups in combination with `not-*`, `has-*`, and `in-*` ([#19100](https://github.com/tailwindlabs/tailwindcss/pull/19100)) -- Prevent important utilities from affecting other utilities ([#19110](https://github.com/tailwindlabs/tailwindcss/pull/19110)) -- Don’t index into strings with the `theme(…)` function ([#19111](https://github.com/tailwindlabs/tailwindcss/pull/19111)) -- Fix parsing issue when `\t` is used in at-rules ([#19130](https://github.com/tailwindlabs/tailwindcss/pull/19130)) -- Upgrade: Canonicalize utilities containing `0` values ([#19095](https://github.com/tailwindlabs/tailwindcss/pull/19095)) -- Upgrade: Migrate deprecated `break-words` to `wrap-break-word` ([#19157](https://github.com/tailwindlabs/tailwindcss/pull/19157)) - -### Changed - -- Remove the `postinstall` script from oxide ([#19149])(https://github.com/tailwindlabs/tailwindcss/pull/19149) - -## [4.1.14] - 2025-10-01 - -### Fixed - -- Handle `'` syntax in ClojureScript when extracting classes ([#18888](https://github.com/tailwindlabs/tailwindcss/pull/18888)) -- Handle `@variant` inside `@custom-variant` ([#18885](https://github.com/tailwindlabs/tailwindcss/pull/18885)) -- Merge suggestions when using `@utility` ([#18900](https://github.com/tailwindlabs/tailwindcss/pull/18900)) -- Ensure that file system watchers created when using the CLI are always cleaned up ([#18905](https://github.com/tailwindlabs/tailwindcss/pull/18905)) -- Do not generate `grid-column` utilities when configuring `grid-column-start` or `grid-column-end` ([#18907](https://github.com/tailwindlabs/tailwindcss/pull/18907)) -- Do not generate `grid-row` utilities when configuring `grid-row-start` or `grid-row-end` ([#18907](https://github.com/tailwindlabs/tailwindcss/pull/18907)) -- Prevent duplicate CSS when overwriting a static utility with a theme key ([#18056](https://github.com/tailwindlabs/tailwindcss/pull/18056)) -- Show Lightning CSS warnings (if any) when optimizing/minifying ([#18918](https://github.com/tailwindlabs/tailwindcss/pull/18918)) -- Use `default` export condition for `@tailwindcss/vite` ([#18948](https://github.com/tailwindlabs/tailwindcss/pull/18948)) -- Re-throw errors from PostCSS nodes ([#18373](https://github.com/tailwindlabs/tailwindcss/pull/18373)) -- Detect classes in markdown inline directives ([#18967](https://github.com/tailwindlabs/tailwindcss/pull/18967)) -- Ensure files with only `@theme` produce no output when built ([#18979](https://github.com/tailwindlabs/tailwindcss/pull/18979)) -- Support Maud templates when extracting classes ([#18988](https://github.com/tailwindlabs/tailwindcss/pull/18988)) -- Upgrade: Do not migrate `variant = 'outline'` during upgrades ([#18922](https://github.com/tailwindlabs/tailwindcss/pull/18922)) -- Upgrade: Show version mismatch (if any) when running upgrade tool ([#19028](https://github.com/tailwindlabs/tailwindcss/pull/19028)) -- Upgrade: Ensure first class inside `className` is migrated ([#19031](https://github.com/tailwindlabs/tailwindcss/pull/19031)) -- Upgrade: Migrate classes inside `*ClassName` and `*Class` attributes ([#19031](https://github.com/tailwindlabs/tailwindcss/pull/19031)) - -## [3.4.18] - 2025-10-01 - -### Fixed - -- Improve support for raw `supports-[…]` queries in arbitrary values ([#13605](https://github.com/tailwindlabs/tailwindcss/pull/13605)) -- Fix `require.cache` error when loaded through a TypeScript file in Node 22.18+ ([#18665](https://github.com/tailwindlabs/tailwindcss/pull/18665)) -- Support `import.meta.resolve(…)` in configs for new enough Node.js versions ([#18938](https://github.com/tailwindlabs/tailwindcss/pull/18938)) -- Allow using newer versions of `postcss-load-config` for better ESM and TypeScript PostCSS config support with the CLI ([#18938](https://github.com/tailwindlabs/tailwindcss/pull/18938)) -- Remove irrelevant utility rules when matching important classes ([#19030](https://github.com/tailwindlabs/tailwindcss/pull/19030)) - -## [4.1.13] - 2025-09-03 - -### Changed - -- Drop warning from browser build ([#18731](https://github.com/tailwindlabs/tailwindcss/issues/18731)) -- Drop exact duplicate declarations when emitting CSS ([#18809](https://github.com/tailwindlabs/tailwindcss/issues/18809)) - -### Fixed - -- Don't transition `visibility` when using `transition` ([#18795](https://github.com/tailwindlabs/tailwindcss/pull/18795)) -- Discard matched variants with unknown named values ([#18799](https://github.com/tailwindlabs/tailwindcss/pull/18799)) -- Discard matched variants with non-string values ([#18799](https://github.com/tailwindlabs/tailwindcss/pull/18799)) -- Show suggestions for known `matchVariant` values ([#18798](https://github.com/tailwindlabs/tailwindcss/pull/18798)) -- Replace deprecated `clip` with `clip-path` in `sr-only` ([#18769](https://github.com/tailwindlabs/tailwindcss/pull/18769)) -- Hide internal fields from completions in `matchUtilities` ([#18820](https://github.com/tailwindlabs/tailwindcss/pull/18820)) -- Ignore `.vercel` folders by default (can be overridden by `@source …` rules) ([#18855](https://github.com/tailwindlabs/tailwindcss/pull/18855)) -- Consider variants starting with `@-` to be invalid (e.g. `@-2xl:flex`) ([#18869](https://github.com/tailwindlabs/tailwindcss/pull/18869)) -- Do not allow custom variants to start or end with a `-` or `_` ([#18867](https://github.com/tailwindlabs/tailwindcss/pull/18867), [#18872](https://github.com/tailwindlabs/tailwindcss/pull/18872)) -- Upgrade: Migrate `aria` theme keys to `@custom-variant` ([#18815](https://github.com/tailwindlabs/tailwindcss/pull/18815)) -- Upgrade: Migrate `data` theme keys to `@custom-variant` ([#18816](https://github.com/tailwindlabs/tailwindcss/pull/18816)) -- Upgrade: Migrate `supports` theme keys to `@custom-variant` ([#18817](https://github.com/tailwindlabs/tailwindcss/pull/18817)) - -## [4.1.12] - 2025-08-13 - -### Fixed - -- Don't consider the global important state in `@apply` ([#18404](https://github.com/tailwindlabs/tailwindcss/pull/18404)) -- Add missing suggestions for `flex-` utilities ([#18642](https://github.com/tailwindlabs/tailwindcss/pull/18642)) -- Fix trailing `)` from interfering with extraction in Clojure keywords ([#18345](https://github.com/tailwindlabs/tailwindcss/pull/18345)) -- Detect classes inside Elixir charlist, word list, and string sigils ([#18432](https://github.com/tailwindlabs/tailwindcss/pull/18432)) -- Track source locations through `@plugin` and `@config` ([#18345](https://github.com/tailwindlabs/tailwindcss/pull/18345)) -- Allow boolean values of `process.env.DEBUG` in `@tailwindcss/node` ([#18485](https://github.com/tailwindlabs/tailwindcss/pull/18485)) -- Ignore consecutive semicolons in the CSS parser ([#18532](https://github.com/tailwindlabs/tailwindcss/pull/18532)) -- Center the dropdown icon added to an input with a paired datalist by default ([#18511](https://github.com/tailwindlabs/tailwindcss/pull/18511)) -- Extract candidates in Slang templates ([#18565](https://github.com/tailwindlabs/tailwindcss/pull/18565)) -- Improve error messages when encountering invalid functional utility names ([#18568](https://github.com/tailwindlabs/tailwindcss/pull/18568)) -- Discard CSS AST objects with `false` or `undefined` properties ([#18571](https://github.com/tailwindlabs/tailwindcss/pull/18571)) -- Allow users to disable URL rebasing in `@tailwindcss/postcss` via `transformAssetUrls: false` ([#18321](https://github.com/tailwindlabs/tailwindcss/pull/18321)) -- Fix false-positive migrations in `addEventListener` and JavaScript variable names ([#18718](https://github.com/tailwindlabs/tailwindcss/pull/18718)) -- Fix Standalone CLI showing default Bun help when run via symlink on Windows ([#18723](https://github.com/tailwindlabs/tailwindcss/pull/18723)) -- Read from `--border-color-*` theme keys in `divide-*` utilities for backwards compatibility ([#18704](https://github.com/tailwindlabs/tailwindcss/pull/18704/)) -- Don't scan `.hdr` and `.exr` files for classes by default ([#18734](https://github.com/tailwindlabs/tailwindcss/pull/18734)) - -## [4.1.11] - 2025-06-26 - -### Fixed - -- Add heuristic to skip candidate migrations inside `emit(…)` ([#18330](https://github.com/tailwindlabs/tailwindcss/pull/18330)) -- Extract candidates with variants in Clojure/ClojureScript keywords ([#18338](https://github.com/tailwindlabs/tailwindcss/pull/18338)) -- Document `--watch=always` in the CLI's usage ([#18337](https://github.com/tailwindlabs/tailwindcss/pull/18337)) -- Add support for Vite 7 to `@tailwindcss/vite` ([#18384](https://github.com/tailwindlabs/tailwindcss/pull/18384)) - -## [4.1.10] - 2025-06-11 - -### Fixed - -- Fix incorrectly generated CSS when using percentages in arbitrary values with calc (e.g. `w-[calc(100%-var(--offset))]`) ([#18289](https://github.com/tailwindlabs/tailwindcss/pull/18289)) - -## [4.1.9] - 2025-06-11 - -### Fixed - -- Correctly parse custom properties with strings containing semicolons ([#18251](https://github.com/tailwindlabs/tailwindcss/pull/18251)) -- Upgrade: Migrate arbitrary modifiers without percentage signs to bare values (e.g. `/[0.16]` → `/16`) ([#18184](https://github.com/tailwindlabs/tailwindcss/pull/18184)) -- Upgrade: Migrate CSS variable shorthands where fallback value contains function call ([#18184](https://github.com/tailwindlabs/tailwindcss/pull/18184)) -- Upgrade: Migrate negative arbitrary values to negative bare values (e.g. `mb-[-32rem]` → `-mb-128`) ([#18212](https://github.com/tailwindlabs/tailwindcss/pull/18212)) -- Upgrade: Do not migrate `blur` in `wire:model.blur` ([#18216](https://github.com/tailwindlabs/tailwindcss/pull/18216)) -- Don't add spaces around CSS dashed idents when formatting math expressions ([#18220](https://github.com/tailwindlabs/tailwindcss/pull/18220)) - -## [4.1.8] - 2025-05-27 - -### Added - -- Improve error messages when `@apply` fails ([#18059](https://github.com/tailwindlabs/tailwindcss/pull/18059)) - -### Fixed - -- Upgrade: Do not migrate declarations that look like candidates in ` - `, - 'src/input.css': css` - @import 'tailwindcss'; - - .foo { - flex-shrink: 1; - } - - .bar { - @apply !underline; - } - `, - }, - }, - async ({ exec, fs, expect }) => { - await exec('pnpm exec upgrade') - - expect(await fs.dumpFiles('./src/**/*.{css,vue}')).toMatchInlineSnapshot(` - " - --- ./src/index.vue --- - - - - - --- ./src/input.css --- - @import 'tailwindcss'; - - .foo { - flex-shrink: 1; - } - - .bar { - @apply underline!; - } - " - `) - }, -) - -function withBOM(text: string): string { - return '\uFEFF' + text -} diff --git a/integrations/upgrade/js-config.test.ts b/integrations/upgrade/js-config.test.ts index cab0d3d62..f2643143a 100644 --- a/integrations/upgrade/js-config.test.ts +++ b/integrations/upgrade/js-config.test.ts @@ -1,6 +1,6 @@ import path from 'node:path' import { describe } from 'vitest' -import { css, html, json, test, ts, txt } from '../utils' +import { css, html, json, test, ts } from '../utils' test( `upgrade JS config files with flat theme values, darkMode, and content fields`, @@ -30,23 +30,13 @@ test( 400: '#f87171', 500: 'red', }, - superRed: '#ff0000', steel: 'rgb(70 130 180 / )', smoke: 'rgba(245, 245, 245, var(--smoke-alpha, ))', }, - ringColor: { - DEFAULT: '#c0ffee', - }, - opacity: { - superOpaque: '0.95', - }, fontSize: { xs: ['0.75rem', { lineHeight: '1rem' }], sm: ['0.875rem', { lineHeight: '1.5rem' }], base: ['1rem', { lineHeight: '2rem' }], - lg: ['1.125rem', '2.5rem'], - xl: ['1.5rem', '3rem', 'invalid'], - '2xl': ['2rem'], }, width: { px: '1px', @@ -147,14 +137,12 @@ test( 'src/test.js': ts` export default { 'shouldNotMigrate': !border.test + '', - 'filter': 'drop-shadow(0 0 0.5rem #000)', } `, 'src/index.html': html` -
-
`, 'node_modules/my-external-lib/src/template.html': html`
@@ -164,22 +152,21 @@ test( }, }, async ({ exec, fs, expect }) => { - await exec('pnpm exec upgrade') + await exec('npx @tailwindcss/upgrade') expect(await fs.dumpFiles('src/**/*.{css,js,html}')).toMatchInlineSnapshot(` " --- src/index.html ---
-
+ class="[letter-spacing:var(--tracking-super-wide)] [line-height:var(--leading-super-loose)]" + >
--- src/input.css --- @import 'tailwindcss'; @source '../node_modules/my-external-lib/**/*.{html}'; - @custom-variant dark (&:where(.dark, .dark *)); + @variant dark (&:where(.dark, .dark *)); @theme { --shadow-*: initial; @@ -190,15 +177,9 @@ test( --color-red-500: #ef4444; --color-red-600: #dc2626; - --color-superRed: #ff0000; --color-steel: rgb(70 130 180); --color-smoke: rgba(245, 245, 245, var(--smoke-alpha, 1)); - --default-ring-color: #c0ffee; - - --opacity-*: initial; - --opacity-superOpaque: 95%; - --text-*: initial; --text-xs: 0.75rem; --text-xs--line-height: 1rem; @@ -206,11 +187,6 @@ test( --text-sm--line-height: 1.5rem; --text-base: 1rem; --text-base--line-height: 2rem; - --text-lg: 1.125rem; - --text-lg--line-height: 2.5rem; - --text-xl: 1.5rem; - --text-xl--line-height: 3rem; - --text-2xl: 2rem; --width-*: initial; --width-0: 0%; @@ -261,18 +237,17 @@ test( --width-225px: 225px; --font-sans: Inter, system-ui, sans-serif; - --font-display: - Cabinet Grotesk, ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', - 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; + --font-display: Cabinet Grotesk, ui-sans-serif, system-ui, sans-serif, + 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; --radius-4xl: 2rem; --animate-spin-clockwise: spin-clockwise 1s linear infinite; --animate-spin-counterclockwise: spin-counterclockwise 1s linear infinite; - --tracking-superWide: 0.25em; + --tracking-super-wide: 0.25em; - --leading-superLoose: 3; + --leading-super-loose: 3; @keyframes spin-clockwise { 0% { @@ -293,7 +268,7 @@ test( } /* - The default border color has changed to \`currentcolor\` in Tailwind CSS v4, + The default border color has changed to \`currentColor\` in Tailwind CSS v4, so we've added these compatibility styles to make sure everything still looks the same as it did with Tailwind CSS v3. @@ -306,14 +281,13 @@ test( ::before, ::backdrop, ::file-selector-button { - border-color: var(--color-gray-200, currentcolor); + border-color: var(--color-gray-200, currentColor); } } --- src/test.js --- export default { 'shouldNotMigrate': !border.test + '', - 'filter': 'drop-shadow(0 0 0.5rem #000)', } " `) @@ -322,105 +296,6 @@ test( }, ) -test( - 'skips gitignored template files even when they are explicitly referenced in `content`', - { - fs: { - 'package.json': json` - { - "dependencies": { - "tailwindcss": "^3", - "@tailwindcss/upgrade": "workspace:^" - } - } - `, - '.gitignore': txt` - node_modules - src/ignored - `, - 'tailwind.config.ts': ts` - import { type Config } from 'tailwindcss' - - module.exports = { - content: [ - './src/migrate-me.html', - './src/ignored/do-not-migrate-me.html', - './node_modules/my-external-lib/template.html', - ], - theme: {}, - plugins: [], - } satisfies Config - `, - 'src/input.css': css` - @tailwind base; - @tailwind components; - @tailwind utilities; - `, - 'src/migrate-me.html': html` -
- `, - 'src/ignored/do-not-migrate-me.html': html` -
- `, - 'node_modules/my-external-lib/template.html': html` -
- `, - }, - }, - async ({ exec, fs, expect }) => { - await exec('pnpm exec upgrade') - - expect( - await fs.dumpFiles( - '{src/**/*.{css,html},node_modules/my-external-lib/template.html,.gitignore}', - ), - ).toMatchInlineSnapshot(` - " - --- .gitignore --- - node_modules - src/ignored - - --- src/input.css --- - @import 'tailwindcss'; - - @source './ignored/do-not-migrate-me.html'; - @source '../node_modules/my-external-lib/template.html'; - - /* - The default border color has changed to \`currentcolor\` in Tailwind CSS v4, - so we've added these compatibility styles to make sure everything still - looks the same as it did with Tailwind CSS v3. - - If we ever want to remove these styles, we need to add an explicit border - color utility to any element that depends on these defaults. - */ - @layer base { - *, - ::after, - ::before, - ::backdrop, - ::file-selector-button { - border-color: var(--color-gray-200, currentcolor); - } - } - - --- src/migrate-me.html --- -
- - --- node_modules/my-external-lib/template.html --- -
- - --- src/ignored/do-not-migrate-me.html --- -
- " - `) - }, -) - test( 'upgrades JS config files with plugins', { @@ -440,14 +315,6 @@ test( import customPlugin from './custom-plugin' export default { - darkMode: [ - 'variant', - [ - '@media not print { .dark & }', - '@media not eink { .dark & }', - '&:where(.dark, .dark *)', - ], - ], plugins: [ typography, customPlugin({ @@ -484,7 +351,7 @@ test( }, }, async ({ exec, fs, expect }) => { - await exec('pnpm exec upgrade') + await exec('npx @tailwindcss/upgrade') expect(await fs.dumpFiles('src/**/*.css')).toMatchInlineSnapshot(` " @@ -509,24 +376,8 @@ test( is-arr-mixed: null, true, false, 1234567, 1.35, 'foo', 'bar', 'true'; } - @custom-variant dark { - @media not print { - .dark & { - @slot; - } - } - @media not eink { - .dark & { - @slot; - } - } - &:where(.dark, .dark *) { - @slot; - } - } - /* - The default border color has changed to \`currentcolor\` in Tailwind CSS v4, + The default border color has changed to \`currentColor\` in Tailwind CSS v4, so we've added these compatibility styles to make sure everything still looks the same as it did with Tailwind CSS v3. @@ -539,7 +390,7 @@ test( ::before, ::backdrop, ::file-selector-button { - border-color: var(--color-gray-200, currentcolor); + border-color: var(--color-gray-200, currentColor); } } " @@ -586,7 +437,7 @@ test( }, }, async ({ exec, fs, expect }) => { - await exec('pnpm exec upgrade') + await exec('npx @tailwindcss/upgrade') expect(await fs.dumpFiles('src/**/*.{css,ts}')).toMatchInlineSnapshot(` " @@ -594,21 +445,21 @@ test( @import 'tailwindcss'; @theme { - --color-gray-50: oklch(98.5% 0 none); - --color-gray-100: oklch(97% 0 none); - --color-gray-200: oklch(92.2% 0 none); - --color-gray-300: oklch(87% 0 none); - --color-gray-400: oklch(70.8% 0 none); - --color-gray-500: oklch(55.6% 0 none); - --color-gray-600: oklch(43.9% 0 none); - --color-gray-700: oklch(37.1% 0 none); - --color-gray-800: oklch(26.9% 0 none); - --color-gray-900: oklch(20.5% 0 none); - --color-gray-950: oklch(14.5% 0 none); + --color-gray-50: oklch(0.985 0 0); + --color-gray-100: oklch(0.97 0 0); + --color-gray-200: oklch(0.922 0 0); + --color-gray-300: oklch(0.87 0 0); + --color-gray-400: oklch(0.708 0 0); + --color-gray-500: oklch(0.556 0 0); + --color-gray-600: oklch(0.439 0 0); + --color-gray-700: oklch(0.371 0 0); + --color-gray-800: oklch(0.269 0 0); + --color-gray-900: oklch(0.205 0 0); + --color-gray-950: oklch(0.145 0 0); } /* - The default border color has changed to \`currentcolor\` in Tailwind CSS v4, + The default border color has changed to \`currentColor\` in Tailwind CSS v4, so we've added these compatibility styles to make sure everything still looks the same as it did with Tailwind CSS v3. @@ -621,7 +472,7 @@ test( ::before, ::backdrop, ::file-selector-button { - border-color: var(--color-gray-200, currentcolor); + border-color: var(--color-gray-200, currentColor); } } " @@ -672,7 +523,7 @@ test( }, }, async ({ exec, fs, expect }) => { - await exec('pnpm exec upgrade') + await exec('npx @tailwindcss/upgrade') expect(await fs.dumpFiles('src/**/*.css')).toMatchInlineSnapshot(` " @@ -682,7 +533,7 @@ test( @config '../tailwind.config.ts'; /* - The default border color has changed to \`currentcolor\` in Tailwind CSS v4, + The default border color has changed to \`currentColor\` in Tailwind CSS v4, so we've added these compatibility styles to make sure everything still looks the same as it did with Tailwind CSS v3. @@ -695,7 +546,7 @@ test( ::before, ::backdrop, ::file-selector-button { - border-color: var(--color-gray-200, currentcolor); + border-color: var(--color-gray-200, currentColor); } } " @@ -750,7 +601,7 @@ test( }, }, async ({ exec, fs, expect }) => { - await exec('pnpm exec upgrade') + await exec('npx @tailwindcss/upgrade') expect(await fs.dumpFiles('src/**/*.css')).toMatchInlineSnapshot(` " @@ -760,7 +611,7 @@ test( @config '../tailwind.config.ts'; /* - The default border color has changed to \`currentcolor\` in Tailwind CSS v4, + The default border color has changed to \`currentColor\` in Tailwind CSS v4, so we've added these compatibility styles to make sure everything still looks the same as it did with Tailwind CSS v3. @@ -773,7 +624,7 @@ test( ::before, ::backdrop, ::file-selector-button { - border-color: var(--color-gray-200, currentcolor); + border-color: var(--color-gray-200, currentColor); } } " @@ -824,7 +675,7 @@ test( }, }, async ({ exec, fs, expect }) => { - await exec('pnpm exec upgrade') + await exec('npx @tailwindcss/upgrade') expect(await fs.dumpFiles('src/**/*.css')).toMatchInlineSnapshot(` " @@ -834,7 +685,7 @@ test( @config '../tailwind.config.ts'; /* - The default border color has changed to \`currentcolor\` in Tailwind CSS v4, + The default border color has changed to \`currentColor\` in Tailwind CSS v4, so we've added these compatibility styles to make sure everything still looks the same as it did with Tailwind CSS v3. @@ -847,7 +698,7 @@ test( ::before, ::backdrop, ::file-selector-button { - border-color: var(--color-gray-200, currentcolor); + border-color: var(--color-gray-200, currentColor); } } " @@ -934,7 +785,7 @@ test( }, }, async ({ exec, fs, expect }) => { - await exec('pnpm exec upgrade') + await exec('npx @tailwindcss/upgrade') expect(await fs.dumpFiles('project-{a,b}/**/*.{css,ts}')).toMatchInlineSnapshot(` " @@ -946,7 +797,7 @@ test( } /* - The default border color has changed to \`currentcolor\` in Tailwind CSS v4, + The default border color has changed to \`currentColor\` in Tailwind CSS v4, so we've added these compatibility styles to make sure everything still looks the same as it did with Tailwind CSS v3. @@ -959,7 +810,7 @@ test( ::before, ::backdrop, ::file-selector-button { - border-color: var(--color-gray-200, currentcolor); + border-color: var(--color-gray-200, currentColor); } } @@ -971,7 +822,7 @@ test( } /* - The default border color has changed to \`currentcolor\` in Tailwind CSS v4, + The default border color has changed to \`currentColor\` in Tailwind CSS v4, so we've added these compatibility styles to make sure everything still looks the same as it did with Tailwind CSS v3. @@ -984,7 +835,7 @@ test( ::before, ::backdrop, ::file-selector-button { - border-color: var(--color-gray-200, currentcolor); + border-color: var(--color-gray-200, currentColor); } } " @@ -1032,7 +883,7 @@ test( }, }, async ({ root, exec, fs, expect }) => { - await exec('pnpm exec upgrade', { + await exec('npx @tailwindcss/upgrade', { cwd: path.join(root, 'frontend'), }) @@ -1048,7 +899,7 @@ test( } /* - The default border color has changed to \`currentcolor\` in Tailwind CSS v4, + The default border color has changed to \`currentColor\` in Tailwind CSS v4, so we've added these compatibility styles to make sure everything still looks the same as it did with Tailwind CSS v3. @@ -1061,253 +912,7 @@ test( ::before, ::backdrop, ::file-selector-button { - border-color: var(--color-gray-200, currentcolor); - } - } - " - `) - }, -) - -test( - 'migrate aria theme keys to custom variants', - { - fs: { - 'package.json': json` - { - "dependencies": { - "tailwindcss": "^3", - "@tailwindcss/upgrade": "workspace:^" - } - } - `, - 'tailwind.config.ts': ts` - export default { - content: { - relative: true, - files: ['./src/**/*.html'], - }, - theme: { - extend: { - aria: { - // Built-in (not really, but visible because of intellisense) - busy: 'busy="true"', - - // Automatically handled by bare values - foo: 'foo="true"', - - // Quotes are optional in CSS for these kinds of attribute - // selectors - bar: 'bar=true', - - // Not automatically handled by bare values because names differ - baz: 'qux="true"', - - // Completely custom - asc: 'sort="ascending"', - desc: 'sort="descending"', - }, - }, - }, - } - `, - 'src/input.css': css` - @tailwind base; - @tailwind components; - @tailwind utilities; - `, - }, - }, - async ({ exec, fs, expect }) => { - await exec('pnpm exec upgrade') - - expect(await fs.dumpFiles('src/*.css')).toMatchInlineSnapshot(` - " - --- src/input.css --- - @import 'tailwindcss'; - - @custom-variant aria-baz (&[aria-qux="true"]); - @custom-variant aria-asc (&[aria-sort="ascending"]); - @custom-variant aria-desc (&[aria-sort="descending"]); - - /* - The default border color has changed to \`currentcolor\` in Tailwind CSS v4, - so we've added these compatibility styles to make sure everything still - looks the same as it did with Tailwind CSS v3. - - If we ever want to remove these styles, we need to add an explicit border - color utility to any element that depends on these defaults. - */ - @layer base { - *, - ::after, - ::before, - ::backdrop, - ::file-selector-button { - border-color: var(--color-gray-200, currentcolor); - } - } - " - `) - }, -) - -test( - 'migrate data theme keys to custom variants', - { - fs: { - 'package.json': json` - { - "dependencies": { - "tailwindcss": "^3", - "@tailwindcss/upgrade": "workspace:^" - } - } - `, - 'tailwind.config.ts': ts` - export default { - content: { - relative: true, - files: ['./src/**/*.html'], - }, - theme: { - extend: { - data: { - // Automatically handled by bare values - foo: 'foo', - - // Not automatically handled by bare values because names differ - bar: 'baz', - - // Custom - checked: 'ui~="checked"', - }, - }, - }, - } - `, - 'src/input.css': css` - @tailwind base; - @tailwind components; - @tailwind utilities; - `, - }, - }, - async ({ exec, fs, expect }) => { - await exec('pnpm exec upgrade') - - expect(await fs.dumpFiles('src/*.css')).toMatchInlineSnapshot(` - " - --- src/input.css --- - @import 'tailwindcss'; - - @custom-variant data-bar (&[data-baz]); - @custom-variant data-checked (&[data-ui~="checked"]); - - /* - The default border color has changed to \`currentcolor\` in Tailwind CSS v4, - so we've added these compatibility styles to make sure everything still - looks the same as it did with Tailwind CSS v3. - - If we ever want to remove these styles, we need to add an explicit border - color utility to any element that depends on these defaults. - */ - @layer base { - *, - ::after, - ::before, - ::backdrop, - ::file-selector-button { - border-color: var(--color-gray-200, currentcolor); - } - } - " - `) - }, -) - -test( - 'migrate supports theme keys to custom variants', - { - fs: { - 'package.json': json` - { - "dependencies": { - "tailwindcss": "^3", - "@tailwindcss/upgrade": "workspace:^" - } - } - `, - 'tailwind.config.ts': ts` - export default { - content: { - relative: true, - files: ['./src/**/*.html'], - }, - theme: { - extend: { - supports: { - // Automatically handled by bare values (using CSS variable as the value) - foo: 'foo: var(--foo)', // parentheses are optional - bar: '(bar: var(--bar))', - - // Not automatically handled by bare values because names differ - foo: 'bar: var(--foo)', // parentheses are optional - bar: '(qux: var(--bar))', - - // Custom - grid: 'display: grid', - }, - }, - }, - } - `, - 'src/input.css': css` - @tailwind base; - @tailwind components; - @tailwind utilities; - `, - }, - }, - async ({ exec, fs, expect }) => { - await exec('pnpm exec upgrade') - - expect(await fs.dumpFiles('src/*.css')).toMatchInlineSnapshot(` - " - --- src/input.css --- - @import 'tailwindcss'; - - @custom-variant supports-foo { - @supports (bar: var(--foo)) { - @slot; - } - } - @custom-variant supports-bar { - @supports ((qux: var(--bar))) { - @slot; - } - } - @custom-variant supports-grid { - @supports (display: grid) { - @slot; - } - } - - /* - The default border color has changed to \`currentcolor\` in Tailwind CSS v4, - so we've added these compatibility styles to make sure everything still - looks the same as it did with Tailwind CSS v3. - - If we ever want to remove these styles, we need to add an explicit border - color utility to any element that depends on these defaults. - */ - @layer base { - *, - ::after, - ::before, - ::backdrop, - ::file-selector-button { - border-color: var(--color-gray-200, currentcolor); + border-color: var(--color-gray-200, currentColor); } } " @@ -1346,7 +951,7 @@ describe('border compatibility', () => { }, }, async ({ exec, fs, expect }) => { - await exec('pnpm exec upgrade') + await exec('npx @tailwindcss/upgrade') expect(await fs.dumpFiles('src/**/*.css')).toMatchInlineSnapshot(` " @@ -1354,7 +959,7 @@ describe('border compatibility', () => { @import 'tailwindcss'; /* - The default border color has changed to \`currentcolor\` in Tailwind CSS v4, + The default border color has changed to \`currentColor\` in Tailwind CSS v4, so we've added these compatibility styles to make sure everything still looks the same as it did with Tailwind CSS v3. @@ -1367,7 +972,7 @@ describe('border compatibility', () => { ::before, ::backdrop, ::file-selector-button { - border-color: var(--color-gray-200, currentcolor); + border-color: var(--color-gray-200, currentColor); } } " @@ -1408,7 +1013,7 @@ describe('border compatibility', () => { }, }, async ({ exec, fs, expect }) => { - await exec('pnpm exec upgrade') + await exec('npx @tailwindcss/upgrade') expect(await fs.dumpFiles('src/**/*.css')).toMatchInlineSnapshot(` " @@ -1416,7 +1021,7 @@ describe('border compatibility', () => { @import 'tailwindcss'; /* - The default border color has changed to \`currentcolor\` in Tailwind CSS v4, + The default border color has changed to \`currentColor\` in Tailwind CSS v4, so we've added these compatibility styles to make sure everything still looks the same as it did with Tailwind CSS v3. @@ -1429,7 +1034,7 @@ describe('border compatibility', () => { ::before, ::backdrop, ::file-selector-button { - border-color: oklch(62.3% 0.214 259.815); + border-color: oklch(0.623 0.214 259.815); } } " @@ -1456,7 +1061,7 @@ describe('border compatibility', () => { theme: { extend: { borderColor: ({ colors }) => ({ - DEFAULT: 'currentcolor', + DEFAULT: 'currentColor', }), }, }, @@ -1470,7 +1075,7 @@ describe('border compatibility', () => { }, }, async ({ exec, fs, expect }) => { - await exec('pnpm exec upgrade') + await exec('npx @tailwindcss/upgrade') expect(await fs.dumpFiles('src/**/*.css')).toMatchInlineSnapshot(` " @@ -1509,7 +1114,7 @@ describe('border compatibility', () => { }, }, async ({ exec, fs, expect }) => { - await exec('pnpm exec upgrade') + await exec('npx @tailwindcss/upgrade') expect(await fs.dumpFiles('src/**/*.css')).toMatchInlineSnapshot(` " @@ -1520,7 +1125,7 @@ describe('border compatibility', () => { @import 'tailwindcss'; /* - The default border color has changed to \`currentcolor\` in Tailwind CSS v4, + The default border color has changed to \`currentColor\` in Tailwind CSS v4, so we've added these compatibility styles to make sure everything still looks the same as it did with Tailwind CSS v3. @@ -1533,7 +1138,7 @@ describe('border compatibility', () => { ::before, ::backdrop, ::file-selector-button { - border-color: var(--color-gray-200, currentcolor); + border-color: var(--color-gray-200, currentColor); } } " @@ -1580,7 +1185,7 @@ describe('border compatibility', () => { }, }, async ({ exec, fs, expect }) => { - await exec('pnpm exec upgrade') + await exec('npx @tailwindcss/upgrade') expect(await fs.dumpFiles('src/**/*.css')).toMatchInlineSnapshot(` " @@ -1589,7 +1194,7 @@ describe('border compatibility', () => { @import 'tailwindcss/preflight' layer(base); /* - The default border color has changed to \`currentcolor\` in Tailwind CSS v4, + The default border color has changed to \`currentColor\` in Tailwind CSS v4, so we've added these compatibility styles to make sure everything still looks the same as it did with Tailwind CSS v3. @@ -1602,7 +1207,7 @@ describe('border compatibility', () => { ::before, ::backdrop, ::file-selector-button { - border-color: var(--color-gray-200, currentcolor); + border-color: var(--color-gray-200, currentColor); } } @@ -1683,18 +1288,18 @@ describe('border compatibility', () => { }, }, async ({ exec, fs, expect }) => { - await exec('pnpm exec upgrade') + await exec('npx @tailwindcss/upgrade') expect(await fs.dumpFiles('src/**/*.{css,html}')).toMatchInlineSnapshot(` " --- src/index.html ---
--- src/input.css --- @@ -1707,7 +1312,7 @@ describe('border compatibility', () => { } /* - The default border color has changed to \`currentcolor\` in Tailwind CSS v4, + The default border color has changed to \`currentColor\` in Tailwind CSS v4, so we've added these compatibility styles to make sure everything still looks the same as it did with Tailwind CSS v3. @@ -1720,15 +1325,15 @@ describe('border compatibility', () => { ::before, ::backdrop, ::file-selector-button { - border-color: var(--color-gray-200, currentcolor); + border-color: var(--color-gray-200, currentColor); } } .container { - width: --spacing(2); - width: --spacing(4.5); + width: calc(var(--spacing) * 2); + width: calc(var(--spacing) * 4.5); width: var(--spacing-5_5); - width: --spacing(13); + width: calc(var(--spacing) * 13); width: var(--spacing-100); width: var(--spacing-miami); } @@ -1793,18 +1398,18 @@ describe('border compatibility', () => { }, }, async ({ exec, fs, expect }) => { - await exec('pnpm exec upgrade') + await exec('npx @tailwindcss/upgrade') expect(await fs.dumpFiles('src/**/*.{css,html}')).toMatchInlineSnapshot(` " --- src/index.html ---
--- src/input.css --- @@ -1821,7 +1426,7 @@ describe('border compatibility', () => { } /* - The default border color has changed to \`currentcolor\` in Tailwind CSS v4, + The default border color has changed to \`currentColor\` in Tailwind CSS v4, so we've added these compatibility styles to make sure everything still looks the same as it did with Tailwind CSS v3. @@ -1834,7 +1439,7 @@ describe('border compatibility', () => { ::before, ::backdrop, ::file-selector-button { - border-color: var(--color-gray-200, currentcolor); + border-color: var(--color-gray-200, currentColor); } } @@ -1895,7 +1500,7 @@ describe('border compatibility', () => { }, }, async ({ exec, fs, expect }) => { - await exec('pnpm exec upgrade') + await exec('npx @tailwindcss/upgrade') expect(await fs.dumpFiles('src/**/*.{css,html}')).toMatchInlineSnapshot(` " @@ -1908,7 +1513,7 @@ describe('border compatibility', () => { @utility container { margin-inline: auto; padding-inline: 2rem; - @media (width >= --theme(--breakpoint-sm)) { + @media (width >= theme(--breakpoint-sm)) { max-width: none; } @media (width >= 48rem) { @@ -1924,7 +1529,7 @@ describe('border compatibility', () => { } /* - The default border color has changed to \`currentcolor\` in Tailwind CSS v4, + The default border color has changed to \`currentColor\` in Tailwind CSS v4, so we've added these compatibility styles to make sure everything still looks the same as it did with Tailwind CSS v3. @@ -1937,7 +1542,7 @@ describe('border compatibility', () => { ::before, ::backdrop, ::file-selector-button { - border-color: var(--color-gray-200, currentcolor); + border-color: var(--color-gray-200, currentColor); } } " @@ -1945,243 +1550,3 @@ describe('border compatibility', () => { }, ) }) - -test( - `future and experimental keys are supported`, - { - fs: { - 'package.json': json` - { - "dependencies": { - "tailwindcss": "^3", - "@tailwindcss/upgrade": "workspace:^" - } - } - `, - 'tailwind.config.ts': ts` - import { type Config } from 'tailwindcss' - import defaultTheme from 'tailwindcss/defaultTheme' - - module.exports = { - darkMode: 'selector', - content: ['./src/**/*.{html,js}'], - future: { - hoverOnlyWhenSupported: true, - respectDefaultRingColorOpacity: true, - disableColorOpacityUtilitiesByDefault: true, - relativeContentPathsByDefault: true, - }, - experimental: { - generalizedModifiers: true, - }, - theme: { - colors: { - red: { - 400: '#f87171', - 500: 'red', - }, - }, - }, - plugins: [], - } satisfies Config - `, - 'src/input.css': css` - @tailwind base; - @tailwind components; - @tailwind utilities; - `, - }, - }, - async ({ exec, fs, expect }) => { - await exec('pnpm exec upgrade') - - expect(await fs.dumpFiles('src/**/*.css')).toMatchInlineSnapshot(` - " - --- src/input.css --- - @import 'tailwindcss'; - - @custom-variant dark (&:where(.dark, .dark *)); - - @theme { - --color-*: initial; - --color-red-400: #f87171; - --color-red-500: red; - } - - /* - The default border color has changed to \`currentcolor\` in Tailwind CSS v4, - so we've added these compatibility styles to make sure everything still - looks the same as it did with Tailwind CSS v3. - - If we ever want to remove these styles, we need to add an explicit border - color utility to any element that depends on these defaults. - */ - @layer base { - *, - ::after, - ::before, - ::backdrop, - ::file-selector-button { - border-color: var(--color-gray-200, currentcolor); - } - } - " - `) - - expect((await fs.dumpFiles('tailwind.config.ts')).trim()).toBe('') - }, -) - -test( - `unknown future keys dont migrate the config`, - { - fs: { - 'package.json': json` - { - "dependencies": { - "tailwindcss": "^3", - "@tailwindcss/upgrade": "workspace:^" - } - } - `, - 'tailwind.config.ts': ts` - import { type Config } from 'tailwindcss' - import defaultTheme from 'tailwindcss/defaultTheme' - - module.exports = { - darkMode: 'selector', - content: ['./src/**/*.{html,js}'], - future: { - something: true, - }, - } satisfies Config - `, - 'src/input.css': css` - @tailwind base; - @tailwind components; - @tailwind utilities; - `, - }, - }, - async ({ exec, fs, expect }) => { - await exec('pnpm exec upgrade') - - expect(await fs.dumpFiles('src/**/*.css')).toMatchInlineSnapshot(` - " - --- src/input.css --- - @import 'tailwindcss'; - - @config '../tailwind.config.ts'; - - /* - The default border color has changed to \`currentcolor\` in Tailwind CSS v4, - so we've added these compatibility styles to make sure everything still - looks the same as it did with Tailwind CSS v3. - - If we ever want to remove these styles, we need to add an explicit border - color utility to any element that depends on these defaults. - */ - @layer base { - *, - ::after, - ::before, - ::backdrop, - ::file-selector-button { - border-color: var(--color-gray-200, currentcolor); - } - } - " - `) - - expect((await fs.dumpFiles('tailwind.config.ts')).trim()).toMatchInlineSnapshot(` - "--- tailwind.config.ts --- - import { type Config } from 'tailwindcss' - import defaultTheme from 'tailwindcss/defaultTheme' - - module.exports = { - darkMode: 'selector', - content: ['./src/**/*.{html,js}'], - future: { - something: true, - }, - } satisfies Config" - `) - }, -) - -test( - `unknown experimental keys dont migrate the config`, - { - fs: { - 'package.json': json` - { - "dependencies": { - "tailwindcss": "^3", - "@tailwindcss/upgrade": "workspace:^" - } - } - `, - 'tailwind.config.ts': ts` - import { type Config } from 'tailwindcss' - import defaultTheme from 'tailwindcss/defaultTheme' - - module.exports = { - darkMode: 'selector', - content: ['./src/**/*.{html,js}'], - experimental: { - something: true, - }, - } satisfies Config - `, - 'src/input.css': css` - @tailwind base; - @tailwind components; - @tailwind utilities; - `, - }, - }, - async ({ exec, fs, expect }) => { - await exec('pnpm exec upgrade') - - expect(await fs.dumpFiles('src/**/*.css')).toMatchInlineSnapshot(` - " - --- src/input.css --- - @import 'tailwindcss'; - - @config '../tailwind.config.ts'; - - /* - The default border color has changed to \`currentcolor\` in Tailwind CSS v4, - so we've added these compatibility styles to make sure everything still - looks the same as it did with Tailwind CSS v3. - - If we ever want to remove these styles, we need to add an explicit border - color utility to any element that depends on these defaults. - */ - @layer base { - *, - ::after, - ::before, - ::backdrop, - ::file-selector-button { - border-color: var(--color-gray-200, currentcolor); - } - } - " - `) - - expect((await fs.dumpFiles('tailwind.config.ts')).trim()).toMatchInlineSnapshot(` - "--- tailwind.config.ts --- - import { type Config } from 'tailwindcss' - import defaultTheme from 'tailwindcss/defaultTheme' - - module.exports = { - darkMode: 'selector', - content: ['./src/**/*.{html,js}'], - experimental: { - something: true, - }, - } satisfies Config" - `) - }, -) diff --git a/integrations/upgrade/upgrade-errors.test.ts b/integrations/upgrade/upgrade-errors.test.ts deleted file mode 100644 index fdc60828e..000000000 --- a/integrations/upgrade/upgrade-errors.test.ts +++ /dev/null @@ -1,254 +0,0 @@ -import { stripVTControlCharacters } from 'node:util' -import { css, html, js, json, test } from '../utils' - -test( - 'upgrades half-upgraded v3 project to v4 (pnpm)', - { - fs: { - 'package.json': json` - { - "dependencies": { - "tailwindcss": "^3", - "@tailwindcss/upgrade": "workspace:^" - }, - "devDependencies": { - "@tailwindcss/cli": "workspace:^" - } - } - `, - 'tailwind.config.js': js` - /** @type {import('tailwindcss').Config} */ - module.exports = { - content: ['./src/**/*.{html,js}'], - } - `, - 'src/index.html': html` -
Hello World
- `, - 'src/input.css': css` - @tailwind base; - @tailwind components; - @tailwind utilities; - `, - }, - retry: 0, - }, - async ({ exec, expect }) => { - // Ensure we are in a git repo - await exec('git init') - await exec('git add --all') - await exec('git commit -m "before migration"') - - // Fully upgrade to v4 - await exec('pnpm exec upgrade') - - // Undo all changes to the current repo. This will bring the repo back to a - // v3 state, but the `node_modules` will now have v4 installed. - await exec('git reset --hard HEAD') - - // Re-running the upgrade should result in an error - return expect(() => { - return exec('pnpm exec upgrade', {}, { ignoreStdErr: true }).catch((e) => { - // Replacing the current version with a hardcoded `v4` to make it stable - // when we release new minor/patch versions. - return Promise.reject( - stripVTControlCharacters(e.message.replace(/\d+\.\d+\.\d+/g, '4.0.0')), - ) - }) - }).rejects.toThrowErrorMatchingInlineSnapshot(` - "Command failed: pnpm exec upgrade - ≈ tailwindcss v4.0.0 - - │ ↳ Upgrading from Tailwind CSS \`v4.0.0\` - - │ ↳ Version mismatch - │ - │ \`\`\`diff - │ - "tailwindcss": "^3" (expected version in \`package.json\`) - │ + "tailwindcss": "4.0.0" (installed version in \`node_modules\`) - │ \`\`\` - │ - │ Make sure to run \`pnpm install\` and try again. - - " - `) - }, -) - -test( - 'upgrades half-upgraded v3 project to v4 (bun)', - { - fs: { - 'package.json': json` - { - "dependencies": { - "tailwindcss": "^3", - "@tailwindcss/upgrade": "workspace:^" - }, - "devDependencies": { - "@tailwindcss/cli": "workspace:^", - "bun": "^1.0.0" - } - } - `, - 'tailwind.config.js': js` - /** @type {import('tailwindcss').Config} */ - module.exports = { - content: ['./src/**/*.{html,js}'], - } - `, - 'src/index.html': html` -
Hello World
- `, - 'src/input.css': css` - @tailwind base; - @tailwind components; - @tailwind utilities; - `, - }, - retry: 0, - }, - async ({ exec, expect }) => { - // Use `bun` to install dependencies - await exec('rm ./pnpm-lock.yaml') - try { - await exec('npx bun install', {}, { ignoreStdErr: true }) - } catch (e) { - // When preparing for a release, the version in `package.json` will point - // to a non-existent version because it's not published yet. - // TODO: Find a better approach to handle this and actually test it even - // on release branches. Note: the pnpm version _does_ work because of - // overrides in the package.json file. - if (`${e}`.includes('No version matching')) return - throw e - } - - // Ensure we are in a git repo - await exec('git init') - await exec('git add --all') - await exec('git commit -m "before migration"') - - // Fully upgrade to v4 - await exec('npx @tailwindcss/upgrade') - - // Undo all changes to the current repo. This will bring the repo back to a - // v3 state, but the `node_modules` will now have v4 installed. - await exec('git reset --hard HEAD') - - // Re-running the upgrade should result in an error - return expect(() => { - return exec('npx @tailwindcss/upgrade', {}, { ignoreStdErr: true }).catch((e) => { - // Replacing the current version with a hardcoded `v4` to make it stable - // when we release new minor/patch versions. - return Promise.reject( - stripVTControlCharacters(e.message.replace(/\d+\.\d+\.\d+/g, '4.0.0')), - ) - }) - }).rejects.toThrowErrorMatchingInlineSnapshot(` - "Command failed: npx @tailwindcss/upgrade - ≈ tailwindcss v4.0.0 - - │ ↳ Upgrading from Tailwind CSS \`v4.0.0\` - - │ ↳ Version mismatch - │ - │ \`\`\`diff - │ - "tailwindcss": "^3" (expected version in \`package.json\`) - │ + "tailwindcss": "4.0.0" (installed version in \`node_modules\`) - │ \`\`\` - │ - │ Make sure to run \`bun install\` and try again. - - " - `) - }, -) - -test( - 'upgrades half-upgraded v3 project to v4 (npm)', - { - fs: { - 'package.json': json` - { - "dependencies": { - "tailwindcss": "^3", - "@tailwindcss/upgrade": "workspace:^" - }, - "devDependencies": { - "@tailwindcss/cli": "workspace:^" - } - } - `, - 'tailwind.config.js': js` - /** @type {import('tailwindcss').Config} */ - module.exports = { - content: ['./src/**/*.{html,js}'], - } - `, - 'src/index.html': html` -
Hello World
- `, - 'src/input.css': css` - @tailwind base; - @tailwind components; - @tailwind utilities; - `, - }, - retry: 0, - }, - async ({ exec, expect }) => { - // Use `npm` to install dependencies - await exec('rm ./pnpm-lock.yaml') - await exec('rm -rf ./node_modules') - try { - await exec('npm install', {}, { ignoreStdErr: true }) - } catch (e) { - // When preparing for a release, the version in `package.json` will point - // to a non-existent version because it's not published yet. - // TODO: Find a better approach to handle this and actually test it even - // on release branches. Note: the pnpm version _does_ work because of - // overrides in the package.json file. - if (`${e}`.includes('npm error code ETARGET')) return - throw e - } - - // Ensure we are in a git repo - await exec('git init') - await exec('git add --all') - await exec('git commit -m "before migration"') - - // Fully upgrade to v4 - await exec('npx @tailwindcss/upgrade') - - // Undo all changes to the current repo. This will bring the repo back to a - // v3 state, but the `node_modules` will now have v4 installed. - await exec('git reset --hard HEAD') - - // Re-running the upgrade should result in an error - return expect(() => { - return exec('npx @tailwindcss/upgrade', {}, { ignoreStdErr: true }).catch((e) => { - // Replacing the current version with a hardcoded `v4` to make it stable - // when we release new minor/patch versions. - return Promise.reject( - stripVTControlCharacters(e.message.replace(/\d+\.\d+\.\d+/g, '4.0.0')), - ) - }) - }).rejects.toThrowErrorMatchingInlineSnapshot(` - "Command failed: npx @tailwindcss/upgrade - ≈ tailwindcss v4.0.0 - - │ ↳ Upgrading from Tailwind CSS \`v4.0.0\` - - │ ↳ Version mismatch - │ - │ \`\`\`diff - │ - "tailwindcss": "^3" (expected version in \`package.json\`) - │ + "tailwindcss": "4.0.0" (installed version in \`node_modules\`) - │ \`\`\` - │ - │ Make sure to run \`npm install\` and try again. - - " - `) - }, -) diff --git a/integrations/utils.ts b/integrations/utils.ts index 9863918d1..8f916a3d0 100644 --- a/integrations/utils.ts +++ b/integrations/utils.ts @@ -1,28 +1,19 @@ import dedent from 'dedent' import fastGlob from 'fast-glob' -import { exec, execFile, spawn, type ChildProcess } from 'node:child_process' +import { exec, spawn } from 'node:child_process' import fs from 'node:fs/promises' -import { createServer } from 'node:net' import { platform, tmpdir } from 'node:os' import path from 'node:path' -import { promisify, stripVTControlCharacters } from 'node:util' -import { RawSourceMap, SourceMapConsumer } from 'source-map-js' +import { stripVTControlCharacters } from 'node:util' import { test as defaultTest, type ExpectStatic } from 'vitest' -import * as Yaml from 'yaml' -import { createLineTable } from '../packages/tailwindcss/src/source-maps/line-table' -import { escape } from '../packages/tailwindcss/src/utils/escape' const REPO_ROOT = path.join(__dirname, '..') -const ROOT_PNPM_WORKSPACE = Yaml.parse( - await fs.readFile(path.join(REPO_ROOT, 'pnpm-workspace.yaml'), 'utf8'), -) const PUBLIC_PACKAGES = (await fs.readdir(path.join(REPO_ROOT, 'dist'))).map((name) => name.replace('tailwindcss-', '@tailwindcss/').replace('.tgz', ''), ) interface SpawnedProcess { - dispose: () => Promise - flush: () => void + dispose: () => void onStdout: (predicate: (message: string) => boolean) => Promise onStderr: (predicate: (message: string) => boolean) => Promise } @@ -34,37 +25,29 @@ interface ChildProcessOptions { interface ExecOptions { ignoreStdErr?: boolean - stdin?: string } interface TestConfig { fs: { [filePath: string]: string | Uint8Array } - - timeout?: number - installDependencies?: boolean - retry?: number } interface TestContext { root: string expect: ExpectStatic exec(command: string, options?: ChildProcessOptions, execOptions?: ExecOptions): Promise spawn(command: string, options?: ChildProcessOptions): Promise - parseSourceMap(opts: string | SourceMapOptions): SourceMap fs: { - write(filePath: string, content: string, encoding?: BufferEncoding): Promise - symlink(dst: string, src: string): Promise + write(filePath: string, content: string): Promise create(filePaths: string[]): Promise read(filePath: string): Promise - delete(filePath: string): Promise glob(pattern: string): Promise<[string, string][]> dumpFiles(pattern: string): Promise expectFileToContain( filePath: string, contents: string | RegExp | (string | RegExp)[], ): Promise - expectFileNotToContain(filePath: string, contents: string[]): Promise + expectFileNotToContain(filePath: string, contents: string | string[]): Promise } } type TestCallback = (context: TestContext) => Promise | void @@ -72,14 +55,11 @@ interface TestFlags { only?: boolean skip?: boolean debug?: boolean - concurrent?: boolean } type SpawnActor = { predicate: (message: string) => boolean; resolve: () => void } -export const IS_WINDOWS = platform() === 'win32' - -const execFileAsync = promisify(execFile) +const IS_WINDOWS = platform() === 'win32' const TEST_TIMEOUT = IS_WINDOWS ? 120000 : 60000 const ASSERTION_TIMEOUT = IS_WINDOWS ? 10000 : 5000 @@ -93,16 +73,16 @@ export function test( name: string, config: TestConfig, testCallback: TestCallback, - { only = false, skip = false, debug = false, concurrent = false }: TestFlags = {}, + { only = false, skip = false, debug = false }: TestFlags = {}, ) { return defaultTest( name, { - timeout: config.timeout ?? TEST_TIMEOUT, - retry: config.retry ?? (process.env.CI ? 2 : 0), + timeout: TEST_TIMEOUT, + retry: process.env.CI ? 2 : 0, only: only || (!process.env.CI && debug), skip, - concurrent, + concurrent: true, }, async (options) => { let rootDir = debug ? path.join(REPO_ROOT, '.debug') : TMP_ROOT @@ -119,46 +99,12 @@ export function test( let context = { root, expect: options.expect, - parseSourceMap, async exec( command: string, childProcessOptions: ChildProcessOptions = {}, execOptions: ExecOptions = {}, ) { let cwd = childProcessOptions.cwd ?? root - let originalCommand = command - - // Avoid `pnpm exec upgrade` on Windows because the upgrader runs - // `pnpm add`, which rewrites Windows `.cmd` shims while the current - // shim is still executing. - // - // Pretty sure this is a pnpm v11 bug on Windows. - if (IS_WINDOWS && command.includes('pnpm exec upgrade')) { - for (let base = cwd; ; base = path.dirname(base)) { - let upgradeBin = path.join( - base, - 'node_modules', - '@tailwindcss', - 'upgrade', - 'dist', - 'index.mjs', - ) - - try { - await fs.access(upgradeBin) - command = command.replace('pnpm exec upgrade', `node "${upgradeBin}"`) - break - } catch (error: any) { - if (error?.code !== 'ENOENT') throw error - } - - let parent = path.dirname(base) - if (parent === base) { - throw new Error(`Unable to resolve @tailwindcss/upgrade from ${cwd}`) - } - } - } - if (debug && cwd !== root) { let relative = path.relative(root, cwd) if (relative[0] !== '.') relative = `./${relative}` @@ -166,23 +112,15 @@ export function test( } if (debug) console.log(`> ${command}`) return new Promise((resolve, reject) => { - let child = exec( + exec( command, { cwd, ...childProcessOptions, - env: { - ...process.env, - ...childProcessOptions.env, - }, + env: childProcessOptions.env, }, (error, stdout, stderr) => { if (error) { - if (command !== originalCommand) { - error.message = error.message.replace(command, originalCommand) - let mappedError = error as any - mappedError.cmd = originalCommand - } if (execOptions.ignoreStdErr !== true) console.error(stderr) if (only || debug) { console.error(stdout) @@ -196,10 +134,6 @@ export function test( } }, ) - if (execOptions.stdin) { - child.stdin?.write(execOptions.stdin) - child.stdin?.end() - } }) }, async spawn(command: string, childProcessOptions: ChildProcessOptions = {}) { @@ -219,7 +153,6 @@ export function test( if (debug) console.log(`>& ${command}`) let child = spawn(command, { cwd, - detached: !IS_WINDOWS, shell: true, ...childProcessOptions, env: { @@ -228,26 +161,22 @@ export function test( }, }) - let disposed = false + function dispose() { + if (!child.kill()) { + child.kill('SIGKILL') + } - async function dispose() { - if (disposed) return disposePromise - disposed = true - - await killProcessTree(child) - - let timer = setTimeout(() => { - forceKillProcessTree(child) - rejectDisposal?.(new Error(`spawned process (${command}) did not exit in time`)) - }, ASSERTION_TIMEOUT) - disposePromise.then( - () => clearTimeout(timer), - () => clearTimeout(timer), + let timer = setTimeout( + () => + rejectDisposal?.(new Error(`spawned process (${command}) did not exit in time`)), + ASSERTION_TIMEOUT, ) + disposePromise.finally(() => { + clearTimeout(timer) + }) return disposePromise } disposables.push(dispose) - function onExit() { resolveDisposal?.() } @@ -316,13 +245,6 @@ export function test( return { dispose, - flush() { - stdoutActors.splice(0) - stderrActors.splice(0) - - stdoutMessages.splice(0) - stderrMessages.splice(0) - }, onStdout(predicate: (message: string) => boolean) { return new Promise((resolve) => { stdoutActors.push({ predicate, resolve }) @@ -338,7 +260,7 @@ export function test( } }, fs: { - async write(filename, content, encoding = 'utf8') { + async write(filename: string, content: string | Uint8Array): Promise { let full = path.join(root, filename) let dir = path.dirname(full) await fs.mkdir(dir, { recursive: true }) @@ -349,8 +271,6 @@ export function test( if (filename.endsWith('package.json')) { content = await overwriteVersionsInPackageJson(content) - } else if (filename.endsWith('pnpm-workspace.yaml')) { - content = overwriteVersionsInPnpmWorkspace(content) } // Ensure that files written on Windows use \r\n line ending @@ -358,22 +278,10 @@ export function test( content = content.replace(/\n/g, '\r\n') } - await fs.writeFile(full, content, encoding) + await fs.writeFile(full, content, 'utf-8') }, - async symlink(target, src) { - let targetAbsolute = path.join(root, target) - let targetParent = path.dirname(targetAbsolute) - await fs.mkdir(targetParent, { recursive: true }) - - let srcAbsolute = path.join(root, src) - let srcParent = path.dirname(srcAbsolute) - await fs.mkdir(srcParent, { recursive: true }) - - await fs.symlink(targetAbsolute, srcAbsolute) - }, - - async create(filenames) { + async create(filenames: string[]): Promise { for (let filename of filenames) { let full = path.join(root, filename) @@ -383,11 +291,7 @@ export function test( } }, - async delete(filename) { - await fs.unlink(path.join(root, filename)) - }, - - async read(filePath) { + async read(filePath: string) { let content = await fs.readFile(path.resolve(root, filePath), 'utf8') // Ensure that files read on Windows have \r\n line endings removed @@ -397,7 +301,7 @@ export function test( return content }, - async glob(pattern) { + async glob(pattern: string) { let files = await fastGlob(pattern, { cwd: root }) return Promise.all( files.map(async (file) => { @@ -405,12 +309,12 @@ export function test( return [ file, // Drop license comment - content.replace(/[\s\n]*\/\*![\s\S]*?\*\/[\s\n]*/g, ''), + content.replace(/[\s\n]*\/\*! tailwindcss .*? \*\/[\s\n]*/g, ''), ] }), ) }, - async dumpFiles(pattern) { + async dumpFiles(pattern: string) { let files = await context.fs.glob(pattern) return `\n${files .slice() @@ -469,45 +373,18 @@ export function test( node_modules/ ` - // Disable Git's automatic line ending conversion in these throwaway test - // repositories. Tools like pnpm write files (e.g. `pnpm-lock.yaml`) with - // LF endings, which on Windows (where `core.autocrlf=true` is common) - // makes Git emit noisy "LF will be replaced by CRLF" warnings when it - // touches those files. - config.fs['.gitattributes'] ??= txt` - * -text - ` - - // Ensure there is always a root `pnpm-workspace.yaml` so that transitive - // dependency overrides (and the build allow list) are injected into it. - // As of pnpm v10, these can no longer live in the `pnpm.overrides` field - // of `package.json`. - config.fs['pnpm-workspace.yaml'] ??= '' - for (let [filename, content] of Object.entries(config.fs)) { - if (content.toString().startsWith('symlink:')) { - // The symlink path is relative to the target destination's path - let target = path.join( - filename, - content.toString().slice('symlink:'.length), // Relative path - ) - - await context.fs.symlink(target, filename) - } else { - await context.fs.write(filename, content) - } + await context.fs.write(filename, content) } - let shouldInstallDependencies = config.installDependencies ?? true - try { - // Every test project gets its own root `pnpm-workspace.yaml` (see - // above). This makes the test directory its own workspace root, so even - // in debug mode — where the directory lives inside this repository's - // pnpm workspace — `pnpm install` won't attach to the parent workspace. - if (shouldInstallDependencies) { - await context.exec(`pnpm install`) - } + // In debug mode, the directory is going to be inside the pnpm workspace + // of the tailwindcss package. This means that `pnpm install` will run + // pnpm install on the workspace instead (expect if the root dir defines + // a separate workspace). We work around this by using the + // `--ignore-workspace` flag. + let ignoreWorkspace = debug && !config.fs['pnpm-workspace.yaml'] + await context.exec(`pnpm install${ignoreWorkspace ? ' --ignore-workspace' : ''}`) } catch (error: any) { console.error(error) console.error(error.stdout?.toString()) @@ -518,18 +395,11 @@ export function test( let disposables: (() => Promise)[] = [] async function dispose() { - let results = await Promise.allSettled(disposables.map((dispose) => dispose())) + await Promise.all(disposables.map((dispose) => dispose())) if (!debug) { await gracefullyRemove(root) } - - let errors = results.flatMap((result) => - result.status === 'rejected' ? [result.reason] : [], - ) - if (errors.length > 0) { - throw new AggregateError(errors, 'Failed to clean up spawned processes') - } } options.onTestFinished(dispose) @@ -539,7 +409,7 @@ export function test( try { await context.exec('git init', { cwd: root }) await context.exec('git add --all', { cwd: root }) - await context.exec('git commit -m "before migration" --allow-empty', { cwd: root }) + await context.exec('git commit -m "before migration"', { cwd: root }) } catch (error: any) { console.error(error) console.error(error.stdout?.toString()) @@ -558,9 +428,6 @@ test.only = (name: string, config: TestConfig, testCallback: TestCallback) => { test.skip = (name: string, config: TestConfig, testCallback: TestCallback) => { return test(name, config, testCallback, { skip: true }) } -test.concurrent = (name: string, config: TestConfig, testCallback: TestCallback) => { - return test(name, config, testCallback, { concurrent: true }) -} test.debug = (name: string, config: TestConfig, testCallback: TestCallback) => { return test(name, config, testCallback, { debug: true }) } @@ -584,43 +451,27 @@ async function overwriteVersionsInPackageJson(content: string): Promise } } - return JSON.stringify(json, null, 2) -} - -function overwriteVersionsInPnpmWorkspace(content: string): string { - let workspace = content.trim() === '' ? {} : Yaml.parse(content) - - // Inherit information from the root workspace - workspace.allowBuilds = { - ...ROOT_PNPM_WORKSPACE.allowBuilds, - ...workspace.allowBuilds, - } - // Inject transitive dependency overwrite. This is necessary because // @tailwindcss/vite internally depends on a specific version of // @tailwindcss/oxide and we instead want to resolve it to the locally built // version. - // - // As of pnpm v10, the `pnpm.overrides` field in `package.json` is no longer - // read. Overrides have to be defined in `pnpm-workspace.yaml` instead. - workspace.overrides ||= {} + json.pnpm ||= {} + json.pnpm.overrides ||= {} for (let pkg of PUBLIC_PACKAGES) { if (pkg === 'tailwindcss') { // We want to be explicit about the `tailwindcss` package so our tests can // also import v3 without conflicting v4 tarballs. - workspace.overrides['@tailwindcss/node>tailwindcss'] = resolveVersion(pkg) - workspace.overrides['@tailwindcss/upgrade>tailwindcss'] = resolveVersion(pkg) - workspace.overrides['@tailwindcss/cli>tailwindcss'] = resolveVersion(pkg) - workspace.overrides['@tailwindcss/postcss>tailwindcss'] = resolveVersion(pkg) - workspace.overrides['@tailwindcss/turbopack>tailwindcss'] = resolveVersion(pkg) - workspace.overrides['@tailwindcss/vite>tailwindcss'] = resolveVersion(pkg) - workspace.overrides['@tailwindcss/webpack>tailwindcss'] = resolveVersion(pkg) + json.pnpm.overrides['@tailwindcss/node>tailwindcss'] = resolveVersion(pkg) + json.pnpm.overrides['@tailwindcss/upgrade>tailwindcss'] = resolveVersion(pkg) + json.pnpm.overrides['@tailwindcss/cli>tailwindcss'] = resolveVersion(pkg) + json.pnpm.overrides['@tailwindcss/postcss>tailwindcss'] = resolveVersion(pkg) + json.pnpm.overrides['@tailwindcss/vite>tailwindcss'] = resolveVersion(pkg) } else { - workspace.overrides[pkg] = resolveVersion(pkg) + json.pnpm.overrides[pkg] = resolveVersion(pkg) } } - return Yaml.stringify(workspace) + return JSON.stringify(json, null, 2) } function resolveVersion(dependency: string) { @@ -637,7 +488,6 @@ export let css = dedent export let html = dedent export let ts = dedent export let js = dedent -export let jsx = dedent export let json = dedent export let yaml = dedent export let txt = dedent @@ -660,6 +510,80 @@ export function candidate(strings: TemplateStringsArray, ...values: any[]) { return `.${escape(output.join('').trim())}` } +// https://drafts.csswg.org/cssom/#serialize-an-identifier +export function escape(value: string) { + if (arguments.length == 0) { + throw new TypeError('`CSS.escape` requires an argument.') + } + var string = String(value) + var length = string.length + var index = -1 + var codeUnit + var result = '' + var firstCodeUnit = string.charCodeAt(0) + + if ( + // If the character is the first character and is a `-` (U+002D), and + // there is no second character, […] + length == 1 && + firstCodeUnit == 0x002d + ) { + return '\\' + string + } + + while (++index < length) { + codeUnit = string.charCodeAt(index) + // Note: there’s no need to special-case astral symbols, surrogate + // pairs, or lone surrogates. + + // If the character is NULL (U+0000), then the REPLACEMENT CHARACTER + // (U+FFFD). + if (codeUnit == 0x0000) { + result += '\uFFFD' + continue + } + + if ( + // If the character is in the range [\1-\1F] (U+0001 to U+001F) or is + // U+007F, […] + (codeUnit >= 0x0001 && codeUnit <= 0x001f) || + codeUnit == 0x007f || + // If the character is the first character and is in the range [0-9] + // (U+0030 to U+0039), […] + (index == 0 && codeUnit >= 0x0030 && codeUnit <= 0x0039) || + // If the character is the second character and is in the range [0-9] + // (U+0030 to U+0039) and the first character is a `-` (U+002D), […] + (index == 1 && codeUnit >= 0x0030 && codeUnit <= 0x0039 && firstCodeUnit == 0x002d) + ) { + // https://drafts.csswg.org/cssom/#escape-a-character-as-code-point + result += '\\' + codeUnit.toString(16) + ' ' + continue + } + + // If the character is not handled by one of the above rules and is + // greater than or equal to U+0080, is `-` (U+002D) or `_` (U+005F), or + // is in one of the ranges [0-9] (U+0030 to U+0039), [A-Z] (U+0041 to + // U+005A), or [a-z] (U+0061 to U+007A), […] + if ( + codeUnit >= 0x0080 || + codeUnit == 0x002d || + codeUnit == 0x005f || + (codeUnit >= 0x0030 && codeUnit <= 0x0039) || + (codeUnit >= 0x0041 && codeUnit <= 0x005a) || + (codeUnit >= 0x0061 && codeUnit <= 0x007a) + ) { + // the character itself + result += string.charAt(index) + continue + } + + // Otherwise, the escaped character. + // https://drafts.csswg.org/cssom/#escape-a-character + result += '\\' + string.charAt(index) + } + return result +} + export async function retryAssertion( fn: () => Promise, { timeout = ASSERTION_TIMEOUT, delay = 5 }: { timeout?: number; delay?: number } = {}, @@ -670,7 +594,6 @@ export async function retryAssertion( try { return await fn() } catch (err) { - Error.captureStackTrace(err, retryAssertion) error = err await new Promise((resolve) => setTimeout(resolve, delay)) } @@ -686,7 +609,7 @@ export async function fetchStyles(base: string, path = '/'): Promise { let index = await fetch(`${base}${path}`) let html = await index.text() - let linkRegex = /]*>([\s\S]*?)<\/style>/gi let stylesheets: string[] = [] @@ -717,155 +640,13 @@ export async function fetchStyles(base: string, path = '/'): Promise { } return stylesheets.reduce((acc, css) => { - if (acc.length > 0) acc += '\n' - acc += css - return acc + return acc + '\n' + css }, '') } -export async function getRandomPort() { - return new Promise((resolve, reject) => { - let server = createServer() - server.unref() - server.on('error', reject) - server.listen(0, '127.0.0.1', () => { - let address = server.address() - server.close(() => { - if (address && typeof address === 'object') { - resolve(address.port) - } else { - reject(new Error('Unable to allocate random port')) - } - }) - }) - }) -} - -async function killProcessTree(child: ChildProcess) { - if (child.exitCode !== null || child.signalCode !== null || child.pid === undefined) { - return - } - - if (IS_WINDOWS) { - await execFileAsync('taskkill', ['/pid', String(child.pid), '/T', '/F'], { - timeout: ASSERTION_TIMEOUT, - windowsHide: true, - }).catch(() => {}) - return - } - - try { - process.kill(-child.pid, 'SIGTERM') - } catch (error: any) { - if (error?.code !== 'ESRCH') { - child.kill() - } - } -} - -function forceKillProcessTree(child: ChildProcess) { - if (child.exitCode !== null || child.signalCode !== null || child.pid === undefined) { - return - } - - if (IS_WINDOWS) { - execFile('taskkill', ['/pid', String(child.pid), '/T', '/F'], { windowsHide: true }, () => {}) - return - } - - try { - process.kill(-child.pid, 'SIGKILL') - } catch (error: any) { - if (error?.code !== 'ESRCH') { - child.kill('SIGKILL') - } - } -} - async function gracefullyRemove(dir: string) { // Skip removing the directory in CI because it can stall on Windows if (!process.env.CI) { - await fs.rm(dir, { recursive: true, force: true }).catch((error) => { - console.log(`Failed to remove ${dir}`, error) - }) - } -} - -const SOURCE_MAP_COMMENT = /^\/\*# sourceMappingURL=data:application\/json;base64,(.*) \*\/$/ - -export interface SourceMap { - at( - line: number, - column: number, - ): { - source: string | null - original: string - generated: string - } -} - -interface SourceMapOptions { - /** - * A raw source map - * - * This may be a string or an object. Strings will be decoded. - */ - map: string | object - - /** - * The content of the generated file the source map is for - */ - content: string - - /** - * The encoding of the source map - * - * Can be used to decode a base64 map (e.g. an inline source map URI) - */ - encoding?: BufferEncoding -} - -function parseSourceMap(opts: string | SourceMapOptions): SourceMap { - if (typeof opts === 'string') { - let lines = opts.trimEnd().split('\n') - let comment = lines.at(-1) ?? '' - let map = String(comment).match(SOURCE_MAP_COMMENT)?.[1] ?? null - if (!map) throw new Error('No source map comment found') - - return parseSourceMap({ - map, - content: lines.slice(0, -1).join('\n'), - encoding: 'base64', - }) - } - - let rawMap: RawSourceMap - let content = opts.content - - if (typeof opts.map === 'object') { - rawMap = opts.map as RawSourceMap - } else { - rawMap = JSON.parse(Buffer.from(opts.map, opts.encoding ?? 'utf-8').toString()) - } - - let map = new SourceMapConsumer(rawMap) - let generatedTable = createLineTable(content) - - return { - at(line: number, column: number) { - let pos = map.originalPositionFor({ line, column }) - let source = pos.source ? map.sourceContentFor(pos.source) : null - let originalTable = createLineTable(source ?? '') - let originalOffset = originalTable.findOffset(pos) - let generatedOffset = generatedTable.findOffset({ line, column }) - - return { - source: pos.source, - original: source - ? source.slice(originalOffset, originalOffset + 10).trim() + '...' - : '(none)', - generated: content.slice(generatedOffset, generatedOffset + 10).trim() + '...', - } - }, + await fs.rm(dir, { recursive: true, force: true }) } } diff --git a/integrations/vite/astro.test.ts b/integrations/vite/astro.test.ts index f828b5071..5b7407e47 100644 --- a/integrations/vite/astro.test.ts +++ b/integrations/vite/astro.test.ts @@ -1,4 +1,4 @@ -import { candidate, css, fetchStyles, html, js, json, retryAssertion, test, ts } from '../utils' +import { candidate, fetchStyles, html, json, retryAssertion, test, ts } from '../utils' test( 'dev mode', @@ -20,8 +20,9 @@ test( // https://astro.build/config export default defineConfig({ - vite: { plugins: [tailwindcss()] }, - build: { inlineStylesheets: 'never' }, + vite: { + plugins: [tailwindcss()], + }, }) `, 'src/pages/index.astro': html` @@ -69,133 +70,3 @@ test( }) }, ) - -test( - 'build mode', - { - fs: { - 'package.json': json` - { - "type": "module", - "dependencies": { - "astro": "^4.15.2", - "react": "^19", - "react-dom": "^19", - "@astrojs/react": "^4", - "@tailwindcss/vite": "workspace:^", - "tailwindcss": "workspace:^" - } - } - `, - 'astro.config.mjs': ts` - import tailwindcss from '@tailwindcss/vite' - import react from '@astrojs/react' - import { defineConfig } from 'astro/config' - - // https://astro.build/config - export default defineConfig({ - vite: { plugins: [tailwindcss()] }, - integrations: [react()], - build: { inlineStylesheets: 'never' }, - }) - `, - // prettier-ignore - 'src/pages/index.astro': html` - --- - import ClientOnly from './client-only'; - --- - -
Hello, world!
- - - - - `, - 'src/pages/client-only.jsx': js` - export default function ClientOnly() { - return
Hello, world!
- } - `, - }, - }, - async ({ fs, exec, expect }) => { - await exec('pnpm astro build') - - let files = await fs.glob('dist/**/*.css') - expect(files).toHaveLength(1) - - await fs.expectFileToContain(files[0][0], [candidate`underline`, candidate`overline`]) - }, -) - -// https://github.com/tailwindlabs/tailwindcss/issues/19677 -test( - 'import aliases should work in - - -

Astro

- - - `, - 'src/styles/global.css': css`@import 'tailwindcss';`, - }, - }, - async ({ fs, exec, expect }) => { - await exec('pnpm astro build') - - let files = await fs.glob('dist/**/*.css') - expect(files).toHaveLength(1) - - await fs.expectFileToContain(files[0][0], [candidate`underline`]) - }, -) diff --git a/integrations/vite/bundled-dev.test.ts b/integrations/vite/bundled-dev.test.ts deleted file mode 100644 index 8ba1b6b73..000000000 --- a/integrations/vite/bundled-dev.test.ts +++ /dev/null @@ -1,193 +0,0 @@ -import path from 'node:path' -import { candidate, css, html, json, retryAssertion, test, ts, txt, yaml } from '../utils' - -// Vite's experimental `bundledDev` mode invokes the `hotUpdate` hook without a -// `server`, which used to crash the plugin on every file edit. -// -// - https://github.com/tailwindlabs/tailwindcss/issues/20378 -// - https://vite.dev/blog/announcing-vite8-1#experimental-bundled-dev-mode -test( - 'dev mode (experimental `bundledDev`)', - { - fs: { - 'package.json': json`{}`, - 'pnpm-workspace.yaml': yaml` - # - packages: - - project-a - `, - 'project-a/package.json': txt` - { - "type": "module", - "dependencies": { - "@tailwindcss/vite": "workspace:^", - "tailwindcss": "workspace:^" - }, - "devDependencies": { - "vite": "^8.1" - } - } - `, - 'project-a/vite.config.ts': ts` - import tailwindcss from '@tailwindcss/vite' - import { defineConfig } from 'vite' - - export default defineConfig({ - experimental: { - bundledDev: true, - }, - plugins: [tailwindcss()], - }) - `, - 'project-a/index.html': html` - - - - -
Hello, world!
- - `, - 'project-a/src/index.css': css` - @reference 'tailwindcss/theme'; - @import 'tailwindcss/utilities'; - @source '../../project-b/src/**/*.html'; - `, - 'project-b/src/index.html': html` -
- `, - }, - }, - async ({ root, spawn, fs, expect }) => { - let process = await spawn('pnpm vite dev', { - cwd: path.join(root, 'project-a'), - env: { - // Some CI machines have an upstream rolldown bug where its file watcher - // never delivers a single event. The debug output is the only way to - // tell that apart from a real regression (see below). - DEBUG: 'vite:full-bundle-mode', - }, - }) - - // Any debug output beyond the "INITIAL:" startup lines proves rolldown's - // watcher delivered at least one file event. - let watcherAlive = false - - // `hotUpdate` errors don't kill the dev server, they are only printed to - // stderr. Track them explicitly so a crash fails the test even if the - // rebuild happens to succeed anyway. - let pluginErrors: string[] = [] - process.onStderr((message) => { - if (message.includes('vite:full-bundle-mode')) { - if (!message.includes('INITIAL:')) watcherAlive = true - } else if (message.includes('@tailwindcss/vite')) { - pluginErrors.push(message) - } - return false - }) - - let url = '' - await process.onStdout((m) => { - let match = /Local:\s*(http.*)\//.exec(m) - if (match) url = match[1] - return Boolean(url) - }) - - // In `bundledDev` mode the stylesheet is not served separately. Instead the - // generated CSS is embedded in the bundled JS and injected at runtime, so - // extract the bundle from the served HTML. While the bundle is being built, - // Vite serves a temporary fallback page instead. - // - // The bundle can be split into multiple chunks (e.g. the HMR client runtime - // and the app itself), and the chunk containing the CSS is not always the - // first one, so fetch every referenced script and stylesheet. - async function fetchBundledStyles(): Promise { - let index = await fetch(`${url}/`) - let html = await index.text() - if (html.includes('__vite_is_fallback_page__')) { - throw new Error('Bundling still in progress') - } - - let sources = [ - ...html.matchAll(/]*\ssrc="([^"]+)"/g), - ...html.matchAll(/]*\srel="stylesheet"[^>]*\shref="([^"]+)"/g), - ].map((match) => match[1]) - if (sources.length === 0) throw new Error(`No scripts or stylesheets found in:\n\n${html}`) - - let contents = await Promise.all( - sources.map(async (src) => { - let response = await fetch(new URL(src, `${url}/`)) - return await response.text() - }), - ) - return contents.join('\n') - } - - await retryAssertion( - async () => { - let styles = await fetchBundledStyles() - expect(styles).toContain(candidate`underline`) - expect(styles).toContain(candidate`flex`) - }, - { timeout: 10_000, delay: 100 }, - ) - - // Edit a module file and a manually `@source`d file. Without a connected - // HMR websocket client (this test only uses HTTP fetches), a file change - // does not trigger an eager rebuild — it only marks the bundle as stale, - // and the next fetch kicks off the rebuild. So poll with fetches without - // touching the files again: rewriting would re-mark the bundle stale right - // before each fetch and the rebuild could never be observed. - await fs.write( - 'project-a/index.html', - html` - - - - -
Hello, world!
- - `, - ) - - await fs.write('project-b/src/index.html', html` -
- `) - - try { - await retryAssertion( - async () => { - let styles = await fetchBundledStyles() - expect(styles).toContain(candidate`underline`) - expect(styles).toContain(candidate`flex`) - expect(styles).toContain(candidate`m-2`) - expect(styles).toContain(candidate`font-bold`) - }, - { timeout: 15_000, delay: 100 }, - ) - } catch (error) { - // If rolldown's watcher delivered any file event, the updates were - // genuinely dropped somewhere along the way — a real failure. - if (watcherAlive) throw error - - // Otherwise the watcher never delivered a single event, so the updates - // can never be observed no matter how long we wait — an upstream - // rolldown bug on some CI machines, not a plugin regression. The crash - // regression this test guards is still covered: `hotUpdate` is driven - // by Vite's own (working) chokidar watcher and asserted via - // `pluginErrors` below. - // - // Skipping is only sound while the server still healthily serves the - // original bundle. If it stopped serving (crashed, or wedged on the - // fallback page), that's real breakage a silent watcher must not mask. - console.log(error) - let styles = await fetchBundledStyles() - expect(styles).toContain(candidate`underline`) - expect(styles).toContain(candidate`flex`) - console.warn( - 'Skipping update assertions: rolldown’s file watcher delivered no events on this machine.', - ) - } - - expect(pluginErrors).toEqual([]) - }, -) diff --git a/integrations/vite/config.test.ts b/integrations/vite/config.test.ts index 0ac68f5e9..3bf560e07 100644 --- a/integrations/vite/config.test.ts +++ b/integrations/vite/config.test.ts @@ -12,7 +12,7 @@ test( "tailwindcss": "workspace:^" }, "devDependencies": { - "vite": "^7" + "vite": "^6" } } `, @@ -76,7 +76,7 @@ test( "tailwindcss": "workspace:^" }, "devDependencies": { - "vite": "^7" + "vite": "^6" } } `, @@ -140,7 +140,7 @@ test( "tailwindcss": "workspace:^" }, "devDependencies": { - "vite": "^7" + "vite": "^6" } } `, @@ -219,7 +219,7 @@ test( "tailwindcss": "workspace:^" }, "devDependencies": { - "vite": "^7" + "vite": "^6" } } `, diff --git a/integrations/vite/css-modules.test.ts b/integrations/vite/css-modules.test.ts index a680ab9b7..668281cb4 100644 --- a/integrations/vite/css-modules.test.ts +++ b/integrations/vite/css-modules.test.ts @@ -14,8 +14,8 @@ describe.each(['postcss', 'lightningcss'])('%s', (transformer) => { "tailwindcss": "workspace:^" }, "devDependencies": { - ${transformer === 'lightningcss' ? `"lightningcss": "^1",` : ''} - "vite": "^7" + ${transformer === 'lightningcss' ? `"lightningcss": "^1.26.0",` : ''} + "vite": "^6" } } `, diff --git a/integrations/vite/html-style-blocks.test.ts b/integrations/vite/html-style-blocks.test.ts deleted file mode 100644 index 22bb91d78..000000000 --- a/integrations/vite/html-style-blocks.test.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { html, json, test, ts } from '../utils' - -test( - 'transforms html style blocks', - { - fs: { - 'package.json': json` - { - "type": "module", - "dependencies": { - "tailwindcss": "workspace:^" - }, - "devDependencies": { - "@tailwindcss/vite": "workspace:^", - "vite": "^7" - } - } - `, - 'vite.config.ts': ts` - import { defineConfig } from 'vite' - import tailwindcss from '@tailwindcss/vite' - - export default defineConfig({ - plugins: [tailwindcss()], - }) - `, - 'index.html': html` - - - -
- - - - `, - }, - }, - async ({ fs, exec, expect }) => { - await exec('pnpm vite build') - - expect(await fs.dumpFiles('dist/*.html')).toMatchInlineSnapshot(` - " - --- dist/index.html --- - - - -
- - - - " - `) - }, -) diff --git a/integrations/vite/ignored-packages.test.ts b/integrations/vite/ignored-packages.test.ts deleted file mode 100644 index 1efa9dc61..000000000 --- a/integrations/vite/ignored-packages.test.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { candidate, css, fetchStyles, html, js, retryAssertion, test, ts, txt } from '../utils' - -const WORKSPACE = { - fs: { - 'package.json': txt` - { - "type": "module", - "dependencies": { - "tailwind-merge": "^2", - "@tailwindcss/vite": "workspace:^", - "tailwindcss": "workspace:^" - }, - "devDependencies": { - "vite": "^7" - } - } - `, - 'vite.config.ts': ts` - import tailwindcss from '@tailwindcss/vite' - import { defineConfig } from 'vite' - - export default defineConfig({ - build: { cssMinify: false }, - plugins: [tailwindcss()], - }) - `, - 'index.html': html` - - - - - `, - 'src/index.js': js` - import { twMerge } from 'tailwind-merge' - - twMerge('underline') - - console.log('underline') - `, - 'src/index.css': css`@import 'tailwindcss/utilities' layer(utilities);`, - }, -} - -test( - 'does not scan tailwind-merge in production builds', - WORKSPACE, - async ({ fs, exec, expect }) => { - await exec('pnpm vite build') - - let files = await fs.glob('dist/**/*.css') - expect(files).toHaveLength(1) - let [, content] = files[0] - - expect(content).toMatchInlineSnapshot(` - "@layer utilities { - .underline { - text-decoration-line: underline; - } - } - " - `) - }, -) - -test('does not scan tailwind-merge in dev builds', WORKSPACE, async ({ spawn, expect }) => { - let process = await spawn('pnpm vite dev') - await process.onStdout((m) => m.includes('ready in')) - - let url = '' - await process.onStdout((m) => { - let match = /Local:\s*(http.*)\//.exec(m) - if (match) url = match[1] - return Boolean(url) - }) - - await retryAssertion(async () => { - let styles = await fetchStyles(url, '/index.html') - - expect(styles).not.toContain(candidate`flex`) - }) -}) diff --git a/integrations/vite/index.test.ts b/integrations/vite/index.test.ts index c346f8e37..eebe11127 100644 --- a/integrations/vite/index.test.ts +++ b/integrations/vite/index.test.ts @@ -7,7 +7,6 @@ import { html, js, json, - jsx, retryAssertion, test, ts, @@ -34,8 +33,8 @@ describe.each(['postcss', 'lightningcss'])('%s', (transformer) => { "tailwindcss": "workspace:^" }, "devDependencies": { - ${transformer === 'lightningcss' ? `"lightningcss": "^1",` : ''} - "vite": "^7" + ${transformer === 'lightningcss' ? `"lightningcss": "^1.26.0",` : ''} + "vite": "^6" } } `, @@ -63,7 +62,7 @@ describe.each(['postcss', 'lightningcss'])('%s', (transformer) => { } `, 'project-a/src/index.css': css` - @reference 'tailwindcss/theme'; + @import 'tailwindcss/theme' theme(reference); @import 'tailwindcss/utilities'; @config '../tailwind.config.js'; @source '../../project-b/src/**/*.html'; @@ -111,8 +110,8 @@ describe.each(['postcss', 'lightningcss'])('%s', (transformer) => { "tailwindcss": "workspace:^" }, "devDependencies": { - ${transformer === 'lightningcss' ? `"lightningcss": "^1",` : ''} - "vite": "^7" + ${transformer === 'lightningcss' ? `"lightningcss": "^1.26.0",` : ''} + "vite": "^6" } } `, @@ -148,17 +147,11 @@ describe.each(['postcss', 'lightningcss'])('%s', (transformer) => { } `, 'project-a/src/index.css': css` - @reference 'tailwindcss/theme'; + @import 'tailwindcss/theme' theme(reference); @import 'tailwindcss/utilities'; - @import './imported.css'; @config '../tailwind.config.js'; @source '../../project-b/src/**/*.html'; `, - 'project-a/src/imported.css': css` - .imported { - color: red; - } - `, 'project-b/src/index.html': html`
`, @@ -181,12 +174,22 @@ describe.each(['postcss', 'lightningcss'])('%s', (transformer) => { return Boolean(url) }) + // Candidates are resolved lazily, so the first visit of index.html + // will only have candidates from this file. await retryAssertion(async () => { let styles = await fetchStyles(url, '/index.html') expect(styles).toContain(candidate`underline`) expect(styles).toContain(candidate`flex`) + expect(styles).not.toContain(candidate`font-bold`) + }) + + // Going to about.html will extend the candidate list to include + // candidates from about.html. + await retryAssertion(async () => { + let styles = await fetchStyles(url, '/about.html') + expect(styles).toContain(candidate`underline`) + expect(styles).toContain(candidate`flex`) expect(styles).toContain(candidate`font-bold`) - expect(styles).toContain(candidate`imported`) }) await retryAssertion(async () => { @@ -207,7 +210,6 @@ describe.each(['postcss', 'lightningcss'])('%s', (transformer) => { expect(styles).toContain(candidate`underline`) expect(styles).toContain(candidate`flex`) expect(styles).toContain(candidate`font-bold`) - expect(styles).toContain(candidate`imported`) expect(styles).toContain(candidate`m-2`) }) @@ -225,7 +227,6 @@ describe.each(['postcss', 'lightningcss'])('%s', (transformer) => { expect(styles).toContain(candidate`underline`) expect(styles).toContain(candidate`flex`) expect(styles).toContain(candidate`font-bold`) - expect(styles).toContain(candidate`imported`) expect(styles).toContain(candidate`m-2`) expect(styles).toContain(candidate`[.changed_&]:content-['project-b/src/index.js']`) }) @@ -247,157 +248,11 @@ describe.each(['postcss', 'lightningcss'])('%s', (transformer) => { let styles = await fetchStyles(url) expect(styles).toContain(candidate`red`) expect(styles).toContain(candidate`flex`) - expect(styles).toContain(candidate`imported`) expect(styles).toContain(candidate`m-2`) expect(styles).toContain(candidate`underline`) expect(styles).toContain(candidate`[.changed_&]:content-['project-b/src/index.js']`) expect(styles).toContain(candidate`font-bold`) }) - - await retryAssertion(async () => { - // Trigger a partial rebuild for the next test - await fs.write( - 'project-a/index.html', - html` - - - - -
Hello, world!
- - `, - ) - let styles = await fetchStyles(url) - expect(styles).toContain(candidate`m-4`) - }) - - await retryAssertion(async () => { - // Changing an `@imported` CSS file after a partial rebuild also triggers the correct update - await fs.write( - 'project-a/src/imported.css', - css` - .imported-updated { - color: red; - } - `, - ) - - let styles = await fetchStyles(url) - expect(styles).toContain(candidate`red`) - expect(styles).toContain(candidate`flex`) - expect(styles).toContain(candidate`m-2`) - expect(styles).toContain(candidate`underline`) - expect(styles).toContain(candidate`[.changed_&]:content-['project-b/src/index.js']`) - expect(styles).toContain(candidate`font-bold`) - expect(styles).toContain(candidate`imported-updated`) - }) - }, - ) - - // https://github.com/tailwindlabs/tailwindcss/issues/20346 - test( - 'dev mode + symlinked `@source` files pick up changes to the real file', - { - fs: { - 'package.json': json`{}`, - 'pnpm-workspace.yaml': yaml` - # - packages: - - project-a - - packages/* - `, - 'project-a/package.json': txt` - { - "type": "module", - "dependencies": { - "@tailwindcss/vite": "workspace:^", - "repro-package": "workspace:*", - "tailwindcss": "workspace:^" - }, - "devDependencies": { - ${transformer === 'lightningcss' ? `"lightningcss": "^1",` : ''} - "vite": "^7" - } - } - `, - 'project-a/vite.config.ts': ts` - import tailwindcss from '@tailwindcss/vite' - import { defineConfig } from 'vite' - - export default defineConfig({ - css: ${transformer === 'postcss' ? '{}' : "{ transformer: 'lightningcss' }"}, - build: { cssMinify: false }, - plugins: [tailwindcss()], - }) - `, - 'project-a/index.html': html` - - - - -
Hello, world!
- - `, - - // The `@source` points through the `node_modules` symlink that pnpm - // creates for the workspace package. Vite's file watcher ignores - // `node_modules` by default, so the symlinked path can not be watched. - // The real file (in `packages/repro-package`) has to be watched - // instead. - 'project-a/src/index.css': css` - @reference 'tailwindcss/theme'; - @import 'tailwindcss/utilities'; - @source '../node_modules/repro-package/source.html'; - `, - 'packages/repro-package/package.json': json` - { - "name": "repro-package", - "private": true, - "version": "1.0.0" - } - `, - 'packages/repro-package/source.html': html` -
- Hello, world! -
- `, - }, - }, - async ({ root, spawn, fs, expect }) => { - let process = await spawn('pnpm vite dev', { - cwd: path.join(root, 'project-a'), - }) - await process.onStdout((m) => m.includes('ready in')) - - let url = '' - await process.onStdout((m) => { - let match = /Local:\s*(http.*)\//.exec(m) - if (match) url = match[1] - return Boolean(url) - }) - - await retryAssertion(async () => { - let styles = await fetchStyles(url, '/index.html') - expect(styles).toContain(candidate`underline`) - expect(styles).toContain(candidate`content-['v1']`) - }) - - await retryAssertion(async () => { - // Changes to the real file (behind the symlink) should be picked up - await fs.write( - 'packages/repro-package/source.html', - html` -
- Hello, world! -
- `, - ) - - let styles = await fetchStyles(url) - expect(styles).toContain(candidate`underline`) - expect(styles).toContain(candidate`content-['v1']`) - expect(styles).toContain(candidate`content-['v2']`) - }) }, ) @@ -419,8 +274,8 @@ describe.each(['postcss', 'lightningcss'])('%s', (transformer) => { "tailwindcss": "workspace:^" }, "devDependencies": { - ${transformer === 'lightningcss' ? `"lightningcss": "^1",` : ''} - "vite": "^7" + ${transformer === 'lightningcss' ? `"lightningcss": "^1.26.0",` : ''} + "vite": "^6" } } `, @@ -447,7 +302,7 @@ describe.each(['postcss', 'lightningcss'])('%s', (transformer) => { } `, 'project-a/src/index.css': css` - @reference 'tailwindcss/theme'; + @import 'tailwindcss/theme' theme(reference); @import 'tailwindcss/utilities'; @import './custom-theme.css'; @config '../tailwind.config.js'; @@ -580,352 +435,6 @@ describe.each(['postcss', 'lightningcss'])('%s', (transformer) => { }, ) - describe.each([['^6'], ['7.0.8'], ['7.1.12'], ['7.3.1'], ['8.0.0']])( - 'Using Vite %s', - (version) => { - test( - 'external source file changes update the CSS', - { - fs: { - 'package.json': json`{}`, - 'pnpm-workspace.yaml': yaml` - # - packages: - - project-a - `, - 'project-a/package.json': json` - { - "type": "module", - "dependencies": { - "@tailwindcss/vite": "workspace:^", - "tailwindcss": "workspace:^" - }, - "devDependencies": { - ${transformer === 'lightningcss' ? `"lightningcss": "^1",` : ''} - "vite": "${version}" - } - } - `, - 'project-a/vite.config.ts': ts` - import fs from 'node:fs' - import path from 'node:path' - import tailwindcss from '@tailwindcss/vite' - import { defineConfig } from 'vite' - - export default defineConfig({ - css: ${transformer === 'postcss' ? '{}' : "{ transformer: 'lightningcss' }"}, - build: { cssMinify: false }, - plugins: [tailwindcss()], - logLevel: 'info', - }) - `, - 'project-a/index.html': html` - - - - - -
- - - - `, - 'project-a/src/main.ts': jsx`import { classes } from './app'`, - 'project-a/src/app.ts': jsx`export let classes = "content-['project-a/src/app.ts']"`, - 'project-a/src/index.css': css` - @import 'tailwindcss'; - @source '../../project-b/**/*.php'; - `, - 'project-b/src/index.php': html` -
- `, - }, - }, - async ({ root, spawn, fs, expect }) => { - let process = await spawn('pnpm vite dev --debug hmr', { - cwd: path.join(root, 'project-a'), - }) - await process.onStdout((m) => m.includes('ready in')) - - let url = '' - await process.onStdout((m) => { - let match = /Local:\s*(http.*)\//.exec(m) - if (match) url = match[1] - return Boolean(url) - }) - - await retryAssertion(async () => { - let styles = await fetchStyles(url, '/index.html') - expect(styles).toContain(candidate`content-['project-b/src/index.php']`) - }) - - // Flush all messages so that we can be sure the next messages are - // from the file changes we're about to make - process.flush() - - // Changing an external .php file hot-updates the generated CSS - { - await fs.write( - 'project-b/src/index.php', - txt`
`, - ) - - // On Vite < 7.1, Vite itself hard-invalidates watched files that - // aren't part of the module graph and reloads the page. - // - // On newer versions nothing reloads the page: the CSS hot-updates - // through the regular pipeline because the changed file is a - // watch dependency of the CSS root. - // - // Reloading the page for external template changes is the - // responsibility of the backend integration (e.g. `laravel-vite-plugin`'s `refresh` option, or `vite-plugin-full-reload`). - // - // https://github.com/tailwindlabs/tailwindcss/issues/20411 - if (version === '^6' || version === '7.0.8') { - await process.onStdout((m) => m.includes('page reload') && m.includes('index.php')) - } else { - await process.onStdout((m) => m.includes('hmr update') && m.includes('index.css')) - } - - // Ensure the styles were regenerated with the new content - let styles = await fetchStyles(url, '/index.html') - expect(styles).toContain(candidate`content-['updated:project-b/src/index.php']`) - } - }, - ) - }, - ) - - // https://github.com/tailwindlabs/tailwindcss/issues/20320 - // https://github.com/tailwindlabs/tailwindcss/issues/19903 - test( - 'editing scanned files that Vite can process as modules does not trigger a full reload', - { - fs: { - 'package.json': json`{}`, - 'pnpm-workspace.yaml': yaml` - # - packages: - - project-a - `, - 'project-a/package.json': json` - { - "type": "module", - "dependencies": { - "@tailwindcss/vite": "workspace:^", - "tailwindcss": "workspace:^" - }, - "devDependencies": { - ${transformer === 'lightningcss' ? `"lightningcss": "^1",` : ''} - "vite": "^8" - } - } - `, - 'project-a/vite.config.ts': ts` - import fs from 'node:fs' - import path from 'node:path' - import tailwindcss from '@tailwindcss/vite' - import { defineConfig } from 'vite' - - export default defineConfig({ - css: ${transformer === 'postcss' ? '{}' : "{ transformer: 'lightningcss' }"}, - build: { cssMinify: false }, - plugins: [ - tailwindcss(), - { - // A plugin that processes a custom file type into a JS - // module, similar to e.g. \`.vue\` or \`.svelte\` files - name: 'custom-file-type', - transform(code, id) { - if (id.endsWith('.custom')) { - return { code: 'export default ' + JSON.stringify(code), map: null } - } - }, - }, - { - // Log all HMR payloads to a file so the test can assert on - // them - name: 'hmr-wiretap', - configureServer(server) { - let logFile = path.resolve('hmr.log') - fs.writeFileSync(logFile, '') - for (let environment of Object.values(server.environments)) { - let send = environment.hot.send.bind(environment.hot) - environment.hot.send = (payload) => { - fs.appendFileSync(logFile, JSON.stringify(payload) + '\\n') - return send(payload) - } - } - }, - }, - ], - }) - `, - 'project-a/index.html': html` - - - - - -
- - - - `, - 'project-a/src/main.ts': ts` - import compA from './comp-a.custom' - import snippet from './snippet.php?raw' - console.log(compA, snippet) - `, - 'project-a/src/snippet.php': html` -
- `, - 'project-a/src/comp-a.custom': html` -
- `, - 'project-a/src/comp-b.custom': html` -
- `, - 'project-a/src/lazy.tsx': jsx` - export default function Lazy() { - return
- } - `, - 'project-a/src/unimported.css': css` - .unimported { - color: red; - } - `, - 'project-a/src/index.css': css` - @import 'tailwindcss'; - @source '../../project-b/**/*.php'; - `, - 'project-b/src/index.php': html` -
- `, - }, - }, - async ({ root, spawn, fs, expect }) => { - let process = await spawn('pnpm vite dev', { - cwd: path.join(root, 'project-a'), - }) - await process.onStdout((m) => m.includes('ready in')) - - let url = '' - await process.onStdout((m) => { - let match = /Local:\s*(http.*)\//.exec(m) - if (match) url = match[1] - return Boolean(url) - }) - - await retryAssertion(async () => { - let styles = await fetchStyles(url, '/index.html') - expect(styles).toContain(candidate`content-['src/lazy.tsx']`) - expect(styles).toContain(candidate`content-['src/comp-b.custom']`) - expect(styles).toContain(candidate`content-['project-b/src/index.php']`) - }) - - // Load `main.ts`, `comp-a.custom`, and `snippet.php?raw` as real - // modules, like a browser visiting the page would - await fetch(`${url}/src/main.ts`) - await fetch(`${url}/src/comp-a.custom?import`) - await fetch(`${url}/src/snippet.php?raw`) - - // Changing a scanned `.tsx` file that is not part of the module graph - // (e.g. a lazily-loaded route that hasn't been visited yet) should not - // trigger a full reload, but new classes should still apply - // - // https://github.com/tailwindlabs/tailwindcss/issues/20320 - { - await fs.write( - 'project-a/src/lazy.tsx', - jsx` - export default function Lazy() { - return
- } - `, - ) - - await retryAssertion(async () => { - let styles = await fetchStyles(url, '/index.html') - expect(styles).toContain(candidate`content-['updated:src/lazy.tsx']`) - }) - } - - // The same holds for a custom file type as long as some file of the - // same type was processed as a module before - { - await fs.write( - 'project-a/src/comp-b.custom', - html`
`, - ) - - await retryAssertion(async () => { - let styles = await fetchStyles(url, '/index.html') - expect(styles).toContain(candidate`content-['updated:src/comp-b.custom']`) - }) - } - - // Changing a scanned stylesheet that is not part of the module graph - // (e.g. a component stylesheet that a framework plugin compiles into - // the component) should not trigger a full reload either - // - // https://github.com/tailwindlabs/tailwindcss/issues/19903 - { - let updates = (await fs.read('project-a/hmr.log')).split('"type":"update"').length - - await fs.write( - 'project-a/src/unimported.css', - css` - .unimported { - color: blue; - } - `, - ) - - // Wait until the change was handled and an update was pushed - await retryAssertion(async () => { - let log = await fs.read('project-a/hmr.log') - expect(log.split('"type":"update"').length).toBeGreaterThan(updates) - }) - } - - // Changing an external file (e.g. a PHP template) hot-updates the - // generated CSS but does not trigger a full reload either. Reloading the - // page for external template changes is the responsibility of the backend - // integration (e.g. `laravel-vite-plugin`'s `refresh` option, or - // `vite-plugin-full-reload`). - // - // https://github.com/tailwindlabs/tailwindcss/issues/20411 - { - let updates = (await fs.read('project-a/hmr.log')).split('"type":"update"').length - - await fs.write( - 'project-b/src/index.php', - html`
`, - ) - - await retryAssertion(async () => { - let log = await fs.read('project-a/hmr.log') - expect(log.split('"type":"update"').length).toBeGreaterThan(updates) - }) - - let styles = await fetchStyles(url, '/index.html') - expect(styles).toContain(candidate`content-['updated:project-b/src/index.php']`) - } - }, - ) - test( `source(none) disables looking at the module graph`, { @@ -944,8 +453,8 @@ describe.each(['postcss', 'lightningcss'])('%s', (transformer) => { "tailwindcss": "workspace:^" }, "devDependencies": { - ${transformer === 'lightningcss' ? `"lightningcss": "^1",` : ''} - "vite": "^7" + ${transformer === 'lightningcss' ? `"lightningcss": "^1.26.0",` : ''} + "vite": "^6" } } `, @@ -1030,8 +539,8 @@ describe.each(['postcss', 'lightningcss'])('%s', (transformer) => { "tailwindcss": "workspace:^" }, "devDependencies": { - ${transformer === 'lightningcss' ? `"lightningcss": "^1",` : ''} - "vite": "^7" + ${transformer === 'lightningcss' ? `"lightningcss": "^1.26.0",` : ''} + "vite": "^6" } } `, @@ -1132,8 +641,8 @@ describe.each(['postcss', 'lightningcss'])('%s', (transformer) => { "tailwindcss": "workspace:^" }, "devDependencies": { - ${transformer === 'lightningcss' ? `"lightningcss": "^1",` : ''} - "vite": "^7" + ${transformer === 'lightningcss' ? `"lightningcss": "^1.26.0",` : ''} + "vite": "^6" } } `, @@ -1178,96 +687,16 @@ describe.each(['postcss', 'lightningcss'])('%s', (transformer) => { async ({ root, fs, exec, expect }) => { await expect(() => exec('pnpm vite build', { cwd: path.join(root, 'project-a') }, { ignoreStdErr: true }), - ).rejects.toThrow('The `source(../i-do-not-exist)` does not exist') + ).rejects.toThrowError('The `source(../i-do-not-exist)` does not exist') let files = await fs.glob('project-a/dist/**/*.css') expect(files).toHaveLength(0) }, ) - - test( - 'source(…) and `@source` are relative to the file they are in', - { - fs: { - 'package.json': json` - { - "type": "module", - "dependencies": { - "@tailwindcss/vite": "workspace:^", - "tailwindcss": "workspace:^" - }, - "devDependencies": { - ${transformer === 'lightningcss' ? `"lightningcss": "^1",` : ''} - "vite": "^7" - } - } - `, - 'vite.config.ts': ts` - import tailwindcss from '@tailwindcss/vite' - import { defineConfig } from 'vite' - - export default defineConfig({ - css: ${transformer === 'postcss' ? '{}' : "{ transformer: 'lightningcss' }"}, - build: { cssMinify: false }, - plugins: [tailwindcss()], - }) - `, - 'index.html': html` - - - - - `, - 'index.css': css` @import './project-a/src/index.css'; `, - - 'project-a/src/index.css': css` - /* Run auto-content detection in ../../project-b */ - @import 'tailwindcss/utilities' source('../../project-b'); - - /* Explicitly using node_modules in the @source allows git ignored folders */ - @source '../../project-c'; - `, - - // Project A is the current folder, but we explicitly configured - // `source(project-b)`, therefore project-a should not be included in - // the output. - 'project-a/src/index.html': html` -
- `, - - // Project B is the configured `source(…)`, therefore auto source - // detection should include known extensions and folders in the output. - 'project-b/src/index.html': html` -
- `, - - // Project C should apply auto source detection, therefore known - // extensions and folders should be included in the output. - 'project-c/src/index.html': html` -
- `, - }, - }, - async ({ fs, exec, spawn, root, expect }) => { - await exec('pnpm vite build', { cwd: root }) - - let content = await fs.dumpFiles('./dist/assets/*.css') - - expect(content).not.toContain(candidate`content-['project-a/src/index.html']`) - expect(content).toContain(candidate`content-['project-b/src/index.html']`) - expect(content).toContain(candidate`content-['project-c/src/index.html']`) - }, - ) }) test( - `demote Tailwind roots to regular CSS files and back to Tailwind roots`, + `demote Tailwind roots to regular CSS files and back to Tailwind roots while restoring all candidates`, { fs: { 'package.json': json` @@ -1278,7 +707,7 @@ test( "tailwindcss": "workspace:^" }, "devDependencies": { - "vite": "^7" + "vite": "^6" } } `, @@ -1321,9 +750,19 @@ test( return Boolean(url) }) + // Candidates are resolved lazily, so the first visit of index.html + // will only have candidates from this file. await retryAssertion(async () => { let styles = await fetchStyles(url, '/index.html') expect(styles).toContain(candidate`underline`) + expect(styles).not.toContain(candidate`font-bold`) + }) + + // Going to about.html will extend the candidate list to include + // candidates from about.html. + await retryAssertion(async () => { + let styles = await fetchStyles(url, '/about.html') + expect(styles).toContain(candidate`underline`) expect(styles).toContain(candidate`font-bold`) }) @@ -1350,7 +789,7 @@ test( "tailwindcss": "workspace:^" }, "devDependencies": { - "vite": "^7" + "vite": "^6" } } `, @@ -1402,325 +841,6 @@ test( }, ) -test( - `does not interfere with ?commonjs-proxy modules`, - { - fs: { - 'package.json': json` - { - "type": "module", - "dependencies": { - "@tailwindcss/vite": "workspace:^", - "tailwindcss": "workspace:^", - "plotly.js": "^3", - "vite": "^7" - } - } - `, - 'vite.config.ts': ts` - import tailwindcss from '@tailwindcss/vite' - import { defineConfig } from 'vite' - - export default defineConfig({ - build: { cssMinify: false }, - plugins: [tailwindcss()], - }) - `, - 'index.html': html` - - - - `, - 'src/index.js': js`import Plotly from 'plotly.js/lib/core'`, - - // `plotly.js` pulls in `es5-ext`, which has a build script. As of pnpm - // v10, build scripts only run when explicitly allowed. - 'pnpm-workspace.yaml': yaml` - # - allowBuilds: - es5-ext: true - `, - }, - }, - async ({ exec, expect, fs }) => { - await exec('pnpm vite build') - - let files = await fs.glob('dist/**/*.css') - expect(files).toHaveLength(1) - let [filename] = files[0] - - await fs.expectFileToContain(filename, [candidate`maplibregl-map`]) - }, -) - function firstLine(str: string) { return str.split('\n')[0] } - -test( - 'optimize option: disabled', - { - fs: { - 'package.json': json` - { - "type": "module", - "dependencies": { - "@tailwindcss/vite": "workspace:^", - "tailwindcss": "workspace:^" - }, - "devDependencies": { - "vite": "^7" - } - } - `, - 'vite.config.ts': ts` - import tailwindcss from '@tailwindcss/vite' - import { defineConfig } from 'vite' - - export default defineConfig({ - build: { cssMinify: false }, - plugins: [tailwindcss({ optimize: false })], - }) - `, - 'index.html': html` - - - - -
Hello, world!
- - `, - 'src/index.css': css` - @reference 'tailwindcss/theme'; - @import 'tailwindcss/utilities'; - `, - }, - }, - async ({ exec, expect, fs }) => { - await exec('pnpm vite build') - - // Should not be minified when optimize is disabled - expect((await fs.dumpFiles('dist/**/*.css')).replace(/-([-_a-zA-Z0-9]*?)\.css/g, '-.css')) - .toMatchInlineSnapshot(` - " - --- dist/assets/index-.css --- - .focus\\:text-\\[black\\]:focus { - color: black; - } - " - `) - }, -) - -test( - 'optimize option: enabled with minify disabled', - { - fs: { - 'package.json': json` - { - "type": "module", - "dependencies": { - "@tailwindcss/vite": "workspace:^", - "tailwindcss": "workspace:^" - }, - "devDependencies": { - "vite": "^7" - } - } - `, - 'vite.config.ts': ts` - import tailwindcss from '@tailwindcss/vite' - import { defineConfig } from 'vite' - - export default defineConfig({ - build: { cssMinify: false }, - plugins: [tailwindcss({ optimize: { minify: false } })], - }) - `, - 'index.html': html` - - - - -
Hello, world!
- - `, - 'src/index.css': css` - @reference 'tailwindcss/theme'; - @import 'tailwindcss/utilities'; - `, - }, - }, - async ({ exec, expect, fs }) => { - await exec('pnpm vite build') - - expect((await fs.dumpFiles('dist/**/*.css')).replace(/-([-_a-zA-Z0-9]*?)\.css/g, '-.css')) - .toMatchInlineSnapshot(` - " - --- dist/assets/index-.css --- - @media (hover: hover) { - .hover\\:text-\\[black\\]:hover { - color: #000; - } - } - " - `) - }, -) - -test( - `the plugin works when using the environment API`, - { - fs: { - 'package.json': txt` - { - "type": "module", - "dependencies": { - "@tailwindcss/vite": "workspace:^", - "tailwindcss": "workspace:^" - }, - "devDependencies": { - "vite": "^7" - } - } - `, - 'vite.config.ts': ts` - import tailwindcss from '@tailwindcss/vite' - import { defineConfig } from 'vite' - - export default defineConfig({ - plugins: [tailwindcss()], - builder: {}, - environments: { - server: { - build: { - cssMinify: false, - emitAssets: true, - rollupOptions: { input: './src/server.ts' }, - }, - }, - }, - }) - `, - // Has to exist or the build fails - 'index.html': html` -
- `, - 'src/server.ts': js` - // Import the stylesheet in the server build - import a from './index.css?url' - console.log(a) - `, - 'src/index.css': css` - @reference 'tailwindcss/theme'; - @import 'tailwindcss/utilities'; - `, - }, - }, - async ({ root, fs, exec, expect }) => { - await exec('pnpm vite build', { cwd: root }) - - let files = await fs.glob('dist/**/*.css') - expect(files).toHaveLength(1) - let [filename] = files[0] - - await fs.expectFileToContain(filename, [candidate`content-['index.html']`]) - }, -) - -// https://github.com/tailwindlabs/tailwindcss/issues/17532 -test( - 'deleting a file should not crash Vite', - { - fs: { - 'package.json': json` - { - "type": "module", - "dependencies": { - "@tailwindcss/vite": "workspace:^", - "tailwindcss": "workspace:^" - }, - "devDependencies": { - "vite": "6.2.5" - } - } - `, - 'vite.config.ts': ts` - import tailwindcss from '@tailwindcss/vite' - import { defineConfig } from 'vite' - - export default defineConfig({ - plugins: [tailwindcss()], - }) - `, - 'index.html': html` - -
- - - `, - 'src/index.css': css`@import 'tailwindcss';`, - 'src/main.js': js` - import iconUrl from './assets/icon.svg?url' - import './index.css' - - document.querySelector('#app').innerHTML = iconUrl - `, - 'src/assets/icon.svg': html` - - - - `, - }, - }, - async ({ fs, spawn, expect }) => { - let process = await spawn('pnpm vite dev') - await process.onStdout((m) => m.includes('ready in')) - - let url = '' - await process.onStdout((m) => { - let match = /Local:\s*(http.*)\//.exec(m) - if (match) url = match[1] - return Boolean(url) - }) - - await retryAssertion(async () => { - let [main, css] = await Promise.all([ - fetch(`${url}/src/main.js`).then((r) => r.text()), - fetch(`${url}/src/index.css`).then((r) => r.text()), - ]) - - expect(main).toContain('/src/assets/icon.svg?import&url') - expect(main).toContain('/src/index.css') - expect(css).toContain('.fill-red-500') - }) - - process.flush() - - let unexpectedError = process.onStderr((m) => { - return /error|crash|panic/i.test(m) - }) - - await fs.write( - 'src/main.js', - js` - import './index.css' - document.querySelector('#app').innerHTML = 'Hello World' - `, - ) - - await fs.delete('src/assets/icon.svg') - - let result = await Promise.race([ - unexpectedError.then(() => 'stderr'), - new Promise((resolve) => setTimeout(() => resolve('timeout'), 500)), - ]) - - expect(result).toBe('timeout') - - await retryAssertion(async () => { - let response = await fetch(`${url}/src/index.css?t=${Date.now()}`) - expect(response.status).toBe(200) - }) - }, -) diff --git a/integrations/vite/multi-root.test.ts b/integrations/vite/multi-root.test.ts index 4020aff0f..39da43690 100644 --- a/integrations/vite/multi-root.test.ts +++ b/integrations/vite/multi-root.test.ts @@ -12,7 +12,7 @@ test( "tailwindcss": "workspace:^" }, "devDependencies": { - "vite": "^7" + "vite": "^6" } } `, @@ -43,12 +43,12 @@ test( `, 'src/shared.css': css` - @reference 'tailwindcss/theme'; + @import 'tailwindcss/theme' theme(reference); @import 'tailwindcss/utilities'; `, 'src/root1.css': css` @import './shared.css'; - @custom-variant one (&:is([data-root='1'])); + @variant one (&:is([data-root='1'])); `, 'root2.html': html` @@ -60,7 +60,7 @@ test( `, 'src/root2.css': css` @import './shared.css'; - @custom-variant two (&:is([data-root='2'])); + @variant two (&:is([data-root='2'])); `, }, }, @@ -96,7 +96,7 @@ test( "tailwindcss": "workspace:^" }, "devDependencies": { - "vite": "^7" + "vite": "^6" } } `, @@ -119,12 +119,12 @@ test( `, 'src/shared.css': css` - @reference 'tailwindcss/theme'; + @import 'tailwindcss/theme' theme(reference); @import 'tailwindcss/utilities'; `, 'src/root1.css': css` @import './shared.css'; - @custom-variant one (&:is([data-root='1'])); + @variant one (&:is([data-root='1'])); `, 'root2.html': html` @@ -136,7 +136,7 @@ test( `, 'src/root2.css': css` @import './shared.css'; - @custom-variant two (&:is([data-root='2'])); + @variant two (&:is([data-root='2'])); `, }, }, diff --git a/integrations/vite/nuxt.test.ts b/integrations/vite/nuxt.test.ts index 20f367020..1b834525c 100644 --- a/integrations/vite/nuxt.test.ts +++ b/integrations/vite/nuxt.test.ts @@ -1,15 +1,4 @@ -import { - candidate, - css, - fetchStyles, - getRandomPort, - html, - json, - retryAssertion, - test, - ts, - yaml, -} from '../utils' +import { candidate, css, fetchStyles, html, json, retryAssertion, test, ts } from '../utils' const SETUP = { fs: { @@ -18,18 +7,12 @@ const SETUP = { "type": "module", "dependencies": { "@tailwindcss/vite": "workspace:^", - "nuxt": "3.16.0", - "nitropack": "2.11.0", + "nuxt": "^3.13.1", "tailwindcss": "workspace:^", "vue": "latest" } } `, - 'pnpm-workspace.yaml': yaml` - # - overrides: - nuxi: 3.28.0 - `, 'nuxt.config.ts': ts` import tailwindcss from '@tailwindcss/vite' @@ -93,10 +76,7 @@ test('dev mode', SETUP, async ({ fs, spawn, expect }) => { test('build', SETUP, async ({ spawn, exec, expect }) => { await exec('pnpm nuxt build') - // The Nuxt preview server does not automatically assign a free port if 3000 - // is taken, so we use a random port instead. - let port = await getRandomPort() - let process = await spawn(`pnpm nuxt preview --port ${port}`, { + let process = await spawn('pnpm nuxt preview', { env: { TEST: 'false', NODE_ENV: 'development', diff --git a/integrations/vite/other-transforms.test.ts b/integrations/vite/other-transforms.test.ts index d56396065..6aef096a7 100644 --- a/integrations/vite/other-transforms.test.ts +++ b/integrations/vite/other-transforms.test.ts @@ -13,8 +13,8 @@ function createSetup(transformer: 'postcss' | 'lightningcss') { "tailwindcss": "workspace:^" }, "devDependencies": { - ${transformer === 'lightningcss' ? `"lightningcss": "^1",` : ''} - "vite": "^7" + ${transformer === 'lightningcss' ? `"lightningcss": "^1.26.0",` : ''} + "vite": "^6" } } `, @@ -47,7 +47,7 @@ function createSetup(transformer: 'postcss' | 'lightningcss') { `, 'src/index.css': css` - @reference 'tailwindcss/theme'; + @import 'tailwindcss/theme' theme(reference); @import 'tailwindcss/utilities'; .foo { @@ -111,7 +111,7 @@ describe.each(['postcss', 'lightningcss'] as const)('%s', (transformer) => { await fs.write( 'src/index.css', css` - @reference 'tailwindcss/theme'; + @import 'tailwindcss/theme' theme(reference); @import 'tailwindcss/utilities'; .foo { @@ -155,7 +155,7 @@ describe.each(['postcss', 'lightningcss'] as const)('%s', (transformer) => { await fs.write( 'src/index.css', css` - @reference 'tailwindcss/theme'; + @import 'tailwindcss/theme' theme(reference); @import 'tailwindcss/utilities'; .foo { diff --git a/integrations/vite/preact.test.ts b/integrations/vite/preact.test.ts deleted file mode 100644 index 8e4deec2b..000000000 --- a/integrations/vite/preact.test.ts +++ /dev/null @@ -1,165 +0,0 @@ -import { candidate, css, fetchStyles, html, json, retryAssertion, test, ts, txt } from '../utils' - -test( - 'dev mode', - { - fs: { - 'package.json': json` - { - "type": "module", - "dependencies": { - "preact": "^10" - }, - "devDependencies": { - "@preact/preset-vite": "^2", - "@tailwindcss/vite": "workspace:^", - "tailwindcss": "workspace:^", - "vite": "^8" - } - } - `, - 'vite.config.ts': ts` - import fs from 'node:fs' - import path from 'node:path' - import preact from '@preact/preset-vite' - import tailwindcss from '@tailwindcss/vite' - import { defineConfig } from 'vite' - - export default defineConfig({ - plugins: [ - tailwindcss(), - preact(), - { - // Log all HMR payloads to a file so the test can assert on them - name: 'hmr-wiretap', - configureServer(server) { - let logFile = path.resolve('hmr.log') - fs.writeFileSync(logFile, '') - for (let environment of Object.values(server.environments)) { - let send = environment.hot.send.bind(environment.hot) - environment.hot.send = (payload) => { - fs.appendFileSync(logFile, JSON.stringify(payload) + '\\n') - return send(payload) - } - } - }, - }, - ], - }) - `, - 'index.html': html` - - - - - -
- - - - `, - 'src/main.tsx': ts` - import { render } from 'preact' - import { App } from './app' - - render(, document.getElementById('app')!) - `, - 'src/app.tsx': ts` - import { useState } from 'preact/hooks' - - export function App() { - const [count, setCount] = useState(0) - return ( - - ) - } - `, - 'src/index.css': css`@import 'tailwindcss';`, - }, - }, - async ({ fs, spawn, expect }) => { - let process = await spawn('pnpm vite dev') - await process.onStdout((m) => m.includes('ready in')) - - let url = '' - await process.onStdout((m) => { - let match = /Local:\s*(http.*)\//.exec(m) - if (match) url = match[1] - return Boolean(url) - }) - - await retryAssertion(async () => { - let styles = await fetchStyles(url) - expect(styles).toContain(candidate`underline`) - }) - - // Load the component modules, like a browser visiting the page would - await fetch(`${url}/src/main.tsx`) - await fetch(`${url}/src/app.tsx`) - - // Editing a component keeps HMR intact: new classes are delivered through - // a regular update, not a full page reload (which would lose all state) - { - await fs.write( - 'src/app.tsx', - ts` - import { useState } from 'preact/hooks' - - export function App() { - const [count, setCount] = useState(0) - return ( - - ) - } - `, - ) - - await retryAssertion(async () => { - let styles = await fetchStyles(url) - expect(styles).toContain(candidate`underline`) - expect(styles).toContain(candidate`flex`) - }) - expect(await fs.read('hmr.log')).toContain('"type":"update"') - expect(await fs.read('hmr.log')).not.toContain('full-reload') - } - - // Changing a scanned file that is not part of the module graph (e.g. - // `package.json`, which package managers and other tooling write to while - // the dev server is running) should not trigger a full reload either — - // that would destroy client state. New candidates should still be picked - // up because the file is a watch dependency of the CSS root, so the CSS - // hot-updates through Vite's regular pipeline. - // - // https://github.com/tailwindlabs/tailwindcss/issues/20411 - { - await fs.write( - 'package.json', - txt` - { - "type": "module", - "description": "content-['package.json']", - "dependencies": { - "preact": "^10" - }, - "devDependencies": { - "@preact/preset-vite": "^2", - "@tailwindcss/vite": "workspace:^", - "tailwindcss": "workspace:^", - "vite": "^8" - } - } - `, - ) - - await retryAssertion(async () => { - let styles = await fetchStyles(url) - expect(styles).toContain(candidate`content-['package.json']`) - }) - expect(await fs.read('hmr.log')).not.toContain('full-reload') - } - }, -) diff --git a/integrations/vite/qwik.test.ts b/integrations/vite/qwik.test.ts deleted file mode 100644 index 42db6563a..000000000 --- a/integrations/vite/qwik.test.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { candidate, css, fetchStyles, json, retryAssertion, test, ts } from '../utils' - -test( - 'dev mode', - { - fs: { - 'package.json': json` - { - "type": "module", - "dependencies": { - "@builder.io/qwik": "^1", - "@builder.io/qwik-city": "^1", - "vite": "^5", - "@tailwindcss/vite": "workspace:^", - "tailwindcss": "workspace:^" - } - } - `, - 'vite.config.ts': ts` - import { defineConfig } from 'vite' - import { qwikVite } from '@builder.io/qwik/optimizer' - import { qwikCity } from '@builder.io/qwik-city/vite' - import tailwindcss from '@tailwindcss/vite' - - export default defineConfig(() => { - return { - plugins: [tailwindcss(), qwikCity(), qwikVite()], - } - }) - `, - 'src/root.tsx': ts` - import { component$ } from '@builder.io/qwik' - import { QwikCityProvider, RouterOutlet } from '@builder.io/qwik-city' - - import './global.css' - - export default component$(() => { - return ( - - - - - - - ) - }) - `, - 'src/global.css': css`@import 'tailwindcss/utilities.css';`, - 'src/entry.ssr.tsx': ts` - import { renderToStream, type RenderToStreamOptions } from '@builder.io/qwik/server' - import Root from './root' - - export default function (opts: RenderToStreamOptions) { - return renderToStream(, opts) - } - `, - 'src/routes/index.tsx': ts` - import { component$ } from '@builder.io/qwik' - - export default component$(() => { - return

Hello World!

- }) - `, - }, - }, - async ({ fs, spawn, expect }) => { - let process = await spawn('pnpm vite --mode ssr') - await process.onStdout((m) => m.includes('ready in')) - - let url = '' - await process.onStdout((m) => { - console.log(m) - let match = /Local:\s*(http.*)\//.exec(m) - if (match) url = match[1] - return Boolean(url) - }) - - await retryAssertion(async () => { - let css = await fetchStyles(url) - expect(css).toContain(candidate`underline`) - }) - - await retryAssertion(async () => { - await fs.write( - 'src/routes/index.tsx', - ts` - import { component$ } from '@builder.io/qwik' - - export default component$(() => { - return

Hello World!

- }) - `, - ) - - let css = await fetchStyles(url) - expect(css).toContain(candidate`underline`) - expect(css).toContain(candidate`flex`) - }) - }, -) diff --git a/integrations/vite/react-router.test.ts b/integrations/vite/react-router.test.ts deleted file mode 100644 index 98b0c928d..000000000 --- a/integrations/vite/react-router.test.ts +++ /dev/null @@ -1,266 +0,0 @@ -import { candidate, css, fetchStyles, json, retryAssertion, test, ts, txt } from '../utils' - -const WORKSPACE = { - 'package.json': json` - { - "type": "module", - "dependencies": { - "@react-router/dev": "^7", - "@react-router/node": "^7", - "@react-router/serve": "^7", - "@tailwindcss/vite": "workspace:^", - "@types/node": "^20", - "@types/react-dom": "^19", - "@types/react": "^19", - "isbot": "^5", - "react-dom": "^19", - "react-router": "^7", - "react": "^19", - "tailwindcss": "workspace:^", - "vite": "^5" - } - } - `, - 'react-router.config.ts': ts` - import type { Config } from '@react-router/dev/config' - export default { ssr: true } satisfies Config - `, - 'vite.config.ts': ts` - import { defineConfig } from 'vite' - import { reactRouter } from '@react-router/dev/vite' - import tailwindcss from '@tailwindcss/vite' - - export default defineConfig({ - plugins: [tailwindcss(), reactRouter()], - }) - `, - 'app/routes/home.tsx': ts` - export default function Home() { - return

Welcome to React Router

- } - `, - 'app/app.css': css`@import 'tailwindcss';`, - 'app/routes.ts': ts` - import { type RouteConfig, index } from '@react-router/dev/routes' - export default [index('routes/home.tsx')] satisfies RouteConfig - `, - 'app/root.tsx': ts` - import { Links, Meta, Outlet, Scripts, ScrollRestoration } from 'react-router' - import './app.css' - export function Layout({ children }: { children: React.ReactNode }) { - return ( - - - - - - - - - {children} - - - - - ) - } - - export default function App() { - return - } - `, -} - -test('dev mode', { fs: WORKSPACE }, async ({ fs, spawn, expect }) => { - let process = await spawn('pnpm react-router dev') - - let url = '' - await process.onStdout((m) => { - let match = /Local:\s*(http.*)\//.exec(m) - if (match) url = match[1] - return Boolean(url) - }) - - await retryAssertion(async () => { - let css = await fetchStyles(url) - expect(css).toContain(candidate`font-bold`) - }) - - await retryAssertion(async () => { - await fs.write( - 'app/routes/home.tsx', - ts` - export default function Home() { - return

Welcome to React Router

- } - `, - ) - - let css = await fetchStyles(url) - expect(css).toContain(candidate`underline`) - expect(css).toContain(candidate`font-bold`) - }) -}) - -test( - // cf. https://github.com/remix-run/react-router/blob/00cb4d7b310663b2e84152700c05d3b503005e83/integration/vite-hmr-hdr-test.ts#L311-L318 - 'dev mode, editing a server-only loader dependency triggers HDR instead of a full reload', - { - fs: { - ...WORKSPACE, - 'package.json': json` - { - "type": "module", - "dependencies": { - "@react-router/dev": "^7", - "@react-router/node": "^7", - "@react-router/serve": "^7", - "@tailwindcss/vite": "workspace:^", - "@types/node": "^20", - "@types/react-dom": "^19", - "@types/react": "^19", - "isbot": "^5", - "react-dom": "^19", - "react-router": "^7", - "react": "^19", - "tailwindcss": "workspace:^", - "vite": "^7" - } - } - `, - 'app/routes/home.tsx': ts` - import type { Route } from './+types/home' - import { direct } from '../direct-hdr-dep' - - export async function loader() { - return { message: direct } - } - - export default function Home({ loaderData }: Route.ComponentProps) { - return ( -
-

{loaderData.message}

- -
- ) - } - `, - 'app/direct-hdr-dep.ts': ts` export const direct = 'HDR: 0' `, - }, - }, - async ({ fs, spawn, expect }) => { - let process = await spawn('pnpm react-router dev') - - let url = '' - await process.onStdout((m) => { - let match = /Local:\s*(http.*)\//.exec(m) - if (match) url = match[1] - return Boolean(url) - }) - - // check initial state - await retryAssertion(async () => { - let html = await (await fetch(url)).text() - expect(html).toContain('HDR: 0') - - let css = await fetchStyles(url) - expect(css).toContain(candidate`font-bold`) - }) - - // Flush stdout so we only see messages triggered by the edit below. - process.flush() - - // Edit the server-only module. The client environment watches this file - // but it only exists in the server module graph. Without the fix, the - // Tailwind CSS plugin would trigger a full page reload on the client - // instead of letting react-router handle HDR. - await fs.write('app/direct-hdr-dep.ts', ts` export const direct = 'HDR: 1' `) - - // check update - await retryAssertion(async () => { - let html = await (await fetch(url)).text() - expect(html).toContain('HDR: 1') - - let css = await fetchStyles(url) - expect(css).toContain(candidate`font-bold`) - }) - - // Assert the client receives an HMR update (not a full page reload). - await process.onStdout((m) => m.includes('(client) hmr update')) - }, -) - -test('build mode', { fs: WORKSPACE }, async ({ spawn, exec, expect }) => { - await exec('pnpm react-router build') - let process = await spawn('pnpm react-router-serve ./build/server/index.js') - - let url = '' - await process.onStdout((m) => { - let match = /\[react-router-serve\]\s*(http.*) \/?/.exec(m) - if (match) url = match[1] - return url != '' - }) - - await retryAssertion(async () => { - let css = await fetchStyles(url) - expect(css).toContain(candidate`font-bold`) - }) -}) - -test( - 'build mode using ?url stylesheet imports should only build one stylesheet (requires `file-system` scanner)', - { - fs: { - ...WORKSPACE, - 'app/root.tsx': ts` - import { Links, Meta, Outlet, Scripts, ScrollRestoration } from 'react-router' - import styles from './app.css?url' - export const links: Route.LinksFunction = () => [{ rel: 'stylesheet', href: styles }] - export function Layout({ children }: { children: React.ReactNode }) { - return ( - - - - - - - - - {children} - - - - - ) - } - - export default function App() { - return - } - `, - 'vite.config.ts': ts` - import { defineConfig } from 'vite' - import { reactRouter } from '@react-router/dev/vite' - import tailwindcss from '@tailwindcss/vite' - - export default defineConfig({ - plugins: [tailwindcss(), reactRouter()], - }) - `, - '.gitignore': txt` - node_modules/ - build/ - `, - }, - }, - async ({ fs, exec, expect }) => { - await exec('pnpm react-router build') - - let files = await fs.glob('build/client/assets/**/*.css') - - expect(files).toHaveLength(1) - let [filename] = files[0] - - await fs.expectFileToContain(filename, [candidate`font-bold`]) - }, -) diff --git a/integrations/vite/resolvers.test.ts b/integrations/vite/resolvers.test.ts index fc9aca5c7..040f84391 100644 --- a/integrations/vite/resolvers.test.ts +++ b/integrations/vite/resolvers.test.ts @@ -1,661 +1,5 @@ import { describe } from 'vitest' -import { - candidate, - css, - fetchStyles, - html, - js, - json, - retryAssertion, - test, - ts, - txt, - yaml, -} from '../utils' - -test( - 'resolves tsconfig paths in production build', - { - fs: { - 'package.json': json` - { - "type": "module", - "dependencies": { - "@tailwindcss/vite": "workspace:^", - "tailwindcss": "workspace:^" - }, - "devDependencies": { - "vite": "^8" - } - } - `, - 'tsconfig.json': json` - { - "compilerOptions": { - "baseUrl": ".", - "paths": { - "@/*": ["./src/*"] - } - } - } - `, - 'vite.config.ts': ts` - import tailwindcss from '@tailwindcss/vite' - import { defineConfig } from 'vite' - - export default defineConfig({ - build: { cssMinify: false }, - plugins: [tailwindcss()], - resolve: { - tsconfigPaths: true, - }, - }) - `, - 'index.html': html` - - - - -
Hello, world!
- - `, - 'src/index.css': css` - @import '@/styles/base.css'; - @plugin '@/plugin.js'; - `, - 'src/styles/base.css': css` - @reference 'tailwindcss/theme'; - @import 'tailwindcss/utilities'; - `, - 'src/plugin.js': js` - export default function ({ addUtilities }) { - addUtilities({ '.custom-underline': { 'border-bottom': '1px solid green' } }) - } - `, - }, - }, - async ({ fs, exec, expect }) => { - await exec('pnpm vite build') - - let files = await fs.glob('dist/**/*.css') - expect(files).toHaveLength(1) - let [filename] = files[0] - - await fs.expectFileToContain(filename, [candidate`underline`, candidate`custom-underline`]) - }, -) - -test( - 'resolves tsconfig paths in dev mode', - { - fs: { - 'package.json': json` - { - "type": "module", - "dependencies": { - "@tailwindcss/vite": "workspace:^", - "tailwindcss": "workspace:^" - }, - "devDependencies": { - "vite": "^8" - } - } - `, - 'tsconfig.json': json` - { - "compilerOptions": { - "baseUrl": ".", - "paths": { - "@/*": ["./src/*"] - } - } - } - `, - 'vite.config.ts': ts` - import tailwindcss from '@tailwindcss/vite' - import { defineConfig } from 'vite' - - export default defineConfig({ - build: { cssMinify: false }, - plugins: [tailwindcss()], - resolve: { - tsconfigPaths: true, - }, - }) - `, - 'index.html': html` - - - - -
Hello, world!
- - `, - 'src/index.css': css` - @import '@/styles/base.css'; - @plugin '@/plugin.js'; - `, - 'src/styles/base.css': css` - @reference 'tailwindcss/theme'; - @import 'tailwindcss/utilities'; - `, - 'src/plugin.js': js` - export default function ({ addUtilities }) { - addUtilities({ '.custom-underline': { 'border-bottom': '1px solid green' } }) - } - `, - }, - }, - async ({ spawn, expect }) => { - let process = await spawn('pnpm vite dev') - await process.onStdout((m) => m.includes('ready in')) - - let url = '' - await process.onStdout((m) => { - let match = /Local:\s*(http.*)\//.exec(m) - if (match) url = match[1] - return Boolean(url) - }) - - await retryAssertion(async () => { - let styles = await fetchStyles(url, '/index.html') - expect(styles).toContain(candidate`underline`) - expect(styles).toContain(candidate`custom-underline`) - }) - }, -) - -test( - 'resolves at-sign aliases in production build', - { - fs: { - 'package.json': json` - { - "type": "module", - "dependencies": { - "@tailwindcss/vite": "workspace:^", - "tailwindcss": "workspace:^" - }, - "devDependencies": { - "vite": "^8" - } - } - `, - 'vite.config.ts': ts` - import tailwindcss from '@tailwindcss/vite' - import { defineConfig } from 'vite' - import { fileURLToPath } from 'node:url' - - export default defineConfig({ - build: { cssMinify: false }, - plugins: [tailwindcss()], - resolve: { - alias: [{ find: '@', replacement: fileURLToPath(new URL('.', import.meta.url)) }], - }, - }) - `, - 'index.html': html` - - - - -
Hello, world!
- - `, - 'src/index.css': css` - @import '@/src/styles/base.css'; - @plugin '@/src/plugin.js'; - `, - 'src/styles/base.css': css` - @reference 'tailwindcss/theme'; - @import 'tailwindcss/utilities'; - `, - 'src/plugin.js': js` - export default function ({ addUtilities }) { - addUtilities({ '.custom-underline': { 'border-bottom': '1px solid green' } }) - } - `, - }, - }, - async ({ fs, exec, expect }) => { - await exec('pnpm vite build') - - let files = await fs.glob('dist/**/*.css') - expect(files).toHaveLength(1) - let [filename] = files[0] - - await fs.expectFileToContain(filename, [candidate`underline`, candidate`custom-underline`]) - }, -) - -test( - 'resolves package plugins in production build with at-sign aliases', - { - fs: { - 'package.json': json` - { - "type": "module", - "dependencies": { - "@tailwindcss/vite": "workspace:^", - "tailwindcss": "workspace:^" - }, - "devDependencies": { - "tailwind-scrollbar": "^4.0.2", - "tailwindcss-motion": "^1.1.1", - "vite": "^8" - } - } - `, - 'vite.config.ts': ts` - import tailwindcss from '@tailwindcss/vite' - import { defineConfig } from 'vite' - import { fileURLToPath } from 'node:url' - - export default defineConfig({ - build: { cssMinify: false }, - plugins: [tailwindcss()], - resolve: { - alias: [{ find: '@', replacement: fileURLToPath(new URL('.', import.meta.url)) }], - }, - }) - `, - 'index.html': html` - - - - -
Hello, world!
- - `, - 'src/index.css': css` - @import 'tailwindcss'; - @plugin 'tailwind-scrollbar'; - @plugin 'tailwindcss-motion'; - `, - }, - }, - async ({ fs, exec, expect }) => { - await exec('pnpm vite build') - - let files = await fs.glob('dist/**/*.css') - expect(files).toHaveLength(1) - let [filename] = files[0] - - await fs.expectFileToContain(filename, [ - candidate`scrollbar`, - candidate`scrollbar-thumb-red-500`, - candidate`motion-preset-fade`, - ]) - }, -) - -test( - 'resolves package plugins to JS entries in production build when browser points to CSS', - { - fs: { - 'package.json': json` - { - "type": "module", - "dependencies": { - "@tailwindcss/vite": "workspace:^", - "plugin-browser-css": "workspace:*", - "tailwindcss": "workspace:^" - }, - "devDependencies": { - "vite": "^8" - } - } - `, - 'pnpm-workspace.yaml': yaml` - # - packages: - - packages/* - `, - 'packages/plugin-browser-css/package.json': json` - { - "name": "plugin-browser-css", - "version": "1.0.0", - "type": "module", - "main": "./index.js", - "module": "./index.js", - "browser": "./browser.css" - } - `, - 'packages/plugin-browser-css/index.js': js` - export default function ({ addUtilities }) { - addUtilities({ '.browser-css-plugin': { 'border-bottom': '1px solid green' } }) - } - `, - 'packages/plugin-browser-css/browser.css': css` - .should-not-be-loaded-as-a-plugin { - display: none; - } - `, - 'vite.config.ts': ts` - import tailwindcss from '@tailwindcss/vite' - import { defineConfig } from 'vite' - - export default defineConfig({ - build: { cssMinify: false }, - plugins: [tailwindcss()], - }) - `, - 'index.html': html` - - - - - -
Hello, world!
- - - `, - 'src/index.css': css` - @import 'tailwindcss'; - @plugin 'plugin-browser-css'; - `, - }, - }, - async ({ fs, exec, expect }) => { - await exec('pnpm vite build') - - let files = await fs.glob('dist/**/*.css') - expect(files).toHaveLength(1) - let [filename] = files[0] - - await fs.expectFileToContain(filename, [candidate`browser-css-plugin`]) - }, -) - -test( - 'resolves package plugins to JS entries in dev mode when browser points to CSS', - { - fs: { - 'package.json': json` - { - "type": "module", - "dependencies": { - "@tailwindcss/vite": "workspace:^", - "plugin-browser-css": "workspace:*", - "tailwindcss": "workspace:^" - }, - "devDependencies": { - "vite": "^8" - } - } - `, - 'pnpm-workspace.yaml': yaml` - # - packages: - - packages/* - `, - 'packages/plugin-browser-css/package.json': json` - { - "name": "plugin-browser-css", - "version": "1.0.0", - "type": "module", - "main": "./index.js", - "module": "./index.js", - "browser": "./browser.css" - } - `, - 'packages/plugin-browser-css/index.js': js` - export default function ({ addUtilities }) { - addUtilities({ '.browser-css-plugin': { 'border-bottom': '1px solid green' } }) - } - `, - 'packages/plugin-browser-css/browser.css': css` - .should-not-be-loaded-as-a-plugin { - display: none; - } - `, - 'vite.config.ts': ts` - import tailwindcss from '@tailwindcss/vite' - import { defineConfig } from 'vite' - - export default defineConfig({ - build: { cssMinify: false }, - plugins: [tailwindcss()], - }) - `, - 'index.html': html` - - - - - -
Hello, world!
- - - `, - 'src/index.css': css` - @import 'tailwindcss'; - @plugin 'plugin-browser-css'; - `, - }, - }, - async ({ spawn, expect }) => { - let process = await spawn('pnpm vite dev') - await process.onStdout((m) => m.includes('ready in')) - - let url = '' - await process.onStdout((m) => { - let match = /Local:\s*(http.*)\//.exec(m) - if (match) url = match[1] - return Boolean(url) - }) - - await retryAssertion(async () => { - let styles = await fetchStyles(url, '/index.html') - expect(styles).toContain(candidate`browser-css-plugin`) - }) - }, -) - -test( - 'resolves package plugins in dev mode when package exports CSS files', - { - fs: { - 'package.json': json` - { - "type": "module", - "dependencies": { - "@tailwindcss/vite": "workspace:^", - "daisyui": "^5", - "tailwindcss": "workspace:^" - }, - "devDependencies": { - "vite": "^8" - } - } - `, - 'vite.config.ts': ts` - import tailwindcss from '@tailwindcss/vite' - import { defineConfig } from 'vite' - - export default defineConfig({ - build: { cssMinify: false }, - plugins: [tailwindcss()], - }) - `, - 'index.html': html` - - - - - - - - - `, - 'src/index.css': css` - @import 'tailwindcss'; - @plugin 'daisyui'; - `, - }, - }, - async ({ spawn, expect }) => { - let process = await spawn('pnpm vite dev') - await process.onStdout((m) => m.includes('ready in')) - - let url = '' - await process.onStdout((m) => { - let match = /Local:\s*(http.*)\//.exec(m) - if (match) url = match[1] - return Boolean(url) - }) - - await retryAssertion(async () => { - let styles = await fetchStyles(url, '/index.html') - expect(styles).toContain('.btn') - expect(styles).toContain('.btn-primary') - }) - }, -) - -test( - 'resolve relative CSS files correctly', - { - fs: { - 'package.json': json` - { - "type": "module", - "dependencies": { - "@tailwindcss/vite": "workspace:^", - "tailwindcss": "workspace:^" - }, - "devDependencies": { - "vite": "^8" - } - } - `, - 'vite.config.ts': ts` - import tailwindcss from '@tailwindcss/vite' - import { defineConfig } from 'vite' - - export default defineConfig({ - build: { cssMinify: false }, - plugins: [tailwindcss()], - }) - `, - 'index.html': html` - - - - - - - `, - 'src/index.css': css` - @reference 'tailwindcss/theme'; - @import 'tailwindcss/utilities'; - @import './themes/glow.css'; - `, - // References a file in the current folder, which names happens to match a - // file in the parent folder as well. - 'src/themes/glow.css': css`@import './entry.css';`, - 'src/themes/entry.css': css` - .do-include-me { - color: green; - } - `, - - // Never rerefenced, so should not be included - 'src/entry.css': css` - .do-not-include-me { - color: red; - } - `, - }, - }, - async ({ exec, fs, expect }) => { - await exec('pnpm vite build') - - expect( - (await fs.dumpFiles('./dist/**/*.css')).replace(/-([-_a-zA-Z0-9]*?)\.css/g, '-.css'), - ).toMatchInlineSnapshot(` - " - --- ./dist/assets/index-.css --- - .do-include-me { - color: green; - } - " - `) - }, -) - -test( - 'resolve relative JS files correctly', - { - fs: { - 'package.json': json` - { - "type": "module", - "dependencies": { - "@tailwindcss/vite": "workspace:^", - "tailwindcss": "workspace:^" - }, - "devDependencies": { - "vite": "^8" - } - } - `, - 'vite.config.ts': ts` - import tailwindcss from '@tailwindcss/vite' - import { defineConfig } from 'vite' - - export default defineConfig({ - build: { cssMinify: false }, - plugins: [tailwindcss()], - }) - `, - 'index.html': html` - - - - - - - `, - 'src/index.css': css` - @reference 'tailwindcss/theme'; - @import 'tailwindcss/utilities'; - @import './themes/glow.css'; - `, - // References a file in the current folder, which names happens to match a - // file in the parent folder as well. - 'src/themes/glow.css': css`@plugin "./my-plugin.js";`, - 'src/themes/my-plugin.js': ts` - export default function ({ addBase }) { - addBase({ '.do-include-me': { color: 'green' } }) - } - `, - - // Never rerefenced, so should not be included - 'src/my-plugin.js': css` - export default function ({ addBase }) { - addBase({ '.do-not-include-me': { 'color': 'red' } }) - } - `, - }, - }, - async ({ exec, fs, expect }) => { - await exec('pnpm vite build') - - expect( - (await fs.dumpFiles('./dist/**/*.css')).replace(/-([-_a-zA-Z0-9]*?)\.css/g, '-.css'), - ).toMatchInlineSnapshot(` - " - --- ./dist/assets/index-.css --- - @layer base { - .do-include-me { - color: green; - } - } - " - `) - }, -) +import { candidate, css, fetchStyles, html, js, retryAssertion, test, ts, txt } from '../utils' describe.each(['postcss', 'lightningcss'])('%s', (transformer) => { test( @@ -670,7 +14,7 @@ describe.each(['postcss', 'lightningcss'])('%s', (transformer) => { "tailwindcss": "workspace:^" }, "devDependencies": { - ${transformer === 'lightningcss' ? `"lightningcss": "^1",` : ''} + ${transformer === 'lightningcss' ? `"lightningcss": "^1.26.0",` : ''} "vite": "^5.3.5" } } @@ -705,7 +49,7 @@ describe.each(['postcss', 'lightningcss'])('%s', (transformer) => { @plugin '#js-alias'; `, 'src/alias.css': css` - @reference 'tailwindcss/theme'; + @import 'tailwindcss/theme' theme(reference); @import 'tailwindcss/utilities'; `, 'src/plugin.js': js` @@ -738,7 +82,7 @@ describe.each(['postcss', 'lightningcss'])('%s', (transformer) => { "tailwindcss": "workspace:^" }, "devDependencies": { - ${transformer === 'lightningcss' ? `"lightningcss": "^1",` : ''} + ${transformer === 'lightningcss' ? `"lightningcss": "^1.26.0",` : ''} "vite": "^5.3.5" } } @@ -773,7 +117,7 @@ describe.each(['postcss', 'lightningcss'])('%s', (transformer) => { @plugin '#js-alias'; `, 'src/alias.css': css` - @reference 'tailwindcss/theme'; + @import 'tailwindcss/theme' theme(reference); @import 'tailwindcss/utilities'; `, 'src/plugin.js': js` diff --git a/integrations/vite/solidstart.test.ts b/integrations/vite/solidstart.test.ts deleted file mode 100644 index bbe9ccc88..000000000 --- a/integrations/vite/solidstart.test.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { candidate, css, fetchStyles, js, json, retryAssertion, test, ts } from '../utils' - -const WORKSPACE = { - 'package.json': json` - { - "type": "module", - "dependencies": { - "@solidjs/start": "^1", - "solid-js": "^1", - "vinxi": "^0", - "@tailwindcss/vite": "workspace:^", - "tailwindcss": "workspace:^" - } - } - `, - 'jsconfig.json': json` - { - "compilerOptions": { - "jsx": "preserve", - "jsxImportSource": "solid-js" - } - } - `, - 'app.config.js': ts` - import { defineConfig } from '@solidjs/start/config' - import tailwindcss from '@tailwindcss/vite' - - export default defineConfig({ - vite: { - plugins: [tailwindcss()], - }, - }) - `, - 'src/entry-server.jsx': js` - // @refresh reload - import { createHandler, StartServer } from '@solidjs/start/server' - - export default createHandler(() => ( - ( - - {assets} - -
{children}
- {scripts} - - - )} - /> - )) - `, - 'src/entry-client.jsx': js` - // @refresh reload - import { mount, StartClient } from '@solidjs/start/client' - - mount(() => , document.getElementById('app')) - `, - 'src/app.jsx': js` - import './app.css' - export default function App() { - return

Hello world!

- } - `, - 'src/app.css': css`@import 'tailwindcss';`, -} - -test( - 'dev mode', - { - fs: WORKSPACE, - }, - async ({ fs, spawn, expect }) => { - let process = await spawn('pnpm vinxi dev', { - env: { - TEST: 'false', // VERY IMPORTANT OTHERWISE YOU WON'T GET OUTPUT - NODE_ENV: 'development', - }, - }) - - let url = '' - await process.onStdout((m) => { - let match = /Local:\s*(http.*)\//.exec(m) - if (match) url = match[1] - return Boolean(url) - }) - - await retryAssertion(async () => { - let css = await fetchStyles(url) - expect(css).toContain(candidate`underline`) - }) - - await retryAssertion(async () => { - await fs.write( - 'src/app.jsx', - js` - import './app.css' - export default function App() { - return

Hello world!

- } - `, - ) - - let css = await fetchStyles(url) - expect(css).toContain(candidate`underline`) - expect(css).toContain(candidate`font-bold`) - }) - }, -) diff --git a/integrations/vite/source-maps.test.ts b/integrations/vite/source-maps.test.ts deleted file mode 100644 index fe26d9a7c..000000000 --- a/integrations/vite/source-maps.test.ts +++ /dev/null @@ -1,157 +0,0 @@ -import { candidate, css, fetchStyles, html, json, retryAssertion, test, ts } from '../utils' - -test( - `dev build`, - { - fs: { - 'package.json': json` - { - "type": "module", - "dependencies": { - "@tailwindcss/vite": "workspace:^", - "tailwindcss": "workspace:^" - }, - "devDependencies": { - "lightningcss": "^1", - "vite": "^7" - } - } - `, - 'vite.config.ts': ts` - import tailwindcss from '@tailwindcss/vite' - import { defineConfig } from 'vite' - - export default defineConfig({ - plugins: [tailwindcss()], - css: { - devSourcemap: true, - }, - }) - `, - 'index.html': html` - - - - -
Hello, world!
- - `, - 'src/index.css': css` - @import 'tailwindcss/utilities'; - /* */ - `, - }, - }, - async ({ fs, spawn, expect, parseSourceMap }) => { - // Source maps only work in development mode in Vite - let process = await spawn('pnpm vite dev') - await process.onStdout((m) => m.includes('ready in')) - - let url = '' - await process.onStdout((m) => { - let match = /Local:\s*(http.*)\//.exec(m) - if (match) url = match[1] - return Boolean(url) - }) - - let styles = await retryAssertion(async () => { - let styles = await fetchStyles(url, '/index.html') - - // Wait until we have the right CSS - expect(styles).toContain(candidate`flex`) - - return styles - }) - - // Make sure we can find a source map - let map = parseSourceMap(styles) - - expect(map.at(1, 0)).toMatchObject({ - source: null, - original: '(none)', - generated: '/*! tailwi...', - }) - - expect(map.at(2, 0)).toMatchObject({ - source: expect.stringContaining('utilities.css'), - original: '@tailwind...', - generated: '.flex {...', - }) - - expect(map.at(3, 2)).toMatchObject({ - source: expect.stringContaining('utilities.css'), - original: '@tailwind...', - generated: 'display: f...', - }) - - expect(map.at(4, 0)).toMatchObject({ - source: null, - original: '(none)', - generated: '}...', - }) - }, -) - -// https://github.com/tailwindlabs/tailwindcss/issues/19930 -test( - 'production build without Tailwind roots should not result in source map warnings', - { - fs: { - 'package.json': json` - { - "type": "module", - "dependencies": { - "@tailwindcss/vite": "workspace:^", - "tailwindcss": "workspace:^" - }, - "devDependencies": { - "vite": "^7" - } - } - `, - 'vite.config.ts': ts` - import { defineConfig } from 'vite' - import tailwindcss from '@tailwindcss/vite' - - export default defineConfig({ - plugins: [ - tailwindcss(), - { - name: 'inspect-source-map-chain', - enforce: 'pre', - transform(_, id) { - if (id.includes('.css')) { - // Force Rollup to collapse the sourcemap chain during this build. - this.getCombinedSourcemap() - } - }, - }, - ], - css: { - devSourcemap: true, - }, - build: { - sourcemap: true, - }, - }) - `, - 'index.html': html` - - -
Hello, world!
- - `, - 'src/index.js': ts` import './index.css' `, - 'src/index.css': css` - body { - color: red; - } - `, - }, - }, - async ({ exec, expect }) => { - let output = await exec('pnpm vite build') - - expect(output).not.toContain('Sourcemap is likely to be incorrect') - }, -) diff --git a/integrations/vite/ssr.test.ts b/integrations/vite/ssr.test.ts index a1d660816..3c3f1cc4b 100644 --- a/integrations/vite/ssr.test.ts +++ b/integrations/vite/ssr.test.ts @@ -1,72 +1,138 @@ -import { describe } from 'vitest' import { candidate, css, html, json, test, ts } from '../utils' -describe.each([['^5.3'], ['^6.0'], ['^7'], ['^8']])('Using Vite %s', (version) => { - test( - `SSR build`, - { - fs: { - 'package.json': json` - { - "type": "module", - "dependencies": { - "@tailwindcss/vite": "workspace:^", - "tailwindcss": "workspace:^" - }, - "devDependencies": { - "vite": "${version}" - } +test( + 'Vite 5', + { + fs: { + 'package.json': json` + { + "type": "module", + "dependencies": { + "@tailwindcss/vite": "workspace:^", + "tailwindcss": "workspace:^" + }, + "_comment": "This test uses Vite 5.3 on purpose. Do not upgrade it to Vite 6.", + "devDependencies": { + "vite": "^5.3" } - `, - 'vite.config.ts': ts` - import tailwindcss from '@tailwindcss/vite' - import { defineConfig } from 'vite' + } + `, + 'vite.config.ts': ts` + import tailwindcss from '@tailwindcss/vite' + import { defineConfig } from 'vite' - export default defineConfig({ - build: { - cssMinify: false, - ssrEmitAssets: true, - }, - plugins: [tailwindcss()], - }) - `, - 'index.html': html` - -
- - - `, - 'src/index.css': css`@import 'tailwindcss';`, - 'src/index.ts': ts` - import './index.css' + export default defineConfig({ + build: { + cssMinify: false, + ssrEmitAssets: true, + }, + plugins: [tailwindcss()], + ssr: { resolve: { conditions: [] } }, + }) + `, + 'index.html': html` + +
+ + + `, + 'src/index.css': css`@import 'tailwindcss';`, + 'src/index.ts': ts` + import './index.css' - document.querySelector('#app').innerHTML = \` -
Hello, world!
- \` - `, - 'server.ts': ts` - import css from './src/index.css?url' + document.querySelector('#app').innerHTML = \` +
Hello, world!
+ \` + `, + 'server.ts': ts` + import css from './src/index.css?url' - document.querySelector('#app').innerHTML = \` - -
Hello, world!
- \` - `, - }, + document.querySelector('#app').innerHTML = \` + +
Hello, world!
+ \` + `, }, - async ({ fs, exec, expect }) => { - await exec('pnpm vite build --ssr server.ts') + }, + async ({ fs, exec, expect }) => { + await exec('pnpm vite build --ssr server.ts') - let files = await fs.glob('dist/**/*.css') - expect(files).toHaveLength(1) - let [filename] = files[0] + let files = await fs.glob('dist/**/*.css') + expect(files).toHaveLength(1) + let [filename] = files[0] - await fs.expectFileToContain(filename, [ - candidate`underline`, - candidate`m-2`, - candidate`overline`, - candidate`m-3`, - ]) + await fs.expectFileToContain(filename, [ + // + candidate`underline`, + candidate`m-2`, + ]) + }, +) + +test( + `Vite 6`, + { + fs: { + 'package.json': json` + { + "type": "module", + "dependencies": { + "@tailwindcss/vite": "workspace:^", + "tailwindcss": "workspace:^" + }, + "devDependencies": { + "vite": "^6.0" + } + } + `, + 'vite.config.ts': ts` + import tailwindcss from '@tailwindcss/vite' + import { defineConfig } from 'vite' + + export default defineConfig({ + build: { + cssMinify: false, + ssrEmitAssets: true, + }, + plugins: [tailwindcss()], + ssr: { resolve: { conditions: [] } }, + }) + `, + 'index.html': html` + +
+ + + `, + 'src/index.css': css`@import 'tailwindcss';`, + 'src/index.ts': ts` + import './index.css' + + document.querySelector('#app').innerHTML = \` +
Hello, world!
+ \` + `, + 'server.ts': ts` + import css from './src/index.css?url' + + document.querySelector('#app').innerHTML = \` + +
Hello, world!
+ \` + `, }, - ) -}) + }, + async ({ fs, exec, expect }) => { + await exec('pnpm vite build --ssr server.ts') + + let files = await fs.glob('dist/**/*.css') + expect(files).toHaveLength(1) + let [filename] = files[0] + + await fs.expectFileToContain(filename, [ + // + candidate`underline`, + candidate`m-2`, + ]) + }, +) diff --git a/integrations/vite/svelte.test.ts b/integrations/vite/svelte.test.ts index e186c3f85..33eca5a13 100644 --- a/integrations/vite/svelte.test.ts +++ b/integrations/vite/svelte.test.ts @@ -14,7 +14,7 @@ test( "devDependencies": { "@sveltejs/vite-plugin-svelte": "^5", "@tailwindcss/vite": "workspace:^", - "vite": "^7" + "vite": "^6" } } `, @@ -57,19 +57,19 @@ test(

Hello {name}!

`, 'src/other.css': css` .local { @apply text-red-500; - animation: 2s ease-in-out infinite localKeyframes; + animation: 2s ease-in-out 0s infinite localKeyframes; } :global(.global) { @apply text-green-500; - animation: 2s ease-in-out infinite globalKeyframes; + animation: 2s ease-in-out 0s infinite globalKeyframes; } @keyframes -global-globalKeyframes { @@ -93,21 +93,18 @@ test( }, }, async ({ exec, fs, expect }) => { - let output = await exec('pnpm vite build') + await exec('pnpm vite build') let files = await fs.glob('dist/**/*.css') expect(files).toHaveLength(1) await fs.expectFileToContain(files[0][0], [ candidate`underline`, - '.global{color:var(--color-green-500,oklch(72.3% .219 149.579));animation:2s ease-in-out infinite globalKeyframes}', - /\.local.svelte-.*\{color:var\(--color-red-500,oklch\(63\.7% \.237 25\.331\)\);animation:2s ease-in-out infinite svelte-.*-localKeyframes\}/, + '.global{color:var(--color-green-500);animation:2s ease-in-out 0s infinite globalKeyframes}', + /\.local.svelte-.*\{color:var\(--color-red-500\);animation:2s ease-in-out 0s infinite svelte-.*-localKeyframes\}/, /@keyframes globalKeyframes\{/, /@keyframes svelte-.*-localKeyframes\{/, ]) - - // Should not print any warnings - expect(output).not.toContain('vite-plugin-svelte') }, ) @@ -125,7 +122,7 @@ test( "devDependencies": { "@sveltejs/vite-plugin-svelte": "^5", "@tailwindcss/vite": "workspace:^", - "vite": "^7" + "vite": "^6" } } `, @@ -167,20 +164,20 @@ test(

Hello {name}!

`, 'src/index.css': css` @import 'tailwindcss'; `, 'src/other.css': css` .local { @apply text-red-500; - animation: 2s ease-in-out infinite localKeyframes; + animation: 2s ease-in-out 0s infinite localKeyframes; } :global(.global) { @apply text-green-500; - animation: 2s ease-in-out infinite globalKeyframes; + animation: 2s ease-in-out 0s infinite globalKeyframes; } @keyframes -global-globalKeyframes { @@ -213,10 +210,10 @@ test( let [, css] = files[0] expect(css).toContain(candidate`underline`) expect(css).toContain( - '.global{color:var(--color-green-500,oklch(72.3% .219 149.579));animation:2s ease-in-out infinite globalKeyframes}', + '.global{color:var(--color-green-500);animation:2s ease-in-out 0s infinite globalKeyframes}', ) expect(css).toMatch( - /\.local.svelte-.*\{color:var\(--color-red-500,oklch\(63\.7% \.237 25\.331\)\);animation:2s ease-in-out infinite svelte-.*-localKeyframes\}/, + /\.local.svelte-.*\{color:var\(--color-red-500\);animation:2s ease-in-out 0s infinite svelte-.*-localKeyframes\}/, ) expect(css).toMatch(/@keyframes globalKeyframes\{/) expect(css).toMatch(/@keyframes svelte-.*-localKeyframes\{/) @@ -238,16 +235,14 @@ test( let [, css] = files[0] expect(css).toContain(candidate`font-bold`) expect(css).toContain( - '.global{color:var(--color-green-500,oklch(72.3% .219 149.579));animation:2s ease-in-out infinite globalKeyframes}', + '.global{color:var(--color-green-500);animation:2s ease-in-out 0s infinite globalKeyframes}', ) expect(css).toMatch( - /\.local.svelte-.*\{color:var\(--color-red-500,oklch\(63\.7% \.237 25\.331\)\);animation:2s ease-in-out infinite svelte-.*-localKeyframes\}/, + /\.local.svelte-.*\{color:var\(--color-red-500\);animation:2s ease-in-out 0s infinite svelte-.*-localKeyframes\}/, ) expect(css).toMatch(/@keyframes globalKeyframes\{/) expect(css).toMatch(/@keyframes svelte-.*-localKeyframes\{/) - expect(css).toMatch( - /\.bar.svelte-.*\{color:var\(--color-pink-500,oklch\(65\.6% \.241 354\.308\)\)\}/, - ) + expect(css).toMatch(/\.bar.svelte-.*\{color:var\(--color-pink-500\)\}/) }) }, ) diff --git a/integrations/vite/sveltekit.test.ts b/integrations/vite/sveltekit.test.ts deleted file mode 100644 index 92e855da9..000000000 --- a/integrations/vite/sveltekit.test.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { candidate, css, html, js, json, test, ts } from '../utils' - -test( - 'sveltekit build resolves package plugins', - { - fs: { - 'package.json': json` - { - "type": "module", - "scripts": { - "prepare": "svelte-kit sync || echo ''" - }, - "dependencies": { - "svelte": "^5", - "tailwindcss": "workspace:^" - }, - "devDependencies": { - "@sveltejs/adapter-auto": "^6", - "@sveltejs/kit": "^2", - "@tailwindcss/forms": "^0.5.11", - "@tailwindcss/vite": "workspace:^", - "vite": "^8" - } - } - `, - 'svelte.config.js': js` - import adapter from '@sveltejs/adapter-auto' - - export default { - kit: { - adapter: adapter(), - }, - } - `, - 'vite.config.ts': ts` - import tailwindcss from '@tailwindcss/vite' - import { sveltekit } from '@sveltejs/kit/vite' - import { defineConfig } from 'vite' - - export default defineConfig({ - build: { cssMinify: false }, - plugins: [tailwindcss(), sveltekit()], - }) - `, - 'src/app.html': html` - - - - %sveltekit.head% - - -
%sveltekit.body%
- - - `, - 'src/routes/+layout.svelte': html` - - - - `, - 'src/routes/+page.svelte': html` -
Hello, world!
- `, - 'src/app.css': css` - @import 'tailwindcss'; - @plugin '@tailwindcss/forms'; - `, - }, - }, - async ({ exec, fs, expect }) => { - await exec('pnpm vite build') - - let files = await fs.glob('.svelte-kit/output/client/**/*.css') - expect(files.length).toBeGreaterThan(0) - - await fs.expectFileToContain(files[0][0], [candidate`form-input`]) - }, -) diff --git a/integrations/vite/url-rewriting.test.ts b/integrations/vite/url-rewriting.test.ts index 500fe6d71..a7c6433d4 100644 --- a/integrations/vite/url-rewriting.test.ts +++ b/integrations/vite/url-rewriting.test.ts @@ -15,9 +15,9 @@ describe.each(['postcss', 'lightningcss'])('%s', (transformer) => { "tailwindcss": "workspace:^" }, "devDependencies": { - ${transformer === 'lightningcss' ? `"lightningcss": "^1",` : ''} + ${transformer === 'lightningcss' ? `"lightningcss": "^1.26.0",` : ''} "@tailwindcss/vite": "workspace:^", - "vite": "^7" + "vite": "^6" } } `, @@ -42,36 +42,31 @@ describe.each(['postcss', 'lightningcss'])('%s', (transformer) => {
+ `, + 'src/main.ts': ts``, 'src/app.css': css` - @reference 'tailwindcss'; @import './dir-1/bar.css'; @import './dir-1/dir-2/baz.css'; @import './dir-1/dir-2/vector.css'; `, 'src/dir-1/bar.css': css` - .test1 { + .bar { background-image: url('../../resources/image.png'); } `, 'src/dir-1/dir-2/baz.css': css` - .test2 { + .baz { background-image: url('../../../resources/image.png'); } `, 'src/dir-1/dir-2/vector.css': css` - @import './dir-3/vector.css'; - .test3 { + .baz { background-image: url('../../../resources/vector.svg'); } `, - 'src/dir-1/dir-2/dir-3/vector.css': css` - .test4 { - background-image: url('./vector-2.svg'); - } - `, 'resources/image.png': binary(SIMPLE_IMAGE), 'resources/vector.svg': svg` @@ -81,14 +76,6 @@ describe.each(['postcss', 'lightningcss'])('%s', (transformer) => { `, - 'src/dir-1/dir-2/dir-3/vector-2.svg': svg` - - - - - - - `, }, }, async ({ fs, exec, expect }) => { @@ -100,7 +87,7 @@ describe.each(['postcss', 'lightningcss'])('%s', (transformer) => { await fs.expectFileToContain(files[0][0], [SIMPLE_IMAGE]) let images = await fs.glob('dist/**/*.svg') - expect(images).toHaveLength(2) + expect(images).toHaveLength(1) await fs.expectFileToContain(files[0][0], [/\/assets\/vector-.*?\.svg/]) }, diff --git a/integrations/vite/virtual-modules.test.ts b/integrations/vite/virtual-modules.test.ts deleted file mode 100644 index 12eadb6c7..000000000 Binary files a/integrations/vite/virtual-modules.test.ts and /dev/null differ diff --git a/integrations/vite/vue.test.ts b/integrations/vite/vue.test.ts index b04f57c6b..7b5da2904 100644 --- a/integrations/vite/vue.test.ts +++ b/integrations/vite/vue.test.ts @@ -1,5 +1,4 @@ -import { stripVTControlCharacters } from 'node:util' -import { candidate, css, fetchStyles, html, json, retryAssertion, test, ts } from '../utils' +import { candidate, html, json, test, ts } from '../utils' test( 'production build', @@ -15,7 +14,7 @@ test( "devDependencies": { "@vitejs/plugin-vue": "^5.1.2", "@tailwindcss/vite": "workspace:^", - "vite": "^7" + "vite": "^6" } } `, @@ -72,309 +71,3 @@ test( await fs.expectFileToContain(files[0][0], ['.bar{']) }, ) - -{ - const VUE_COMPONENT_COUNT = 1_000 - - let vueComponentsWithReferences = Object.fromEntries( - Array.from({ length: VUE_COMPONENT_COUNT }, (_, idx) => [ - `src/components/Component${idx}.vue`, - html` - - - - `, - ]), - ) - - let vueComponentImports = Array.from( - { length: VUE_COMPONENT_COUNT }, - (_, idx) => `import Component${idx} from './components/Component${idx}.vue'`, - ).join('\n') - - let vueComponentUsages = Array.from( - { length: VUE_COMPONENT_COUNT }, - (_, idx) => ``, - ).join('\n') - - test( - 'production build with many Vue style blocks referencing the main stylesheet', - { - fs: { - 'package.json': json` - { - "type": "module", - "dependencies": { - "vue": "^3.4.37", - "tailwindcss": "workspace:^" - }, - "devDependencies": { - "@vitejs/plugin-vue": "^5.1.2", - "@tailwindcss/vite": "workspace:^", - "vite": "^7" - } - } - `, - 'vite.config.ts': ts` - import { defineConfig } from 'vite' - import vue from '@vitejs/plugin-vue' - import tailwindcss from '@tailwindcss/vite' - - export default defineConfig({ - plugins: [vue(), tailwindcss()], - }) - `, - 'index.html': html` - - - -
- - - - `, - 'src/main.css': css`@import 'tailwindcss';`, - 'src/main.ts': ts` - import { createApp } from 'vue' - import './main.css' - import App from './App.vue' - - createApp(App).mount('#app') - `, - 'src/App.vue': html` - - - - `, - ...vueComponentsWithReferences, - }, - }, - async ({ fs, exec, expect }) => { - await exec('pnpm vite build') - - let files = await fs.glob('dist/**/*.css') - expect(files).toHaveLength(1) - - await fs.expectFileToContain(files[0][0], [ - candidate`content-['component-0']`, - candidate`component-0`, - candidate`content-['component-99']`, - candidate`component-99`, - candidate`content-['component-999']`, - candidate`component-999`, - ]) - }, - ) -} - -test( - 'error when using `@apply` without `@reference`', - { - fs: { - 'package.json': json` - { - "type": "module", - "dependencies": { - "vue": "^3.4.37", - "tailwindcss": "workspace:^" - }, - "devDependencies": { - "@vitejs/plugin-vue": "^5.1.2", - "@tailwindcss/vite": "workspace:^", - "vite": "^7" - } - } - `, - 'vite.config.ts': ts` - import { defineConfig } from 'vite' - import vue from '@vitejs/plugin-vue' - import tailwindcss from '@tailwindcss/vite' - - export default defineConfig({ - plugins: [vue(), tailwindcss()], - }) - `, - 'index.html': html` - - - -
- - - - `, - 'src/main.ts': ts` - import { createApp } from 'vue' - import App from './App.vue' - - createApp(App).mount('#app') - `, - 'src/App.vue': html` - - - - `, - }, - }, - async ({ exec, expect }) => { - expect.assertions(1) - - try { - await exec('pnpm vite build', {}, { ignoreStdErr: true }) - } catch (error) { - let [, message] = - /error during build:([\s\S]*?)file:/g.exec( - stripVTControlCharacters(error.message.replace(/\r?\n/g, '\n')), - ) ?? [] - expect(message.trim()).toMatchInlineSnapshot( - `"[@tailwindcss/vite:generate:build] Cannot apply unknown utility class \`text-red-500\`. Are you using CSS modules or similar and missing \`@reference\`? https://tailwindcss.com/docs/functions-and-directives#reference-directive"`, - ) - } - }, -) - -// https://github.com/tailwindlabs/tailwindcss/issues/20320 -test( - 'editing a scanned `.vue` file that is not loaded as a module does not trigger a full reload', - { - fs: { - 'package.json': json` - { - "type": "module", - "dependencies": { - "vue": "^3.4.37", - "tailwindcss": "workspace:^" - }, - "devDependencies": { - "@vitejs/plugin-vue": "^6", - "@tailwindcss/vite": "workspace:^", - "vite": "^8" - } - } - `, - 'vite.config.ts': ts` - import fs from 'node:fs' - import path from 'node:path' - import { defineConfig } from 'vite' - import vue from '@vitejs/plugin-vue' - import tailwindcss from '@tailwindcss/vite' - - export default defineConfig({ - plugins: [ - vue(), - tailwindcss(), - { - // Log update and full-reload HMR payloads to a file so the - // test can assert on them. Custom events are not logged - // because \`@vitejs/plugin-vue\` sends a \`file-changed\` event - // for every file change, including changes to the log file - // itself, which would cause an infinite feedback loop. - name: 'hmr-wiretap', - configureServer(server) { - let logFile = path.resolve('hmr.log') - fs.writeFileSync(logFile, '') - for (let environment of Object.values(server.environments)) { - let send = environment.hot.send.bind(environment.hot) - environment.hot.send = (payload) => { - if (payload.type === 'update' || payload.type === 'full-reload') { - fs.appendFileSync(logFile, JSON.stringify(payload) + '\\n') - } - return send(payload) - } - } - }, - }, - ], - }) - `, - 'index.html': html` - - - - - - -
- - - - `, - 'src/index.css': css`@import 'tailwindcss';`, - 'src/main.ts': ts` - import { createApp } from 'vue' - import App from './App.vue' - - createApp(App).mount('#app') - `, - 'src/App.vue': html` - - `, - - // This file is scanned by Tailwind but never imported, so it is not - // part of the loaded module graph (e.g. a lazy route that hasn't been - // visited yet) - 'src/LazyRoute.vue': html` - - `, - }, - }, - async ({ spawn, fs, expect }) => { - let process = await spawn('pnpm vite dev') - await process.onStdout((m) => m.includes('ready in')) - - let url = '' - await process.onStdout((m) => { - let match = /Local:\s*(http.*)\//.exec(m) - if (match) url = match[1] - return Boolean(url) - }) - - await retryAssertion(async () => { - let styles = await fetchStyles(url, '/index.html') - expect(styles).toContain(candidate`content-['src/App.vue']`) - expect(styles).toContain(candidate`content-['src/LazyRoute.vue']`) - }) - - // Load `main.ts` and `App.vue` as real modules, like a browser visiting - // the page would - await fetch(`${url}/src/main.ts`) - await fetch(`${url}/src/App.vue`) - - // Changing the scanned but unloaded `.vue` file should not trigger a - // full reload, but new classes should still apply - await fs.write( - 'src/LazyRoute.vue', - html` - - `, - ) - - await retryAssertion(async () => { - let styles = await fetchStyles(url, '/index.html') - expect(styles).toContain(candidate`content-['updated:src/LazyRoute.vue']`) - }) - expect(await fs.read('hmr.log')).not.toContain('full-reload') - }, -) diff --git a/integrations/vitest.config.mts b/integrations/vitest.config.ts similarity index 100% rename from integrations/vitest.config.mts rename to integrations/vitest.config.ts diff --git a/integrations/webpack/index.test.ts b/integrations/webpack/index.test.ts deleted file mode 100644 index 2a91411d2..000000000 --- a/integrations/webpack/index.test.ts +++ /dev/null @@ -1,110 +0,0 @@ -import { css, html, js, json, test } from '../utils' - -test( - 'webpack + PostCSS (watch)', - { - fs: { - 'package.json': json` - { - "main": "./src/index.js", - "browser": "./src/index.js", - "dependencies": { - "css-loader": "^6", - "postcss": "^8", - "postcss-loader": "^7", - "webpack": "^5", - "webpack-cli": "^5", - "mini-css-extract-plugin": "^2", - "tailwindcss": "workspace:^", - "@tailwindcss/postcss": "workspace:^" - } - } - `, - 'postcss.config.js': js` - /** @type {import('postcss-load-config').Config} */ - module.exports = { - plugins: { - '@tailwindcss/postcss': {}, - }, - } - `, - 'webpack.config.js': js` - let MiniCssExtractPlugin = require('mini-css-extract-plugin') - - module.exports = { - output: { - clean: true, - }, - plugins: [new MiniCssExtractPlugin()], - module: { - rules: [ - { - test: /.css$/i, - use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader'], - }, - ], - }, - } - `, - 'src/index.js': js`import './index.css'`, - 'src/index.html': html` -
- `, - 'src/index.css': css` - @import 'tailwindcss/theme'; - @import 'tailwindcss/utilities'; - `, - 'src/unrelated.module.css': css` - .module { - color: var(--color-blue-500); - } - `, - }, - }, - async ({ fs, spawn, exec, expect }) => { - // Generate the initial build so output CSS files exist on disk - await exec('pnpm webpack --mode=development') - - // NOTE: We are writing to an output CSS file which is not being ignored by - // `.gitignore` nor marked with `@source not`. This should not result in an - // infinite loop. - let process = await spawn('pnpm webpack --mode=development --watch') - await process.onStdout((m) => m.includes('compiled successfully in')) - - expect(await fs.dumpFiles('./dist/*.css')).toMatchInlineSnapshot(` - " - --- ./dist/main.css --- - :root, :host { - --color-blue-500: oklch(62.3% 0.214 259.815); - } - .flex { - display: flex; - } - " - `) - - await fs.write( - 'src/unrelated.module.css', - css` - .module { - color: var(--color-blue-500); - background-color: var(--color-red-500); - } - `, - ) - await process.onStdout((m) => m.includes('compiled successfully in')) - - expect(await fs.dumpFiles('./dist/*.css')).toMatchInlineSnapshot(` - " - --- ./dist/main.css --- - :root, :host { - --color-red-500: oklch(63.7% 0.237 25.331); - --color-blue-500: oklch(62.3% 0.214 259.815); - } - .flex { - display: flex; - } - " - `) - }, -) diff --git a/integrations/webpack/loader.test.ts b/integrations/webpack/loader.test.ts deleted file mode 100644 index 9c3d870af..000000000 --- a/integrations/webpack/loader.test.ts +++ /dev/null @@ -1,495 +0,0 @@ -import { css, html, js, json, test } from '../utils' - -test( - '@tailwindcss/webpack loader (build)', - { - fs: { - 'package.json': json` - { - "main": "./src/index.js", - "browser": "./src/index.js", - "dependencies": { - "css-loader": "^6", - "webpack": "^5", - "webpack-cli": "^5", - "mini-css-extract-plugin": "^2", - "tailwindcss": "workspace:^", - "@tailwindcss/webpack": "workspace:^" - } - } - `, - 'webpack.config.js': js` - let MiniCssExtractPlugin = require('mini-css-extract-plugin') - - module.exports = { - output: { - clean: true, - }, - plugins: [new MiniCssExtractPlugin()], - module: { - rules: [ - { - test: /.css$/i, - use: [MiniCssExtractPlugin.loader, 'css-loader', '@tailwindcss/webpack'], - }, - ], - }, - } - `, - 'src/index.js': js`import './index.css'`, - 'src/index.html': html` -
- `, - 'src/index.css': css` - @import 'tailwindcss/theme'; - @import 'tailwindcss/utilities'; - `, - }, - }, - async ({ fs, exec, expect }) => { - await exec('pnpm webpack --mode=development') - - expect(await fs.dumpFiles('./dist/*.css')).toMatchInlineSnapshot(` - " - --- ./dist/main.css --- - .flex { - display: flex; - } - " - `) - }, -) - -test( - '@tailwindcss/webpack loader (watch)', - { - fs: { - 'package.json': json` - { - "main": "./src/index.js", - "browser": "./src/index.js", - "dependencies": { - "css-loader": "^6", - "webpack": "^5", - "webpack-cli": "^5", - "mini-css-extract-plugin": "^2", - "tailwindcss": "workspace:^", - "@tailwindcss/webpack": "workspace:^" - } - } - `, - 'webpack.config.js': js` - let MiniCssExtractPlugin = require('mini-css-extract-plugin') - - module.exports = { - output: { - clean: true, - }, - plugins: [new MiniCssExtractPlugin()], - module: { - rules: [ - { - test: /.css$/i, - use: [MiniCssExtractPlugin.loader, 'css-loader', '@tailwindcss/webpack'], - }, - ], - }, - } - `, - 'src/index.js': js`import './index.css'`, - 'src/index.html': html` -
- `, - 'src/index.css': css` - @import 'tailwindcss/theme'; - @import 'tailwindcss/utilities'; - `, - }, - }, - async ({ fs, spawn, exec, expect }) => { - // Generate the initial build so output CSS files exist on disk - await exec('pnpm webpack --mode=development') - - let process = await spawn('pnpm webpack --mode=development --watch') - await process.onStdout((m) => m.includes('compiled successfully in')) - - expect(await fs.dumpFiles('./dist/*.css')).toMatchInlineSnapshot(` - " - --- ./dist/main.css --- - .flex { - display: flex; - } - " - `) - - // Add a new Tailwind class to the HTML file - await fs.write('src/index.html', html` -
- `) - await process.onStdout((m) => m.includes('compiled successfully in')) - - expect(await fs.dumpFiles('./dist/*.css')).toMatchInlineSnapshot(` - " - --- ./dist/main.css --- - .flex { - display: flex; - } - .underline { - text-decoration-line: underline; - } - " - `) - }, -) - -test( - '@tailwindcss/webpack loader with @apply', - { - fs: { - 'package.json': json` - { - "main": "./src/index.js", - "browser": "./src/index.js", - "dependencies": { - "css-loader": "^6", - "webpack": "^5", - "webpack-cli": "^5", - "mini-css-extract-plugin": "^2", - "tailwindcss": "workspace:^", - "@tailwindcss/webpack": "workspace:^" - } - } - `, - 'webpack.config.js': js` - let MiniCssExtractPlugin = require('mini-css-extract-plugin') - - module.exports = { - output: { - clean: true, - }, - plugins: [new MiniCssExtractPlugin()], - module: { - rules: [ - { - test: /.css$/i, - use: [MiniCssExtractPlugin.loader, 'css-loader', '@tailwindcss/webpack'], - }, - ], - }, - } - `, - 'src/index.js': js`import './index.css'`, - 'src/index.css': css` - @import 'tailwindcss/theme'; - - .btn { - @apply flex items-center px-4 py-2 rounded-md; - } - `, - }, - }, - async ({ fs, exec, expect }) => { - await exec('pnpm webpack --mode=development') - - expect(await fs.dumpFiles('./dist/*.css')).toMatchInlineSnapshot(` - " - --- ./dist/main.css --- - :root, :host { - --spacing: 0.25rem; - --radius-md: 0.375rem; - } - .btn { - display: flex; - align-items: center; - border-radius: var(--radius-md); - padding-inline: calc(var(--spacing) * 4); - padding-block: calc(var(--spacing) * 2); - } - " - `) - }, -) - -test( - '@tailwindcss/webpack loader with optimization', - { - fs: { - 'package.json': json` - { - "main": "./src/index.js", - "browser": "./src/index.js", - "dependencies": { - "css-loader": "^6", - "webpack": "^5", - "webpack-cli": "^5", - "mini-css-extract-plugin": "^2", - "tailwindcss": "workspace:^", - "@tailwindcss/webpack": "workspace:^" - } - } - `, - 'webpack.config.js': js` - let MiniCssExtractPlugin = require('mini-css-extract-plugin') - - module.exports = { - output: { - clean: true, - }, - plugins: [new MiniCssExtractPlugin()], - module: { - rules: [ - { - test: /.css$/i, - use: [ - MiniCssExtractPlugin.loader, - 'css-loader', - { - loader: '@tailwindcss/webpack', - options: { - optimize: true, - }, - }, - ], - }, - ], - }, - } - `, - 'src/index.js': js`import './index.css'`, - 'src/index.html': html` -
- `, - 'src/index.css': css` - @import 'tailwindcss/theme'; - @import 'tailwindcss/utilities'; - `, - }, - }, - async ({ fs, exec, expect }) => { - await exec('pnpm webpack --mode=development') - - expect(await fs.dumpFiles('./dist/*.css')).toMatchInlineSnapshot(` - " - --- ./dist/main.css --- - .flex{display:flex} - " - `) - }, -) - -test( - '@tailwindcss/webpack loader with CSS @import', - { - fs: { - 'package.json': json` - { - "main": "./src/index.js", - "browser": "./src/index.js", - "dependencies": { - "css-loader": "^6", - "webpack": "^5", - "webpack-cli": "^5", - "mini-css-extract-plugin": "^2", - "tailwindcss": "workspace:^", - "@tailwindcss/webpack": "workspace:^" - } - } - `, - 'webpack.config.js': js` - let MiniCssExtractPlugin = require('mini-css-extract-plugin') - - module.exports = { - output: { - clean: true, - }, - plugins: [new MiniCssExtractPlugin()], - module: { - rules: [ - { - test: /.css$/i, - use: [MiniCssExtractPlugin.loader, 'css-loader', '@tailwindcss/webpack'], - }, - ], - }, - } - `, - 'src/index.js': js`import './index.css'`, - 'src/index.html': html` -
- `, - 'src/index.css': css` - @import './custom.css'; - @import 'tailwindcss/theme'; - @import 'tailwindcss/utilities'; - `, - 'src/custom.css': css` - /**/ - @utility custom-util { - color: var(--color-red-500); - } - `, - }, - }, - async ({ fs, exec, expect }) => { - await exec('pnpm webpack --mode=development') - - expect(await fs.dumpFiles('./dist/*.css')).toMatchInlineSnapshot(` - " - --- ./dist/main.css --- - :root, :host { - --color-red-500: oklch(63.7% 0.237 25.331); - } - .flex { - display: flex; - } - .custom-util { - color: var(--color-red-500); - } - " - `) - }, -) - -test( - '@tailwindcss/webpack loader with @plugin', - { - fs: { - 'package.json': json` - { - "main": "./src/index.js", - "browser": "./src/index.js", - "dependencies": { - "css-loader": "^6", - "webpack": "^5", - "webpack-cli": "^5", - "mini-css-extract-plugin": "^2", - "tailwindcss": "workspace:^", - "@tailwindcss/webpack": "workspace:^" - } - } - `, - 'webpack.config.js': js` - let MiniCssExtractPlugin = require('mini-css-extract-plugin') - - module.exports = { - output: { - clean: true, - }, - plugins: [new MiniCssExtractPlugin()], - module: { - rules: [ - { - test: /.css$/i, - use: [MiniCssExtractPlugin.loader, 'css-loader', '@tailwindcss/webpack'], - }, - ], - }, - } - `, - 'src/index.js': js`import './index.css'`, - 'src/index.html': html` -
- `, - 'src/index.css': css` - @import 'tailwindcss/utilities'; - @plugin './plugin.js'; - `, - 'src/plugin.js': js` - export default function ({ addUtilities }) { - addUtilities({ - '.custom-underline': { - 'border-bottom': '1px solid green', - }, - }) - } - `, - }, - }, - async ({ fs, exec, expect }) => { - await exec('pnpm webpack --mode=development') - - expect(await fs.dumpFiles('./dist/*.css')).toMatchInlineSnapshot(` - " - --- ./dist/main.css --- - .custom-underline { - border-bottom: 1px solid green; - } - " - `) - }, -) - -test( - '@tailwindcss/webpack loader isolates cache by resource including query', - { - fs: { - 'package.json': json` - { - "main": "./src/index.js", - "browser": "./src/index.js", - "dependencies": { - "css-loader": "^6", - "webpack": "^5", - "webpack-cli": "^5", - "mini-css-extract-plugin": "^2", - "tailwindcss": "workspace:^", - "@tailwindcss/webpack": "workspace:^" - } - } - `, - 'webpack.config.js': js` - let MiniCssExtractPlugin = require('mini-css-extract-plugin') - let path = require('node:path') - - module.exports = { - mode: 'development', - entry: { - a: './src/a.js', - b: './src/b.js', - }, - output: { - clean: true, - }, - plugins: [new MiniCssExtractPlugin()], - module: { - rules: [ - { - test: /.css$/i, - use: [ - MiniCssExtractPlugin.loader, - 'css-loader', - '@tailwindcss/webpack', - path.resolve(__dirname, 'query-loader.js'), - ], - }, - ], - }, - } - `, - 'query-loader.js': js` - module.exports = function (source) { - if (this.resourceQuery.includes('a')) { - return '@import "tailwindcss/utilities"; @utility only-a {color: var(--color-red-500);}' - } - - if (this.resourceQuery.includes('b')) { - return '@import "tailwindcss/utilities"; @utility only-b {color: var(--color-blue-500);}' - } - - return source - } - `, - 'src/a.js': js`import './index.css?a'`, - 'src/b.js': js`import './index.css?b'`, - 'src/index.css': css``, - }, - }, - async ({ fs, exec }) => { - await exec('pnpm webpack --mode=development') - - await fs.expectFileToContain('dist/a.css', ['only-a', '--color-red-500']) - await fs.expectFileToContain('dist/b.css', ['only-b', '--color-blue-500']) - await fs.expectFileNotToContain('dist/a.css', ['only-b', '--color-blue-500']) - await fs.expectFileNotToContain('dist/b.css', ['only-a', '--color-red-500']) - }, -) diff --git a/package.json b/package.json index 7d41a469e..75befd109 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "dev": "turbo dev --filter=!./playgrounds/*", "test": "cargo test && vitest run --hideSkippedTests", "test:integrations": "vitest --root=./integrations", - "test:ui": "pnpm run --filter=tailwindcss test:ui && pnpm run --filter=@tailwindcss/browser test:ui", + "test:ui": "pnpm run --filter=tailwindcss test:ui", "tdd": "vitest --hideSkippedTests", "bench": "vitest bench", "version-packages": "node ./scripts/version-packages.mjs", @@ -48,17 +48,23 @@ }, "license": "MIT", "devDependencies": { - "@playwright/test": "^1.62.1", + "@playwright/test": "^1.49.0", "@types/node": "catalog:", - "postcss": "catalog:", - "postcss-import": "^16.1.1", - "prettier": "catalog:", - "prettier-plugin-embed": "^0.5.1", - "prettier-plugin-organize-imports": "^4.3.0", - "tsup": "^8.5.1", - "turbo": "^2.10.8", - "typescript": "^5.9.3", - "vitest": "^4.1.10" + "postcss": "8.4.49", + "postcss-import": "^16.1.0", + "prettier": "^3.3.3", + "prettier-plugin-embed": "^0.4.15", + "prettier-plugin-organize-imports": "^4.0.0", + "tsup": "^8.2.4", + "turbo": "^2.2.3", + "typescript": "^5.5.4", + "vitest": "^2.0.5" }, - "packageManager": "pnpm@11.9.0" + "packageManager": "pnpm@9.6.0", + "pnpm": { + "patchedDependencies": { + "lightningcss@1.26.0": "patches/lightningcss@1.26.0.patch", + "@parcel/watcher@2.5.0": "patches/@parcel__watcher@2.5.0.patch" + } + } } diff --git a/packages/@tailwindcss-browser/README.md b/packages/@tailwindcss-browser/README.md deleted file mode 100644 index 5f532607d..000000000 --- a/packages/@tailwindcss-browser/README.md +++ /dev/null @@ -1,36 +0,0 @@ -

- - - - - Tailwind CSS - - -

- -

- A utility-first CSS framework for rapidly building custom user interfaces. -

- -

- Build Status - Total Downloads - Latest Release - License -

- ---- - -## Documentation - -For full documentation, visit [tailwindcss.com](https://tailwindcss.com). - -## Community - -For help, discussion about best practices, or feature ideas: - -[Discuss Tailwind CSS on GitHub](https://github.com/tailwindlabs/tailwindcss/discussions) - -## Contributing - -If you're interested in contributing to Tailwind CSS, please read our [contributing docs](https://github.com/tailwindlabs/tailwindcss/blob/main/.github/CONTRIBUTING.md) **before submitting a pull request**. diff --git a/packages/@tailwindcss-browser/package.json b/packages/@tailwindcss-browser/package.json deleted file mode 100644 index 70af78c1e..000000000 --- a/packages/@tailwindcss-browser/package.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "name": "@tailwindcss/browser", - "version": "4.3.3", - "description": "A utility-first CSS framework for rapidly building custom user interfaces.", - "license": "MIT", - "main": "./dist/index.global.js", - "browser": "./dist/index.global.js", - "repository": { - "type": "git", - "url": "https://github.com/tailwindlabs/tailwindcss.git", - "directory": "packages/@tailwindcss-browser" - }, - "bugs": "https://github.com/tailwindlabs/tailwindcss/issues", - "homepage": "https://tailwindcss.com", - "scripts": { - "lint": "tsc --noEmit", - "build": "tsup-node", - "dev": "pnpm run build -- --watch", - "test:ui": "playwright test" - }, - "exports": { - ".": "./dist/index.global.js", - "./package.json": "./package.json" - }, - "files": [ - "dist" - ], - "publishConfig": { - "provenance": true, - "access": "public" - }, - "devDependencies": { - "h3": "^1.15.11", - "listhen": "^1.10.1", - "tailwindcss": "workspace:*" - } -} diff --git a/packages/@tailwindcss-browser/playwright.config.ts b/packages/@tailwindcss-browser/playwright.config.ts deleted file mode 100644 index c6059dd82..000000000 --- a/packages/@tailwindcss-browser/playwright.config.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { defineConfig, devices } from '@playwright/test' - -/** - * See https://playwright.dev/docs/test-configuration. - */ -export default defineConfig({ - testDir: './tests', - /* Run tests in files in parallel */ - fullyParallel: true, - /* Fail the build on CI if you accidentally left test.only in the source code. */ - forbidOnly: !!process.env.CI, - /* Retry on CI only */ - retries: process.env.CI ? 2 : 0, - /* Opt out of parallel tests on CI. */ - workers: process.env.CI ? 1 : undefined, - /* Reporter to use. See https://playwright.dev/docs/test-reporters */ - reporter: [['html', { open: 'never' }]], - /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ - use: { - /* Base URL to use in actions like `await page.goto('/')`. */ - // baseURL: 'http://127.0.0.1:3000', - - /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ - trace: 'on-first-retry', - }, - - /* Configure projects for major browsers */ - projects: [ - { - name: 'chromium', - use: { ...devices['Desktop Chrome'] }, - }, - // Playwright 1.60's Windows WebKit worker hangs on shutdown after all tests - // pass, causing CI to fail with a worker force-kill error. - ...(process.platform === 'win32' - ? [] - : [{ name: 'webkit', use: { ...devices['Desktop Safari'] } }]), - { - name: 'firefox', - use: { - ...devices['Desktop Firefox'], - // https://playwright.dev/docs/test-use-options#more-browser-and-context-options - launchOptions: { - // https://playwright.dev/docs/api/class-browsertype#browser-type-launch-option-firefox-user-prefs - firefoxUserPrefs: { - // By default, headless Firefox runs as though no pointers - // capabilities are available. - // https://github.com/microsoft/playwright/issues/7769#issuecomment-966098074 - // - // This impacts our `hover` variant implementation which uses an - // '(hover: hover)' media query to determine if hover is available. - // - // Available values for pointer capabilities: - // NO_POINTER = 0x00; - // COARSE_POINTER = 0x01; - // FINE_POINTER = 0x02; - // HOVER_CAPABLE_POINTER = 0x04; - // - // Setting to 0x02 | 0x04 says the system supports a mouse - 'ui.primaryPointerCapabilities': 0x02 | 0x04, - 'ui.allPointerCapabilities': 0x02 | 0x04, - }, - }, - }, - }, - ], -}) diff --git a/packages/@tailwindcss-browser/src/assets.ts b/packages/@tailwindcss-browser/src/assets.ts deleted file mode 100644 index e72d47658..000000000 --- a/packages/@tailwindcss-browser/src/assets.ts +++ /dev/null @@ -1,11 +0,0 @@ -import index from 'tailwindcss/index.css' -import preflight from 'tailwindcss/preflight.css' -import theme from 'tailwindcss/theme.css' -import utilities from 'tailwindcss/utilities.css' - -export const css = { - index, - preflight, - theme, - utilities, -} diff --git a/packages/@tailwindcss-browser/src/index.ts b/packages/@tailwindcss-browser/src/index.ts deleted file mode 100644 index 49c7e4675..000000000 --- a/packages/@tailwindcss-browser/src/index.ts +++ /dev/null @@ -1,294 +0,0 @@ -import * as tailwindcss from 'tailwindcss' -import * as assets from './assets' -import { Instrumentation } from './instrumentation' - -/** - * The type used by ` - `, - body: html`
`, - }) - - await expect(page.locator('[data-test]')).toHaveCSS('background-color', 'rgb(255, 0, 0)') - - await page.evaluate(() => { - document.querySelector('[data-css]')!.textContent = ` - .foo { - @apply bg-blue; - } - ` - }) - - await expect(page.locator('[data-test]')).toHaveCSS('background-color', 'rgb(0, 0, 255)') -}) - -test('changes to `@theme`', async ({ page }) => { - await server.render({ - page, - head: html` - - `, - body: html`
`, - }) - - await expect(page.locator('[data-test]')).toHaveCSS('background-color', 'rgb(255, 0, 0)') - - await page.evaluate(() => { - document.querySelector('[data-css]')!.textContent = ` - @theme { - --color-primary: #0000ff; - } - ` - }) - - await expect(page.locator('[data-test]')).toHaveCSS('background-color', 'rgb(0, 0, 255)') -}) - -test('no classes', async ({ page }) => { - await server.render({ - page, - body: html`
test
`, - }) - - await expect(page.locator('body')).toHaveCSS('margin', '0px') -}) - -test('html classes', async ({ page }) => { - await server.render({ - page, - htmlClasses: 'h-4', - }) - - await expect(page.locator('html')).toHaveCSS('height', '16px') -}) - -async function createServer() { - const { createApp, createRouter, defineEventHandler, toNodeListener } = await import('h3') - const { listen } = await import('listhen') - - interface PageOptions { - page: Page - head?: string - body?: string - htmlClasses?: string - } - - async function render({ page, htmlClasses, head, body }: PageOptions) { - let content = html` - - - - - - - Document - - - ${head ?? ''} - - - ${body ?? ''} - - - ` - - router.get( - '/', - defineEventHandler(() => content), - ) - - await page.goto(server.url) - } - - const app = createApp() - const router = createRouter() - - router.get( - '/tailwindcss.js', - defineEventHandler(() => readFile(require.resolve('@tailwindcss/browser'))), - ) - - app.use(router) - - let workerIndex = Number(process.env.TEST_WORKER_INDEX ?? 0) - - let listener = await listen(toNodeListener(app), { - port: 3000 + workerIndex, - showURL: false, - open: false, - }) - - return { - app, - url: listener.url, - close: listener.close, - render, - } -} diff --git a/packages/@tailwindcss-browser/tsconfig.json b/packages/@tailwindcss-browser/tsconfig.json deleted file mode 100644 index 8ea040daf..000000000 --- a/packages/@tailwindcss-browser/tsconfig.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "extends": "../tsconfig.base.json", - "compilerOptions": { - "lib": ["es2022", "esnext.disposable", "dom", "dom.iterable"], - }, -} diff --git a/packages/@tailwindcss-browser/tsup.config.ts b/packages/@tailwindcss-browser/tsup.config.ts deleted file mode 100644 index 10a73f2b7..000000000 --- a/packages/@tailwindcss-browser/tsup.config.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { defineConfig } from 'tsup' - -export default defineConfig({ - format: ['iife'], - clean: true, - minify: true, - entry: ['src/index.ts'], - noExternal: [/.*/], - loader: { - '.css': 'text', - }, - define: { - 'process.env.NODE_ENV': '"production"', - 'process.env.FEATURES_ENV': '"stable"', - }, - esbuildPlugins: [ - { - name: 'patch-intellisense-apis', - setup(build) { - build.onLoad({ filter: /intellisense.ts$/ }, () => { - return { - contents: ` - export function getClassList() { return [] } - export function getVariants() { return [] } - export function canonicalizeCandidates() { return [] } - `, - } - }) - }, - }, - ], -}) diff --git a/packages/@tailwindcss-browser/vitest.config.mts b/packages/@tailwindcss-browser/vitest.config.mts deleted file mode 100644 index f6f91227d..000000000 --- a/packages/@tailwindcss-browser/vitest.config.mts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from 'vitest/config' - -export default defineConfig({ - test: { - exclude: ['**/*.spec.?(c|m)[jt]s?(x)', '**/node_modules/**'], - }, -}) diff --git a/packages/@tailwindcss-cli/README.md b/packages/@tailwindcss-cli/README.md index 5f532607d..95ec9d87d 100644 --- a/packages/@tailwindcss-cli/README.md +++ b/packages/@tailwindcss-cli/README.md @@ -13,10 +13,10 @@

- Build Status + Build Status Total Downloads - Latest Release - License + Latest Release + License

--- @@ -27,10 +27,14 @@ For full documentation, visit [tailwindcss.com](https://tailwindcss.com). ## Community -For help, discussion about best practices, or feature ideas: +For help, discussion about best practices, or any other conversation that would benefit from being searchable: -[Discuss Tailwind CSS on GitHub](https://github.com/tailwindlabs/tailwindcss/discussions) +[Discuss Tailwind CSS on GitHub](https://github.com/tailwindcss/tailwindcss/discussions) + +For chatting with others using the framework: + +[Join the Tailwind CSS Discord Server](https://discord.gg/7NF8GNe) ## Contributing -If you're interested in contributing to Tailwind CSS, please read our [contributing docs](https://github.com/tailwindlabs/tailwindcss/blob/main/.github/CONTRIBUTING.md) **before submitting a pull request**. +If you're interested in contributing to Tailwind CSS, please read our [contributing docs](https://github.com/tailwindcss/tailwindcss/blob/next/.github/CONTRIBUTING.md) **before submitting a pull request**. diff --git a/packages/@tailwindcss-cli/package.json b/packages/@tailwindcss-cli/package.json index 7fa5b5500..4a71f0724 100644 --- a/packages/@tailwindcss-cli/package.json +++ b/packages/@tailwindcss-cli/package.json @@ -1,6 +1,6 @@ { "name": "@tailwindcss/cli", - "version": "4.3.3", + "version": "4.0.0-beta.7", "description": "A utility-first CSS framework for rapidly building custom user interfaces.", "license": "MIT", "repository": { @@ -29,10 +29,11 @@ "access": "public" }, "dependencies": { - "@parcel/watcher": "catalog:", - "@tailwindcss/node": "workspace:*", - "@tailwindcss/oxide": "workspace:*", - "enhanced-resolve": "catalog:", + "@parcel/watcher": "^2.5.0", + "@tailwindcss/node": "workspace:^", + "@tailwindcss/oxide": "workspace:^", + "enhanced-resolve": "^5.17.1", + "lightningcss": "catalog:", "mri": "^1.2.0", "picocolors": "^1.1.1", "tailwindcss": "workspace:*" diff --git a/packages/@tailwindcss-cli/src/commands/build/index.ts b/packages/@tailwindcss-cli/src/commands/build/index.ts index ffef2ae8b..bf1066e90 100644 --- a/packages/@tailwindcss-cli/src/commands/build/index.ts +++ b/packages/@tailwindcss-cli/src/commands/build/index.ts @@ -1,13 +1,8 @@ -import { - compile, - env, - Instrumentation, - optimize, - toSourceMap, - type SourceMap, -} from '@tailwindcss/node' +import watcher from '@parcel/watcher' +import { compile, env, Instrumentation } from '@tailwindcss/node' import { clearRequireCache } from '@tailwindcss/node/require-cache' import { Scanner, type ChangedContent } from '@tailwindcss/oxide' +import { Features, transform } from 'lightningcss' import { existsSync, type Stats } from 'node:fs' import fs from 'node:fs/promises' import path from 'node:path' @@ -20,13 +15,11 @@ import { highlight, println, relative, - wordWrap, } from '../../utils/renderer' import { drainStdin, outputFile } from './utils' const css = String.raw const DEBUG = env.DEBUG -const DEFAULT_POLL_INTERVAL_MS = 250 export function options() { return { @@ -39,20 +32,11 @@ export function options() { type: 'string', description: 'Output file', alias: '-o', - default: '-', }, '--watch': { type: 'boolean | string', - description: - 'Watch for changes and rebuild as needed, and use `always` to keep watching when stdin is closed', + description: 'Watch for changes and rebuild as needed', alias: '-w', - values: ['always'], - }, - '--poll': { - type: 'boolean | number', - description: 'Use polling instead of filesystem events when watching', - default: false, - values: ['ms'], }, '--minify': { type: 'boolean', @@ -68,73 +52,28 @@ export function options() { description: 'The current working directory', default: '.', }, - '--map': { - type: 'boolean | string', - description: 'Generate a source map', - default: false, - }, - '--silent': { - type: 'boolean', - description: 'Suppress non-error output', - }, } satisfies Arg } -function formatError(error: unknown): string { - let seen = new Set() // Track seen errors to prevent circular errors - function render(err: unknown, depth: number): string[] { - let indent = ' '.repeat(depth) - let width = (process.stderr.columns ?? Infinity) - 2 * (depth + 1) - - let output = [ - `${indent}${red(depth === 0 ? 'Error:' : 'Caused by:')}`, - `${indent}${dim('\u250C')}`, - ] - - for (let line of `${err}`.split('\n')) { - let wrapped = wordWrap(line, width) - if (wrapped.length === 0) wrapped = [''] - for (let chunk of wrapped) { - output.push(`${indent}${dim('\u2502')} ${chunk}`) - } - } - - output.push(`${indent}${dim('\u2514')}`) - - if (typeof err === 'object' && err !== null && 'cause' in err && err.cause != null) { - if (!seen.add(err).has(err.cause)) { - output.push(...render(err.cause, depth + 1)) - } - } - - return output - } - - return render(error, 0).join('\n') -} - async function handleError(fn: () => T): Promise { try { return await fn() } catch (err) { - eprintln(formatError(err)) + if (err instanceof Error) { + eprintln(err.toString()) + } process.exit(1) } } export async function handle(args: Result>) { - if (!args['--silent']) eprintln(header()) - if (!args['--silent']) eprintln() - using I = new Instrumentation() DEBUG && I.start('[@tailwindcss/cli] (initial build)') let base = path.resolve(args['--cwd']) - // Resolve the output as an absolute path. If the output is a `-`, then we - // don't need to resolve it because this is a flag to indicate that we want to - // use `stdout` instead. - if (args['--output'] && args['--output'] !== '-') { + // Resolve the output as an absolute path. + if (args['--output']) { args['--output'] = path.resolve(base, args['--output']) } @@ -146,43 +85,13 @@ export async function handle(args: Result>) { // Ensure the provided `--input` exists. if (!existsSync(args['--input'])) { + eprintln(header()) + eprintln() eprintln(`Specified input file ${highlight(relative(args['--input']))} does not exist.`) process.exit(1) } } - // Check if the input and output file paths are identical, otherwise return an - // error to the user. - if (args['--input'] === args['--output'] && args['--input'] !== '-') { - eprintln( - `Specified input file ${highlight(relative(args['--input']))} and output file ${highlight(relative(args['--output']))} are identical.`, - ) - process.exit(1) - } - - // If the user passes `{bin} build --map -` then this likely means they want to output the map inline - // this is the default behavior of `{bin build} --map` to inform the user of that - if (args['--map'] === '-') { - eprintln(`Use --map without a value to inline the source map.`) - process.exit(1) - } - - if (args['--poll'] === undefined) { - eprintln(`Use --poll with a non-zero value in milliseconds.`) - process.exit(1) - } - let pollInterval = args['--poll'] === true ? DEFAULT_POLL_INTERVAL_MS : args['--poll'] - if (pollInterval !== false && pollInterval <= 0) { - eprintln(`Specified polling interval must be a positive number.`) - process.exit(1) - } - - // Resolve the map as an absolute path. If the output is true then we - // don't need to resolve it because it'll be an inline source map - if (args['--map'] && args['--map'] !== true) { - args['--map'] = path.resolve(base, args['--map']) - } - let start = process.hrtime.bigint() let input = args['--input'] @@ -196,75 +105,36 @@ export async function handle(args: Result>) { let previous = { css: '', optimizedCss: '', - output: null as string | null, } - async function write( - css: string, - map: SourceMap | null, - args: Result>, - I: Instrumentation, - ) { + async function write(css: string, args: Result>, I: Instrumentation) { let output = css // Optimize the output if (args['--minify'] || args['--optimize']) { if (css !== previous.css) { DEBUG && I.start('Optimize CSS') - let optimized = optimize(css, { + let optimizedCss = optimizeCss(css, { file: args['--input'] ?? 'input.css', minify: args['--minify'] ?? false, - map: map?.raw ?? undefined, }) DEBUG && I.end('Optimize CSS') previous.css = css - previous.optimizedCss = optimized.code - if (optimized.map) { - map = toSourceMap(optimized.map) - } - output = optimized.code + previous.optimizedCss = optimizedCss + output = optimizedCss } else { output = previous.optimizedCss } } // Write the output - if (map) { - // Inline the source map - if (args['--map'] === true) { - output += `\n` - output += map.inline - } else if (typeof args['--map'] === 'string') { - let basePath = - args['--output'] && args['--output'] !== '-' - ? path.dirname(path.resolve(args['--output'])) - : process.cwd() - - let mapPath = path.resolve(args['--map']) - - let relativePath = path.relative(basePath, mapPath) - - output += `\n` - output += map.comment(relativePath) - - DEBUG && I.start('Write source map') - await outputFile(args['--map'], map.raw) - DEBUG && I.end('Write source map') - } - } - - let didChange = output !== previous.output - DEBUG && I.start('Write output') - if (args['--output'] && args['--output'] !== '-') { + if (args['--output']) { await outputFile(args['--output'], output) - } else if (didChange) { + } else { println(output) } DEBUG && I.end('Write output') - - previous.output = output - return didChange } let inputFilePath = @@ -273,12 +143,10 @@ export async function handle(args: Result>) { let inputBasePath = inputFilePath ? path.dirname(inputFilePath) : process.cwd() let fullRebuildPaths: string[] = inputFilePath ? [inputFilePath] : [] - let backupRebuildPaths = fullRebuildPaths async function createCompiler(css: string, I: Instrumentation) { DEBUG && I.start('Setup compiler') let compiler = await compile(css, { - from: args['--output'] ? (inputFilePath ?? 'stdin.css') : undefined, base: inputBasePath, onDependency(path) { fullRebuildPaths.push(path) @@ -293,30 +161,12 @@ export async function handle(args: Result>) { // No root specified, use the base directory if (compiler.root === null) { - return [{ base, pattern: '**/*', negated: false }] + return [{ base, pattern: '**/*' }] } // Use the specified root - return [{ ...compiler.root, negated: false }] - })().concat(compiler.sources) - - // Do not scan the current executable. Otherwise when using the standalone - // CLI, if the CLI lives in the current repo we would be scanning that file. - // - // This is also immune against renames of the executable file. - sources.push({ - base: path.dirname(process.execPath), - pattern: path.basename(process.execPath), - negated: true, - }) - - if (inputFilePath !== null) { - sources.push({ - base: path.dirname(inputFilePath), - pattern: path.basename(inputFilePath), - negated: false, - }) - } + return [compiler.root] + })().concat(compiler.globs) let scanner = new Scanner({ sources }) DEBUG && I.end('Setup compiler') @@ -325,16 +175,12 @@ export async function handle(args: Result>) { } let [compiler, scanner] = await handleError(() => createCompiler(input, I)) - let cleanupWatchers: (() => Promise)[] = [] // Watch for changes - if (args['--watch'] && pollInterval === false) { - // Ensure the file watcher can be loaded before setting up any watchers, - // such that we can present a helpful error message if needed. - await handleError(() => loadWatcher()) - - cleanupWatchers.push( - await createWatchers(await watchDirectories(scanner), async function handle(files) { + if (args['--watch']) { + let cleanupWatchers = await createWatchers( + watchDirectories(scanner), + async function handle(files) { try { // If the only change happened to the output file, then we don't want to // trigger a rebuild because that will result in an infinite loop. @@ -346,15 +192,35 @@ export async function handle(args: Result>) { // Re-compile the input let start = process.hrtime.bigint() + let changedFiles: ChangedContent[] = [] + let rebuildStrategy: 'incremental' | 'full' = 'incremental' + let resolvedFullRebuildPaths = fullRebuildPaths - let rebuildStrategy = getRebuildStrategy(files, resolvedFullRebuildPaths) + + for (let file of files) { + // If one of the changed files is related to the input CSS or JS + // config/plugin files, then we need to do a full rebuild because + // the theme might have changed. + if (resolvedFullRebuildPaths.includes(file)) { + rebuildStrategy = 'full' + + // No need to check the rest of the events, because we already know we + // need to do a full rebuild. + break + } + + // Track new and updated files for incremental rebuilds. + changedFiles.push({ + file, + extension: path.extname(file).slice(1), + } satisfies ChangedContent) + } // Track the compiled CSS let compiledCss = '' - let compiledMap: SourceMap | null = null // Scan the entire `base` directory for full rebuilds. - if (rebuildStrategy.kind === 'full') { + if (rebuildStrategy === 'full') { // Read the new `input`. let input = args['--input'] ? args['--input'] === '-' @@ -364,23 +230,11 @@ export async function handle(args: Result>) { @import 'tailwindcss'; ` clearRequireCache(resolvedFullRebuildPaths) - - // Track current rebuild paths in case something goes wrong when - // performing a full rebuild. - backupRebuildPaths = fullRebuildPaths.slice() - - // The `inputFilePath`, if provided, will be the only known full - // rebuild path before the compiler is re-created. fullRebuildPaths = inputFilePath ? [inputFilePath] : [] // Create a new compiler, given the new `input` ;[compiler, scanner] = await createCompiler(input, I) - // Successfully created a new compiler, so the `fullRebuildPaths` - // will be updated. If other errors occur, we should be able to - // restore the paths unconditionally. - backupRebuildPaths = fullRebuildPaths.slice() - // Scan the directory for candidates DEBUG && I.start('Scan for candidates') let candidates = scanner.scan() @@ -388,107 +242,60 @@ export async function handle(args: Result>) { // Setup new watchers DEBUG && I.start('Setup new watchers') - let newCleanupFunction = await createWatchers(await watchDirectories(scanner), handle) + let newCleanupWatchers = await createWatchers(watchDirectories(scanner), handle) DEBUG && I.end('Setup new watchers') // Clear old watchers DEBUG && I.start('Cleanup old watchers') - await Promise.all(cleanupWatchers.splice(0).map((cleanup) => cleanup())) + await cleanupWatchers() DEBUG && I.end('Cleanup old watchers') - cleanupWatchers.push(newCleanupFunction) + cleanupWatchers = newCleanupWatchers // Re-compile the CSS DEBUG && I.start('Build CSS') compiledCss = compiler.build(candidates) DEBUG && I.end('Build CSS') - - if (args['--map']) { - DEBUG && I.start('Build Source Map') - compiledMap = toSourceMap(compiler.buildSourceMap()) - DEBUG && I.end('Build Source Map') - } } // Scan changed files only for incremental rebuilds. - else if (rebuildStrategy.kind === 'incremental') { + else if (rebuildStrategy === 'incremental') { DEBUG && I.start('Scan for candidates') - let newCandidates = scanner.scanFiles(rebuildStrategy.changedFiles) + let newCandidates = scanner.scanFiles(changedFiles) DEBUG && I.end('Scan for candidates') // No new candidates found which means we don't need to write to // disk, and can return early. if (newCandidates.length <= 0) { let end = process.hrtime.bigint() - if (!args['--silent']) eprintln(`Done in ${formatDuration(end - start)}`) + eprintln(`Done in ${formatDuration(end - start)}`) return } DEBUG && I.start('Build CSS') compiledCss = compiler.build(newCandidates) DEBUG && I.end('Build CSS') - - if (args['--map']) { - DEBUG && I.start('Build Source Map') - compiledMap = toSourceMap(compiler.buildSourceMap()) - DEBUG && I.end('Build Source Map') - } } - await write(compiledCss, compiledMap, args, I) + await write(compiledCss, args, I) let end = process.hrtime.bigint() - if (!args['--silent']) eprintln(`Done in ${formatDuration(end - start)}`) + eprintln(`Done in ${formatDuration(end - start)}`) } catch (err) { - // It's important that we perform a full rebuild when any of the - // dependencies tracked in `fullRebuildPaths` has been changed. - // - // If we remove one of those files, then a subsequent build will be - // triggered, but it will fail because the dependency is gone. The - // compiler itself will be in a broken state and won't be able to - // register any dependencies therefore we want to restore all the - // dependencies from before. If we don't do that, then we won't be - // able to recover from a bug in a transitive dependency. - // - // E.g.: - // ```css - // /* input.css — known full rebuild path */ - // @import 'tailwindcss'; - // @config "./tailwind.config.js"; - // ``` - // - // ```js - // // tailwind.config.js - // const theme = require('./my-theme.js'); - // - // module.exports = { - // theme - // } - // ``` - // In this case `my-theme.js` is a transitive dependency of - // `input.css` via `tailwind.config.js`. Removing `my-theme.js` will - // result in an error, restoring `my-theme.js` should trigger a - // fresh build even though the compiler didn't restore. - // - // Once the build error is fixed, a fresh full rebuild will happen - // which in turn will fixup the full rebuild paths. - fullRebuildPaths = backupRebuildPaths - // Catch any errors and print them to stderr, but don't exit the process // and keep watching. - eprintln(formatError(err)) - - let end = process.hrtime.bigint() - if (!args['--silent']) eprintln(`Done in ${formatDuration(end - start)}`) + if (err instanceof Error) { + eprintln(err.toString()) + } } - }), + }, ) // Abort the watcher if `stdin` is closed to avoid zombie processes. You can // disable this behavior with `--watch=always`. if (args['--watch'] !== 'always') { process.stdin.on('end', () => { - Promise.all(cleanupWatchers.map((fn) => fn())).then( + cleanupWatchers().then( () => process.exit(0), () => process.exit(1), ) @@ -505,197 +312,27 @@ export async function handle(args: Result>) { DEBUG && I.start('Build CSS') let output = await handleError(() => compiler.build(candidates)) DEBUG && I.end('Build CSS') - - let map: SourceMap | null = null - - if (args['--map']) { - DEBUG && I.start('Build Source Map') - map = await handleError(() => toSourceMap(compiler.buildSourceMap())) - DEBUG && I.end('Build Source Map') - } - - await write(output, map, args, I) + await write(output, args, I) let end = process.hrtime.bigint() - if (!args['--silent']) eprintln(`Done in ${formatDuration(end - start)}`) - - // Watch for changes, using polling - if (args['--watch'] && pollInterval !== false) { - let cleanupPollingIndicator = () => {} - - function logPollingMessage(message: string) { - if (!args['--silent']) { - process.stderr.write('\r\x1B[2K') - } - - eprintln(message) - - if (!args['--silent']) { - process.stderr.write(`\r\x1B[2K${dim(`Polling for changes…`)}`) - } - } - - async function fullRebuild(I: Instrumentation) { - clearRequireCache(fullRebuildPaths) - backupRebuildPaths = fullRebuildPaths.slice() - fullRebuildPaths = inputFilePath ? [inputFilePath] : [] - - let input = args['--input'] - ? args['--input'] === '-' - ? await drainStdin() - : await fs.readFile(args['--input'], 'utf-8') - : css` - @import 'tailwindcss'; - ` - - ;[compiler, scanner] = await createCompiler(input, I) - backupRebuildPaths = fullRebuildPaths.slice() - - DEBUG && I.start('Scan for candidates') - let candidates = scanner.scan() - DEBUG && I.end('Scan for candidates') - - DEBUG && I.start('Build CSS') - let output = compiler.build(candidates) - DEBUG && I.end('Build CSS') - - let map: SourceMap | null = null - - if (args['--map']) { - DEBUG && I.start('Build Source Map') - map = toSourceMap(compiler.buildSourceMap()) - DEBUG && I.end('Build Source Map') - } - - await write(output, map, args, I) - } - - if (!args['--silent']) { - let restored = false - - function restoreCursor() { - if (restored) return - restored = true - process.stderr.write('\r\x1B[2K\x1B[?25h') - process.off('exit', restoreCursor) - process.off('SIGINT', onSigint) - process.off('SIGTERM', onSigterm) - } - - function onSigint() { - restoreCursor() - process.exit(130) - } - - function onSigterm() { - restoreCursor() - process.exit(143) - } - - process.stderr.write('\x1B[?25l') - process.on('exit', restoreCursor) - process.on('SIGINT', onSigint) - process.on('SIGTERM', onSigterm) - - cleanupPollingIndicator = restoreCursor - cleanupWatchers.push(async () => cleanupPollingIndicator()) - } - - cleanupWatchers.push( - createPollingWatcher(async () => { - using I = new Instrumentation() - - DEBUG && I.start('Scan for candidates') - let candidates = scanner.scan() - DEBUG && I.end('Scan for candidates') - - let files = scanner.scannedFiles.filter( - (file) => file !== args['--output'] && file !== args['--map'], - ) - - if (files.length <= 0) return - - let start = process.hrtime.bigint() - - let strategy = getRebuildStrategy(files, fullRebuildPaths) - - if (strategy.kind === 'full') { - try { - await fullRebuild(I) - } catch (err) { - fullRebuildPaths = backupRebuildPaths - - logPollingMessage(formatError(err)) - } - - if (!args['--silent']) { - logPollingMessage(`Done in ${formatDuration(process.hrtime.bigint() - start)}`) - } - return - } - - // No candidates found which means we don't need to write to disk, and - // can return early. - if (candidates.length <= 0) { - if (!args['--silent']) { - logPollingMessage(`Done in ${formatDuration(process.hrtime.bigint() - start)}`) - } - return - } - - DEBUG && I.start('Build CSS') - let output = compiler.build(candidates) - DEBUG && I.end('Build CSS') - - let map: SourceMap | null = null - - if (args['--map']) { - DEBUG && I.start('Build Source Map') - map = toSourceMap(compiler.buildSourceMap()) - DEBUG && I.end('Build Source Map') - } - - await write(output, map, args, I) - - if (!args['--silent']) { - logPollingMessage(`Done in ${formatDuration(process.hrtime.bigint() - start)}`) - } - }, pollInterval), - ) - - if (args['--watch'] !== 'always') { - process.stdin.on('end', () => { - Promise.all(cleanupWatchers.map((fn) => fn())).then( - () => process.exit(0), - () => process.exit(1), - ) - }) - } - - process.stdin.resume() - if (!args['--silent']) { - process.stderr.write(`\r\x1B[2K${dim(`Polling for changes…`)}`) - } - } + eprintln(header()) + eprintln() + eprintln(`Done in ${formatDuration(end - start)}`) } -// Load `@parcel/watcher` lazily so a missing or broken native binding only -// affects `--watch` (without `--poll`), instead of crashing one-off builds and -// polling mode as well. -async function loadWatcher(): Promise { - try { - return (await import('@parcel/watcher')).default - } catch (err) { - throw new Error( - `Failed to load the file watcher. Your platform may not be supported by \`@parcel/watcher\`. As a workaround, you can use polling instead by passing the \`--watch --poll\` flags.`, - { cause: err }, - ) - } +function watchDirectories(scanner: Scanner) { + return scanner.globs.flatMap((globEntry) => { + // We don't want a watcher for negated globs. + if (globEntry.pattern[0] === '!') return [] + + // We don't want a watcher for files, only directories. + if (globEntry.pattern === '') return [] + + return globEntry.base + }) } async function createWatchers(dirs: string[], cb: (files: string[]) => void) { - let watcher = await loadWatcher() - // Remove any directories that are children of an already watched directory. // If we don't we may not get notified of certain filesystem events regardless // of whether or not they are for the directory that is duplicated. @@ -757,16 +394,10 @@ async function createWatchers(dirs: string[], cb: (files: string[]) => void) { await Promise.all( events.map(async (event) => { - // When a file is deleted, a rebuild should be triggered such that we - // can figure out whether this file must trigger a fresh build or not. - // - // If it must trigger a fresh build, then we will temporarily end up - // in a broken state, but an error will be shown to the user. Once the - // user resolves the issue, the CLI will recover. - if (event.type === 'delete') { - files.add(event.path) - return - } + // We currently don't handle deleted files because it doesn't influence + // the CSS output. This is because we currently keep all scanned + // candidates in a cache for performance reasons. + if (event.type === 'delete') return // Ignore directory changes. We only care about file changes let stats: Stats | null = null @@ -797,78 +428,35 @@ async function createWatchers(dirs: string[], cb: (files: string[]) => void) { } } -function getRebuildStrategy( - files: string[], - fullRebuildPaths: string[], -): { kind: 'incremental'; changedFiles: ChangedContent[] } | { kind: 'full' } { - let changedFiles: ChangedContent[] = [] - - for (let file of files) { - // If one of the changed files is related to the input CSS or JS - // config/plugin files, then we need to do a full rebuild because - // the theme might have changed. - if (fullRebuildPaths.includes(file)) { - return { kind: 'full' } - } - - // Track new and updated files for incremental rebuilds. - changedFiles.push({ - file, - extension: path.extname(file).slice(1), - } satisfies ChangedContent) +function optimizeCss( + input: string, + { file = 'input.css', minify = false }: { file?: string; minify?: boolean } = {}, +) { + function optimize(code: Buffer | Uint8Array) { + return transform({ + filename: file, + code, + minify, + sourceMap: false, + drafts: { + customMedia: true, + }, + nonStandard: { + deepSelectorCombinator: true, + }, + include: Features.Nesting, + exclude: Features.LogicalProperties | Features.DirSelector, + targets: { + safari: (16 << 16) | (4 << 8), + ios_saf: (16 << 16) | (4 << 8), + firefox: 128 << 16, + chrome: 111 << 16, + }, + errorRecovery: true, + }).code } - return { kind: 'incremental', changedFiles } -} - -function createPollingWatcher(cb: () => Promise, pollInterval: number) { - let disposed = false - let timer: ReturnType | null = null - - async function poll() { - if (disposed) return - - try { - await cb() - } catch (err) { - console.error(err) - } finally { - if (!disposed) { - timer = setTimeout(poll, pollInterval) - } - } - } - - timer = setTimeout(poll, pollInterval) - - return async () => { - disposed = true - if (timer) clearTimeout(timer) - } -} - -async function watchDirectories(scanner: Scanner) { - let directories = ( - await Promise.all( - scanner.normalizedSources.map(async (globEntry) => { - let resolvedPath = path.resolve(globEntry.base) - let realPath = await fs.realpath(resolvedPath).catch(() => resolvedPath) - - return fs - .stat(realPath) - .then((stat) => (stat.isDirectory() ? [realPath] : [])) - .catch(() => []) - }), - ) - ).flat(1) - - return Array.from(new Set(directories)) -} - -function dim(str: string) { - return `\x1B[2m${str}\x1B[22m` -} - -function red(str: string) { - return `\x1B[31m${str}\x1B[39m` + // Running Lightning CSS twice to ensure that adjacent rules are merged after + // nesting is applied. This creates a more optimized output. + return optimize(optimize(Buffer.from(input))).toString() } diff --git a/packages/@tailwindcss-cli/src/commands/build/utils.ts b/packages/@tailwindcss-cli/src/commands/build/utils.ts index ecdd96726..b41a74358 100644 --- a/packages/@tailwindcss-cli/src/commands/build/utils.ts +++ b/packages/@tailwindcss-cli/src/commands/build/utils.ts @@ -13,19 +13,10 @@ export function drainStdin() { } export async function outputFile(file: string, contents: string) { - // Check for special files like `/dev/stdout` or pipes. We don't want to read from these as that - // will hang the process until the file descriptors are closed. - let isSpecialFile = await fs - .stat(file) - .then((stats) => stats.isCharacterDevice() || stats.isFIFO()) - .catch(() => false) - - if (!isSpecialFile) { - try { - let currentContents = await fs.readFile(file, 'utf8') - if (currentContents === contents) return // Skip writing the file - } catch {} - } + try { + let currentContents = await fs.readFile(file, 'utf8') + if (currentContents === contents) return // Skip writing the file + } catch {} // Ensure the parent directories exist await fs.mkdir(path.dirname(file), { recursive: true }) diff --git a/packages/@tailwindcss-cli/src/commands/canonicalize/canonicalize.test.ts b/packages/@tailwindcss-cli/src/commands/canonicalize/canonicalize.test.ts deleted file mode 100644 index 4392380a5..000000000 --- a/packages/@tailwindcss-cli/src/commands/canonicalize/canonicalize.test.ts +++ /dev/null @@ -1,175 +0,0 @@ -import path from 'node:path' -import { PassThrough, Readable } from 'node:stream' -import { fileURLToPath } from 'node:url' -import { describe, expect, test } from 'vitest' -import { runCommandLine, streamStdin } from '.' -import { normalizeWindowsSeparators } from '../../utils/test-helpers' - -let css = normalizeWindowsSeparators( - path.resolve(path.dirname(fileURLToPath(import.meta.url)), 'fixtures/input.css'), -) - -describe('runCommandLine', { timeout: 30_000 }, () => { - test('canonicalizes, collapses, and sorts candidate groups from positional arguments', async () => { - let result = await runCommandLine({ - argv: ['--css', css, 'py-3 p-1 px-3'], - stdinIsTTY: true, - stdoutIsTTY: false, - }) - - expect(result).toEqual({ - exitCode: 0, - stdout: 'p-3', - stderr: '', - }) - }) - - test('falls back to the default tailwind import when --css is omitted', async () => { - let result = await runCommandLine({ - argv: ['py-3 p-1 px-3'], - cwd: path.dirname(css), - stdinIsTTY: true, - stdoutIsTTY: false, - }) - - expect(result).toEqual({ - exitCode: 0, - stdout: 'p-3', - stderr: '', - }) - }) - - test('canonicalizes, collapses, and sorts multiple groups from stdin lines', async () => { - let result = await runCommandLine({ - argv: ['--css', css], - stdin: '[display:_flex_] py-3 p-1 px-3\nmt-2 mr-2 mb-2 ml-2 focus:hover:p-3 hover:p-1 py-3\n', - stdinIsTTY: false, - stdoutIsTTY: false, - }) - - expect(result).toEqual({ - exitCode: 0, - stdout: 'flex p-3\nm-2 py-3 hover:p-1 focus:hover:p-3', - stderr: '', - }) - }) - - test('collapses equivalent candidates', async () => { - let result = await runCommandLine({ - argv: ['--css', css, 'mt-2 mr-2 mb-2 ml-2'], - stdinIsTTY: true, - stdoutIsTTY: false, - }) - - expect(result).toEqual({ - exitCode: 0, - stdout: 'm-2', - stderr: '', - }) - }) - - test('renders json output for processed candidate groups', async () => { - let result = await runCommandLine({ - argv: ['--css', css, '--format', 'json', 'py-3 p-1 px-3'], - stdinIsTTY: true, - stdoutIsTTY: false, - }) - - expect(result.exitCode).toBe(0) - expect(JSON.parse(result.stdout)).toEqual([ - { - input: 'py-3 p-1 px-3', - output: 'p-3', - changed: true, - }, - ]) - expect(result.stderr).toBe('') - }) - - test('splits candidate lists with segment-aware spacing', async () => { - let result = await runCommandLine({ - argv: ['--css', css, '--format', 'json', "content-['hello world'] p-1"], - stdinIsTTY: true, - stdoutIsTTY: false, - }) - - expect(result.exitCode).toBe(0) - expect(JSON.parse(result.stdout)).toEqual([ - { - input: "content-['hello world'] p-1", - output: "p-1 content-['hello_world']", - changed: true, - }, - ]) - expect(result.stderr).toBe('') - }) - - test('shows a usage error when no candidate groups are provided', async () => { - let result = await runCommandLine({ - argv: ['--css', css], - stdinIsTTY: true, - stdoutIsTTY: false, - }) - - expect(result.exitCode).toBe(1) - expect(result.stderr).toBe('No candidate groups provided') - expect(result.stdout).toContain('Usage:') - }) - - test('streams canonicalized output line by line', async () => { - let input = Readable.from('py-3 p-1 px-3\nmt-2 mr-2 mb-2 ml-2\n') - let { stream: output, collect: collectOutput } = createOutput() - - await streamStdin({ css, cwd: path.dirname(css), format: 'text', input, output }) - - expect(collectOutput()).toBe('p-3\nm-2\n') - }) - - test('streams empty lines as empty lines', async () => { - let input = Readable.from('py-3 p-1 px-3\n\nmt-2 mr-2 mb-2 ml-2\n') - let { stream: output, collect: collectOutput } = createOutput() - - await streamStdin({ css, cwd: path.dirname(css), format: 'text', input, output }) - - expect(collectOutput()).toBe('p-3\n\nm-2\n') - }) - - test('streams json output when requested', async () => { - let input = Readable.from('py-3 p-1 px-3\nmt-2 mr-2 mb-2 ml-2\n') - let { stream: output, collect: collectOutput } = createOutput() - - await streamStdin({ css, cwd: path.dirname(css), format: 'json', input, output }) - - expect(JSON.parse(collectOutput())).toEqual([ - { - input: 'py-3 p-1 px-3', - output: 'p-3', - changed: true, - }, - { - input: 'mt-2 mr-2 mb-2 ml-2', - output: 'm-2', - changed: true, - }, - ]) - }) - - test('streams jsonl output when requested', async () => { - let input = Readable.from('py-3 p-1 px-3\nmt-2 mr-2 mb-2 ml-2\n') - let { stream: output, collect: collectOutput } = createOutput() - - await streamStdin({ css, cwd: path.dirname(css), format: 'jsonl', input, output }) - - expect(collectOutput()).toBe( - '{"input":"py-3 p-1 px-3","output":"p-3","changed":true}\n' + - '{"input":"mt-2 mr-2 mb-2 ml-2","output":"m-2","changed":true}\n', - ) - }) -}) - -function createOutput() { - let stream = new PassThrough() - let chunks: Buffer[] = [] - stream.on('data', (chunk) => chunks.push(chunk)) - return { stream, collect: () => Buffer.concat(chunks).toString() } -} diff --git a/packages/@tailwindcss-cli/src/commands/canonicalize/fixtures/input.css b/packages/@tailwindcss-cli/src/commands/canonicalize/fixtures/input.css deleted file mode 100644 index d4b507858..000000000 --- a/packages/@tailwindcss-cli/src/commands/canonicalize/fixtures/input.css +++ /dev/null @@ -1 +0,0 @@ -@import 'tailwindcss'; diff --git a/packages/@tailwindcss-cli/src/commands/canonicalize/index.ts b/packages/@tailwindcss-cli/src/commands/canonicalize/index.ts deleted file mode 100644 index 5aecfe51e..000000000 --- a/packages/@tailwindcss-cli/src/commands/canonicalize/index.ts +++ /dev/null @@ -1,362 +0,0 @@ -import { __unstable__loadDesignSystem } from '@tailwindcss/node' -import fs from 'node:fs/promises' -import path from 'node:path' -import { createInterface } from 'node:readline' -import type { Readable, Writable } from 'node:stream' -import { compare } from '../../../../tailwindcss/src/utils/compare' -import { segment } from '../../../../tailwindcss/src/utils/segment' -import { args, type Arg } from '../../utils/args' -import { help } from '../help' - -const css = String.raw -export type OutputFormat = 'text' | 'json' | 'jsonl' - -export interface CandidateGroupResult { - input: string - output: string - changed: boolean -} - -export interface RunCommandLineOptions { - argv?: string[] - cwd?: string - stdin?: string | null - stdinIsTTY?: boolean - stdoutIsTTY?: boolean -} - -export interface RunCommandLineResult { - exitCode: number - stdout: string - stderr: string -} - -export function usage() { - return 'tailwindcss canonicalize [classes...]' -} - -function usageWithCss() { - return 'tailwindcss canonicalize --css input.css [classes...]' -} - -function usageWithStream() { - return 'tailwindcss canonicalize --stream [--css input.css]' -} - -export function options() { - return { - '--css': { - type: 'string', - description: - 'CSS entry file used to load the Tailwind design system (defaults to `@import "tailwindcss";`)', - }, - '--format': { - type: 'string', - description: 'Output format', - default: 'text', - values: ['text', 'json', 'jsonl'], - }, - '--stream': { - type: 'boolean', - description: 'Read candidate groups from stdin line by line and write results to stdout', - default: false, - }, - } satisfies Arg -} - -const sharedOptions = { - '--help': { - type: 'boolean', - description: 'Display usage information', - alias: '-h', - default: false, - }, -} satisfies Arg - -export async function runCommandLine({ - argv = process.argv.slice(2), - cwd = process.cwd(), - stdin = null, - stdinIsTTY = process.stdin.isTTY, - stdoutIsTTY = process.stdout.isTTY, -}: RunCommandLineOptions = {}): Promise { - try { - let flags = args( - { - ...options(), - ...sharedOptions, - }, - argv, - ) - - let format = parseFormat(flags['--format'] ?? 'text') - - if ((stdoutIsTTY && argv.length === 0) || flags['--help']) { - return { - exitCode: 0, - stdout: helpMessage() ?? '', - stderr: '', - } - } - - if (flags['--stream']) { - await streamStdin({ - css: flags['--css'], - cwd, - format, - input: process.stdin, - output: process.stdout, - }) - return { exitCode: 0, stdout: '', stderr: '' } - } - - let inputs = flags._.length > 0 ? flags._ : await readCandidateGroups({ stdin, stdinIsTTY }) - - if (inputs.length === 0) { - return usageError('No candidate groups provided') - } - - let results = await processCandidateGroups({ - css: flags['--css'], - cwd, - inputs, - }) - - return { - exitCode: 0, - stdout: formatCandidateResults(results, format), - stderr: '', - } - } catch (error) { - return { - exitCode: 1, - stdout: '', - stderr: error instanceof Error ? error.message : String(error), - } - } -} - -export async function streamStdin({ - css: cssFile, - cwd, - format, - input, - output, -}: { - css: string | null - cwd: string - format: OutputFormat - input: Readable - output: Writable -}): Promise { - let designSystem = await loadDesignSystem(cssFile, cwd) - let rl = createInterface({ input }) - let first = true - - if (format === 'json') { - output.write('[') - } - - for await (let line of rl) { - let result = createCandidateGroupResult(designSystem, line) - - switch (format) { - case 'text': { - output.write(result.output + '\n') - break - } - - case 'jsonl': { - output.write(JSON.stringify(result) + '\n') - break - } - - case 'json': { - if (first) { - output.write('\n') - } else { - output.write(',\n') - } - - output.write(indent(JSON.stringify(result, null, 2), 2)) - first = false - break - } - } - } - - if (format === 'json') { - output.write(first ? ']' : '\n]') - } -} - -export function readCandidateGroups({ - stdin, - stdinIsTTY, -}: { - stdin: string | null - stdinIsTTY: boolean -}) { - if (stdin !== null) { - return Promise.resolve(splitCandidateGroups(stdin)) - } - - if (stdinIsTTY) { - return Promise.resolve([]) - } - - return drainStdin().then(splitCandidateGroups) -} - -export async function drainStdin() { - return new Promise((resolve, reject) => { - let result = '' - - process.stdin.on('data', (chunk) => { - result += chunk - }) - - process.stdin.on('end', () => resolve(result)) - process.stdin.on('error', (err) => reject(err)) - }) -} - -export async function processCandidateGroups({ - css, - cwd = process.cwd(), - inputs, -}: { - css: string | null - cwd?: string - inputs: string[] -}): Promise { - let designSystem = await loadDesignSystem(css, cwd) - - return inputs.map((input) => createCandidateGroupResult(designSystem, input)) -} - -export function formatCandidateResults(results: CandidateGroupResult[], format: OutputFormat) { - switch (format) { - case 'json': - return JSON.stringify(results, null, 2) - case 'jsonl': - return results.map((result) => JSON.stringify(result)).join('\n') - case 'text': - return results.map((result) => result.output).join('\n') - } -} - -function helpMessage() { - return help({ - render: false, - usage: [usage(), usageWithCss(), usageWithStream()], - options: { - ...options(), - ...sharedOptions, - }, - }) -} - -async function loadDesignSystem(cssFile: string | null, cwd: string) { - if (cssFile === null) { - return __unstable__loadDesignSystem( - css` - @import 'tailwindcss'; - `, - { base: cwd }, - ) - } - - let resolvedCssFile = path.resolve(cwd, cssFile) - let content = await fs.readFile(resolvedCssFile, 'utf8') - return __unstable__loadDesignSystem(content, { - base: path.dirname(resolvedCssFile), - }) -} - -function splitCandidateGroups(input: string) { - return input - .split(/\r?\n/g) - .map((line) => line.trim()) - .filter((line) => line.length > 0) -} - -function parseFormat(input: string): OutputFormat { - if (input === 'text' || input === 'json' || input === 'jsonl') { - return input - } - - throw new Error(`Invalid value for --format: ${input}`) -} - -function usageError(message: string): RunCommandLineResult { - return { - exitCode: 1, - stdout: helpMessage() ?? '', - stderr: message, - } -} - -function splitCandidates(input: string) { - let trimmedInput = input.trim() - if (trimmedInput.length === 0) return [] - - return segment(trimmedInput, ' ') - .map((candidate) => candidate.trim()) - .filter((candidate) => candidate.length > 0) -} - -function canonicalize( - designSystem: Awaited>, - input: string, -) { - let candidates = splitCandidates(input) - candidates = designSystem.canonicalizeCandidates(candidates, { - collapse: true, - logicalToPhysical: true, - }) - return defaultSort(designSystem.getClassOrder(candidates)).join(' ') -} - -function createCandidateGroupResult( - designSystem: Awaited>, - input: string, -): CandidateGroupResult { - let output = canonicalize(designSystem, input) - - return { - input, - output, - changed: output !== input, - } -} - -function indent(input: string, size: number) { - let prefix = ' '.repeat(size) - return input - .split('\n') - .map((line) => prefix + line) - .join('\n') -} - -function defaultSort(entries: [string, bigint | null][]) { - return entries - .slice() - .sort(([candidateA, orderA], [candidateZ, orderZ]) => { - if (orderA === orderZ) return compare(candidateA, candidateZ) - if (orderA === null) return -1 - if (orderZ === null) return 1 - return bigSign(orderA - orderZ) || compare(candidateA, candidateZ) - }) - .map(([candidate]) => candidate) -} - -function bigSign(value: bigint) { - if (value > 0n) { - return 1 - } else if (value === 0n) { - return 0 - } else { - return -1 - } -} diff --git a/packages/@tailwindcss-cli/src/commands/help/index.ts b/packages/@tailwindcss-cli/src/commands/help/index.ts index b557d03e0..20ee78208 100644 --- a/packages/@tailwindcss-cli/src/commands/help/index.ts +++ b/packages/@tailwindcss-cli/src/commands/help/index.ts @@ -3,34 +3,30 @@ import type { Arg } from '../../utils/args' import { UI, header, highlight, indent, println, wordWrap } from '../../utils/renderer' export function help({ - render = true, invalid, usage, options, }: { - render?: boolean invalid?: string usage?: string[] options?: Arg }) { // Available terminal width - let width = process.stdout.columns ?? 80 - let lines: string[] = [] - let writeLine = render ? println : (value = '') => void lines.push(value) + let width = process.stdout.columns // Render header - writeLine(header()) + println(header()) // Render the invalid command if (invalid) { - writeLine() - writeLine(`${pc.dim('Invalid command:')} ${invalid}`) + println() + println(`${pc.dim('Invalid command:')} ${invalid}`) } // Render usage if (usage && usage.length > 0) { - writeLine() - writeLine(pc.dim('Usage:')) + println() + println(pc.dim('Usage:')) for (let [idx, example] of usage.entries()) { // Split the usage example into the command and its options. This allows // us to wrap the options based on the available width of the terminal. @@ -69,7 +65,7 @@ export function help({ // tailwindcss other [--watch] [options...] // ``` if (lines.length > 1 && idx !== 0) { - writeLine() + println() } // Print the usage examples based on available width of the terminal. @@ -90,9 +86,9 @@ export function help({ // ``` // // > Note how the second line is indented to align with the first line. - writeLine(indent(`${command}${lines.shift()}`)) + println(indent(`${command}${lines.shift()}`)) for (let line of lines) { - writeLine(indent(line, command.length)) + println(indent(line, command.length)) } } } @@ -116,11 +112,7 @@ export function help({ // `alias` followed by `, ` and followed by the `flag`. let maxOptionLength = 0 - for (let [flag, { alias, values }] of Object.entries(options)) { - if (values?.length) { - flag += `[=${values.join(', ')}]` - } - + for (let [flag, { alias }] of Object.entries(options)) { // The option string, which is the combination of the alias and the flag // but already properly indented based on the other aliases to ensure // everything is aligned properly. @@ -135,8 +127,8 @@ export function help({ maxOptionLength = Math.max(maxOptionLength, option.length) } - writeLine() - writeLine(pc.dim('Options:')) + println() + println(pc.dim('Options:')) // The minimum amount of dots between the option and the description. let minimumGap = 8 @@ -164,19 +156,15 @@ export function help({ ) // Print the option, the spacer dots and the start of the description. - writeLine( + println( indent(`${pc.blue(option)} ${pc.dim(pc.gray('\u00B7')).repeat(dotCount)} ${lines.shift()}`), ) // Print the remaining lines of the description, indenting them to align // with the start of the description. for (let line of lines) { - writeLine(indent(`${' '.repeat(option.length + dotCount + spaces)}${line}`)) + println(indent(`${' '.repeat(option.length + dotCount + spaces)}${line}`)) } } } - - if (!render) { - return lines.join('\n') - } } diff --git a/packages/@tailwindcss-cli/src/index.ts b/packages/@tailwindcss-cli/src/index.ts index 1543f7d13..511781759 100644 --- a/packages/@tailwindcss-cli/src/index.ts +++ b/packages/@tailwindcss-cli/src/index.ts @@ -3,80 +3,46 @@ import { args, type Arg } from './utils/args' import * as build from './commands/build' -import * as canonicalize from './commands/canonicalize' import { help } from './commands/help' const sharedOptions = { '--help': { type: 'boolean', description: 'Display usage information', alias: '-h' }, } satisfies Arg -function buildUsage(command = 'tailwindcss') { - return `${command} [--input input.css] [--output output.css] [--watch] [--poll=ms] [options…]` -} +const flags = args({ + ...build.options(), + ...sharedOptions, +}) +const command = flags._[0] -function rootHelp({ invalid }: { invalid?: string } = {}) { +// Right now we don't support any sub-commands. Let's show the help message +// instead. +if (command) { help({ - invalid, - usage: [buildUsage('tailwindcss'), buildUsage('tailwindcss build'), canonicalize.usage()], - commands: { - build: 'Build your CSS', - canonicalize: 'Canonicalize candidate lists', - }, + invalid: command, + usage: ['tailwindcss [options]'], options: { ...build.options(), ...sharedOptions }, }) + process.exit(1) } -async function run() { - let argv = process.argv.slice(2) - let command = argv[0] - let rootFlags = args({ ...build.options(), ...sharedOptions }, argv) - - if (command === 'build') { - let flags = args({ ...build.options(), ...sharedOptions }, argv.slice(1)) - - if ((process.stdout.isTTY && argv.length === 1) || flags['--help']) { - help({ - usage: [buildUsage('tailwindcss build')], - options: { ...build.options(), ...sharedOptions }, - }) - process.exit(0) - } - - await build.handle(flags) - return - } - - if (command === 'canonicalize') { - let result = await canonicalize.runCommandLine({ argv: argv.slice(1) }) - - if (result.stdout.length > 0) { - process.stdout.write(`${result.stdout}\n`) - } - - if (result.stderr.length > 0) { - process.stderr.write(`${result.stderr}\n`) - } - - process.exitCode = result.exitCode - return - } - - if ((process.stdout.isTTY && command === undefined) || rootFlags['--help']) { - rootHelp() - process.exit(0) - } - - if (command && !command.startsWith('-')) { - rootHelp({ invalid: command }) - process.exit(1) - } - - let flags = args({ - ...build.options(), - ...sharedOptions, +// Display main help message if no command is being used. +// +// E.g.: +// +// - `tailwindcss` // should show the help message +// +// E.g.: implicit `build` command +// +// - `tailwindcss -o output.css` // should run the build command, not show the help message +// - `tailwindcss > output.css` // should run the build command, not show the help message +if ((process.stdout.isTTY && !flags['--output']) || flags['--help']) { + help({ + usage: ['tailwindcss [--input input.css] [--output output.css] [--watch] [options…]'], + options: { ...build.options(), ...sharedOptions }, }) - - await build.handle(flags) + process.exit(0) } -await run() +// Handle the build command +build.handle(flags) diff --git a/packages/@tailwindcss-cli/src/utils/args.test.ts b/packages/@tailwindcss-cli/src/utils/args.test.ts index 249fb23eb..51d2c4747 100644 --- a/packages/@tailwindcss-cli/src/utils/args.test.ts +++ b/packages/@tailwindcss-cli/src/utils/args.test.ts @@ -17,38 +17,6 @@ it('should be possible to parse a single argument', () => { `) }) -it('should only return the last value for duplicate arguments', () => { - expect( - args( - { - '--output': { type: 'string', description: 'Output file' }, - }, - ['--output', 'output.css', '--output', 'override.css'], - ), - ).toMatchInlineSnapshot(` - { - "--output": "override.css", - "_": [], - } - `) -}) - -it('uses last value when flag with "-" is supplied multiple times', () => { - let result = args( - { - '--output': { type: 'string', description: 'Output file', alias: '-o' }, - }, - ['--output', 'output.css', '--output', '-'], - ) - - expect(result).toMatchInlineSnapshot(` - { - "--output": "-", - "_": [], - } - `) -}) - it('should fallback to the default value if no flag is passed', () => { expect( args( @@ -153,34 +121,3 @@ it('should be possible to provide multiple types, and convert the value to that } `) }) - -it('should be possible to provide boolean or number arguments', () => { - let options = { - '--poll': { - type: 'boolean | number', - description: 'Use polling instead of filesystem events when watching', - default: false, - }, - } satisfies Arg - - expect(args(options, ['--poll'])).toMatchInlineSnapshot(` - { - "--poll": true, - "_": [], - } - `) - - expect(args(options, ['--poll=50'])).toMatchInlineSnapshot(` - { - "--poll": 50, - "_": [], - } - `) - - expect(args(options, ['--poll=foo'])).toMatchInlineSnapshot(` - { - "--poll": undefined, - "_": [], - } - `) -}) diff --git a/packages/@tailwindcss-cli/src/utils/args.ts b/packages/@tailwindcss-cli/src/utils/args.ts index 88b306b05..81bd847d5 100644 --- a/packages/@tailwindcss-cli/src/utils/args.ts +++ b/packages/@tailwindcss-cli/src/utils/args.ts @@ -7,7 +7,6 @@ export type Arg = { description: string alias?: `-${string}` default?: Types[keyof Types] - values?: string[] } } @@ -68,28 +67,8 @@ export type Result = { } export function args(options: T, argv = process.argv.slice(2)): Result { - for (let [idx, value] of argv.entries()) { - if (value === '-') { - argv[idx] = '__IO_DEFAULT_VALUE__' - } - } - let parsed = parse(argv) - for (let key in parsed) { - let value = parsed[key] - - if (key !== '_' && Array.isArray(value)) { - value = value[value.length - 1] - } - - if (value === '__IO_DEFAULT_VALUE__') { - value = '-' - } - - parsed[key] = value - } - let result: { _: string[]; [key: string]: unknown } = { _: parsed._, } diff --git a/packages/@tailwindcss-cli/src/utils/renderer.test.ts b/packages/@tailwindcss-cli/src/utils/renderer.test.ts index 7acef4551..b9950655f 100644 --- a/packages/@tailwindcss-cli/src/utils/renderer.test.ts +++ b/packages/@tailwindcss-cli/src/utils/renderer.test.ts @@ -1,29 +1,29 @@ import path from 'node:path' import { describe, expect, it } from 'vitest' import { relative, wordWrap } from './renderer' -import { normalizeWindowsSeparators } from './test-helpers' +import { normalizeWindowsSeperators } from './test-helpers' describe('relative', () => { it('should print an absolute path relative to the current working directory', () => { - expect(normalizeWindowsSeparators(relative(path.resolve('index.css')))).toMatchInlineSnapshot( + expect(normalizeWindowsSeperators(relative(path.resolve('index.css')))).toMatchInlineSnapshot( `"./index.css"`, ) }) it('should prefer the shortest value by default', () => { // Shortest between absolute and relative paths - expect(normalizeWindowsSeparators(relative('index.css'))).toMatchInlineSnapshot(`"index.css"`) + expect(normalizeWindowsSeperators(relative('index.css'))).toMatchInlineSnapshot(`"index.css"`) }) it('should be possible to override the current working directory', () => { - expect(normalizeWindowsSeparators(relative('../utils/index.css', '..'))).toMatchInlineSnapshot( + expect(normalizeWindowsSeperators(relative('../utils/index.css', '..'))).toMatchInlineSnapshot( `"./utils/index.css"`, ) }) it('should be possible to always prefer the relative path', () => { expect( - normalizeWindowsSeparators( + normalizeWindowsSeperators( relative('index.css', process.cwd(), { preferAbsoluteIfShorter: false }), ), ).toMatchInlineSnapshot(`"./index.css"`) diff --git a/packages/@tailwindcss-cli/src/utils/renderer.ts b/packages/@tailwindcss-cli/src/utils/renderer.ts index da817dda7..6b0098586 100644 --- a/packages/@tailwindcss-cli/src/utils/renderer.ts +++ b/packages/@tailwindcss-cli/src/utils/renderer.ts @@ -49,9 +49,7 @@ export function wordWrap(text: string, width: number) { for (let word of words) { let wordLength = stripVTControlCharacters(word).length - // A word longer than `width` is kept on its own line rather than - // introducing an empty line before it. - if (lineLength > 0 && lineLength + wordLength + 1 > width) { + if (lineLength + wordLength + 1 > width) { lines.push(line) line = '' lineLength = 0 diff --git a/packages/@tailwindcss-cli/src/utils/test-helpers.ts b/packages/@tailwindcss-cli/src/utils/test-helpers.ts index 30f4fc777..8e61b0a13 100644 --- a/packages/@tailwindcss-cli/src/utils/test-helpers.ts +++ b/packages/@tailwindcss-cli/src/utils/test-helpers.ts @@ -1,5 +1,5 @@ import path from 'node:path' -export function normalizeWindowsSeparators(p: string) { +export function normalizeWindowsSeperators(p: string) { return path.sep === '\\' ? p.replaceAll('\\', '/') : p } diff --git a/packages/@tailwindcss-node/README.md b/packages/@tailwindcss-node/README.md index 5f532607d..95ec9d87d 100644 --- a/packages/@tailwindcss-node/README.md +++ b/packages/@tailwindcss-node/README.md @@ -13,10 +13,10 @@

- Build Status + Build Status Total Downloads - Latest Release - License + Latest Release + License

--- @@ -27,10 +27,14 @@ For full documentation, visit [tailwindcss.com](https://tailwindcss.com). ## Community -For help, discussion about best practices, or feature ideas: +For help, discussion about best practices, or any other conversation that would benefit from being searchable: -[Discuss Tailwind CSS on GitHub](https://github.com/tailwindlabs/tailwindcss/discussions) +[Discuss Tailwind CSS on GitHub](https://github.com/tailwindcss/tailwindcss/discussions) + +For chatting with others using the framework: + +[Join the Tailwind CSS Discord Server](https://discord.gg/7NF8GNe) ## Contributing -If you're interested in contributing to Tailwind CSS, please read our [contributing docs](https://github.com/tailwindlabs/tailwindcss/blob/main/.github/CONTRIBUTING.md) **before submitting a pull request**. +If you're interested in contributing to Tailwind CSS, please read our [contributing docs](https://github.com/tailwindcss/tailwindcss/blob/next/.github/CONTRIBUTING.md) **before submitting a pull request**. diff --git a/packages/@tailwindcss-node/package.json b/packages/@tailwindcss-node/package.json index 0eced7366..4776236c6 100644 --- a/packages/@tailwindcss-node/package.json +++ b/packages/@tailwindcss-node/package.json @@ -1,6 +1,6 @@ { "name": "@tailwindcss/node", - "version": "4.3.3", + "version": "4.0.0-beta.7", "description": "A utility-first CSS framework for rapidly building custom user interfaces.", "license": "MIT", "repository": { @@ -19,46 +19,26 @@ ], "publishConfig": { "provenance": true, - "access": "public", - "exports": { - ".": { - "types": "./dist/index.d.ts", - "import": "./dist/index.mjs", - "require": "./dist/index.js" - }, - "./require-cache": { - "types": "./dist/require-cache.d.ts", - "default": "./dist/require-cache.js" - }, - "./esm-cache-loader": { - "types": "./dist/esm-cache.loader.d.mts", - "default": "./dist/esm-cache.loader.mjs" - } - } + "access": "public" }, "exports": { ".": { - "types": "./src/index.ts", - "import": "./src/index.ts", - "require": "./src/index.cts" + "types": "./dist/index.d.ts", + "import": "./dist/index.mjs", + "require": "./dist/index.js" }, "./require-cache": { - "types": "./src/require-cache.ts", - "import": "./src/require-cache.ts", - "require": "./src/require-cache.cts" + "types": "./dist/require-cache.d.ts", + "default": "./dist/require-cache.js" }, "./esm-cache-loader": { - "types": "./src/esm-cache.loader.mts", - "default": "./src/esm-cache.loader.mts" + "types": "./dist/esm-cache.loader.d.mts", + "default": "./dist/esm-cache.loader.mjs" } }, "dependencies": { - "@jridgewell/remapping": "^2.3.5", - "enhanced-resolve": "catalog:", - "jiti": "^2.7.0", - "lightningcss": "catalog:", - "magic-string": "^1.1.0", - "source-map-js": "^1.2.1", + "enhanced-resolve": "^5.17.1", + "jiti": "^2.4.0", "tailwindcss": "workspace:*" } } diff --git a/packages/@tailwindcss-node/src/compile.ts b/packages/@tailwindcss-node/src/compile.ts index e5f8782c8..b946c79de 100644 --- a/packages/@tailwindcss-node/src/compile.ts +++ b/packages/@tailwindcss-node/src/compile.ts @@ -2,29 +2,26 @@ import EnhancedResolve from 'enhanced-resolve' import { createJiti, type Jiti } from 'jiti' import fs from 'node:fs' import fsPromises from 'node:fs/promises' -import path from 'node:path' +import path, { dirname } from 'node:path' import { pathToFileURL } from 'node:url' import { __unstable__loadDesignSystem as ___unstable__loadDesignSystem, compile as _compile, compileAst as _compileAst, Features, - Polyfills, } from 'tailwindcss' import type { AstNode } from '../../tailwindcss/src/ast' import { getModuleDependencies } from './get-module-dependencies' import { rewriteUrls } from './urls' -export { Features, Polyfills } +export { Features } export type Resolver = (id: string, base: string) => Promise export interface CompileOptions { base: string - from?: string onDependency: (path: string) => void shouldRewriteUrls?: boolean - polyfills?: Polyfills customCssResolver?: Resolver customJsResolver?: Resolver @@ -32,8 +29,6 @@ export interface CompileOptions { function createCompileOptions({ base, - from, - polyfills, onDependency, shouldRewriteUrls, @@ -42,13 +37,11 @@ function createCompileOptions({ }: CompileOptions) { return { base, - polyfills, - from, async loadModule(id: string, base: string) { return loadModule(id, base, onDependency, customJsResolver) }, - async loadStylesheet(id: string, sheetBase: string) { - let sheet = await loadStylesheet(id, sheetBase, onDependency, customCssResolver) + async loadStylesheet(id: string, base: string) { + let sheet = await loadStylesheet(id, base, onDependency, customCssResolver) if (shouldRewriteUrls) { sheet.content = await rewriteUrls({ @@ -63,9 +56,10 @@ function createCompileOptions({ } } -async function ensureSourceDetectionRootExists(compiler: { - root: Awaited>['root'] -}) { +async function ensureSourceDetectionRootExists( + compiler: { root: Awaited>['root'] }, + base: string, +) { // Verify if the `source(…)` path exists (until the glob pattern starts) if (compiler.root && compiler.root !== 'none') { let globSymbols = /[*{]/ @@ -79,27 +73,25 @@ async function ensureSourceDetectionRootExists(compiler: { } let exists = await fsPromises - .stat(path.resolve(compiler.root.base, basePath.join('/'))) + .stat(path.resolve(base, basePath.join('/'))) .then((stat) => stat.isDirectory()) .catch(() => false) if (!exists) { - throw new Error( - `The \`source(${compiler.root.pattern})\` does not exist or is not a directory.`, - ) + throw new Error(`The \`source(${compiler.root.pattern})\` does not exist`) } } } export async function compileAst(ast: AstNode[], options: CompileOptions) { let compiler = await _compileAst(ast, createCompileOptions(options)) - await ensureSourceDetectionRootExists(compiler) + await ensureSourceDetectionRootExists(compiler, options.base) return compiler } export async function compile(css: string, options: CompileOptions) { let compiler = await _compile(css, createCompileOptions(options)) - await ensureSourceDetectionRootExists(compiler) + await ensureSourceDetectionRootExists(compiler, options.base) return compiler } @@ -129,8 +121,7 @@ export async function loadModule( let module = await importModule(pathToFileURL(resolvedPath).href) return { - path: resolvedPath, - base: path.dirname(resolvedPath), + base: dirname(resolvedPath), module: module.default ?? module, } } @@ -149,8 +140,7 @@ export async function loadModule( onDependency(file) } return { - path: resolvedPath, - base: path.dirname(resolvedPath), + base: dirname(resolvedPath), module: module.default ?? module, } } @@ -166,9 +156,18 @@ async function loadStylesheet( onDependency(resolvedPath) + if (typeof globalThis.__tw_readFile === 'function') { + let file = await globalThis.__tw_readFile(resolvedPath, 'utf-8') + if (file) { + return { + base: path.dirname(resolvedPath), + content: file, + } + } + } + let file = await fsPromises.readFile(resolvedPath, 'utf-8') return { - path: resolvedPath, base: path.dirname(resolvedPath), content: file, } @@ -194,18 +193,12 @@ async function importModule(path: string): Promise { } } -const modules = [ - 'node_modules', - ...(process.env.NODE_PATH ? [...process.env.NODE_PATH.split(path.delimiter)] : []), -] - const cssResolver = EnhancedResolve.ResolverFactory.createResolver({ fileSystem: new EnhancedResolve.CachedInputFileSystem(fs, 4000), useSyncFileSystemCalls: true, extensions: ['.css'], mainFields: ['style'], conditionNames: ['style'], - modules, }) async function resolveCssId( id: string, @@ -234,7 +227,6 @@ const esmResolver = EnhancedResolve.ResolverFactory.createResolver({ useSyncFileSystemCalls: true, extensions: ['.js', '.json', '.node', '.ts'], conditionNames: ['node', 'import'], - modules, }) const cjsResolver = EnhancedResolve.ResolverFactory.createResolver({ @@ -242,7 +234,6 @@ const cjsResolver = EnhancedResolve.ResolverFactory.createResolver({ useSyncFileSystemCalls: true, extensions: ['.js', '.json', '.node', '.ts'], conditionNames: ['node', 'require'], - modules, }) async function resolveJsId( diff --git a/packages/@tailwindcss-node/src/env.ts b/packages/@tailwindcss-node/src/env.ts index 3b1a1b726..517ccc6c5 100644 --- a/packages/@tailwindcss-node/src/env.ts +++ b/packages/@tailwindcss-node/src/env.ts @@ -1,10 +1,6 @@ export const DEBUG = resolveDebug(process.env.DEBUG) function resolveDebug(debug: typeof process.env.DEBUG) { - if (typeof debug === 'boolean') { - return debug - } - if (debug === undefined) { return false } diff --git a/packages/@tailwindcss-node/src/esm-cache.loader.mts b/packages/@tailwindcss-node/src/esm-cache.loader.mts index 96d297a29..edcfc8d77 100644 --- a/packages/@tailwindcss-node/src/esm-cache.loader.mts +++ b/packages/@tailwindcss-node/src/esm-cache.loader.mts @@ -1,40 +1,22 @@ -import { - isBuiltin, - type ResolveFnOutput, - type ResolveHook, - type ResolveHookContext, - type ResolveHookSync, -} from 'node:module' +import { isBuiltin, type ResolveHook } from 'node:module' export let resolve: ResolveHook = async (specifier, context, nextResolve) => { let result = await nextResolve(specifier, context) - return processResolve(context, result) -} -export let resolveSync: ResolveHookSync = (specifier, context, nextResolve) => { - let result = nextResolve(specifier, context) - return processResolve(context, result) -} + if (result.url === import.meta.url) return result + if (isBuiltin(result.url)) return result + if (!context.parentURL) return result -function processResolve(context: ResolveHookContext, result: ResolveFnOutput) { - try { - if (result.url === import.meta.url) return result - if (isBuiltin(result.url)) return result - if (!context.parentURL) return result + let parent = new URL(context.parentURL) - let parent = new URL(context.parentURL) + let id = parent.searchParams.get('id') + if (id === null) return result - let id = parent.searchParams.get('id') - if (id === null) return result + let url = new URL(result.url) + url.searchParams.set('id', id) - let url = new URL(result.url) - url.searchParams.set('id', id) - - return { - ...result, - url: `${url}`, - } - } catch { - return result + return { + ...result, + url: `${url}`, } } diff --git a/packages/@tailwindcss-node/src/index.cts b/packages/@tailwindcss-node/src/index.cts index 9f2788933..2e79e25c7 100644 --- a/packages/@tailwindcss-node/src/index.cts +++ b/packages/@tailwindcss-node/src/index.cts @@ -1,26 +1,17 @@ import * as Module from 'node:module' import { pathToFileURL } from 'node:url' import * as env from './env' -import { resolveSync } from './esm-cache.loader.mjs' export * from './compile' export * from './instrumentation' export * from './normalize-path' -export * from './optimize' -export * from './source-maps' export { env } // In Bun, ESM modules will also populate `require.cache`, so the module hook is // not necessary. if (!process.versions.bun) { // `Module#register` was added in Node v18.19.0 and v20.6.0 - // `Module#registerHooks` was added in Node v22.15.0 and v23.5.0 and is the preferred API since v25.9.0, - // runtime-deprecating `Module#register` since v26 // // Not calling it means that while ESM dependencies don't get reloaded, the // actual included files will because they cache bust directly via `?id=…` - if (Module.registerHooks) { - Module.registerHooks({ resolve: resolveSync }) - } else { - Module.register?.(pathToFileURL(require.resolve('@tailwindcss/node/esm-cache-loader'))) - } + Module.register?.(pathToFileURL(require.resolve('@tailwindcss/node/esm-cache-loader'))) } diff --git a/packages/@tailwindcss-node/src/index.ts b/packages/@tailwindcss-node/src/index.ts index 8eff1466a..4ee2fe805 100644 --- a/packages/@tailwindcss-node/src/index.ts +++ b/packages/@tailwindcss-node/src/index.ts @@ -1,27 +1,19 @@ import * as Module from 'node:module' import { pathToFileURL } from 'node:url' import * as env from './env' -import { resolveSync } from './esm-cache.loader.mjs' -export * from './compile' +export { __unstable__loadDesignSystem, compile, compileAst, Features } from './compile' export * from './instrumentation' export * from './normalize-path' -export * from './optimize' -export * from './source-maps' export { env } // In Bun, ESM modules will also populate `require.cache`, so the module hook is // not necessary. if (!process.versions.bun) { + let localRequire = Module.createRequire(import.meta.url) + // `Module#register` was added in Node v18.19.0 and v20.6.0 - // `Module#registerHooks` was added in Node v22.15.0 and v23.5.0 and is the preferred API since v25.9.0, - // runtime-deprecating `Module#register` since v26 // // Not calling it means that while ESM dependencies don't get reloaded, the // actual included files will because they cache bust directly via `?id=…` - if (Module.registerHooks) { - Module.registerHooks({ resolve: resolveSync }) - } else { - let localRequire = Module.createRequire(import.meta.url) - Module.register?.(pathToFileURL(localRequire.resolve('@tailwindcss/node/esm-cache-loader'))) - } + Module.register?.(pathToFileURL(localRequire.resolve('@tailwindcss/node/esm-cache-loader'))) } diff --git a/packages/@tailwindcss-node/src/instrumentation.test.ts b/packages/@tailwindcss-node/src/instrumentation.test.ts index 102c7ed8e..1f06796fd 100644 --- a/packages/@tailwindcss-node/src/instrumentation.test.ts +++ b/packages/@tailwindcss-node/src/instrumentation.test.ts @@ -2,7 +2,7 @@ import { stripVTControlCharacters } from 'util' import { expect, it } from 'vitest' import { Instrumentation } from './instrumentation' -it('should add instrumentation using start/end markers', () => { +it('should add instrumentation', () => { let I = new Instrumentation() I.start('Foo') @@ -35,83 +35,6 @@ it('should add instrumentation using start/end markers', () => { }) }) -it('should measure callbacks via the `span` api', () => { - let I = new Instrumentation() - - I.span('Foo', () => { - let x = 1 - for (let i = 0; i < 100; i++) { - I.span('Bar', () => { - x **= 2 - }) - } - }) - - expect.assertions(1) - - I.report((output) => { - expect(stripVTControlCharacters(output).replace(/\[.*\]/g, '[0.xxms]')).toMatchInlineSnapshot(` - " - [0.xxms] Foo - [0.xxms] ↳ Bar × 100 - " - `) - }) -}) - -it('should measure async callbacks via the `span` api', async () => { - let I = new Instrumentation() - - await I.span('Foo', async () => { - let x = 1 - for (let i = 0; i < 100; i++) { - I.span('Bar', () => { - x **= 2 - }) - } - await new Promise((r) => setTimeout(r, 500)) - }) - - expect.assertions(2) - - I.report((output) => { - expect(stripVTControlCharacters(output).replace(/\[.*\]/g, '[0.xxms]')).toMatchInlineSnapshot(` - " - [0.xxms] Foo - [0.xxms] ↳ Bar × 100 - " - `) - - let [, duration] = stripVTControlCharacters(output).match(/\[(.*)\]/)! - expect(parseFloat(duration)).toBeGreaterThanOrEqual(500 - 2 /* Margin of error */) - }) -}) - -it('should measure blocks until they go out of scope via `using`', () => { - let I = new Instrumentation() - - { - using _ = I.track('Foo') - - let x = 1 - for (let i = 0; i < 100; i++) { - using _ = I.track('Bar') - x **= 2 - } - } - - expect.assertions(1) - - I.report((output) => { - expect(stripVTControlCharacters(output).replace(/\[.*\]/g, '[0.xxms]')).toMatchInlineSnapshot(` - " - [0.xxms] Foo - [0.xxms] ↳ Bar × 100 - " - `) - }) -}) - it('should auto end pending timers when reporting', () => { let I = new Instrumentation() diff --git a/packages/@tailwindcss-node/src/instrumentation.ts b/packages/@tailwindcss-node/src/instrumentation.ts index e454e6744..c408c4db7 100644 --- a/packages/@tailwindcss-node/src/instrumentation.ts +++ b/packages/@tailwindcss-node/src/instrumentation.ts @@ -1,21 +1,12 @@ import { DefaultMap } from '../../tailwindcss/src/utils/default-map' import * as env from './env' -// See: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-2.html#:~:text=Symbol.dispose,-??=%20Symbol(%22Symbol.dispose -// @ts-expect-error — Ensure Symbol.dispose exists -Symbol.dispose ??= Symbol('Symbol.dispose') -// @ts-expect-error — Ensure Symbol.asyncDispose exists -Symbol.asyncDispose ??= Symbol('Symbol.asyncDispose') - export class Instrumentation implements Disposable { #hits = new DefaultMap(() => ({ value: 0 })) #timers = new DefaultMap(() => ({ value: 0n })) #timerStack: { id: string; label: string; namespace: string; value: bigint }[] = [] - constructor( - private shouldReport = env.DEBUG, - private defaultFlush = (message: string) => void process.stderr.write(`${message}\n`), - ) {} + constructor(private defaultFlush = (message: string) => process.stderr.write(`${message}\n`)) {} hit(label: string) { this.#hits.get(label).value++ @@ -49,41 +40,6 @@ export class Instrumentation implements Disposable { this.#timers.get(parent.id).value += elapsed } - track(label: string) { - this.start(label) - let done = false - - return { - [Symbol.dispose]: () => { - if (!done) { - this.end(label) - done = true - } - }, - [Symbol.asyncDispose]: () => { - if (!done) { - this.end(label) - done = true - } - }, - } - } - - span(label: string, fn: () => T): T { - this.start(label) - let isPromise = false - try { - let result = fn() - - isPromise = result && typeof (result as any).then === 'function' - - // @ts-expect-error — TS can't infer that result is a Promise here - return isPromise ? result.finally(() => this.end(label)) : result - } finally { - if (!isPromise) this.end(label) - } - } - reset() { this.#hits.clear() this.#timers.clear() @@ -136,7 +92,7 @@ export class Instrumentation implements Disposable { } [Symbol.dispose]() { - this.shouldReport && this.report() + env.DEBUG && this.report() } } diff --git a/packages/@tailwindcss-node/src/optimize.ts b/packages/@tailwindcss-node/src/optimize.ts deleted file mode 100644 index 2f0d39589..000000000 --- a/packages/@tailwindcss-node/src/optimize.ts +++ /dev/null @@ -1,155 +0,0 @@ -import remapping from '@jridgewell/remapping' -import { Features, transform } from 'lightningcss' -import MagicString from 'magic-string' - -export interface OptimizeOptions { - /** - * The file being transformed - */ - file?: string - - /** - * Enabled minified output - */ - minify?: boolean - - /** - * The output source map before optimization - * - * If omitted a resulting source map will not be available - */ - map?: string -} - -export interface TransformResult { - code: string - map: string | undefined -} - -export function optimize( - input: string, - { file = 'input.css', minify = false, map }: OptimizeOptions = {}, -): TransformResult { - function optimize(code: Buffer | Uint8Array, map: string | undefined) { - return transform({ - filename: file, - code, - minify, - sourceMap: typeof map !== 'undefined', - inputSourceMap: map, - drafts: { - customMedia: true, - }, - nonStandard: { - deepSelectorCombinator: true, - }, - include: Features.Nesting | Features.MediaQueries, - exclude: Features.LogicalProperties | Features.DirSelector | Features.LightDark, - targets: { - safari: (16 << 16) | (4 << 8), - ios_saf: (16 << 16) | (4 << 8), - firefox: 128 << 16, - chrome: 111 << 16, - }, - errorRecovery: true, - }) - } - - // Running Lightning CSS twice to ensure that adjacent rules are merged after - // nesting is applied. This creates a more optimized output. - let result = optimize(Buffer.from(input), map) - map = result.map?.toString() - - result.warnings = result.warnings.filter((warning) => { - // Ignore warnings about unknown pseudo-classes that are used in frameworks - // such as Vue or Angular and are handled by their own compilers, before - // reaching the browser. - if ( - /'(deep|slotted|global|ng-deep|host-context)' is not recognized as a valid pseudo-/.test( - warning.message, - ) - ) { - return false - } - - return true - }) - - // Because of `errorRecovery: true`, there could be warnings, so let's let the - // user know about them. - if (process.env.NODE_ENV !== 'test' && result.warnings.length > 0) { - let lines = input.split('\n') - - let output = [ - `Found ${result.warnings.length} ${result.warnings.length === 1 ? 'warning' : 'warnings'} while optimizing generated CSS:`, - ] - - for (let [idx, warning] of result.warnings.entries()) { - output.push('') - if (result.warnings.length > 1) { - output.push(`Issue #${idx + 1}:`) - } - - let context = 2 - - let start = Math.max(0, warning.loc.line - context - 1) - let end = Math.min(lines.length, warning.loc.line + context) - - let snippet = lines.slice(start, end).map((line, idx) => { - if (start + idx + 1 === warning.loc.line) { - return `${dim(`\u2502`)} ${line}` - } else { - return dim(`\u2502 ${line}`) - } - }) - - snippet.splice( - warning.loc.line - start, - 0, - `${dim('\u2506')}${' '.repeat(warning.loc.column - 1)} ${yellow(`${dim('^--')} ${warning.message}`)}`, - `${dim('\u2506')}`, - ) - - output.push(...snippet) - } - output.push('') - - console.warn(output.join('\n')) - } - - result = optimize(result.code, map) - map = result.map?.toString() - - let code = result.code.toString() - - // Work around an issue where the media query range syntax transpilation - // generates code that is invalid with `@media` queries level 3. - let magic = new MagicString(code) - magic.replaceAll('@media not (', '@media not all and (') - - // We have to use a source-map-preserving method of replacing the content - // which requires the use of Magic String + remapping(…) to make sure - // the resulting map is correct - if (map !== undefined && magic.hasChanged()) { - let magicMap = magic.generateMap({ source: 'original', hires: 'boundary' }).toString() - - let remapped = remapping([magicMap, map], () => null) - - map = remapped.toString() - } - - code = magic.toString() - - return { - code, - map, - } -} - -function dim(str: string) { - return `\x1B[2m${str}\x1B[22m` -} - -function yellow(str: string) { - return `\x1B[33m${str}\x1B[39m` -} diff --git a/packages/@tailwindcss-node/src/require-cache.ts b/packages/@tailwindcss-node/src/require-cache.ts deleted file mode 100644 index ea0562019..000000000 --- a/packages/@tailwindcss-node/src/require-cache.ts +++ /dev/null @@ -1,5 +0,0 @@ -export function clearRequireCache(files: string[]) { - for (let key of files) { - delete require.cache[key] - } -} diff --git a/packages/@tailwindcss-node/src/source-maps.test.ts b/packages/@tailwindcss-node/src/source-maps.test.ts deleted file mode 100644 index 96ff8f05c..000000000 --- a/packages/@tailwindcss-node/src/source-maps.test.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { expect, it } from 'vitest' -import { toSourceMap } from './source-maps' - -it('should emit source maps', () => { - let map = toSourceMap('{"version":3,"sources":[],"names":[],"mappings":""}') - - expect(map.comment('app.css.map')).toBe('/*# sourceMappingURL=app.css.map */\n') -}) diff --git a/packages/@tailwindcss-node/src/source-maps.ts b/packages/@tailwindcss-node/src/source-maps.ts deleted file mode 100644 index 58b79cb25..000000000 --- a/packages/@tailwindcss-node/src/source-maps.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { SourceMapGenerator } from 'source-map-js' -import type { DecodedSource, DecodedSourceMap } from '../../tailwindcss/src/source-maps/source-map' -import { DefaultMap } from '../../tailwindcss/src/utils/default-map' - -export type { DecodedSource, DecodedSourceMap } -export interface SourceMap { - readonly raw: string - readonly inline: string - comment(url: string): string -} - -function serializeSourceMap(map: DecodedSourceMap): string { - let generator = new SourceMapGenerator() - - let id = 1 - let sourceTable = new DefaultMap< - DecodedSource | null, - { - url: string - content: string - } - >((src) => { - return { - url: src?.url ?? ``, - content: src?.content ?? '', - } - }) - - for (let mapping of map.mappings) { - let original = sourceTable.get(mapping.originalPosition?.source ?? null) - - generator.addMapping({ - generated: mapping.generatedPosition, - original: mapping.originalPosition, - source: original.url, - name: mapping.name, - }) - - generator.setSourceContent(original.url, original.content) - } - - return generator.toString() -} - -export function toSourceMap(map: DecodedSourceMap | string): SourceMap { - let raw = typeof map === 'string' ? map : serializeSourceMap(map) - - function comment(url: string) { - return `/*# sourceMappingURL\x3d${url} */\n` - } - - return { - raw, - get inline() { - let inlined = Buffer.from(raw, 'utf-8').toString('base64') - return comment(`data:application/json;base64,${inlined}`) - }, - comment, - } -} diff --git a/packages/@tailwindcss-node/src/urls.test.ts b/packages/@tailwindcss-node/src/urls.test.ts index 16ba352a7..3378e45ed 100644 --- a/packages/@tailwindcss-node/src/urls.test.ts +++ b/packages/@tailwindcss-node/src/urls.test.ts @@ -24,20 +24,6 @@ test('URLs can be rewritten', async () => { background: url('/image.jpg'); background: url("/image.jpg"); - /* Potentially Vite-aliased URLs: ignored */ - background: url(~/image.jpg); - background: url(~/foo/image.jpg); - background: url('~/image.jpg'); - background: url("~/image.jpg"); - background: url(#/image.jpg); - background: url(#/foo/image.jpg); - background: url('#/image.jpg'); - background: url("#/image.jpg"); - background: url(@/image.jpg); - background: url(@/foo/image.jpg); - background: url('@/image.jpg'); - background: url("@/image.jpg"); - /* External URL: ignored */ background: url(http://example.com/image.jpg); background: url('http://example.com/image.jpg'); @@ -123,18 +109,6 @@ test('URLs can be rewritten', async () => { background: url(/foo/image.jpg); background: url('/image.jpg'); background: url("/image.jpg"); - background: url(~/image.jpg); - background: url(~/foo/image.jpg); - background: url('~/image.jpg'); - background: url("~/image.jpg"); - background: url(#/image.jpg); - background: url(#/foo/image.jpg); - background: url('#/image.jpg'); - background: url("#/image.jpg"); - background: url(@/image.jpg); - background: url(@/foo/image.jpg); - background: url('@/image.jpg'); - background: url("@/image.jpg"); background: url(http://example.com/image.jpg); background: url('http://example.com/image.jpg'); background: url("http://example.com/image.jpg"); diff --git a/packages/@tailwindcss-node/src/urls.ts b/packages/@tailwindcss-node/src/urls.ts index 61695a9d1..c4d56deb7 100644 --- a/packages/@tailwindcss-node/src/urls.ts +++ b/packages/@tailwindcss-node/src/urls.ts @@ -5,9 +5,8 @@ // Minor modifications have been made to work with the Tailwind CSS codebase import * as path from 'node:path' -import { toCss } from '../../tailwindcss/src/ast' +import { toCss, walk } from '../../tailwindcss/src/ast' import { parse } from '../../tailwindcss/src/css-parser' -import { walk } from '../../tailwindcss/src/walk' import { normalizePath } from './normalize-path' const cssUrlRE = @@ -150,12 +149,9 @@ async function doUrlReplace( return `${funcName}(${wrap}${newUrl}${wrap})` } -function skipUrlReplacer(rawUrl: string, aliases?: string[]) { +function skipUrlReplacer(rawUrl: string) { return ( - isExternalUrl(rawUrl) || - isDataUrl(rawUrl) || - !rawUrl[0].match(/[.a-zA-Z0-9_]/) || - functionCallRE.test(rawUrl) + isExternalUrl(rawUrl) || isDataUrl(rawUrl) || rawUrl[0] === '#' || functionCallRE.test(rawUrl) ) } diff --git a/packages/@tailwindcss-node/tsconfig.json b/packages/@tailwindcss-node/tsconfig.json index d2131cbeb..6ae022f65 100644 --- a/packages/@tailwindcss-node/tsconfig.json +++ b/packages/@tailwindcss-node/tsconfig.json @@ -1,6 +1,3 @@ { "extends": "../tsconfig.base.json", - "compilerOptions": { - "verbatimModuleSyntax": false, - }, } diff --git a/packages/@tailwindcss-node/tsup.config.ts b/packages/@tailwindcss-node/tsup.config.ts index 3f2d184d5..0f2ac5855 100644 --- a/packages/@tailwindcss-node/tsup.config.ts +++ b/packages/@tailwindcss-node/tsup.config.ts @@ -6,35 +6,23 @@ export default defineConfig([ minify: true, dts: true, entry: ['src/index.cts'], - define: { - 'process.env.NODE_ENV': '"production"', - }, }, { format: ['esm'], minify: true, dts: true, entry: ['src/index.ts'], - define: { - 'process.env.NODE_ENV': '"production"', - }, }, { format: ['esm'], minify: true, dts: true, entry: ['src/esm-cache.loader.mts'], - define: { - 'process.env.NODE_ENV': '"production"', - }, }, { format: ['cjs'], minify: true, dts: true, entry: ['src/require-cache.cts'], - define: { - 'process.env.NODE_ENV': '"production"', - }, }, ]) diff --git a/packages/@tailwindcss-postcss/README.md b/packages/@tailwindcss-postcss/README.md index 3facf2887..95ec9d87d 100644 --- a/packages/@tailwindcss-postcss/README.md +++ b/packages/@tailwindcss-postcss/README.md @@ -13,10 +13,10 @@

- Build Status + Build Status Total Downloads - Latest Release - License + Latest Release + License

--- @@ -27,85 +27,14 @@ For full documentation, visit [tailwindcss.com](https://tailwindcss.com). ## Community -For help, discussion about best practices, or feature ideas: +For help, discussion about best practices, or any other conversation that would benefit from being searchable: -[Discuss Tailwind CSS on GitHub](https://github.com/tailwindlabs/tailwindcss/discussions) +[Discuss Tailwind CSS on GitHub](https://github.com/tailwindcss/tailwindcss/discussions) + +For chatting with others using the framework: + +[Join the Tailwind CSS Discord Server](https://discord.gg/7NF8GNe) ## Contributing -If you're interested in contributing to Tailwind CSS, please read our [contributing docs](https://github.com/tailwindlabs/tailwindcss/blob/main/.github/CONTRIBUTING.md) **before submitting a pull request**. - ---- - -## `@tailwindcss/postcss` plugin API - -### Changing where the plugin searches for source files - -You can use the `base` option (defaults to the current working directory) to change the directory in which the plugin searches for source files: - -```js -import tailwindcss from '@tailwindcss/postcss' - -export default { - plugins: [ - tailwindcss({ - base: path.resolve(__dirname, './path'), - }), - ], -} -``` - -### Enabling or disabling Lightning CSS - -By default, this plugin detects whether or not the CSS is being built for production by checking the `NODE_ENV` environment variable. When building for production Lightning CSS will be enabled otherwise it is disabled. - -If you want to always enable or disable Lightning CSS the `optimize` option may be used: - -```js -import tailwindcss from '@tailwindcss/postcss' - -export default { - plugins: [ - tailwindcss({ - // Enable or disable Lightning CSS - optimize: false, - }), - ], -} -``` - -It's also possible to keep Lightning CSS enabled but disable minification: - -```js -import tailwindcss from '@tailwindcss/postcss' - -export default { - plugins: [ - tailwindcss({ - optimize: { minify: false }, - }), - ], -} -``` - -### Enabling or disabling `url(…)` rewriting - -Our PostCSS plugin can rewrite `url(…)`s for you since it also handles `@import` (no `postcss-import` is needed). This feature is enabled by default. - -In some situations the bundler or framework you're using may provide this feature itself. In this case you can set `transformAssetUrls` to `false` to disable this feature: - -```js -import tailwindcss from '@tailwindcss/postcss' - -export default { - plugins: [ - tailwindcss({ - // Disable `url(…)` rewriting - transformAssetUrls: false, - - // Enable `url(…)` rewriting (the default) - transformAssetUrls: true, - }), - ], -} -``` +If you're interested in contributing to Tailwind CSS, please read our [contributing docs](https://github.com/tailwindcss/tailwindcss/blob/next/.github/CONTRIBUTING.md) **before submitting a pull request**. diff --git a/packages/@tailwindcss-postcss/package.json b/packages/@tailwindcss-postcss/package.json index 891578509..7e567a8d0 100644 --- a/packages/@tailwindcss-postcss/package.json +++ b/packages/@tailwindcss-postcss/package.json @@ -1,6 +1,6 @@ { "name": "@tailwindcss/postcss", - "version": "4.3.3", + "version": "4.0.0-beta.7", "description": "PostCSS plugin for Tailwind CSS, a utility-first CSS framework for rapidly building custom user interfaces", "license": "MIT", "repository": { @@ -24,28 +24,24 @@ }, "exports": { ".": { - "import": { - "types": "./dist/index.d.mts", - "default": "./dist/index.mjs" - }, - "require": { - "types": "./dist/index.d.ts", - "default": "./dist/index.js" - } + "types": "./dist/index.d.ts", + "import": "./dist/index.mjs", + "require": "./dist/index.js" } }, "dependencies": { "@alloc/quick-lru": "^5.2.0", - "@tailwindcss/node": "workspace:*", - "@tailwindcss/oxide": "workspace:*", - "postcss": "catalog:", + "@tailwindcss/node": "workspace:^", + "@tailwindcss/oxide": "workspace:^", + "lightningcss": "catalog:", + "postcss": "^8.4.41", "tailwindcss": "workspace:*" }, "devDependencies": { "@types/node": "catalog:", "@types/postcss-import": "14.0.3", - "dedent": "catalog:", + "dedent": "1.5.3", "internal-example-plugin": "workspace:*", - "postcss-import": "^16.1.1" + "postcss-import": "^16.1.0" } } diff --git a/packages/@tailwindcss-postcss/src/__snapshots__/index.test.ts.snap b/packages/@tailwindcss-postcss/src/__snapshots__/index.test.ts.snap index 05087fa39..cf0794ff2 100644 --- a/packages/@tailwindcss-postcss/src/__snapshots__/index.test.ts.snap +++ b/packages/@tailwindcss-postcss/src/__snapshots__/index.test.ts.snap @@ -1,27 +1,373 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html exports[`\`@import 'tailwindcss'\` is replaced with the generated CSS 1`] = ` -" -@layer properties { - @supports (((-webkit-hyphens: none)) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color: rgb(from red r g b)))) { - *, :before, :after, ::backdrop { - --tw-font-weight: initial; - } - } -} - -@layer theme { - :root, :host { - --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, - sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; - --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", - monospace; +"@layer theme { + :root { + --font-sans: ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + --font-serif: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif; + --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; + --color-red-50: oklch(.971 .013 17.38); + --color-red-100: oklch(.936 .032 17.717); + --color-red-200: oklch(.885 .062 18.334); + --color-red-300: oklch(.808 .114 19.571); + --color-red-400: oklch(.704 .191 22.216); + --color-red-500: oklch(.637 .237 25.331); + --color-red-600: oklch(.577 .245 27.325); + --color-red-700: oklch(.505 .213 27.518); + --color-red-800: oklch(.444 .177 26.899); + --color-red-900: oklch(.396 .141 25.723); + --color-red-950: oklch(.258 .092 26.042); + --color-orange-50: oklch(.98 .016 73.684); + --color-orange-100: oklch(.954 .038 75.164); + --color-orange-200: oklch(.901 .076 70.697); + --color-orange-300: oklch(.837 .128 66.29); + --color-orange-400: oklch(.75 .183 55.934); + --color-orange-500: oklch(.705 .213 47.604); + --color-orange-600: oklch(.646 .222 41.116); + --color-orange-700: oklch(.553 .195 38.402); + --color-orange-800: oklch(.47 .157 37.304); + --color-orange-900: oklch(.408 .123 38.172); + --color-orange-950: oklch(.266 .079 36.259); + --color-amber-50: oklch(.987 .022 95.277); + --color-amber-100: oklch(.962 .059 95.617); + --color-amber-200: oklch(.924 .12 95.746); + --color-amber-300: oklch(.879 .169 91.605); + --color-amber-400: oklch(.828 .189 84.429); + --color-amber-500: oklch(.769 .188 70.08); + --color-amber-600: oklch(.666 .179 58.318); + --color-amber-700: oklch(.555 .163 48.998); + --color-amber-800: oklch(.473 .137 46.201); + --color-amber-900: oklch(.414 .112 45.904); + --color-amber-950: oklch(.279 .077 45.635); + --color-yellow-50: oklch(.987 .026 102.212); + --color-yellow-100: oklch(.973 .071 103.193); + --color-yellow-200: oklch(.945 .129 101.54); + --color-yellow-300: oklch(.905 .182 98.111); + --color-yellow-400: oklch(.852 .199 91.936); + --color-yellow-500: oklch(.795 .184 86.047); + --color-yellow-600: oklch(.681 .162 75.834); + --color-yellow-700: oklch(.554 .135 66.442); + --color-yellow-800: oklch(.476 .114 61.907); + --color-yellow-900: oklch(.421 .095 57.708); + --color-yellow-950: oklch(.286 .066 53.813); + --color-lime-50: oklch(.986 .031 120.757); + --color-lime-100: oklch(.967 .067 122.328); + --color-lime-200: oklch(.938 .127 124.321); + --color-lime-300: oklch(.897 .196 126.665); + --color-lime-400: oklch(.841 .238 128.85); + --color-lime-500: oklch(.768 .233 130.85); + --color-lime-600: oklch(.648 .2 131.684); + --color-lime-700: oklch(.532 .157 131.589); + --color-lime-800: oklch(.453 .124 130.933); + --color-lime-900: oklch(.405 .101 131.063); + --color-lime-950: oklch(.274 .072 132.109); + --color-green-50: oklch(.982 .018 155.826); + --color-green-100: oklch(.962 .044 156.743); + --color-green-200: oklch(.925 .084 155.995); + --color-green-300: oklch(.871 .15 154.449); + --color-green-400: oklch(.792 .209 151.711); + --color-green-500: oklch(.723 .219 149.579); + --color-green-600: oklch(.627 .194 149.214); + --color-green-700: oklch(.527 .154 150.069); + --color-green-800: oklch(.448 .119 151.328); + --color-green-900: oklch(.393 .095 152.535); + --color-green-950: oklch(.266 .065 152.934); + --color-emerald-50: oklch(.979 .021 166.113); + --color-emerald-100: oklch(.95 .052 163.051); + --color-emerald-200: oklch(.905 .093 164.15); + --color-emerald-300: oklch(.845 .143 164.978); + --color-emerald-400: oklch(.765 .177 163.223); + --color-emerald-500: oklch(.696 .17 162.48); + --color-emerald-600: oklch(.596 .145 163.225); + --color-emerald-700: oklch(.508 .118 165.612); + --color-emerald-800: oklch(.432 .095 166.913); + --color-emerald-900: oklch(.378 .077 168.94); + --color-emerald-950: oklch(.262 .051 172.552); + --color-teal-50: oklch(.984 .014 180.72); + --color-teal-100: oklch(.953 .051 180.801); + --color-teal-200: oklch(.91 .096 180.426); + --color-teal-300: oklch(.855 .138 181.071); + --color-teal-400: oklch(.777 .152 181.912); + --color-teal-500: oklch(.704 .14 182.503); + --color-teal-600: oklch(.6 .118 184.704); + --color-teal-700: oklch(.511 .096 186.391); + --color-teal-800: oklch(.437 .078 188.216); + --color-teal-900: oklch(.386 .063 188.416); + --color-teal-950: oklch(.277 .046 192.524); + --color-cyan-50: oklch(.984 .019 200.873); + --color-cyan-100: oklch(.956 .045 203.388); + --color-cyan-200: oklch(.917 .08 205.041); + --color-cyan-300: oklch(.865 .127 207.078); + --color-cyan-400: oklch(.789 .154 211.53); + --color-cyan-500: oklch(.715 .143 215.221); + --color-cyan-600: oklch(.609 .126 221.723); + --color-cyan-700: oklch(.52 .105 223.128); + --color-cyan-800: oklch(.45 .085 224.283); + --color-cyan-900: oklch(.398 .07 227.392); + --color-cyan-950: oklch(.302 .056 229.695); + --color-sky-50: oklch(.977 .013 236.62); + --color-sky-100: oklch(.951 .026 236.824); + --color-sky-200: oklch(.901 .058 230.902); + --color-sky-300: oklch(.828 .111 230.318); + --color-sky-400: oklch(.746 .16 232.661); + --color-sky-500: oklch(.685 .169 237.323); + --color-sky-600: oklch(.588 .158 241.966); + --color-sky-700: oklch(.5 .134 242.749); + --color-sky-800: oklch(.443 .11 240.79); + --color-sky-900: oklch(.391 .09 240.876); + --color-sky-950: oklch(.293 .066 243.157); + --color-blue-50: oklch(.97 .014 254.604); + --color-blue-100: oklch(.932 .032 255.585); + --color-blue-200: oklch(.882 .059 254.128); + --color-blue-300: oklch(.809 .105 251.813); + --color-blue-400: oklch(.707 .165 254.624); + --color-blue-500: oklch(.623 .214 259.815); + --color-blue-600: oklch(.546 .245 262.881); + --color-blue-700: oklch(.488 .243 264.376); + --color-blue-800: oklch(.424 .199 265.638); + --color-blue-900: oklch(.379 .146 265.522); + --color-blue-950: oklch(.282 .091 267.935); + --color-indigo-50: oklch(.962 .018 272.314); + --color-indigo-100: oklch(.93 .034 272.788); + --color-indigo-200: oklch(.87 .065 274.039); + --color-indigo-300: oklch(.785 .115 274.713); + --color-indigo-400: oklch(.673 .182 276.935); + --color-indigo-500: oklch(.585 .233 277.117); + --color-indigo-600: oklch(.511 .262 276.966); + --color-indigo-700: oklch(.457 .24 277.023); + --color-indigo-800: oklch(.398 .195 277.366); + --color-indigo-900: oklch(.359 .144 278.697); + --color-indigo-950: oklch(.257 .09 281.288); + --color-violet-50: oklch(.969 .016 293.756); + --color-violet-100: oklch(.943 .029 294.588); + --color-violet-200: oklch(.894 .057 293.283); + --color-violet-300: oklch(.811 .111 293.571); + --color-violet-400: oklch(.702 .183 293.541); + --color-violet-500: oklch(.606 .25 292.717); + --color-violet-600: oklch(.541 .281 293.009); + --color-violet-700: oklch(.491 .27 292.581); + --color-violet-800: oklch(.432 .232 292.759); + --color-violet-900: oklch(.38 .189 293.745); + --color-violet-950: oklch(.283 .141 291.089); + --color-purple-50: oklch(.977 .014 308.299); + --color-purple-100: oklch(.946 .033 307.174); + --color-purple-200: oklch(.902 .063 306.703); + --color-purple-300: oklch(.827 .119 306.383); + --color-purple-400: oklch(.714 .203 305.504); + --color-purple-500: oklch(.627 .265 303.9); + --color-purple-600: oklch(.558 .288 302.321); + --color-purple-700: oklch(.496 .265 301.924); + --color-purple-800: oklch(.438 .218 303.724); + --color-purple-900: oklch(.381 .176 304.987); + --color-purple-950: oklch(.291 .149 302.717); + --color-fuchsia-50: oklch(.977 .017 320.058); + --color-fuchsia-100: oklch(.952 .037 318.852); + --color-fuchsia-200: oklch(.903 .076 319.62); + --color-fuchsia-300: oklch(.833 .145 321.434); + --color-fuchsia-400: oklch(.74 .238 322.16); + --color-fuchsia-500: oklch(.667 .295 322.15); + --color-fuchsia-600: oklch(.591 .293 322.896); + --color-fuchsia-700: oklch(.518 .253 323.949); + --color-fuchsia-800: oklch(.452 .211 324.591); + --color-fuchsia-900: oklch(.401 .17 325.612); + --color-fuchsia-950: oklch(.293 .136 325.661); + --color-pink-50: oklch(.971 .014 343.198); + --color-pink-100: oklch(.948 .028 342.258); + --color-pink-200: oklch(.899 .061 343.231); + --color-pink-300: oklch(.823 .12 346.018); + --color-pink-400: oklch(.718 .202 349.761); + --color-pink-500: oklch(.656 .241 354.308); + --color-pink-600: oklch(.592 .249 .584); + --color-pink-700: oklch(.525 .223 3.958); + --color-pink-800: oklch(.459 .187 3.815); + --color-pink-900: oklch(.408 .153 2.432); + --color-pink-950: oklch(.284 .109 3.907); + --color-rose-50: oklch(.969 .015 12.422); + --color-rose-100: oklch(.941 .03 12.58); + --color-rose-200: oklch(.892 .058 10.001); + --color-rose-300: oklch(.81 .117 11.638); + --color-rose-400: oklch(.712 .194 13.428); + --color-rose-500: oklch(.645 .246 16.439); + --color-rose-600: oklch(.586 .253 17.585); + --color-rose-700: oklch(.514 .222 16.935); + --color-rose-800: oklch(.455 .188 13.697); + --color-rose-900: oklch(.41 .159 10.272); + --color-rose-950: oklch(.271 .105 12.094); + --color-slate-50: oklch(.984 .003 247.858); + --color-slate-100: oklch(.968 .007 247.896); + --color-slate-200: oklch(.929 .013 255.508); + --color-slate-300: oklch(.869 .022 252.894); + --color-slate-400: oklch(.704 .04 256.788); + --color-slate-500: oklch(.554 .046 257.417); + --color-slate-600: oklch(.446 .043 257.281); + --color-slate-700: oklch(.372 .044 257.287); + --color-slate-800: oklch(.279 .041 260.031); + --color-slate-900: oklch(.208 .042 265.755); + --color-slate-950: oklch(.129 .042 264.695); + --color-gray-50: oklch(.985 .002 247.839); + --color-gray-100: oklch(.967 .003 264.542); + --color-gray-200: oklch(.928 .006 264.531); + --color-gray-300: oklch(.872 .01 258.338); + --color-gray-400: oklch(.707 .022 261.325); + --color-gray-500: oklch(.551 .027 264.364); + --color-gray-600: oklch(.446 .03 256.802); + --color-gray-700: oklch(.373 .034 259.733); + --color-gray-800: oklch(.278 .033 256.848); + --color-gray-900: oklch(.21 .034 264.665); + --color-gray-950: oklch(.13 .028 261.692); + --color-zinc-50: oklch(.985 0 0); + --color-zinc-100: oklch(.967 .001 286.375); + --color-zinc-200: oklch(.92 .004 286.32); + --color-zinc-300: oklch(.871 .006 286.286); + --color-zinc-400: oklch(.705 .015 286.067); + --color-zinc-500: oklch(.552 .016 285.938); + --color-zinc-600: oklch(.442 .017 285.786); + --color-zinc-700: oklch(.37 .013 285.805); + --color-zinc-800: oklch(.274 .006 286.033); + --color-zinc-900: oklch(.21 .006 285.885); + --color-zinc-950: oklch(.141 .005 285.823); + --color-neutral-50: oklch(.985 0 0); + --color-neutral-100: oklch(.97 0 0); + --color-neutral-200: oklch(.922 0 0); + --color-neutral-300: oklch(.87 0 0); + --color-neutral-400: oklch(.708 0 0); + --color-neutral-500: oklch(.556 0 0); + --color-neutral-600: oklch(.439 0 0); + --color-neutral-700: oklch(.371 0 0); + --color-neutral-800: oklch(.269 0 0); + --color-neutral-900: oklch(.205 0 0); + --color-neutral-950: oklch(.145 0 0); + --color-stone-50: oklch(.985 .001 106.423); + --color-stone-100: oklch(.97 .001 106.424); + --color-stone-200: oklch(.923 .003 48.717); + --color-stone-300: oklch(.869 .005 56.366); + --color-stone-400: oklch(.709 .01 56.259); + --color-stone-500: oklch(.553 .013 58.071); + --color-stone-600: oklch(.444 .011 73.639); + --color-stone-700: oklch(.374 .01 67.558); + --color-stone-800: oklch(.268 .007 34.298); + --color-stone-900: oklch(.216 .006 56.043); + --color-stone-950: oklch(.147 .004 49.25); --color-black: #000; + --color-white: #fff; + --spacing: .25rem; + --breakpoint-sm: 40rem; + --breakpoint-md: 48rem; + --breakpoint-lg: 64rem; + --breakpoint-xl: 80rem; + --breakpoint-2xl: 96rem; + --container-3xs: 16rem; + --container-2xs: 18rem; + --container-xs: 20rem; + --container-sm: 24rem; + --container-md: 28rem; + --container-lg: 32rem; + --container-xl: 36rem; + --container-2xl: 42rem; + --container-3xl: 48rem; + --container-4xl: 56rem; + --container-5xl: 64rem; + --container-6xl: 72rem; + --container-7xl: 80rem; + --container-prose: 65ch; + --text-xs: .75rem; + --text-xs--line-height: calc(1 / .75); + --text-sm: .875rem; + --text-sm--line-height: calc(1.25 / .875); + --text-base: 1rem; + --text-base--line-height: calc(1.5 / 1); + --text-lg: 1.125rem; + --text-lg--line-height: calc(1.75 / 1.125); + --text-xl: 1.25rem; + --text-xl--line-height: calc(1.75 / 1.25); --text-2xl: 1.5rem; --text-2xl--line-height: calc(2 / 1.5); + --text-3xl: 1.875rem; + --text-3xl--line-height: calc(2.25 / 1.875); + --text-4xl: 2.25rem; + --text-4xl--line-height: calc(2.5 / 2.25); + --text-5xl: 3rem; + --text-5xl--line-height: 1; + --text-6xl: 3.75rem; + --text-6xl--line-height: 1; + --text-7xl: 4.5rem; + --text-7xl--line-height: 1; + --text-8xl: 6rem; + --text-8xl--line-height: 1; + --text-9xl: 8rem; + --text-9xl--line-height: 1; + --font-weight-thin: 100; + --font-weight-extralight: 200; + --font-weight-light: 300; + --font-weight-normal: 400; + --font-weight-medium: 500; + --font-weight-semibold: 600; --font-weight-bold: 700; + --font-weight-extrabold: 800; + --font-weight-black: 900; + --tracking-tighter: -.05em; + --tracking-tight: -.025em; + --tracking-normal: 0em; + --tracking-wide: .025em; + --tracking-wider: .05em; + --tracking-widest: .1em; + --leading-tight: 1.25; + --leading-snug: 1.375; + --leading-normal: 1.5; + --leading-relaxed: 1.625; + --leading-loose: 2; + --radius-xs: .125rem; + --radius-sm: .25rem; + --radius-md: .375rem; + --radius-lg: .5rem; + --radius-xl: .75rem; + --radius-2xl: 1rem; + --radius-3xl: 1.5rem; + --radius-4xl: 2rem; + --shadow-2xs: 0 1px #0000000d; + --shadow-xs: 0 1px 2px 0 #0000000d; + --shadow-sm: 0 1px 3px 0 #0000001a, 0 1px 2px -1px #0000001a; + --shadow-md: 0 4px 6px -1px #0000001a, 0 2px 4px -2px #0000001a; + --shadow-lg: 0 10px 15px -3px #0000001a, 0 4px 6px -4px #0000001a; + --shadow-xl: 0 20px 25px -5px #0000001a, 0 8px 10px -6px #0000001a; + --shadow-2xl: 0 25px 50px -12px #00000040; + --inset-shadow-2xs: inset 0 1px #0000000d; + --inset-shadow-xs: inset 0 1px 1px #0000000d; + --inset-shadow-sm: inset 0 2px 4px #0000000d; + --drop-shadow-xs: 0 1px 1px #0000000d; + --drop-shadow-sm: 0 1px 2px #00000026; + --drop-shadow-md: 0 3px 3px #0000001f; + --drop-shadow-lg: 0 4px 4px #00000026; + --drop-shadow-xl: 0 9px 7px #0000001a; + --drop-shadow-2xl: 0 25px 25px #00000026; + --ease-in: cubic-bezier(.4, 0, 1, 1); + --ease-out: cubic-bezier(0, 0, .2, 1); + --ease-in-out: cubic-bezier(.4, 0, .2, 1); + --animate-spin: spin 1s linear infinite; + --animate-ping: ping 1s cubic-bezier(0, 0, .2, 1) infinite; + --animate-pulse: pulse 2s cubic-bezier(.4, 0, .6, 1) infinite; + --animate-bounce: bounce 1s infinite; + --blur-xs: 4px; + --blur-sm: 8px; + --blur-md: 12px; + --blur-lg: 16px; + --blur-xl: 24px; + --blur-2xl: 40px; + --blur-3xl: 64px; + --perspective-dramatic: 100px; + --perspective-near: 300px; + --perspective-normal: 500px; + --perspective-midrange: 800px; + --perspective-distant: 1200px; + --aspect-video: 16 / 9; + --default-transition-duration: .15s; + --default-transition-timing-function: cubic-bezier(.4, 0, .2, 1); --default-font-family: var(--font-sans); + --default-font-feature-settings: var(--font-sans--font-feature-settings); + --default-font-variation-settings: var(--font-sans--font-variation-settings); --default-mono-font-family: var(--font-mono); + --default-mono-font-feature-settings: var(--font-mono--font-feature-settings); + --default-mono-font-variation-settings: var(--font-mono--font-variation-settings); } } @@ -44,16 +390,20 @@ exports[`\`@import 'tailwindcss'\` is replaced with the generated CSS 1`] = ` -webkit-text-size-adjust: 100%; tab-size: 4; line-height: 1.5; - font-family: var(--default-font-family, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"); + font-family: var(--default-font-family, ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"); font-feature-settings: var(--default-font-feature-settings, normal); font-variation-settings: var(--default-font-variation-settings, normal); -webkit-tap-highlight-color: transparent; } + body { + line-height: inherit; + } + hr { - height: 0; color: inherit; border-top-width: 1px; + height: 0; } abbr:where([title]) { @@ -110,7 +460,7 @@ exports[`\`@import 'tailwindcss'\` is replaced with the generated CSS 1`] = ` border-collapse: collapse; } - :-moz-focusring:where(:not(iframe)) { + :-moz-focusring { outline: auto; } @@ -172,18 +522,7 @@ exports[`\`@import 'tailwindcss'\` is replaced with the generated CSS 1`] = ` ::placeholder { opacity: 1; - } - - @supports (not ((-webkit-appearance: -apple-pay-button))) or (contain-intrinsic-size: 1px) { - ::placeholder { - color: currentColor; - } - - @supports (color: color-mix(in lab, red, red)) { - ::placeholder { - color: color-mix(in oklab, currentcolor 50%, transparent); - } - } + color: color-mix(in oklab, currentColor 50%, transparent); } textarea { @@ -195,8 +534,8 @@ exports[`\`@import 'tailwindcss'\` is replaced with the generated CSS 1`] = ` } ::-webkit-date-and-time-value { - min-height: 1lh; text-align: inherit; + min-height: 1lh; } ::-webkit-datetime-edit { @@ -243,10 +582,6 @@ exports[`\`@import 'tailwindcss'\` is replaced with the generated CSS 1`] = ` padding-block: 0; } - ::-webkit-calendar-picker-indicator { - line-height: 1; - } - :-moz-ui-invalid { box-shadow: none; } @@ -281,20 +616,14 @@ exports[`\`@import 'tailwindcss'\` is replaced with the generated CSS 1`] = ` } .text-black\\/50 { - color: #00000080; - } - - @supports (color: color-mix(in lab, red, red)) { - .text-black\\/50 { - color: color-mix(in oklab, var(--color-black) 50%, transparent); - } + color: color-mix(in oklab, var(--color-black) 50%, transparent); } .underline { text-decoration-line: underline; } - @media (min-width: 96rem) { + @media (width >= 96rem) { .\\32 xl\\:font-bold { --tw-font-weight: var(--font-weight-bold); font-weight: var(--font-weight-bold); @@ -302,9 +631,47 @@ exports[`\`@import 'tailwindcss'\` is replaced with the generated CSS 1`] = ` } } +@supports (-moz-orient: inline) { + @layer base { + *, :before, :after, ::backdrop { + --tw-font-weight: initial; + } + } +} + +@keyframes spin { + to { + transform: rotate(360deg); + } +} + +@keyframes ping { + 75%, 100% { + opacity: 0; + transform: scale(2); + } +} + +@keyframes pulse { + 50% { + opacity: .5; + } +} + +@keyframes bounce { + 0%, 100% { + animation-timing-function: cubic-bezier(.8, 0, 1, 1); + transform: translateY(-25%); + } + + 50% { + animation-timing-function: cubic-bezier(0, 0, .2, 1); + transform: none; + } +} + @property --tw-font-weight { syntax: "*"; inherits: false -} -" +}" `; diff --git a/packages/@tailwindcss-postcss/src/ast.test.ts b/packages/@tailwindcss-postcss/src/ast.test.ts index 8a2a5b019..dd7095428 100644 --- a/packages/@tailwindcss-postcss/src/ast.test.ts +++ b/packages/@tailwindcss-postcss/src/ast.test.ts @@ -84,7 +84,7 @@ it('should convert a Tailwind CSS AST into a PostCSS AST', () => { ` let ast = parse(input) - let transformedAst = cssAstToPostCssAst(postcss, ast) + let transformedAst = cssAstToPostCssAst(ast) expect(transformedAst.toString()).toMatchInlineSnapshot(` "@charset "UTF-8"; diff --git a/packages/@tailwindcss-postcss/src/ast.ts b/packages/@tailwindcss-postcss/src/ast.ts index 7ca9e2add..201dd4bf8 100644 --- a/packages/@tailwindcss-postcss/src/ast.ts +++ b/packages/@tailwindcss-postcss/src/ast.ts @@ -1,67 +1,18 @@ -import type * as postcss from 'postcss' +import postcss, { + type ChildNode as PostCssChildNode, + type Container as PostCssContainerNode, + type Root as PostCssRoot, + type Source as PostcssSource, +} from 'postcss' import { atRule, comment, decl, rule, type AstNode } from '../../tailwindcss/src/ast' -import { createLineTable, type LineTable } from '../../tailwindcss/src/source-maps/line-table' -import type { Source, SourceLocation } from '../../tailwindcss/src/source-maps/source' -import { DefaultMap } from '../../tailwindcss/src/utils/default-map' const EXCLAMATION_MARK = 0x21 -export function cssAstToPostCssAst( - postcss: postcss.Postcss, - ast: AstNode[], - source?: postcss.Source, -): postcss.Root { - let inputMap = new DefaultMap((src) => { - return new postcss.Input(src.code, { - map: source?.input.map, - from: src.file ?? undefined, - }) - }) - - let lineTables = new DefaultMap((src) => createLineTable(src.code)) - +export function cssAstToPostCssAst(ast: AstNode[], source: PostcssSource | undefined): PostCssRoot { let root = postcss.root() root.source = source - function toSource(loc: SourceLocation | undefined): postcss.Source | undefined { - // Use the fallback if this node has no location info in the AST - if (!loc) return - if (!loc[0]) return - - let table = lineTables.get(loc[0]) - let start = table.find(loc[1]) - let end = table.find(loc[2]) - - return { - input: inputMap.get(loc[0]), - start: { - line: start.line, - column: start.column + 1, - offset: loc[1], - }, - end: { - line: end.line, - column: end.column + 1, - offset: loc[2], - }, - } - } - - function updateSource(astNode: postcss.ChildNode, loc: SourceLocation | undefined) { - let source = toSource(loc) - - // The `source` property on PostCSS nodes must be defined if present because - // `toJSON()` reads each property and tries to read from source.input if it - // sees a `source` property. This means for a missing or otherwise absent - // source it must be *missing* from the object rather than just `undefined` - if (source) { - astNode.source = source - } else { - delete astNode.source - } - } - - function transform(node: AstNode, parent: postcss.Container) { + function transform(node: AstNode, parent: PostCssContainerNode) { // Declaration if (node.kind === 'declaration') { let astNode = postcss.decl({ @@ -69,14 +20,14 @@ export function cssAstToPostCssAst( value: node.value ?? '', important: node.important, }) - updateSource(astNode, node.src) + astNode.source = source parent.append(astNode) } // Rule else if (node.kind === 'rule') { let astNode = postcss.rule({ selector: node.selector }) - updateSource(astNode, node.src) + astNode.source = source astNode.raws.semicolon = true parent.append(astNode) for (let child of node.nodes) { @@ -87,7 +38,7 @@ export function cssAstToPostCssAst( // AtRule else if (node.kind === 'at-rule') { let astNode = postcss.atRule({ name: node.name.slice(1), params: node.params }) - updateSource(astNode, node.src) + astNode.source = source astNode.raws.semicolon = true parent.append(astNode) for (let child of node.nodes) { @@ -102,7 +53,7 @@ export function cssAstToPostCssAst( // spaces. astNode.raws.left = '' astNode.raws.right = '' - updateSource(astNode, node.src) + astNode.source = source parent.append(astNode) } @@ -123,39 +74,19 @@ export function cssAstToPostCssAst( return root } -export function postCssAstToCssAst(root: postcss.Root): AstNode[] { - let inputMap = new DefaultMap((input) => ({ - file: input.file ?? input.id ?? null, - code: input.css, - })) - - function toSource(node: postcss.ChildNode): SourceLocation | undefined { - let source = node.source - if (!source) return - - let input = source.input - if (!input) return - if (source.start === undefined) return - if (source.end === undefined) return - - return [inputMap.get(input), source.start.offset, source.end.offset] - } - +export function postCssAstToCssAst(root: PostCssRoot): AstNode[] { function transform( - node: postcss.ChildNode, + node: PostCssChildNode, parent: Extract['nodes'], ) { // Declaration if (node.type === 'decl') { - let astNode = decl(node.prop, node.value, node.important) - astNode.src = toSource(node) - parent.push(astNode) + parent.push(decl(node.prop, node.value, node.important)) } // Rule else if (node.type === 'rule') { let astNode = rule(node.selector) - astNode.src = toSource(node) node.each((child) => transform(child, astNode.nodes)) parent.push(astNode) } @@ -163,7 +94,6 @@ export function postCssAstToCssAst(root: postcss.Root): AstNode[] { // AtRule else if (node.type === 'atrule') { let astNode = atRule(`@${node.name}`, node.params) - astNode.src = toSource(node) node.each((child) => transform(child, astNode.nodes)) parent.push(astNode) } @@ -171,9 +101,7 @@ export function postCssAstToCssAst(root: postcss.Root): AstNode[] { // Comment else if (node.type === 'comment') { if (node.text.charCodeAt(0) !== EXCLAMATION_MARK) return - let astNode = comment(node.text) - astNode.src = toSource(node) - parent.push(astNode) + parent.push(comment(node.text)) } // Unknown diff --git a/packages/@tailwindcss-postcss/src/fixtures/example-project/input.css b/packages/@tailwindcss-postcss/src/fixtures/example-project/input.css deleted file mode 100644 index f1af498fc..000000000 --- a/packages/@tailwindcss-postcss/src/fixtures/example-project/input.css +++ /dev/null @@ -1 +0,0 @@ -/* the content for this file is set in the tests */ diff --git a/packages/@tailwindcss-postcss/src/index.test.ts b/packages/@tailwindcss-postcss/src/index.test.ts index b393cc382..50f72a13d 100644 --- a/packages/@tailwindcss-postcss/src/index.test.ts +++ b/packages/@tailwindcss-postcss/src/index.test.ts @@ -1,10 +1,7 @@ import dedent from 'dedent' -import { mkdir, mkdtemp, readFile, rm, unlink, writeFile } from 'node:fs/promises' -import { tmpdir } from 'node:os' -import path from 'path' +import { unlink, writeFile } from 'node:fs/promises' import postcss from 'postcss' -import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest' -import { pretty } from '../../tailwindcss/src/test-utils/run' +import { afterEach, beforeEach, describe, expect, test } from 'vitest' import tailwindcss from './index' // We give this file path to PostCSS for processing. @@ -20,16 +17,6 @@ function inputCssFilePath() { const css = dedent -async function run(plugin: any, from: string, input: string): Promise { - let ast = postcss.parse(input) - for (let runner of plugin.plugins) { - if (runner.Once) { - await runner.Once(ast, { postcss, result: { opts: { from }, messages: [] } }) - } - } - return ast.toString() -} - test("`@import 'tailwindcss'` is replaced with the generated CSS", async () => { let processor = postcss([ tailwindcss({ base: `${__dirname}/fixtures/example-project`, optimize: { minify: false } }), @@ -37,7 +24,7 @@ test("`@import 'tailwindcss'` is replaced with the generated CSS", async () => { let result = await processor.process(`@import 'tailwindcss'`, { from: inputCssFilePath() }) - expect(pretty(result.css)).toMatchSnapshot() + expect(result.css.trim()).toMatchSnapshot() // Check for dependency messages expect(result.messages).toContainEqual({ @@ -54,7 +41,7 @@ test("`@import 'tailwindcss'` is replaced with the generated CSS", async () => { }) expect(result.messages).toContainEqual({ type: 'dir-dependency', - dir: expect.stringMatching(/example-project[/|\\]src$/g), + dir: expect.stringMatching(/example-project[\/|\\]src$/g), glob: expect.stringMatching(/^\*\*\/\*/g), parent: expect.any(String), plugin: expect.any(String), @@ -83,9 +70,8 @@ test('output is optimized by Lightning CSS', async () => { { from: inputCssFilePath() }, ) - expect(pretty(result.css)).toMatchInlineSnapshot(` - " - @layer utilities { + expect(result.css.trim()).toMatchInlineSnapshot(` + "@layer utilities { .foo { color: #000; } @@ -93,8 +79,7 @@ test('output is optimized by Lightning CSS', async () => { .bar { color: red; } - } - " + }" `) }) @@ -105,7 +90,7 @@ test('@apply can be used without emitting the theme in the CSS file', async () = let result = await processor.process( css` - @reference 'tailwindcss/theme.css'; + @import 'tailwindcss/theme.css' theme(reference); .foo { @apply text-red-500; } @@ -113,31 +98,22 @@ test('@apply can be used without emitting the theme in the CSS file', async () = { from: inputCssFilePath() }, ) - expect(pretty(result.css)).toMatchInlineSnapshot(` - " - .foo { - color: var(--color-red-500, oklch(63.7% .237 25.331)); - } - " + expect(result.css.trim()).toMatchInlineSnapshot(` + ".foo { + color: var(--color-red-500); + }" `) }) describe('processing without specifying a base path', () => { - let filepath: string - let dir: string + let filepath = `${process.cwd()}/my-test-file.html` - beforeEach(async () => { - dir = await mkdtemp(path.join(tmpdir(), 'tw-postcss')) - await mkdir(dir, { recursive: true }) - filepath = path.join(dir, 'my-test-file.html') - await writeFile(filepath, `
`) - }) + beforeEach(() => + writeFile(filepath, `
`), + ) afterEach(() => unlink(filepath)) test('the current working directory is used by default', async () => { - using spy = vi.spyOn(process, 'cwd') - spy.mockReturnValue(dir) - let processor = postcss([tailwindcss({ optimize: { minify: false } })]) let result = await processor.process(`@import "tailwindcss"`, { from: inputCssFilePath() }) @@ -155,18 +131,6 @@ describe('processing without specifying a base path', () => { }) }) -test('fallback to `base` directory when `result.opts.from` is not provided', async () => { - using _ = vi.spyOn(console, 'warn').mockImplementation(() => {}) - - let processor = postcss([ - tailwindcss({ base: `${__dirname}/fixtures/example-project`, optimize: { minify: false } }), - ]) - - let result = await processor.process(`@import 'tailwindcss'`) - - expect(result.css.length).toBeGreaterThan(0) -}) - describe('plugins', () => { test('local CJS plugin', async () => { let processor = postcss([ @@ -181,9 +145,8 @@ describe('plugins', () => { { from: inputCssFilePath() }, ) - expect(pretty(result.css)).toMatchInlineSnapshot(` - " - .underline { + expect(result.css.trim()).toMatchInlineSnapshot(` + ".underline { text-decoration-line: underline; } @@ -195,8 +158,7 @@ describe('plugins', () => { .hocus\\:underline:focus, .hocus\\:underline:hover { text-decoration-line: underline; - } - " + }" `) }) @@ -213,9 +175,8 @@ describe('plugins', () => { { from: `${__dirname}/fixtures/another-project/input.css` }, ) - expect(pretty(result.css)).toMatchInlineSnapshot(` - " - .underline { + expect(result.css.trim()).toMatchInlineSnapshot(` + ".underline { text-decoration-line: underline; } @@ -227,8 +188,7 @@ describe('plugins', () => { .hocus\\:underline:focus, .hocus\\:underline:hover { text-decoration-line: underline; - } - " + }" `) }) @@ -245,9 +205,8 @@ describe('plugins', () => { { from: inputCssFilePath() }, ) - expect(pretty(result.css)).toMatchInlineSnapshot(` - " - .underline { + expect(result.css.trim()).toMatchInlineSnapshot(` + ".underline { text-decoration-line: underline; } @@ -259,8 +218,7 @@ describe('plugins', () => { .hocus\\:underline:focus, .hocus\\:underline:hover { text-decoration-line: underline; - } - " + }" `) }) }) @@ -283,66 +241,10 @@ test('bail early when Tailwind is not used', async () => { // didn't use `@tailwind utilities` we didn't scan for utilities. expect(result.css).not.toContain('.underline {') - expect(pretty(result.css)).toMatchInlineSnapshot(` - " - .custom-css { + expect(result.css.trim()).toMatchInlineSnapshot(` + ".custom-css { color: red; - } - " - `) -}) - -test('handle CSS when only using a `@reference` (we should not bail early)', async () => { - let processor = postcss([ - tailwindcss({ base: `${__dirname}/fixtures/example-project`, optimize: { minify: false } }), - ]) - - let result = await processor.process( - css` - @reference "tailwindcss/theme.css"; - - .foo { - @variant md { - bar: baz; - } - } - `, - { from: inputCssFilePath() }, - ) - - expect(pretty(result.css)).toMatchInlineSnapshot(` - " - @media (min-width: 48rem) { - .foo { - bar: baz; - } - } - " - `) -}) - -test('handle CSS when using a `@variant` using variants that do not rely on the `@theme`', async () => { - let processor = postcss([ - tailwindcss({ base: `${__dirname}/fixtures/example-project`, optimize: { minify: false } }), - ]) - - let result = await processor.process( - css` - .foo { - @variant data-is-hoverable { - bar: baz; - } - } - `, - { from: inputCssFilePath() }, - ) - - expect(pretty(result.css)).toMatchInlineSnapshot(` - " - .foo[data-is-hoverable] { - bar: baz; - } - " + }" `) }) @@ -377,142 +279,30 @@ test('runs `Once` plugins in the right order', async () => { { from: inputCssFilePath() }, ) - expect(pretty(result.css)).toMatchInlineSnapshot(` - " + expect(result.css.trim()).toMatchInlineSnapshot(` + ":root { + --color-red-500: red; + } + .custom-css { color: red; - } - " + }" `) - expect(pretty(before)).toMatchInlineSnapshot(` - " - @theme { + expect(before).toMatchInlineSnapshot(` + "@theme { --color-red-500: red; } .custom-css { color: theme(--color-red-500); - } - " + }" `) - expect(pretty(after)).toMatchInlineSnapshot(` - " + expect(after).toMatchInlineSnapshot(` + ":root { + --color-red-500: red; + } + .custom-css { color: red; - } - " + }" `) }) - -describe('concurrent builds', () => { - let dir: string - beforeEach(async () => { - dir = await mkdtemp(path.join(tmpdir(), 'tw-postcss')) - await writeFile(path.join(dir, 'index.html'), `
`) - await writeFile( - path.join(dir, 'index.css'), - css` - @import './dependency.css'; - `, - ) - await writeFile( - path.join(dir, 'dependency.css'), - css` - @tailwind utilities; - `, - ) - }) - afterEach(() => rm(dir, { recursive: true, force: true })) - - test('does experience a race-condition when calling the plugin two times for the same change', async () => { - using spy = vi.spyOn(process, 'cwd') - spy.mockReturnValue(dir) - - let from = path.join(dir, 'index.css') - let input = (await readFile(path.join(dir, 'index.css'))).toString() - - let plugin = tailwindcss({ optimize: { minify: false } }) - - let result = await run(plugin, from, input) - - expect(result).toContain('.underline') - - // Ensure that the mtime is updated - await new Promise((resolve) => setTimeout(resolve, 100)) - await writeFile( - path.join(dir, 'dependency.css'), - css` - @tailwind utilities; - .red { - color: red; - } - `, - ) - - let promise1 = run(plugin, from, input) - let promise2 = run(plugin, from, input) - - expect(await promise1).toContain('.red') - expect(await promise2).toContain('.red') - }) -}) - -test('rebuilds when the input CSS changes even if the `from` file on disk did not', async () => { - let dir = await mkdtemp(path.join(tmpdir(), 'tw-postcss')) - // The `from` file exists on disk with a stable mtime. The input CSS is handed - // to the plugin directly (as a preprocessor like Sass would produce it), so it - // can change without `from`'s mtime ever changing. - await writeFile(path.join(dir, 'index.css'), '') - - let from = path.join(dir, 'index.css') - let plugin = tailwindcss({ base: dir, optimize: { minify: false } }) - - let first = await run( - plugin, - from, - css` - @tailwind utilities; - .first { - @apply underline; - } - `, - ) - let second = await run( - plugin, - from, - css` - @tailwind utilities; - .second { - @apply line-through; - } - `, - ) - - expect(first).toContain('.first') - expect(second).toContain('.second') - - await rm(dir, { recursive: true, force: true }) -}) - -test('does not register the input file as a dependency, even if it is passed in as relative path', async () => { - let processor = postcss([ - tailwindcss({ base: `${__dirname}/fixtures/example-project`, optimize: { minify: false } }), - ]) - - let result = await processor.process(`@tailwind utilities`, { from: './input.css' }) - - expect(pretty(result.css)).toMatchInlineSnapshot(` - " - .underline { - text-decoration-line: underline; - } - " - `) - - // Check for dependency messages - expect(result.messages).not.toContainEqual({ - type: 'dependency', - file: expect.stringMatching(/input.css$/g), - parent: expect.any(String), - plugin: expect.any(String), - }) -}) diff --git a/packages/@tailwindcss-postcss/src/index.ts b/packages/@tailwindcss-postcss/src/index.ts index a4a8d9326..c69b9a875 100644 --- a/packages/@tailwindcss-postcss/src/index.ts +++ b/packages/@tailwindcss-postcss/src/index.ts @@ -1,17 +1,11 @@ import QuickLRU from '@alloc/quick-lru' -import { - compileAst, - env, - Features, - Instrumentation, - optimize as optimizeCss, - Polyfills, -} from '@tailwindcss/node' +import { compileAst, env, Features, Instrumentation } from '@tailwindcss/node' import { clearRequireCache } from '@tailwindcss/node/require-cache' import { Scanner } from '@tailwindcss/oxide' +import { Features as LightningCssFeatures, transform } from 'lightningcss' import fs from 'node:fs' import path, { relative } from 'node:path' -import type { AcceptedPlugin, PluginCreator, Postcss, Root } from 'postcss' +import postcss, { type AcceptedPlugin, type PluginCreator } from 'postcss' import { toCss, type AstNode } from '../../tailwindcss/src/ast' import { cssAstToPostCssAst, postCssAstToCssAst } from './ast' import fixRelativePathsPlugin from './postcss-fix-relative-paths' @@ -20,22 +14,20 @@ const DEBUG = env.DEBUG interface CacheEntry { mtimes: Map - inputCss: string - compiler: null | ReturnType + compiler: null | Awaited> scanner: null | Scanner tailwindCssAst: AstNode[] - cachedPostCssAst: Root - optimizedPostCssAst: Root + cachedPostCssAst: postcss.Root + optimizedPostCssAst: postcss.Root fullRebuildPaths: string[] } const cache = new QuickLRU({ maxSize: 50 }) -function getContextFromCache(postcss: Postcss, inputFile: string, opts: PluginOptions): CacheEntry { +function getContextFromCache(inputFile: string, opts: PluginOptions): CacheEntry { let key = `${inputFile}:${opts.base ?? ''}:${JSON.stringify(opts.optimize)}` if (cache.has(key)) return cache.get(key)! let entry = { mtimes: new Map(), - inputCss: '', compiler: null, scanner: null, @@ -50,30 +42,16 @@ function getContextFromCache(postcss: Postcss, inputFile: string, opts: PluginOp } export type PluginOptions = { - /** - * The base directory to scan for class candidates. - * - * Defaults to the current working directory. - */ + // The base directory to scan for class candidates. base?: string - /** - * Optimize and minify the output CSS. - */ + // Optimize and minify the output CSS. optimize?: boolean | { minify?: boolean } - - /** - * Enable or disable asset URL rewriting. - * - * Defaults to `true`. - */ - transformAssetUrls?: boolean } function tailwindcss(opts: PluginOptions = {}): AcceptedPlugin { let base = opts.base ?? process.cwd() let optimize = opts.optimize ?? process.env.NODE_ENV === 'production' - let shouldRewriteUrls = opts.transformAssetUrls ?? true return { postcssPlugin: '@tailwindcss/postcss', @@ -85,11 +63,10 @@ function tailwindcss(opts: PluginOptions = {}): AcceptedPlugin { { postcssPlugin: 'tailwindcss', - async Once(root, { result, postcss }) { + async Once(root, { result }) { using I = new Instrumentation() let inputFile = result.opts.from ?? '' - let isCSSModuleFile = inputFile.endsWith('.module.css') DEBUG && I.start(`[@tailwindcss/postcss] ${relative(base, inputFile)}`) @@ -100,13 +77,10 @@ function tailwindcss(opts: PluginOptions = {}): AcceptedPlugin { root.walkAtRules((node) => { if ( node.name === 'import' || - node.name === 'reference' || node.name === 'theme' || - node.name === 'variant' || node.name === 'config' || node.name === 'plugin' || - node.name === 'apply' || - node.name === 'tailwind' + node.name === 'apply' ) { canBail = false return false @@ -116,12 +90,8 @@ function tailwindcss(opts: PluginOptions = {}): AcceptedPlugin { DEBUG && I.end('Quick bail check') } - let context = getContextFromCache(postcss, inputFile, opts) - let inputBasePath = inputFile ? path.dirname(path.resolve(inputFile)) : base - - // Whether this is the first build or not, if it is, then we can - // optimize the build by not creating the compiler until we need it. - let isInitialBuild = context.compiler === null + let context = getContextFromCache(inputFile, opts) + let inputBasePath = path.dirname(path.resolve(inputFile)) async function createCompiler() { DEBUG && I.start('Setup compiler') @@ -137,14 +107,10 @@ function tailwindcss(opts: PluginOptions = {}): AcceptedPlugin { DEBUG && I.start('Create compiler') let compiler = await compileAst(ast, { - from: result.opts.from, base: inputBasePath, - shouldRewriteUrls, - onDependency: (path) => context.fullRebuildPaths.push(path), - // In CSS Module files, we have to disable the `@property` polyfill since these will - // emit global `*` rules which are considered to be non-pure and will cause builds - // to fail. - polyfills: isCSSModuleFile ? Polyfills.All ^ Polyfills.AtProperty : Polyfills.All, + onDependency: (path) => { + context.fullRebuildPaths.push(path) + }, }) DEBUG && I.end('Create compiler') @@ -152,203 +118,23 @@ function tailwindcss(opts: PluginOptions = {}): AcceptedPlugin { return compiler } - try { - // Setup the compiler if it doesn't exist yet. This way we can - // guarantee a `build()` function is available. - context.compiler ??= createCompiler() + // Whether this is the first build or not, if it is, then we can + // optimize the build by not creating the compiler until we need it. + let isInitialBuild = context.compiler === null - if ((await context.compiler).features === Features.None) { - return - } + // Setup the compiler if it doesn't exist yet. This way we can + // guarantee a `build()` function is available. + context.compiler ??= await createCompiler() - let rebuildStrategy: 'full' | 'incremental' = 'incremental' + if (context.compiler.features === Features.None) { + return + } - // Track file modification times to CSS files - DEBUG && I.start('Register full rebuild paths') - { - for (let file of context.fullRebuildPaths) { - result.messages.push({ - type: 'dependency', - plugin: '@tailwindcss/postcss', - file: path.resolve(file), - parent: result.opts.from, - }) - } + let rebuildStrategy: 'full' | 'incremental' = 'incremental' - let files = result.messages.flatMap((message) => { - if (message.type !== 'dependency') return [] - return message.file - }) - files.push(inputFile) - - for (let file of files) { - let changedTime = fs.statSync(file, { throwIfNoEntry: false })?.mtimeMs ?? null - if (changedTime === null) { - if (file === inputFile) { - rebuildStrategy = 'full' - } - continue - } - - let prevTime = context.mtimes.get(file) - if (prevTime === changedTime) continue - - rebuildStrategy = 'full' - context.mtimes.set(file, changedTime) - } - - // The mtimes above only track files on disk. When the input CSS is - // generated by another tool (e.g. Sass) and passed to `process()`, - // it can change without any tracked file's mtime changing, so also - // rebuild when the input CSS itself differs from the last build. - let inputCss = root.source?.input.css ?? root.toString() - if (context.inputCss !== inputCss) { - rebuildStrategy = 'full' - context.inputCss = inputCss - } - } - DEBUG && I.end('Register full rebuild paths') - - if ( - rebuildStrategy === 'full' && - // We can reuse the compiler if it was created during the - // initial build. If it wasn't, we need to create a new one. - !isInitialBuild - ) { - context.compiler = createCompiler() - } - - let compiler = await context.compiler - - if (context.scanner === null || rebuildStrategy === 'full') { - DEBUG && I.start('Setup scanner') - let sources = (() => { - // Disable auto source detection - if (compiler.root === 'none') { - return [] - } - - // No root specified, use the base directory - if (compiler.root === null) { - return [{ base, pattern: '**/*', negated: false }] - } - - // Use the specified root - return [{ ...compiler.root, negated: false }] - })().concat(compiler.sources) - - // Look for candidates used to generate the CSS - context.scanner = new Scanner({ sources }) - DEBUG && I.end('Setup scanner') - } - - DEBUG && I.start('Scan for candidates') - let candidates = compiler.features & Features.Utilities ? context.scanner.scan() : [] - DEBUG && I.end('Scan for candidates') - - if (compiler.features & Features.Utilities) { - DEBUG && I.start('Register dependency messages') - // Add all found files as direct dependencies - // Note: With Turbopack, the input file might not be a resolved path - let resolvedInputFile = path.resolve(base, inputFile) - for (let file of context.scanner.files) { - let absolutePath = path.resolve(file) - // The CSS file cannot be a dependency of itself - if (absolutePath === resolvedInputFile) { - continue - } - result.messages.push({ - type: 'dependency', - plugin: '@tailwindcss/postcss', - file: absolutePath, - parent: result.opts.from, - }) - } - - // Register dependencies so changes in `base` cause a rebuild while - // giving tools like Vite or Parcel a glob that can be used to limit - // the files that cause a rebuild to only those that match it. - for (let { base: globBase, pattern } of context.scanner.globs) { - // Avoid adding a dependency on the base directory itself, since it - // causes Next.js to start an endless recursion if the `distDir` is - // configured to anything other than the default `.next` dir. - if (pattern === '*' && base === globBase) { - continue - } - - if (pattern === '') { - result.messages.push({ - type: 'dependency', - plugin: '@tailwindcss/postcss', - file: path.resolve(globBase), - parent: result.opts.from, - }) - } else { - result.messages.push({ - type: 'dir-dependency', - plugin: '@tailwindcss/postcss', - dir: path.resolve(globBase), - glob: pattern, - parent: result.opts.from, - }) - } - } - DEBUG && I.end('Register dependency messages') - } - - DEBUG && I.start('Build utilities') - let tailwindCssAst = compiler.build(candidates) - DEBUG && I.end('Build utilities') - - if (context.tailwindCssAst !== tailwindCssAst) { - if (optimize) { - DEBUG && I.start('Optimization') - - DEBUG && I.start('AST -> CSS') - let css = toCss(tailwindCssAst) - DEBUG && I.end('AST -> CSS') - - DEBUG && I.start('Lightning CSS') - let optimized = optimizeCss(css, { - minify: typeof optimize === 'object' ? optimize.minify : true, - }) - DEBUG && I.end('Lightning CSS') - - DEBUG && I.start('CSS -> PostCSS AST') - context.optimizedPostCssAst = postcss.parse(optimized.code, result.opts) - DEBUG && I.end('CSS -> PostCSS AST') - - DEBUG && I.end('Optimization') - } else { - // Convert our AST to a PostCSS AST - DEBUG && I.start('Transform Tailwind CSS AST into PostCSS AST') - context.cachedPostCssAst = cssAstToPostCssAst(postcss, tailwindCssAst, root.source) - DEBUG && I.end('Transform Tailwind CSS AST into PostCSS AST') - } - } - - context.tailwindCssAst = tailwindCssAst - - DEBUG && I.start('Update PostCSS AST') - root.removeAll() - root.append( - optimize - ? context.optimizedPostCssAst.clone().nodes - : context.cachedPostCssAst.clone().nodes, - ) - - // Trick PostCSS into thinking the indent is 2 spaces, so it uses that - // as the default instead of 4. - root.raws.indent = ' ' - DEBUG && I.end('Update PostCSS AST') - - DEBUG && I.end(`[@tailwindcss/postcss] ${relative(base, inputFile)}`) - } catch (error) { - // An error requires a full rebuild to fix - context.compiler = null - - // Ensure all dependencies we have collected thus far are included so that the rebuild - // is correctly triggered + // Track file modification times to CSS files + DEBUG && I.start('Register full rebuild paths') + { for (let file of context.fullRebuildPaths) { result.messages.push({ type: 'dependency', @@ -358,20 +144,193 @@ function tailwindcss(opts: PluginOptions = {}): AcceptedPlugin { }) } - // We found that throwing the error will cause PostCSS to no longer watch for changes - // in some situations so we instead log the error and continue with an empty stylesheet. - console.error(error) + let files = result.messages.flatMap((message) => { + if (message.type !== 'dependency') return [] + return message.file + }) + files.push(inputFile) - if (error && typeof error === 'object' && 'message' in error) { - throw root.error(`${error.message}`) + for (let file of files) { + let changedTime = fs.statSync(file, { throwIfNoEntry: false })?.mtimeMs ?? null + if (changedTime === null) { + if (file === inputFile) { + rebuildStrategy = 'full' + } + continue + } + + let prevTime = context.mtimes.get(file) + if (prevTime === changedTime) continue + + rebuildStrategy = 'full' + context.mtimes.set(file, changedTime) + } + } + DEBUG && I.end('Register full rebuild paths') + + if ( + rebuildStrategy === 'full' && + // We can re-use the compiler if it was created during the + // initial build. If it wasn't, we need to create a new one. + !isInitialBuild + ) { + context.compiler = await createCompiler() + } + + if (context.scanner === null || rebuildStrategy === 'full') { + DEBUG && I.start('Setup scanner') + let sources = (() => { + // Disable auto source detection + if (context.compiler.root === 'none') { + return [] + } + + // No root specified, use the base directory + if (context.compiler.root === null) { + return [{ base, pattern: '**/*' }] + } + + // Use the specified root + return [context.compiler.root] + })().concat(context.compiler.globs) + + // Look for candidates used to generate the CSS + context.scanner = new Scanner({ sources }) + DEBUG && I.end('Setup scanner') + } + + DEBUG && I.start('Scan for candidates') + let candidates = + context.compiler.features & Features.Utilities ? context.scanner.scan() : [] + DEBUG && I.end('Scan for candidates') + + if (context.compiler.features & Features.Utilities) { + DEBUG && I.start('Register dependency messages') + // Add all found files as direct dependencies + for (let file of context.scanner.files) { + result.messages.push({ + type: 'dependency', + plugin: '@tailwindcss/postcss', + file: path.resolve(file), + parent: result.opts.from, + }) } - throw root.error(`${error}`) + // Register dependencies so changes in `base` cause a rebuild while + // giving tools like Vite or Parcel a glob that can be used to limit + // the files that cause a rebuild to only those that match it. + for (let { base: globBase, pattern } of context.scanner.globs) { + // Avoid adding a dependency on the base directory itself, since it + // causes Next.js to start an endless recursion if the `distDir` is + // configured to anything other than the default `.next` dir. + if (pattern === '*' && base === globBase) { + continue + } + + if (pattern === '') { + result.messages.push({ + type: 'dependency', + plugin: '@tailwindcss/postcss', + file: path.resolve(globBase), + parent: result.opts.from, + }) + } else { + result.messages.push({ + type: 'dir-dependency', + plugin: '@tailwindcss/postcss', + dir: path.resolve(globBase), + glob: pattern, + parent: result.opts.from, + }) + } + } + DEBUG && I.end('Register dependency messages') } + + DEBUG && I.start('Build utilities') + let tailwindCssAst = context.compiler.build(candidates) + DEBUG && I.end('Build utilities') + + if (context.tailwindCssAst !== tailwindCssAst) { + if (optimize) { + DEBUG && I.start('Optimization') + + DEBUG && I.start('AST -> CSS') + let css = toCss(tailwindCssAst) + DEBUG && I.end('AST -> CSS') + + DEBUG && I.start('Lightning CSS') + let ast = optimizeCss(css, { + minify: typeof optimize === 'object' ? optimize.minify : true, + }) + DEBUG && I.end('Lightning CSS') + + DEBUG && I.start('CSS -> PostCSS AST') + context.optimizedPostCssAst = postcss.parse(ast, result.opts) + DEBUG && I.end('CSS -> PostCSS AST') + + DEBUG && I.end('Optimization') + } else { + // Convert our AST to a PostCSS AST + DEBUG && I.start('Transform Tailwind CSS AST into PostCSS AST') + context.cachedPostCssAst = cssAstToPostCssAst(tailwindCssAst, root.source) + DEBUG && I.end('Transform Tailwind CSS AST into PostCSS AST') + } + } + + context.tailwindCssAst = tailwindCssAst + + DEBUG && I.start('Update PostCSS AST') + root.removeAll() + root.append( + optimize + ? context.optimizedPostCssAst.clone().nodes + : context.cachedPostCssAst.clone().nodes, + ) + + // Trick PostCSS into thinking the indent is 2 spaces, so it uses that + // as the default instead of 4. + root.raws.indent = ' ' + DEBUG && I.end('Update PostCSS AST') + + DEBUG && I.end(`[@tailwindcss/postcss] ${relative(base, inputFile)}`) }, }, ], } } +function optimizeCss( + input: string, + { file = 'input.css', minify = false }: { file?: string; minify?: boolean } = {}, +) { + function optimize(code: Buffer | Uint8Array) { + return transform({ + filename: file, + code, + minify, + sourceMap: false, + drafts: { + customMedia: true, + }, + nonStandard: { + deepSelectorCombinator: true, + }, + include: LightningCssFeatures.Nesting, + exclude: LightningCssFeatures.LogicalProperties | LightningCssFeatures.DirSelector, + targets: { + safari: (16 << 16) | (4 << 8), + ios_saf: (16 << 16) | (4 << 8), + firefox: 128 << 16, + chrome: 111 << 16, + }, + errorRecovery: true, + }).code + } + + // Running Lightning CSS twice to ensure that adjacent rules are merged after + // nesting is applied. This creates a more optimized output. + return optimize(optimize(Buffer.from(input))).toString() +} + export default Object.assign(tailwindcss, { postcss: true }) as PluginCreator diff --git a/packages/@tailwindcss-postcss/src/postcss-fix-relative-paths/index.test.ts b/packages/@tailwindcss-postcss/src/postcss-fix-relative-paths/index.test.ts index fd90c483e..d2f72f664 100644 --- a/packages/@tailwindcss-postcss/src/postcss-fix-relative-paths/index.test.ts +++ b/packages/@tailwindcss-postcss/src/postcss-fix-relative-paths/index.test.ts @@ -4,7 +4,6 @@ import postcss from 'postcss' import atImport from 'postcss-import' import { describe, expect, test } from 'vitest' import fixRelativePathsPlugin from '.' -import { pretty } from '../../../tailwindcss/src/test-utils/run' describe('fixRelativePathsPlugin', () => { test('rewrites @source and @plugin to be relative to the initial css file', async () => { @@ -15,13 +14,11 @@ describe('fixRelativePathsPlugin', () => { let result = await processor.process(css, { from: cssPath }) - expect(pretty(result.css)).toMatchInlineSnapshot(` - " - @source "../../example-project/src/**/*.ts"; + expect(result.css.trim()).toMatchInlineSnapshot(` + "@source "../../example-project/src/**/*.ts"; @source "!../../example-project/src/**/*.ts"; @plugin "../../example-project/src/plugin.js"; - @plugin "../../example-project/src/what\\"s-this.js"; - " + @plugin "../../example-project/src/what\\"s-this.js";" `) }) @@ -33,13 +30,11 @@ describe('fixRelativePathsPlugin', () => { let result = await processor.process(css, { from: cssPath }) - expect(pretty(result.css)).toMatchInlineSnapshot(` - " - @plugin "/absolute/paths"; + expect(result.css.trim()).toMatchInlineSnapshot(` + "@plugin "/absolute/paths"; @plugin "C:\\Program Files\\HAL 9000"; @plugin "\\\\Media\\Pictures\\Worth\\1000 words"; - @plugin "some-node-dep"; - " + @plugin "some-node-dep";" `) }) @@ -51,16 +46,13 @@ describe('fixRelativePathsPlugin', () => { let result = await processor.process(css, { from: cssPath }) - expect(pretty(result.css)).toMatchInlineSnapshot(` - " - @plugin './plugin-in-sibling.ts'; + expect(result.css.trim()).toMatchInlineSnapshot(` + "@plugin './plugin-in-sibling.ts'; @plugin '../plugin-in-sibling.ts'; @plugin 'plugin-in-sibling'; - @plugin './plugin-in-root.ts'; @plugin '../plugin-in-root.ts'; - @plugin 'plugin-in-root'; - " + @plugin 'plugin-in-root';" `) }) }) diff --git a/packages/@tailwindcss-postcss/tsconfig.json b/packages/@tailwindcss-postcss/tsconfig.json index d2131cbeb..6ae022f65 100644 --- a/packages/@tailwindcss-postcss/tsconfig.json +++ b/packages/@tailwindcss-postcss/tsconfig.json @@ -1,6 +1,3 @@ { "extends": "../tsconfig.base.json", - "compilerOptions": { - "verbatimModuleSyntax": false, - }, } diff --git a/packages/@tailwindcss-standalone/package.json b/packages/@tailwindcss-standalone/package.json index 24f8c93c7..704ed563e 100644 --- a/packages/@tailwindcss-standalone/package.json +++ b/packages/@tailwindcss-standalone/package.json @@ -1,6 +1,6 @@ { "name": "@tailwindcss/standalone", - "version": "4.3.3", + "version": "4.0.0-beta.7", "private": true, "description": "Standalone CLI for Tailwind CSS", "license": "MIT", @@ -26,30 +26,30 @@ ], "dependencies": { "@tailwindcss/aspect-ratio": "^0.4.2", - "@tailwindcss/cli": "workspace:*", - "@tailwindcss/forms": "^0.5.11", - "@tailwindcss/typography": "^0.5.20", + "@tailwindcss/cli": "workspace:^", + "@tailwindcss/forms": "^0.5.9", + "@tailwindcss/typography": "^0.5.15", "detect-libc": "1.0.3", - "enhanced-resolve": "catalog:", - "tailwindcss": "workspace:*" + "enhanced-resolve": "^5.17.1", + "tailwindcss": "workspace:^" }, "__notes": "These binary packages must be included so Bun can build the CLI for all supported platforms. We also rely on Lightning CSS and Parcel being patched so Bun can statically analyze the executables.", "devDependencies": { - "@parcel/watcher-darwin-arm64": "catalog:", - "@parcel/watcher-darwin-x64": "catalog:", - "@parcel/watcher-linux-arm64-glibc": "catalog:", - "@parcel/watcher-linux-arm64-musl": "catalog:", - "@parcel/watcher-linux-x64-glibc": "catalog:", - "@parcel/watcher-linux-x64-musl": "catalog:", - "@parcel/watcher-win32-x64": "catalog:", - "@types/bun": "^1.3.14", - "bun": "^1.3.14", - "lightningcss-darwin-arm64": "catalog:", - "lightningcss-darwin-x64": "catalog:", - "lightningcss-linux-arm64-gnu": "catalog:", - "lightningcss-linux-arm64-musl": "catalog:", - "lightningcss-linux-x64-gnu": "catalog:", - "lightningcss-linux-x64-musl": "catalog:", - "lightningcss-win32-x64-msvc": "catalog:" + "@parcel/watcher-darwin-arm64": "^2.5.0", + "@parcel/watcher-darwin-x64": "^2.5.0", + "@parcel/watcher-linux-arm64-glibc": "^2.5.0", + "@parcel/watcher-linux-arm64-musl": "^2.5.0", + "@parcel/watcher-linux-x64-glibc": "^2.5.0", + "@parcel/watcher-linux-x64-musl": "^2.5.0", + "@parcel/watcher-win32-x64": "^2.5.0", + "@types/bun": "^1.1.13", + "bun": "1.1.29", + "lightningcss-darwin-arm64": "^1.25.1", + "lightningcss-darwin-x64": "^1.25.1", + "lightningcss-linux-arm64-gnu": "^1.25.1", + "lightningcss-linux-arm64-musl": "^1.25.1", + "lightningcss-linux-x64-gnu": "^1.25.1", + "lightningcss-linux-x64-musl": "^1.25.1", + "lightningcss-win32-x64-msvc": "^1.25.1" } } diff --git a/packages/@tailwindcss-standalone/scripts/build.ts b/packages/@tailwindcss-standalone/scripts/build.ts index 0aee26435..83f3b20a9 100644 --- a/packages/@tailwindcss-standalone/scripts/build.ts +++ b/packages/@tailwindcss-standalone/scripts/build.ts @@ -1,3 +1,4 @@ +import { $ } from 'bun' import { createHash } from 'node:crypto' import { mkdir, readFile, writeFile } from 'node:fs/promises' import * as path from 'node:path' @@ -5,107 +6,66 @@ import { fileURLToPath } from 'node:url' const __dirname = fileURLToPath(new URL('.', import.meta.url)) -// Workaround for Bun binary downloads failing on Windows CI when -// USERPROFILE is passed through by Turborepo. -// -// Unfortunately, setting this at runtime doesn't appear to work so we have to -// spawn a new process without the env var. -if (process.env.NESTED_BUILD !== '1' && process.env.USERPROFILE && process.env.USERPROFILE !== '') { - let result = await Bun.$`bun ${fileURLToPath(import.meta.url)}`.env({ - USERPROFILE: '', - NESTED_BUILD: '1', - }) +async function buildForPlatform(triple: string, outfile: string) { + // We wrap this in a retry because occasionally the atomic rename fails for some reason + for (let i = 0; i < 5; ++i) { + try { + return await $`bun build --compile --target=${triple} ./src/index.ts --outfile=${outfile}` + } catch (err) { + if (i < 5) continue - process.exit(result.exitCode) + throw new Error(`Failed to build for platform ${triple}`, { cause: err }) + } + } } -// We use baseline builds for all x64 platforms to ensure compatibility with -// older hardware. -let builds: { target: Bun.Build.Target; name: string }[] = [ - { name: 'tailwindcss-linux-arm64', target: 'bun-linux-arm64' }, - { name: 'tailwindcss-linux-arm64-musl', target: 'bun-linux-arm64-musl' }, - // @ts-expect-error: Either the types are wrong or the runtime needs to be updated - // to accept a `-glibc` at the end like the types suggest. - { name: 'tailwindcss-linux-x64', target: 'bun-linux-x64-baseline' }, - { name: 'tailwindcss-linux-x64-musl', target: 'bun-linux-x64-baseline-musl' }, - { name: 'tailwindcss-macos-arm64', target: 'bun-darwin-arm64' }, - { name: 'tailwindcss-macos-x64', target: 'bun-darwin-x64-baseline' }, - { name: 'tailwindcss-windows-x64.exe', target: 'bun-windows-x64-baseline' }, -] +async function build(triple: string, file: string) { + let start = process.hrtime.bigint() -let summary: { target: Bun.Build.Target; name: string; sum: string }[] = [] + let outfile = path.resolve(__dirname, `../dist/${file}`) -// Build platform binaries and checksum them. -let start = process.hrtime.bigint() -for (let { target, name } of builds) { - let outfile = path.resolve(__dirname, `../dist/${name}`) + await buildForPlatform(triple, outfile) - let result = await Bun.build({ - entrypoints: ['./src/index.ts'], - target: 'node', - minify: { - whitespace: false, - syntax: true, - identifiers: false, - keepNames: true, - }, - - define: { - // This ensures only necessary binaries are bundled for linux targets - // It reduces binary size since no runtime selection is necessary - 'process.env.PLATFORM_LIBC': JSON.stringify(target.includes('-musl') ? 'musl' : 'glibc'), - - // This prevents the WASI build from being bundled with the binary - 'process.env.NAPI_RS_FORCE_WASI': JSON.stringify(''), - - // This simplifies the Oxide loading code a small amount - 'process.env.NAPI_RS_NATIVE_LIBRARY_PATH': JSON.stringify(''), - }, - - compile: { - target, - outfile, - - // Disable .env loading - autoloadDotenv: false, - - // Disable bunfig.toml loading - autoloadBunfig: false, - }, - - plugins: [ - { - name: 'tailwindcss-plugin', - setup(build) { - build.onLoad({ filter: /tailwindcss-oxide\.wasi\.cjs$/ }, async (args) => { - return { contents: '' } - }) - }, - }, - ], - }) - - let entry = result.outputs.find((output) => output.kind === 'entry-point') - if (!entry) throw new Error(`Build failed for ${target}`) + await new Promise((resolve) => setTimeout(resolve, 100)) let content = await readFile(outfile) + let sum = createHash('sha256').update(content).digest('hex') - summary.push({ - target, - name, - sum: createHash('sha256').update(content).digest('hex'), - }) + let elapsed = process.hrtime.bigint() - start + + return { + triple, + file, + sum, + elapsed, + } } await mkdir(path.resolve(__dirname, '../dist'), { recursive: true }) +// Build platform binaries and checksum them +let results = await Promise.all([ + build('bun-linux-arm64', './tailwindcss-linux-arm64'), + build('bun-linux-x64', './tailwindcss-linux-x64'), + // build('linux-armv7', 'tailwindcss-linux-armv7'), + build('bun-darwin-arm64', './tailwindcss-macos-arm64'), + build('bun-darwin-x64', './tailwindcss-macos-x64'), + // The Windows x64 build uses `bun-baseline` instead of the regular bun build. + // This enables support for running inside the ARM emulation mode. + build('bun-windows-x64-baseline', './tailwindcss-windows-x64.exe'), + // buildForPlatform('win32-arm64', 'tailwindcss-windows-arm64'), +]) + // Write the checksums to a file let sumsFile = path.resolve(__dirname, '../dist/sha256sums.txt') -let sums = summary.map(({ name, sum }) => `${sum} ./${name}`) +let sums = results.map(({ file, sum }) => `${sum} ${file}`) + +console.table( + results.map(({ triple, sum, elapsed }) => ({ + triple, + sum, + elapsed: `${(Number(elapsed) / 1e6).toFixed(0)}ms`, + })), +) await writeFile(sumsFile, sums.join('\n') + '\n') - -console.table(summary.map(({ target, sum }) => ({ target, sum }))) - -let elapsed = process.hrtime.bigint() - start -console.log(`Build completed in ${(Number(elapsed) / 1e6).toFixed(0)}ms`) diff --git a/packages/@tailwindcss-standalone/src/index.ts b/packages/@tailwindcss-standalone/src/index.ts index 23a928f8b..98e75c3dc 100644 --- a/packages/@tailwindcss-standalone/src/index.ts +++ b/packages/@tailwindcss-standalone/src/index.ts @@ -1,3 +1,4 @@ +import fs from 'node:fs' import { createRequire } from 'node:module' import packageJson from 'tailwindcss/package.json' @@ -60,39 +61,14 @@ globalThis.__tw_load = async (id) => { } } globalThis.__tw_version = packageJson.version - -// We use a plugin to make sure that the JS APIs are bundled with the standalone -// CLI and can be imported inside configs and plugins -Bun.plugin({ - name: 'bundle-tailwindcss-apis', - target: 'bun', - async setup(build) { - // These imports must be static strings otherwise they won't be bundled - let bundled = { - tailwindcss: await import('tailwindcss'), - 'tailwindcss/colors': await import('tailwindcss/colors'), - 'tailwindcss/colors.js': await import('tailwindcss/colors'), - 'tailwindcss/plugin': await import('tailwindcss/plugin'), - 'tailwindcss/plugin.js': await import('tailwindcss/plugin'), - 'tailwindcss/package.json': await import('tailwindcss/package.json'), - 'tailwindcss/lib/util/flattenColorPalette': - await import('tailwindcss/lib/util/flattenColorPalette'), - 'tailwindcss/lib/util/flattenColorPalette.js': - await import('tailwindcss/lib/util/flattenColorPalette'), - 'tailwindcss/defaultTheme': await import('tailwindcss/defaultTheme'), - 'tailwindcss/defaultTheme.js': await import('tailwindcss/defaultTheme'), - } - - for (let [id, exports] of Object.entries(bundled)) { - build.module(id, () => ({ - loader: 'object', - exports: { - ...exports, - __esModule: true, - }, - })) - } - }, -}) +globalThis.__tw_readFile = async (path, encoding) => { + // When reading a file from the `$bunfs`, we need to use the synchronous + // `readFileSync` API + let isEmbeddedFileBase = path.includes('/$bunfs/root') || path.includes(':/~BUN/root') + if (!isEmbeddedFileBase) { + return + } + return fs.readFileSync(path, encoding) +} await import('../../@tailwindcss-cli/src/index.ts') diff --git a/packages/@tailwindcss-standalone/src/types.d.ts b/packages/@tailwindcss-standalone/src/types.d.ts index 0b5deb6ea..3212ac5b6 100644 --- a/packages/@tailwindcss-standalone/src/types.d.ts +++ b/packages/@tailwindcss-standalone/src/types.d.ts @@ -6,5 +6,6 @@ declare module '*.css' { declare var __tw_version: string | undefined declare var __tw_resolve: undefined | ((id: string, base?: string) => string | false) declare var __tw_readFile: - undefined | ((path: string, encoding: BufferEncoding) => Promise) + | undefined + | ((path: string, encoding: BufferEncoding) => Promise) declare var __tw_load: undefined | ((path: string) => Promise) diff --git a/packages/@tailwindcss-turbopack/README.md b/packages/@tailwindcss-turbopack/README.md deleted file mode 100644 index ee54b4d03..000000000 --- a/packages/@tailwindcss-turbopack/README.md +++ /dev/null @@ -1,99 +0,0 @@ -

- - - - - Tailwind CSS - - -

- -

- A utility-first CSS framework for rapidly building custom user interfaces. -

- -

- Build Status - Total Downloads - Latest Release - License -

- ---- - -## Documentation - -For full documentation, visit [tailwindcss.com](https://tailwindcss.com). - -## Community - -For help, discussion about best practices, or feature ideas: - -[Discuss Tailwind CSS on GitHub](https://github.com/tailwindlabs/tailwindcss/discussions) - -## Contributing - -If you're interested in contributing to Tailwind CSS, please read our [contributing docs](https://github.com/tailwindlabs/tailwindcss/blob/main/.github/CONTRIBUTING.md) **before submitting a pull request**. - ---- - -## @tailwindcss/turbopack - -A Turbopack loader for Tailwind CSS v4. - -## Installation - -```sh -npm install @tailwindcss/turbopack -``` - -### Usage - -```javascript -// next.config.js -module.exports = { - turbopack: { - rules: { - '*.css': { - loaders: ['@tailwindcss/turbopack'], - as: '*.css', - }, - }, - }, -} -``` - -Then create a CSS file that imports Tailwind: - -```css -/* src/index.css */ -@import 'tailwindcss'; -``` - -### Options - -#### `base` - -The base directory to scan for class candidates. Defaults to the current working directory. - -```javascript -{ - loader: '@tailwindcss/turbopack', - options: { - base: process.cwd(), - }, -} -``` - -#### `optimize` - -Whether to optimize and minify the output CSS. Defaults to `true` in production mode. - -```javascript -{ - loader: '@tailwindcss/turbopack', - options: { - optimize: true, // or { minify: true } - }, -} -``` diff --git a/packages/@tailwindcss-turbopack/package.json b/packages/@tailwindcss-turbopack/package.json deleted file mode 100644 index abdbbe90e..000000000 --- a/packages/@tailwindcss-turbopack/package.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "name": "@tailwindcss/turbopack", - "version": "4.3.3", - "description": "A Turbopack loader for Tailwind CSS v4.", - "license": "MIT", - "repository": { - "type": "git", - "url": "https://github.com/tailwindlabs/tailwindcss.git", - "directory": "packages/@tailwindcss-turbopack" - }, - "bugs": "https://github.com/tailwindlabs/tailwindcss/issues", - "homepage": "https://tailwindcss.com", - "scripts": { - "build": "tsup-node", - "dev": "pnpm run build -- --watch" - }, - "files": [ - "dist/" - ], - "publishConfig": { - "provenance": true, - "access": "public" - }, - "exports": { - ".": { - "types": "./dist/index.d.ts", - "import": "./dist/index.mjs", - "require": "./dist/index.js" - } - }, - "main": "./dist/index.js", - "types": "./dist/index.d.ts", - "dependencies": { - "@alloc/quick-lru": "^5.2.0", - "@tailwindcss/node": "workspace:*", - "@tailwindcss/oxide": "workspace:*", - "tailwindcss": "workspace:*" - }, - "devDependencies": { - "@types/node": "catalog:", - "webpack": "catalog:" - } -} diff --git a/packages/@tailwindcss-turbopack/src/index.cts b/packages/@tailwindcss-turbopack/src/index.cts deleted file mode 100644 index dbdded748..000000000 --- a/packages/@tailwindcss-turbopack/src/index.cts +++ /dev/null @@ -1,5 +0,0 @@ -import tailwindLoader from './index.ts' - -// CommonJS export for webpack loaders - must be the function directly -// @ts-ignore -export = tailwindLoader diff --git a/packages/@tailwindcss-turbopack/src/index.ts b/packages/@tailwindcss-turbopack/src/index.ts deleted file mode 100644 index a70f28871..000000000 --- a/packages/@tailwindcss-turbopack/src/index.ts +++ /dev/null @@ -1,287 +0,0 @@ -import QuickLRU from '@alloc/quick-lru' -import { - compile, - env, - Features, - Instrumentation, - normalizePath, - optimize, - Polyfills, -} from '@tailwindcss/node' -import { clearRequireCache } from '@tailwindcss/node/require-cache' -import { Scanner } from '@tailwindcss/oxide' -import fs from 'node:fs' -import path from 'node:path' -import type { LoaderContext } from 'webpack' - -const DEBUG = env.DEBUG - -export interface LoaderOptions { - /** - * The base directory to scan for class candidates. - * - * Defaults to the current working directory. - */ - base?: string - - /** - * Optimize and minify the output CSS. - */ - optimize?: boolean | { minify?: boolean } -} - -interface CacheEntry { - mtimes: Map - compiler: null | Awaited> - scanner: null | Scanner - candidates: Set - fullRebuildPaths: string[] -} - -const cache = new QuickLRU({ maxSize: 50 }) - -function getCacheKey(resourceId: string, opts: LoaderOptions): string { - return `${resourceId}:${opts.base ?? ''}:${JSON.stringify(opts.optimize)}` -} - -function getContextFromCache(resourceId: string, opts: LoaderOptions): CacheEntry { - let key = getCacheKey(resourceId, opts) - if (cache.has(key)) return cache.get(key)! - let entry: CacheEntry = { - mtimes: new Map(), - compiler: null, - scanner: null, - candidates: new Set(), - fullRebuildPaths: [], - } - cache.set(key, entry) - return entry -} - -export default async function tailwindLoader( - this: LoaderContext, - source: string, -): Promise { - let callback = this.async() - let options = this.getOptions() ?? {} - let inputFile = this.resourcePath - let resourceId = this.resource - let base = options.base ?? process.cwd() - let shouldOptimize = options.optimize ?? process.env.NODE_ENV === 'production' - let isCSSModuleFile = inputFile.endsWith('.module.css') - - using I = new Instrumentation() - - DEBUG && I.start(`[@tailwindcss/turbopack] ${path.relative(base, inputFile)}`) - - // Bail out early if this is guaranteed to be a non-Tailwind CSS file. - { - DEBUG && I.start('Quick bail check') - let canBail = !/@(import|reference|theme|variant|config|plugin|apply|tailwind)\b/.test(source) - if (canBail) { - DEBUG && I.end('Quick bail check') - DEBUG && I.end(`[@tailwindcss/turbopack] ${path.relative(base, inputFile)}`) - callback(null, source) - return - } - DEBUG && I.end('Quick bail check') - } - - try { - let context = getContextFromCache(resourceId, options) - let inputBasePath = path.dirname(path.resolve(inputFile)) - - // Whether this is the first build or not - let isInitialBuild = context.compiler === null - - async function createCompiler() { - DEBUG && I.start('Setup compiler') - if (context.fullRebuildPaths.length > 0 && !isInitialBuild) { - clearRequireCache(context.fullRebuildPaths) - } - - context.fullRebuildPaths = [] - - DEBUG && I.start('Create compiler') - let compiler = await compile(source, { - from: inputFile, - base: inputBasePath, - shouldRewriteUrls: true, - onDependency: (depPath) => context.fullRebuildPaths.push(depPath), - // In CSS Module files, we have to disable the `@property` polyfill since these will - // emit global `*` rules which are considered to be non-pure and will cause builds - // to fail. - polyfills: isCSSModuleFile ? Polyfills.All ^ Polyfills.AtProperty : Polyfills.All, - }) - DEBUG && I.end('Create compiler') - - DEBUG && I.end('Setup compiler') - return compiler - } - - // Setup the compiler if it doesn't exist yet - context.compiler ??= await createCompiler() - - // Early exit if no Tailwind features are used - if (context.compiler.features === Features.None) { - DEBUG && I.end(`[@tailwindcss/turbopack] ${path.relative(base, inputFile)}`) - callback(null, source) - return - } - - let rebuildStrategy: 'full' | 'incremental' = 'incremental' - - // Track file modification times to CSS files - DEBUG && I.start('Register full rebuild paths') - { - // Report dependencies for config files, plugins, etc. - for (let file of context.fullRebuildPaths) { - this.addDependency(path.resolve(file)) - } - - let files = [...context.fullRebuildPaths, inputFile] - - for (let file of files) { - let changedTime: number | null = null - try { - changedTime = fs.statSync(file)?.mtimeMs ?? null - } catch { - // File might not exist - } - - if (changedTime === null) { - if (file === inputFile) { - rebuildStrategy = 'full' - } - continue - } - - let prevTime = context.mtimes.get(file) - if (prevTime === changedTime) continue - - rebuildStrategy = 'full' - context.mtimes.set(file, changedTime) - } - } - DEBUG && I.end('Register full rebuild paths') - - if (rebuildStrategy === 'full' && !isInitialBuild) { - context.compiler = await createCompiler() - } - - let compiler = context.compiler - - // Check if we need to process this file at all - if ( - !( - compiler.features & - (Features.AtApply | Features.JsPluginCompat | Features.ThemeFunction | Features.Utilities) - ) - ) { - DEBUG && I.end(`[@tailwindcss/turbopack] ${path.relative(base, inputFile)}`) - callback(null, source) - return - } - - // Setup or update scanner if needed - if (context.scanner === null || rebuildStrategy === 'full') { - DEBUG && I.start('Setup scanner') - let sources = (() => { - // Disable auto source detection - if (compiler.root === 'none') { - return [] - } - - // No root specified, use the base directory - if (compiler.root === null) { - return [{ base, pattern: '**/*', negated: false }] - } - - // Use the specified root - return [{ ...compiler.root, negated: false }] - })().concat(compiler.sources) - - context.scanner = new Scanner({ sources }) - DEBUG && I.end('Setup scanner') - } - - // Scan for candidates if utilities are used - if (compiler.features & Features.Utilities) { - DEBUG && I.start('Scan for candidates') - for (let candidate of context.scanner.scan()) { - context.candidates.add(candidate) - } - DEBUG && I.end('Scan for candidates') - - DEBUG && I.start('Register dependency messages') - // Add all found files as direct dependencies - let resolvedInputFile = path.resolve(base, inputFile) - for (let file of context.scanner.files) { - let absolutePath = path.resolve(file) - // The CSS file cannot be a dependency of itself - if (absolutePath === resolvedInputFile) { - continue - } - this.addDependency(absolutePath) - } - - // Register context dependencies for glob patterns - for (let glob of context.scanner.globs) { - // Skip negated patterns - if (glob.pattern[0] === '!') continue - - // Avoid adding a dependency on the base directory itself - if (glob.pattern === '*' && base === glob.base) { - continue - } - - this.addContextDependency(path.resolve(glob.base)) - } - - // Validate that source(...) paths are directories - let root = compiler.root - if (root !== 'none' && root !== null) { - let basePath = normalizePath(path.resolve(root.base, root.pattern)) - try { - let stats = fs.statSync(basePath) - if (!stats.isDirectory()) { - throw new Error( - `The path given to \`source(…)\` must be a directory but got \`source(${basePath})\` instead.`, - ) - } - } catch (err) { - if ((err as NodeJS.ErrnoException).code !== 'ENOENT') { - throw err - } - // Directory doesn't exist yet, which is fine - } - } - DEBUG && I.end('Register dependency messages') - } - - DEBUG && I.start('Build utilities') - let css = compiler.build([...context.candidates]) - DEBUG && I.end('Build utilities') - - // Optionally optimize the output - let result = css - if (shouldOptimize) { - DEBUG && I.start('Optimization') - let optimized = optimize(css, { - minify: typeof shouldOptimize === 'object' ? shouldOptimize.minify : true, - }) - result = optimized.code - DEBUG && I.end('Optimization') - } - - DEBUG && I.end(`[@tailwindcss/turbopack] ${path.relative(base, inputFile)}`) - callback(null, result) - } catch (error) { - // Clear the cache entry on error to force a full rebuild next time - let key = getCacheKey(resourceId, options) - cache.delete(key) - - DEBUG && I.end(`[@tailwindcss/turbopack] ${path.relative(base, inputFile)}`) - callback(error as Error) - } -} diff --git a/packages/@tailwindcss-turbopack/tsconfig.json b/packages/@tailwindcss-turbopack/tsconfig.json deleted file mode 100644 index d2131cbeb..000000000 --- a/packages/@tailwindcss-turbopack/tsconfig.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "extends": "../tsconfig.base.json", - "compilerOptions": { - "verbatimModuleSyntax": false, - }, -} diff --git a/packages/@tailwindcss-turbopack/tsup.config.ts b/packages/@tailwindcss-turbopack/tsup.config.ts deleted file mode 100644 index 998eebe4f..000000000 --- a/packages/@tailwindcss-turbopack/tsup.config.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { defineConfig } from 'tsup' - -export default defineConfig([ - { - format: ['esm'], - clean: true, - minify: true, - cjsInterop: true, - dts: true, - entry: ['src/index.ts'], - }, - { - format: ['cjs'], - minify: true, - cjsInterop: true, - dts: true, - entry: ['src/index.cts'], - }, -]) diff --git a/packages/@tailwindcss-upgrade/README.md b/packages/@tailwindcss-upgrade/README.md index 5f532607d..95ec9d87d 100644 --- a/packages/@tailwindcss-upgrade/README.md +++ b/packages/@tailwindcss-upgrade/README.md @@ -13,10 +13,10 @@

- Build Status + Build Status Total Downloads - Latest Release - License + Latest Release + License

--- @@ -27,10 +27,14 @@ For full documentation, visit [tailwindcss.com](https://tailwindcss.com). ## Community -For help, discussion about best practices, or feature ideas: +For help, discussion about best practices, or any other conversation that would benefit from being searchable: -[Discuss Tailwind CSS on GitHub](https://github.com/tailwindlabs/tailwindcss/discussions) +[Discuss Tailwind CSS on GitHub](https://github.com/tailwindcss/tailwindcss/discussions) + +For chatting with others using the framework: + +[Join the Tailwind CSS Discord Server](https://discord.gg/7NF8GNe) ## Contributing -If you're interested in contributing to Tailwind CSS, please read our [contributing docs](https://github.com/tailwindlabs/tailwindcss/blob/main/.github/CONTRIBUTING.md) **before submitting a pull request**. +If you're interested in contributing to Tailwind CSS, please read our [contributing docs](https://github.com/tailwindcss/tailwindcss/blob/next/.github/CONTRIBUTING.md) **before submitting a pull request**. diff --git a/packages/@tailwindcss-upgrade/package.json b/packages/@tailwindcss-upgrade/package.json index e960d7677..7183ec3d5 100644 --- a/packages/@tailwindcss-upgrade/package.json +++ b/packages/@tailwindcss-upgrade/package.json @@ -1,6 +1,6 @@ { "name": "@tailwindcss/upgrade", - "version": "4.3.3", + "version": "4.0.0-beta.7", "description": "A utility-first CSS framework for rapidly building custom user interfaces.", "license": "MIT", "repository": { @@ -27,26 +27,26 @@ "access": "public" }, "dependencies": { - "@tailwindcss/node": "workspace:*", - "@tailwindcss/oxide": "workspace:*", - "dedent": "catalog:", - "enhanced-resolve": "catalog:", - "globby": "^16.2.2", - "jiti": "^2.7.0", + "@tailwindcss/node": "workspace:^", + "@tailwindcss/oxide": "workspace:^", + "braces": "^3.0.3", + "dedent": "1.5.3", + "enhanced-resolve": "^5.17.1", + "globby": "^14.0.2", + "jiti": "^2.0.0-beta.3", "mri": "^1.2.0", "picocolors": "^1.1.1", - "postcss": "catalog:", - "postcss-import": "^16.1.1", - "postcss-selector-parser": "^7.1.4", - "prettier": "catalog:", - "semver": "^7.8.5", - "tailwindcss": "workspace:*", - "tree-sitter": "^0.25.1", - "tree-sitter-typescript": "^0.23.2" + "postcss": "^8.4.41", + "postcss-import": "^16.1.0", + "postcss-selector-parser": "^7.0.0", + "prettier": "^3.3.3", + "tree-sitter": "^0.22.1", + "tree-sitter-typescript": "^0.23.2", + "tailwindcss": "workspace:*" }, "devDependencies": { + "@types/braces": "^3.0.4", "@types/node": "catalog:", - "@types/postcss-import": "^14.0.3", - "@types/semver": "^7.8.0" + "@types/postcss-import": "^14.0.3" } } diff --git a/packages/@tailwindcss-upgrade/src/codemods/css/analyze.ts b/packages/@tailwindcss-upgrade/src/codemods/css/analyze.ts deleted file mode 100644 index c7058df54..000000000 --- a/packages/@tailwindcss-upgrade/src/codemods/css/analyze.ts +++ /dev/null @@ -1,303 +0,0 @@ -import { isGitIgnored } from 'globby' -import path from 'node:path' -import postcss, { type Result } from 'postcss' -import { DefaultMap } from '../../../../tailwindcss/src/utils/default-map' -import { segment } from '../../../../tailwindcss/src/utils/segment' -import { Stylesheet, type StylesheetConnection } from '../../stylesheet' -import { gitRoot } from '../../utils/git' -import { error, highlight, relative } from '../../utils/renderer' -import { resolveCssId } from '../../utils/resolve' - -export async function analyze(stylesheets: Stylesheet[], { base }: { base: string }) { - // Use the project's git root, instead of the `base` to ensure all - // `.gitignore` rules are being used. - let isIgnored = await isGitIgnored({ cwd: gitRoot(base) ?? base }) - let processingQueue: (() => Promise)[] = [] - let stylesheetsByFile = new DefaultMap((file) => { - // We don't want to process ignored files (like node_modules) - try { - if (isIgnored(file)) { - return null - } - } catch { - // If the file is not part of the current working directory (which can - // happen if you import `tailwindcss` and it's loading a shared file from - // pnpm) then this will throw. - return null - } - - try { - let sheet = Stylesheet.loadSync(file) - - // Mutate incoming stylesheets to include the newly discovered sheet - stylesheets.push(sheet) - - // Queue up the processing of this stylesheet - processingQueue.push(() => processor.process(sheet.root, { from: sheet.file! })) - - return sheet - } catch { - return null - } - }) - - // Step 1: Record which `@import` rules point to which stylesheets - // and which stylesheets are parents/children of each other - let processor = postcss([ - { - postcssPlugin: 'mark-import-nodes', - AtRule: { - import(node) { - // Find what the import points to - let id = node.params.match(/['"](.*?)['"]/)?.[1] - if (!id) return - - let basePath = node.source?.input.file - ? path.dirname(node.source.input.file) - : process.cwd() - - // Resolve the import to a file path - let resolvedPath: string | false = false - try { - // We first try to resolve the file as relative to the current file - // to mimic the behavior of `postcss-import` since that's what was - // used to resolve imports in Tailwind CSS v3. - if (id[0] !== '.') { - try { - resolvedPath = resolveCssId(`./${id}`, basePath) - } catch {} - } - - if (!resolvedPath) { - resolvedPath = resolveCssId(id, basePath) - } - } catch (err) { - // Import is a URL, we don't want to process these, but also don't - // want to show an error message for them. - if (id.startsWith('http://') || id.startsWith('https://') || id.startsWith('//')) { - return - } - - // Something went wrong, we can't resolve the import. - error( - `Failed to resolve import: ${highlight(id)} in ${highlight(relative(node.source?.input.file!, basePath))}. Skipping.`, - { prefix: '↳ ' }, - ) - return - } - - if (!resolvedPath) return - - // Find the stylesheet pointing to the resolved path - let stylesheet = stylesheetsByFile.get(resolvedPath) - - // If it _does not_ exist in stylesheets we don't care and skip it - // this is likely because its in node_modules or a workspace package - // that we don't want to modify - if (!stylesheet) return - - // Mark the import node with the ID of the stylesheet it points to - // We will use these later to build lookup tables and modify the AST - node.raws.tailwind_destination_sheet_id = stylesheet.id - - let parent = node.source?.input.file - ? stylesheetsByFile.get(node.source.input.file) - : undefined - - let layers: string[] = [] - - for (let part of segment(node.params, ' ')) { - if (!part.startsWith('layer(')) continue - if (!part.endsWith(')')) continue - - layers.push(part.slice(6, -1).trim()) - } - - // Connect sheets together in a dependency graph - if (parent) { - let meta = { layers } - stylesheet.parents.add({ item: parent, meta }) - parent.children.add({ item: stylesheet, meta }) - } - }, - }, - }, - ]) - - // Seed the map with all the known stylesheets, and queue up the processing of - // each incoming stylesheet. - for (let sheet of stylesheets) { - if (sheet.file) { - stylesheetsByFile.set(sheet.file, sheet) - processingQueue.push(() => processor.process(sheet.root, { from: sheet.file ?? undefined })) - } - } - - // Process all the stylesheets from step 1 - while (processingQueue.length > 0) { - let task = processingQueue.shift()! - await task() - } - - // --- - - let commonPath = process.cwd() - - function pathToString(path: StylesheetConnection[]) { - let parts: string[] = [] - - for (let connection of path) { - if (!connection.item.file) continue - - let filePath = connection.item.file.replace(commonPath, '') - let layers = connection.meta.layers.join(', ') - - if (layers.length > 0) { - parts.push(`${filePath} (layers: ${layers})`) - } else { - parts.push(filePath) - } - } - - return parts.join(' <- ') - } - - let lines: string[] = [] - - for (let sheet of stylesheets) { - if (!sheet.file) continue - - let { convertiblePaths, nonConvertiblePaths } = sheet.analyzeImportPaths() - let isAmbiguous = convertiblePaths.length > 0 && nonConvertiblePaths.length > 0 - - if (!isAmbiguous) continue - - sheet.canMigrate = false - - let filePath = sheet.file.replace(commonPath, '') - - for (let path of convertiblePaths) { - lines.push(`- ${filePath} <- ${pathToString(path)}`) - } - - for (let path of nonConvertiblePaths) { - lines.push(`- ${filePath} <- ${pathToString(path)}`) - } - } - - if (lines.length === 0) { - let tailwindRootLeafs = new Set() - - for (let sheet of stylesheets) { - // If the current file already contains `@config`, then we can assume it's - // a Tailwind CSS root file. - sheet.root.walkAtRules('config', () => { - sheet.isTailwindRoot = true - return false - }) - if (sheet.isTailwindRoot) continue - - // If an `@tailwind` at-rule, or `@import "tailwindcss"` is present, - // then we can assume it's a file where Tailwind CSS might be configured. - // - // However, if 2 or more stylesheets exist with these rules that share a - // common parent, then we want to mark the common parent as the root - // stylesheet instead. - sheet.root.walkAtRules((node) => { - if ( - node.name === 'tailwind' || - (node.name === 'import' && node.params.match(/^["']tailwindcss["']/)) || - (node.name === 'import' && node.params.match(/^["']tailwindcss\/.*?["']$/)) - ) { - sheet.isTailwindRoot = true - tailwindRootLeafs.add(sheet) - } - }) - } - - // Only a single Tailwind CSS root file exists, no need to do anything else. - if (tailwindRootLeafs.size <= 1) { - return - } - - // Mark the common parent as the root file - { - // Group each sheet from tailwindRootLeafs by their common parent - let commonParents = new DefaultMap>(() => new Set()) - - // Seed common parents with leafs - for (let sheet of tailwindRootLeafs) { - commonParents.get(sheet).add(sheet) - } - - // If any 2 common parents come from the same tree, then all children of - // parent A and parent B will be moved to the parent of parent A and - // parent B. Parent A and parent B will be removed. - let repeat = true - repeat: while (repeat) { - repeat = false - - for (let [sheetA, childrenA] of commonParents) { - for (let [sheetB, childrenB] of commonParents) { - if (sheetA === sheetB) continue - - // Ancestors from self to root. Reversed order so we find the - // nearest common parent first - // - // Including self because if you compare a sheet with its parent, - // then the parent is still the common sheet between the two. In - // this case, the parent is the root file. - let ancestorsA = [sheetA].concat(Array.from(sheetA.ancestors()).reverse()) - let ancestorsB = [sheetB].concat(Array.from(sheetB.ancestors()).reverse()) - - for (let parentA of ancestorsA) { - for (let parentB of ancestorsB) { - if (parentA !== parentB) continue - - // Found the parent - let parent = parentA - - commonParents.delete(sheetA) - commonParents.delete(sheetB) - - for (let child of childrenA) { - commonParents.get(parent).add(child) - } - - for (let child of childrenB) { - commonParents.get(parent).add(child) - } - - // Found a common parent between sheet A and sheet B. We can - // stop looking for more common parents between A and B, and - // continue with the next sheet. - repeat = true - continue repeat - } - } - } - } - } - - // Mark the common parent as the Tailwind CSS root file, and remove the - // flag from each leaf. - for (let [parent, children] of commonParents) { - parent.isTailwindRoot = true - - for (let child of children) { - if (parent === child) continue - - child.isTailwindRoot = false - } - } - return - } - } - - { - let error = `You have one or more stylesheets that are imported into a utility layer and non-utility layer.\n` - error += `We cannot convert stylesheets under these conditions. Please look at the following stylesheets:\n` - - throw new Error(error + lines.join('\n')) - } -} diff --git a/packages/@tailwindcss-upgrade/src/codemods/css/link.ts b/packages/@tailwindcss-upgrade/src/codemods/css/link.ts deleted file mode 100644 index 04c2dd770..000000000 --- a/packages/@tailwindcss-upgrade/src/codemods/css/link.ts +++ /dev/null @@ -1,122 +0,0 @@ -import { normalizePath } from '@tailwindcss/node' -import path from 'node:path' -import postcss from 'postcss' -import { DefaultMap } from '../../../../tailwindcss/src/utils/default-map' -import { Stylesheet } from '../../stylesheet' -import { error, highlight, relative, success } from '../../utils/renderer' -import { detectConfigPath } from '../template/prepare-config' - -export async function linkConfigs( - stylesheets: Stylesheet[], - { configPath, base }: { configPath: string | null; base: string }, -) { - let rootStylesheets = stylesheets.filter((sheet) => sheet.isTailwindRoot) - if (rootStylesheets.length === 0) { - throw new Error( - `Cannot find any CSS files that reference Tailwind CSS.\nBefore your project can be upgraded you need to create a CSS file that imports Tailwind CSS or uses ${highlight('@tailwind')}.`, - ) - } - let withoutAtConfig = rootStylesheets.filter((sheet) => { - let hasConfig = false - sheet.root.walkAtRules('config', (node) => { - let configPath = path.resolve(path.dirname(sheet.file!), node.params.slice(1, -1)) - sheet.linkedConfigPath = configPath - hasConfig = true - return false - }) - return !hasConfig - }) - - // All stylesheets have a `@config` directives - if (withoutAtConfig.length === 0) return - - // Find the config file path for each stylesheet - let configPathBySheet = new Map() - let sheetByConfigPath = new DefaultMap>(() => new Set()) - for (let sheet of withoutAtConfig) { - if (!sheet.file) continue - - let localConfigPath = configPath as string - if (configPath === null) { - localConfigPath = await detectConfigPath(path.dirname(sheet.file), base) - } else if (!path.isAbsolute(localConfigPath)) { - localConfigPath = path.resolve(base, localConfigPath) - } - - configPathBySheet.set(sheet, localConfigPath) - sheetByConfigPath.get(localConfigPath).add(sheet) - } - - let problematicStylesheets = new Set() - for (let sheets of sheetByConfigPath.values()) { - if (sheets.size > 1) { - for (let sheet of sheets) { - problematicStylesheets.add(sheet) - } - } - } - - // There are multiple "root" files without `@config` directives. Manual - // intervention is needed to link to the correct Tailwind config files. - if (problematicStylesheets.size > 1) { - for (let sheet of problematicStylesheets) { - error( - `Could not determine configuration file for: ${highlight(relative(sheet.file!, base))}\nUpdate your stylesheet to use ${highlight('@config')} to specify the correct configuration file explicitly and then run the upgrade tool again.`, - { prefix: '↳ ' }, - ) - } - - process.exit(1) - } - - let relativePath = relative - for (let [sheet, configPath] of configPathBySheet) { - try { - if (!sheet || !sheet.file) return - success( - `Linked ${highlight(relativePath(configPath, base))} to ${highlight(relativePath(sheet.file, base))}`, - { prefix: '↳ ' }, - ) - - // Link the `@config` directive to the root stylesheets - - // Track the config file path on the stylesheet itself for easy access - // without traversing the CSS ast and finding the corresponding - // `@config` later. - sheet.linkedConfigPath = configPath - - // Create a relative path from the current file to the config file. - let relative = path.relative(path.dirname(sheet.file), configPath) - - // If the path points to a file in the same directory, `path.relative` will - // remove the leading `./` and we need to add it back in order to still - // consider the path relative - if (!relative.startsWith('.') && !path.isAbsolute(relative)) { - relative = './' + relative - } - - relative = normalizePath(relative) - - // Add the `@config` directive to the root stylesheet. - { - let target = sheet.root as postcss.Root | postcss.AtRule - let atConfig = postcss.atRule({ name: 'config', params: `'${relative}'` }) - - sheet.root.walkAtRules((node) => { - if (node.name === 'tailwind' || node.name === 'import') { - target = node - } - }) - - if (target.type === 'root') { - sheet.root.prepend(atConfig) - } else if (target.type === 'atrule') { - target.after(atConfig) - } - } - } catch (e: any) { - error('Could not load the configuration file: ' + e.message, { prefix: '↳ ' }) - process.exit(1) - } - } -} diff --git a/packages/@tailwindcss-upgrade/src/codemods/css/migrate.ts b/packages/@tailwindcss-upgrade/src/codemods/css/migrate.ts deleted file mode 100644 index cb9150851..000000000 --- a/packages/@tailwindcss-upgrade/src/codemods/css/migrate.ts +++ /dev/null @@ -1,57 +0,0 @@ -import postcss from 'postcss' -import type { Config } from '../../../../tailwindcss/src/compat/plugin-api' -import type { DesignSystem } from '../../../../tailwindcss/src/design-system' -import { Stylesheet } from '../../stylesheet' -import type { JSConfigMigration } from '../config/migrate-js-config' -import { migrateAtApply } from './migrate-at-apply' -import { migrateAtLayerUtilities } from './migrate-at-layer-utilities' -import { migrateConfig } from './migrate-config' -import { migrateImport } from './migrate-import' -import { migrateMediaScreen } from './migrate-media-screen' -import { migrateMissingLayers } from './migrate-missing-layers' -import { migratePreflight } from './migrate-preflight' -import { migrateTailwindDirectives } from './migrate-tailwind-directives' -import { migrateThemeToVar } from './migrate-theme-to-var' -import { migrateVariantsDirective } from './migrate-variants-directive' - -export interface MigrateOptions { - newPrefix: string | null - designSystem: DesignSystem | null - userConfig: Config | null - configFilePath: string | null - jsConfigMigration: JSConfigMigration | null -} - -export async function migrate(stylesheet: Stylesheet, options: MigrateOptions) { - if (!stylesheet.file) { - throw new Error('Cannot migrate a stylesheet without a file path') - } - - if (!stylesheet.canMigrate) return - - await migrateContents(stylesheet, options) -} - -export async function migrateContents( - stylesheet: Stylesheet | string, - options: MigrateOptions, - file?: string, -) { - if (typeof stylesheet === 'string') { - stylesheet = await Stylesheet.fromString(stylesheet) - stylesheet.file = file ?? null - } - - return postcss() - .use(migrateImport()) - .use(migrateAtApply(options)) - .use(migrateMediaScreen(options)) - .use(migrateVariantsDirective()) - .use(migrateAtLayerUtilities(stylesheet)) - .use(migrateMissingLayers()) - .use(migrateTailwindDirectives(options)) - .use(migrateConfig(stylesheet, options)) - .use(migratePreflight(options)) - .use(migrateThemeToVar(options)) - .process(stylesheet.root, { from: stylesheet.file ?? undefined }) -} diff --git a/packages/@tailwindcss-upgrade/src/codemods/css/split.ts b/packages/@tailwindcss-upgrade/src/codemods/css/split.ts deleted file mode 100644 index 146d30733..000000000 --- a/packages/@tailwindcss-upgrade/src/codemods/css/split.ts +++ /dev/null @@ -1,257 +0,0 @@ -import postcss from 'postcss' -import { DefaultMap } from '../../../../tailwindcss/src/utils/default-map' -import { Stylesheet, type StylesheetId } from '../../stylesheet' -import { walk, WalkAction } from '../../utils/walk' - -export async function split(stylesheets: Stylesheet[]) { - let stylesheetsById = new Map() - let stylesheetsByFile = new Map() - - for (let sheet of stylesheets) { - stylesheetsById.set(sheet.id, sheet) - - if (sheet.file) { - stylesheetsByFile.set(sheet.file, sheet) - } - } - - // Keep track of sheets that contain `@utility` rules - let requiresSplit = new Set() - - for (let sheet of stylesheets) { - // Root files don't need to be split - if (sheet.isTailwindRoot) continue - - let containsUtility = false - let containsUnsafe = sheet.layers().size > 0 - - walk(sheet.root, (node) => { - if (node.type === 'atrule' && node.name === 'utility') { - containsUtility = true - } - - // Safe to keep without splitting - else if ( - // An `@import "…" layer(…)` is safe - (node.type === 'atrule' && node.name === 'import' && node.params.includes('layer(')) || - // @layer blocks are safe - (node.type === 'atrule' && node.name === 'layer') || - // Comments are safe - node.type === 'comment' - ) { - return WalkAction.Skip - } - - // Everything else is not safe, and requires a split - else { - containsUnsafe = true - } - - // We already know we need to split this sheet - if (containsUtility && containsUnsafe) { - return WalkAction.Stop - } - - return WalkAction.Skip - }) - - if (containsUtility && containsUnsafe) { - requiresSplit.add(sheet) - } - } - - // Split every imported stylesheet into two parts - let utilitySheets = new Map() - - for (let sheet of stylesheets) { - // Ignore stylesheets that were not imported - if (!sheet.file) continue - if (sheet.parents.size === 0) continue - - // Skip stylesheets that don't have utilities - // and don't have any children that have utilities - if (!requiresSplit.has(sheet)) { - if (!Array.from(sheet.descendants()).some((child) => requiresSplit.has(child))) { - continue - } - } - - let utilities = postcss.root() - - walk(sheet.root, (node) => { - if (node.type !== 'atrule') return - if (node.name !== 'utility') return - - // `append` will move this node from the original sheet - // to the new utilities sheet - utilities.append(node) - - return WalkAction.Skip - }) - - let newFileName = sheet.file.replace(/\.css$/, '.utilities.css') - - let counter = 0 - - // If we already have a utility sheet with this name, we need to rename it - while (stylesheetsByFile.has(newFileName)) { - counter += 1 - newFileName = sheet.file.replace(/\.css$/, `.utilities.${counter}.css`) - } - - let utilitySheet = await Stylesheet.fromRoot(utilities, newFileName) - - utilitySheet.extension = counter > 0 ? `.utilities.${counter}.css` : `.utilities.css` - - utilitySheets.set(sheet, utilitySheet) - stylesheetsById.set(utilitySheet.id, utilitySheet) - } - - // Make sure the utility sheets are linked to one another - for (let [normalSheet, utilitySheet] of utilitySheets) { - for (let parent of normalSheet.parents) { - let utilityParent = utilitySheets.get(parent.item) - if (!utilityParent) continue - utilitySheet.parents.add({ - item: utilityParent, - meta: parent.meta, - }) - } - - for (let child of normalSheet.children) { - let utilityChild = utilitySheets.get(child.item) - if (!utilityChild) continue - utilitySheet.children.add({ - item: utilityChild, - meta: child.meta, - }) - } - } - - for (let sheet of stylesheets) { - let utilitySheet = utilitySheets.get(sheet) - let utilityImports: Set = new Set() - - for (let node of sheet.importRules) { - let sheetId = node.raws.tailwind_destination_sheet_id as StylesheetId | undefined - - // This import rule does not point to a stylesheet - // which likely means it points to `node_modules` - if (!sheetId) continue - - let originalDestination = stylesheetsById.get(sheetId) - - // This import points to a stylesheet that no longer exists which likely - // means it was removed by the optimizer this will be cleaned up later - if (!originalDestination) continue - - let utilityDestination = utilitySheets.get(originalDestination) - - // A utility sheet doesn't exist for this import so it doesn't need - // to be processed - if (!utilityDestination) continue - - let match = node.params.match(/(['"])(.*)\1/) - if (!match) return - - let quote = match[1] - let id = match[2] - - let newFile = id.replace(/\.css$/, utilityDestination.extension!) - - // The import will just point to the new file without any media queries, - // layers, or other conditions because `@utility` MUST be top-level. - let newImport = node.clone({ - params: `${quote}${newFile}${quote}`, - raws: { - tailwind_injected_layer: node.raws.tailwind_injected_layer, - tailwind_original_params: `${quote}${id}${quote}`, - tailwind_destination_sheet_id: utilityDestination.id, - }, - }) - - if (utilitySheet) { - // If this import is intended to go into the utility sheet - // we'll collect it into a list to add later. If we don't' - // we'll end up adding them in reverse order. - utilityImports.add(newImport) - } else { - // This import will go immediately after the original import - node.after(newImport) - } - } - - // Add imports to the top of the utility sheet if necessary - if (utilitySheet && utilityImports.size > 0) { - utilitySheet.root.prepend(Array.from(utilityImports)) - } - } - - // Tracks the at rules that import a given stylesheet - let importNodes = new DefaultMap>(() => new Set()) - - for (let sheet of stylesheetsById.values()) { - for (let node of sheet.importRules) { - let sheetId = node.raws.tailwind_destination_sheet_id as StylesheetId | undefined - - // This import rule does not point to a stylesheet - if (!sheetId) continue - - let destination = stylesheetsById.get(sheetId) - - // This import rule does not point to a stylesheet that exists - // We'll remove it later - if (!destination) continue - - importNodes.get(destination).add(node) - } - } - - // At this point we've created many `{name}.utilities.css` files. - // If the original file _becomes_ empty after splitting that means that - // dedicated utility file is not required and we can move the utilities - // back to the original file. - // - // This could be done in one step but separating them makes it easier to - // reason about since the stylesheets are in a consistent state before we - // perform any cleanup tasks. - let list: Stylesheet[] = [] - - for (let sheet of stylesheets.slice()) { - for (let child of sheet.descendants()) { - list.push(child) - } - - list.push(sheet) - } - - for (let sheet of list) { - let utilitySheet = utilitySheets.get(sheet) - - // This sheet was not split so there's nothing to do - if (!utilitySheet) continue - - // This sheet did not become empty - if (!sheet.isEmpty) continue - - // We have a sheet that became empty after splitting - // 1. Replace the sheet with it's utility sheet content - sheet.root = utilitySheet.root - - // 2. Rewrite imports in parent sheets to point to the original sheet - // Ideally this wouldn't need to be _undone_ but instead only done once at the end - for (let node of importNodes.get(utilitySheet)) { - node.params = node.raws.tailwind_original_params as any - } - - // 3. Remove the original import from the non-utility sheet - for (let node of importNodes.get(sheet)) { - node.remove() - } - - // 3. Mark the utility sheet for removal - utilitySheets.delete(sheet) - } - - stylesheets.push(...utilitySheets.values()) -} diff --git a/packages/@tailwindcss-upgrade/src/codemods/css/fixtures/test.css b/packages/@tailwindcss-upgrade/src/codemods/fixtures/test.css similarity index 100% rename from packages/@tailwindcss-upgrade/src/codemods/css/fixtures/test.css rename to packages/@tailwindcss-upgrade/src/codemods/fixtures/test.css diff --git a/packages/@tailwindcss-upgrade/src/codemods/css/format-nodes.test.ts b/packages/@tailwindcss-upgrade/src/codemods/format-nodes.test.ts similarity index 100% rename from packages/@tailwindcss-upgrade/src/codemods/css/format-nodes.test.ts rename to packages/@tailwindcss-upgrade/src/codemods/format-nodes.test.ts diff --git a/packages/@tailwindcss-upgrade/src/codemods/css/format-nodes.ts b/packages/@tailwindcss-upgrade/src/codemods/format-nodes.ts similarity index 98% rename from packages/@tailwindcss-upgrade/src/codemods/css/format-nodes.ts rename to packages/@tailwindcss-upgrade/src/codemods/format-nodes.ts index 489f2d349..a5c980505 100644 --- a/packages/@tailwindcss-upgrade/src/codemods/css/format-nodes.ts +++ b/packages/@tailwindcss-upgrade/src/codemods/format-nodes.ts @@ -1,6 +1,6 @@ import postcss, { type ChildNode, type Plugin, type Root } from 'postcss' import { format, type Options } from 'prettier' -import { walk } from '../../utils/walk' +import { walk } from '../utils/walk' const FORMAT_OPTIONS: Options = { parser: 'css', diff --git a/packages/@tailwindcss-upgrade/src/codemods/css/migrate-at-apply.test.ts b/packages/@tailwindcss-upgrade/src/codemods/migrate-at-apply.test.ts similarity index 53% rename from packages/@tailwindcss-upgrade/src/codemods/css/migrate-at-apply.test.ts rename to packages/@tailwindcss-upgrade/src/codemods/migrate-at-apply.test.ts index 9f6a92008..362f52054 100644 --- a/packages/@tailwindcss-upgrade/src/codemods/css/migrate-at-apply.test.ts +++ b/packages/@tailwindcss-upgrade/src/codemods/migrate-at-apply.test.ts @@ -1,11 +1,9 @@ import { __unstable__loadDesignSystem } from '@tailwindcss/node' import dedent from 'dedent' import postcss from 'postcss' -import { expect, it, vi } from 'vitest' -import type { Config } from '../../../../tailwindcss/src/compat/plugin-api' -import * as versions from '../../utils/version' +import { expect, it } from 'vitest' +import type { Config } from '../../../tailwindcss/src/compat/plugin-api' import { migrateAtApply } from './migrate-at-apply' -vi.spyOn(versions, 'isMajor').mockReturnValue(true) const css = dedent @@ -13,11 +11,6 @@ async function migrate(input: string, config: Config = {}) { let designSystem = await __unstable__loadDesignSystem( css` @import 'tailwindcss'; - - /* TODO(perf): Only here to speed up the tests */ - @theme { - --*: initial; - } `, { base: __dirname }, ) @@ -61,6 +54,21 @@ it('should append `!` to each utility, when using `!important`', async () => { `) }) +// TODO: Handle SCSS syntax +it.skip('should append `!` to each utility, when using `#{!important}`', async () => { + expect( + await migrate(css` + .foo { + @apply flex flex-col #{!important}; + } + `), + ).toMatchInlineSnapshot(` + ".foo { + @apply flex! flex-col!; + }" + `) +}) + it('should move the legacy `!` prefix, to the new `!` postfix notation', async () => { expect( await migrate(css` @@ -75,44 +83,35 @@ it('should move the legacy `!` prefix, to the new `!` postfix notation', async ( `) }) -it( - 'should apply all candidate migration when migrating with a config', - { timeout: 10_000 }, - async () => { - async function migrateWithPrefix(input: string) { - return postcss() - .use( - migrateAtApply({ - designSystem: await __unstable__loadDesignSystem( - css` - @import 'tailwindcss' prefix(tw); +it('should apply all candidate migration when migrating with a config', async () => { + async function migrateWithPrefix(input: string) { + return postcss() + .use( + migrateAtApply({ + designSystem: await __unstable__loadDesignSystem( + css` + @import 'tailwindcss' prefix(tw); + `, + { base: __dirname }, + ), + userConfig: { + prefix: 'tw_', + }, + }), + ) + .process(input, { from: expect.getState().testPath }) + .then((result) => result.css) + } - /* TODO(perf): Only here to speed up the tests */ - @theme { - --*: initial; - } - `, - { base: __dirname }, - ), - userConfig: { - prefix: 'tw_', - }, - }), - ) - .process(input, { from: expect.getState().testPath }) - .then((result) => result.css) - } - - expect( - await migrateWithPrefix(css` - .foo { - @apply !tw_flex [color:--my-color] tw_bg-gradient-to-t; - } - `), - ).toMatchInlineSnapshot(` + expect( + await migrateWithPrefix(css` + .foo { + @apply !tw_flex [color:--my-color] tw_bg-gradient-to-t; + } + `), + ).toMatchInlineSnapshot(` ".foo { - @apply tw:flex! tw:text-(--my-color) tw:bg-linear-to-t; + @apply tw:flex! tw:[color:var(--my-color)] tw:bg-linear-to-t; }" `) - }, -) +}) diff --git a/packages/@tailwindcss-upgrade/src/codemods/css/migrate-at-apply.ts b/packages/@tailwindcss-upgrade/src/codemods/migrate-at-apply.ts similarity index 83% rename from packages/@tailwindcss-upgrade/src/codemods/css/migrate-at-apply.ts rename to packages/@tailwindcss-upgrade/src/codemods/migrate-at-apply.ts index 69f92688d..0d3a1f035 100644 --- a/packages/@tailwindcss-upgrade/src/codemods/css/migrate-at-apply.ts +++ b/packages/@tailwindcss-upgrade/src/codemods/migrate-at-apply.ts @@ -1,15 +1,15 @@ import type { AtRule, Plugin } from 'postcss' -import type { Config } from '../../../../tailwindcss/src/compat/plugin-api' -import type { DesignSystem } from '../../../../tailwindcss/src/design-system' -import { segment } from '../../../../tailwindcss/src/utils/segment' +import type { Config } from '../../../tailwindcss/src/compat/plugin-api' +import type { DesignSystem } from '../../../tailwindcss/src/design-system' +import { segment } from '../../../tailwindcss/src/utils/segment' import { migrateCandidate } from '../template/migrate' export function migrateAtApply({ designSystem, userConfig, }: { - designSystem: DesignSystem | null - userConfig: Config | null + designSystem: DesignSystem + userConfig: Config }): Plugin { function migrate(atRule: AtRule) { let utilities = atRule.params.split(/(\s+)/) @@ -35,8 +35,6 @@ export function migrateAtApply({ }) return async () => { - if (!designSystem) return - // If we have a valid designSystem and config setup, we can run all // candidate migrations on each utility params = await Promise.all( diff --git a/packages/@tailwindcss-upgrade/src/codemods/css/migrate-at-layer-utilities.test.ts b/packages/@tailwindcss-upgrade/src/codemods/migrate-at-layer-utilities.test.ts similarity index 88% rename from packages/@tailwindcss-upgrade/src/codemods/css/migrate-at-layer-utilities.test.ts rename to packages/@tailwindcss-upgrade/src/codemods/migrate-at-layer-utilities.test.ts index e115951d3..17aeb8577 100644 --- a/packages/@tailwindcss-upgrade/src/codemods/css/migrate-at-layer-utilities.test.ts +++ b/packages/@tailwindcss-upgrade/src/codemods/migrate-at-layer-utilities.test.ts @@ -1,12 +1,10 @@ import dedent from 'dedent' import postcss from 'postcss' -import { describe, expect, it, vi } from 'vitest' -import { Stylesheet } from '../../stylesheet' -import * as versions from '../../utils/version' +import { describe, expect, it } from 'vitest' +import { Stylesheet } from '../stylesheet' import { formatNodes } from './format-nodes' import { migrateAtLayerUtilities } from './migrate-at-layer-utilities' import { sortBuckets } from './sort-buckets' -vi.spyOn(versions, 'isMajor').mockReturnValue(true) const css = dedent @@ -39,7 +37,7 @@ async function migrate( .use(sortBuckets()) .use(formatNodes()) .process(stylesheet.root!, { from: expect.getState().testPath }) - .then((result) => `\n${result.css.trim()}\n`) + .then((result) => result.css) } it('should migrate simple `@layer utilities` to `@utility`', async () => { @@ -52,11 +50,9 @@ it('should migrate simple `@layer utilities` to `@utility`', async () => { } `), ).toMatchInlineSnapshot(` - " - @utility foo { + "@utility foo { color: red; - } - " + }" `) }) @@ -71,15 +67,13 @@ it('should split multiple selectors in separate utilities', async () => { } `), ).toMatchInlineSnapshot(` - " - @utility foo { + "@utility foo { color: red; } @utility bar { color: red; - } - " + }" `) }) @@ -103,16 +97,14 @@ it('should merge `@utility` with the same name', async () => { } `), ).toMatchInlineSnapshot(` - " - @utility foo { + "@utility foo { color: red; font-weight: bold; } .bar { color: blue; - } - " + }" `) }) @@ -155,8 +147,7 @@ it('should leave non-class utilities alone', async () => { } `), ).toMatchInlineSnapshot(` - " - @utility foo { + "@utility foo { /* 2. */ /* 2.1. */ color: red; @@ -189,58 +180,7 @@ it('should leave non-class utilities alone', async () => { font-weight: bold; } } - } - " - `) -}) - -it('should not convert empty classes into `@utility` since that would make them invalid', async () => { - expect( - await migrate(css` - @layer utilities { - .good { - color: red; - } - - .bad-empty { - } - - /* Comment above */ - .bad-with-comment-above { - } - - .bad-with-comment-inside { - /* Comment inside */ - } - - .bad-with-comment-below { - } - /* Comment below */ - } - `), - ).toMatchInlineSnapshot(` - " - @utility good { - color: red; - } - - @layer utilities { - .bad-empty { - } - - /* Comment above */ - .bad-with-comment-above { - } - - .bad-with-comment-inside { - /* Comment inside */ - } - - .bad-with-comment-below { - } - /* Comment below */ - } - " + }" `) }) @@ -262,8 +202,7 @@ it('should migrate simple `@layer utilities` with nesting to `@utility`', async } `), ).toMatchInlineSnapshot(` - " - @utility foo { + "@utility foo { color: red; &:hover { @@ -273,8 +212,7 @@ it('should migrate simple `@layer utilities` with nesting to `@utility`', async &:focus { color: green; } - } - " + }" `) }) @@ -292,15 +230,13 @@ it('should migrate multiple simple `@layer utilities` to `@utility`', async () = } `), ).toMatchInlineSnapshot(` - " - @utility foo { + "@utility foo { color: red; } @utility bar { color: blue; - } - " + }" `) }) @@ -322,8 +258,7 @@ it('should not migrate Rules inside of Rules to a `@utility`', async () => { } `), ).toMatchInlineSnapshot(` - " - @utility foo { + "@utility foo { color: red; } @@ -333,8 +268,7 @@ it('should not migrate Rules inside of Rules to a `@utility`', async () => { .baz { color: green; } - } - " + }" `) }) @@ -350,13 +284,11 @@ it('should invert at-rules to make them migrate-able', async () => { } `), ).toMatchInlineSnapshot(` - " - @utility foo { + "@utility foo { @media (min-width: 640px) { color: red; } - } - " + }" `) }) @@ -380,8 +312,7 @@ it('should migrate at-rules with multiple utilities and invert them', async () = } `), ).toMatchInlineSnapshot(` - " - @utility foo { + "@utility foo { @media (min-width: 640px) { color: red; } @@ -391,8 +322,7 @@ it('should migrate at-rules with multiple utilities and invert them', async () = @media (min-width: 640px) { color: blue; } - } - " + }" `) }) @@ -424,8 +354,7 @@ it('should migrate deeply nested at-rules with multiple utilities and invert the } `), ).toMatchInlineSnapshot(` - " - @utility foo { + "@utility foo { @media (min-width: 640px) { color: red; } @@ -453,8 +382,7 @@ it('should migrate deeply nested at-rules with multiple utilities and invert the } } } - } - " + }" `) }) @@ -468,13 +396,11 @@ it('should migrate classes with pseudo elements', async () => { } `), ).toMatchInlineSnapshot(` - " - @utility no-scrollbar { + "@utility no-scrollbar { &::-webkit-scrollbar { display: none; } - } - " + }" `) }) @@ -488,13 +414,11 @@ it('should migrate classes with attribute selectors', async () => { } `), ).toMatchInlineSnapshot(` - " - @utility no-scrollbar { + "@utility no-scrollbar { &[data-checked=''] { display: none; } - } - " + }" `) }) @@ -508,13 +432,11 @@ it('should migrate classes with element selectors', async () => { } `), ).toMatchInlineSnapshot(` - " - @utility no-scrollbar { + "@utility no-scrollbar { & main { display: none; } - } - " + }" `) }) @@ -528,13 +450,11 @@ it('should migrate classes attached to an element selector', async () => { } `), ).toMatchInlineSnapshot(` - " - @utility no-scrollbar { + "@utility no-scrollbar { &main { display: none; } - } - " + }" `) }) @@ -548,13 +468,11 @@ it('should migrate classes with id selectors', async () => { } `), ).toMatchInlineSnapshot(` - " - @utility no-scrollbar { + "@utility no-scrollbar { &#main { display: none; } - } - " + }" `) }) @@ -568,8 +486,7 @@ it('should migrate classes with another attached class', async () => { } `), ).toMatchInlineSnapshot(` - " - @utility no-scrollbar { + "@utility no-scrollbar { &.main { display: none; } @@ -579,8 +496,7 @@ it('should migrate classes with another attached class', async () => { &.no-scrollbar { display: none; } - } - " + }" `) }) @@ -594,8 +510,7 @@ it('should migrate a selector with multiple classes to multiple @utility definit } `), ).toMatchInlineSnapshot(` - " - @utility foo { + "@utility foo { & .bar:hover .baz:focus { display: none; } @@ -611,8 +526,7 @@ it('should migrate a selector with multiple classes to multiple @utility definit .foo .bar:hover &:focus { display: none; } - } - " + }" `) }) @@ -632,8 +546,7 @@ it('should merge `@utility` definitions with the same name', async () => { } `), ).toMatchInlineSnapshot(` - " - @utility step { + "@utility step { counter-increment: step; &:before { @@ -641,8 +554,7 @@ it('should merge `@utility` definitions with the same name', async () => { @apply ml-[-41px]; content: counter(step); } - } - " + }" `) }) @@ -656,8 +568,7 @@ it('should not migrate nested classes inside a `:not(…)`', async () => { } `), ).toMatchInlineSnapshot(` - " - @utility foo { + "@utility foo { & .bar:not(.qux):has(.baz) { display: none; } @@ -673,8 +584,7 @@ it('should not migrate nested classes inside a `:not(…)`', async () => { .foo .bar:not(.qux):has(&) { display: none; } - } - " + }" `) }) @@ -708,8 +618,7 @@ it('should migrate advanced combinations', async () => { } `), ).toMatchInlineSnapshot(` - " - @utility foo { + "@utility foo { @media (width >= 100px) { @supports (display: none) { & .bar:not(.qux):has(.baz) { @@ -748,8 +657,7 @@ it('should migrate advanced combinations', async () => { } } } - } - " + }" `) }) @@ -767,15 +675,12 @@ describe('comments', () => { } `), ).toMatchInlineSnapshot(` - " - /* Start of utilities: */ - + "/* Start of utilities: */ @utility foo { /* Utility #1 */ /* Declarations: */ color: red; - } - " + }" `) }) @@ -792,9 +697,7 @@ describe('comments', () => { } `), ).toMatchInlineSnapshot(` - " - /* Start of utilities: */ - + "/* Start of utilities: */ @utility foo { /* Foo & Bar */ & .bar { @@ -802,15 +705,13 @@ describe('comments', () => { color: red; } } - @utility bar { /* Foo & Bar */ .foo & { /* Declarations: */ color: red; } - } - " + }" `) }) @@ -830,9 +731,7 @@ describe('comments', () => { } `), ).toMatchInlineSnapshot(` - " - /* Start of utilities: */ - + "/* Start of utilities: */ @utility foo { /* Mobile only */ @media (width <= 640px) { @@ -840,8 +739,7 @@ describe('comments', () => { /* Declarations: */ color: red; } - } - " + }" `) }) @@ -880,9 +778,7 @@ describe('comments', () => { /* After */ `), ).toMatchInlineSnapshot(` - " - /* Tailwind Utilities: */ - + "/* Tailwind Utilities: */ @utility no-scrollbar { /* Chrome, Safari and Opera */ /* Second comment */ @@ -909,8 +805,7 @@ describe('comments', () => { .after { /* Inside */ } - /* After */ - " + /* After */" `) }) }) @@ -935,8 +830,7 @@ it('should not lose attribute selectors', async () => { } `), ).toMatchInlineSnapshot(` - " - @layer components { + "@layer components { #TableOfContents { .toc a { @apply block max-w-full truncate py-1 pl-2 hover:font-medium hover:no-underline; @@ -949,8 +843,7 @@ it('should not lose attribute selectors', async () => { } } } - } - " + }" `) }) @@ -968,13 +861,11 @@ describe('layered stylesheets', () => { layers: ['utilities'], }), ).toMatchInlineSnapshot(` - " - @utility foo { + "@utility foo { /* Utility #1 */ /* Declarations: */ color: red; - } - " + }" `) }) @@ -991,13 +882,11 @@ describe('layered stylesheets', () => { layers: ['components'], }), ).toMatchInlineSnapshot(` - " - @utility foo { + "@utility foo { /* Utility #1 */ /* Declarations: */ color: red; - } - " + }" `) }) @@ -1014,13 +903,11 @@ describe('layered stylesheets', () => { layers: ['foo'], }), ).toMatchInlineSnapshot(` - " - /* Utility #1 */ + "/* Utility #1 */ .foo { /* Declarations: */ color: red; - } - " + }" `) }) @@ -1040,8 +927,7 @@ describe('layered stylesheets', () => { layers: ['utilities'], }), ).toMatchInlineSnapshot(` - " - @utility foo { + "@utility foo { /* Utility #1 */ /* Declarations: */ color: red; @@ -1049,8 +935,7 @@ describe('layered stylesheets', () => { #main { color: red; - } - " + }" `) }) @@ -1091,8 +976,7 @@ describe('layered stylesheets', () => { layers: ['utilities'], }), ).toMatchInlineSnapshot(` - " - @utility foo { + "@utility foo { @layer utilities { @layer utilities { /* Utility #1 */ @@ -1125,8 +1009,7 @@ describe('layered stylesheets', () => { #secondary { color: red; - } - " + }" `) }) @@ -1143,13 +1026,11 @@ describe('layered stylesheets', () => { layers: ['utilities'], }), ).toMatchInlineSnapshot(` - " - @import 'thing'; + "@import 'thing'; @utility foo { color: red; - } - " + }" `) }) @@ -1166,13 +1047,11 @@ describe('layered stylesheets', () => { layers: ['utilities'], }), ).toMatchInlineSnapshot(` - " - @charset "utf-8"; + "@charset "utf-8"; @utility foo { color: red; - } - " + }" `) }) }) diff --git a/packages/@tailwindcss-upgrade/src/codemods/css/migrate-at-layer-utilities.ts b/packages/@tailwindcss-upgrade/src/codemods/migrate-at-layer-utilities.ts similarity index 83% rename from packages/@tailwindcss-upgrade/src/codemods/css/migrate-at-layer-utilities.ts rename to packages/@tailwindcss-upgrade/src/codemods/migrate-at-layer-utilities.ts index 6bcb72d47..f0f11d3d6 100644 --- a/packages/@tailwindcss-upgrade/src/codemods/css/migrate-at-layer-utilities.ts +++ b/packages/@tailwindcss-upgrade/src/codemods/migrate-at-layer-utilities.ts @@ -1,17 +1,11 @@ -import { type AtRule, type Comment, type Container, type Plugin, type Rule } from 'postcss' +import { type AtRule, type Comment, type Plugin, type Rule } from 'postcss' import SelectorParser from 'postcss-selector-parser' -import { segment } from '../../../../tailwindcss/src/utils/segment' -import { Stylesheet } from '../../stylesheet' -import * as version from '../../utils/version' -import { walk, WalkAction, walkDepth } from '../../utils/walk' +import { segment } from '../../../tailwindcss/src/utils/segment' +import { Stylesheet } from '../stylesheet' +import { walk, WalkAction, walkDepth } from '../utils/walk' export function migrateAtLayerUtilities(stylesheet: Stylesheet): Plugin { function migrate(atRule: AtRule) { - // Migrating `@layer utilities` to `@utility` is only supported in Tailwind - // CSS v3 projects. Tailwind CSS v4 projects could also have `@layer - // utilities` but those aren't actual utilities. - if (!version.isMajor(3)) return - // Only migrate `@layer utilities` and `@layer components`. if (atRule.params !== 'utilities' && atRule.params !== 'components') return @@ -43,7 +37,6 @@ export function migrateAtLayerUtilities(stylesheet: Stylesheet): Plugin { walk(atRule, (node) => { if (node.type !== 'rule') return - if (isEmpty(node)) return // Find all the classes in the selector SelectorParser((selectors) => { @@ -185,18 +178,6 @@ export function migrateAtLayerUtilities(stylesheet: Stylesheet): Plugin { toRemove.push(node.parent?.nodes.at(i) as Comment) } } - - let commentsAfter: Comment[] = [] - for (let i = idx + 1; i < (node.parent?.nodes.length ?? 0); i++) { - if (node.parent?.nodes.at(i)?.type === 'rule') { - commentsAfter = [] - break - } - if (node.parent?.nodes.at(i)?.type === 'comment') { - commentsAfter.push(node.parent?.nodes.at(i) as Comment) - } - } - toRemove.push(...commentsAfter) } for (let node of toRemove) { node.remove() @@ -244,12 +225,8 @@ export function migrateAtLayerUtilities(stylesheet: Stylesheet): Plugin { } } - // Remove empty rules from `@utility` clones and empty wrapper at-rules - // from the default `@layer` clone. - if ( - (node.type === 'atrule' && node.nodes?.length === 0) || - (clone !== defaultsAtRule && node.type === 'rule' && node.nodes?.length === 0) - ) { + // Remove empty rules + if ((node.type === 'rule' || node.type === 'atrule') && node.nodes?.length === 0) { node.remove() } @@ -278,11 +255,6 @@ export function migrateAtLayerUtilities(stylesheet: Stylesheet): Plugin { // Remove empty clones entirely if (clone.nodes?.length === 0) { clones.splice(idx, 1) - } else if (clone === defaultsAtRule) { - let first = clone.nodes?.[0] - if (first) { - first.raws.before = first.raws.before?.replace(/\n\s*\n/g, '\n') - } } } @@ -338,17 +310,3 @@ export function migrateAtLayerUtilities(stylesheet: Stylesheet): Plugin { }, } } - -function isEmpty(node: Container): boolean { - // We have no body - if (node.nodes === undefined) return false - - // We have a body, but no nodes - if (node.nodes.length === 0) return true - - // We have nodes, but they are only comments which we consider empty - if (node.nodes.every((child) => child.type === 'comment')) return true - - // Not empty - return false -} diff --git a/packages/@tailwindcss-upgrade/src/codemods/css/migrate-config.ts b/packages/@tailwindcss-upgrade/src/codemods/migrate-config.ts similarity index 90% rename from packages/@tailwindcss-upgrade/src/codemods/css/migrate-config.ts rename to packages/@tailwindcss-upgrade/src/codemods/migrate-config.ts index 2004d0969..b54fec34c 100644 --- a/packages/@tailwindcss-upgrade/src/codemods/css/migrate-config.ts +++ b/packages/@tailwindcss-upgrade/src/codemods/migrate-config.ts @@ -1,8 +1,8 @@ import path from 'node:path' import postcss, { AtRule, type Plugin } from 'postcss' -import { normalizePath } from '../../../../@tailwindcss-node/src/normalize-path' -import type { Stylesheet } from '../../stylesheet' -import type { JSConfigMigration } from '../config/migrate-js-config' +import { normalizePath } from '../../../@tailwindcss-node/src/normalize-path' +import type { JSConfigMigration } from '../migrate-js-config' +import type { Stylesheet } from '../stylesheet' const ALREADY_INJECTED = new WeakMap() @@ -11,11 +11,10 @@ export function migrateConfig( { configFilePath, jsConfigMigration, - }: { configFilePath: string | null; jsConfigMigration: JSConfigMigration | null }, + }: { configFilePath: string; jsConfigMigration: JSConfigMigration }, ): Plugin { function migrate() { if (!sheet.isTailwindRoot) return - if (!configFilePath) return let alreadyInjected = ALREADY_INJECTED.get(sheet) if (alreadyInjected && alreadyInjected.includes(configFilePath)) { diff --git a/packages/@tailwindcss-upgrade/src/codemods/css/migrate-import.test.ts b/packages/@tailwindcss-upgrade/src/codemods/migrate-import.test.ts similarity index 100% rename from packages/@tailwindcss-upgrade/src/codemods/css/migrate-import.test.ts rename to packages/@tailwindcss-upgrade/src/codemods/migrate-import.test.ts diff --git a/packages/@tailwindcss-upgrade/src/codemods/css/migrate-import.ts b/packages/@tailwindcss-upgrade/src/codemods/migrate-import.ts similarity index 85% rename from packages/@tailwindcss-upgrade/src/codemods/css/migrate-import.ts rename to packages/@tailwindcss-upgrade/src/codemods/migrate-import.ts index 419f5aa32..cfdf00ee6 100644 --- a/packages/@tailwindcss-upgrade/src/codemods/css/migrate-import.ts +++ b/packages/@tailwindcss-upgrade/src/codemods/migrate-import.ts @@ -1,9 +1,9 @@ import fs from 'node:fs/promises' import { dirname, resolve } from 'node:path' import { type Plugin, type Root } from 'postcss' -import { parseImportParams } from '../../../../tailwindcss/src/at-import' -import { segment } from '../../../../tailwindcss/src/utils/segment' -import * as ValueParser from '../../../../tailwindcss/src/value-parser' +import { parseImportParams } from '../../../tailwindcss/src/at-import' +import { segment } from '../../../tailwindcss/src/utils/segment' +import * as ValueParser from '../../../tailwindcss/src/value-parser' export function migrateImport(): Plugin { async function migrate(root: Root) { @@ -16,7 +16,6 @@ export function migrateImport(): Plugin { let [firstParam, ...rest] = segment(rule.params, ' ') let params = parseImportParams(ValueParser.parse(firstParam)) - if (!params) return let isRelative = params.uri[0] === '.' let hasCssExtension = params.uri.endsWith('.css') diff --git a/packages/@tailwindcss-upgrade/src/codemods/css/migrate-media-screen.test.ts b/packages/@tailwindcss-upgrade/src/codemods/migrate-media-screen.test.ts similarity index 97% rename from packages/@tailwindcss-upgrade/src/codemods/css/migrate-media-screen.test.ts rename to packages/@tailwindcss-upgrade/src/codemods/migrate-media-screen.test.ts index 18ce72e8b..f4afd15fa 100644 --- a/packages/@tailwindcss-upgrade/src/codemods/css/migrate-media-screen.test.ts +++ b/packages/@tailwindcss-upgrade/src/codemods/migrate-media-screen.test.ts @@ -2,7 +2,7 @@ import { __unstable__loadDesignSystem } from '@tailwindcss/node' import dedent from 'dedent' import postcss from 'postcss' import { expect, it } from 'vitest' -import type { UserConfig } from '../../../../tailwindcss/src/compat/config/types' +import type { UserConfig } from '../../../tailwindcss/src/compat/config/types' import { formatNodes } from './format-nodes' import { migrateMediaScreen } from './migrate-media-screen' import { sortBuckets } from './sort-buckets' diff --git a/packages/@tailwindcss-upgrade/src/codemods/css/migrate-media-screen.ts b/packages/@tailwindcss-upgrade/src/codemods/migrate-media-screen.ts similarity index 64% rename from packages/@tailwindcss-upgrade/src/codemods/css/migrate-media-screen.ts rename to packages/@tailwindcss-upgrade/src/codemods/migrate-media-screen.ts index c10e9ee99..40fe29c3c 100644 --- a/packages/@tailwindcss-upgrade/src/codemods/css/migrate-media-screen.ts +++ b/packages/@tailwindcss-upgrade/src/codemods/migrate-media-screen.ts @@ -1,27 +1,25 @@ import { type Plugin, type Root } from 'postcss' -import { resolveConfig } from '../../../../tailwindcss/src/compat/config/resolve-config' -import type { Config } from '../../../../tailwindcss/src/compat/plugin-api' -import { buildMediaQuery } from '../../../../tailwindcss/src/compat/screens-config' -import type { DesignSystem } from '../../../../tailwindcss/src/design-system' -import { DefaultMap } from '../../../../tailwindcss/src/utils/default-map' +import { resolveConfig } from '../../../tailwindcss/src/compat/config/resolve-config' +import type { Config } from '../../../tailwindcss/src/compat/plugin-api' +import { buildMediaQuery } from '../../../tailwindcss/src/compat/screens-config' +import type { DesignSystem } from '../../../tailwindcss/src/design-system' +import { DefaultMap } from '../../../tailwindcss/src/utils/default-map' export function migrateMediaScreen({ designSystem, userConfig, }: { - designSystem?: DesignSystem | null - userConfig?: Config | null + designSystem?: DesignSystem + userConfig?: Config } = {}): Plugin { function migrate(root: Root) { if (!designSystem || !userConfig) return - let { resolvedConfig } = resolveConfig(designSystem, [ - { base: '', config: userConfig, reference: false, src: undefined }, - ]) + let { resolvedConfig } = resolveConfig(designSystem, [{ base: '', config: userConfig }]) let screens = resolvedConfig?.theme?.screens || {} let mediaQueries = new DefaultMap((name) => { - let value = designSystem?.resolveThemeValue(`--breakpoint-${name}`, true) ?? screens?.[name] + let value = designSystem?.resolveThemeValue(`--breakpoint-${name}`) ?? screens?.[name] if (typeof value === 'string') return `(width >= theme(--breakpoint-${name}))` return value ? buildMediaQuery(value) : null }) diff --git a/packages/@tailwindcss-upgrade/src/codemods/css/migrate-missing-layers.test.ts b/packages/@tailwindcss-upgrade/src/codemods/migrate-missing-layers.test.ts similarity index 100% rename from packages/@tailwindcss-upgrade/src/codemods/css/migrate-missing-layers.test.ts rename to packages/@tailwindcss-upgrade/src/codemods/migrate-missing-layers.test.ts diff --git a/packages/@tailwindcss-upgrade/src/codemods/css/migrate-missing-layers.ts b/packages/@tailwindcss-upgrade/src/codemods/migrate-missing-layers.ts similarity index 97% rename from packages/@tailwindcss-upgrade/src/codemods/css/migrate-missing-layers.ts rename to packages/@tailwindcss-upgrade/src/codemods/migrate-missing-layers.ts index 10c9d55de..7dad26e73 100644 --- a/packages/@tailwindcss-upgrade/src/codemods/css/migrate-missing-layers.ts +++ b/packages/@tailwindcss-upgrade/src/codemods/migrate-missing-layers.ts @@ -1,5 +1,5 @@ import { AtRule, type ChildNode, type Plugin, type Root } from 'postcss' -import { segment } from '../../../../tailwindcss/src/utils/segment' +import { segment } from '../../../tailwindcss/src/utils/segment' export function migrateMissingLayers(): Plugin { function migrate(root: Root) { @@ -16,7 +16,6 @@ export function migrateMissingLayers(): Plugin { node.name === 'source' || node.name === 'theme' || node.name === 'utility' || - node.name === 'custom-variant' || node.name === 'variant' ) { if (bucket.length > 0) { diff --git a/packages/@tailwindcss-upgrade/src/codemods/css/migrate-preflight.test.ts b/packages/@tailwindcss-upgrade/src/codemods/migrate-preflight.test.ts similarity index 85% rename from packages/@tailwindcss-upgrade/src/codemods/css/migrate-preflight.test.ts rename to packages/@tailwindcss-upgrade/src/codemods/migrate-preflight.test.ts index 2d8b70041..21793e1ed 100644 --- a/packages/@tailwindcss-upgrade/src/codemods/css/migrate-preflight.test.ts +++ b/packages/@tailwindcss-upgrade/src/codemods/migrate-preflight.test.ts @@ -1,12 +1,10 @@ import { __unstable__loadDesignSystem } from '@tailwindcss/node' import dedent from 'dedent' import postcss from 'postcss' -import { expect, it, vi } from 'vitest' -import * as versions from '../../utils/version' +import { expect, it } from 'vitest' import { formatNodes } from './format-nodes' import { migratePreflight } from './migrate-preflight' import { sortBuckets } from './sort-buckets' -vi.spyOn(versions, 'isMajor').mockReturnValue(true) const css = dedent @@ -35,7 +33,7 @@ it("should add compatibility CSS after the `@import 'tailwindcss'`", async () => "@import 'tailwindcss'; /* - The default border color has changed to \`currentcolor\` in Tailwind CSS v4, + The default border color has changed to \`currentColor\` in Tailwind CSS v4, so we've added these compatibility styles to make sure everything still looks the same as it did with Tailwind CSS v3. @@ -48,7 +46,7 @@ it("should add compatibility CSS after the `@import 'tailwindcss'`", async () => ::before, ::backdrop, ::file-selector-button { - border-color: var(--color-gray-200, currentcolor); + border-color: var(--color-gray-200, currentColor); } }" `) @@ -67,7 +65,7 @@ it('should add the compatibility CSS after the last `@import`', async () => { @import './bar.css'; /* - The default border color has changed to \`currentcolor\` in Tailwind CSS v4, + The default border color has changed to \`currentColor\` in Tailwind CSS v4, so we've added these compatibility styles to make sure everything still looks the same as it did with Tailwind CSS v3. @@ -80,7 +78,7 @@ it('should add the compatibility CSS after the last `@import`', async () => { ::before, ::backdrop, ::file-selector-button { - border-color: var(--color-gray-200, currentcolor); + border-color: var(--color-gray-200, currentColor); } }" `) @@ -113,7 +111,7 @@ it('should add the compatibility CSS after the last import, even if a body-less @import './bar.css'; /* - The default border color has changed to \`currentcolor\` in Tailwind CSS v4, + The default border color has changed to \`currentColor\` in Tailwind CSS v4, so we've added these compatibility styles to make sure everything still looks the same as it did with Tailwind CSS v3. @@ -126,7 +124,7 @@ it('should add the compatibility CSS after the last import, even if a body-less ::before, ::backdrop, ::file-selector-button { - border-color: var(--color-gray-200, currentcolor); + border-color: var(--color-gray-200, currentColor); } }" `) @@ -137,7 +135,7 @@ it('should add the compatibility CSS before the first `@layer base` (if the "tai await migrate(css` @import 'tailwindcss'; - @custom-variant foo { + @variant foo { } @utility bar { @@ -155,11 +153,11 @@ it('should add the compatibility CSS before the first `@layer base` (if the "tai ).toMatchInlineSnapshot(` "@import 'tailwindcss'; - @custom-variant foo { + @variant foo { } /* - The default border color has changed to \`currentcolor\` in Tailwind CSS v4, + The default border color has changed to \`currentColor\` in Tailwind CSS v4, so we've added these compatibility styles to make sure everything still looks the same as it did with Tailwind CSS v3. @@ -172,7 +170,7 @@ it('should add the compatibility CSS before the first `@layer base` (if the "tai ::before, ::backdrop, ::file-selector-button { - border-color: var(--color-gray-200, currentcolor); + border-color: var(--color-gray-200, currentColor); } } @@ -195,7 +193,7 @@ it('should add the compatibility CSS before the first `@layer base` (if the "tai await migrate(css` @import 'tailwindcss/preflight'; - @custom-variant foo { + @variant foo { } @utility bar { @@ -213,11 +211,11 @@ it('should add the compatibility CSS before the first `@layer base` (if the "tai ).toMatchInlineSnapshot(` "@import 'tailwindcss/preflight'; - @custom-variant foo { + @variant foo { } /* - The default border color has changed to \`currentcolor\` in Tailwind CSS v4, + The default border color has changed to \`currentColor\` in Tailwind CSS v4, so we've added these compatibility styles to make sure everything still looks the same as it did with Tailwind CSS v3. @@ -230,7 +228,7 @@ it('should add the compatibility CSS before the first `@layer base` (if the "tai ::before, ::backdrop, ::file-selector-button { - border-color: var(--color-gray-200, currentcolor); + border-color: var(--color-gray-200, currentColor); } } @@ -251,7 +249,7 @@ it('should add the compatibility CSS before the first `@layer base` (if the "tai it('should not add the backwards compatibility CSS when no `@import "tailwindcss"` or `@import "tailwindcss/preflight"` exists', async () => { expect( await migrate(css` - @custom-variant foo { + @variant foo { } @utility bar { @@ -267,7 +265,7 @@ it('should not add the backwards compatibility CSS when no `@import "tailwindcss } `), ).toMatchInlineSnapshot(` - "@custom-variant foo { + "@variant foo { } @utility bar { @@ -289,7 +287,7 @@ it('should not add the backwards compatibility CSS when another `@import "tailwi await migrate(css` @import 'tailwindcss/theme'; - @custom-variant foo { + @variant foo { } @utility bar { @@ -307,7 +305,7 @@ it('should not add the backwards compatibility CSS when another `@import "tailwi ).toMatchInlineSnapshot(` "@import 'tailwindcss/theme'; - @custom-variant foo { + @variant foo { } @utility bar { diff --git a/packages/@tailwindcss-upgrade/src/codemods/css/migrate-preflight.ts b/packages/@tailwindcss-upgrade/src/codemods/migrate-preflight.ts similarity index 81% rename from packages/@tailwindcss-upgrade/src/codemods/css/migrate-preflight.ts rename to packages/@tailwindcss-upgrade/src/codemods/migrate-preflight.ts index d32d96979..8677d6af6 100644 --- a/packages/@tailwindcss-upgrade/src/codemods/css/migrate-preflight.ts +++ b/packages/@tailwindcss-upgrade/src/codemods/migrate-preflight.ts @@ -1,20 +1,18 @@ import dedent from 'dedent' import postcss, { type Plugin, type Root } from 'postcss' -import { keyPathToCssProperty } from '../../../../tailwindcss/src/compat/apply-config-to-theme' -import type { Config } from '../../../../tailwindcss/src/compat/plugin-api' -import type { DesignSystem } from '../../../../tailwindcss/src/design-system' -import { toKeyPath } from '../../../../tailwindcss/src/utils/to-key-path' -import * as ValueParser from '../../../../tailwindcss/src/value-parser' -import { walk, WalkAction } from '../../../../tailwindcss/src/walk' -import * as version from '../../utils/version' +import { keyPathToCssProperty } from '../../../tailwindcss/src/compat/apply-config-to-theme' +import type { Config } from '../../../tailwindcss/src/compat/plugin-api' +import type { DesignSystem } from '../../../tailwindcss/src/design-system' +import { toKeyPath } from '../../../tailwindcss/src/utils/to-key-path' +import * as ValueParser from '../../../tailwindcss/src/value-parser' // Defaults in v4 -const DEFAULT_BORDER_COLOR = 'currentcolor' +const DEFAULT_BORDER_COLOR = 'currentColor' const css = dedent const BORDER_COLOR_COMPATIBILITY_CSS = css` /* - The default border color has changed to \`currentcolor\` in Tailwind CSS v4, + The default border color has changed to \`currentColor\` in Tailwind CSS v4, so we've added these compatibility styles to make sure everything still looks the same as it did with Tailwind CSS v3. @@ -36,23 +34,18 @@ export function migratePreflight({ designSystem, userConfig, }: { - designSystem: DesignSystem | null - userConfig?: Config | null + designSystem: DesignSystem + userConfig?: Config }): Plugin { // @ts-expect-error let defaultBorderColor = userConfig?.theme?.borderColor?.DEFAULT function canResolveThemeValue(path: string) { - if (!designSystem) return false let variable = `--${keyPathToCssProperty(toKeyPath(path))}` as const return Boolean(designSystem.theme.get([variable])) } function migrate(root: Root) { - // CSS for backwards compatibility with v3 should only injected in v3 - // projects and not v4 projects. - if (!version.isMajor(3)) return - let isTailwindRoot = false root.walkAtRules('import', (node) => { if ( @@ -85,7 +78,7 @@ export function migratePreflight({ return defaultBorderColor } else { if (path === 'borderColor.DEFAULT') { - return 'var(--color-gray-200, currentcolor)' + return 'var(--color-gray-200, currentColor)' } } return null @@ -118,7 +111,7 @@ function substituteFunctionsInValue( ast: ValueParser.ValueAstNode[], handle: (value: string, fallback?: string) => string | null, ) { - walk(ast, (node) => { + ValueParser.walk(ast, (node, { replaceWith }) => { if (node.kind === 'function' && node.value === 'theme') { if (node.nodes.length < 1) return @@ -156,7 +149,7 @@ function substituteFunctionsInValue( fallbackValues.length > 0 ? handle(path, ValueParser.toCss(fallbackValues)) : handle(path) if (replacement === null) return - return WalkAction.Replace(ValueParser.parse(replacement)) + replaceWith(ValueParser.parse(replacement)) } }) diff --git a/packages/@tailwindcss-upgrade/src/codemods/css/migrate-tailwind-directives.test.ts b/packages/@tailwindcss-upgrade/src/codemods/migrate-tailwind-directives.test.ts similarity index 100% rename from packages/@tailwindcss-upgrade/src/codemods/css/migrate-tailwind-directives.test.ts rename to packages/@tailwindcss-upgrade/src/codemods/migrate-tailwind-directives.test.ts diff --git a/packages/@tailwindcss-upgrade/src/codemods/css/migrate-tailwind-directives.ts b/packages/@tailwindcss-upgrade/src/codemods/migrate-tailwind-directives.ts similarity index 100% rename from packages/@tailwindcss-upgrade/src/codemods/css/migrate-tailwind-directives.ts rename to packages/@tailwindcss-upgrade/src/codemods/migrate-tailwind-directives.ts diff --git a/packages/@tailwindcss-upgrade/src/codemods/css/migrate-theme-to-var.test.ts b/packages/@tailwindcss-upgrade/src/codemods/migrate-theme-to-var.test.ts similarity index 89% rename from packages/@tailwindcss-upgrade/src/codemods/css/migrate-theme-to-var.test.ts rename to packages/@tailwindcss-upgrade/src/codemods/migrate-theme-to-var.test.ts index f0b4844ad..ce3940bc9 100644 --- a/packages/@tailwindcss-upgrade/src/codemods/css/migrate-theme-to-var.test.ts +++ b/packages/@tailwindcss-upgrade/src/codemods/migrate-theme-to-var.test.ts @@ -35,11 +35,11 @@ it('should migrate `theme(…)` to `var(…)`', async () => { } `), ).toMatchInlineSnapshot(` - "@media --theme(--breakpoint-sm) { + "@media theme(--breakpoint-sm) { .foo { background-color: var(--color-red-900); - color: --theme(--color-red-900 / 75%); - border-color: --theme(--color-red-200 / 75%); + color: theme(--color-red-900 / 75%); + border-color: theme(--color-red-200 / 75%); } }" `) diff --git a/packages/@tailwindcss-upgrade/src/codemods/css/migrate-theme-to-var.ts b/packages/@tailwindcss-upgrade/src/codemods/migrate-theme-to-var.ts similarity index 80% rename from packages/@tailwindcss-upgrade/src/codemods/css/migrate-theme-to-var.ts rename to packages/@tailwindcss-upgrade/src/codemods/migrate-theme-to-var.ts index 8285def1e..558e6d0cb 100644 --- a/packages/@tailwindcss-upgrade/src/codemods/css/migrate-theme-to-var.ts +++ b/packages/@tailwindcss-upgrade/src/codemods/migrate-theme-to-var.ts @@ -1,11 +1,11 @@ import { type Plugin } from 'postcss' -import type { DesignSystem } from '../../../../tailwindcss/src/design-system' -import { Convert, createConverter } from '../template/migrate-theme-to-var' +import type { DesignSystem } from '../../../tailwindcss/src/design-system' +import { Convert, createConverter } from '../template/codemods/theme-to-var' export function migrateThemeToVar({ designSystem, }: { - designSystem?: DesignSystem | null + designSystem?: DesignSystem } = {}): Plugin { return { postcssPlugin: '@tailwindcss/upgrade/migrate-theme-to-var', diff --git a/packages/@tailwindcss-upgrade/src/codemods/css/migrate-variants-directive.test.ts b/packages/@tailwindcss-upgrade/src/codemods/migrate-variants-directive.test.ts similarity index 100% rename from packages/@tailwindcss-upgrade/src/codemods/css/migrate-variants-directive.test.ts rename to packages/@tailwindcss-upgrade/src/codemods/migrate-variants-directive.test.ts diff --git a/packages/@tailwindcss-upgrade/src/codemods/css/migrate-variants-directive.ts b/packages/@tailwindcss-upgrade/src/codemods/migrate-variants-directive.ts similarity index 100% rename from packages/@tailwindcss-upgrade/src/codemods/css/migrate-variants-directive.ts rename to packages/@tailwindcss-upgrade/src/codemods/migrate-variants-directive.ts diff --git a/packages/@tailwindcss-upgrade/src/codemods/css/sort-buckets.ts b/packages/@tailwindcss-upgrade/src/codemods/sort-buckets.ts similarity index 94% rename from packages/@tailwindcss-upgrade/src/codemods/css/sort-buckets.ts rename to packages/@tailwindcss-upgrade/src/codemods/sort-buckets.ts index 22b0581dd..b99badeb0 100644 --- a/packages/@tailwindcss-upgrade/src/codemods/css/sort-buckets.ts +++ b/packages/@tailwindcss-upgrade/src/codemods/sort-buckets.ts @@ -1,6 +1,6 @@ import postcss, { type AtRule, type ChildNode, type Comment, type Plugin, type Root } from 'postcss' -import { DefaultMap } from '../../../../tailwindcss/src/utils/default-map' -import { walk, WalkAction } from '../../utils/walk' +import { DefaultMap } from '../../../tailwindcss/src/utils/default-map' +import { walk, WalkAction } from '../utils/walk' const BUCKET_ORDER = [ // Imports @@ -10,7 +10,7 @@ const BUCKET_ORDER = [ 'config', // @config 'plugin', // @plugin 'source', // @source - 'custom-variant', // @custom-variant + 'variant', // @variant 'theme', // @theme // Styles @@ -75,7 +75,7 @@ export function sortBuckets(): Plugin { // Known at-rules else if ( node.type === 'atrule' && - ['config', 'plugin', 'source', 'theme', 'utility', 'custom-variant'].includes(node.name) + ['config', 'plugin', 'source', 'theme', 'utility', 'variant'].includes(node.name) ) { injectInto(node.name, node) } diff --git a/packages/@tailwindcss-upgrade/src/codemods/template/candidates.test.ts b/packages/@tailwindcss-upgrade/src/codemods/template/candidates.test.ts deleted file mode 100644 index 2e4d150aa..000000000 --- a/packages/@tailwindcss-upgrade/src/codemods/template/candidates.test.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { __unstable__loadDesignSystem } from '@tailwindcss/node' -import { expect, test } from 'vitest' -import { spliceChangesIntoString } from '../../utils/splice-changes-into-string' -import { extractRawCandidates } from './candidates' - -let html = String.raw - -test('extracts candidates with positions from a template', async () => { - let content = html` -
- -
- ` - let designSystem = await __unstable__loadDesignSystem('@import "tailwindcss";', { - base: __dirname, - }) - - let candidates = await extractRawCandidates(content, 'html') - let validCandidates = candidates.filter( - ({ rawCandidate }) => designSystem.parseCandidate(rawCandidate).length > 0, - ) - - expect(validCandidates).toMatchInlineSnapshot(` - [ - { - "end": 28, - "rawCandidate": "bg-blue-500", - "start": 17, - }, - { - "end": 51, - "rawCandidate": "hover:focus:text-white", - "start": 29, - }, - { - "end": 63, - "rawCandidate": "[color:red]", - "start": 52, - }, - { - "end": 98, - "rawCandidate": "bg-blue-500", - "start": 87, - }, - { - "end": 109, - "rawCandidate": "text-white", - "start": 99, - }, - ] - `) -}) - -test('replaces the right positions for a candidate', async () => { - let content = html` -

🤠👋

-
- ` - - let designSystem = await __unstable__loadDesignSystem('@import "tailwindcss";', { - base: __dirname, - }) - - let candidates = await extractRawCandidates(content, 'html') - - let candidate = candidates.find( - ({ rawCandidate }) => designSystem.parseCandidate(rawCandidate).length > 0, - )! - - let migrated = spliceChangesIntoString(content, [ - { - start: candidate.start, - end: candidate.end, - replacement: 'flex', - }, - ]) - - expect(migrated).toMatchInlineSnapshot(` - " -

🤠👋

-
- " - `) -}) diff --git a/packages/@tailwindcss-upgrade/src/codemods/template/candidates.ts b/packages/@tailwindcss-upgrade/src/codemods/template/candidates.ts deleted file mode 100644 index 88b1e4e03..000000000 --- a/packages/@tailwindcss-upgrade/src/codemods/template/candidates.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { Scanner } from '@tailwindcss/oxide' -import { cloneCandidate, type Candidate } from '../../../../tailwindcss/src/candidate' -import type { DesignSystem } from '../../../../tailwindcss/src/design-system' - -export async function extractRawCandidates( - content: string, - extension: string = 'html', -): Promise<{ rawCandidate: string; start: number; end: number }[]> { - let scanner = new Scanner({}) - let result = scanner.getCandidatesWithPositions({ content, extension }) - - let candidates: { rawCandidate: string; start: number; end: number }[] = [] - for (let { candidate: rawCandidate, position: start } of result) { - candidates.push({ rawCandidate, start, end: start + rawCandidate.length }) - } - return candidates -} - -// Create a basic stripped candidate without variants or important flag -export function baseCandidate(candidate: T) { - let base = cloneCandidate(candidate) - - base.important = false - base.variants = [] - - return base -} - -export function parseCandidate(designSystem: DesignSystem, input: string) { - return designSystem.parseCandidate( - designSystem.theme.prefix && !input.startsWith(`${designSystem.theme.prefix}:`) - ? `${designSystem.theme.prefix}:${input}` - : input, - ) -} - -export function printUnprefixedCandidate(designSystem: DesignSystem, candidate: Candidate) { - let candidateString = designSystem.printCandidate(candidate) - - return designSystem.theme.prefix && candidateString.startsWith(`${designSystem.theme.prefix}:`) - ? candidateString.slice(designSystem.theme.prefix.length + 1) - : candidateString -} diff --git a/packages/@tailwindcss-upgrade/src/codemods/template/is-safe-migration.test.ts b/packages/@tailwindcss-upgrade/src/codemods/template/is-safe-migration.test.ts deleted file mode 100644 index 7cfb16c75..000000000 --- a/packages/@tailwindcss-upgrade/src/codemods/template/is-safe-migration.test.ts +++ /dev/null @@ -1,154 +0,0 @@ -import { __unstable__loadDesignSystem } from '@tailwindcss/node' -import { describe, expect, test, vi } from 'vitest' -import * as versions from '../../utils/version' -import { migrateCandidate } from './migrate' -vi.spyOn(versions, 'isMajor').mockReturnValue(true) - -const css = String.raw - -describe('is-safe-migration', async () => { - let designSystem = await __unstable__loadDesignSystem( - css` - @import 'tailwindcss'; - - /* TODO(perf): Only here to speed up the tests */ - @theme { - --*: initial; - --shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); - --shadow-sm: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); - } - `, - { base: __dirname }, - ) - - test.each([ - [`let notBorder = !border \n`, '!border'], - [`{ "foo": !border.something + ""}\n`, '!border'], - [`
\n`, '!border'], - [`
\n`, '!border'], - [`
\n`, '!border'], - [`
\n`, '!border'], - [`
\n`, '!border'], - [`
\n`, '!border'], - [`
\n`, '!border'], - [`
\n`, '!border'], - [`
\n`, '!border'], - [`
\n`, '!border'], - - [`let notShadow = shadow \n`, 'shadow'], - [`{ "foo": shadow.something + ""}\n`, 'shadow'], - [`
\n`, 'shadow'], - [`
\n`, 'shadow'], - [`
\n`, 'shadow'], - [`
\n`, 'shadow'], - [`
\n`, 'shadow'], - [`
\n`, 'shadow'], - [`
\n`, 'shadow'], - [`
\n`, 'shadow'], - [`
\n`, 'shadow'], - [`
\n`, 'shadow'], - [`
\n`, 'shadow'], - [`
\n`, 'flex-grow'], - [`
\n`, 'flex-shrink'], - [`
\n`, 'flex-shrink'], - [`
\n`, 'flex-shrink'], - - // Next.js Image placeholder cases - [``, 'blur'], - [``, 'blur'], - [``, 'blur'], - - // https://github.com/tailwindlabs/tailwindcss/issues/17974 - ['
', '!duration'], - ['
', '!duration'], - ['
', '!visible'], - - // Alpine/Livewire wire:… - ['', 'blur'], - - // Vue 3 events - [`emit('blur', props.modelValue)\n`, 'blur'], - [`$emit('blur', props.modelValue)\n`, 'blur'], - - // JavaScript / TypeScript - [`document.addEventListener('blur',handleBlur)`, 'blur'], - [`document.addEventListener('blur', handleBlur)`, 'blur'], - - [`function foo({ outline = true })`, 'outline'], - [`function foo({ before = false, outline = true })`, 'outline'], - [`function foo({before=false,outline=true })`, 'outline'], - [`function foo({outline=true })`, 'outline'], - // https://github.com/tailwindlabs/tailwindcss/issues/18675 - [ - // With default value - `function foo({ size = "1.25rem", digit, outline = true, textClass = "", className = "" })`, - 'outline', - ], - [ - // Without default value - `function foo({ size = "1.25rem", digit, outline, textClass = "", className = "" })`, - 'outline', - ], - [ - // As the last argument - `function foo({ size = "1.25rem", digit, outline })`, - 'outline', - ], - [ - // As the last argument, but there is technically another `"` on the same line - `function foo({ size = "1.25rem", digit, outline }): { return "foo" }`, - 'outline', - ], - [ - // Tricky quote balancing - `function foo({ before = "'", outline, after = "'" }): { return "foo" }`, - 'outline', - ], - - [`function foo(blur, foo)`, 'blur'], - [`function foo(blur,foo)`, 'blur'], - - // shadcn/ui variants - [` +
+ ` + let designSystem = await __unstable__loadDesignSystem('@import "tailwindcss";', { + base: __dirname, + }) + + let candidates = await extractRawCandidates(content, 'html') + let validCandidates = candidates.filter( + ({ rawCandidate }) => designSystem.parseCandidate(rawCandidate).length > 0, + ) + + expect(validCandidates).toMatchInlineSnapshot(` + [ + { + "end": 28, + "rawCandidate": "bg-blue-500", + "start": 17, + }, + { + "end": 51, + "rawCandidate": "hover:focus:text-white", + "start": 29, + }, + { + "end": 63, + "rawCandidate": "[color:red]", + "start": 52, + }, + { + "end": 98, + "rawCandidate": "bg-blue-500", + "start": 87, + }, + { + "end": 109, + "rawCandidate": "text-white", + "start": 99, + }, + ] + `) +}) + +test('replaces the right positions for a candidate', async () => { + let content = html` +

🤠👋

+
+ ` + + let designSystem = await __unstable__loadDesignSystem('@import "tailwindcss";', { + base: __dirname, + }) + + let candidates = await extractRawCandidates(content, 'html') + + let candidate = candidates.find( + ({ rawCandidate }) => designSystem.parseCandidate(rawCandidate).length > 0, + )! + + let migrated = spliceChangesIntoString(content, [ + { + start: candidate.start, + end: candidate.end, + replacement: 'flex', + }, + ]) + + expect(migrated).toMatchInlineSnapshot(` + " +

🤠👋

+
+ " + `) +}) + +const candidates = [ + // Arbitrary candidates + ['[color:red]', '[color:red]'], + ['[color:red]/50', '[color:red]/50'], + ['[color:red]/[0.5]', '[color:red]/[0.5]'], + ['[color:red]/50!', '[color:red]/50!'], + ['![color:red]/50', '[color:red]/50!'], + ['[color:red]/[0.5]!', '[color:red]/[0.5]!'], + + // Static candidates + ['box-border', 'box-border'], + ['underline!', 'underline!'], + ['!underline', 'underline!'], + ['-inset-full', '-inset-full'], + + // Functional candidates + ['bg-red-500', 'bg-red-500'], + ['bg-red-500/50', 'bg-red-500/50'], + ['bg-red-500/[0.5]', 'bg-red-500/[0.5]'], + ['bg-red-500!', 'bg-red-500!'], + ['!bg-red-500', 'bg-red-500!'], + ['bg-[#0088cc]/50', 'bg-[#0088cc]/50'], + ['bg-[#0088cc]/[0.5]', 'bg-[#0088cc]/[0.5]'], + ['bg-[#0088cc]!', 'bg-[#0088cc]!'], + ['!bg-[#0088cc]', 'bg-[#0088cc]!'], + ['bg-[var(--spacing)-1px]', 'bg-[var(--spacing)-1px]'], + ['bg-[var(--spacing)_-_1px]', 'bg-[var(--spacing)-1px]'], + ['bg-[-1px_-1px]', 'bg-[-1px_-1px]'], + ['p-[round(to-zero,1px)]', 'p-[round(to-zero,1px)]'], + ['w-1/2', 'w-1/2'], + ['p-[calc((100vw-theme(maxWidth.2xl))_/_2)]', 'p-[calc((100vw-theme(maxWidth.2xl))/2)]'], + + // Keep spaces in strings + ['content-["hello_world"]', 'content-["hello_world"]'], + ['content-[____"hello_world"___]', 'content-["hello_world"]'], + + // Do not escape underscores for url() and CSS variable in var() + ['bg-[no-repeat_url(/image_13.png)]', 'bg-[no-repeat_url(/image_13.png)]'], + [ + 'bg-[var(--spacing-0_5,_var(--spacing-1_5,_3rem))]', + 'bg-(--spacing-0_5,var(--spacing-1_5,3rem))', + ], +] + +const variants = [ + ['', ''], // no variant + ['*:', '*:'], + ['focus:', 'focus:'], + ['group-focus:', 'group-focus:'], + + ['hover:focus:', 'hover:focus:'], + ['hover:group-focus:', 'hover:group-focus:'], + ['group-hover:focus:', 'group-hover:focus:'], + ['group-hover:group-focus:', 'group-hover:group-focus:'], + + ['min-[10px]:', 'min-[10px]:'], + + // Normalize spaces + ['min-[calc(1000px_+_12em)]:', 'min-[calc(1000px+12em)]:'], + ['min-[calc(1000px_+12em)]:', 'min-[calc(1000px+12em)]:'], + ['min-[calc(1000px+_12em)]:', 'min-[calc(1000px+12em)]:'], + ['min-[calc(1000px___+___12em)]:', 'min-[calc(1000px+12em)]:'], + + ['peer-[&_p]:', 'peer-[&_p]:'], + ['peer-[&_p]:hover:', 'peer-[&_p]:hover:'], + ['hover:peer-[&_p]:', 'hover:peer-[&_p]:'], + ['hover:peer-[&_p]:focus:', 'hover:peer-[&_p]:focus:'], + ['peer-[&:hover]:peer-[&_p]:', 'peer-[&:hover]:peer-[&_p]:'], + + ['[p]:', '[p]:'], + ['[_p_]:', '[p]:'], + ['has-[p]:', 'has-[p]:'], + ['has-[_p_]:', 'has-[p]:'], + + // Simplify `&:is(p)` to `p` + ['[&:is(p)]:', '[p]:'], + ['[&:is(_p_)]:', '[p]:'], + ['has-[&:is(p)]:', 'has-[p]:'], + ['has-[&:is(_p_)]:', 'has-[p]:'], +] + +let combinations: [string, string][] = [] + +for (let [inputVariant, outputVariant] of variants) { + for (let [inputCandidate, outputCandidate] of candidates) { + combinations.push([`${inputVariant}${inputCandidate}`, `${outputVariant}${outputCandidate}`]) + } +} + +describe('printCandidate()', () => { + test.each(combinations)('%s -> %s', async (candidate: string, result: string) => { + let designSystem = await __unstable__loadDesignSystem('@import "tailwindcss";', { + base: __dirname, + }) + + let candidates = designSystem.parseCandidate(candidate) + + // Sometimes we will have a functional and a static candidate for the same + // raw input string (e.g. `-inset-full`). Dedupe in this case. + let cleaned = new Set([...candidates].map((c) => printCandidate(designSystem, c))) + + expect([...cleaned]).toEqual([result]) + }) +}) diff --git a/packages/@tailwindcss-upgrade/src/template/candidates.ts b/packages/@tailwindcss-upgrade/src/template/candidates.ts new file mode 100644 index 000000000..6a0ab65bd --- /dev/null +++ b/packages/@tailwindcss-upgrade/src/template/candidates.ts @@ -0,0 +1,290 @@ +import { Scanner } from '@tailwindcss/oxide' +import type { Candidate, Variant } from '../../../tailwindcss/src/candidate' +import type { DesignSystem } from '../../../tailwindcss/src/design-system' +import * as ValueParser from '../../../tailwindcss/src/value-parser' + +export async function extractRawCandidates( + content: string, + extension: string = 'html', +): Promise<{ rawCandidate: string; start: number; end: number }[]> { + let scanner = new Scanner({}) + let result = scanner.getCandidatesWithPositions({ content, extension }) + + let candidates: { rawCandidate: string; start: number; end: number }[] = [] + for (let { candidate: rawCandidate, position: start } of result) { + candidates.push({ rawCandidate, start, end: start + rawCandidate.length }) + } + return candidates +} + +export function printCandidate(designSystem: DesignSystem, candidate: Candidate) { + let parts: string[] = [] + + for (let variant of candidate.variants) { + parts.unshift(printVariant(variant)) + } + + // Handle prefix + if (designSystem.theme.prefix) { + parts.unshift(designSystem.theme.prefix) + } + + let base: string = '' + + // Handle static + if (candidate.kind === 'static') { + base += candidate.root + } + + // Handle functional + if (candidate.kind === 'functional') { + base += candidate.root + + if (candidate.value) { + if (candidate.value.kind === 'arbitrary') { + if (candidate.value !== null) { + let isVarValue = isVar(candidate.value.value) + let value = isVarValue ? candidate.value.value.slice(4, -1) : candidate.value.value + let [open, close] = isVarValue ? ['(', ')'] : ['[', ']'] + + if (candidate.value.dataType) { + base += `-${open}${candidate.value.dataType}:${printArbitraryValue(value)}${close}` + } else { + base += `-${open}${printArbitraryValue(value)}${close}` + } + } + } else if (candidate.value.kind === 'named') { + base += `-${candidate.value.value}` + } + } + } + + // Handle arbitrary + if (candidate.kind === 'arbitrary') { + base += `[${candidate.property}:${printArbitraryValue(candidate.value)}]` + } + + // Handle modifier + if (candidate.kind === 'arbitrary' || candidate.kind === 'functional') { + if (candidate.modifier) { + let isVarValue = isVar(candidate.modifier.value) + let value = isVarValue ? candidate.modifier.value.slice(4, -1) : candidate.modifier.value + let [open, close] = isVarValue ? ['(', ')'] : ['[', ']'] + + if (candidate.modifier.kind === 'arbitrary') { + base += `/${open}${printArbitraryValue(value)}${close}` + } else if (candidate.modifier.kind === 'named') { + base += `/${candidate.modifier.value}` + } + } + } + + // Handle important + if (candidate.important) { + base += '!' + } + + parts.push(base) + + return parts.join(':') +} + +function printVariant(variant: Variant) { + // Handle static variants + if (variant.kind === 'static') { + return variant.root + } + + // Handle arbitrary variants + if (variant.kind === 'arbitrary') { + return `[${printArbitraryValue(simplifyArbitraryVariant(variant.selector))}]` + } + + let base: string = '' + + // Handle functional variants + if (variant.kind === 'functional') { + base += variant.root + if (variant.value) { + if (variant.value.kind === 'arbitrary') { + let isVarValue = isVar(variant.value.value) + let value = isVarValue ? variant.value.value.slice(4, -1) : variant.value.value + let [open, close] = isVarValue ? ['(', ')'] : ['[', ']'] + + base += `-${open}${printArbitraryValue(value)}${close}` + } else if (variant.value.kind === 'named') { + base += `-${variant.value.value}` + } + } + } + + // Handle compound variants + if (variant.kind === 'compound') { + base += variant.root + base += '-' + base += printVariant(variant.variant) + } + + // Handle modifiers + if (variant.kind === 'functional' || variant.kind === 'compound') { + if (variant.modifier) { + if (variant.modifier.kind === 'arbitrary') { + base += `/[${printArbitraryValue(variant.modifier.value)}]` + } else if (variant.modifier.kind === 'named') { + base += `/${variant.modifier.value}` + } + } + } + + return base +} + +function printArbitraryValue(input: string) { + let ast = ValueParser.parse(input) + + let drop = new Set() + + ValueParser.walk(ast, (node, { parent }) => { + let parentArray = parent === null ? ast : (parent.nodes ?? []) + + // Handle operators (e.g.: inside of `calc(…)`) + if ( + node.kind === 'word' && + // Operators + (node.value === '+' || node.value === '-' || node.value === '*' || node.value === '/') + ) { + let idx = parentArray.indexOf(node) ?? -1 + + // This should not be possible + if (idx === -1) return + + let previous = parentArray[idx - 1] + if (previous?.kind !== 'separator' || previous.value !== ' ') return + + let next = parentArray[idx + 1] + if (next?.kind !== 'separator' || next.value !== ' ') return + + drop.add(previous) + drop.add(next) + } + + // The value parser handles `/` as a separator in some scenarios. E.g.: + // `theme(colors.red/50%)`. Because of this, we have to handle this case + // separately. + else if (node.kind === 'separator' && node.value.trim() === '/') { + node.value = '/' + } + + // Leading and trailing whitespace + else if (node.kind === 'separator' && node.value.length > 0 && node.value.trim() === '') { + if (parentArray[0] === node || parentArray[parentArray.length - 1] === node) { + drop.add(node) + } + } + + // Whitespace around `,` separators can be removed. + // E.g.: `min(1px , 2px)` -> `min(1px,2px)` + else if (node.kind === 'separator' && node.value.trim() === ',') { + node.value = ',' + } + }) + + if (drop.size > 0) { + ValueParser.walk(ast, (node, { replaceWith }) => { + if (drop.has(node)) { + drop.delete(node) + replaceWith([]) + } + }) + } + + recursivelyEscapeUnderscores(ast) + + return ValueParser.toCss(ast) +} + +function simplifyArbitraryVariant(input: string) { + let ast = ValueParser.parse(input) + + // &:is(…) + if ( + ast.length === 3 && + // & + ast[0].kind === 'word' && + ast[0].value === '&' && + // : + ast[1].kind === 'separator' && + ast[1].value === ':' && + // is(…) + ast[2].kind === 'function' && + ast[2].value === 'is' + ) { + return ValueParser.toCss(ast[2].nodes) + } + + return input +} + +function recursivelyEscapeUnderscores(ast: ValueParser.ValueAstNode[]) { + for (let node of ast) { + switch (node.kind) { + case 'function': { + if (node.value === 'url' || node.value.endsWith('_url')) { + // Don't decode underscores in url() but do decode the function name + node.value = escapeUnderscore(node.value) + break + } + + if ( + node.value === 'var' || + node.value.endsWith('_var') || + node.value === 'theme' || + node.value.endsWith('_theme') + ) { + // Don't decode underscores in the first argument of var() and theme() + // but do decode the function name + node.value = escapeUnderscore(node.value) + for (let i = 0; i < node.nodes.length; i++) { + if (i == 0 && node.nodes[i].kind === 'word') { + continue + } + recursivelyEscapeUnderscores([node.nodes[i]]) + } + break + } + + node.value = escapeUnderscore(node.value) + recursivelyEscapeUnderscores(node.nodes) + break + } + case 'separator': + node.value = escapeUnderscore(node.value) + break + case 'word': { + // Dashed idents and variables `var(--my-var)` and `--my-var` should not + // have underscores escaped + if (node.value[0] !== '-' && node.value[1] !== '-') { + node.value = escapeUnderscore(node.value) + } + break + } + default: + never(node) + } + } +} + +function isVar(value: string) { + let ast = ValueParser.parse(value) + return ast.length === 1 && ast[0].kind === 'function' && ast[0].value === 'var' +} + +function never(value: never): never { + throw new Error(`Unexpected value: ${value}`) +} + +function escapeUnderscore(value: string): string { + return value + .replaceAll('_', String.raw`\_`) // Escape underscores to keep them as-is + .replaceAll(' ', '_') // Replace spaces with underscores +} diff --git a/packages/@tailwindcss-upgrade/src/template/codemods/arbitrary-value-to-bare-value.test.ts b/packages/@tailwindcss-upgrade/src/template/codemods/arbitrary-value-to-bare-value.test.ts new file mode 100644 index 000000000..62355dc6f --- /dev/null +++ b/packages/@tailwindcss-upgrade/src/template/codemods/arbitrary-value-to-bare-value.test.ts @@ -0,0 +1,64 @@ +import { __unstable__loadDesignSystem } from '@tailwindcss/node' +import { expect, test } from 'vitest' +import { arbitraryValueToBareValue } from './arbitrary-value-to-bare-value' + +test.each([ + ['aspect-[12/34]', 'aspect-12/34'], + ['aspect-[1.2/34]', 'aspect-[1.2/34]'], + ['col-start-[7]', 'col-start-7'], + ['flex-[2]', 'flex-2'], // `flex` is implemented as static and functional utilities + + ['grid-cols-[subgrid]', 'grid-cols-subgrid'], + ['grid-rows-[subgrid]', 'grid-rows-subgrid'], + + // Only 50-200% (inclusive) are valid: + // https://developer.mozilla.org/en-US/docs/Web/CSS/font-stretch#percentage + ['font-stretch-[50%]', 'font-stretch-50%'], + ['font-stretch-[50.5%]', 'font-stretch-[50.5%]'], + ['font-stretch-[201%]', 'font-stretch-[201%]'], + ['font-stretch-[49%]', 'font-stretch-[49%]'], + // Should stay as-is + ['font-stretch-[1/2]', 'font-stretch-[1/2]'], + + // Bare value with % is valid for these utilities + ['from-[28%]', 'from-28%'], + ['via-[28%]', 'via-28%'], + ['to-[28%]', 'to-28%'], + ['from-[28.5%]', 'from-[28.5%]'], + ['via-[28.5%]', 'via-[28.5%]'], + ['to-[28.5%]', 'to-[28.5%]'], + + // This test in itself is a bit flawed because `text-[1/2]` currently + // generates something. Converting it to `text-1/2` doesn't produce anything. + ['text-[1/2]', 'text-[1/2]'], + + ['data-[selected]:flex', 'data-selected:flex'], + ['data-[foo=bar]:flex', 'data-[foo=bar]:flex'], + + ['supports-[gap]:flex', 'supports-gap:flex'], + ['supports-[display:grid]:flex', 'supports-[display:grid]:flex'], + + ['group-data-[selected]:flex', 'group-data-selected:flex'], + ['group-data-[foo=bar]:flex', 'group-data-[foo=bar]:flex'], + ['group-has-data-[selected]:flex', 'group-has-data-selected:flex'], + + ['aria-[selected]:flex', 'aria-[selected]:flex'], + ['aria-[selected="true"]:flex', 'aria-selected:flex'], + ['aria-[selected*="true"]:flex', 'aria-[selected*="true"]:flex'], + + ['group-aria-[selected]:flex', 'group-aria-[selected]:flex'], + ['group-aria-[selected="true"]:flex', 'group-aria-selected:flex'], + ['group-has-aria-[selected]:flex', 'group-has-aria-[selected]:flex'], + + ['max-lg:hover:data-[selected]:flex!', 'max-lg:hover:data-selected:flex!'], + [ + 'data-[selected]:aria-[selected="true"]:aspect-[12/34]', + 'data-selected:aria-selected:aspect-12/34', + ], +])('%s => %s', async (candidate, result) => { + let designSystem = await __unstable__loadDesignSystem('@import "tailwindcss";', { + base: __dirname, + }) + + expect(arbitraryValueToBareValue(designSystem, {}, candidate)).toEqual(result) +}) diff --git a/packages/@tailwindcss-upgrade/src/template/codemods/arbitrary-value-to-bare-value.ts b/packages/@tailwindcss-upgrade/src/template/codemods/arbitrary-value-to-bare-value.ts new file mode 100644 index 000000000..77a303dc3 --- /dev/null +++ b/packages/@tailwindcss-upgrade/src/template/codemods/arbitrary-value-to-bare-value.ts @@ -0,0 +1,186 @@ +import { parseCandidate, type Candidate, type Variant } from '../../../../tailwindcss/src/candidate' +import type { Config } from '../../../../tailwindcss/src/compat/plugin-api' +import type { DesignSystem } from '../../../../tailwindcss/src/design-system' +import { isPositiveInteger } from '../../../../tailwindcss/src/utils/infer-data-type' +import { segment } from '../../../../tailwindcss/src/utils/segment' +import { printCandidate } from '../candidates' + +export function arbitraryValueToBareValue( + designSystem: DesignSystem, + _userConfig: Config, + rawCandidate: string, +): string { + for (let candidate of parseCandidate(rawCandidate, designSystem)) { + let clone = structuredClone(candidate) + let changed = false + + // Convert [subgrid] to subgrid + if ( + clone.kind === 'functional' && + clone.value?.kind === 'arbitrary' && + clone.value.value === 'subgrid' && + (clone.root === 'grid-cols' || clone.root == 'grid-rows') + ) { + changed = true + clone.value = { + kind: 'named', + value: 'subgrid', + fraction: null, + } + } + + // Convert utilities that accept bare values ending in % + if ( + clone.kind === 'functional' && + clone.value?.kind === 'arbitrary' && + clone.value.dataType === null && + (clone.root === 'from' || + clone.root === 'via' || + clone.root === 'to' || + clone.root === 'font-stretch') + ) { + if (clone.value.value.endsWith('%') && isPositiveInteger(clone.value.value.slice(0, -1))) { + let percentage = parseInt(clone.value.value) + if ( + clone.root === 'from' || + clone.root === 'via' || + clone.root === 'to' || + (clone.root === 'font-stretch' && percentage >= 50 && percentage <= 200) + ) { + changed = true + clone.value = { + kind: 'named', + value: clone.value.value, + fraction: null, + } + } + } + } + + // Convert arbitrary values with positive integers to bare values + // Convert arbitrary values with fractions to bare values + else if ( + clone.kind === 'functional' && + clone.value?.kind === 'arbitrary' && + clone.value.dataType === null + ) { + let parts = segment(clone.value.value, '/') + if (parts.every((part) => isPositiveInteger(part))) { + changed = true + + let currentValue = clone.value + let currentModifier = clone.modifier + + // E.g.: `col-start-[12]` + // ^^ + if (parts.length === 1) { + clone.value = { + kind: 'named', + value: clone.value.value, + fraction: null, + } + } + + // E.g.: `aspect-[12/34]` + // ^^ ^^ + else { + clone.value = { + kind: 'named', + value: parts[0], + fraction: clone.value.value, + } + clone.modifier = { + kind: 'named', + value: parts[1], + } + } + + // Double check that the new value compiles correctly + if (designSystem.compileAstNodes(clone).length === 0) { + clone.value = currentValue + clone.modifier = currentModifier + changed = false + } + } + } + + for (let variant of variants(clone)) { + // Convert `data-[selected]` to `data-selected` + if ( + variant.kind === 'functional' && + variant.root === 'data' && + variant.value?.kind === 'arbitrary' && + !variant.value.value.includes('=') + ) { + changed = true + variant.value = { + kind: 'named', + value: variant.value.value, + } + } + + // Convert `aria-[selected="true"]` to `aria-selected` + else if ( + variant.kind === 'functional' && + variant.root === 'aria' && + variant.value?.kind === 'arbitrary' && + (variant.value.value.endsWith('=true') || + variant.value.value.endsWith('="true"') || + variant.value.value.endsWith("='true'")) + ) { + let [key, _value] = segment(variant.value.value, '=') + if ( + // aria-[foo~="true"] + key[key.length - 1] === '~' || + // aria-[foo|="true"] + key[key.length - 1] === '|' || + // aria-[foo^="true"] + key[key.length - 1] === '^' || + // aria-[foo$="true"] + key[key.length - 1] === '$' || + // aria-[foo*="true"] + key[key.length - 1] === '*' + ) { + continue + } + + changed = true + variant.value = { + kind: 'named', + value: variant.value.value.slice(0, variant.value.value.indexOf('=')), + } + } + + // Convert `supports-[gap]` to `supports-gap` + else if ( + variant.kind === 'functional' && + variant.root === 'supports' && + variant.value?.kind === 'arbitrary' && + /^[a-z-][a-z0-9-]*$/i.test(variant.value.value) + ) { + changed = true + variant.value = { + kind: 'named', + value: variant.value.value, + } + } + } + + return changed ? printCandidate(designSystem, clone) : rawCandidate + } + + return rawCandidate +} + +function* variants(candidate: Candidate) { + function* inner(variant: Variant): Iterable { + yield variant + if (variant.kind === 'compound') { + yield* inner(variant.variant) + } + } + + for (let variant of candidate.variants) { + yield* inner(variant) + } +} diff --git a/packages/@tailwindcss-upgrade/src/codemods/template/migrate-automatic-var-injection.test.ts b/packages/@tailwindcss-upgrade/src/template/codemods/automatic-var-injection.test.ts similarity index 82% rename from packages/@tailwindcss-upgrade/src/codemods/template/migrate-automatic-var-injection.test.ts rename to packages/@tailwindcss-upgrade/src/template/codemods/automatic-var-injection.test.ts index 5da651d51..d9e714e9e 100644 --- a/packages/@tailwindcss-upgrade/src/codemods/template/migrate-automatic-var-injection.test.ts +++ b/packages/@tailwindcss-upgrade/src/template/codemods/automatic-var-injection.test.ts @@ -1,6 +1,6 @@ import { __unstable__loadDesignSystem } from '@tailwindcss/node' import { expect, test } from 'vitest' -import { migrateAutomaticVarInjection } from './migrate-automatic-var-injection' +import { automaticVarInjection } from './automatic-var-injection' test.each([ // Arbitrary candidates @@ -36,15 +36,6 @@ test.each([ ['supports-[--test]:flex', 'supports-(--test):flex'], ['supports-[_--test]:flex', 'supports-[--test]:flex'], - // Custom CSS functions that look like variables should not be converted - ['w-[--spacing(5)]', 'w-[--spacing(5)]'], - ['bg-[--theme(--color-red-500)]', 'bg-[--theme(--color-red-500)]'], - - // Fallback values should be included inside the `var(…)` function - ['bg-[--my-color,red]', 'bg-(--my-color,red)'], - // Fallback values can contain CSS functions - ['bg-[--my-color,theme(spacing.1)]', 'bg-(--my-color,theme(spacing.1))'], - // Some properties never had var() injection in v3. ['[scroll-timeline-name:--myTimeline]', '[scroll-timeline-name:--myTimeline]'], ['[timeline-scope:--myScope]', '[timeline-scope:--myScope]'], @@ -63,6 +54,6 @@ test.each([ base: __dirname, }) - let migrated = migrateAutomaticVarInjection(designSystem, {}, candidate) + let migrated = automaticVarInjection(designSystem, {}, candidate) expect(migrated).toEqual(result) }) diff --git a/packages/@tailwindcss-upgrade/src/codemods/template/migrate-automatic-var-injection.ts b/packages/@tailwindcss-upgrade/src/template/codemods/automatic-var-injection.ts similarity index 79% rename from packages/@tailwindcss-upgrade/src/codemods/template/migrate-automatic-var-injection.ts rename to packages/@tailwindcss-upgrade/src/template/codemods/automatic-var-injection.ts index 0ea3bd691..33995c04a 100644 --- a/packages/@tailwindcss-upgrade/src/codemods/template/migrate-automatic-var-injection.ts +++ b/packages/@tailwindcss-upgrade/src/template/codemods/automatic-var-injection.ts @@ -1,19 +1,18 @@ -import { cloneCandidate, type Candidate, type Variant } from '../../../../tailwindcss/src/candidate' +import { walk, WalkAction } from '../../../../tailwindcss/src/ast' +import { type Candidate, type Variant } from '../../../../tailwindcss/src/candidate' import type { Config } from '../../../../tailwindcss/src/compat/plugin-api' import type { DesignSystem } from '../../../../tailwindcss/src/design-system' -import type { Writable } from '../../../../tailwindcss/src/types' -import * as ValueParser from '../../../../tailwindcss/src/value-parser' -import { walk, WalkAction } from '../../../../tailwindcss/src/walk' +import { printCandidate } from '../candidates' -export function migrateAutomaticVarInjection( +export function automaticVarInjection( designSystem: DesignSystem, - _userConfig: Config | null, + _userConfig: Config, rawCandidate: string, ): string { for (let readonlyCandidate of designSystem.parseCandidate(rawCandidate)) { // The below logic makes extended use of mutation. Since candidates in the // DesignSystem are cached, we can't mutate them directly. - let candidate = cloneCandidate(readonlyCandidate) as Writable + let candidate = structuredClone(readonlyCandidate) as Candidate let didChange = false @@ -67,7 +66,7 @@ export function migrateAutomaticVarInjection( } if (didChange) { - return designSystem.printCandidate(candidate) + return printCandidate(designSystem, candidate) } } return rawCandidate @@ -76,27 +75,12 @@ export function migrateAutomaticVarInjection( function injectVar(value: string): { value: string; didChange: boolean } { let didChange = false if (value.startsWith('--')) { - // E.g.: - // - // - `--my-color` → `var(--my-color)` Convert variable - // - `--my-color,red` → `var(--my-color,red)` Convert variable with fallback - // - `--theme(color.red)` → `--theme(color.red)` Do not convert functions - // - if ( - // No `(` definitely means there is no function - !value.includes('(') || - // There could be a function call in the fallback value, but it cannot be - // top-level, so we can safely check the first part - ValueParser.parse(value)[0]?.kind !== 'function' - ) { - value = `var(${value})` - didChange = true - } + value = `var(${value})` + didChange = true } else if (value.startsWith(' --')) { value = value.slice(1) didChange = true } - return { value, didChange } } diff --git a/packages/@tailwindcss-upgrade/src/template/codemods/bg-gradient.test.ts b/packages/@tailwindcss-upgrade/src/template/codemods/bg-gradient.test.ts new file mode 100644 index 000000000..3c42903c3 --- /dev/null +++ b/packages/@tailwindcss-upgrade/src/template/codemods/bg-gradient.test.ts @@ -0,0 +1,22 @@ +import { __unstable__loadDesignSystem } from '@tailwindcss/node' +import { expect, test } from 'vitest' +import { bgGradient } from './bg-gradient' + +test.each([ + ['bg-gradient-to-t', 'bg-linear-to-t'], + ['bg-gradient-to-tr', 'bg-linear-to-tr'], + ['bg-gradient-to-r', 'bg-linear-to-r'], + ['bg-gradient-to-br', 'bg-linear-to-br'], + ['bg-gradient-to-b', 'bg-linear-to-b'], + ['bg-gradient-to-bl', 'bg-linear-to-bl'], + ['bg-gradient-to-l', 'bg-linear-to-l'], + ['bg-gradient-to-tl', 'bg-linear-to-tl'], + + ['max-lg:hover:bg-gradient-to-t', 'max-lg:hover:bg-linear-to-t'], +])('%s => %s', async (candidate, result) => { + let designSystem = await __unstable__loadDesignSystem('@import "tailwindcss";', { + base: __dirname, + }) + + expect(bgGradient(designSystem, {}, candidate)).toEqual(result) +}) diff --git a/packages/@tailwindcss-upgrade/src/template/codemods/bg-gradient.ts b/packages/@tailwindcss-upgrade/src/template/codemods/bg-gradient.ts new file mode 100644 index 000000000..02ad5590b --- /dev/null +++ b/packages/@tailwindcss-upgrade/src/template/codemods/bg-gradient.ts @@ -0,0 +1,27 @@ +import type { Config } from '../../../../tailwindcss/src/compat/plugin-api' +import type { DesignSystem } from '../../../../tailwindcss/src/design-system' +import { printCandidate } from '../candidates' + +const DIRECTIONS = ['t', 'tr', 'r', 'br', 'b', 'bl', 'l', 'tl'] + +export function bgGradient( + designSystem: DesignSystem, + _userConfig: Config, + rawCandidate: string, +): string { + for (let candidate of designSystem.parseCandidate(rawCandidate)) { + if (candidate.kind === 'static' && candidate.root.startsWith('bg-gradient-to-')) { + let direction = candidate.root.slice(15) + + if (!DIRECTIONS.includes(direction)) { + continue + } + + return printCandidate(designSystem, { + ...candidate, + root: `bg-linear-to-${direction}`, + }) + } + } + return rawCandidate +} diff --git a/packages/@tailwindcss-upgrade/src/codemods/template/migrate-handle-empty-arbitrary-values.test.ts b/packages/@tailwindcss-upgrade/src/template/codemods/handle-empty-arbitrary-values.test.ts similarity index 68% rename from packages/@tailwindcss-upgrade/src/codemods/template/migrate-handle-empty-arbitrary-values.test.ts rename to packages/@tailwindcss-upgrade/src/template/codemods/handle-empty-arbitrary-values.test.ts index bebd43343..b451fbf86 100644 --- a/packages/@tailwindcss-upgrade/src/codemods/template/migrate-handle-empty-arbitrary-values.test.ts +++ b/packages/@tailwindcss-upgrade/src/template/codemods/handle-empty-arbitrary-values.test.ts @@ -1,9 +1,7 @@ import { __unstable__loadDesignSystem } from '@tailwindcss/node' -import { expect, test, vi } from 'vitest' -import * as versions from '../../utils/version' -import { migrateEmptyArbitraryValues } from './migrate-handle-empty-arbitrary-values' -import { migratePrefix } from './migrate-prefix' -vi.spyOn(versions, 'isMajor').mockReturnValue(true) +import { expect, test } from 'vitest' +import { handleEmptyArbitraryValues } from './handle-empty-arbitrary-values' +import { prefix } from './prefix' test.each([ ['group-[]:flex', 'group-[&]:flex'], @@ -16,7 +14,7 @@ test.each([ base: __dirname, }) - expect(migrateEmptyArbitraryValues(designSystem, {}, candidate)).toEqual(result) + expect(handleEmptyArbitraryValues(designSystem, {}, candidate)).toEqual(result) }) test.each([ @@ -31,7 +29,7 @@ test.each([ }) expect( - [migrateEmptyArbitraryValues, migratePrefix].reduce( + [handleEmptyArbitraryValues, prefix].reduce( (acc, step) => step(designSystem, { prefix: 'tw-' }, acc), candidate, ), diff --git a/packages/@tailwindcss-upgrade/src/codemods/template/migrate-handle-empty-arbitrary-values.ts b/packages/@tailwindcss-upgrade/src/template/codemods/handle-empty-arbitrary-values.ts similarity index 91% rename from packages/@tailwindcss-upgrade/src/codemods/template/migrate-handle-empty-arbitrary-values.ts rename to packages/@tailwindcss-upgrade/src/template/codemods/handle-empty-arbitrary-values.ts index 0058814d9..8f7dc5e6e 100644 --- a/packages/@tailwindcss-upgrade/src/codemods/template/migrate-handle-empty-arbitrary-values.ts +++ b/packages/@tailwindcss-upgrade/src/template/codemods/handle-empty-arbitrary-values.ts @@ -1,9 +1,9 @@ import type { Config } from '../../../../tailwindcss/src/compat/plugin-api' import type { DesignSystem } from '../../../../tailwindcss/src/design-system' -export function migrateEmptyArbitraryValues( +export function handleEmptyArbitraryValues( designSystem: DesignSystem, - _userConfig: Config | null, + _userConfig: Config, rawCandidate: string, ): string { // We can parse the candidate, nothing to do diff --git a/packages/@tailwindcss-upgrade/src/template/codemods/important.test.ts b/packages/@tailwindcss-upgrade/src/template/codemods/important.test.ts new file mode 100644 index 000000000..60d78aa53 --- /dev/null +++ b/packages/@tailwindcss-upgrade/src/template/codemods/important.test.ts @@ -0,0 +1,68 @@ +import { __unstable__loadDesignSystem } from '@tailwindcss/node' +import { expect, test } from 'vitest' +import { important } from './important' + +test.each([ + ['!flex', 'flex!'], + ['min-[calc(1000px+12em)]:!flex', 'min-[calc(1000px+12em)]:flex!'], + ['md:!block', 'md:block!'], + + // Does not change non-important candidates + ['bg-blue-500', 'bg-blue-500'], + ['min-[calc(1000px+12em)]:flex', 'min-[calc(1000px+12em)]:flex'], +])('%s => %s', async (candidate, result) => { + let designSystem = await __unstable__loadDesignSystem('@import "tailwindcss";', { + base: __dirname, + }) + + expect( + important(designSystem, {}, candidate, { + contents: `"${candidate}"`, + start: 1, + end: candidate.length + 1, + }), + ).toEqual(result) +}) + +test('does not match false positives', async () => { + let designSystem = await __unstable__loadDesignSystem('@import "tailwindcss";', { + base: __dirname, + }) + + expect( + important(designSystem, {}, '!border', { + contents: `let notBorder = !border\n`, + start: 16, + end: 16 + '!border'.length, + }), + ).toEqual('!border') +}) + +test('does not match false positives', async () => { + let designSystem = await __unstable__loadDesignSystem('@import "tailwindcss";', { + base: __dirname, + }) + + function shouldNotDetect(example: string, candidate = '!border') { + expect( + important(designSystem, {}, candidate, { + contents: example, + start: example.indexOf(candidate), + end: example.indexOf(candidate) + candidate.length, + }), + ).toEqual('!border') + } + + shouldNotDetect(`let notBorder = !border \n`) + shouldNotDetect(`{ "foo": !border.something + ""}\n`) + shouldNotDetect(`
\n`) + shouldNotDetect(`
\n`) + shouldNotDetect(`
\n`) + shouldNotDetect(`
\n`) + shouldNotDetect(`
\n`) + shouldNotDetect(`
\n`) + shouldNotDetect(`
\n`) + shouldNotDetect(`
\n`) + shouldNotDetect(`
\n`) + shouldNotDetect(`
\n`) +}) diff --git a/packages/@tailwindcss-upgrade/src/template/codemods/important.ts b/packages/@tailwindcss-upgrade/src/template/codemods/important.ts new file mode 100644 index 000000000..4f2c6871f --- /dev/null +++ b/packages/@tailwindcss-upgrade/src/template/codemods/important.ts @@ -0,0 +1,49 @@ +import { parseCandidate } from '../../../../tailwindcss/src/candidate' +import type { Config } from '../../../../tailwindcss/src/compat/plugin-api' +import type { DesignSystem } from '../../../../tailwindcss/src/design-system' +import { printCandidate } from '../candidates' +import { isSafeMigration } from '../is-safe-migration' + +// In v3 the important modifier `!` sits in front of the utility itself, not +// before any of the variants. In v4, we want it to be at the end of the utility +// so that it's always in the same location regardless of whether you used +// variants or not. +// +// So this: +// +// !flex md:!block +// +// Should turn into: +// +// flex! md:block! +export function important( + designSystem: DesignSystem, + _userConfig: Config, + rawCandidate: string, + location?: { + contents: string + start: number + end: number + }, +): string { + nextCandidate: for (let candidate of parseCandidate(rawCandidate, designSystem)) { + if (candidate.important && candidate.raw[candidate.raw.length - 1] !== '!') { + // The important migration is one of the most broad migrations with a high + // potential of matching false positives since `!` is a valid character in + // most programming languages. Since v4 is technically backward compatible + // with v3 in that it can read `!` in the front of the utility too, we err + // on the side of caution and only migrate candidates that we are certain + // are inside of a string. + if (location && !isSafeMigration(location)) { + continue nextCandidate + } + + // The printCandidate function will already put the exclamation mark in + // the right place, so we just need to mark this candidate as requiring a + // migration. + return printCandidate(designSystem, candidate) + } + } + + return rawCandidate +} diff --git a/packages/@tailwindcss-upgrade/src/codemods/template/migrate-legacy-arbitrary-values.test.ts b/packages/@tailwindcss-upgrade/src/template/codemods/legacy-arbitrary-values.test.ts similarity index 72% rename from packages/@tailwindcss-upgrade/src/codemods/template/migrate-legacy-arbitrary-values.test.ts rename to packages/@tailwindcss-upgrade/src/template/codemods/legacy-arbitrary-values.test.ts index 8bb193b43..974cd0ca3 100644 --- a/packages/@tailwindcss-upgrade/src/codemods/template/migrate-legacy-arbitrary-values.test.ts +++ b/packages/@tailwindcss-upgrade/src/template/codemods/legacy-arbitrary-values.test.ts @@ -1,6 +1,6 @@ import { __unstable__loadDesignSystem } from '@tailwindcss/node' import { expect, test } from 'vitest' -import { migrateLegacyArbitraryValues } from './migrate-legacy-arbitrary-values' +import { legacyArbitraryValues } from './legacy-arbitrary-values' test.each([ ['grid-cols-[auto,1fr]', 'grid-cols-[auto_1fr]'], @@ -11,5 +11,5 @@ test.each([ base: __dirname, }) - expect(migrateLegacyArbitraryValues(designSystem, {}, candidate)).toEqual(result) + expect(legacyArbitraryValues(designSystem, {}, candidate)).toEqual(result) }) diff --git a/packages/@tailwindcss-upgrade/src/codemods/template/migrate-legacy-arbitrary-values.ts b/packages/@tailwindcss-upgrade/src/template/codemods/legacy-arbitrary-values.ts similarity index 72% rename from packages/@tailwindcss-upgrade/src/codemods/template/migrate-legacy-arbitrary-values.ts rename to packages/@tailwindcss-upgrade/src/template/codemods/legacy-arbitrary-values.ts index 2bd7d2fd5..1c60526fd 100644 --- a/packages/@tailwindcss-upgrade/src/codemods/template/migrate-legacy-arbitrary-values.ts +++ b/packages/@tailwindcss-upgrade/src/template/codemods/legacy-arbitrary-values.ts @@ -1,15 +1,16 @@ -import { cloneCandidate, parseCandidate } from '../../../../tailwindcss/src/candidate' +import { parseCandidate } from '../../../../tailwindcss/src/candidate' import type { Config } from '../../../../tailwindcss/src/compat/plugin-api' import type { DesignSystem } from '../../../../tailwindcss/src/design-system' import { segment } from '../../../../tailwindcss/src/utils/segment' +import { printCandidate } from '../candidates' -export function migrateLegacyArbitraryValues( +export function legacyArbitraryValues( designSystem: DesignSystem, - _userConfig: Config | null, + _userConfig: Config, rawCandidate: string, ): string { for (let candidate of parseCandidate(rawCandidate, designSystem)) { - let clone = cloneCandidate(candidate) + let clone = structuredClone(candidate) let changed = false // Convert commas to spaces. E.g.: [auto,1fr] to [auto_1fr] @@ -22,7 +23,7 @@ export function migrateLegacyArbitraryValues( clone.value.value = segment(clone.value.value, ',').join(' ') } - return changed ? designSystem.printCandidate(clone) : rawCandidate + return changed ? printCandidate(designSystem, clone) : rawCandidate } return rawCandidate diff --git a/packages/@tailwindcss-upgrade/src/codemods/template/migrate-legacy-classes.test.ts b/packages/@tailwindcss-upgrade/src/template/codemods/legacy-classes.test.ts similarity index 74% rename from packages/@tailwindcss-upgrade/src/codemods/template/migrate-legacy-classes.test.ts rename to packages/@tailwindcss-upgrade/src/template/codemods/legacy-classes.test.ts index 5b204386f..5d29c1b71 100644 --- a/packages/@tailwindcss-upgrade/src/codemods/template/migrate-legacy-classes.test.ts +++ b/packages/@tailwindcss-upgrade/src/template/codemods/legacy-classes.test.ts @@ -1,8 +1,6 @@ import { __unstable__loadDesignSystem } from '@tailwindcss/node' -import { expect, test, vi } from 'vitest' -import * as versions from '../../utils/version' -import { migrateLegacyClasses } from './migrate-legacy-classes' -vi.spyOn(versions, 'isMajor').mockReturnValue(true) +import { expect, test } from 'vitest' +import { legacyClasses } from './legacy-classes' test.each([ ['shadow', 'shadow-sm'], @@ -27,8 +25,6 @@ test.each([ ['ring', 'ring-3'], - ['outline', 'outline-solid'], - ['blur!', 'blur-sm!'], ['hover:blur', 'hover:blur-sm'], ['hover:blur!', 'hover:blur-sm!'], @@ -41,5 +37,5 @@ test.each([ base: __dirname, }) - expect(await migrateLegacyClasses(designSystem, {}, candidate)).toEqual(result) + expect(await legacyClasses(designSystem, {}, candidate)).toEqual(result) }) diff --git a/packages/@tailwindcss-upgrade/src/codemods/template/migrate-legacy-classes.ts b/packages/@tailwindcss-upgrade/src/template/codemods/legacy-classes.ts similarity index 69% rename from packages/@tailwindcss-upgrade/src/codemods/template/migrate-legacy-classes.ts rename to packages/@tailwindcss-upgrade/src/template/codemods/legacy-classes.ts index 2b088aa2e..adf31e7f4 100644 --- a/packages/@tailwindcss-upgrade/src/codemods/template/migrate-legacy-classes.ts +++ b/packages/@tailwindcss-upgrade/src/template/codemods/legacy-classes.ts @@ -1,12 +1,12 @@ import { __unstable__loadDesignSystem } from '@tailwindcss/node' import path from 'node:path' import url from 'node:url' -import { cloneCandidate, type Candidate } from '../../../../tailwindcss/src/candidate' +import type { Candidate } from '../../../../tailwindcss/src/candidate' import type { Config } from '../../../../tailwindcss/src/compat/plugin-api' import type { DesignSystem } from '../../../../tailwindcss/src/design-system' import { DefaultMap } from '../../../../tailwindcss/src/utils/default-map' -import * as version from '../../utils/version' -import { baseCandidate } from './candidates' +import { printCandidate } from '../candidates' +import { isSafeMigration } from '../is-safe-migration' const __filename = url.fileURLToPath(import.meta.url) const __dirname = path.dirname(__filename) @@ -33,8 +33,6 @@ const LEGACY_CLASS_MAP = new Map([ ['backdrop-blur-sm', 'backdrop-blur-xs'], ['ring', 'ring-3'], - - ['outline', 'outline-solid'], ]) const THEME_KEYS = new Map([ @@ -59,7 +57,7 @@ const THEME_KEYS = new Map([ ['backdrop-blur-sm', '--backdrop-blur-sm'], ['backdrop-blur-xs', '--backdrop-blur-xs'], - ['ring', '--default-ring-width'], + ['ring', '--ring-width'], ['ring-3', '--ring-width-3'], ]) @@ -67,28 +65,26 @@ const DESIGN_SYSTEMS = new DefaultMap((base) => { return __unstable__loadDesignSystem('@import "tailwindcss";', { base }) }) -export async function migrateLegacyClasses( +export async function legacyClasses( designSystem: DesignSystem, - _userConfig: Config | null, + _userConfig: Config, rawCandidate: string, + location?: { + contents: string + start: number + end: number + }, ): Promise { - // These migrations are only safe when migrating from v3 to v4. - // - // Migrating from `rounded` to `rounded-sm` once is fine (v3 -> v4). But if we - // migrate again (v4 -> v4), then `rounded-sm` would be migrated to - // `rounded-xs` which is incorrect because we already migrated this. - if (!version.isMajor(3)) { - return rawCandidate - } - let defaultDesignSystem = await DESIGN_SYSTEMS.get(__dirname) function* migrate(rawCandidate: string) { for (let candidate of designSystem.parseCandidate(rawCandidate)) { // Create a base candidate string from the candidate. // E.g.: `hover:blur!` -> `blur` - let base = baseCandidate(candidate) - let baseCandidateString = designSystem.printCandidate(base) + let baseCandidate = structuredClone(candidate) as Candidate + baseCandidate.variants = [] + baseCandidate.important = false + let baseCandidateString = printCandidate(designSystem, baseCandidate) // Find the new base candidate string. `blur` -> `blur-sm` let newBaseCandidateString = LEGACY_CLASS_MAP.get(baseCandidateString) @@ -100,11 +96,12 @@ export async function migrateLegacyClasses( // Re-apply the variants and important flag from the original candidate. // E.g.: `hover:blur!` -> `blur` -> `blur-sm` -> `hover:blur-sm!` - let newCandidate = cloneCandidate(newBaseCandidate) as Candidate + let newCandidate = structuredClone(newBaseCandidate) as Candidate newCandidate.variants = candidate.variants newCandidate.important = candidate.important yield [ + candidate, newCandidate, THEME_KEYS.get(baseCandidateString), THEME_KEYS.get(newBaseCandidateString), @@ -112,12 +109,39 @@ export async function migrateLegacyClasses( } } - for (let [toCandidate, fromThemeKey, toThemeKey] of migrate(rawCandidate)) { + for (let [fromCandidate, toCandidate, fromThemeKey, toThemeKey] of migrate(rawCandidate)) { + // Every utility that has a simple representation (e.g.: `blur`, `radius`, + // etc.`) without variants or special characters _could_ be a potential + // problem during the migration. + let isPotentialProblematicClass = (() => { + if (fromCandidate.variants.length > 0) { + return false + } + + if (fromCandidate.kind === 'arbitrary') { + return false + } + + if (fromCandidate.kind === 'static') { + return !fromCandidate.root.includes('-') + } + + if (fromCandidate.kind === 'functional') { + return fromCandidate.value === null || !fromCandidate.root.includes('-') + } + + return false + })() + + if (location && isPotentialProblematicClass && !isSafeMigration(location)) { + continue + } + if (fromThemeKey && toThemeKey) { // Migrating something that resolves to a value in the theme. - let customFrom = designSystem.resolveThemeValue(fromThemeKey, true) - let defaultFrom = defaultDesignSystem.resolveThemeValue(fromThemeKey, true) - let customTo = designSystem.resolveThemeValue(toThemeKey, true) + let customFrom = designSystem.resolveThemeValue(fromThemeKey) + let defaultFrom = defaultDesignSystem.resolveThemeValue(fromThemeKey) + let customTo = designSystem.resolveThemeValue(toThemeKey) let defaultTo = defaultDesignSystem.resolveThemeValue(toThemeKey) // The new theme value is not defined, which means we can't safely @@ -137,7 +161,7 @@ export async function migrateLegacyClasses( } } - return designSystem.printCandidate(toCandidate) + return printCandidate(designSystem, toCandidate) } return rawCandidate diff --git a/packages/@tailwindcss-upgrade/src/codemods/template/migrate-max-width-screen.test.ts b/packages/@tailwindcss-upgrade/src/template/codemods/max-width-screen.test.ts similarity index 74% rename from packages/@tailwindcss-upgrade/src/codemods/template/migrate-max-width-screen.test.ts rename to packages/@tailwindcss-upgrade/src/template/codemods/max-width-screen.test.ts index 91b57b3db..3e3151cbc 100644 --- a/packages/@tailwindcss-upgrade/src/codemods/template/migrate-max-width-screen.test.ts +++ b/packages/@tailwindcss-upgrade/src/template/codemods/max-width-screen.test.ts @@ -1,12 +1,12 @@ import { __unstable__loadDesignSystem } from '@tailwindcss/node' import { expect, test } from 'vitest' -import { migrateMaxWidthScreen } from './migrate-max-width-screen' +import { maxWidthScreen } from './max-width-screen' test('converts max-w-screen-* to max-w-[theme(screens.*)] (so it will later be converted to the var injection)', async () => { let designSystem = await __unstable__loadDesignSystem('@import "tailwindcss";', { base: __dirname, }) - let migrated = migrateMaxWidthScreen(designSystem, {}, 'max-w-screen-md') + let migrated = maxWidthScreen(designSystem, {}, 'max-w-screen-md') expect(migrated).toMatchInlineSnapshot(`"max-w-[theme(screens.md)]"`) }) diff --git a/packages/@tailwindcss-upgrade/src/codemods/template/migrate-max-width-screen.ts b/packages/@tailwindcss-upgrade/src/template/codemods/max-width-screen.ts similarity index 81% rename from packages/@tailwindcss-upgrade/src/codemods/template/migrate-max-width-screen.ts rename to packages/@tailwindcss-upgrade/src/template/codemods/max-width-screen.ts index cc9b7e9e2..4a14e5aad 100644 --- a/packages/@tailwindcss-upgrade/src/codemods/template/migrate-max-width-screen.ts +++ b/packages/@tailwindcss-upgrade/src/template/codemods/max-width-screen.ts @@ -1,9 +1,10 @@ import type { Config } from '../../../../tailwindcss/src/compat/plugin-api' import type { DesignSystem } from '../../../../tailwindcss/src/design-system' +import { printCandidate } from '../candidates' -export function migrateMaxWidthScreen( +export function maxWidthScreen( designSystem: DesignSystem, - _userConfig: Config | null, + _userConfig: Config, rawCandidate: string, ): string { for (let candidate of designSystem.parseCandidate(rawCandidate)) { @@ -12,7 +13,7 @@ export function migrateMaxWidthScreen( candidate.root === 'max-w' && candidate.value?.value.startsWith('screen-') ) { - return designSystem.printCandidate({ + return printCandidate(designSystem, { ...candidate, value: { ...candidate.value, diff --git a/packages/@tailwindcss-upgrade/src/template/codemods/modernize-arbitrary-values.test.ts b/packages/@tailwindcss-upgrade/src/template/codemods/modernize-arbitrary-values.test.ts new file mode 100644 index 000000000..ec38d0864 --- /dev/null +++ b/packages/@tailwindcss-upgrade/src/template/codemods/modernize-arbitrary-values.test.ts @@ -0,0 +1,138 @@ +import { __unstable__loadDesignSystem } from '@tailwindcss/node' +import { expect, test } from 'vitest' +import { handleEmptyArbitraryValues } from './handle-empty-arbitrary-values' +import { modernizeArbitraryValues } from './modernize-arbitrary-values' +import { prefix } from './prefix' + +test.each([ + // Arbitrary variants + ['[[data-visible]]:flex', 'data-visible:flex'], + ['[&[data-visible]]:flex', 'data-visible:flex'], + ['[[data-visible]&]:flex', 'data-visible:flex'], + ['[&>[data-visible]]:flex', '*:data-visible:flex'], + ['[&_>_[data-visible]]:flex', '*:data-visible:flex'], + ['[&>*]:flex', '*:flex'], + ['[&_>_*]:flex', '*:flex'], + + ['[&_[data-visible]]:flex', '**:data-visible:flex'], + ['[&_*]:flex', '**:flex'], + + ['[&:first-child]:flex', 'first:flex'], + ['[&:not(:first-child)]:flex', 'not-first:flex'], + + // in-* variants + ['[p_&]:flex', 'in-[p]:flex'], + ['[.foo_&]:flex', 'in-[.foo]:flex'], + ['[[data-visible]_&]:flex', 'in-data-visible:flex'], + // Multiple selectors, should stay as-is + ['[[data-foo][data-bar]_&]:flex', '[[data-foo][data-bar]_&]:flex'], + // Using `>` instead of ` ` should not be transformed: + ['[figure>&]:my-0', '[figure>&]:my-0'], + // Some extreme examples of what happens in the wild: + ['group-[]:flex', 'in-[.group]:flex'], + ['group-[]/name:flex', 'in-[.group\\/name]:flex'], + + // Migrate `peer-[]` to a parsable `peer-[&]` instead: + ['peer-[]:flex', 'peer-[&]:flex'], + ['peer-[]/name:flex', 'peer-[&]/name:flex'], + + // These shouldn't happen in the real world (because compound variants are + // new). But this could happen once we allow codemods to run in v4+ projects. + ['has-group-[]:flex', 'has-in-[.group]:flex'], + ['has-group-[]/name:flex', 'has-in-[.group\\/name]:flex'], + ['not-group-[]:flex', 'not-in-[.group]:flex'], + ['not-group-[]/name:flex', 'not-in-[.group\\/name]:flex'], + + // nth-child + ['[&:nth-child(2)]:flex', 'nth-2:flex'], + ['[&:not(:nth-child(2))]:flex', 'not-nth-2:flex'], + + ['[&:nth-child(-n+3)]:flex', 'nth-[-n+3]:flex'], + ['[&:not(:nth-child(-n+3))]:flex', 'not-nth-[-n+3]:flex'], + ['[&:nth-child(-n_+_3)]:flex', 'nth-[-n+3]:flex'], + ['[&:not(:nth-child(-n_+_3))]:flex', 'not-nth-[-n+3]:flex'], + + // nth-last-child + ['[&:nth-last-child(2)]:flex', 'nth-last-2:flex'], + ['[&:not(:nth-last-child(2))]:flex', 'not-nth-last-2:flex'], + + ['[&:nth-last-child(-n+3)]:flex', 'nth-last-[-n+3]:flex'], + ['[&:not(:nth-last-child(-n+3))]:flex', 'not-nth-last-[-n+3]:flex'], + ['[&:nth-last-child(-n_+_3)]:flex', 'nth-last-[-n+3]:flex'], + ['[&:not(:nth-last-child(-n_+_3))]:flex', 'not-nth-last-[-n+3]:flex'], + + // nth-child odd/even + ['[&:nth-child(odd)]:flex', 'odd:flex'], + ['[&:not(:nth-child(odd))]:flex', 'even:flex'], + ['[&:nth-child(even)]:flex', 'even:flex'], + ['[&:not(:nth-child(even))]:flex', 'odd:flex'], + + // Keep multiple attribute selectors as-is + ['[[data-visible][data-dark]]:flex', '[[data-visible][data-dark]]:flex'], + + // Complex attribute selectors with operators, quotes and insensitivity flags + ['[[data-url*="example"]]:flex', 'data-[url*="example"]:flex'], + ['[[data-url$=".com"_i]]:flex', 'data-[url$=".com"_i]:flex'], + ['[[data-url$=.com_i]]:flex', 'data-[url$=.com_i]:flex'], + + // Attribute selector wrapped in `&:is(…)` + ['[&:is([data-visible])]:flex', 'data-visible:flex'], + + // Compound arbitrary variants + ['has-[[data-visible]]:flex', 'has-data-visible:flex'], + ['has-[&:is([data-visible])]:flex', 'has-data-visible:flex'], + ['has-[&>[data-visible]]:flex', 'has-[&>[data-visible]]:flex'], + + ['has-[[data-slot=description]]:flex', 'has-data-[slot=description]:flex'], + ['has-[&:is([data-slot=description])]:flex', 'has-data-[slot=description]:flex'], + + ['has-[[aria-visible="true"]]:flex', 'has-aria-visible:flex'], + ['has-[[aria-visible]]:flex', 'has-aria-[visible]:flex'], + + ['has-[&:not(:nth-child(even))]:flex', 'has-odd:flex'], +])('%s => %s (%#)', async (candidate, result) => { + let designSystem = await __unstable__loadDesignSystem('@import "tailwindcss";', { + base: __dirname, + }) + + expect( + [handleEmptyArbitraryValues, modernizeArbitraryValues].reduce( + (acc, step) => step(designSystem, {}, acc), + candidate, + ), + ).toEqual(result) +}) + +test.each([ + // Should not prefix classes in arbitrary values + ['[.foo_&]:tw-flex', 'tw:in-[.foo]:flex'], + + // Should migrate `.group` classes + ['group-[]:tw-flex', 'tw:in-[.tw\\:group]:flex'], + ['group-[]/name:tw-flex', 'tw:in-[.tw\\:group\\/name]:flex'], + + // Migrate `peer-[]` to a parsable `peer-[&]` instead: + ['peer-[]:tw-flex', 'tw:peer-[&]:flex'], + ['peer-[]/name:tw-flex', 'tw:peer-[&]/name:flex'], + + // However, `.group` inside of an arbitrary variant should not be prefixed: + ['[.group_&]:tw-flex', 'tw:in-[.group]:flex'], + + // These shouldn't happen in the real world (because compound variants are + // new). But this could happen once we allow codemods to run in v4+ projects. + ['has-group-[]:tw-flex', 'tw:has-in-[.tw\\:group]:flex'], + ['has-group-[]/name:tw-flex', 'tw:has-in-[.tw\\:group\\/name]:flex'], + ['not-group-[]:tw-flex', 'tw:not-in-[.tw\\:group]:flex'], + ['not-group-[]/name:tw-flex', 'tw:not-in-[.tw\\:group\\/name]:flex'], +])('%s => %s (%#)', async (candidate, result) => { + let designSystem = await __unstable__loadDesignSystem('@import "tailwindcss" prefix(tw);', { + base: __dirname, + }) + + expect( + [handleEmptyArbitraryValues, prefix, modernizeArbitraryValues].reduce( + (acc, step) => step(designSystem, { prefix: 'tw-' }, acc), + candidate, + ), + ).toEqual(result) +}) diff --git a/packages/@tailwindcss-upgrade/src/template/codemods/modernize-arbitrary-values.ts b/packages/@tailwindcss-upgrade/src/template/codemods/modernize-arbitrary-values.ts new file mode 100644 index 000000000..3d90351b1 --- /dev/null +++ b/packages/@tailwindcss-upgrade/src/template/codemods/modernize-arbitrary-values.ts @@ -0,0 +1,402 @@ +import SelectorParser from 'postcss-selector-parser' +import { parseCandidate, type Candidate, type Variant } from '../../../../tailwindcss/src/candidate' +import type { Config } from '../../../../tailwindcss/src/compat/plugin-api' +import type { DesignSystem } from '../../../../tailwindcss/src/design-system' +import { isPositiveInteger } from '../../../../tailwindcss/src/utils/infer-data-type' +import { printCandidate } from '../candidates' + +function memcpy(target: T, source: U): U { + // Clear out the target object, otherwise inspecting the final object will + // look very confusing. + for (let key in target) delete target[key] + + return Object.assign(target, source) +} + +export function modernizeArbitraryValues( + designSystem: DesignSystem, + _userConfig: Config, + rawCandidate: string, +): string { + for (let candidate of parseCandidate(rawCandidate, designSystem)) { + let clone = structuredClone(candidate) + let changed = false + + for (let [variant, parent] of variants(clone)) { + // Forward modifier from the root to the compound variant + if ( + variant.kind === 'compound' && + (variant.root === 'has' || variant.root === 'not' || variant.root === 'in') + ) { + if (variant.modifier !== null) { + if ('modifier' in variant.variant) { + variant.variant.modifier = variant.modifier + variant.modifier = null + } + } + } + + // Promote `group-[]:flex` to `in-[.group]:flex` + // ^^ Yes, this is empty + // Promote `group-[]/name:flex` to `in-[.group\/name]:flex` + if ( + variant.kind === 'compound' && + variant.root === 'group' && + variant.variant.kind === 'arbitrary' && + variant.variant.selector === '&' + ) { + // `group-[]` + if (variant.modifier === null) { + changed = true + memcpy( + variant, + designSystem.parseVariant( + designSystem.theme.prefix + ? `in-[.${designSystem.theme.prefix}\\:group]` + : 'in-[.group]', + ), + ) + } + + // `group-[]/name` + else if (variant.modifier.kind === 'named') { + changed = true + memcpy( + variant, + designSystem.parseVariant( + designSystem.theme.prefix + ? `in-[.${designSystem.theme.prefix}\\:group\\/${variant.modifier.value}]` + : `in-[.group\\/${variant.modifier.value}]`, + ), + ) + } + continue + } + + // Expecting an arbitrary variant + if (variant.kind === 'arbitrary') { + // Expecting a non-relative arbitrary variant + if (variant.relative) continue + + let ast = SelectorParser().astSync(variant.selector) + + // Expecting a single selector node + if (ast.nodes.length !== 1) continue + + // `[&>*]` can be replaced with `*` + if ( + // Only top-level, so `has-[&>*]` is not supported + parent === null && + // [&_>_*]:flex + // ^ ^ ^ + ast.nodes[0].length === 3 && + ast.nodes[0].nodes[0].type === 'nesting' && + ast.nodes[0].nodes[0].value === '&' && + ast.nodes[0].nodes[1].type === 'combinator' && + ast.nodes[0].nodes[1].value === '>' && + ast.nodes[0].nodes[2].type === 'universal' + ) { + changed = true + memcpy(variant, designSystem.parseVariant('*')) + continue + } + + // `[&_*]` can be replaced with `**` + if ( + // Only top-level, so `has-[&_*]` is not supported + parent === null && + // [&_*]:flex + // ^ ^ + ast.nodes[0].length === 3 && + ast.nodes[0].nodes[0].type === 'nesting' && + ast.nodes[0].nodes[0].value === '&' && + ast.nodes[0].nodes[1].type === 'combinator' && + ast.nodes[0].nodes[1].value === ' ' && + ast.nodes[0].nodes[2].type === 'universal' + ) { + changed = true + memcpy(variant, designSystem.parseVariant('**')) + continue + } + + // `in-*` variant. If the selector ends with ` &`, we can convert it to an + // `in-*` variant. + // + // E.g.: `[[data-visible]_&]` => `in-data-visible` + if ( + // Only top-level, so `in-[&_[data-visible]]` is not supported + parent === null && + // [[data-visible]___&]:flex + // ^^^^^^^^^^^^^^ ^ ^ + ast.nodes[0].nodes.length === 3 && + ast.nodes[0].nodes[1].type === 'combinator' && + ast.nodes[0].nodes[1].value === ' ' && + ast.nodes[0].nodes[2].type === 'nesting' + ) { + ast.nodes[0].nodes.pop() // Remove the nesting node + ast.nodes[0].nodes.pop() // Remove the combinator + + changed = true + // When handling a compound like `in-[[data-visible]]`, we will first + // handle `[[data-visible]]`, then the parent `in-*` part. This means + // that we can convert `[[data-visible]_&]` to `in-[[data-visible]]`. + // + // Later this gets converted to `in-data-visible`. + memcpy(variant, designSystem.parseVariant(`in-[${ast.toString()}]`)) + continue + } + + let prefixedVariant: Variant | null = null + + // Handling a child combinator. E.g.: `[&>[data-visible]]` => `*:data-visible` + if ( + // Only top-level, so `has-[&>[data-visible]]` is not supported + parent === null && + // [&_>_[data-visible]]:flex + // ^ ^ ^^^^^^^^^^^^^^ + ast.nodes[0].length === 3 && + ast.nodes[0].nodes[0].type === 'nesting' && + ast.nodes[0].nodes[0].value === '&' && + ast.nodes[0].nodes[1].type === 'combinator' && + ast.nodes[0].nodes[1].value === '>' && + ast.nodes[0].nodes[2].type === 'attribute' + ) { + ast.nodes[0].nodes = [ast.nodes[0].nodes[2]] + prefixedVariant = designSystem.parseVariant('*') + } + + // Handling a grand child combinator. E.g.: `[&_[data-visible]]` => `**:data-visible` + if ( + // Only top-level, so `has-[&_[data-visible]]` is not supported + parent === null && + // [&_[data-visible]]:flex + // ^ ^^^^^^^^^^^^^^ + ast.nodes[0].length === 3 && + ast.nodes[0].nodes[0].type === 'nesting' && + ast.nodes[0].nodes[0].value === '&' && + ast.nodes[0].nodes[1].type === 'combinator' && + ast.nodes[0].nodes[1].value === ' ' && + ast.nodes[0].nodes[2].type === 'attribute' + ) { + ast.nodes[0].nodes = [ast.nodes[0].nodes[2]] + prefixedVariant = designSystem.parseVariant('**') + } + + // Filter out `&`. E.g.: `&[data-foo]` => `[data-foo]` + let selectorNodes = ast.nodes[0].filter((node) => node.type !== 'nesting') + + // Expecting a single selector (normal selector or attribute selector) + if (selectorNodes.length !== 1) continue + + let target = selectorNodes[0] + if (target.type === 'pseudo' && target.value === ':is') { + // Expecting a single selector node + if (target.nodes.length !== 1) continue + + // Expecting a single attribute selector + if (target.nodes[0].nodes.length !== 1) continue + + // Unwrap the selector from inside `&:is(…)` + target = target.nodes[0].nodes[0] + } + + // Expecting a pseudo selector + if (target.type === 'pseudo') { + let targetNode = target + let compoundNot = false + if (target.value === ':not') { + compoundNot = true + if (target.nodes.length !== 1) continue + if (target.nodes[0].type !== 'selector') continue + if (target.nodes[0].nodes.length !== 1) continue + if (target.nodes[0].nodes[0].type !== 'pseudo') continue + + targetNode = target.nodes[0].nodes[0] + } + + let newVariant = ((value) => { + // + if (value === ':first-letter') return 'first-letter' + else if (value === ':first-line') return 'first-line' + // + else if (value === ':file-selector-button') return 'file' + else if (value === ':placeholder') return 'placeholder' + else if (value === ':backdrop') return 'backdrop' + // Positional + else if (value === ':first-child') return 'first' + else if (value === ':last-child') return 'last' + else if (value === ':only-child') return 'only' + else if (value === ':first-of-type') return 'first-of-type' + else if (value === ':last-of-type') return 'last-of-type' + else if (value === ':only-of-type') return 'only-of-type' + // State + else if (value === ':visited') return 'visited' + else if (value === ':target') return 'target' + // Forms + else if (value === ':default') return 'default' + else if (value === ':checked') return 'checked' + else if (value === ':indeterminate') return 'indeterminate' + else if (value === ':placeholder-shown') return 'placeholder-shown' + else if (value === ':autofill') return 'autofill' + else if (value === ':optional') return 'optional' + else if (value === ':required') return 'required' + else if (value === ':valid') return 'valid' + else if (value === ':invalid') return 'invalid' + else if (value === ':in-range') return 'in-range' + else if (value === ':out-of-range') return 'out-of-range' + else if (value === ':read-only') return 'read-only' + // Content + else if (value === ':empty') return 'empty' + // Interactive + else if (value === ':focus-within') return 'focus-within' + else if (value === ':focus') return 'focus' + else if (value === ':focus-visible') return 'focus-visible' + else if (value === ':active') return 'active' + else if (value === ':enabled') return 'enabled' + else if (value === ':disabled') return 'disabled' + // + if ( + value === ':nth-child' && + targetNode.nodes.length === 1 && + targetNode.nodes[0].nodes.length === 1 && + targetNode.nodes[0].nodes[0].type === 'tag' && + targetNode.nodes[0].nodes[0].value === 'odd' + ) { + if (compoundNot) { + compoundNot = false + return 'even' + } + return 'odd' + } + if ( + value === ':nth-child' && + targetNode.nodes.length === 1 && + targetNode.nodes[0].nodes.length === 1 && + targetNode.nodes[0].nodes[0].type === 'tag' && + targetNode.nodes[0].nodes[0].value === 'even' + ) { + if (compoundNot) { + compoundNot = false + return 'odd' + } + return 'even' + } + + for (let [selector, variantName] of [ + [':nth-child', 'nth'], + [':nth-last-child', 'nth-last'], + [':nth-of-type', 'nth-of-type'], + [':nth-last-of-type', 'nth-of-last-type'], + ]) { + if (value === selector && targetNode.nodes.length === 1) { + if ( + targetNode.nodes[0].nodes.length === 1 && + targetNode.nodes[0].nodes[0].type === 'tag' && + isPositiveInteger(targetNode.nodes[0].nodes[0].value) + ) { + return `${variantName}-${targetNode.nodes[0].nodes[0].value}` + } + + return `${variantName}-[${targetNode.nodes[0].toString()}]` + } + } + + return null + })(targetNode.value) + + if (newVariant === null) continue + + // Add `not-` prefix + if (compoundNot) newVariant = `not-${newVariant}` + + let parsed = designSystem.parseVariant(newVariant) + if (parsed === null) continue + + // Update original variant + changed = true + memcpy(variant, parsed) + } + + // Expecting an attribute selector + else if (target.type === 'attribute') { + // Attribute selectors + let attributeKey = target.attribute + let attributeValue = target.value + ? target.quoted + ? `${target.quoteMark}${target.value}${target.quoteMark}` + : target.value + : null + + // Insensitive attribute selectors. E.g.: `[data-foo="value" i]` + // ^ + if (target.insensitive && attributeValue) { + attributeValue += ' i' + } + + let operator = target.operator ?? '=' + + // Migrate `data-*` + if (attributeKey.startsWith('data-')) { + changed = true + attributeKey = attributeKey.slice(5) // Remove `data-` + memcpy(variant, { + kind: 'functional', + root: 'data', + modifier: null, + value: + attributeValue === null + ? { kind: 'named', value: attributeKey } + : { kind: 'arbitrary', value: `${attributeKey}${operator}${attributeValue}` }, + } satisfies Variant) + } + + // Migrate `aria-*` + else if (attributeKey.startsWith('aria-')) { + changed = true + attributeKey = attributeKey.slice(5) // Remove `aria-` + memcpy(variant, { + kind: 'functional', + root: 'aria', + modifier: null, + value: + attributeValue === null + ? { kind: 'arbitrary', value: attributeKey } // aria-[foo] + : operator === '=' && target.value === 'true' && !target.insensitive + ? { kind: 'named', value: attributeKey } // aria-[foo="true"] or aria-[foo='true'] or aria-[foo=true] + : { kind: 'arbitrary', value: `${attributeKey}${operator}${attributeValue}` }, // aria-[foo~="true"], aria-[foo|="true"], … + } satisfies Variant) + } + } + + if (prefixedVariant) { + let idx = clone.variants.indexOf(variant) + if (idx === -1) continue + + // Ensure we inject the prefixed variant + clone.variants.splice(idx, 1, variant, prefixedVariant) + } + } + } + + return changed ? printCandidate(designSystem, clone) : rawCandidate + } + + return rawCandidate +} + +function* variants(candidate: Candidate) { + function* inner( + variant: Variant, + parent: Extract | null = null, + ): Iterable<[Variant, Extract | null]> { + yield [variant, parent] + + if (variant.kind === 'compound') { + yield* inner(variant.variant, variant) + } + } + + for (let variant of candidate.variants) { + yield* inner(variant, null) + } +} diff --git a/packages/@tailwindcss-upgrade/src/codemods/template/migrate-prefix.test.ts b/packages/@tailwindcss-upgrade/src/template/codemods/prefix.test.ts similarity index 75% rename from packages/@tailwindcss-upgrade/src/codemods/template/migrate-prefix.test.ts rename to packages/@tailwindcss-upgrade/src/template/codemods/prefix.test.ts index f47e181af..a7ad6a03e 100644 --- a/packages/@tailwindcss-upgrade/src/codemods/template/migrate-prefix.test.ts +++ b/packages/@tailwindcss-upgrade/src/template/codemods/prefix.test.ts @@ -1,8 +1,6 @@ import { __unstable__loadDesignSystem } from '@tailwindcss/node' -import { describe, expect, test, vi } from 'vitest' -import * as versions from '../../utils/version' -import { migratePrefix } from './migrate-prefix' -vi.spyOn(versions, 'isMajor').mockReturnValue(true) +import { describe, expect, test } from 'vitest' +import { prefix } from './prefix' describe('for projects with configured prefix', () => { test.each([ @@ -33,7 +31,7 @@ describe('for projects with configured prefix', () => { base: __dirname, }) - expect(migratePrefix(designSystem, { prefix: 'tw-' }, candidate)).toEqual(result) + expect(prefix(designSystem, { prefix: 'tw-' }, candidate)).toEqual(result) }) }) @@ -42,7 +40,7 @@ test('can handle complex prefix separators', async () => { base: __dirname, }) - expect(migratePrefix(designSystem, { prefix: 'tw__' }, 'tw__flex')).toEqual('tw:flex') + expect(prefix(designSystem, { prefix: 'tw__' }, 'tw__flex')).toEqual('tw:flex') }) describe('for projects without configured prefix', () => { @@ -51,6 +49,6 @@ describe('for projects without configured prefix', () => { base: __dirname, }) - expect(migratePrefix(designSystem, {}, 'tw-flex')).toEqual('tw-flex') + expect(prefix(designSystem, {}, 'tw-flex')).toEqual('tw-flex') }) }) diff --git a/packages/@tailwindcss-upgrade/src/codemods/template/migrate-prefix.ts b/packages/@tailwindcss-upgrade/src/template/codemods/prefix.ts similarity index 79% rename from packages/@tailwindcss-upgrade/src/codemods/template/migrate-prefix.ts rename to packages/@tailwindcss-upgrade/src/template/codemods/prefix.ts index 776032850..47a377239 100644 --- a/packages/@tailwindcss-upgrade/src/codemods/template/migrate-prefix.ts +++ b/packages/@tailwindcss-upgrade/src/template/codemods/prefix.ts @@ -1,34 +1,21 @@ -import { decl } from '../../../../tailwindcss/src/ast' import { parseCandidate, type Candidate } from '../../../../tailwindcss/src/candidate' import type { Config } from '../../../../tailwindcss/src/compat/plugin-api' import type { DesignSystem } from '../../../../tailwindcss/src/design-system' import { segment } from '../../../../tailwindcss/src/utils/segment' -import * as version from '../../utils/version' +import { printCandidate } from '../candidates' let seenDesignSystems = new WeakSet() -export function migratePrefix( +export function prefix( designSystem: DesignSystem, - userConfig: Config | null, + userConfig: Config, rawCandidate: string, ): string { if (!designSystem.theme.prefix) return rawCandidate - if (!userConfig) return rawCandidate - if (!version.isMajor(3)) return rawCandidate if (!seenDesignSystems.has(designSystem)) { - designSystem.utilities.functional('group', (value) => [ - // To ensure that `@apply group` works when computing a signature - decl('--phantom-class', 'group'), - // To ensure `group` and `group/foo` are considered different classes - decl('--phantom-modifier', value.modifier?.value), - ]) - designSystem.utilities.functional('peer', (value) => [ - // To ensure that `@apply peer` works when computing a signature - decl('--phantom-class', 'peer'), - // To ensure `peer` and `peer/foo` are considered different classes - decl('--phantom-modifier', value.modifier?.value), - ]) + designSystem.utilities.functional('group', () => null) + designSystem.utilities.functional('peer', () => null) seenDesignSystems.add(designSystem) } @@ -58,7 +45,7 @@ export function migratePrefix( if (!candidate) return rawCandidate - return designSystem.printCandidate(candidate) + return printCandidate(designSystem, candidate) } // Parses a raw candidate with v3 compatible prefix syntax. This won't match if @@ -128,7 +115,7 @@ function extractV3Base( } const VALID_PREFIX = /([a-z]+)/ -export function migratePrefixValue(prefix: string): string { +export function migratePrefix(prefix: string): string { let result = VALID_PREFIX.exec(prefix.toLocaleLowerCase()) if (!result) { console.warn( diff --git a/packages/@tailwindcss-upgrade/src/codemods/template/migrate-simple-legacy-classes.test.ts b/packages/@tailwindcss-upgrade/src/template/codemods/simple-legacy-classes.test.ts similarity index 73% rename from packages/@tailwindcss-upgrade/src/codemods/template/migrate-simple-legacy-classes.test.ts rename to packages/@tailwindcss-upgrade/src/template/codemods/simple-legacy-classes.test.ts index 456671dd7..a9da9e54e 100644 --- a/packages/@tailwindcss-upgrade/src/codemods/template/migrate-simple-legacy-classes.test.ts +++ b/packages/@tailwindcss-upgrade/src/template/codemods/simple-legacy-classes.test.ts @@ -1,8 +1,6 @@ import { __unstable__loadDesignSystem } from '@tailwindcss/node' -import { expect, test, vi } from 'vitest' -import * as versions from '../../utils/version' -import { migrateSimpleLegacyClasses } from './migrate-simple-legacy-classes' -vi.spyOn(versions, 'isMajor').mockReturnValue(true) +import { expect, test } from 'vitest' +import { simpleLegacyClasses } from './simple-legacy-classes' test.each([ ['overflow-ellipsis', 'text-ellipsis'], @@ -26,5 +24,5 @@ test.each([ base: __dirname, }) - expect(migrateSimpleLegacyClasses(designSystem, {}, candidate)).toEqual(result) + expect(simpleLegacyClasses(designSystem, {}, candidate)).toEqual(result) }) diff --git a/packages/@tailwindcss-upgrade/src/codemods/template/migrate-simple-legacy-classes.ts b/packages/@tailwindcss-upgrade/src/template/codemods/simple-legacy-classes.ts similarity index 56% rename from packages/@tailwindcss-upgrade/src/codemods/template/migrate-simple-legacy-classes.ts rename to packages/@tailwindcss-upgrade/src/template/codemods/simple-legacy-classes.ts index 415ed524c..1251d0f2d 100644 --- a/packages/@tailwindcss-upgrade/src/codemods/template/migrate-simple-legacy-classes.ts +++ b/packages/@tailwindcss-upgrade/src/template/codemods/simple-legacy-classes.ts @@ -1,10 +1,10 @@ import type { Config } from '../../../../tailwindcss/src/compat/plugin-api' import type { DesignSystem } from '../../../../tailwindcss/src/design-system' -import * as version from '../../utils/version' +import { printCandidate } from '../candidates' // Classes that used to exist in Tailwind CSS v3, but do not exist in Tailwind // CSS v4 anymore. -const LEGACY_CLASS_MAP: Record = { +const LEGACY_CLASS_MAP = { 'overflow-ellipsis': 'text-ellipsis', 'flex-grow': 'grow', @@ -15,33 +15,16 @@ const LEGACY_CLASS_MAP: Record = { 'decoration-clone': 'box-decoration-clone', 'decoration-slice': 'box-decoration-slice', - // Since v4.1.0 - 'bg-left-top': 'bg-top-left', - 'bg-left-bottom': 'bg-bottom-left', - 'bg-right-top': 'bg-top-right', - 'bg-right-bottom': 'bg-bottom-right', - 'object-left-top': 'object-top-left', - 'object-left-bottom': 'object-bottom-left', - 'object-right-top': 'object-top-right', - 'object-right-bottom': 'object-bottom-right', + 'outline-none': 'outline-hidden', } let seenDesignSystems = new WeakSet() -export function migrateSimpleLegacyClasses( +export function simpleLegacyClasses( designSystem: DesignSystem, - _userConfig: Config | null, + _userConfig: Config, rawCandidate: string, ): string { - // `outline-none` in v3 has the same meaning as `outline-hidden` in v4. However, - // `outline-none` in v4 _also_ exists but has a different meaning. - // - // We can only migrate `outline-none` to `outline-hidden` if we are migrating a - // v3 project to v4. - if (version.isMajor(3)) { - LEGACY_CLASS_MAP['outline-none'] = 'outline-hidden' - } - // Prepare design system with the unknown legacy classes if (!seenDesignSystems.has(designSystem)) { for (let old in LEGACY_CLASS_MAP) { @@ -52,7 +35,7 @@ export function migrateSimpleLegacyClasses( for (let candidate of designSystem.parseCandidate(rawCandidate)) { if (candidate.kind === 'static' && Object.hasOwn(LEGACY_CLASS_MAP, candidate.root)) { - return designSystem.printCandidate({ + return printCandidate(designSystem, { ...candidate, root: LEGACY_CLASS_MAP[candidate.root as keyof typeof LEGACY_CLASS_MAP], }) diff --git a/packages/@tailwindcss-upgrade/src/template/codemods/theme-to-var.test.ts b/packages/@tailwindcss-upgrade/src/template/codemods/theme-to-var.test.ts new file mode 100644 index 000000000..f5f2a41db --- /dev/null +++ b/packages/@tailwindcss-upgrade/src/template/codemods/theme-to-var.test.ts @@ -0,0 +1,191 @@ +import { __unstable__loadDesignSystem } from '@tailwindcss/node' +import { expect, test } from 'vitest' +import { themeToVar } from './theme-to-var' + +let css = String.raw + +test.each([ + // Keep candidates that don't contain `theme(…)` or `theme(…, …)` + ['[color:red]', '[color:red]'], + + // Handle special cases around `.1` in the `theme(…)` + ['[--value:theme(spacing.1)]', '[--value:calc(var(--spacing)*1)]'], + ['[--value:theme(fontSize.xs.1.lineHeight)]', '[--value:var(--text-xs--line-height)]'], + ['[--value:theme(spacing[1.25])]', '[--value:calc(var(--spacing)*1.25)]'], + + // Should not convert invalid spacing values to calc + ['[--value:theme(spacing[1.1])]', '[--value:theme(spacing[1.1])]'], + + // Convert to `var(…)` if we can resolve the path + ['[color:theme(colors.red.500)]', '[color:var(--color-red-500)]'], // Arbitrary property + ['[color:theme(colors.red.500)]/50', '[color:var(--color-red-500)]/50'], // Arbitrary property + modifier + ['bg-[theme(colors.red.500)]', 'bg-(--color-red-500)'], // Arbitrary value + ['bg-[size:theme(spacing.4)]', 'bg-[size:calc(var(--spacing)*4)]'], // Arbitrary value + data type hint + + // Convert to `var(…)` if we can resolve the path, but keep fallback values + ['bg-[theme(colors.red.500,red)]', 'bg-(--color-red-500,red)'], + + // Keep `theme(…)` if we can't resolve the path + ['bg-[theme(colors.foo.1000)]', 'bg-[theme(colors.foo.1000)]'], + + // Keep `theme(…)` if we can't resolve the path, but still try to convert the + // fallback value. + [ + 'bg-[theme(colors.foo.1000,theme(colors.red.500))]', + 'bg-[theme(colors.foo.1000,var(--color-red-500))]', + ], + + // Use `theme(…)` (deeply nested) inside of a `calc(…)` function + ['text-[calc(theme(fontSize.xs)*2)]', 'text-[calc(var(--text-xs)*2)]'], + + // Multiple `theme(… / …)` calls should result in modern syntax of `theme(…)` + // - Can't convert to `var(…)` because that would lose the modifier. + // - Can't convert to a candidate modifier because there are multiple + // `theme(…)` calls. + // + // If we really want to, we can make a fancy migration that tries to move it + // to a candidate modifier _if_ all `theme(…)` calls use the same modifier. + [ + '[color:theme(colors.red.500/50,theme(colors.blue.500/50))]', + '[color:theme(--color-red-500/50,theme(--color-blue-500/50))]', + ], + [ + '[color:theme(colors.red.500/50,theme(colors.blue.500/50))]/50', + '[color:theme(--color-red-500/50,theme(--color-blue-500/50))]/50', + ], + + // Convert the `theme(…)`, but try to move the inline modifier (e.g. `50%`), + // to a candidate modifier. + // Arbitrary property, with simple percentage modifier + ['[color:theme(colors.red.500/75%)]', '[color:var(--color-red-500)]/75'], + + // Arbitrary property, with numbers (0-1) without a unit + ['[color:theme(colors.red.500/.12)]', '[color:var(--color-red-500)]/12'], + ['[color:theme(colors.red.500/0.12)]', '[color:var(--color-red-500)]/12'], + + // Arbitrary property, with more complex modifier (we only allow whole numbers + // as bare modifiers). Convert the complex numbers to arbitrary values instead. + ['[color:theme(colors.red.500/12.34%)]', '[color:var(--color-red-500)]/[12.34%]'], + ['[color:theme(colors.red.500/var(--opacity))]', '[color:var(--color-red-500)]/(--opacity)'], + ['[color:theme(colors.red.500/.12345)]', '[color:var(--color-red-500)]/[12.345]'], + ['[color:theme(colors.red.500/50.25%)]', '[color:var(--color-red-500)]/[50.25%]'], + + // Arbitrary value + ['bg-[theme(colors.red.500/75%)]', 'bg-(--color-red-500)/75'], + ['bg-[theme(colors.red.500/12.34%)]', 'bg-(--color-red-500)/[12.34%]'], + + // Arbitrary property that already contains a modifier + ['[color:theme(colors.red.500/50%)]/50', '[color:theme(--color-red-500/50%)]/50'], + + // Values that don't contain only `theme(…)` calls should not be converted to + // use a modifier since the color is not the whole value. + [ + 'shadow-[shadow:inset_0px_1px_theme(colors.white/15%)]', + 'shadow-[shadow:inset_0px_1px_theme(--color-white/15%)]', + ], + + // Arbitrary value, where the candidate already contains a modifier + // This should still migrate the `theme(…)` syntax to the modern syntax. + ['bg-[theme(colors.red.500/50%)]/50', 'bg-[theme(--color-red-500/50%)]/50'], + + // Variants, we can't use `var(…)` especially inside of `@media(…)`. We can + // still upgrade the `theme(…)` to the modern syntax. + ['max-[theme(screens.lg)]:flex', 'max-[theme(--breakpoint-lg)]:flex'], + // There are no variables for `--spacing` multiples, so we can't convert this + ['max-[theme(spacing.4)]:flex', 'max-[theme(spacing.4)]:flex'], + + // This test in itself doesn't make much sense. But we need to make sure + // that this doesn't end up as the modifier in the candidate itself. + ['max-[theme(spacing.4/50)]:flex', 'max-[theme(spacing.4/50)]:flex'], + + // `theme(…)` calls in another CSS function is replaced correctly. + // Additionally we remove unnecessary whitespace. + [ + 'grid-cols-[min(50%_,_theme(spacing.80))_auto]', + 'grid-cols-[min(50%,calc(var(--spacing)*80))_auto]', + ], + + // `theme(…)` calls valid in v3, but not in v4 should still be converted. + ['[--foo:theme(transitionDuration.500)]', '[--foo:theme(transitionDuration.500)]'], + + // Renamed theme keys + ['max-w-[theme(screens.md)]', 'max-w-(--breakpoint-md)'], + ['w-[theme(maxWidth.md)]', 'w-(--container-md)'], + + // Invalid cases + ['[--foo:theme(colors.red.500/50/50)]', '[--foo:theme(colors.red.500/50/50)]'], + ['[--foo:theme(colors.red.500/50/50)]/50', '[--foo:theme(colors.red.500/50/50)]/50'], + + // Partially invalid cases + [ + '[--foo:theme(colors.red.500/50/50)_theme(colors.blue.200)]', + '[--foo:theme(colors.red.500/50/50)_var(--color-blue-200)]', + ], + [ + '[--foo:theme(colors.red.500/50/50)_theme(colors.blue.200)]/50', + '[--foo:theme(colors.red.500/50/50)_var(--color-blue-200)]/50', + ], +])('%s => %s', async (candidate, result) => { + let designSystem = await __unstable__loadDesignSystem( + css` + @import 'tailwindcss'; + `, + { + base: __dirname, + }, + ) + + expect(themeToVar(designSystem, {}, candidate)).toEqual(result) +}) + +test('extended space scale converts to var or calc', async () => { + let designSystem = await __unstable__loadDesignSystem( + css` + @import 'tailwindcss'; + @theme { + --spacing-2: 2px; + --spacing-miami: 0.875rem; + } + `, + { + base: __dirname, + }, + ) + expect(themeToVar(designSystem, {}, '[--value:theme(spacing.1)]')).toEqual( + '[--value:calc(var(--spacing)*1)]', + ) + expect(themeToVar(designSystem, {}, '[--value:theme(spacing.2)]')).toEqual( + '[--value:var(--spacing-2)]', + ) + expect(themeToVar(designSystem, {}, '[--value:theme(spacing.miami)]')).toEqual( + '[--value:var(--spacing-miami)]', + ) + expect(themeToVar(designSystem, {}, '[--value:theme(spacing.nyc)]')).toEqual( + '[--value:theme(spacing.nyc)]', + ) +}) + +test('custom space scale converts to var', async () => { + let designSystem = await __unstable__loadDesignSystem( + css` + @import 'tailwindcss'; + @theme { + --spacing-*: initial; + --spacing-1: 0.25rem; + --spacing-2: 0.5rem; + } + `, + { + base: __dirname, + }, + ) + expect(themeToVar(designSystem, {}, '[--value:theme(spacing.1)]')).toEqual( + '[--value:var(--spacing-1)]', + ) + expect(themeToVar(designSystem, {}, '[--value:theme(spacing.2)]')).toEqual( + '[--value:var(--spacing-2)]', + ) + expect(themeToVar(designSystem, {}, '[--value:theme(spacing.3)]')).toEqual( + '[--value:theme(spacing.3)]', + ) +}) diff --git a/packages/@tailwindcss-upgrade/src/codemods/template/migrate-theme-to-var.ts b/packages/@tailwindcss-upgrade/src/template/codemods/theme-to-var.ts similarity index 70% rename from packages/@tailwindcss-upgrade/src/codemods/template/migrate-theme-to-var.ts rename to packages/@tailwindcss-upgrade/src/template/codemods/theme-to-var.ts index e566e7d6e..b83e5add1 100644 --- a/packages/@tailwindcss-upgrade/src/codemods/template/migrate-theme-to-var.ts +++ b/packages/@tailwindcss-upgrade/src/template/codemods/theme-to-var.ts @@ -1,11 +1,17 @@ -import { type CandidateModifier } from '../../../../tailwindcss/src/candidate' +import { + parseCandidate, + type Candidate, + type CandidateModifier, + type Variant, +} from '../../../../tailwindcss/src/candidate' import { keyPathToCssProperty } from '../../../../tailwindcss/src/compat/apply-config-to-theme' +import type { Config } from '../../../../tailwindcss/src/compat/plugin-api' import type { DesignSystem } from '../../../../tailwindcss/src/design-system' import { isValidSpacingMultiplier } from '../../../../tailwindcss/src/utils/infer-data-type' import { segment } from '../../../../tailwindcss/src/utils/segment' import { toKeyPath } from '../../../../tailwindcss/src/utils/to-key-path' import * as ValueParser from '../../../../tailwindcss/src/value-parser' -import { walk, WalkAction } from '../../../../tailwindcss/src/walk' +import { printCandidate } from '../candidates' export const enum Convert { All = 0, @@ -13,6 +19,68 @@ export const enum Convert { MigrateThemeOnly = 1 << 1, } +export function themeToVar( + designSystem: DesignSystem, + _userConfig: Config, + rawCandidate: string, +): string { + let convert = createConverter(designSystem) + + for (let candidate of parseCandidate(rawCandidate, designSystem)) { + let clone = structuredClone(candidate) + let changed = false + + if (clone.kind === 'arbitrary') { + let [newValue, modifier] = convert( + clone.value, + clone.modifier === null ? Convert.MigrateModifier : Convert.All, + ) + if (newValue !== clone.value) { + changed = true + clone.value = newValue + + if (modifier !== null) { + clone.modifier = modifier + } + } + } else if (clone.kind === 'functional' && clone.value?.kind === 'arbitrary') { + let [newValue, modifier] = convert( + clone.value.value, + clone.modifier === null ? Convert.MigrateModifier : Convert.All, + ) + if (newValue !== clone.value.value) { + changed = true + clone.value.value = newValue + + if (modifier !== null) { + clone.modifier = modifier + } + } + } + + // Handle variants + for (let variant of variants(clone)) { + if (variant.kind === 'arbitrary') { + let [newValue] = convert(variant.selector, Convert.MigrateThemeOnly) + if (newValue !== variant.selector) { + changed = true + variant.selector = newValue + } + } else if (variant.kind === 'functional' && variant.value?.kind === 'arbitrary') { + let [newValue] = convert(variant.value.value, Convert.MigrateThemeOnly) + if (newValue !== variant.value.value) { + changed = true + variant.value.value = newValue + } + } + } + + return changed ? printCandidate(designSystem, clone) : rawCandidate + } + + return rawCandidate +} + export function createConverter(designSystem: DesignSystem, { prettyPrint = false } = {}) { function convert(input: string, options = Convert.All): [string, CandidateModifier | null] { let ast = ValueParser.parse(input) @@ -28,7 +96,7 @@ export function createConverter(designSystem: DesignSystem, { prettyPrint = fals let themeModifierCount = 0 // Analyze AST - walk(ast, (node) => { + ValueParser.walk(ast, (node) => { if (node.kind !== 'function') return if (node.value !== 'theme') return @@ -36,19 +104,19 @@ export function createConverter(designSystem: DesignSystem, { prettyPrint = fals themeUsageCount += 1 // Figure out if a modifier is used - walk(node.nodes, (child) => { + ValueParser.walk(node.nodes, (child) => { // If we see a `,`, it means that we have a fallback value if (child.kind === 'separator' && child.value.includes(',')) { - return WalkAction.Stop + return ValueParser.ValueWalkAction.Stop } // If we see a `/`, we have a modifier - else if (child.kind === 'word' && child.value === '/') { + else if (child.kind === 'separator' && child.value.trim() === '/') { themeModifierCount += 1 - return WalkAction.Stop + return ValueParser.ValueWalkAction.Stop } - return WalkAction.Skip + return ValueParser.ValueWalkAction.Skip }) }) @@ -80,7 +148,9 @@ export function createConverter(designSystem: DesignSystem, { prettyPrint = fals let parts = segment(path, '/').map((part) => part.trim()) // Multiple `/` separators, which makes this an invalid path - if (parts.length > 2) return null + if (parts.length > 2) { + return null + } // The path contains a `/`, which means that there is a modifier such as // `theme(colors.red.500/50%)`. @@ -130,10 +200,6 @@ export function createConverter(designSystem: DesignSystem, { prettyPrint = fals let variable = `--${keyPathToCssProperty(toKeyPath(path))}` as const if (!designSystem.theme.get([variable])) return null - if (designSystem.theme.prefix) { - return `--${designSystem.theme.prefix}-${variable.slice(2)}` - } - return variable } @@ -146,7 +212,7 @@ export function createConverter(designSystem: DesignSystem, { prettyPrint = fals let multiplier = keyPath[1] if (!isValidSpacingMultiplier(multiplier)) return null - return `--spacing(${multiplier})` + return 'calc(var(--spacing) * ' + multiplier + ')' } return null @@ -161,9 +227,7 @@ export function createConverter(designSystem: DesignSystem, { prettyPrint = fals let modifier = parts.length > 0 ? (prettyPrint ? ` / ${parts.join(' / ')}` : `/${parts.join('/')}`) : '' - return fallback - ? `--theme(${variable}${modifier}, ${fallback})` - : `--theme(${variable}${modifier})` + return fallback ? `theme(${variable}${modifier}, ${fallback})` : `theme(${variable}${modifier})` } return convert @@ -173,7 +237,7 @@ function substituteFunctionsInValue( ast: ValueParser.ValueAstNode[], handle: (value: string, fallback?: string) => string | null, ) { - walk(ast, (node, ctx) => { + ValueParser.walk(ast, (node, { replaceWith }) => { if (node.kind === 'function' && node.value === 'theme') { if (node.nodes.length < 1) return @@ -211,38 +275,7 @@ function substituteFunctionsInValue( fallbackValues.length > 0 ? handle(path, ValueParser.toCss(fallbackValues)) : handle(path) if (replacement === null) return - { - let idx = ctx.index - 1 - while (idx !== -1) { - let previous = ctx.siblings[idx] - // Skip the space separator - if (previous.kind === 'separator' && previous.value.trim() === '') { - idx -= 1 - continue - } - - // If the previous node is a word and contains an operator, we need to - // wrap the replacement in parentheses to make the output less - // ambiguous. - // - // Input: - // - `calc(100dvh-theme(spacing.2))` - // - // Output: - // - `calc(100dvh-(--spacing(2)))` - // - // Not: - // -`calc(100dvh---spacing(2))` - // - if (/^[-+*/]$/.test(previous.value.trim())) { - replacement = `(${replacement})` - } - - break - } - } - - return WalkAction.Replace(ValueParser.parse(replacement)) + replaceWith(ValueParser.parse(replacement)) } }) @@ -268,3 +301,16 @@ function eventuallyUnquote(value: string) { return unquoted } + +function* variants(candidate: Candidate) { + function* inner(variant: Variant): Iterable { + yield variant + if (variant.kind === 'compound') { + yield* inner(variant.variant) + } + } + + for (let variant of candidate.variants) { + yield* inner(variant) + } +} diff --git a/packages/@tailwindcss-upgrade/src/codemods/template/migrate-variant-order.test.ts b/packages/@tailwindcss-upgrade/src/template/codemods/variant-order.test.ts similarity index 84% rename from packages/@tailwindcss-upgrade/src/codemods/template/migrate-variant-order.test.ts rename to packages/@tailwindcss-upgrade/src/template/codemods/variant-order.test.ts index 1b14d533f..e42595645 100644 --- a/packages/@tailwindcss-upgrade/src/codemods/template/migrate-variant-order.test.ts +++ b/packages/@tailwindcss-upgrade/src/template/codemods/variant-order.test.ts @@ -1,9 +1,7 @@ import { __unstable__loadDesignSystem } from '@tailwindcss/node' import dedent from 'dedent' -import { expect, test, vi } from 'vitest' -import * as versions from '../../utils/version' -import { migrateVariantOrder } from './migrate-variant-order' -vi.spyOn(versions, 'isMajor').mockReturnValue(true) +import { expect, test } from 'vitest' +import { variantOrder } from './variant-order' let css = dedent @@ -55,26 +53,26 @@ test.each([ base: __dirname, }) - expect(migrateVariantOrder(designSystem, {}, candidate)).toEqual(result) + expect(variantOrder(designSystem, {}, candidate)).toEqual(result) }) test('it works with custom variants', async () => { let designSystem = await __unstable__loadDesignSystem( css` @import 'tailwindcss'; - @custom-variant atrule { + @variant atrule { @media (print) { @slot; } } - @custom-variant combinator { + @variant combinator { > * { @slot; } } - @custom-variant pseudo { + @variant pseudo { &::before { @slot; } @@ -85,7 +83,7 @@ test('it works with custom variants', async () => { }, ) - expect(migrateVariantOrder(designSystem, {}, 'combinator:pseudo:atrule:underline')).toEqual( + expect(variantOrder(designSystem, {}, 'combinator:pseudo:atrule:underline')).toEqual( 'atrule:combinator:pseudo:underline', ) }) diff --git a/packages/@tailwindcss-upgrade/src/codemods/template/migrate-variant-order.ts b/packages/@tailwindcss-upgrade/src/template/codemods/variant-order.ts similarity index 85% rename from packages/@tailwindcss-upgrade/src/codemods/template/migrate-variant-order.ts rename to packages/@tailwindcss-upgrade/src/template/codemods/variant-order.ts index 3fd84af7c..07c7015ab 100644 --- a/packages/@tailwindcss-upgrade/src/codemods/template/migrate-variant-order.ts +++ b/packages/@tailwindcss-upgrade/src/template/codemods/variant-order.ts @@ -1,24 +1,14 @@ -import { type AstNode } from '../../../../tailwindcss/src/ast' +import { walk, type AstNode } from '../../../../tailwindcss/src/ast' import { type Variant } from '../../../../tailwindcss/src/candidate' import type { Config } from '../../../../tailwindcss/src/compat/plugin-api' import type { DesignSystem } from '../../../../tailwindcss/src/design-system' -import { walk } from '../../../../tailwindcss/src/walk' -import * as version from '../../utils/version' +import { printCandidate } from '../candidates' -export function migrateVariantOrder( +export function variantOrder( designSystem: DesignSystem, - _userConfig: Config | null, + _userConfig: Config, rawCandidate: string, ): string { - // This migration is only needed for Tailwind CSS v3 - // - // Changing the variant order when migrating from v3 to v4 is fine, but - // migrating v4 to v4 would make it unsafe because the variant order would - // flip-flop every time you run the migration. - if (!version.isMajor(3)) { - return rawCandidate - } - for (let candidate of designSystem.parseCandidate(rawCandidate)) { if (candidate.variants.length <= 1) { continue @@ -56,7 +46,7 @@ export function migrateVariantOrder( continue } - return designSystem.printCandidate({ ...candidate, variants: newOrder }) + return printCandidate(designSystem, { ...candidate, variants: newOrder }) } return rawCandidate } diff --git a/packages/@tailwindcss-upgrade/src/template/is-safe-migration.ts b/packages/@tailwindcss-upgrade/src/template/is-safe-migration.ts new file mode 100644 index 000000000..046ee10e6 --- /dev/null +++ b/packages/@tailwindcss-upgrade/src/template/is-safe-migration.ts @@ -0,0 +1,62 @@ +const QUOTES = ['"', "'", '`'] +const LOGICAL_OPERATORS = ['&&', '||', '?', '===', '==', '!=', '!==', '>', '>=', '<', '<='] +const CONDITIONAL_TEMPLATE_SYNTAX = [ + // Vue + /v-else-if=['"]$/, + /v-if=['"]$/, + /v-show=['"]$/, + + // Alpine + /x-if=['"]$/, + /x-show=['"]$/, +] + +export function isSafeMigration(location: { contents: string; start: number; end: number }) { + let currentLineBeforeCandidate = '' + for (let i = location.start - 1; i >= 0; i--) { + let char = location.contents.at(i)! + if (char === '\n') { + break + } + currentLineBeforeCandidate = char + currentLineBeforeCandidate + } + let currentLineAfterCandidate = '' + for (let i = location.end; i < location.contents.length; i++) { + let char = location.contents.at(i)! + if (char === '\n') { + break + } + currentLineAfterCandidate += char + } + + // Heuristic 1: Require the candidate to be inside quotes + let isQuoteBeforeCandidate = QUOTES.some((quote) => currentLineBeforeCandidate.includes(quote)) + let isQuoteAfterCandidate = QUOTES.some((quote) => currentLineAfterCandidate.includes(quote)) + if (!isQuoteBeforeCandidate || !isQuoteAfterCandidate) { + return false + } + + // Heuristic 2: Disallow object access immediately following the candidate + if (currentLineAfterCandidate[0] === '.') { + return false + } + + // Heuristic 3: Disallow logical operators preceding or following the candidate + for (let operator of LOGICAL_OPERATORS) { + if ( + currentLineAfterCandidate.trim().startsWith(operator) || + currentLineBeforeCandidate.trim().endsWith(operator) + ) { + return false + } + } + + // Heuristic 4: Disallow conditional template syntax + for (let rule of CONDITIONAL_TEMPLATE_SYNTAX) { + if (rule.test(currentLineBeforeCandidate)) { + return false + } + } + + return true +} diff --git a/packages/@tailwindcss-upgrade/src/template/migrate.ts b/packages/@tailwindcss-upgrade/src/template/migrate.ts new file mode 100644 index 000000000..7fdc164f2 --- /dev/null +++ b/packages/@tailwindcss-upgrade/src/template/migrate.ts @@ -0,0 +1,104 @@ +import fs from 'node:fs/promises' +import path, { extname } from 'node:path' +import type { Config } from '../../../tailwindcss/src/compat/plugin-api' +import type { DesignSystem } from '../../../tailwindcss/src/design-system' +import { extractRawCandidates } from './candidates' +import { arbitraryValueToBareValue } from './codemods/arbitrary-value-to-bare-value' +import { automaticVarInjection } from './codemods/automatic-var-injection' +import { bgGradient } from './codemods/bg-gradient' +import { handleEmptyArbitraryValues } from './codemods/handle-empty-arbitrary-values' +import { important } from './codemods/important' +import { legacyArbitraryValues } from './codemods/legacy-arbitrary-values' +import { legacyClasses } from './codemods/legacy-classes' +import { maxWidthScreen } from './codemods/max-width-screen' +import { modernizeArbitraryValues } from './codemods/modernize-arbitrary-values' +import { prefix } from './codemods/prefix' +import { simpleLegacyClasses } from './codemods/simple-legacy-classes' +import { themeToVar } from './codemods/theme-to-var' +import { variantOrder } from './codemods/variant-order' +import { spliceChangesIntoString, type StringChange } from './splice-changes-into-string' + +export type Migration = ( + designSystem: DesignSystem, + userConfig: Config, + rawCandidate: string, + location?: { + contents: string + start: number + end: number + }, +) => string | Promise + +export const DEFAULT_MIGRATIONS: Migration[] = [ + handleEmptyArbitraryValues, + prefix, + important, + bgGradient, + simpleLegacyClasses, + legacyClasses, + maxWidthScreen, + themeToVar, + variantOrder, // Has to happen before migrations that modify variants + automaticVarInjection, + legacyArbitraryValues, + arbitraryValueToBareValue, + modernizeArbitraryValues, +] + +export async function migrateCandidate( + designSystem: DesignSystem, + userConfig: Config, + rawCandidate: string, + // Location is only set when migrating a candidate from a source file + location?: { + contents: string + start: number + end: number + }, +): Promise { + for (let migration of DEFAULT_MIGRATIONS) { + rawCandidate = await migration(designSystem, userConfig, rawCandidate, location) + } + return rawCandidate +} + +export default async function migrateContents( + designSystem: DesignSystem, + userConfig: Config, + contents: string, + extension: string, +): Promise { + let candidates = await extractRawCandidates(contents, extension) + + let changes: StringChange[] = [] + + for (let { rawCandidate, start, end } of candidates) { + let migratedCandidate = await migrateCandidate(designSystem, userConfig, rawCandidate, { + contents, + start, + end, + }) + + if (migratedCandidate === rawCandidate) { + continue + } + + changes.push({ + start, + end, + replacement: migratedCandidate, + }) + } + + return spliceChangesIntoString(contents, changes) +} + +export async function migrate(designSystem: DesignSystem, userConfig: Config, file: string) { + let fullPath = path.isAbsolute(file) ? file : path.resolve(process.cwd(), file) + let contents = await fs.readFile(fullPath, 'utf-8') + + await fs.writeFile( + fullPath, + await migrateContents(designSystem, userConfig, contents, extname(file)), + ) +} diff --git a/packages/@tailwindcss-upgrade/src/codemods/template/prepare-config.ts b/packages/@tailwindcss-upgrade/src/template/prepare-config.ts similarity index 83% rename from packages/@tailwindcss-upgrade/src/codemods/template/prepare-config.ts rename to packages/@tailwindcss-upgrade/src/template/prepare-config.ts index d9fae442b..f5a817d40 100644 --- a/packages/@tailwindcss-upgrade/src/codemods/template/prepare-config.ts +++ b/packages/@tailwindcss-upgrade/src/template/prepare-config.ts @@ -2,12 +2,12 @@ import { __unstable__loadDesignSystem, compile } from '@tailwindcss/node' import fs from 'node:fs/promises' import path, { dirname } from 'node:path' import { fileURLToPath } from 'node:url' -import { loadModule } from '../../../../@tailwindcss-node/src/compile' -import { resolveConfig } from '../../../../tailwindcss/src/compat/config/resolve-config' -import type { Config } from '../../../../tailwindcss/src/compat/plugin-api' -import type { DesignSystem } from '../../../../tailwindcss/src/design-system' -import { error, highlight, relative } from '../../utils/renderer' -import { migratePrefixValue } from './migrate-prefix' +import { loadModule } from '../../../@tailwindcss-node/src/compile' +import { resolveConfig } from '../../../tailwindcss/src/compat/config/resolve-config' +import type { Config } from '../../../tailwindcss/src/compat/plugin-api' +import type { DesignSystem } from '../../../tailwindcss/src/design-system' +import { error, highlight, relative } from '../utils/renderer' +import { migratePrefix } from './codemods/prefix' const __filename = fileURLToPath(import.meta.url) const __dirname = dirname(__filename) @@ -19,7 +19,7 @@ export async function prepareConfig( options: { base: string }, ): Promise<{ designSystem: DesignSystem - sources: { base: string; pattern: string }[] + globs: { base: string; pattern: string }[] userConfig: Config configFilePath: string @@ -40,16 +40,16 @@ export async function prepareConfig( // If the path points to a file in the same directory, `path.relative` will // remove the leading `./` and we need to add it back in order to still // consider the path relative - if (!relative.startsWith('.') && !path.isAbsolute(relative)) { + if (!relative.startsWith('.')) { relative = './' + relative } let userConfig = await createResolvedUserConfig(configFilePath) - let newPrefix = userConfig.prefix ? migratePrefixValue(userConfig.prefix) : null + let newPrefix = userConfig.prefix ? migratePrefix(userConfig.prefix) : null let input = css` @import 'tailwindcss' ${newPrefix ? `prefix(${newPrefix})` : ''}; - @config '${relative}'; + @config './${relative}'; ` let [compiler, designSystem] = await Promise.all([ @@ -59,7 +59,7 @@ export async function prepareConfig( return { designSystem, - sources: compiler.sources, + globs: compiler.globs, userConfig, newPrefix, configFilePath, @@ -82,7 +82,7 @@ async function createResolvedUserConfig(fullConfigPath: string): Promise ]) return resolveConfig(noopDesignSystem, [ - { base: dirname(fullConfigPath), config: unresolvedUserConfig, reference: false }, + { base: dirname(fullConfigPath), config: unresolvedUserConfig }, ]).resolvedConfig as any } diff --git a/packages/@tailwindcss-upgrade/src/utils/splice-changes-into-string.ts b/packages/@tailwindcss-upgrade/src/template/splice-changes-into-string.ts similarity index 100% rename from packages/@tailwindcss-upgrade/src/utils/splice-changes-into-string.ts rename to packages/@tailwindcss-upgrade/src/template/splice-changes-into-string.ts diff --git a/packages/@tailwindcss-upgrade/src/utils/git.ts b/packages/@tailwindcss-upgrade/src/utils/git.ts index 38edf21cb..d716fbb8a 100644 --- a/packages/@tailwindcss-upgrade/src/utils/git.ts +++ b/packages/@tailwindcss-upgrade/src/utils/git.ts @@ -1,20 +1,8 @@ import { execSync } from 'node:child_process' -export function gitRoot(cwd?: string): string | null { +export function isRepoDirty() { try { - return execSync('git rev-parse --show-toplevel', { - encoding: 'utf-8', - cwd, - stdio: ['ignore', 'pipe', 'ignore'], - }).trim() - } catch { - return null - } -} - -export function isRepoDirty(cwd?: string) { - try { - let stdout = execSync('git status --porcelain', { encoding: 'utf-8', cwd }) + let stdout = execSync('git status --porcelain', { encoding: 'utf-8' }) return stdout.trim() !== '' } catch (error) { // If it's not a git repository we don't know if it's dirty or not. But we diff --git a/packages/@tailwindcss-upgrade/src/utils/hoist-static-glob-parts.test.ts b/packages/@tailwindcss-upgrade/src/utils/hoist-static-glob-parts.test.ts new file mode 100644 index 000000000..1e6d8b1e8 --- /dev/null +++ b/packages/@tailwindcss-upgrade/src/utils/hoist-static-glob-parts.test.ts @@ -0,0 +1,48 @@ +import { expect, it } from 'vitest' +import { hoistStaticGlobParts } from './hoist-static-glob-parts' + +it.each([ + // A basic glob + [ + { base: '/projects/project-a', pattern: './src/**/*.html' }, + [{ base: '/projects/project-a/src', pattern: '**/*.html' }], + ], + + // A glob pointing to a folder should result in `**/*` + [ + { base: '/projects/project-a', pattern: './src' }, + [{ base: '/projects/project-a/src', pattern: '**/*' }], + ], + + // A glob pointing to a file, should result in the file as the pattern + [ + { base: '/projects/project-a', pattern: './src/index.html' }, + [{ base: '/projects/project-a/src', pattern: 'index.html' }], + ], + + // A glob going up a directory, should result in the new directory as the base + [ + { base: '/projects/project-a', pattern: '../project-b/src/**/*.html' }, + [{ base: '/projects/project-b/src', pattern: '**/*.html' }], + ], + + // A glob with curlies, should be expanded to multiple globs + [ + { base: '/projects/project-a', pattern: '../project-{b,c}/src/**/*.html' }, + [ + { base: '/projects/project-b/src', pattern: '**/*.html' }, + { base: '/projects/project-c/src', pattern: '**/*.html' }, + ], + ], + [ + { base: '/projects/project-a', pattern: '../project-{b,c}/src/**/*.{js,html}' }, + [ + { base: '/projects/project-b/src', pattern: '**/*.js' }, + { base: '/projects/project-b/src', pattern: '**/*.html' }, + { base: '/projects/project-c/src', pattern: '**/*.js' }, + { base: '/projects/project-c/src', pattern: '**/*.html' }, + ], + ], +])('should hoist the static parts of the glob: %s', (input, output) => { + expect(hoistStaticGlobParts(input)).toEqual(output) +}) diff --git a/packages/@tailwindcss-upgrade/src/utils/hoist-static-glob-parts.ts b/packages/@tailwindcss-upgrade/src/utils/hoist-static-glob-parts.ts new file mode 100644 index 000000000..18d587998 --- /dev/null +++ b/packages/@tailwindcss-upgrade/src/utils/hoist-static-glob-parts.ts @@ -0,0 +1,82 @@ +import { normalizePath } from '@tailwindcss/node' +import braces from 'braces' +import path from 'node:path' + +interface GlobEntry { + base: string + pattern: string +} + +export function hoistStaticGlobParts(entry: GlobEntry): GlobEntry[] { + return braces(entry.pattern, { expand: true }).map((pattern) => { + let clone = { ...entry } + let [staticPart, dynamicPart] = splitPattern(pattern) + + // Move static part into the `base`. + let absolutePosixPath = normalizePath(entry.base) + + if (staticPart !== null) { + clone.base = path.posix.join(absolutePosixPath, staticPart) + } else { + clone.base = absolutePosixPath + } + + // Move dynamic part into the `pattern`. + if (dynamicPart === null) { + clone.pattern = '**/*' + } else { + clone.pattern = dynamicPart + } + + // If the pattern looks like a file, move the file name from the `base` to + // the `pattern`. + let file = path.basename(clone.base) + if (file.includes('.')) { + clone.pattern = file + clone.base = path.dirname(clone.base) + } + + return clone + }) +} + +// Split a glob pattern into a `static` and `dynamic` part. +// +// Assumption: we assume that all globs are expanded, which means that the only +// dynamic parts are using `*`. +// +// E.g.: +// Original input: `../project-b/**/*.{html,js}` +// Expanded input: `../project-b/**/*.html` & `../project-b/**/*.js` +// Split on first input: ("../project-b", "**/*.html") +// Split on second input: ("../project-b", "**/*.js") +function splitPattern(pattern: string): [staticPart: string | null, dynamicPart: string | null] { + // No dynamic parts, so we can just return the input as-is. + if (!pattern.includes('*')) { + return [pattern, null] + } + + let lastSlashPosition: number | null = null + + for (let i = 0; i < pattern.length; i++) { + let c = pattern[i] + if (c === '/') { + lastSlashPosition = i + } + + if (c === '*' || c === '!') { + break + } + } + + // Very first character is a `*`, therefore there is no static part, only a + // dynamic part. + if (lastSlashPosition === null) { + return [null, pattern] + } + + let staticPart = pattern.slice(0, lastSlashPosition).trim() + let dynamicPart = pattern.slice(lastSlashPosition + 1).trim() + + return [staticPart || null, dynamicPart || null] +} diff --git a/packages/@tailwindcss-upgrade/src/utils/package-version.ts b/packages/@tailwindcss-upgrade/src/utils/package-version.ts index 64a1e7ed1..833ccadf2 100644 --- a/packages/@tailwindcss-upgrade/src/utils/package-version.ts +++ b/packages/@tailwindcss-upgrade/src/utils/package-version.ts @@ -1,4 +1,3 @@ -import { readFileSync } from 'node:fs' import fs from 'node:fs/promises' import { resolveJsId } from './resolve' @@ -16,14 +15,3 @@ export async function getPackageVersion(pkg: string, base: string): Promise = { bun: '-d', } -const manifests = new DefaultMap((base) => { - try { - let packageJsonPath = resolve(base, 'package.json') - return readFileSync(packageJsonPath, 'utf-8') - } catch { - return '' - } -}) - export function pkg(base: string) { return { - async manager() { - return await packageManagerForBase.get(base) - }, async add(packages: string[], location: 'dependencies' | 'devDependencies' = 'dependencies') { let packageManager = await packageManagerForBase.get(base) let args = packages.slice() if (location === 'devDependencies') { args.push(SAVE_DEV[packageManager] || SAVE_DEV.default) } - - // Allow running the `pnpm` command in the workspace root without - // erroring. Can't just use `--workspace-root` because that will force - // install dependencies in the workspace root. - if (packageManager === 'pnpm') { - args.push('--ignore-workspace-root-check') - } - - let command = `${packageManager} add ${args.join(' ')}` - try { - return await exec(command, { cwd: base }) - } catch (e: any) { - error(`An error occurred while running \`${command}\`\n\n${e.stdout}\n${e.stderr}`, { - prefix: '↳ ', - }) - throw e - } finally { - manifests.delete(base) - } - }, - has(name: string) { - return manifests.get(base).includes(`"${name}":`) + return exec(`${packageManager} add ${args.join(' ')}`, { cwd: base }) }, async remove(packages: string[]) { let packageManager = await packageManagerForBase.get(base) - let command = `${packageManager} remove ${packages.join(' ')}` - try { - return await exec(command, { cwd: base }) - } catch (e: any) { - error(`An error occurred while running \`${command}\`\n\n${e.stdout}\n${e.stderr}`, { - prefix: '↳ ', - }) - throw e - } finally { - manifests.delete(base) - } + return exec(`${packageManager} remove ${packages.join(' ')}`, { cwd: base }) }, } } diff --git a/packages/@tailwindcss-upgrade/src/utils/renderer.ts b/packages/@tailwindcss-upgrade/src/utils/renderer.ts index c9a967801..38bd9826a 100644 --- a/packages/@tailwindcss-upgrade/src/utils/renderer.ts +++ b/packages/@tailwindcss-upgrade/src/utils/renderer.ts @@ -44,7 +44,7 @@ export function wordWrap(text: string, width: number): string[] { // Handle text with newlines by maintaining the newlines, then splitting // each line separately. if (text.includes('\n')) { - return text.split('\n').flatMap((line) => (line ? wordWrap(line, width) : [''])) + return text.split('\n').flatMap((line) => wordWrap(line, width)) } let words = text.split(' ') diff --git a/packages/@tailwindcss-upgrade/src/utils/version.ts b/packages/@tailwindcss-upgrade/src/utils/version.ts deleted file mode 100644 index 27bc44f2b..000000000 --- a/packages/@tailwindcss-upgrade/src/utils/version.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { execSync } from 'node:child_process' -import semver from 'semver' -import { DefaultMap } from '../../../tailwindcss/src/utils/default-map' -import { getPackageVersionSync } from './package-version' - -/** - * Must be of major version. - * - * E.g.: `isMajor(3)` - */ -export function isMajor(version: number) { - return semver.satisfies(installedTailwindVersion(), `>=${version}.0.0 <${version + 1}.0.0`) -} - -/** - * Must be of greater than the current major version including minor and patch. - * - * E.g.: `isGreaterThan(3)` - */ -export function isGreaterThan(version: number) { - return semver.gte(installedTailwindVersion(), `${version + 1}.0.0`) -} - -let cache = new DefaultMap((base) => { - let tailwindVersion = getPackageVersionSync('tailwindcss', base) - if (!tailwindVersion) throw new Error('Tailwind CSS is not installed') - return tailwindVersion -}) - -export function installedTailwindVersion(base = process.cwd()): string { - return cache.get(base) -} - -let expectedCache = new DefaultMap((base) => { - try { - // This will report a problem if the package.json/package-lock.json - // mismatches with the installed version in node_modules. - // - // Also tested this with Bun and PNPM, both seem to work fine. - execSync('npm ls tailwindcss --json', { cwd: base, stdio: 'pipe' }) - return installedTailwindVersion(base) - } catch (_e) { - try { - let e = _e as { stdout: Buffer } - let data = JSON.parse(e.stdout.toString()) - - return ( - // Could be a sub-dependency issue, but we are only interested in - // the top-level version mismatch. - /"(.*?)" from the root project/.exec(data.dependencies.tailwindcss.invalid)?.[1] ?? - // Fallback to the installed version - installedTailwindVersion(base) - ) - } catch { - // We don't know how to verify, so let's just return the installed - // version to not block the user. - return installedTailwindVersion(base) - } - } -}) -export function expectedTailwindVersion(base = process.cwd()): string { - return expectedCache.get(base) -} diff --git a/packages/@tailwindcss-upgrade/src/utils/walk-variants.ts b/packages/@tailwindcss-upgrade/src/utils/walk-variants.ts deleted file mode 100644 index e0dd16899..000000000 --- a/packages/@tailwindcss-upgrade/src/utils/walk-variants.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { Candidate, Variant } from '../../../tailwindcss/src/candidate' - -export function* walkVariants(candidate: Candidate) { - function* inner( - variant: Variant, - parent: Extract | null = null, - ): Iterable<[Variant, Extract | null]> { - yield [variant, parent] - - if (variant.kind === 'compound') { - yield* inner(variant.variant, variant) - } - } - - for (let variant of candidate.variants) { - yield* inner(variant, null) - } -} diff --git a/packages/@tailwindcss-upgrade/src/utils/write-file-safely.ts b/packages/@tailwindcss-upgrade/src/utils/write-file-safely.ts deleted file mode 100644 index 2ff99f9e7..000000000 --- a/packages/@tailwindcss-upgrade/src/utils/write-file-safely.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { randomUUID } from 'node:crypto' -import fs from 'node:fs/promises' -import path from 'node:path' - -export async function writeFileSafely(file: string, contents: string) { - // Resolve symlinks so the rename replaces the actual target file rather than - // replacing the symlink itself with a regular file. - let realFile = await fs.realpath(file).catch(() => file) - - // Start by creating a new file in the current directory that is guaranteed to - // be unique (via `uuid`). We can embed the `process.id` in case we need to - // debug things later. - // - // While we can write this to a more global `/tmp` folder, I want to be 100% - // sure that we are on the same file system (same drive) so the rename - // operation is atomic. Once the file is written, we will rename the file. If - // this fails, the old file is still intact, if it works we have an updated - // file. - // - // If this still causes problems (but it will slow things down): - // 1. We could make sure that we inherit the file permissions - // 2. Use an explicit fsync to force a flush to disk - let temporaryFile = path.join( - path.dirname(realFile), - `.${path.basename(realFile)}.tailwind-upgrade.${process.pid}.${randomUUID()}.tmp`, - ) - - // Write file uses the `w` flag by default, which is defined as: - // > Open file for writing. The file is created (if it does not exist) or truncated (if it exists). - // > https://nodejs.org/api/fs.html#file-system-flags - // - // Which means that if this function is actively running, and you cancel the - // process at the wrong time, then the truncated files are present. Since all - // these migrations happen in parallel, multiple files are open and available - // to be written to, it could mean in multiple truncated files. - // - // Writing to a temp file first means that if the process is cancelled at this - // point, that the old original file is still correct. - // - // The rename part should be atomic (especially because we guarantee it to be - // on the same file system) so this either succeeds or doesn't happen. - try { - await fs.writeFile(temporaryFile, contents, 'utf8') - await fs.rename(temporaryFile, realFile) - } catch (error) { - await fs.unlink(temporaryFile).catch(() => {}) - throw error - } -} diff --git a/packages/@tailwindcss-vite/README.md b/packages/@tailwindcss-vite/README.md index 1a5d25c73..95ec9d87d 100644 --- a/packages/@tailwindcss-vite/README.md +++ b/packages/@tailwindcss-vite/README.md @@ -13,10 +13,10 @@

- Build Status + Build Status Total Downloads - Latest Release - License + Latest Release + License

--- @@ -27,50 +27,14 @@ For full documentation, visit [tailwindcss.com](https://tailwindcss.com). ## Community -For help, discussion about best practices, or feature ideas: +For help, discussion about best practices, or any other conversation that would benefit from being searchable: -[Discuss Tailwind CSS on GitHub](https://github.com/tailwindlabs/tailwindcss/discussions) +[Discuss Tailwind CSS on GitHub](https://github.com/tailwindcss/tailwindcss/discussions) + +For chatting with others using the framework: + +[Join the Tailwind CSS Discord Server](https://discord.gg/7NF8GNe) ## Contributing -If you're interested in contributing to Tailwind CSS, please read our [contributing docs](https://github.com/tailwindlabs/tailwindcss/blob/main/.github/CONTRIBUTING.md) **before submitting a pull request**. - ---- - -## `@tailwindcss/vite` plugin API - -### Enabling or disabling Lightning CSS - -By default, this plugin detects whether or not the CSS is being built for production by checking the `NODE_ENV` environment variable. When building for production Lightning CSS will be enabled otherwise it is disabled. - -If you want to always enable or disable Lightning CSS the `optimize` option may be used: - -```js -import tailwindcss from '@tailwindcss/vite' -import { defineConfig } from 'vite' - -export default defineConfig({ - plugins: [ - tailwindcss({ - // Disable Lightning CSS optimization - optimize: false, - }), - ], -}) -``` - -It's also possible to keep Lightning CSS enabled but disable minification: - -```js -import tailwindcss from '@tailwindcss/vite' -import { defineConfig } from 'vite' - -export default defineConfig({ - plugins: [ - tailwindcss({ - // Enable Lightning CSS but disable minification - optimize: { minify: false }, - }), - ], -}) -``` +If you're interested in contributing to Tailwind CSS, please read our [contributing docs](https://github.com/tailwindcss/tailwindcss/blob/next/.github/CONTRIBUTING.md) **before submitting a pull request**. diff --git a/packages/@tailwindcss-vite/package.json b/packages/@tailwindcss-vite/package.json index 821704a1d..5c50f8328 100644 --- a/packages/@tailwindcss-vite/package.json +++ b/packages/@tailwindcss-vite/package.json @@ -1,6 +1,6 @@ { "name": "@tailwindcss/vite", - "version": "4.3.3", + "version": "4.0.0-beta.7", "description": "A utility-first CSS framework for rapidly building custom user interfaces.", "license": "MIT", "repository": { @@ -24,12 +24,13 @@ "exports": { ".": { "types": "./dist/index.d.mts", - "default": "./dist/index.mjs" + "import": "./dist/index.mjs" } }, "dependencies": { - "@tailwindcss/node": "workspace:*", - "@tailwindcss/oxide": "workspace:*", + "@tailwindcss/node": "workspace:^", + "@tailwindcss/oxide": "workspace:^", + "lightningcss": "catalog:", "tailwindcss": "workspace:*" }, "devDependencies": { @@ -37,6 +38,6 @@ "vite": "catalog:" }, "peerDependencies": { - "vite": "^5.2.0 || ^6 || ^7 || ^8" + "vite": "^5.2.0 || ^6" } } diff --git a/packages/@tailwindcss-vite/src/index.ts b/packages/@tailwindcss-vite/src/index.ts index 8fc660eaa..b3c9ace1e 100644 --- a/packages/@tailwindcss-vite/src/index.ts +++ b/packages/@tailwindcss-vite/src/index.ts @@ -1,203 +1,213 @@ -import { - compile, - env, - Features, - Instrumentation, - normalizePath, - optimize, - toSourceMap, -} from '@tailwindcss/node' +import { compile, env, Features, Instrumentation, normalizePath } from '@tailwindcss/node' import { clearRequireCache } from '@tailwindcss/node/require-cache' import { Scanner } from '@tailwindcss/oxide' +import { Features as LightningCssFeatures, transform } from 'lightningcss' import fs from 'node:fs/promises' import path from 'node:path' -import type { Environment, InternalResolveOptions, Plugin, ResolvedConfig } from 'vite' -import * as vite from 'vite' +import type { Plugin, ResolvedConfig, Rollup, Update, ViteDevServer } from 'vite' const DEBUG = env.DEBUG -const SPECIAL_QUERY_RE = /[?&](?:worker|sharedworker|raw|url)\b/ -const COMMON_JS_PROXY_RE = /\?commonjs-proxy/ -const INLINE_STYLE_ID_RE = /[?&]index=\d+\.css$/ +const SPECIAL_QUERY_RE = /[?&](raw|url)\b/ -export type PluginOptions = { - /** - * Optimize and minify the output CSS. - */ - optimize?: boolean | { minify?: boolean } -} - -function createCustomResolver( - resolvers: ((id: string, importer: string) => Promise)[], - filter = (_path: string) => true, -) { - return async (id: string, base: string) => { - // The resolver expects an `importer` file. We don't really know where the - // current `id` was imported from, but Vite will essentially do a - // `path.dirname(importer)` so it doesn't really matter. - // - // It does matter that this is a file, otherwise we would go up a directory, - // which means that we would be resolving files from a parent folder first, - // instead of the current folder we are in. - let importer = path.resolve(base, '__placeholder__.ts') - - for (let resolver of resolvers) { - let resolved = await resolver(id, importer) - - // If we didn't resolve, we don't have to bail immediately, but we can try - // the next resolver - if (!resolved) continue - - if (resolved === id) continue - - // Looks like a relative file, let's resolve it to an absolute path - if (resolved[0] === '.') resolved = path.resolve(base, resolved) - - // Must adhere to additional filters (e.g.: must be a .css file) - if (!filter(resolved)) continue - - // If it's not an absolute path, then we don't really know how to read - // the file from disk. - if (!path.isAbsolute(resolved)) continue - - return resolved - } - } -} - -export default function tailwindcss(opts: PluginOptions = {}): Plugin[] { +export default function tailwindcss(): Plugin[] { + let servers: ViteDevServer[] = [] let config: ResolvedConfig | null = null - let rootsByEnv = new DefaultMap>((env: string) => new Map()) let isSSR = false - let shouldOptimize = true - let minify = true + let minify = false - function createRoot(env: Environment | null, id: string) { - type ResolveFn = (id: string, base: string) => Promise + // The Vite extension has two types of sources for candidates: + // + // 1. The module graph: These are all modules that vite transforms and we want + // them to be automatically scanned for candidates. + // 2. Root defined `@source`s + // + // Module graph candidates are global to the Vite extension since we do not + // know which CSS roots will be used for the modules. We are using a custom + // scanner instance with auto source discovery disabled to parse these. + // + // For candidates coming from custom `@source` directives of the CSS roots, we + // create an individual scanner for each root. + // + // Note: To improve performance, we do not remove candidates from this set. + // This means a longer-ongoing dev mode session might contain candidates that + // are no longer referenced in code. + let moduleGraphCandidates = new DefaultMap>(() => new Set()) + let moduleGraphScanner = new Scanner({}) - let customCssResolver: ResolveFn - let customJsResolver: ResolveFn - - if (!env) { - // Older, pre-environment Vite API - // TODO: Can we drop this?? - let cssResolver = config!.createResolver({ - ...config!.resolve, - extensions: ['.css'], - mainFields: ['style'], - conditions: ['style', 'development|production'], - tryIndex: false, - preferRelative: true, - }) - - let jsResolver = config!.createResolver(config!.resolve) - - customCssResolver = createCustomResolver( - [ - (id, importer) => cssResolver(id, importer, true, isSSR), - (id, importer) => cssResolver(id, importer, false, isSSR), - ], - (path) => path.endsWith('.css'), - ) - customJsResolver = createCustomResolver( - [ - (id, importer) => jsResolver(id, importer, true, isSSR), - (id, importer) => jsResolver(id, importer, false, isSSR), - ], - (path) => !path.endsWith('.css'), - ) - } else { - type ResolveIdFn = ( - environment: Environment, - id: string, - importer?: string, - aliasOnly?: boolean, - ) => Promise - - // There are cases where Environment API is available, - // but `createResolver` is still overridden (for example astro v5) - // - // Copied as-is from vite, because this function is not a part of public API - // - // TODO: Remove this function and pre-environment code when Vite < 7 is no longer supported - function createBackCompatIdResolver( - config: ResolvedConfig, - options?: Partial, - ): ResolveIdFn { - const compatResolve = config.createResolver(options) - let resolve: ResolveIdFn - return async (environment, id, importer, aliasOnly) => { - if (environment.name === 'client' || environment.name === 'ssr') { - return compatResolve(id, importer, aliasOnly, environment.name === 'ssr') - } - resolve ??= vite.createIdResolver(config, options) - return resolve(environment, id, importer, aliasOnly) - } - } - - // Newer Vite versions - let cssResolver = createBackCompatIdResolver(env.config, { - ...env.config.resolve, - extensions: ['.css'], - mainFields: ['style'], - conditions: ['style', 'development|production'], - tryIndex: false, - preferRelative: true, - }) - - let jsResolver = createBackCompatIdResolver(env.config, env.config.resolve) - - customCssResolver = createCustomResolver( - [ - (id, importer) => cssResolver(env, id, importer, true), - (id, importer) => cssResolver(env, id, importer, false), - ], - (path) => path.endsWith('.css'), - ) - customJsResolver = createCustomResolver( - [ - (id, importer) => jsResolver(env, id, importer, true), - (id, importer) => jsResolver(env, id, importer, false), - ], - (path) => !path.endsWith('.css'), - ) + let roots: DefaultMap = new DefaultMap((id) => { + let cssResolver = config!.createResolver({ + ...config!.resolve, + extensions: ['.css'], + mainFields: ['style'], + conditions: ['style', 'development|production'], + tryIndex: false, + preferRelative: true, + }) + function customCssResolver(id: string, base: string) { + return cssResolver(id, base, true, isSSR) } + let jsResolver = config!.createResolver(config!.resolve) + function customJsResolver(id: string, base: string) { + return jsResolver(id, base, true, isSSR) + } return new Root( id, - config!.root, - // Currently, Vite only supports CSS source maps in development and they - // are off by default. Check to see if we need them or not. - config?.css.devSourcemap ?? false, + () => moduleGraphCandidates, + config!.base, customCssResolver, customJsResolver, ) + }) + + function scanFile(id: string, content: string, extension: string, isSSR: boolean) { + let updated = false + for (let candidate of moduleGraphScanner.scanFiles([{ content, extension }])) { + updated = true + moduleGraphCandidates.get(id).add(candidate) + } + + if (updated) { + invalidateAllRoots(isSSR) + } + } + + function invalidateAllRoots(isSSR: boolean) { + for (let server of servers) { + let updates: Update[] = [] + for (let [id, root] of roots.entries()) { + let module = server.moduleGraph.getModuleById(id) + if (!module) { + // The module for this root might not exist yet + if (root.builtBeforeTransform) { + continue + } + + // Note: Removing this during SSR is not safe and will produce + // inconsistent results based on the timing of the removal and + // the order / timing of transforms. + if (!isSSR) { + // It is safe to remove the item here since we're iterating on a copy + // of the keys. + roots.delete(id) + } + continue + } + + roots.get(id).requiresRebuild = false + server.moduleGraph.invalidateModule(module) + updates.push({ + type: `${module.type}-update`, + path: module.url, + acceptedPath: module.url, + timestamp: Date.now(), + }) + } + + if (updates.length > 0) { + server.hot.send({ type: 'update', updates }) + } + } + } + + async function regenerateOptimizedCss( + root: Root, + addWatchFile: (file: string) => void, + I: Instrumentation, + ) { + let content = root.lastContent + let generated = await root.generate(content, addWatchFile, I) + if (generated === false) { + return + } + DEBUG && I.start('Optimize CSS') + let result = optimizeCss(generated, { minify }) + DEBUG && I.end('Optimize CSS') + return result + } + + // Manually run the transform functions of non-Tailwind plugins on the given CSS + async function transformWithPlugins(context: Rollup.PluginContext, id: string, css: string) { + let transformPluginContext = { + ...context, + getCombinedSourcemap: () => { + throw new Error('getCombinedSourcemap not implemented') + }, + } + + for (let plugin of config!.plugins) { + if (!plugin.transform) continue + + if (plugin.name.startsWith('@tailwindcss/')) { + // We do not run any Tailwind transforms anymore + continue + } else if ( + plugin.name.startsWith('vite:') && + // Apply the vite:css plugin to generated CSS for transformations like + // URL path rewriting and image inlining. + plugin.name !== 'vite:css' && + // In build mode, since `renderStart` runs after all transformations, we + // need to also apply vite:css-post. + plugin.name !== 'vite:css-post' && + // The vite:vue plugin handles CSS specific post-processing for Vue + plugin.name !== 'vite:vue' + ) { + continue + } else if (plugin.name === 'ssr-styles') { + // The Nuxt ssr-styles plugin emits styles from server-side rendered + // components, we can't run it in the `renderStart` phase so we're + // skipping it. + continue + } + + let transformHandler = + 'handler' in plugin.transform! ? plugin.transform.handler : plugin.transform! + + try { + // Directly call the plugin's transform function to process the + // generated CSS. In build mode, this updates the chunks later used to + // generate the bundle. In serve mode, the transformed source should be + // applied in transform. + let result = await transformHandler.call(transformPluginContext, css, id) + if (!result) continue + if (typeof result === 'string') { + css = result + } else if (result.code) { + css = result.code + } + } catch (e) { + console.error(`Error running ${plugin.name} on Tailwind CSS output. Skipping.`) + } + } + return css } return [ + svelteProcessor(roots), { // Step 1: Scan source files for candidates name: '@tailwindcss/vite:scan', enforce: 'pre', + configureServer(server) { + servers.push(server) + }, + async configResolved(_config) { config = _config + minify = config.build.cssMinify !== false isSSR = config.build.ssr !== false && config.build.ssr !== undefined + }, - // By default we optimize CSS during the build phase but if the user - // provides explicit options we'll use those instead - if (opts.optimize !== undefined) { - shouldOptimize = opts.optimize !== false - } - - // Minification is also performed when optimizing as long as it's also - // enabled in Vite - minify = shouldOptimize && config.build.cssMinify !== false - - // But again, the user can override that choice explicitly - if (typeof opts.optimize === 'object') { - minify = opts.optimize.minify !== false - } + // Scan all non-CSS files for candidates + transformIndexHtml(html, { path }) { + scanFile(path, html, 'html', isSSR) + }, + transform(src, id, options) { + let extension = getExtension(id) + if (isPotentialCssRootFile(id)) return + scanFile(id, src, extension, options?.ssr ?? false) }, }, @@ -206,35 +216,45 @@ export default function tailwindcss(opts: PluginOptions = {}): Plugin[] { name: '@tailwindcss/vite:generate:serve', apply: 'serve', enforce: 'pre', - transform: { - filter: { - id: { - exclude: [/\/\.vite\//, SPECIAL_QUERY_RE, COMMON_JS_PROXY_RE], - include: [/\.css(?:\?.*)?$/, /&lang\.css/, INLINE_STYLE_ID_RE], - }, - }, - async handler(src, id) { - if (!isPotentialCssRootFile(id)) return - using I = new Instrumentation() - DEBUG && I.start('[@tailwindcss/vite] Generate CSS (serve)') + async transform(src, id, options) { + if (!isPotentialCssRootFile(id)) return - let roots = rootsByEnv.get(this.environment?.name ?? 'default') - let root = roots.get(id) - if (!root) { - root ??= createRoot(this.environment ?? null, id) - roots.set(id, root) - } + using I = new Instrumentation() + I.start('[@tailwindcss/vite] Generate CSS (serve)') - let result = await root.generate(src, (file) => this.addWatchFile(file), I) - if (!result) { - roots.delete(id) - return - } + let root = roots.get(id) - DEBUG && I.end('[@tailwindcss/vite] Generate CSS (serve)') - return result - }, + // If the root was built outside of the transform hook (e.g. in the + // Svelte preprocessor), we still want to mark all dependencies of the + // root as watched files. + if (root.builtBeforeTransform) { + root.builtBeforeTransform.forEach((file) => this.addWatchFile(file)) + root.builtBeforeTransform = undefined + } + + // We only process Svelte `' + - '
' + - '
one
' + - '
two
' + - '
' - } - } - - customElements.define('my-component', Component) - - - - `, - ) - - let gap = await page.evaluate(() => { - let shadowRoot = document.querySelector('#shadow')!.shadowRoot! - let x = shadowRoot.querySelector('#x')! - return window.getComputedStyle(x).getPropertyValue('gap') - }) - - expect(gap).toBe('8px') -}) - -// @scope related tests -{ - test('custom variant using `@scope`', async ({ page }) => { - let { getPropertyValue } = await render( - page, - html` -
-
In scope
-
-
Beyond the limit
-
-
-
Not in scope
- `, - css` - @custom-variant in-checkout { - @scope (.checkout) to (.payment) { - @slot; - } - } - `, - ) - - test.skip(!(await supportsAtScope(page)), '`@scope` is not supported in this browser') - - expect(await getPropertyValue('#in', 'text-decoration-line')).toEqual('underline') - expect(await getPropertyValue('#beyond', 'text-decoration-line')).toEqual('none') - expect(await getPropertyValue('#out', 'text-decoration-line')).toEqual('none') - }) - - test('custom variant using `@scope` behaves like the equivalent authored CSS', async ({ - page, - }) => { - // Render the same structure twice: - // - Once styled by authored CSS using `@scope`, like the "normal CSS" - // reference in https://github.com/tailwindlabs/tailwindcss/issues/18961 - // - Once styled by utilities using an equivalent custom variant - function structure(prefix: string, probe: string) { - return html` -
-
In scope
-
-
Beyond the limit
-
-
-
Not in scope
- ` - } - - let { getPropertyValue } = await render( - page, - structure('a', 'a-probe') + structure('c', 'in-checkout:underline'), - css` - @custom-variant in-checkout { - @scope (.checkout) to (.payment) { - @slot; - } - } - `, - ) - - // The `a-*` structure is styled by the authored CSS as-is - await page.addStyleTag({ - content: css` - @scope (.checkout) to (.payment) { - .a-probe { - text-decoration-line: underline; - } - } - `, - }) - - test.skip(!(await supportsAtScope(page)), '`@scope` is not supported in this browser') - - for (let prefix of ['a', 'c']) { - expect(await getPropertyValue(`#${prefix}-in`, 'text-decoration-line')).toEqual('underline') - expect(await getPropertyValue(`#${prefix}-beyond`, 'text-decoration-line')).toEqual('none') - expect(await getPropertyValue(`#${prefix}-out`, 'text-decoration-line')).toEqual('none') - } - }) - - test('user-authored nested `@scope` behaves like the authored CSS', async ({ page }) => { - // User-authored `@scope` rules are compiled to their native CSS nesting - // semantics. Rendering the same structure twice: - // - Once styled by the authored (nested) CSS as-is - // - Once styled by the compiled output - function structure(prefix: string) { - return html` -
-
- in scope -
- beyond the limit -
-
-
-
- scope not inside parent -
- ` - } - - function scopeCss(prefix: string) { - return css` - .${prefix}-parent { - @scope (& > .${prefix}-scope) to (& .${prefix}-limit) { - .${prefix}-content { - text-decoration-line: underline; - } - } - } - ` - } - - // The `c-*` structure is styled by the compiled CSS - let { getPropertyValue } = await render(page, structure('a') + structure('c'), scopeCss('c')) - - // The `a-*` structure is styled by the authored CSS as-is - await page.addStyleTag({ content: scopeCss('a') }) - - test.skip(!(await supportsAtScope(page)), '`@scope` is not supported in this browser') - - // The compiled output only applies within the scope - expect(await getPropertyValue('#c-in', 'text-decoration-line')).toEqual('underline') - expect(await getPropertyValue('#c-beyond', 'text-decoration-line')).toEqual('none') - expect(await getPropertyValue('#c-out', 'text-decoration-line')).toEqual('none') - - // The authored CSS behaves the same - expect(await getPropertyValue('#a-in', 'text-decoration-line')).toEqual('underline') - expect(await getPropertyValue('#a-out', 'text-decoration-line')).toEqual('none') - - // WebKit currently drops the `` limit entirely when it contains - // `&`. Since we resolve the `&` at build time, the compiled output works - // even though the authored CSS doesn't. - if (test.info().project.name !== 'webkit') { - expect(await getPropertyValue('#a-beyond', 'text-decoration-line')).toEqual('none') - } - }) - - test('user-authored `@scope` nested inside another `@scope`', async ({ page }) => { - function structure(prefix: string) { - return html` - -
-
-
ctrl
-
-
- - -
-
-
ancestor
-
-
- - -
-
-
-
beyond
-
-
-
- ` - } - - function scopeCss(prefix: string) { - return css` - @scope (.${prefix}-outer) to (.${prefix}-outer-limit) { - .${prefix}-middle { - @scope (.${prefix}-inner) to (.${prefix}-inner-limit) { - text-decoration-line: underline; - } - } - } - ` - } - - // The `c-*` structure is styled by the compiled CSS - let { getPropertyValue } = await render(page, structure('a') + structure('c'), scopeCss('c')) - - // The `a-*` structure is styled by the authored CSS as-is - await page.addStyleTag({ content: scopeCss('a') }) - - test.skip(!(await supportsAtScope(page)), '`@scope` is not supported in this browser') - - // The compiled output behaves the same in every browser - expect(await getPropertyValue('#c-ctrl', 'text-decoration-line')).toEqual('underline') - expect(await getPropertyValue('#c-ancestor', 'text-decoration-line')).toEqual('none') - expect(await getPropertyValue('#c-beyond', 'text-decoration-line')).toEqual('none') - - // The authored CSS behaves the same … - expect(await getPropertyValue('#a-ctrl', 'text-decoration-line')).toEqual('underline') - expect(await getPropertyValue('#a-beyond', 'text-decoration-line')).toEqual('none') - - // … except in Chromium, which resolves the nesting context of a - // rule-nested `@scope` without the enclosing scope's constraint (Safari - // and Firefox both constrain it). The compiled output normalizes this - // browser difference. - if (test.info().project.name !== 'chromium') { - expect(await getPropertyValue('#a-ancestor', 'text-decoration-line')).toEqual('none') - } - }) - - function supportsAtScope(page: Page) { - return page.evaluate(() => typeof CSSScopeRule !== 'undefined') - } -} - -for (let kind of ['group', 'peer']) { - test(`${kind}-* variants`, async ({ page }) => { - let targets = html` -
-
- ` - - let { getPropertyValue } = await render( - page, - kind === 'group' - ? html`
${targets}
` - : html`
-
- ${targets} -
`, - css` - .owner > .applied { - @apply ${kind}-focus:z-20; - } - `, - ) - - expect(await getPropertyValue('#target', 'z-index')).toEqual('auto') - expect(await getPropertyValue('#applied', 'z-index')).toEqual('auto') - - await page.locator('#trigger').focus() - - expect(await getPropertyValue('#target', 'z-index')).toEqual('10') - expect(await getPropertyValue('#applied', 'z-index')).toEqual('20') - - await page.locator('#trigger').blur() - - expect(await getPropertyValue('#target', 'z-index')).toEqual('auto') - expect(await getPropertyValue('#applied', 'z-index')).toEqual('auto') - }) -} - -test('group-* variants do not change specificity', async ({ page }) => { - let { getPropertyValue } = await render( - page, - html` -
-
-
- `, - css` - @layer utilities { - .target { - z-index: 20; - } - .target.equal { - z-index: 30; - } - } - `, - ) - - await page.locator('#trigger').focus() - - expect(await getPropertyValue('#target', 'z-index')).toEqual('10') - - await page.locator('#target').evaluate((element) => element.classList.add('equal')) - - expect(await getPropertyValue('#target', 'z-index')).toEqual('30') -}) - -test('stacked group-* variants match regardless of the order of the groups', async ({ page }) => { - for (let [outer, inner] of [ - ['a', 'b'], - ['b', 'a'], - ]) { - let { getPropertyValue } = await render( - page, - html` -
-
-
-
-
- `, - ) - - expect(await getPropertyValue('#target', 'z-index')).toEqual('10') - - await page.locator('#inner').evaluate((element) => element.removeAttribute('data-active')) - - expect(await getPropertyValue('#target', 'z-index')).toEqual('auto') - } -}) - -test('compound group-* and peer-* variants', async ({ page }) => { - let { getPropertyValue } = await render( - page, - html` -
-
-
-
-
-
- `, - ) - - await page.locator('#peer').focus() - - expect(await getPropertyValue('#target', 'z-index')).toEqual('10') - expect(await getPropertyValue('#middle', 'z-index')).toEqual('auto') - - await page.locator('#outer').focus() - - expect(await getPropertyValue('#target', 'z-index')).toEqual('auto') - expect(await getPropertyValue('#middle', 'z-index')).toEqual('20') -}) - // --- const preflight = fs.readFileSync(path.resolve(__dirname, '..', 'preflight.css'), 'utf-8') @@ -2516,8 +654,6 @@ async function render(page: Page, content: string, extraCss: string = '') { --color-red: rgb(255, 0, 0); --color-green: rgb(0, 255, 0); --color-blue: rgb(0, 0, 255); - --color-black: black; - --color-transparent: transparent; } } @layer base { @@ -2537,13 +673,14 @@ async function render(page: Page, content: string, extraCss: string = '') { // mouse to before running the tests. content = `
${content}` + await page.setContent(content) + let scanner = new Scanner({}) let candidates = scanner.scanFiles([{ content, extension: 'html' }]) - let { code: styles } = optimize(build(candidates)) - - content = `${content}` - await page.setContent(content) + await page.addStyleTag({ + content: optimizeCss(build(candidates)), + }) await page.locator('#mouse-park').hover() @@ -2555,16 +692,6 @@ async function render(page: Page, content: string, extraCss: string = '') { property, ) }, - - async getPropertyList(selector: string | [string, string], property: string) { - let value = await getPropertyValue( - page, - Array.isArray(selector) ? selector : [selector, undefined], - property, - ) - - return segment(value, ',').map((item) => item.trim()) - }, } } @@ -2573,7 +700,7 @@ async function getPropertyValue( selector: [string, string | undefined], property: string, ) { - let value = await page.evaluate( + return page.evaluate( ([[selector, pseudo], property]) => { return window .getComputedStyle(document.querySelector(selector)!, pseudo) @@ -2581,16 +708,4 @@ async function getPropertyValue( }, [selector, property] as const, ) - - switch (property) { - case 'outline': - // Order in webkit vs chromium is different. Sort to normalize. - return segment(value, ' ') - .map((part) => part.trim()) - .sort((a, z) => a.length - z.length) - .join(' ') - - default: - return value - } } diff --git a/packages/tailwindcss/theme.css b/packages/tailwindcss/theme.css index 05364f5c2..a0652e07d 100644 --- a/packages/tailwindcss/theme.css +++ b/packages/tailwindcss/theme.css @@ -1,323 +1,273 @@ @theme default { - --font-sans: - -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', 'Noto Sans', Arial, - sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; + --font-sans: ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', + 'Segoe UI Symbol', 'Noto Color Emoji'; --font-serif: ui-serif, Georgia, Cambria, 'Times New Roman', Times, serif; - --font-mono: - ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', - monospace; + --font-mono: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', + 'Courier New', monospace; - --color-red-50: oklch(97.1% 0.013 17.38); - --color-red-100: oklch(93.6% 0.032 17.717); - --color-red-200: oklch(88.5% 0.062 18.334); - --color-red-300: oklch(80.8% 0.114 19.571); - --color-red-400: oklch(70.4% 0.191 22.216); - --color-red-500: oklch(63.7% 0.237 25.331); - --color-red-600: oklch(57.7% 0.245 27.325); - --color-red-700: oklch(50.5% 0.213 27.518); - --color-red-800: oklch(44.4% 0.177 26.899); - --color-red-900: oklch(39.6% 0.141 25.723); - --color-red-950: oklch(25.8% 0.092 26.042); + --color-red-50: oklch(0.971 0.013 17.38); + --color-red-100: oklch(0.936 0.032 17.717); + --color-red-200: oklch(0.885 0.062 18.334); + --color-red-300: oklch(0.808 0.114 19.571); + --color-red-400: oklch(0.704 0.191 22.216); + --color-red-500: oklch(0.637 0.237 25.331); + --color-red-600: oklch(0.577 0.245 27.325); + --color-red-700: oklch(0.505 0.213 27.518); + --color-red-800: oklch(0.444 0.177 26.899); + --color-red-900: oklch(0.396 0.141 25.723); + --color-red-950: oklch(0.258 0.092 26.042); - --color-orange-50: oklch(98% 0.016 73.684); - --color-orange-100: oklch(95.4% 0.038 75.164); - --color-orange-200: oklch(90.1% 0.076 70.697); - --color-orange-300: oklch(83.7% 0.128 66.29); - --color-orange-400: oklch(75% 0.183 55.934); - --color-orange-500: oklch(70.5% 0.213 47.604); - --color-orange-600: oklch(64.6% 0.222 41.116); - --color-orange-700: oklch(55.3% 0.195 38.402); - --color-orange-800: oklch(47% 0.157 37.304); - --color-orange-900: oklch(40.8% 0.123 38.172); - --color-orange-950: oklch(26.6% 0.079 36.259); + --color-orange-50: oklch(0.98 0.016 73.684); + --color-orange-100: oklch(0.954 0.038 75.164); + --color-orange-200: oklch(0.901 0.076 70.697); + --color-orange-300: oklch(0.837 0.128 66.29); + --color-orange-400: oklch(0.75 0.183 55.934); + --color-orange-500: oklch(0.705 0.213 47.604); + --color-orange-600: oklch(0.646 0.222 41.116); + --color-orange-700: oklch(0.553 0.195 38.402); + --color-orange-800: oklch(0.47 0.157 37.304); + --color-orange-900: oklch(0.408 0.123 38.172); + --color-orange-950: oklch(0.266 0.079 36.259); - --color-amber-50: oklch(98.7% 0.022 95.277); - --color-amber-100: oklch(96.2% 0.059 95.617); - --color-amber-200: oklch(92.4% 0.12 95.746); - --color-amber-300: oklch(87.9% 0.169 91.605); - --color-amber-400: oklch(82.8% 0.189 84.429); - --color-amber-500: oklch(76.9% 0.188 70.08); - --color-amber-600: oklch(66.6% 0.179 58.318); - --color-amber-700: oklch(55.5% 0.163 48.998); - --color-amber-800: oklch(47.3% 0.137 46.201); - --color-amber-900: oklch(41.4% 0.112 45.904); - --color-amber-950: oklch(27.9% 0.077 45.635); + --color-amber-50: oklch(0.987 0.022 95.277); + --color-amber-100: oklch(0.962 0.059 95.617); + --color-amber-200: oklch(0.924 0.12 95.746); + --color-amber-300: oklch(0.879 0.169 91.605); + --color-amber-400: oklch(0.828 0.189 84.429); + --color-amber-500: oklch(0.769 0.188 70.08); + --color-amber-600: oklch(0.666 0.179 58.318); + --color-amber-700: oklch(0.555 0.163 48.998); + --color-amber-800: oklch(0.473 0.137 46.201); + --color-amber-900: oklch(0.414 0.112 45.904); + --color-amber-950: oklch(0.279 0.077 45.635); - --color-yellow-50: oklch(98.7% 0.026 102.212); - --color-yellow-100: oklch(97.3% 0.071 103.193); - --color-yellow-200: oklch(94.5% 0.129 101.54); - --color-yellow-300: oklch(90.5% 0.182 98.111); - --color-yellow-400: oklch(85.2% 0.199 91.936); - --color-yellow-500: oklch(79.5% 0.184 86.047); - --color-yellow-600: oklch(68.1% 0.162 75.834); - --color-yellow-700: oklch(55.4% 0.135 66.442); - --color-yellow-800: oklch(47.6% 0.114 61.907); - --color-yellow-900: oklch(42.1% 0.095 57.708); - --color-yellow-950: oklch(28.6% 0.066 53.813); + --color-yellow-50: oklch(0.987 0.026 102.212); + --color-yellow-100: oklch(0.973 0.071 103.193); + --color-yellow-200: oklch(0.945 0.129 101.54); + --color-yellow-300: oklch(0.905 0.182 98.111); + --color-yellow-400: oklch(0.852 0.199 91.936); + --color-yellow-500: oklch(0.795 0.184 86.047); + --color-yellow-600: oklch(0.681 0.162 75.834); + --color-yellow-700: oklch(0.554 0.135 66.442); + --color-yellow-800: oklch(0.476 0.114 61.907); + --color-yellow-900: oklch(0.421 0.095 57.708); + --color-yellow-950: oklch(0.286 0.066 53.813); - --color-lime-50: oklch(98.6% 0.031 120.757); - --color-lime-100: oklch(96.7% 0.067 122.328); - --color-lime-200: oklch(93.8% 0.127 124.321); - --color-lime-300: oklch(89.7% 0.196 126.665); - --color-lime-400: oklch(84.1% 0.238 128.85); - --color-lime-500: oklch(76.8% 0.233 130.85); - --color-lime-600: oklch(64.8% 0.2 131.684); - --color-lime-700: oklch(53.2% 0.157 131.589); - --color-lime-800: oklch(45.3% 0.124 130.933); - --color-lime-900: oklch(40.5% 0.101 131.063); - --color-lime-950: oklch(27.4% 0.072 132.109); + --color-lime-50: oklch(0.986 0.031 120.757); + --color-lime-100: oklch(0.967 0.067 122.328); + --color-lime-200: oklch(0.938 0.127 124.321); + --color-lime-300: oklch(0.897 0.196 126.665); + --color-lime-400: oklch(0.841 0.238 128.85); + --color-lime-500: oklch(0.768 0.233 130.85); + --color-lime-600: oklch(0.648 0.2 131.684); + --color-lime-700: oklch(0.532 0.157 131.589); + --color-lime-800: oklch(0.453 0.124 130.933); + --color-lime-900: oklch(0.405 0.101 131.063); + --color-lime-950: oklch(0.274 0.072 132.109); - --color-green-50: oklch(98.2% 0.018 155.826); - --color-green-100: oklch(96.2% 0.044 156.743); - --color-green-200: oklch(92.5% 0.084 155.995); - --color-green-300: oklch(87.1% 0.15 154.449); - --color-green-400: oklch(79.2% 0.209 151.711); - --color-green-500: oklch(72.3% 0.219 149.579); - --color-green-600: oklch(62.7% 0.194 149.214); - --color-green-700: oklch(52.7% 0.154 150.069); - --color-green-800: oklch(44.8% 0.119 151.328); - --color-green-900: oklch(39.3% 0.095 152.535); - --color-green-950: oklch(26.6% 0.065 152.934); + --color-green-50: oklch(0.982 0.018 155.826); + --color-green-100: oklch(0.962 0.044 156.743); + --color-green-200: oklch(0.925 0.084 155.995); + --color-green-300: oklch(0.871 0.15 154.449); + --color-green-400: oklch(0.792 0.209 151.711); + --color-green-500: oklch(0.723 0.219 149.579); + --color-green-600: oklch(0.627 0.194 149.214); + --color-green-700: oklch(0.527 0.154 150.069); + --color-green-800: oklch(0.448 0.119 151.328); + --color-green-900: oklch(0.393 0.095 152.535); + --color-green-950: oklch(0.266 0.065 152.934); - --color-emerald-50: oklch(97.9% 0.021 166.113); - --color-emerald-100: oklch(95% 0.052 163.051); - --color-emerald-200: oklch(90.5% 0.093 164.15); - --color-emerald-300: oklch(84.5% 0.143 164.978); - --color-emerald-400: oklch(76.5% 0.177 163.223); - --color-emerald-500: oklch(69.6% 0.17 162.48); - --color-emerald-600: oklch(59.6% 0.145 163.225); - --color-emerald-700: oklch(50.8% 0.118 165.612); - --color-emerald-800: oklch(43.2% 0.095 166.913); - --color-emerald-900: oklch(37.8% 0.077 168.94); - --color-emerald-950: oklch(26.2% 0.051 172.552); + --color-emerald-50: oklch(0.979 0.021 166.113); + --color-emerald-100: oklch(0.95 0.052 163.051); + --color-emerald-200: oklch(0.905 0.093 164.15); + --color-emerald-300: oklch(0.845 0.143 164.978); + --color-emerald-400: oklch(0.765 0.177 163.223); + --color-emerald-500: oklch(0.696 0.17 162.48); + --color-emerald-600: oklch(0.596 0.145 163.225); + --color-emerald-700: oklch(0.508 0.118 165.612); + --color-emerald-800: oklch(0.432 0.095 166.913); + --color-emerald-900: oklch(0.378 0.077 168.94); + --color-emerald-950: oklch(0.262 0.051 172.552); - --color-teal-50: oklch(98.4% 0.014 180.72); - --color-teal-100: oklch(95.3% 0.051 180.801); - --color-teal-200: oklch(91% 0.096 180.426); - --color-teal-300: oklch(85.5% 0.138 181.071); - --color-teal-400: oklch(77.7% 0.152 181.912); - --color-teal-500: oklch(70.4% 0.14 182.503); - --color-teal-600: oklch(60% 0.118 184.704); - --color-teal-700: oklch(51.1% 0.096 186.391); - --color-teal-800: oklch(43.7% 0.078 188.216); - --color-teal-900: oklch(38.6% 0.063 188.416); - --color-teal-950: oklch(27.7% 0.046 192.524); + --color-teal-50: oklch(0.984 0.014 180.72); + --color-teal-100: oklch(0.953 0.051 180.801); + --color-teal-200: oklch(0.91 0.096 180.426); + --color-teal-300: oklch(0.855 0.138 181.071); + --color-teal-400: oklch(0.777 0.152 181.912); + --color-teal-500: oklch(0.704 0.14 182.503); + --color-teal-600: oklch(0.6 0.118 184.704); + --color-teal-700: oklch(0.511 0.096 186.391); + --color-teal-800: oklch(0.437 0.078 188.216); + --color-teal-900: oklch(0.386 0.063 188.416); + --color-teal-950: oklch(0.277 0.046 192.524); - --color-cyan-50: oklch(98.4% 0.019 200.873); - --color-cyan-100: oklch(95.6% 0.045 203.388); - --color-cyan-200: oklch(91.7% 0.08 205.041); - --color-cyan-300: oklch(86.5% 0.127 207.078); - --color-cyan-400: oklch(78.9% 0.154 211.53); - --color-cyan-500: oklch(71.5% 0.143 215.221); - --color-cyan-600: oklch(60.9% 0.126 221.723); - --color-cyan-700: oklch(52% 0.105 223.128); - --color-cyan-800: oklch(45% 0.085 224.283); - --color-cyan-900: oklch(39.8% 0.07 227.392); - --color-cyan-950: oklch(30.2% 0.056 229.695); + --color-cyan-50: oklch(0.984 0.019 200.873); + --color-cyan-100: oklch(0.956 0.045 203.388); + --color-cyan-200: oklch(0.917 0.08 205.041); + --color-cyan-300: oklch(0.865 0.127 207.078); + --color-cyan-400: oklch(0.789 0.154 211.53); + --color-cyan-500: oklch(0.715 0.143 215.221); + --color-cyan-600: oklch(0.609 0.126 221.723); + --color-cyan-700: oklch(0.52 0.105 223.128); + --color-cyan-800: oklch(0.45 0.085 224.283); + --color-cyan-900: oklch(0.398 0.07 227.392); + --color-cyan-950: oklch(0.302 0.056 229.695); - --color-sky-50: oklch(97.7% 0.013 236.62); - --color-sky-100: oklch(95.1% 0.026 236.824); - --color-sky-200: oklch(90.1% 0.058 230.902); - --color-sky-300: oklch(82.8% 0.111 230.318); - --color-sky-400: oklch(74.6% 0.16 232.661); - --color-sky-500: oklch(68.5% 0.169 237.323); - --color-sky-600: oklch(58.8% 0.158 241.966); - --color-sky-700: oklch(50% 0.134 242.749); - --color-sky-800: oklch(44.3% 0.11 240.79); - --color-sky-900: oklch(39.1% 0.09 240.876); - --color-sky-950: oklch(29.3% 0.066 243.157); + --color-sky-50: oklch(0.977 0.013 236.62); + --color-sky-100: oklch(0.951 0.026 236.824); + --color-sky-200: oklch(0.901 0.058 230.902); + --color-sky-300: oklch(0.828 0.111 230.318); + --color-sky-400: oklch(0.746 0.16 232.661); + --color-sky-500: oklch(0.685 0.169 237.323); + --color-sky-600: oklch(0.588 0.158 241.966); + --color-sky-700: oklch(0.5 0.134 242.749); + --color-sky-800: oklch(0.443 0.11 240.79); + --color-sky-900: oklch(0.391 0.09 240.876); + --color-sky-950: oklch(0.293 0.066 243.157); - --color-blue-50: oklch(97% 0.014 254.604); - --color-blue-100: oklch(93.2% 0.032 255.585); - --color-blue-200: oklch(88.2% 0.059 254.128); - --color-blue-300: oklch(80.9% 0.105 251.813); - --color-blue-400: oklch(70.7% 0.165 254.624); - --color-blue-500: oklch(62.3% 0.214 259.815); - --color-blue-600: oklch(54.6% 0.245 262.881); - --color-blue-700: oklch(48.8% 0.243 264.376); - --color-blue-800: oklch(42.4% 0.199 265.638); - --color-blue-900: oklch(37.9% 0.146 265.522); - --color-blue-950: oklch(28.2% 0.091 267.935); + --color-blue-50: oklch(0.97 0.014 254.604); + --color-blue-100: oklch(0.932 0.032 255.585); + --color-blue-200: oklch(0.882 0.059 254.128); + --color-blue-300: oklch(0.809 0.105 251.813); + --color-blue-400: oklch(0.707 0.165 254.624); + --color-blue-500: oklch(0.623 0.214 259.815); + --color-blue-600: oklch(0.546 0.245 262.881); + --color-blue-700: oklch(0.488 0.243 264.376); + --color-blue-800: oklch(0.424 0.199 265.638); + --color-blue-900: oklch(0.379 0.146 265.522); + --color-blue-950: oklch(0.282 0.091 267.935); - --color-indigo-50: oklch(96.2% 0.018 272.314); - --color-indigo-100: oklch(93% 0.034 272.788); - --color-indigo-200: oklch(87% 0.065 274.039); - --color-indigo-300: oklch(78.5% 0.115 274.713); - --color-indigo-400: oklch(67.3% 0.182 276.935); - --color-indigo-500: oklch(58.5% 0.233 277.117); - --color-indigo-600: oklch(51.1% 0.262 276.966); - --color-indigo-700: oklch(45.7% 0.24 277.023); - --color-indigo-800: oklch(39.8% 0.195 277.366); - --color-indigo-900: oklch(35.9% 0.144 278.697); - --color-indigo-950: oklch(25.7% 0.09 281.288); + --color-indigo-50: oklch(0.962 0.018 272.314); + --color-indigo-100: oklch(0.93 0.034 272.788); + --color-indigo-200: oklch(0.87 0.065 274.039); + --color-indigo-300: oklch(0.785 0.115 274.713); + --color-indigo-400: oklch(0.673 0.182 276.935); + --color-indigo-500: oklch(0.585 0.233 277.117); + --color-indigo-600: oklch(0.511 0.262 276.966); + --color-indigo-700: oklch(0.457 0.24 277.023); + --color-indigo-800: oklch(0.398 0.195 277.366); + --color-indigo-900: oklch(0.359 0.144 278.697); + --color-indigo-950: oklch(0.257 0.09 281.288); - --color-violet-50: oklch(96.9% 0.016 293.756); - --color-violet-100: oklch(94.3% 0.029 294.588); - --color-violet-200: oklch(89.4% 0.057 293.283); - --color-violet-300: oklch(81.1% 0.111 293.571); - --color-violet-400: oklch(70.2% 0.183 293.541); - --color-violet-500: oklch(60.6% 0.25 292.717); - --color-violet-600: oklch(54.1% 0.281 293.009); - --color-violet-700: oklch(49.1% 0.27 292.581); - --color-violet-800: oklch(43.2% 0.232 292.759); - --color-violet-900: oklch(38% 0.189 293.745); - --color-violet-950: oklch(28.3% 0.141 291.089); + --color-violet-50: oklch(0.969 0.016 293.756); + --color-violet-100: oklch(0.943 0.029 294.588); + --color-violet-200: oklch(0.894 0.057 293.283); + --color-violet-300: oklch(0.811 0.111 293.571); + --color-violet-400: oklch(0.702 0.183 293.541); + --color-violet-500: oklch(0.606 0.25 292.717); + --color-violet-600: oklch(0.541 0.281 293.009); + --color-violet-700: oklch(0.491 0.27 292.581); + --color-violet-800: oklch(0.432 0.232 292.759); + --color-violet-900: oklch(0.38 0.189 293.745); + --color-violet-950: oklch(0.283 0.141 291.089); - --color-purple-50: oklch(97.7% 0.014 308.299); - --color-purple-100: oklch(94.6% 0.033 307.174); - --color-purple-200: oklch(90.2% 0.063 306.703); - --color-purple-300: oklch(82.7% 0.119 306.383); - --color-purple-400: oklch(71.4% 0.203 305.504); - --color-purple-500: oklch(62.7% 0.265 303.9); - --color-purple-600: oklch(55.8% 0.288 302.321); - --color-purple-700: oklch(49.6% 0.265 301.924); - --color-purple-800: oklch(43.8% 0.218 303.724); - --color-purple-900: oklch(38.1% 0.176 304.987); - --color-purple-950: oklch(29.1% 0.149 302.717); + --color-purple-50: oklch(0.977 0.014 308.299); + --color-purple-100: oklch(0.946 0.033 307.174); + --color-purple-200: oklch(0.902 0.063 306.703); + --color-purple-300: oklch(0.827 0.119 306.383); + --color-purple-400: oklch(0.714 0.203 305.504); + --color-purple-500: oklch(0.627 0.265 303.9); + --color-purple-600: oklch(0.558 0.288 302.321); + --color-purple-700: oklch(0.496 0.265 301.924); + --color-purple-800: oklch(0.438 0.218 303.724); + --color-purple-900: oklch(0.381 0.176 304.987); + --color-purple-950: oklch(0.291 0.149 302.717); - --color-fuchsia-50: oklch(97.7% 0.017 320.058); - --color-fuchsia-100: oklch(95.2% 0.037 318.852); - --color-fuchsia-200: oklch(90.3% 0.076 319.62); - --color-fuchsia-300: oklch(83.3% 0.145 321.434); - --color-fuchsia-400: oklch(74% 0.238 322.16); - --color-fuchsia-500: oklch(66.7% 0.295 322.15); - --color-fuchsia-600: oklch(59.1% 0.293 322.896); - --color-fuchsia-700: oklch(51.8% 0.253 323.949); - --color-fuchsia-800: oklch(45.2% 0.211 324.591); - --color-fuchsia-900: oklch(40.1% 0.17 325.612); - --color-fuchsia-950: oklch(29.3% 0.136 325.661); + --color-fuchsia-50: oklch(0.977 0.017 320.058); + --color-fuchsia-100: oklch(0.952 0.037 318.852); + --color-fuchsia-200: oklch(0.903 0.076 319.62); + --color-fuchsia-300: oklch(0.833 0.145 321.434); + --color-fuchsia-400: oklch(0.74 0.238 322.16); + --color-fuchsia-500: oklch(0.667 0.295 322.15); + --color-fuchsia-600: oklch(0.591 0.293 322.896); + --color-fuchsia-700: oklch(0.518 0.253 323.949); + --color-fuchsia-800: oklch(0.452 0.211 324.591); + --color-fuchsia-900: oklch(0.401 0.17 325.612); + --color-fuchsia-950: oklch(0.293 0.136 325.661); - --color-pink-50: oklch(97.1% 0.014 343.198); - --color-pink-100: oklch(94.8% 0.028 342.258); - --color-pink-200: oklch(89.9% 0.061 343.231); - --color-pink-300: oklch(82.3% 0.12 346.018); - --color-pink-400: oklch(71.8% 0.202 349.761); - --color-pink-500: oklch(65.6% 0.241 354.308); - --color-pink-600: oklch(59.2% 0.249 0.584); - --color-pink-700: oklch(52.5% 0.223 3.958); - --color-pink-800: oklch(45.9% 0.187 3.815); - --color-pink-900: oklch(40.8% 0.153 2.432); - --color-pink-950: oklch(28.4% 0.109 3.907); + --color-pink-50: oklch(0.971 0.014 343.198); + --color-pink-100: oklch(0.948 0.028 342.258); + --color-pink-200: oklch(0.899 0.061 343.231); + --color-pink-300: oklch(0.823 0.12 346.018); + --color-pink-400: oklch(0.718 0.202 349.761); + --color-pink-500: oklch(0.656 0.241 354.308); + --color-pink-600: oklch(0.592 0.249 0.584); + --color-pink-700: oklch(0.525 0.223 3.958); + --color-pink-800: oklch(0.459 0.187 3.815); + --color-pink-900: oklch(0.408 0.153 2.432); + --color-pink-950: oklch(0.284 0.109 3.907); - --color-rose-50: oklch(96.9% 0.015 12.422); - --color-rose-100: oklch(94.1% 0.03 12.58); - --color-rose-200: oklch(89.2% 0.058 10.001); - --color-rose-300: oklch(81% 0.117 11.638); - --color-rose-400: oklch(71.2% 0.194 13.428); - --color-rose-500: oklch(64.5% 0.246 16.439); - --color-rose-600: oklch(58.6% 0.253 17.585); - --color-rose-700: oklch(51.4% 0.222 16.935); - --color-rose-800: oklch(45.5% 0.188 13.697); - --color-rose-900: oklch(41% 0.159 10.272); - --color-rose-950: oklch(27.1% 0.105 12.094); + --color-rose-50: oklch(0.969 0.015 12.422); + --color-rose-100: oklch(0.941 0.03 12.58); + --color-rose-200: oklch(0.892 0.058 10.001); + --color-rose-300: oklch(0.81 0.117 11.638); + --color-rose-400: oklch(0.712 0.194 13.428); + --color-rose-500: oklch(0.645 0.246 16.439); + --color-rose-600: oklch(0.586 0.253 17.585); + --color-rose-700: oklch(0.514 0.222 16.935); + --color-rose-800: oklch(0.455 0.188 13.697); + --color-rose-900: oklch(0.41 0.159 10.272); + --color-rose-950: oklch(0.271 0.105 12.094); - --color-slate-50: oklch(98.4% 0.003 247.858); - --color-slate-100: oklch(96.8% 0.007 247.896); - --color-slate-200: oklch(92.9% 0.013 255.508); - --color-slate-300: oklch(86.9% 0.022 252.894); - --color-slate-400: oklch(70.4% 0.04 256.788); - --color-slate-500: oklch(55.4% 0.046 257.417); - --color-slate-600: oklch(44.6% 0.043 257.281); - --color-slate-700: oklch(37.2% 0.044 257.287); - --color-slate-800: oklch(27.9% 0.041 260.031); - --color-slate-900: oklch(20.8% 0.042 265.755); - --color-slate-950: oklch(12.9% 0.042 264.695); + --color-slate-50: oklch(0.984 0.003 247.858); + --color-slate-100: oklch(0.968 0.007 247.896); + --color-slate-200: oklch(0.929 0.013 255.508); + --color-slate-300: oklch(0.869 0.022 252.894); + --color-slate-400: oklch(0.704 0.04 256.788); + --color-slate-500: oklch(0.554 0.046 257.417); + --color-slate-600: oklch(0.446 0.043 257.281); + --color-slate-700: oklch(0.372 0.044 257.287); + --color-slate-800: oklch(0.279 0.041 260.031); + --color-slate-900: oklch(0.208 0.042 265.755); + --color-slate-950: oklch(0.129 0.042 264.695); - --color-gray-50: oklch(98.5% 0.002 247.839); - --color-gray-100: oklch(96.7% 0.003 264.542); - --color-gray-200: oklch(92.8% 0.006 264.531); - --color-gray-300: oklch(87.2% 0.01 258.338); - --color-gray-400: oklch(70.7% 0.022 261.325); - --color-gray-500: oklch(55.1% 0.027 264.364); - --color-gray-600: oklch(44.6% 0.03 256.802); - --color-gray-700: oklch(37.3% 0.034 259.733); - --color-gray-800: oklch(27.8% 0.033 256.848); - --color-gray-900: oklch(21% 0.034 264.665); - --color-gray-950: oklch(13% 0.028 261.692); + --color-gray-50: oklch(0.985 0.002 247.839); + --color-gray-100: oklch(0.967 0.003 264.542); + --color-gray-200: oklch(0.928 0.006 264.531); + --color-gray-300: oklch(0.872 0.01 258.338); + --color-gray-400: oklch(0.707 0.022 261.325); + --color-gray-500: oklch(0.551 0.027 264.364); + --color-gray-600: oklch(0.446 0.03 256.802); + --color-gray-700: oklch(0.373 0.034 259.733); + --color-gray-800: oklch(0.278 0.033 256.848); + --color-gray-900: oklch(0.21 0.034 264.665); + --color-gray-950: oklch(0.13 0.028 261.692); - --color-zinc-50: oklch(98.5% 0 none); - --color-zinc-100: oklch(96.7% 0.001 286.375); - --color-zinc-200: oklch(92% 0.004 286.32); - --color-zinc-300: oklch(87.1% 0.006 286.286); - --color-zinc-400: oklch(70.5% 0.015 286.067); - --color-zinc-500: oklch(55.2% 0.016 285.938); - --color-zinc-600: oklch(44.2% 0.017 285.786); - --color-zinc-700: oklch(37% 0.013 285.805); - --color-zinc-800: oklch(27.4% 0.006 286.033); - --color-zinc-900: oklch(21% 0.006 285.885); - --color-zinc-950: oklch(14.1% 0.005 285.823); + --color-zinc-50: oklch(0.985 0 0); + --color-zinc-100: oklch(0.967 0.001 286.375); + --color-zinc-200: oklch(0.92 0.004 286.32); + --color-zinc-300: oklch(0.871 0.006 286.286); + --color-zinc-400: oklch(0.705 0.015 286.067); + --color-zinc-500: oklch(0.552 0.016 285.938); + --color-zinc-600: oklch(0.442 0.017 285.786); + --color-zinc-700: oklch(0.37 0.013 285.805); + --color-zinc-800: oklch(0.274 0.006 286.033); + --color-zinc-900: oklch(0.21 0.006 285.885); + --color-zinc-950: oklch(0.141 0.005 285.823); - --color-neutral-50: oklch(98.5% 0 none); - --color-neutral-100: oklch(97% 0 none); - --color-neutral-200: oklch(92.2% 0 none); - --color-neutral-300: oklch(87% 0 none); - --color-neutral-400: oklch(70.8% 0 none); - --color-neutral-500: oklch(55.6% 0 none); - --color-neutral-600: oklch(43.9% 0 none); - --color-neutral-700: oklch(37.1% 0 none); - --color-neutral-800: oklch(26.9% 0 none); - --color-neutral-900: oklch(20.5% 0 none); - --color-neutral-950: oklch(14.5% 0 none); + --color-neutral-50: oklch(0.985 0 0); + --color-neutral-100: oklch(0.97 0 0); + --color-neutral-200: oklch(0.922 0 0); + --color-neutral-300: oklch(0.87 0 0); + --color-neutral-400: oklch(0.708 0 0); + --color-neutral-500: oklch(0.556 0 0); + --color-neutral-600: oklch(0.439 0 0); + --color-neutral-700: oklch(0.371 0 0); + --color-neutral-800: oklch(0.269 0 0); + --color-neutral-900: oklch(0.205 0 0); + --color-neutral-950: oklch(0.145 0 0); - --color-stone-50: oklch(98.5% 0.001 106.423); - --color-stone-100: oklch(97% 0.001 106.424); - --color-stone-200: oklch(92.3% 0.003 48.717); - --color-stone-300: oklch(86.9% 0.005 56.366); - --color-stone-400: oklch(70.9% 0.01 56.259); - --color-stone-500: oklch(55.3% 0.013 58.071); - --color-stone-600: oklch(44.4% 0.011 73.639); - --color-stone-700: oklch(37.4% 0.01 67.558); - --color-stone-800: oklch(26.8% 0.007 34.298); - --color-stone-900: oklch(21.6% 0.006 56.043); - --color-stone-950: oklch(14.7% 0.004 49.25); - - --color-mauve-50: oklch(98.5% 0 none); - --color-mauve-100: oklch(96% 0.003 325.6); - --color-mauve-200: oklch(92.2% 0.005 325.62); - --color-mauve-300: oklch(86.5% 0.012 325.68); - --color-mauve-400: oklch(71.1% 0.019 323.02); - --color-mauve-500: oklch(54.2% 0.034 322.5); - --color-mauve-600: oklch(43.5% 0.029 321.78); - --color-mauve-700: oklch(36.4% 0.029 323.89); - --color-mauve-800: oklch(26.3% 0.024 320.12); - --color-mauve-900: oklch(21.2% 0.019 322.12); - --color-mauve-950: oklch(14.5% 0.008 326); - - --color-olive-50: oklch(98.8% 0.003 106.5); - --color-olive-100: oklch(96.6% 0.005 106.5); - --color-olive-200: oklch(93% 0.007 106.5); - --color-olive-300: oklch(88% 0.011 106.6); - --color-olive-400: oklch(73.7% 0.021 106.9); - --color-olive-500: oklch(58% 0.031 107.3); - --color-olive-600: oklch(46.6% 0.025 107.3); - --color-olive-700: oklch(39.4% 0.023 107.4); - --color-olive-800: oklch(28.6% 0.016 107.4); - --color-olive-900: oklch(22.8% 0.013 107.4); - --color-olive-950: oklch(15.3% 0.006 107.1); - - --color-mist-50: oklch(98.7% 0.002 197.1); - --color-mist-100: oklch(96.3% 0.002 197.1); - --color-mist-200: oklch(92.5% 0.005 214.3); - --color-mist-300: oklch(87.2% 0.007 219.6); - --color-mist-400: oklch(72.3% 0.014 214.4); - --color-mist-500: oklch(56% 0.021 213.5); - --color-mist-600: oklch(45% 0.017 213.2); - --color-mist-700: oklch(37.8% 0.015 216); - --color-mist-800: oklch(27.5% 0.011 216.9); - --color-mist-900: oklch(21.8% 0.008 223.9); - --color-mist-950: oklch(14.8% 0.004 228.8); - - --color-taupe-50: oklch(98.6% 0.002 67.8); - --color-taupe-100: oklch(96% 0.002 17.2); - --color-taupe-200: oklch(92.2% 0.005 34.3); - --color-taupe-300: oklch(86.8% 0.007 39.5); - --color-taupe-400: oklch(71.4% 0.014 41.2); - --color-taupe-500: oklch(54.7% 0.021 43.1); - --color-taupe-600: oklch(43.8% 0.017 39.3); - --color-taupe-700: oklch(36.7% 0.016 35.7); - --color-taupe-800: oklch(26.8% 0.011 36.5); - --color-taupe-900: oklch(21.4% 0.009 43.1); - --color-taupe-950: oklch(14.7% 0.004 49.3); + --color-stone-50: oklch(0.985 0.001 106.423); + --color-stone-100: oklch(0.97 0.001 106.424); + --color-stone-200: oklch(0.923 0.003 48.717); + --color-stone-300: oklch(0.869 0.005 56.366); + --color-stone-400: oklch(0.709 0.01 56.259); + --color-stone-500: oklch(0.553 0.013 58.071); + --color-stone-600: oklch(0.444 0.011 73.639); + --color-stone-700: oklch(0.374 0.01 67.558); + --color-stone-800: oklch(0.268 0.007 34.298); + --color-stone-900: oklch(0.216 0.006 56.043); + --color-stone-950: oklch(0.147 0.004 49.25); --color-black: #000; --color-white: #fff; @@ -343,6 +293,7 @@ --container-5xl: 64rem; --container-6xl: 72rem; --container-7xl: 80rem; + --container-prose: 65ch; --text-xs: 0.75rem; --text-xs--line-height: calc(1 / 0.75); @@ -422,15 +373,6 @@ --drop-shadow-xl: 0 9px 7px rgb(0 0 0 / 0.1); --drop-shadow-2xl: 0 25px 25px rgb(0 0 0 / 0.15); - --text-shadow-2xs: 0px 1px 0px rgb(0 0 0 / 0.15); - --text-shadow-xs: 0px 1px 1px rgb(0 0 0 / 0.2); - --text-shadow-sm: - 0px 1px 0px rgb(0 0 0 / 0.075), 0px 1px 1px rgb(0 0 0 / 0.075), 0px 2px 2px rgb(0 0 0 / 0.075); - --text-shadow-md: - 0px 1px 1px rgb(0 0 0 / 0.1), 0px 1px 2px rgb(0 0 0 / 0.1), 0px 2px 4px rgb(0 0 0 / 0.1); - --text-shadow-lg: - 0px 1px 2px rgb(0 0 0 / 0.1), 0px 3px 2px rgb(0 0 0 / 0.1), 0px 4px 8px rgb(0 0 0 / 0.1); - --ease-in: cubic-bezier(0.4, 0, 1, 1); --ease-out: cubic-bezier(0, 0, 0.2, 1); --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1); @@ -491,12 +433,12 @@ --default-transition-duration: 150ms; --default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); - --default-font-family: --theme(--font-sans, initial); - --default-font-feature-settings: --theme(--font-sans--font-feature-settings, initial); - --default-font-variation-settings: --theme(--font-sans--font-variation-settings, initial); - --default-mono-font-family: --theme(--font-mono, initial); - --default-mono-font-feature-settings: --theme(--font-mono--font-feature-settings, initial); - --default-mono-font-variation-settings: --theme(--font-mono--font-variation-settings, initial); + --default-font-family: var(--font-sans); + --default-font-feature-settings: var(--font-sans--font-feature-settings); + --default-font-variation-settings: var(--font-sans--font-variation-settings); + --default-mono-font-family: var(--font-mono); + --default-mono-font-feature-settings: var(--font-mono--font-feature-settings); + --default-mono-font-variation-settings: var(--font-mono--font-variation-settings); } /* Deprecated */ @@ -506,5 +448,4 @@ --shadow-inner: inset 0 2px 4px 0 rgb(0 0 0 / 0.05); --drop-shadow: 0 1px 2px rgb(0 0 0 / 0.1), 0 1px 1px rgb(0 0 0 / 0.06); --radius: 0.25rem; - --max-width-prose: 65ch; } diff --git a/packages/tailwindcss/tsconfig.json b/packages/tailwindcss/tsconfig.json index d2131cbeb..6ae022f65 100644 --- a/packages/tailwindcss/tsconfig.json +++ b/packages/tailwindcss/tsconfig.json @@ -1,6 +1,3 @@ { "extends": "../tsconfig.base.json", - "compilerOptions": { - "verbatimModuleSyntax": false, - }, } diff --git a/packages/tailwindcss/tsup.config.ts b/packages/tailwindcss/tsup.config.ts index 6bc831056..59c8bdfa2 100644 --- a/packages/tailwindcss/tsup.config.ts +++ b/packages/tailwindcss/tsup.config.ts @@ -12,9 +12,6 @@ export default defineConfig([ 'default-theme': 'src/compat/default-theme.ts', 'flatten-color-palette': 'src/compat/flatten-color-palette.ts', }, - define: { - 'process.env.FEATURES_ENV': JSON.stringify(process.env.FEATURES_ENV ?? 'insiders'), - }, }, { format: ['cjs'], @@ -27,8 +24,5 @@ export default defineConfig([ 'default-theme': 'src/compat/default-theme.cts', 'flatten-color-palette': 'src/compat/flatten-color-palette.cts', }, - define: { - 'process.env.FEATURES_ENV': JSON.stringify(process.env.FEATURES_ENV ?? 'insiders'), - }, }, ]) diff --git a/packages/tailwindcss/vitest.config.mts b/packages/tailwindcss/vitest.config.ts similarity index 100% rename from packages/tailwindcss/vitest.config.mts rename to packages/tailwindcss/vitest.config.ts diff --git a/patches/@napi-rs__cli@3.7.4.patch b/patches/@napi-rs__cli@3.7.4.patch deleted file mode 100644 index e72212499..000000000 --- a/patches/@napi-rs__cli@3.7.4.patch +++ /dev/null @@ -1,80 +0,0 @@ -diff --git a/dist/cli.js b/dist/cli.js -index c4c2d568bc070c07dbf3a1f9f4a0c946466668cf..353bbca86e3261a2ba9a8fc56dc612c7c84dab6d 100755 ---- a/dist/cli.js -+++ b/dist/cli.js -@@ -1,4 +1,13 @@ - #!/usr/bin/env node -+// PATCHED (see patches/@napi-rs__cli@3.7.4.patch): the embedded wasi loader -+// and worker templates below retry `new WASI(...)` with narrower preopens, -+// because preopening `/` throws `UVWASI_EACCES` on sandboxed platforms (e.g. -+// OpenHarmony), which would make the generated wasm binding fail to load. -+// -+// The same templates also exist in `dist/index.js` and `dist/index.cjs` (the -+// programmatic API). Those are intentionally NOT patched because we only -+// build through the `napi` bin, which runs this file. If we ever start using -+// the programmatic API, update the patch to cover those bundles too. - import { createRequire } from "node:module"; - import { Cli, Command, Option } from "clipanion"; - import path, { basename, dirname, isAbsolute, join, parse, resolve } from "node:path"; -@@ -1021,13 +1030,25 @@ const { - - const __rootDir = __nodePath.parse(process.cwd()).root - --const __wasi = new __nodeWASI({ -- version: 'preview1', -- env: process.env, -- preopens: { -- [__rootDir]: __rootDir, -+const __wasi = (() => { -+ // Preopening '/' fails with UVWASI_EACCES in sandboxed environments (e.g. -+ // OpenHarmony, Android), which would prevent the wasm binding from loading -+ // at all. Retry with narrower preopens instead. Without any preopens the -+ // binding still loads; only file system access is unavailable. -+ let lastError = null -+ for (const dir of [__rootDir, process.cwd(), null]) { -+ try { -+ return new __nodeWASI({ -+ version: 'preview1', -+ env: process.env, -+ preopens: dir === null ? {} : { [dir]: dir }, -+ }) -+ } catch (error) { -+ lastError = error -+ } - } --}) -+ throw lastError -+})() - - const __emnapiContext = __emnapiGetDefaultContext() - -@@ -1151,13 +1172,22 @@ const __rootDir = parse(process.cwd()).root; - - const handler = new MessageHandler({ - onLoad({ wasmModule, wasmMemory }) { -- const wasi = new WASI({ -- version: 'preview1', -- env: process.env, -- preopens: { -- [__rootDir]: __rootDir, -- }, -- }); -+ // Keep in sync with the preopen fallback in the main-thread loader. -+ const wasi = (() => { -+ let lastError = null; -+ for (const dir of [__rootDir, process.cwd(), null]) { -+ try { -+ return new WASI({ -+ version: 'preview1', -+ env: process.env, -+ preopens: dir === null ? {} : { [dir]: dir }, -+ }); -+ } catch (error) { -+ lastError = error; -+ } -+ } -+ throw lastError; -+ })(); - - return instantiateNapiModuleSync(wasmModule, { - childThread: true, diff --git a/patches/@parcel__watcher@2.5.0.patch b/patches/@parcel__watcher@2.5.0.patch new file mode 100644 index 000000000..4f0f223ff --- /dev/null +++ b/patches/@parcel__watcher@2.5.0.patch @@ -0,0 +1,67 @@ +diff --git a/index.js b/index.js +index 8afb2b1126dcc687b7ff9b631589da252c1f9c22..f3b1158eb5612235388ff5f5347f6edcbf323090 100644 +--- a/index.js ++++ b/index.js +@@ -1,41 +1,27 @@ +-const {createWrapper} = require('./wrapper'); ++const { createWrapper } = require('./wrapper') + +-let name = `@parcel/watcher-${process.platform}-${process.arch}`; +-if (process.platform === 'linux') { +- const { MUSL, family } = require('detect-libc'); +- if (family === MUSL) { +- name += '-musl'; +- } else { +- name += '-glibc'; +- } +-} ++function loadPackage() { ++ if (process.platform === 'linux') { ++ let { MUSL, GLIBC, family, familySync } = require('detect-libc') ++ // Bun polyfills `detect-libc` in compiled binaries. We rely on ++ // detect-libc@1.0.3 but the polyfilled version is 2.x. In detect-libc@2x ++ // there is a `familySync` function that we can use instead. ++ if (typeof familySync === 'function') family = familySync() + +-let binding; +-try { +- binding = require(name); +-} catch (err) { +- handleError(err); +- try { +- binding = require('./build/Release/watcher.node'); +- } catch (err) { +- handleError(err); +- try { +- binding = require('./build/Debug/watcher.node'); +- } catch (err) { +- handleError(err); +- throw new Error(`No prebuild or local build of @parcel/watcher found. Tried ${name}. Please ensure it is installed (don't use --no-optional when installing with npm). Otherwise it is possible we don't support your platform yet. If this is the case, please report an issue to https://github.com/parcel-bundler/watcher.`); ++ if (family === MUSL) { ++ return require(`@parcel/watcher-${process.platform}-${process.arch}-musl`) ++ } else if (family === GLIBC) { ++ return require(`@parcel/watcher-${process.platform}-${process.arch}-glibc`) ++ } else { ++ throw new Error(`Unsupported libc on: ${process.platform}-${process.arch}`) + } ++ } else { ++ return require(`@parcel/watcher-${process.platform}-${process.arch}`) + } + } + +-function handleError(err) { +- if (err?.code !== 'MODULE_NOT_FOUND') { +- throw err; +- } +-} +- +-const wrapper = createWrapper(binding); +-exports.writeSnapshot = wrapper.writeSnapshot; +-exports.getEventsSince = wrapper.getEventsSince; +-exports.subscribe = wrapper.subscribe; +-exports.unsubscribe = wrapper.unsubscribe; ++const wrapper = createWrapper(loadPackage()) ++exports.writeSnapshot = wrapper.writeSnapshot ++exports.getEventsSince = wrapper.getEventsSince ++exports.subscribe = wrapper.subscribe ++exports.unsubscribe = wrapper.unsubscribe diff --git a/patches/@parcel__watcher@2.6.0.patch b/patches/@parcel__watcher@2.6.0.patch deleted file mode 100644 index 37ff83f04..000000000 --- a/patches/@parcel__watcher@2.6.0.patch +++ /dev/null @@ -1,70 +0,0 @@ -diff --git a/index.js b/index.js -index 78ee744d74900c39a839cafa46b295258fc86307..f28fd092644ccfb8aff2618b966cb5219a181a02 100644 ---- a/index.js -+++ b/index.js -@@ -1,43 +1,32 @@ - const {createWrapper} = require('./wrapper'); - --let name = `@parcel/watcher-${process.platform}-${process.arch}`; --if (process.platform === 'linux') { -- const {MUSL, familySync} = require('detect-libc'); -- const family = familySync(); -- if (family === MUSL) { -- name += '-musl'; -- } else { -- name += '-glibc'; -- } --} -+// We need to take the `process.env.PLATFORM_LIBC` into account, and we also -+// need static analysis, so we can't make use of the `parts.push(…)` approach. -+function loadPackage() { -+ if (process.platform === 'linux') { -+ if (process.env.PLATFORM_LIBC === "musl") { -+ return require(`@parcel/watcher-${process.platform}-${process.arch}-musl`) -+ } else if (process.env.PLATFORM_LIBC === "glibc") { -+ return require(`@parcel/watcher-${process.platform}-${process.arch}-glibc`) -+ } else { -+ let { MUSL, GLIBC, familySync } = require('detect-libc') -+ let family = familySync() - --let binding; --try { -- binding = require(name); --} catch (err) { -- handleError(err); -- try { -- binding = require('./build/Release/watcher.node'); -- } catch (err) { -- handleError(err); -- try { -- binding = require('./build/Debug/watcher.node'); -- } catch (err) { -- handleError(err); -- throw new Error( -- `No prebuild or local build of @parcel/watcher found. Tried ${name}. Please ensure it is installed (don't use --no-optional when installing with npm). Otherwise it is possible we don't support your platform yet. If this is the case, please report an issue to https://github.com/parcel-bundler/watcher.`, -- ); -- } -- } --} - --function handleError(err) { -- if (err?.code !== 'MODULE_NOT_FOUND') { -- throw err; -+ if (family === MUSL) { -+ return require(`@parcel/watcher-${process.platform}-${process.arch}-musl`) -+ } else if (family === GLIBC) { -+ return require(`@parcel/watcher-${process.platform}-${process.arch}-glibc`) -+ } else { -+ throw new Error(`Unsupported libc on: ${process.platform}-${process.arch}`) -+ } -+ } -+ } else { -+ return require(`@parcel/watcher-${process.platform}-${process.arch}`) - } - } - --const wrapper = createWrapper(binding); -+const wrapper = createWrapper(loadPackage()); - exports.writeSnapshot = wrapper.writeSnapshot; - exports.getEventsSince = wrapper.getEventsSince; - exports.subscribe = wrapper.subscribe; diff --git a/patches/lightningcss@1.26.0.patch b/patches/lightningcss@1.26.0.patch new file mode 100644 index 000000000..1b83d90c8 --- /dev/null +++ b/patches/lightningcss@1.26.0.patch @@ -0,0 +1,60 @@ +diff --git a/node/index.js b/node/index.js +index a9f2f6d5f3394329fcf8bc06af549030c01167a5..b92cc804adb694dbb17ee48368f13a03dd729267 100644 +--- a/node/index.js ++++ b/node/index.js +@@ -1,27 +1,32 @@ +-let parts = [process.platform, process.arch]; +-if (process.platform === 'linux') { +- const { MUSL, family } = require('detect-libc'); +- if (family === MUSL) { +- parts.push('musl'); +- } else if (process.arch === 'arm') { +- parts.push('gnueabihf'); +- } else { +- parts.push('gnu'); +- } +-} else if (process.platform === 'win32') { +- parts.push('msvc'); +-} ++function loadPackage() { ++ if (process.platform === "linux") { ++ let { MUSL, GLIBC, family, familySync } = require("detect-libc"); ++ // Bun polyfills `detect-libc` in compiled binaries. We rely on ++ // detect-libc@1.0.3 but the polyfilled version is 2.x. In detect-libc@2x ++ // there is a `familySync` function that we can use instead. ++ if (typeof familySync === 'function') family = familySync() + +-if (process.env.CSS_TRANSFORMER_WASM) { +- module.exports = require(`../pkg`); +-} else { +- try { +- module.exports = require(`lightningcss-${parts.join('-')}`); +- } catch (err) { +- module.exports = require(`../lightningcss.${parts.join('-')}.node`); ++ if (family === MUSL) { ++ return require(`lightningcss-${process.platform}-${process.arch}-musl`); ++ } else if (family === GLIBC) { ++ if (process.arch === "arm") { ++ return require(`lightningcss-${process.platform}-${process.arch}-gnueabihf`); ++ } else { ++ return require(`lightningcss-${process.platform}-${process.arch}-gnu`); ++ } ++ } else { ++ throw new Error( ++ `Unsupported libc on: ${process.platform}-${process.arch}` ++ ); ++ } ++ } else if (process.platform === "win32") { ++ return require(`lightningcss-${process.platform}-${process.arch}-msvc`); ++ } else { ++ return require(`lightningcss-${process.platform}-${process.arch}`); + } + } + +-module.exports.browserslistToTargets = require('./browserslistToTargets'); +-module.exports.composeVisitors = require('./composeVisitors'); +-module.exports.Features = require('./flags').Features; ++module.exports = loadPackage(); ++module.exports.browserslistToTargets = require("./browserslistToTargets"); ++module.exports.composeVisitors = require("./composeVisitors"); ++module.exports.Features = require("./flags").Features; diff --git a/patches/lightningcss@1.33.0.patch b/patches/lightningcss@1.33.0.patch deleted file mode 100644 index e70be2315..000000000 --- a/patches/lightningcss@1.33.0.patch +++ /dev/null @@ -1,62 +0,0 @@ -diff --git a/node/index.js b/node/index.js -index 6fe25aef457aa5448f9ee6204da1e253f5534800..742be0229b94450b631b6e069ffc372d2b35df47 100644 ---- a/node/index.js -+++ b/node/index.js -@@ -1,25 +1,40 @@ --let parts = [process.platform, process.arch]; --if (process.platform === 'linux') { -- const { MUSL, familySync } = require('detect-libc'); -- const family = familySync(); -- if (family === MUSL) { -- parts.push('musl'); -- } else if (process.arch === 'arm') { -- parts.push('gnueabihf'); -+// We need to take the `process.env.PLATFORM_LIBC` into account, and we also -+// need static analysis, so we can't make use of the `parts.push(…)` approach. -+function loadPackage() { -+ if (process.platform === 'linux') { -+ if (process.env.PLATFORM_LIBC === 'musl') { -+ return require(`lightningcss-${process.platform}-${process.arch}-musl`) -+ } else if (process.env.PLATFORM_LIBC === 'glibc') { -+ if (process.arch === 'arm') { -+ return require(`lightningcss-${process.platform}-${process.arch}-gnueabihf`) -+ } else { -+ return require(`lightningcss-${process.platform}-${process.arch}-gnu`) -+ } -+ } else { -+ let { MUSL, GLIBC, familySync } = require('detect-libc') -+ let family = familySync() -+ -+ if (family === MUSL) { -+ return require(`lightningcss-${process.platform}-${process.arch}-musl`) -+ } else if (family === GLIBC) { -+ if (process.arch === 'arm') { -+ return require(`lightningcss-${process.platform}-${process.arch}-gnueabihf`) -+ } else { -+ return require(`lightningcss-${process.platform}-${process.arch}-gnu`) -+ } -+ } else { -+ throw new Error(`Unsupported libc on: ${process.platform}-${process.arch}`) -+ } -+ } -+ } else if (process.platform === 'win32') { -+ return require(`lightningcss-${process.platform}-${process.arch}-msvc`) - } else { -- parts.push('gnu'); -+ return require(`lightningcss-${process.platform}-${process.arch}`) - } --} else if (process.platform === 'win32') { -- parts.push('msvc'); - } - --let native; --try { -- native = require(`lightningcss-${parts.join('-')}`); --} catch (err) { -- native = require(`../lightningcss.${parts.join('-')}.node`); --} - -+let native = loadPackage(); - module.exports.transform = wrap(native.transform); - module.exports.transformStyleAttribute = wrap(native.transformStyleAttribute); - module.exports.bundle = wrap(native.bundle); diff --git a/playgrounds/nextjs/app/layout.tsx b/playgrounds/nextjs/app/layout.tsx index 41ee7f492..cf832e94e 100644 --- a/playgrounds/nextjs/app/layout.tsx +++ b/playgrounds/nextjs/app/layout.tsx @@ -15,7 +15,7 @@ export default function RootLayout({ children: React.ReactNode }>) { return ( - + {/* */} {children} diff --git a/playgrounds/nextjs/app/page.module.css b/playgrounds/nextjs/app/page.module.css index b0117f44c..e0c1bf51e 100644 --- a/playgrounds/nextjs/app/page.module.css +++ b/playgrounds/nextjs/app/page.module.css @@ -1,5 +1,228 @@ -@reference "./globals.css"; - -.heading { - @apply text-red-500; +.main { + display: flex; + flex-direction: column; + justify-content: space-between; + align-items: center; + padding: 6rem; + min-height: 100vh; +} + +.description { + display: inherit; + justify-content: inherit; + align-items: inherit; + font-size: 0.85rem; + max-width: var(--max-width); + width: 100%; + z-index: 2; + font-family: var(--font-mono); +} + +.description a { + display: flex; + justify-content: center; + align-items: center; + gap: 0.5rem; +} + +.description p { + position: relative; + margin: 0; + padding: 1rem; + background-color: rgba(var(--callout-rgb), 0.5); + border: 1px solid rgba(var(--callout-border-rgb), 0.3); + border-radius: var(--border-radius); +} + +.code { + font-weight: 700; + font-family: var(--font-mono); +} + +.grid { + display: grid; + grid-template-columns: repeat(4, minmax(25%, auto)); + max-width: 100%; + width: var(--max-width); +} + +.card { + padding: 1rem 1.2rem; + border-radius: var(--border-radius); + background: rgba(var(--card-rgb), 0); + border: 1px solid rgba(var(--card-border-rgb), 0); + transition: + background 200ms, + border 200ms; +} + +.card span { + display: inline-block; + transition: transform 200ms; +} + +.card h2 { + font-weight: 600; + margin-bottom: 0.7rem; +} + +.card p { + margin: 0; + opacity: 0.6; + font-size: 0.9rem; + line-height: 1.5; + max-width: 30ch; + text-wrap: balance; +} + +.center { + display: flex; + justify-content: center; + align-items: center; + position: relative; + padding: 4rem 0; +} + +.center::before { + background: var(--secondary-glow); + border-radius: 50%; + width: 480px; + height: 360px; + margin-left: -400px; +} + +.center::after { + background: var(--primary-glow); + width: 240px; + height: 180px; + z-index: -1; +} + +.center::before, +.center::after { + content: ''; + left: 50%; + position: absolute; + filter: blur(45px); + transform: translateZ(0); +} + +.logo { + position: relative; +} +/* Enable hover only on non-touch devices */ +@media (hover: hover) and (pointer: fine) { + .card:hover { + background: rgba(var(--card-rgb), 0.1); + border: 1px solid rgba(var(--card-border-rgb), 0.15); + } + + .card:hover span { + transform: translateX(4px); + } +} + +@media (prefers-reduced-motion) { + .card:hover span { + transform: none; + } +} + +/* Mobile */ +@media (max-width: 700px) { + .content { + padding: 4rem; + } + + .grid { + grid-template-columns: 1fr; + margin-bottom: 120px; + max-width: 320px; + text-align: center; + } + + .card { + padding: 1rem 2.5rem; + } + + .card h2 { + margin-bottom: 0.5rem; + } + + .center { + padding: 8rem 0 6rem; + } + + .center::before { + transform: none; + height: 300px; + } + + .description { + font-size: 0.8rem; + } + + .description a { + padding: 1rem; + } + + .description p, + .description div { + display: flex; + justify-content: center; + position: fixed; + width: 100%; + } + + .description p { + align-items: center; + inset: 0 0 auto; + padding: 2rem 1rem 1.4rem; + border-radius: 0; + border: none; + border-bottom: 1px solid rgba(var(--callout-border-rgb), 0.25); + background: linear-gradient( + to bottom, + rgba(var(--background-start-rgb), 1), + rgba(var(--callout-rgb), 0.5) + ); + background-clip: padding-box; + backdrop-filter: blur(24px); + } + + .description div { + align-items: flex-end; + pointer-events: none; + inset: auto 0 0; + padding: 2rem; + height: 200px; + background: linear-gradient(to bottom, transparent 0%, rgb(var(--background-end-rgb)) 40%); + z-index: 1; + } +} + +/* Tablet and Smaller Desktop */ +@media (min-width: 701px) and (max-width: 1120px) { + .grid { + grid-template-columns: repeat(2, 50%); + } +} + +@media (prefers-color-scheme: dark) { + .vercelLogo { + filter: invert(1); + } + + .logo { + filter: invert(1) drop-shadow(0 0 0.3rem #ffffff70); + } +} + +@keyframes rotate { + from { + transform: rotate(360deg); + } + to { + transform: rotate(0deg); + } } diff --git a/playgrounds/nextjs/app/page.tsx b/playgrounds/nextjs/app/page.tsx index 70ea89898..3c5390442 100644 --- a/playgrounds/nextjs/app/page.tsx +++ b/playgrounds/nextjs/app/page.tsx @@ -1,5 +1,3 @@ -import styles from './page.module.css' - export default function Home() { - return

Hello world!

+ return

Hello world!

} diff --git a/playgrounds/nextjs/package.json b/playgrounds/nextjs/package.json index 5487af5a5..8468750dc 100644 --- a/playgrounds/nextjs/package.json +++ b/playgrounds/nextjs/package.json @@ -5,20 +5,23 @@ "scripts": { "dev": "next dev", "build": "next build", - "start": "next start" + "start": "next start", + "lint": "next lint" }, "dependencies": { "@tailwindcss/postcss": "workspace:^", - "fast-glob": "^3.3.3", - "next": "16.2.7", - "react": "19.2.7", - "react-dom": "19.2.7", + "fast-glob": "^3.3.2", + "next": "15.0.3", + "react": "^18.3.1", + "react-dom": "^18.3.1", "tailwindcss": "workspace:^" }, "devDependencies": { "@types/node": "catalog:", - "@types/react": "19.2.15", - "@types/react-dom": "19.2.3", - "typescript": "^6.0.3" + "@types/react": "^18.3.12", + "@types/react-dom": "^18.3.1", + "eslint": "^9.15.0", + "eslint-config-next": "^15.0.3", + "typescript": "^5.5.4" } } diff --git a/playgrounds/nextjs/tsconfig.json b/playgrounds/nextjs/tsconfig.json index 27414aae7..862143548 100644 --- a/playgrounds/nextjs/tsconfig.json +++ b/playgrounds/nextjs/tsconfig.json @@ -10,7 +10,7 @@ "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, - "jsx": "react-jsx", + "jsx": "preserve", "incremental": true, "plugins": [ { @@ -20,14 +20,7 @@ "paths": { "@/*": ["./*"], }, - "target": "ES2017", }, - "include": [ - "next-env.d.ts", - "**/*.ts", - "**/*.tsx", - ".next/types/**/*.ts", - ".next/dev/types/**/*.ts", - ], + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], "exclude": ["node_modules"], } diff --git a/playgrounds/v3/package.json b/playgrounds/v3/package.json index 8c08310db..c69808098 100644 --- a/playgrounds/v3/package.json +++ b/playgrounds/v3/package.json @@ -9,16 +9,18 @@ "upgrade": "node scripts/upgrade.mjs" }, "dependencies": { - "next": "16.2.7", - "react": "19.2.7", - "react-dom": "19.2.7", + "next": "15.0.3", + "react": "^18.3.1", + "react-dom": "^18.3.1", "tailwindcss": "^3" }, "devDependencies": { - "@types/node": "catalog:", - "@types/react": "19.2.15", - "@types/react-dom": "19.2.3", - "autoprefixer": "^10.5.0", - "typescript": "^6.0.3" + "@types/node": "^20.14.8", + "@types/react": "^18.3.12", + "@types/react-dom": "^18.3.1", + "autoprefixer": "^10.4.20", + "eslint": "^9.15.0", + "eslint-config-next": "^15.0.3", + "typescript": "^5.5.4" } } diff --git a/playgrounds/v3/tsconfig.json b/playgrounds/v3/tsconfig.json index 27414aae7..862143548 100644 --- a/playgrounds/v3/tsconfig.json +++ b/playgrounds/v3/tsconfig.json @@ -10,7 +10,7 @@ "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, - "jsx": "react-jsx", + "jsx": "preserve", "incremental": true, "plugins": [ { @@ -20,14 +20,7 @@ "paths": { "@/*": ["./*"], }, - "target": "ES2017", }, - "include": [ - "next-env.d.ts", - "**/*.ts", - "**/*.tsx", - ".next/types/**/*.ts", - ".next/dev/types/**/*.ts", - ], + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], "exclude": ["node_modules"], } diff --git a/playgrounds/vite/package.json b/playgrounds/vite/package.json index 25ab1a33b..716337c36 100644 --- a/playgrounds/vite/package.json +++ b/playgrounds/vite/package.json @@ -10,15 +10,15 @@ }, "dependencies": { "@tailwindcss/vite": "workspace:^", - "@vitejs/plugin-react": "^6.0.2", - "react": "^19.2.6", - "react-dom": "^19.2.6", + "@vitejs/plugin-react": "^4.3.1", + "react": "^18.3.1", + "react-dom": "^18.3.1", "tailwindcss": "workspace:^" }, "devDependencies": { - "@types/react": "^19.2.15", - "@types/react-dom": "^19.2.3", - "bun": "^1.3.14", + "@types/react": "^18.3.12", + "@types/react-dom": "^18.3.1", + "bun": "^1.1.29", "vite": "catalog:" } } diff --git a/playgrounds/vite/src/app.tsx b/playgrounds/vite/src/app.tsx index 8ec502989..4abc17cb5 100644 --- a/playgrounds/vite/src/app.tsx +++ b/playgrounds/vite/src/app.tsx @@ -2,6 +2,7 @@ export function App() { return (

Hello World

+
) } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8382b2ba5..440843400 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,138 +4,52 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false -catalogs: - default: - '@parcel/watcher': - specifier: 2.6.0 - version: 2.6.0 - '@parcel/watcher-darwin-arm64': - specifier: 2.6.0 - version: 2.6.0 - '@parcel/watcher-darwin-x64': - specifier: 2.6.0 - version: 2.6.0 - '@parcel/watcher-linux-arm64-glibc': - specifier: 2.6.0 - version: 2.6.0 - '@parcel/watcher-linux-arm64-musl': - specifier: 2.6.0 - version: 2.6.0 - '@parcel/watcher-linux-x64-glibc': - specifier: 2.6.0 - version: 2.6.0 - '@parcel/watcher-linux-x64-musl': - specifier: 2.6.0 - version: 2.6.0 - '@parcel/watcher-win32-x64': - specifier: 2.6.0 - version: 2.6.0 - '@types/node': - specifier: 22.20.1 - version: 22.20.1 - dedent: - specifier: 1.7.2 - version: 1.7.2 - enhanced-resolve: - specifier: ^5.24.5 - version: 5.24.5 - lightningcss: - specifier: 1.33.0 - version: 1.33.0 - lightningcss-darwin-arm64: - specifier: 1.33.0 - version: 1.33.0 - lightningcss-darwin-x64: - specifier: 1.33.0 - version: 1.33.0 - lightningcss-linux-arm64-gnu: - specifier: 1.33.0 - version: 1.33.0 - lightningcss-linux-arm64-musl: - specifier: 1.33.0 - version: 1.33.0 - lightningcss-linux-x64-gnu: - specifier: 1.33.0 - version: 1.33.0 - lightningcss-linux-x64-musl: - specifier: 1.33.0 - version: 1.33.0 - lightningcss-win32-x64-msvc: - specifier: 1.33.0 - version: 1.33.0 - postcss: - specifier: ^8.5.25 - version: 8.5.25 - prettier: - specifier: 3.9.6 - version: 3.9.6 - vite: - specifier: ^8.2.0 - version: 8.2.0 - webpack: - specifier: ^5.109.2 - version: 5.109.2 - patchedDependencies: - '@napi-rs/cli@3.7.4': 9912bf0a9c2cef8329d11c41fbce4d33ce2bdcf660a630b258c962c0a3c44bed - '@parcel/watcher@2.6.0': 705ce75ccea54337110c4d7fe0a8b421658ea0c23e1a77c1fa890a86041179da - lightningcss@1.33.0: 1d4a8800d60d13d42887b88b3a86576df4b451670308145fb432ec8abbf40930 + '@parcel/watcher@2.5.0': + hash: pyfayeoxwesjxsefsxp3jpev4q + path: patches/@parcel__watcher@2.5.0.patch + lightningcss@1.26.0: + hash: 5hwfyehqvg5wjb7mwtdvubqbl4 + path: patches/lightningcss@1.26.0.patch importers: - .: devDependencies: '@playwright/test': - specifier: ^1.62.1 - version: 1.62.1 + specifier: ^1.49.0 + version: 1.49.0 '@types/node': specifier: 'catalog:' - version: 22.20.1 + version: 20.14.13 postcss: - specifier: 'catalog:' - version: 8.5.25 + specifier: 8.4.49 + version: 8.4.49 postcss-import: - specifier: ^16.1.1 - version: 16.1.1(postcss@8.5.25) + specifier: ^16.1.0 + version: 16.1.0(postcss@8.4.49) prettier: - specifier: 'catalog:' - version: 3.9.6 + specifier: ^3.3.3 + version: 3.3.3 prettier-plugin-embed: - specifier: ^0.5.1 - version: 0.5.1 + specifier: ^0.4.15 + version: 0.4.15 prettier-plugin-organize-imports: - specifier: ^4.3.0 - version: 4.3.0(prettier@3.9.6)(typescript@5.9.3) + specifier: ^4.0.0 + version: 4.0.0(prettier@3.3.3)(typescript@5.5.4) tsup: - specifier: ^8.5.1 - version: 8.5.1(jiti@2.7.0)(postcss@8.5.25)(typescript@5.9.3)(yaml@2.9.0) + specifier: ^8.2.4 + version: 8.2.4(jiti@2.4.0)(postcss@8.4.49)(tsx@4.19.1)(typescript@5.5.4)(yaml@2.6.0) turbo: - specifier: ^2.10.8 - version: 2.10.8 + specifier: ^2.2.3 + version: 2.2.3 typescript: - specifier: ^5.9.3 - version: 5.9.3 + specifier: ^5.5.4 + version: 5.5.4 vitest: - specifier: ^4.1.10 - version: 4.1.10(@types/node@22.20.1)(vite@8.2.0(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.48.0)(yaml@2.9.0)) + specifier: ^2.0.5 + version: 2.0.5(@types/node@20.14.13)(lightningcss@1.26.0(patch_hash=5hwfyehqvg5wjb7mwtdvubqbl4))(terser@5.31.6) crates/node: - devDependencies: - '@emnapi/core': - specifier: 1.11.3 - version: 1.11.3 - '@emnapi/runtime': - specifier: 1.11.3 - version: 1.11.3 - '@napi-rs/cli': - specifier: 3.7.4 - version: 3.7.4(patch_hash=9912bf0a9c2cef8329d11c41fbce4d33ce2bdcf660a630b258c962c0a3c44bed)(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@types/node@25.9.1)(node-addon-api@8.7.0) - '@napi-rs/wasm-runtime': - specifier: ^1.2.2 - version: 1.2.2(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3) - emnapi: - specifier: 1.11.3 - version: 1.11.3(node-addon-api@8.7.0) optionalDependencies: '@tailwindcss/oxide-android-arm64': specifier: workspace:* @@ -164,15 +78,16 @@ importers: '@tailwindcss/oxide-linux-x64-musl': specifier: workspace:* version: link:npm/linux-x64-musl - '@tailwindcss/oxide-wasm32-wasi': - specifier: workspace:* - version: link:npm/wasm32-wasi '@tailwindcss/oxide-win32-arm64-msvc': specifier: workspace:* version: link:npm/win32-arm64-msvc '@tailwindcss/oxide-win32-x64-msvc': specifier: workspace:* version: link:npm/win32-x64-msvc + devDependencies: + '@napi-rs/cli': + specifier: ^2.18.4 + version: 2.18.4 crates/node/npm/android-arm-eabi: {} @@ -194,27 +109,6 @@ importers: crates/node/npm/linux-x64-musl: {} - crates/node/npm/wasm32-wasi: - dependencies: - '@emnapi/core': - specifier: ^1.11.3 - version: 1.11.3 - '@emnapi/runtime': - specifier: ^1.11.3 - version: 1.11.3 - '@emnapi/wasi-threads': - specifier: ^1.2.3 - version: 1.2.3 - '@napi-rs/wasm-runtime': - specifier: ^1.2.2 - version: 1.2.2(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3) - '@tybys/wasm-util': - specifier: ^0.10.3 - version: 0.10.3 - tslib: - specifier: ^2.8.1 - version: 2.8.1 - crates/node/npm/win32-arm64-msvc: {} crates/node/npm/win32-x64-msvc: {} @@ -222,44 +116,29 @@ importers: integrations: devDependencies: dedent: - specifier: 'catalog:' - version: 1.7.2 + specifier: 1.5.3 + version: 1.5.3 fast-glob: - specifier: ^3.3.3 - version: 3.3.3 - source-map-js: - specifier: ^1.2.1 - version: 1.2.1 - yaml: - specifier: ^2.9.0 - version: 2.9.0 - - packages/@tailwindcss-browser: - devDependencies: - h3: - specifier: ^1.15.11 - version: 1.15.11 - listhen: - specifier: ^1.10.1 - version: 1.10.1(@parcel/watcher@2.6.0(patch_hash=705ce75ccea54337110c4d7fe0a8b421658ea0c23e1a77c1fa890a86041179da)) - tailwindcss: - specifier: workspace:* - version: link:../tailwindcss + specifier: ^3.3.2 + version: 3.3.2 packages/@tailwindcss-cli: dependencies: '@parcel/watcher': - specifier: 'catalog:' - version: 2.6.0(patch_hash=705ce75ccea54337110c4d7fe0a8b421658ea0c23e1a77c1fa890a86041179da) + specifier: ^2.5.0 + version: 2.5.0(patch_hash=pyfayeoxwesjxsefsxp3jpev4q) '@tailwindcss/node': - specifier: workspace:* + specifier: workspace:^ version: link:../@tailwindcss-node '@tailwindcss/oxide': - specifier: workspace:* + specifier: workspace:^ version: link:../../crates/node enhanced-resolve: + specifier: ^5.17.1 + version: 5.17.1 + lightningcss: specifier: 'catalog:' - version: 5.24.5 + version: 1.26.0(patch_hash=5hwfyehqvg5wjb7mwtdvubqbl4) mri: specifier: ^1.2.0 version: 1.2.0 @@ -272,24 +151,12 @@ importers: packages/@tailwindcss-node: dependencies: - '@jridgewell/remapping': - specifier: ^2.3.5 - version: 2.3.5 enhanced-resolve: - specifier: 'catalog:' - version: 5.24.5 + specifier: ^5.17.1 + version: 5.17.1 jiti: - specifier: ^2.7.0 - version: 2.7.0 - lightningcss: - specifier: 'catalog:' - version: 1.33.0(patch_hash=1d4a8800d60d13d42887b88b3a86576df4b451670308145fb432ec8abbf40930) - magic-string: - specifier: ^1.1.0 - version: 1.1.0 - source-map-js: - specifier: ^1.2.1 - version: 1.2.1 + specifier: ^2.4.0 + version: 2.4.0 tailwindcss: specifier: workspace:* version: link:../tailwindcss @@ -300,33 +167,36 @@ importers: specifier: ^5.2.0 version: 5.2.0 '@tailwindcss/node': - specifier: workspace:* + specifier: workspace:^ version: link:../@tailwindcss-node '@tailwindcss/oxide': - specifier: workspace:* + specifier: workspace:^ version: link:../../crates/node - postcss: + lightningcss: specifier: 'catalog:' - version: 8.5.25 + version: 1.26.0(patch_hash=5hwfyehqvg5wjb7mwtdvubqbl4) + postcss: + specifier: ^8.4.41 + version: 8.4.41 tailwindcss: specifier: workspace:* version: link:../tailwindcss devDependencies: '@types/node': specifier: 'catalog:' - version: 22.20.1 + version: 20.14.13 '@types/postcss-import': specifier: 14.0.3 version: 14.0.3 dedent: - specifier: 'catalog:' - version: 1.7.2 + specifier: 1.5.3 + version: 1.5.3 internal-example-plugin: specifier: workspace:* version: link:../internal-example-plugin postcss-import: - specifier: ^16.1.1 - version: 16.1.1(postcss@8.5.25) + specifier: ^16.1.0 + version: 16.1.0(postcss@8.4.41) packages/@tailwindcss-standalone: dependencies: @@ -334,115 +204,96 @@ importers: specifier: ^0.4.2 version: 0.4.2(tailwindcss@packages+tailwindcss) '@tailwindcss/cli': - specifier: workspace:* + specifier: workspace:^ version: link:../@tailwindcss-cli '@tailwindcss/forms': - specifier: ^0.5.11 - version: 0.5.11(tailwindcss@packages+tailwindcss) + specifier: ^0.5.9 + version: 0.5.9(tailwindcss@packages+tailwindcss) '@tailwindcss/typography': - specifier: ^0.5.20 - version: 0.5.20(tailwindcss@packages+tailwindcss) + specifier: ^0.5.15 + version: 0.5.15(tailwindcss@packages+tailwindcss) detect-libc: specifier: 1.0.3 version: 1.0.3 enhanced-resolve: - specifier: 'catalog:' - version: 5.24.5 + specifier: ^5.17.1 + version: 5.17.1 tailwindcss: - specifier: workspace:* + specifier: workspace:^ version: link:../tailwindcss devDependencies: '@parcel/watcher-darwin-arm64': - specifier: 'catalog:' - version: 2.6.0 + specifier: ^2.5.0 + version: 2.5.0 '@parcel/watcher-darwin-x64': - specifier: 'catalog:' - version: 2.6.0 + specifier: ^2.5.0 + version: 2.5.0 '@parcel/watcher-linux-arm64-glibc': - specifier: 'catalog:' - version: 2.6.0 + specifier: ^2.5.0 + version: 2.5.0 '@parcel/watcher-linux-arm64-musl': - specifier: 'catalog:' - version: 2.6.0 + specifier: ^2.5.0 + version: 2.5.0 '@parcel/watcher-linux-x64-glibc': - specifier: 'catalog:' - version: 2.6.0 + specifier: ^2.5.0 + version: 2.5.0 '@parcel/watcher-linux-x64-musl': - specifier: 'catalog:' - version: 2.6.0 + specifier: ^2.5.0 + version: 2.5.0 '@parcel/watcher-win32-x64': - specifier: 'catalog:' - version: 2.6.0 + specifier: ^2.5.0 + version: 2.5.0 '@types/bun': - specifier: ^1.3.14 - version: 1.3.14 + specifier: ^1.1.13 + version: 1.1.13 bun: - specifier: ^1.3.14 - version: 1.3.14 + specifier: 1.1.29 + version: 1.1.29 lightningcss-darwin-arm64: - specifier: 'catalog:' - version: 1.33.0 + specifier: ^1.25.1 + version: 1.26.0 lightningcss-darwin-x64: - specifier: 'catalog:' - version: 1.33.0 + specifier: ^1.25.1 + version: 1.26.0 lightningcss-linux-arm64-gnu: - specifier: 'catalog:' - version: 1.33.0 + specifier: ^1.25.1 + version: 1.26.0 lightningcss-linux-arm64-musl: - specifier: 'catalog:' - version: 1.33.0 + specifier: ^1.25.1 + version: 1.26.0 lightningcss-linux-x64-gnu: - specifier: 'catalog:' - version: 1.33.0 + specifier: ^1.25.1 + version: 1.26.0 lightningcss-linux-x64-musl: - specifier: 'catalog:' - version: 1.33.0 + specifier: ^1.25.1 + version: 1.26.0 lightningcss-win32-x64-msvc: - specifier: 'catalog:' - version: 1.33.0 - - packages/@tailwindcss-turbopack: - dependencies: - '@alloc/quick-lru': - specifier: ^5.2.0 - version: 5.2.0 - '@tailwindcss/node': - specifier: workspace:* - version: link:../@tailwindcss-node - '@tailwindcss/oxide': - specifier: workspace:* - version: link:../../crates/node - tailwindcss: - specifier: workspace:* - version: link:../tailwindcss - devDependencies: - '@types/node': - specifier: 'catalog:' - version: 22.20.1 - webpack: - specifier: 'catalog:' - version: 5.109.2(esbuild@0.27.7)(postcss@8.5.25) + specifier: ^1.25.1 + version: 1.26.0 packages/@tailwindcss-upgrade: dependencies: '@tailwindcss/node': - specifier: workspace:* + specifier: workspace:^ version: link:../@tailwindcss-node '@tailwindcss/oxide': - specifier: workspace:* + specifier: workspace:^ version: link:../../crates/node + braces: + specifier: ^3.0.3 + version: 3.0.3 dedent: - specifier: 'catalog:' - version: 1.7.2 + specifier: 1.5.3 + version: 1.5.3 enhanced-resolve: - specifier: 'catalog:' - version: 5.24.5 + specifier: ^5.17.1 + version: 5.17.1 globby: - specifier: ^16.2.2 - version: 16.2.2 + specifier: ^14.0.2 + version: 14.0.2 jiti: - specifier: ^2.7.0 - version: 2.7.0 + specifier: ^2.0.0-beta.3 + version: 2.4.0 mri: specifier: ^1.2.0 version: 1.2.0 @@ -450,109 +301,75 @@ importers: specifier: ^1.1.1 version: 1.1.1 postcss: - specifier: 'catalog:' - version: 8.5.25 + specifier: ^8.4.41 + version: 8.4.41 postcss-import: - specifier: ^16.1.1 - version: 16.1.1(postcss@8.5.25) + specifier: ^16.1.0 + version: 16.1.0(postcss@8.4.41) postcss-selector-parser: - specifier: ^7.1.4 - version: 7.1.4 + specifier: ^7.0.0 + version: 7.0.0 prettier: - specifier: 'catalog:' - version: 3.9.6 - semver: - specifier: ^7.8.5 - version: 7.8.5 + specifier: ^3.3.3 + version: 3.3.3 tailwindcss: specifier: workspace:* version: link:../tailwindcss tree-sitter: - specifier: ^0.25.1 - version: 0.25.1 + specifier: ^0.22.1 + version: 0.22.1 tree-sitter-typescript: specifier: ^0.23.2 - version: 0.23.2(tree-sitter@0.25.1) + version: 0.23.2(tree-sitter@0.22.1) devDependencies: + '@types/braces': + specifier: ^3.0.4 + version: 3.0.4 '@types/node': specifier: 'catalog:' - version: 22.20.1 + version: 20.14.13 '@types/postcss-import': specifier: ^14.0.3 version: 14.0.3 - '@types/semver': - specifier: ^7.8.0 - version: 7.8.0 packages/@tailwindcss-vite: dependencies: '@tailwindcss/node': - specifier: workspace:* + specifier: workspace:^ version: link:../@tailwindcss-node '@tailwindcss/oxide': - specifier: workspace:* + specifier: workspace:^ version: link:../../crates/node + lightningcss: + specifier: 'catalog:' + version: 1.26.0(patch_hash=5hwfyehqvg5wjb7mwtdvubqbl4) tailwindcss: specifier: workspace:* version: link:../tailwindcss devDependencies: '@types/node': specifier: 'catalog:' - version: 22.20.1 + version: 20.14.13 vite: specifier: 'catalog:' - version: 8.2.0(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.48.0)(yaml@2.9.0) - - packages/@tailwindcss-webpack: - dependencies: - '@alloc/quick-lru': - specifier: ^5.2.0 - version: 5.2.0 - '@rspack/core': - specifier: ^1.0.0 || ^2.0.0 - version: 2.0.2(@swc/helpers@0.5.15) - '@tailwindcss/node': - specifier: workspace:* - version: link:../@tailwindcss-node - '@tailwindcss/oxide': - specifier: workspace:* - version: link:../../crates/node - tailwindcss: - specifier: workspace:* - version: link:../tailwindcss - devDependencies: - '@types/node': - specifier: 'catalog:' - version: 22.20.1 - webpack: - specifier: 'catalog:' - version: 5.109.2(esbuild@0.27.7)(postcss@8.5.25) + version: 6.0.0(@types/node@20.14.13)(jiti@2.4.0)(lightningcss@1.26.0(patch_hash=5hwfyehqvg5wjb7mwtdvubqbl4))(terser@5.31.6)(tsx@4.19.1)(yaml@2.6.0) packages/internal-example-plugin: {} packages/tailwindcss: devDependencies: - '@jridgewell/remapping': - specifier: ^2.3.5 - version: 2.3.5 '@tailwindcss/oxide': specifier: workspace:^ version: link:../../crates/node '@types/node': specifier: 'catalog:' - version: 22.20.1 + version: 20.14.13 dedent: - specifier: 'catalog:' - version: 1.7.2 + specifier: 1.5.3 + version: 1.5.3 lightningcss: specifier: 'catalog:' - version: 1.33.0(patch_hash=1d4a8800d60d13d42887b88b3a86576df4b451670308145fb432ec8abbf40930) - magic-string: - specifier: ^1.1.0 - version: 1.1.0 - source-map-js: - specifier: ^1.2.1 - version: 1.2.1 + version: 1.26.0(patch_hash=5hwfyehqvg5wjb7mwtdvubqbl4) playgrounds/nextjs: dependencies: @@ -560,64 +377,76 @@ importers: specifier: workspace:^ version: link:../../packages/@tailwindcss-postcss fast-glob: - specifier: ^3.3.3 - version: 3.3.3 + specifier: ^3.3.2 + version: 3.3.2 next: - specifier: 16.2.7 - version: 16.2.7(@playwright/test@1.62.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + specifier: 15.0.3 + version: 15.0.3(@playwright/test@1.49.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: - specifier: 19.2.7 - version: 19.2.7 + specifier: ^18.3.1 + version: 18.3.1 react-dom: - specifier: 19.2.7 - version: 19.2.7(react@19.2.7) + specifier: ^18.3.1 + version: 18.3.1(react@18.3.1) tailwindcss: specifier: workspace:^ version: link:../../packages/tailwindcss devDependencies: '@types/node': specifier: 'catalog:' - version: 22.20.1 + version: 20.14.13 '@types/react': - specifier: 19.2.15 - version: 19.2.15 + specifier: ^18.3.12 + version: 18.3.12 '@types/react-dom': - specifier: 19.2.3 - version: 19.2.3(@types/react@19.2.15) + specifier: ^18.3.1 + version: 18.3.1 + eslint: + specifier: ^9.15.0 + version: 9.15.0(jiti@2.4.0) + eslint-config-next: + specifier: ^15.0.3 + version: 15.0.3(eslint@9.15.0(jiti@2.4.0))(typescript@5.5.4) typescript: - specifier: ^6.0.3 - version: 6.0.3 + specifier: ^5.5.4 + version: 5.5.4 playgrounds/v3: dependencies: next: - specifier: 16.2.7 - version: 16.2.7(@playwright/test@1.62.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + specifier: 15.0.3 + version: 15.0.3(@playwright/test@1.49.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) react: - specifier: 19.2.7 - version: 19.2.7 + specifier: ^18.3.1 + version: 18.3.1 react-dom: - specifier: 19.2.7 - version: 19.2.7(react@19.2.7) + specifier: ^18.3.1 + version: 18.3.1(react@18.3.1) tailwindcss: specifier: ^3 - version: 3.4.19(yaml@2.9.0) + version: 3.4.14 devDependencies: '@types/node': - specifier: 'catalog:' - version: 22.20.1 + specifier: ^20.14.8 + version: 20.14.13 '@types/react': - specifier: 19.2.15 - version: 19.2.15 + specifier: ^18.3.12 + version: 18.3.12 '@types/react-dom': - specifier: 19.2.3 - version: 19.2.3(@types/react@19.2.15) + specifier: ^18.3.1 + version: 18.3.1 autoprefixer: - specifier: ^10.5.0 - version: 10.5.0(postcss@8.5.25) + specifier: ^10.4.20 + version: 10.4.20(postcss@8.4.47) + eslint: + specifier: ^9.15.0 + version: 9.15.0(jiti@2.4.0) + eslint-config-next: + specifier: ^15.0.3 + version: 15.0.3(eslint@9.15.0(jiti@2.4.0))(typescript@5.6.3) typescript: - specifier: ^6.0.3 - version: 6.0.3 + specifier: ^5.5.4 + version: 5.6.3 playgrounds/vite: dependencies: @@ -625,2306 +454,4194 @@ importers: specifier: workspace:^ version: link:../../packages/@tailwindcss-vite '@vitejs/plugin-react': - specifier: ^6.0.2 - version: 6.0.2(vite@8.2.0(@types/node@25.9.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.48.0)(yaml@2.9.0)) + specifier: ^4.3.1 + version: 4.3.1(vite@6.0.0(@types/node@20.14.13)(jiti@2.4.0)(lightningcss@1.26.0(patch_hash=5hwfyehqvg5wjb7mwtdvubqbl4))(terser@5.31.6)(tsx@4.19.1)(yaml@2.6.0)) react: - specifier: ^19.2.6 - version: 19.2.6 + specifier: ^18.3.1 + version: 18.3.1 react-dom: - specifier: ^19.2.6 - version: 19.2.6(react@19.2.6) + specifier: ^18.3.1 + version: 18.3.1(react@18.3.1) tailwindcss: specifier: workspace:^ version: link:../../packages/tailwindcss devDependencies: '@types/react': - specifier: ^19.2.15 - version: 19.2.15 + specifier: ^18.3.12 + version: 18.3.12 '@types/react-dom': - specifier: ^19.2.3 - version: 19.2.3(@types/react@19.2.15) + specifier: ^18.3.1 + version: 18.3.1 bun: - specifier: ^1.3.14 - version: 1.3.14 + specifier: ^1.1.29 + version: 1.1.29 vite: specifier: 'catalog:' - version: 8.2.0(@types/node@25.9.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.48.0)(yaml@2.9.0) + version: 6.0.0(@types/node@20.14.13)(jiti@2.4.0)(lightningcss@1.26.0(patch_hash=5hwfyehqvg5wjb7mwtdvubqbl4))(terser@5.31.6)(tsx@4.19.1)(yaml@2.6.0) packages: - '@alloc/quick-lru@5.2.0': - resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==, + } + engines: { node: '>=10' } - '@emnapi/core@1.10.0': - resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} + '@ampproject/remapping@2.3.0': + resolution: + { + integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==, + } + engines: { node: '>=6.0.0' } - '@emnapi/core@1.11.3': - resolution: {integrity: sha512-zLpS5asjEb7lq8jYLq37N6XKaE41DIexlY1rF/z4/tIl3wo13Sqm28fRyfIsKZD+NZ8mM5RoKkpW/rBcuoSZSg==} + '@babel/code-frame@7.24.7': + resolution: + { + integrity: sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==, + } + engines: { node: '>=6.9.0' } - '@emnapi/core@2.0.0-alpha.3': - resolution: {integrity: sha512-AZypUeJ/yByuxyS7BlSNRDOMLMlROYtjYdIAuBmJssVz1UJDSeYxLrdizhXCFYhedC5bqd/ASy8EuNXbVVXp9g==} + '@babel/compat-data@7.25.2': + resolution: + { + integrity: sha512-bYcppcpKBvX4znYaPEeFau03bp89ShqNMLs+rmdptMw+heSZh9+z84d2YG+K7cYLbWwzdjtDoW/uqZmPjulClQ==, + } + engines: { node: '>=6.9.0' } - '@emnapi/runtime@1.10.0': - resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} + '@babel/core@7.25.2': + resolution: + { + integrity: sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==, + } + engines: { node: '>=6.9.0' } - '@emnapi/runtime@1.11.3': - resolution: {integrity: sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==} + '@babel/generator@7.25.0': + resolution: + { + integrity: sha512-3LEEcj3PVW8pW2R1SR1M89g/qrYk/m/mB/tLqn7dn4sbBUQyTqnlod+II2U4dqiGtUmkcnAmkMDralTFZttRiw==, + } + engines: { node: '>=6.9.0' } - '@emnapi/runtime@2.0.0-alpha.3': - resolution: {integrity: sha512-hFPAhMUjJD9BSyCANEISPOogeXC9Zo9ZQl7L6vKnaVsMkCtzznaW/naYypeyl0Gv5rYfWYsZbpixTMpjDJzQeA==} + '@babel/helper-compilation-targets@7.25.2': + resolution: + { + integrity: sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==, + } + engines: { node: '>=6.9.0' } - '@emnapi/wasi-threads@1.2.1': - resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} + '@babel/helper-module-imports@7.24.7': + resolution: + { + integrity: sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==, + } + engines: { node: '>=6.9.0' } - '@emnapi/wasi-threads@1.2.3': - resolution: {integrity: sha512-ELEBe8PsLvvJ6QMr0zLt8ffvOHW/dc1m3CEzNMg7aJUv3bMaoDtw2TXyDAwkYBuroxxuHEwhRTLJSe5sya547g==} + '@babel/helper-module-transforms@7.25.2': + resolution: + { + integrity: sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==, + } + engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0 - '@emnapi/wasi-threads@2.0.1': - resolution: {integrity: sha512-9DsSk+o5NBX0CCJT8s0EROGSGxjR/tKu6aBTaVyq+SjAEQH4XcdcRxPBRzsBLizTTJ49MJjF+jgu3qnO9GLQcQ==} + '@babel/helper-plugin-utils@7.24.8': + resolution: + { + integrity: sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==, + } + engines: { node: '>=6.9.0' } - '@esbuild/aix-ppc64@0.27.7': - resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} - engines: {node: '>=18'} + '@babel/helper-simple-access@7.24.7': + resolution: + { + integrity: sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==, + } + engines: { node: '>=6.9.0' } + + '@babel/helper-string-parser@7.24.8': + resolution: + { + integrity: sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==, + } + engines: { node: '>=6.9.0' } + + '@babel/helper-validator-identifier@7.24.7': + resolution: + { + integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==, + } + engines: { node: '>=6.9.0' } + + '@babel/helper-validator-option@7.24.8': + resolution: + { + integrity: sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==, + } + engines: { node: '>=6.9.0' } + + '@babel/helpers@7.25.0': + resolution: + { + integrity: sha512-MjgLZ42aCm0oGjJj8CtSM3DB8NOOf8h2l7DCTePJs29u+v7yO/RBX9nShlKMgFnRks/Q4tBAe7Hxnov9VkGwLw==, + } + engines: { node: '>=6.9.0' } + + '@babel/highlight@7.24.7': + resolution: + { + integrity: sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==, + } + engines: { node: '>=6.9.0' } + + '@babel/parser@7.25.3': + resolution: + { + integrity: sha512-iLTJKDbJ4hMvFPgQwwsVoxtHyWpKKPBrxkANrSYewDPaPpT5py5yeVkgPIJ7XYXhndxJpaA3PyALSXQ7u8e/Dw==, + } + engines: { node: '>=6.0.0' } + hasBin: true + + '@babel/plugin-transform-react-jsx-self@7.24.7': + resolution: + { + integrity: sha512-fOPQYbGSgH0HUp4UJO4sMBFjY6DuWq+2i8rixyUMb3CdGixs/gccURvYOAhajBdKDoGajFr3mUq5rH3phtkGzw==, + } + engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-source@7.24.7': + resolution: + { + integrity: sha512-J2z+MWzZHVOemyLweMqngXrgGC42jQ//R0KdxqkIz/OrbVIIlhFI3WigZ5fO+nwFvBlncr4MGapd8vTyc7RPNQ==, + } + engines: { node: '>=6.9.0' } + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/template@7.25.0': + resolution: + { + integrity: sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==, + } + engines: { node: '>=6.9.0' } + + '@babel/traverse@7.25.3': + resolution: + { + integrity: sha512-HefgyP1x754oGCsKmV5reSmtV7IXj/kpaE1XYY+D9G5PvKKoFfSbiS4M77MdjuwlZKDIKFCffq9rPU+H/s3ZdQ==, + } + engines: { node: '>=6.9.0' } + + '@babel/types@7.25.2': + resolution: + { + integrity: sha512-YTnYtra7W9e6/oAZEHj0bJehPRUlLH9/fbpT5LfB0NhQXyALCRkRs3zH9v07IYhkgpqX6Z78FnuccZr/l4Fs4Q==, + } + engines: { node: '>=6.9.0' } + + '@emnapi/runtime@1.3.1': + resolution: + { + integrity: sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==, + } + + '@esbuild/aix-ppc64@0.21.5': + resolution: + { + integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==, + } + engines: { node: '>=12' } cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.27.7': - resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} - engines: {node: '>=18'} + '@esbuild/aix-ppc64@0.23.0': + resolution: + { + integrity: sha512-3sG8Zwa5fMcA9bgqB8AfWPQ+HFke6uD3h1s3RIwUNK8EG7a4buxvuFTs3j1IMs2NXAk9F30C/FF4vxRgQCcmoQ==, + } + engines: { node: '>=18' } + cpu: [ppc64] + os: [aix] + + '@esbuild/aix-ppc64@0.23.1': + resolution: + { + integrity: sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==, + } + engines: { node: '>=18' } + cpu: [ppc64] + os: [aix] + + '@esbuild/aix-ppc64@0.24.0': + resolution: + { + integrity: sha512-WtKdFM7ls47zkKHFVzMz8opM7LkcsIp9amDUBIAWirg70RM71WRSjdILPsY5Uv1D42ZpUfaPILDlfactHgsRkw==, + } + engines: { node: '>=18' } + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.21.5': + resolution: + { + integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==, + } + engines: { node: '>=12' } cpu: [arm64] os: [android] - '@esbuild/android-arm@0.27.7': - resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==} - engines: {node: '>=18'} + '@esbuild/android-arm64@0.23.0': + resolution: + { + integrity: sha512-EuHFUYkAVfU4qBdyivULuu03FhJO4IJN9PGuABGrFy4vUuzk91P2d+npxHcFdpUnfYKy0PuV+n6bKIpHOB3prQ==, + } + engines: { node: '>=18' } + cpu: [arm64] + os: [android] + + '@esbuild/android-arm64@0.23.1': + resolution: + { + integrity: sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==, + } + engines: { node: '>=18' } + cpu: [arm64] + os: [android] + + '@esbuild/android-arm64@0.24.0': + resolution: + { + integrity: sha512-Vsm497xFM7tTIPYK9bNTYJyF/lsP590Qc1WxJdlB6ljCbdZKU9SY8i7+Iin4kyhV/KV5J2rOKsBQbB77Ab7L/w==, + } + engines: { node: '>=18' } + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.21.5': + resolution: + { + integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==, + } + engines: { node: '>=12' } cpu: [arm] os: [android] - '@esbuild/android-x64@0.27.7': - resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==} - engines: {node: '>=18'} + '@esbuild/android-arm@0.23.0': + resolution: + { + integrity: sha512-+KuOHTKKyIKgEEqKbGTK8W7mPp+hKinbMBeEnNzjJGyFcWsfrXjSTNluJHCY1RqhxFurdD8uNXQDei7qDlR6+g==, + } + engines: { node: '>=18' } + cpu: [arm] + os: [android] + + '@esbuild/android-arm@0.23.1': + resolution: + { + integrity: sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==, + } + engines: { node: '>=18' } + cpu: [arm] + os: [android] + + '@esbuild/android-arm@0.24.0': + resolution: + { + integrity: sha512-arAtTPo76fJ/ICkXWetLCc9EwEHKaeya4vMrReVlEIUCAUncH7M4bhMQ+M9Vf+FFOZJdTNMXNBrWwW+OXWpSew==, + } + engines: { node: '>=18' } + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.21.5': + resolution: + { + integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==, + } + engines: { node: '>=12' } cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.27.7': - resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} - engines: {node: '>=18'} + '@esbuild/android-x64@0.23.0': + resolution: + { + integrity: sha512-WRrmKidLoKDl56LsbBMhzTTBxrsVwTKdNbKDalbEZr0tcsBgCLbEtoNthOW6PX942YiYq8HzEnb4yWQMLQuipQ==, + } + engines: { node: '>=18' } + cpu: [x64] + os: [android] + + '@esbuild/android-x64@0.23.1': + resolution: + { + integrity: sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==, + } + engines: { node: '>=18' } + cpu: [x64] + os: [android] + + '@esbuild/android-x64@0.24.0': + resolution: + { + integrity: sha512-t8GrvnFkiIY7pa7mMgJd7p8p8qqYIz1NYiAoKc75Zyv73L3DZW++oYMSHPRarcotTKuSs6m3hTOa5CKHaS02TQ==, + } + engines: { node: '>=18' } + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.21.5': + resolution: + { + integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==, + } + engines: { node: '>=12' } cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.27.7': - resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==} - engines: {node: '>=18'} + '@esbuild/darwin-arm64@0.23.0': + resolution: + { + integrity: sha512-YLntie/IdS31H54Ogdn+v50NuoWF5BDkEUFpiOChVa9UnKpftgwzZRrI4J132ETIi+D8n6xh9IviFV3eXdxfow==, + } + engines: { node: '>=18' } + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-arm64@0.23.1': + resolution: + { + integrity: sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==, + } + engines: { node: '>=18' } + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-arm64@0.24.0': + resolution: + { + integrity: sha512-CKyDpRbK1hXwv79soeTJNHb5EiG6ct3efd/FTPdzOWdbZZfGhpbcqIpiD0+vwmpu0wTIL97ZRPZu8vUt46nBSw==, + } + engines: { node: '>=18' } + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.21.5': + resolution: + { + integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==, + } + engines: { node: '>=12' } cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.27.7': - resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} - engines: {node: '>=18'} + '@esbuild/darwin-x64@0.23.0': + resolution: + { + integrity: sha512-IMQ6eme4AfznElesHUPDZ+teuGwoRmVuuixu7sv92ZkdQcPbsNHzutd+rAfaBKo8YK3IrBEi9SLLKWJdEvJniQ==, + } + engines: { node: '>=18' } + cpu: [x64] + os: [darwin] + + '@esbuild/darwin-x64@0.23.1': + resolution: + { + integrity: sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==, + } + engines: { node: '>=18' } + cpu: [x64] + os: [darwin] + + '@esbuild/darwin-x64@0.24.0': + resolution: + { + integrity: sha512-rgtz6flkVkh58od4PwTRqxbKH9cOjaXCMZgWD905JOzjFKW+7EiUObfd/Kav+A6Gyud6WZk9w+xu6QLytdi2OA==, + } + engines: { node: '>=18' } + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.21.5': + resolution: + { + integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==, + } + engines: { node: '>=12' } cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.27.7': - resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==} - engines: {node: '>=18'} + '@esbuild/freebsd-arm64@0.23.0': + resolution: + { + integrity: sha512-0muYWCng5vqaxobq6LB3YNtevDFSAZGlgtLoAc81PjUfiFz36n4KMpwhtAd4he8ToSI3TGyuhyx5xmiWNYZFyw==, + } + engines: { node: '>=18' } + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-arm64@0.23.1': + resolution: + { + integrity: sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==, + } + engines: { node: '>=18' } + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-arm64@0.24.0': + resolution: + { + integrity: sha512-6Mtdq5nHggwfDNLAHkPlyLBpE5L6hwsuXZX8XNmHno9JuL2+bg2BX5tRkwjyfn6sKbxZTq68suOjgWqCicvPXA==, + } + engines: { node: '>=18' } + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.21.5': + resolution: + { + integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==, + } + engines: { node: '>=12' } cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.27.7': - resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} - engines: {node: '>=18'} + '@esbuild/freebsd-x64@0.23.0': + resolution: + { + integrity: sha512-XKDVu8IsD0/q3foBzsXGt/KjD/yTKBCIwOHE1XwiXmrRwrX6Hbnd5Eqn/WvDekddK21tfszBSrE/WMaZh+1buQ==, + } + engines: { node: '>=18' } + cpu: [x64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.23.1': + resolution: + { + integrity: sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==, + } + engines: { node: '>=18' } + cpu: [x64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.24.0': + resolution: + { + integrity: sha512-D3H+xh3/zphoX8ck4S2RxKR6gHlHDXXzOf6f/9dbFt/NRBDIE33+cVa49Kil4WUjxMGW0ZIYBYtaGCa2+OsQwQ==, + } + engines: { node: '>=18' } + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.21.5': + resolution: + { + integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==, + } + engines: { node: '>=12' } cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.27.7': - resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==} - engines: {node: '>=18'} + '@esbuild/linux-arm64@0.23.0': + resolution: + { + integrity: sha512-j1t5iG8jE7BhonbsEg5d9qOYcVZv/Rv6tghaXM/Ug9xahM0nX/H2gfu6X6z11QRTMT6+aywOMA8TDkhPo8aCGw==, + } + engines: { node: '>=18' } + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm64@0.23.1': + resolution: + { + integrity: sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==, + } + engines: { node: '>=18' } + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm64@0.24.0': + resolution: + { + integrity: sha512-TDijPXTOeE3eaMkRYpcy3LarIg13dS9wWHRdwYRnzlwlA370rNdZqbcp0WTyyV/k2zSxfko52+C7jU5F9Tfj1g==, + } + engines: { node: '>=18' } + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.21.5': + resolution: + { + integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==, + } + engines: { node: '>=12' } cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.27.7': - resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==} - engines: {node: '>=18'} + '@esbuild/linux-arm@0.23.0': + resolution: + { + integrity: sha512-SEELSTEtOFu5LPykzA395Mc+54RMg1EUgXP+iw2SJ72+ooMwVsgfuwXo5Fn0wXNgWZsTVHwY2cg4Vi/bOD88qw==, + } + engines: { node: '>=18' } + cpu: [arm] + os: [linux] + + '@esbuild/linux-arm@0.23.1': + resolution: + { + integrity: sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==, + } + engines: { node: '>=18' } + cpu: [arm] + os: [linux] + + '@esbuild/linux-arm@0.24.0': + resolution: + { + integrity: sha512-gJKIi2IjRo5G6Glxb8d3DzYXlxdEj2NlkixPsqePSZMhLudqPhtZ4BUrpIuTjJYXxvF9njql+vRjB2oaC9XpBw==, + } + engines: { node: '>=18' } + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.21.5': + resolution: + { + integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==, + } + engines: { node: '>=12' } cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.27.7': - resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==} - engines: {node: '>=18'} + '@esbuild/linux-ia32@0.23.0': + resolution: + { + integrity: sha512-P7O5Tkh2NbgIm2R6x1zGJJsnacDzTFcRWZyTTMgFdVit6E98LTxO+v8LCCLWRvPrjdzXHx9FEOA8oAZPyApWUA==, + } + engines: { node: '>=18' } + cpu: [ia32] + os: [linux] + + '@esbuild/linux-ia32@0.23.1': + resolution: + { + integrity: sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==, + } + engines: { node: '>=18' } + cpu: [ia32] + os: [linux] + + '@esbuild/linux-ia32@0.24.0': + resolution: + { + integrity: sha512-K40ip1LAcA0byL05TbCQ4yJ4swvnbzHscRmUilrmP9Am7//0UjPreh4lpYzvThT2Quw66MhjG//20mrufm40mA==, + } + engines: { node: '>=18' } + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.21.5': + resolution: + { + integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==, + } + engines: { node: '>=12' } cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.27.7': - resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==} - engines: {node: '>=18'} + '@esbuild/linux-loong64@0.23.0': + resolution: + { + integrity: sha512-InQwepswq6urikQiIC/kkx412fqUZudBO4SYKu0N+tGhXRWUqAx+Q+341tFV6QdBifpjYgUndV1hhMq3WeJi7A==, + } + engines: { node: '>=18' } + cpu: [loong64] + os: [linux] + + '@esbuild/linux-loong64@0.23.1': + resolution: + { + integrity: sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==, + } + engines: { node: '>=18' } + cpu: [loong64] + os: [linux] + + '@esbuild/linux-loong64@0.24.0': + resolution: + { + integrity: sha512-0mswrYP/9ai+CU0BzBfPMZ8RVm3RGAN/lmOMgW4aFUSOQBjA31UP8Mr6DDhWSuMwj7jaWOT0p0WoZ6jeHhrD7g==, + } + engines: { node: '>=18' } + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.21.5': + resolution: + { + integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==, + } + engines: { node: '>=12' } cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.27.7': - resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==} - engines: {node: '>=18'} + '@esbuild/linux-mips64el@0.23.0': + resolution: + { + integrity: sha512-J9rflLtqdYrxHv2FqXE2i1ELgNjT+JFURt/uDMoPQLcjWQA5wDKgQA4t/dTqGa88ZVECKaD0TctwsUfHbVoi4w==, + } + engines: { node: '>=18' } + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-mips64el@0.23.1': + resolution: + { + integrity: sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==, + } + engines: { node: '>=18' } + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-mips64el@0.24.0': + resolution: + { + integrity: sha512-hIKvXm0/3w/5+RDtCJeXqMZGkI2s4oMUGj3/jM0QzhgIASWrGO5/RlzAzm5nNh/awHE0A19h/CvHQe6FaBNrRA==, + } + engines: { node: '>=18' } + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.21.5': + resolution: + { + integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==, + } + engines: { node: '>=12' } cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.27.7': - resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==} - engines: {node: '>=18'} + '@esbuild/linux-ppc64@0.23.0': + resolution: + { + integrity: sha512-cShCXtEOVc5GxU0fM+dsFD10qZ5UpcQ8AM22bYj0u/yaAykWnqXJDpd77ublcX6vdDsWLuweeuSNZk4yUxZwtw==, + } + engines: { node: '>=18' } + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-ppc64@0.23.1': + resolution: + { + integrity: sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==, + } + engines: { node: '>=18' } + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-ppc64@0.24.0': + resolution: + { + integrity: sha512-HcZh5BNq0aC52UoocJxaKORfFODWXZxtBaaZNuN3PUX3MoDsChsZqopzi5UupRhPHSEHotoiptqikjN/B77mYQ==, + } + engines: { node: '>=18' } + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.21.5': + resolution: + { + integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==, + } + engines: { node: '>=12' } cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.27.7': - resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==} - engines: {node: '>=18'} + '@esbuild/linux-riscv64@0.23.0': + resolution: + { + integrity: sha512-HEtaN7Y5UB4tZPeQmgz/UhzoEyYftbMXrBCUjINGjh3uil+rB/QzzpMshz3cNUxqXN7Vr93zzVtpIDL99t9aRw==, + } + engines: { node: '>=18' } + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-riscv64@0.23.1': + resolution: + { + integrity: sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==, + } + engines: { node: '>=18' } + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-riscv64@0.24.0': + resolution: + { + integrity: sha512-bEh7dMn/h3QxeR2KTy1DUszQjUrIHPZKyO6aN1X4BCnhfYhuQqedHaa5MxSQA/06j3GpiIlFGSsy1c7Gf9padw==, + } + engines: { node: '>=18' } + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.21.5': + resolution: + { + integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==, + } + engines: { node: '>=12' } cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.27.7': - resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==} - engines: {node: '>=18'} + '@esbuild/linux-s390x@0.23.0': + resolution: + { + integrity: sha512-WDi3+NVAuyjg/Wxi+o5KPqRbZY0QhI9TjrEEm+8dmpY9Xir8+HE/HNx2JoLckhKbFopW0RdO2D72w8trZOV+Wg==, + } + engines: { node: '>=18' } + cpu: [s390x] + os: [linux] + + '@esbuild/linux-s390x@0.23.1': + resolution: + { + integrity: sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==, + } + engines: { node: '>=18' } + cpu: [s390x] + os: [linux] + + '@esbuild/linux-s390x@0.24.0': + resolution: + { + integrity: sha512-ZcQ6+qRkw1UcZGPyrCiHHkmBaj9SiCD8Oqd556HldP+QlpUIe2Wgn3ehQGVoPOvZvtHm8HPx+bH20c9pvbkX3g==, + } + engines: { node: '>=18' } + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.21.5': + resolution: + { + integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==, + } + engines: { node: '>=12' } cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.27.7': - resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] + '@esbuild/linux-x64@0.23.0': + resolution: + { + integrity: sha512-a3pMQhUEJkITgAw6e0bWA+F+vFtCciMjW/LPtoj99MhVt+Mfb6bbL9hu2wmTZgNd994qTAEw+U/r6k3qHWWaOQ==, + } + engines: { node: '>=18' } + cpu: [x64] + os: [linux] - '@esbuild/netbsd-x64@0.27.7': - resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==} - engines: {node: '>=18'} + '@esbuild/linux-x64@0.23.1': + resolution: + { + integrity: sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==, + } + engines: { node: '>=18' } + cpu: [x64] + os: [linux] + + '@esbuild/linux-x64@0.24.0': + resolution: + { + integrity: sha512-vbutsFqQ+foy3wSSbmjBXXIJ6PL3scghJoM8zCL142cGaZKAdCZHyf+Bpu/MmX9zT9Q0zFBVKb36Ma5Fzfa8xA==, + } + engines: { node: '>=18' } + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-x64@0.21.5': + resolution: + { + integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==, + } + engines: { node: '>=12' } cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.27.7': - resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} - engines: {node: '>=18'} + '@esbuild/netbsd-x64@0.23.0': + resolution: + { + integrity: sha512-cRK+YDem7lFTs2Q5nEv/HHc4LnrfBCbH5+JHu6wm2eP+d8OZNoSMYgPZJq78vqQ9g+9+nMuIsAO7skzphRXHyw==, + } + engines: { node: '>=18' } + cpu: [x64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.23.1': + resolution: + { + integrity: sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==, + } + engines: { node: '>=18' } + cpu: [x64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.24.0': + resolution: + { + integrity: sha512-hjQ0R/ulkO8fCYFsG0FZoH+pWgTTDreqpqY7UnQntnaKv95uP5iW3+dChxnx7C3trQQU40S+OgWhUVwCjVFLvg==, + } + engines: { node: '>=18' } + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.23.0': + resolution: + { + integrity: sha512-suXjq53gERueVWu0OKxzWqk7NxiUWSUlrxoZK7usiF50C6ipColGR5qie2496iKGYNLhDZkPxBI3erbnYkU0rQ==, + } + engines: { node: '>=18' } cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.27.7': - resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==} - engines: {node: '>=18'} + '@esbuild/openbsd-arm64@0.23.1': + resolution: + { + integrity: sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==, + } + engines: { node: '>=18' } + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-arm64@0.24.0': + resolution: + { + integrity: sha512-MD9uzzkPQbYehwcN583yx3Tu5M8EIoTD+tUgKF982WYL9Pf5rKy9ltgD0eUgs8pvKnmizxjXZyLt0z6DC3rRXg==, + } + engines: { node: '>=18' } + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.21.5': + resolution: + { + integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==, + } + engines: { node: '>=12' } cpu: [x64] os: [openbsd] - '@esbuild/openharmony-arm64@0.27.7': - resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] + '@esbuild/openbsd-x64@0.23.0': + resolution: + { + integrity: sha512-6p3nHpby0DM/v15IFKMjAaayFhqnXV52aEmv1whZHX56pdkK+MEaLoQWj+H42ssFarP1PcomVhbsR4pkz09qBg==, + } + engines: { node: '>=18' } + cpu: [x64] + os: [openbsd] - '@esbuild/sunos-x64@0.27.7': - resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} - engines: {node: '>=18'} + '@esbuild/openbsd-x64@0.23.1': + resolution: + { + integrity: sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==, + } + engines: { node: '>=18' } + cpu: [x64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.24.0': + resolution: + { + integrity: sha512-4ir0aY1NGUhIC1hdoCzr1+5b43mw99uNwVzhIq1OY3QcEwPDO3B7WNXBzaKY5Nsf1+N11i1eOfFcq+D/gOS15Q==, + } + engines: { node: '>=18' } + cpu: [x64] + os: [openbsd] + + '@esbuild/sunos-x64@0.21.5': + resolution: + { + integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==, + } + engines: { node: '>=12' } cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.27.7': - resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} - engines: {node: '>=18'} + '@esbuild/sunos-x64@0.23.0': + resolution: + { + integrity: sha512-BFelBGfrBwk6LVrmFzCq1u1dZbG4zy/Kp93w2+y83Q5UGYF1d8sCzeLI9NXjKyujjBBniQa8R8PzLFAUrSM9OA==, + } + engines: { node: '>=18' } + cpu: [x64] + os: [sunos] + + '@esbuild/sunos-x64@0.23.1': + resolution: + { + integrity: sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==, + } + engines: { node: '>=18' } + cpu: [x64] + os: [sunos] + + '@esbuild/sunos-x64@0.24.0': + resolution: + { + integrity: sha512-jVzdzsbM5xrotH+W5f1s+JtUy1UWgjU0Cf4wMvffTB8m6wP5/kx0KiaLHlbJO+dMgtxKV8RQ/JvtlFcdZ1zCPA==, + } + engines: { node: '>=18' } + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.21.5': + resolution: + { + integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==, + } + engines: { node: '>=12' } cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.27.7': - resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==} - engines: {node: '>=18'} + '@esbuild/win32-arm64@0.23.0': + resolution: + { + integrity: sha512-lY6AC8p4Cnb7xYHuIxQ6iYPe6MfO2CC43XXKo9nBXDb35krYt7KGhQnOkRGar5psxYkircpCqfbNDB4uJbS2jQ==, + } + engines: { node: '>=18' } + cpu: [arm64] + os: [win32] + + '@esbuild/win32-arm64@0.23.1': + resolution: + { + integrity: sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==, + } + engines: { node: '>=18' } + cpu: [arm64] + os: [win32] + + '@esbuild/win32-arm64@0.24.0': + resolution: + { + integrity: sha512-iKc8GAslzRpBytO2/aN3d2yb2z8XTVfNV0PjGlCxKo5SgWmNXx82I/Q3aG1tFfS+A2igVCY97TJ8tnYwpUWLCA==, + } + engines: { node: '>=18' } + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.21.5': + resolution: + { + integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==, + } + engines: { node: '>=12' } cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.27.7': - resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==} - engines: {node: '>=18'} + '@esbuild/win32-ia32@0.23.0': + resolution: + { + integrity: sha512-7L1bHlOTcO4ByvI7OXVI5pNN6HSu6pUQq9yodga8izeuB1KcT2UkHaH6118QJwopExPn0rMHIseCTx1CRo/uNA==, + } + engines: { node: '>=18' } + cpu: [ia32] + os: [win32] + + '@esbuild/win32-ia32@0.23.1': + resolution: + { + integrity: sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==, + } + engines: { node: '>=18' } + cpu: [ia32] + os: [win32] + + '@esbuild/win32-ia32@0.24.0': + resolution: + { + integrity: sha512-vQW36KZolfIudCcTnaTpmLQ24Ha1RjygBo39/aLkM2kmjkWmZGEJ5Gn9l5/7tzXA42QGIoWbICfg6KLLkIw6yw==, + } + engines: { node: '>=18' } + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.21.5': + resolution: + { + integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==, + } + engines: { node: '>=12' } cpu: [x64] os: [win32] - '@img/colour@1.1.0': - resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} - engines: {node: '>=18'} + '@esbuild/win32-x64@0.23.0': + resolution: + { + integrity: sha512-Arm+WgUFLUATuoxCJcahGuk6Yj9Pzxd6l11Zb/2aAuv5kWWvvfhLFo2fni4uSK5vzlUdCGZ/BdV5tH8klj8p8g==, + } + engines: { node: '>=18' } + cpu: [x64] + os: [win32] - '@img/sharp-darwin-arm64@0.34.5': - resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@esbuild/win32-x64@0.23.1': + resolution: + { + integrity: sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==, + } + engines: { node: '>=18' } + cpu: [x64] + os: [win32] + + '@esbuild/win32-x64@0.24.0': + resolution: + { + integrity: sha512-7IAFPrjSQIJrGsK6flwg7NFmwBoSTyF3rl7If0hNUFQU4ilTsEPL6GuMuU9BfIWVVGuRnuIidkSMC+c0Otu8IA==, + } + engines: { node: '>=18' } + cpu: [x64] + os: [win32] + + '@eslint-community/eslint-utils@4.4.0': + resolution: + { + integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==, + } + engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.11.1': + resolution: + { + integrity: sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==, + } + engines: { node: ^12.0.0 || ^14.0.0 || >=16.0.0 } + + '@eslint-community/regexpp@4.12.1': + resolution: + { + integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==, + } + engines: { node: ^12.0.0 || ^14.0.0 || >=16.0.0 } + + '@eslint/config-array@0.19.0': + resolution: + { + integrity: sha512-zdHg2FPIFNKPdcHWtiNT+jEFCHYVplAXRDlQDyqy0zGx/q2parwh7brGJSiTxRk/TSMkbM//zt/f5CHgyTyaSQ==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + '@eslint/core@0.9.0': + resolution: + { + integrity: sha512-7ATR9F0e4W85D/0w7cU0SNj7qkAexMG+bAHEZOjo9akvGuhHE2m7umzWzfnpa0XAg5Kxc1BWmtPMV67jJ+9VUg==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + '@eslint/eslintrc@3.2.0': + resolution: + { + integrity: sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + '@eslint/js@9.15.0': + resolution: + { + integrity: sha512-tMTqrY+EzbXmKJR5ToI8lxu7jaN5EdmrBFJpQk5JmSlyLsx6o4t27r883K5xsLuCYCpfKBCGswMSWXsM+jB7lg==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + '@eslint/object-schema@2.1.4': + resolution: + { + integrity: sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + '@eslint/plugin-kit@0.2.3': + resolution: + { + integrity: sha512-2b/g5hRmpbb1o4GnTZax9N9m0FXzz9OV42ZzI4rDDMDuHUqigAiQCEWChBWCY4ztAGVRjoWT19v0yMmc5/L5kA==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + '@humanfs/core@0.19.1': + resolution: + { + integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==, + } + engines: { node: '>=18.18.0' } + + '@humanfs/node@0.16.6': + resolution: + { + integrity: sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==, + } + engines: { node: '>=18.18.0' } + + '@humanwhocodes/module-importer@1.0.1': + resolution: + { + integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==, + } + engines: { node: '>=12.22' } + + '@humanwhocodes/retry@0.3.1': + resolution: + { + integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==, + } + engines: { node: '>=18.18' } + + '@humanwhocodes/retry@0.4.1': + resolution: + { + integrity: sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==, + } + engines: { node: '>=18.18' } + + '@img/sharp-darwin-arm64@0.33.5': + resolution: + { + integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } cpu: [arm64] os: [darwin] - '@img/sharp-darwin-x64@0.34.5': - resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-darwin-x64@0.33.5': + resolution: + { + integrity: sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } cpu: [x64] os: [darwin] - '@img/sharp-libvips-darwin-arm64@1.2.4': - resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + '@img/sharp-libvips-darwin-arm64@1.0.4': + resolution: + { + integrity: sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==, + } cpu: [arm64] os: [darwin] - '@img/sharp-libvips-darwin-x64@1.2.4': - resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + '@img/sharp-libvips-darwin-x64@1.0.4': + resolution: + { + integrity: sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==, + } cpu: [x64] os: [darwin] - '@img/sharp-libvips-linux-arm64@1.2.4': - resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + '@img/sharp-libvips-linux-arm64@1.0.4': + resolution: + { + integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==, + } cpu: [arm64] os: [linux] - libc: [glibc] - '@img/sharp-libvips-linux-arm@1.2.4': - resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + '@img/sharp-libvips-linux-arm@1.0.5': + resolution: + { + integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==, + } cpu: [arm] os: [linux] - libc: [glibc] - '@img/sharp-libvips-linux-ppc64@1.2.4': - resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} - cpu: [ppc64] - os: [linux] - libc: [glibc] - - '@img/sharp-libvips-linux-riscv64@1.2.4': - resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} - cpu: [riscv64] - os: [linux] - libc: [glibc] - - '@img/sharp-libvips-linux-s390x@1.2.4': - resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + '@img/sharp-libvips-linux-s390x@1.0.4': + resolution: + { + integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==, + } cpu: [s390x] os: [linux] - libc: [glibc] - '@img/sharp-libvips-linux-x64@1.2.4': - resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + '@img/sharp-libvips-linux-x64@1.0.4': + resolution: + { + integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==, + } cpu: [x64] os: [linux] - libc: [glibc] - '@img/sharp-libvips-linuxmusl-arm64@1.2.4': - resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + '@img/sharp-libvips-linuxmusl-arm64@1.0.4': + resolution: + { + integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==, + } cpu: [arm64] os: [linux] - libc: [musl] - '@img/sharp-libvips-linuxmusl-x64@1.2.4': - resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + '@img/sharp-libvips-linuxmusl-x64@1.0.4': + resolution: + { + integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==, + } cpu: [x64] os: [linux] - libc: [musl] - '@img/sharp-linux-arm64@0.34.5': - resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-arm64@0.33.5': + resolution: + { + integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } cpu: [arm64] os: [linux] - libc: [glibc] - '@img/sharp-linux-arm@0.34.5': - resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-arm@0.33.5': + resolution: + { + integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } cpu: [arm] os: [linux] - libc: [glibc] - '@img/sharp-linux-ppc64@0.34.5': - resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [ppc64] - os: [linux] - libc: [glibc] - - '@img/sharp-linux-riscv64@0.34.5': - resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [riscv64] - os: [linux] - libc: [glibc] - - '@img/sharp-linux-s390x@0.34.5': - resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-s390x@0.33.5': + resolution: + { + integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } cpu: [s390x] os: [linux] - libc: [glibc] - '@img/sharp-linux-x64@0.34.5': - resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-x64@0.33.5': + resolution: + { + integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } cpu: [x64] os: [linux] - libc: [glibc] - '@img/sharp-linuxmusl-arm64@0.34.5': - resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linuxmusl-arm64@0.33.5': + resolution: + { + integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } cpu: [arm64] os: [linux] - libc: [musl] - '@img/sharp-linuxmusl-x64@0.34.5': - resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linuxmusl-x64@0.33.5': + resolution: + { + integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } cpu: [x64] os: [linux] - libc: [musl] - '@img/sharp-wasm32@0.34.5': - resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-wasm32@0.33.5': + resolution: + { + integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } cpu: [wasm32] - '@img/sharp-win32-arm64@0.34.5': - resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [arm64] - os: [win32] - - '@img/sharp-win32-ia32@0.34.5': - resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-win32-ia32@0.33.5': + resolution: + { + integrity: sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } cpu: [ia32] os: [win32] - '@img/sharp-win32-x64@0.34.5': - resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-win32-x64@0.33.5': + resolution: + { + integrity: sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } cpu: [x64] os: [win32] - '@inquirer/ansi@2.0.7': - resolution: {integrity: sha512-3eTuUO1vH2cZm2ZKHeQxnOqlTi9EfZDGgIe3BL3I4u+rJHocr9Fz86M4fjYABPvFnQG/gGK551HqDiIcETwU6Q==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} + '@isaacs/cliui@8.0.2': + resolution: + { + integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==, + } + engines: { node: '>=12' } - '@inquirer/checkbox@5.2.1': - resolution: {integrity: sha512-b6xmA/VlTe0ZgDQHDui+Nav470u7u49nRd8/iuhOcQPO9Ch7lGuogydhi2VOmNlZ+zXcM8IcPuNSwQcdJaF/kw==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - - '@inquirer/confirm@6.1.1': - resolution: {integrity: sha512-eb8DBZcz/2qHWQda4rk2JiQk5h9QV/cVHi1yjt0f69WFZMRFn0sJTye3EAP8icut8UDMjQPsaH5KbcOogefrFQ==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - - '@inquirer/core@11.2.1': - resolution: {integrity: sha512-Qd6GJT1yVyrZZCfN8W2qKF5ApmqryXRhRKCuip8h01x2w/esJQ2XIYc6f9abMIHgKQdBfFTSOdbHRLAhuM09UA==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - - '@inquirer/editor@5.2.2': - resolution: {integrity: sha512-ZRVd/oD+sYsUd5zVm0NflqEzlqfYCyHNsqkHl2oWXEUHs12tCbcSFi+wVFEvD8+LGRaMUsVrE7qeo6lSG/S1Vg==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - - '@inquirer/expand@5.1.1': - resolution: {integrity: sha512-YmQpenjbFSHAK3sOd44puHh3V1KXXr+JiNpUztoSQ4drLh2rTVzTap/YtlAVu/5xavifIlBfNEzJ/neZJ1a/1g==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - - '@inquirer/external-editor@3.0.3': - resolution: {integrity: sha512-6thf5I8q7lZwzGLAxPaaGEREEkZ3nyePPDQ1oyobblxmEE8mqTLguScP7pDjUTAibiyb4hfXl+qjUEJ+di/aNA==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - - '@inquirer/figures@2.0.7': - resolution: {integrity: sha512-aJ8TBPOGB6f/2qziPfElISTCEd5XOYTFckA2SGjhNmiKzfK/u4ot3v0DUzGVdUnKjN10EqnnEPck36BkyfLnJw==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} - - '@inquirer/input@5.1.2': - resolution: {integrity: sha512-9K/DDBSQpOyZSkt6sOVP9Vo0TR7atX2kuILsUu0x3wVcVbe97lJwIJKMLdMw25tDYuXl/qp6erT0Xs1rfmcfZg==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - - '@inquirer/number@4.1.1': - resolution: {integrity: sha512-XF4IXAbPnGPgw0wsbC/i2tPcyfdZgDpUlhsqU0SfT4IRIGWha6Xm9VRgN5yYxJq+jnyXlfXI/nQ3ulfk0iEICA==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - - '@inquirer/password@5.1.1': - resolution: {integrity: sha512-3XBfF7DAsp5qeDsvN5Rd1HmbNokVvEQoUM0QLrRcybC9nX96w3Pbmu7qUsb3IT3J3jBvs2+mTXaKHOUsgHMLzg==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - - '@inquirer/prompts@8.5.2': - resolution: {integrity: sha512-IYR/3C/paEVVQYQvdDlFZVjRCJVYHHON0XXMH91KO9GSxs0TdKYWlUdvfQl2EfAHDxUaN3IBffkE/BDTh5nJ6g==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - - '@inquirer/rawlist@5.3.1': - resolution: {integrity: sha512-QqdTqQddL3qPX/PPrjobpsO25NZ4dWXgTLenrR445L2ptLEYE6Z+PD5c5CNDJNx4ugRgELAIpSIJxZaO2jJ2Og==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - - '@inquirer/search@4.2.1': - resolution: {integrity: sha512-xJj8QWKRSrfKoBIITLZK61dD3zwo0Rz11fgDImku30/Oe81zMdIdGgrLY2h6RkJ+KZ/GhNYIRMKnH/62qBTA5g==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - - '@inquirer/select@5.2.1': - resolution: {integrity: sha512-FlDndEUww8m7BfukO2nJa25vhD+H5jxxCv4oGioKqzyWz3nPHhhw4LKdYRSlXuAx7DsdWia7iyaBPKKS95Evfw==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - - '@inquirer/type@4.0.7': - resolution: {integrity: sha512-t28inv14nMQ1PhKpsJPY+kEs/c00qzeCOS2gTNRyTjG5d6qsVA2fItxW4hkvGZ5lvanGLdtCzVIx5dwdRpN1+g==} - engines: {node: '>=23.5.0 || ^22.13.0 || ^20.17.0'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - - '@jridgewell/gen-mapping@0.3.13': - resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} - - '@jridgewell/remapping@2.3.5': - resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + '@jridgewell/gen-mapping@0.3.5': + resolution: + { + integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==, + } + engines: { node: '>=6.0.0' } '@jridgewell/resolve-uri@3.1.2': - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} + resolution: + { + integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==, + } + engines: { node: '>=6.0.0' } - '@jridgewell/source-map@0.3.11': - resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} + '@jridgewell/set-array@1.2.1': + resolution: + { + integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==, + } + engines: { node: '>=6.0.0' } - '@jridgewell/sourcemap-codec@1.5.5': - resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + '@jridgewell/source-map@0.3.6': + resolution: + { + integrity: sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==, + } - '@jridgewell/trace-mapping@0.3.31': - resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@jridgewell/sourcemap-codec@1.5.0': + resolution: + { + integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==, + } - '@napi-rs/cli@3.7.4': - resolution: {integrity: sha512-idELIUceJ9zPgx/shcMt1fSSsteFG68v56RIXi4qUm7OYuJOt7CoMj2KnHVmbOqXgUHWQU1lCULrtQdZDG4F5A==} - engines: {node: '>= 16'} + '@jridgewell/trace-mapping@0.3.25': + resolution: + { + integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==, + } + + '@napi-rs/cli@2.18.4': + resolution: + { + integrity: sha512-SgJeA4df9DE2iAEpr3M2H0OKl/yjtg1BnRI5/JyowS71tUWhrfSu2LT0V3vlHET+g1hBVlrO60PmEXwUEKp8Mg==, + } + engines: { node: '>= 10' } hasBin: true - peerDependencies: - '@emnapi/runtime': ^1.7.1 - peerDependenciesMeta: - '@emnapi/runtime': - optional: true - '@napi-rs/cross-toolchain@1.0.3': - resolution: {integrity: sha512-ENPfLe4937bsKVTDA6zdABx4pq9w0tHqRrJHyaGxgaPq03a2Bd1unD5XSKjXJjebsABJ+MjAv1A2OvCgK9yehg==} - peerDependencies: - '@napi-rs/cross-toolchain-arm64-target-aarch64': ^1.0.3 - '@napi-rs/cross-toolchain-arm64-target-armv7': ^1.0.3 - '@napi-rs/cross-toolchain-arm64-target-ppc64le': ^1.0.3 - '@napi-rs/cross-toolchain-arm64-target-s390x': ^1.0.3 - '@napi-rs/cross-toolchain-arm64-target-x86_64': ^1.0.3 - '@napi-rs/cross-toolchain-x64-target-aarch64': ^1.0.3 - '@napi-rs/cross-toolchain-x64-target-armv7': ^1.0.3 - '@napi-rs/cross-toolchain-x64-target-ppc64le': ^1.0.3 - '@napi-rs/cross-toolchain-x64-target-s390x': ^1.0.3 - '@napi-rs/cross-toolchain-x64-target-x86_64': ^1.0.3 - peerDependenciesMeta: - '@napi-rs/cross-toolchain-arm64-target-aarch64': - optional: true - '@napi-rs/cross-toolchain-arm64-target-armv7': - optional: true - '@napi-rs/cross-toolchain-arm64-target-ppc64le': - optional: true - '@napi-rs/cross-toolchain-arm64-target-s390x': - optional: true - '@napi-rs/cross-toolchain-arm64-target-x86_64': - optional: true - '@napi-rs/cross-toolchain-x64-target-aarch64': - optional: true - '@napi-rs/cross-toolchain-x64-target-armv7': - optional: true - '@napi-rs/cross-toolchain-x64-target-ppc64le': - optional: true - '@napi-rs/cross-toolchain-x64-target-s390x': - optional: true - '@napi-rs/cross-toolchain-x64-target-x86_64': - optional: true + '@next/env@15.0.3': + resolution: + { + integrity: sha512-t9Xy32pjNOvVn2AS+Utt6VmyrshbpfUMhIjFO60gI58deSo/KgLOp31XZ4O+kY/Is8WAGYwA5gR7kOb1eORDBA==, + } - '@napi-rs/lzma-android-arm-eabi@1.4.5': - resolution: {integrity: sha512-Up4gpyw2SacmyKWWEib06GhiDdF+H+CCU0LAV8pnM4aJIDqKKd5LHSlBht83Jut6frkB0vwEPmAkv4NjQ5u//Q==} - engines: {node: '>= 10'} - cpu: [arm] - os: [android] + '@next/eslint-plugin-next@15.0.3': + resolution: + { + integrity: sha512-3Ln/nHq2V+v8uIaxCR6YfYo7ceRgZNXfTd3yW1ukTaFbO+/I8jNakrjYWODvG9BuR2v5kgVtH/C8r0i11quOgw==, + } - '@napi-rs/lzma-android-arm64@1.4.5': - resolution: {integrity: sha512-uwa8sLlWEzkAM0MWyoZJg0JTD3BkPknvejAFG2acUA1raXM8jLrqujWCdOStisXhqQjZ2nDMp3FV6cs//zjfuQ==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [android] - - '@napi-rs/lzma-darwin-arm64@1.4.5': - resolution: {integrity: sha512-0Y0TQLQ2xAjVabrMDem1NhIssOZzF/y/dqetc6OT8mD3xMTDtF8u5BqZoX3MyPc9FzpsZw4ksol+w7DsxHrpMA==} - engines: {node: '>= 10'} + '@next/swc-darwin-arm64@15.0.3': + resolution: + { + integrity: sha512-s3Q/NOorCsLYdCKvQlWU+a+GeAd3C8Rb3L1YnetsgwXzhc3UTWrtQpB/3eCjFOdGUj5QmXfRak12uocd1ZiiQw==, + } + engines: { node: '>= 10' } cpu: [arm64] os: [darwin] - '@napi-rs/lzma-darwin-x64@1.4.5': - resolution: {integrity: sha512-vR2IUyJY3En+V1wJkwmbGWcYiT8pHloTAWdW4pG24+51GIq+intst6Uf6D/r46citObGZrlX0QvMarOkQeHWpw==} - engines: {node: '>= 10'} + '@next/swc-darwin-x64@15.0.3': + resolution: + { + integrity: sha512-Zxl/TwyXVZPCFSf0u2BNj5sE0F2uR6iSKxWpq4Wlk/Sv9Ob6YCKByQTkV2y6BCic+fkabp9190hyrDdPA/dNrw==, + } + engines: { node: '>= 10' } cpu: [x64] os: [darwin] - '@napi-rs/lzma-freebsd-x64@1.4.5': - resolution: {integrity: sha512-XpnYQC5SVovO35tF0xGkbHYjsS6kqyNCjuaLQ2dbEblFRr5cAZVvsJ/9h7zj/5FluJPJRDojVNxGyRhTp4z2lw==} - engines: {node: '>= 10'} - cpu: [x64] - os: [freebsd] - - '@napi-rs/lzma-linux-arm-gnueabihf@1.4.5': - resolution: {integrity: sha512-ic1ZZMoRfRMwtSwxkyw4zIlbDZGC6davC9r+2oX6x9QiF247BRqqT94qGeL5ZP4Vtz0Hyy7TEViWhx5j6Bpzvw==} - engines: {node: '>= 10'} - cpu: [arm] - os: [linux] - - '@napi-rs/lzma-linux-arm64-gnu@1.4.5': - resolution: {integrity: sha512-asEp7FPd7C1Yi6DQb45a3KPHKOFBSfGuJWXcAd4/bL2Fjetb2n/KK2z14yfW8YC/Fv6x3rBM0VAZKmJuz4tysg==} - engines: {node: '>= 10'} + '@next/swc-linux-arm64-gnu@15.0.3': + resolution: + { + integrity: sha512-T5+gg2EwpsY3OoaLxUIofmMb7ohAUlcNZW0fPQ6YAutaWJaxt1Z1h+8zdl4FRIOr5ABAAhXtBcpkZNwUcKI2fw==, + } + engines: { node: '>= 10' } cpu: [arm64] os: [linux] - libc: [glibc] - '@napi-rs/lzma-linux-arm64-musl@1.4.5': - resolution: {integrity: sha512-yWjcPDgJ2nIL3KNvi4536dlT/CcCWO0DUyEOlBs/SacG7BeD6IjGh6yYzd3/X1Y3JItCbZoDoLUH8iB1lTXo3w==} - engines: {node: '>= 10'} + '@next/swc-linux-arm64-musl@15.0.3': + resolution: + { + integrity: sha512-WkAk6R60mwDjH4lG/JBpb2xHl2/0Vj0ZRu1TIzWuOYfQ9tt9NFsIinI1Epma77JVgy81F32X/AeD+B2cBu/YQA==, + } + engines: { node: '>= 10' } cpu: [arm64] os: [linux] - libc: [musl] - '@napi-rs/lzma-linux-ppc64-gnu@1.4.5': - resolution: {integrity: sha512-0XRhKuIU/9ZjT4WDIG/qnX7Xz7mSQHYZo9Gb3MP2gcvBgr6BA4zywQ9k3gmQaPn9ECE+CZg2V7DV7kT+x2pUMQ==} - engines: {node: '>= 10'} - cpu: [ppc64] - os: [linux] - libc: [glibc] - - '@napi-rs/lzma-linux-riscv64-gnu@1.4.5': - resolution: {integrity: sha512-QrqDIPEUUB23GCpyQj/QFyMlr8SGxxyExeZz9OWFnHfb70kXdTLWrHS/hEI1Ru+lSbQ/6xRqeoGyQ4Aqdg+/RA==} - engines: {node: '>= 10'} - cpu: [riscv64] - os: [linux] - libc: [glibc] - - '@napi-rs/lzma-linux-s390x-gnu@1.4.5': - resolution: {integrity: sha512-k8RVM5aMhW86E9H0QXdquwojew4H3SwPxbRVbl49/COJQWCUjGi79X6mYruMnMPEznZinUiT1jgKbFo2A00NdA==} - engines: {node: '>= 10'} - cpu: [s390x] - os: [linux] - libc: [glibc] - - '@napi-rs/lzma-linux-x64-gnu@1.4.5': - resolution: {integrity: sha512-6rMtBgnIq2Wcl1rQdZsnM+rtCcVCbws1nF8S2NzaUsVaZv8bjrPiAa0lwg4Eqnn1d9lgwqT+cZgm5m+//K08Kw==} - engines: {node: '>= 10'} + '@next/swc-linux-x64-gnu@15.0.3': + resolution: + { + integrity: sha512-gWL/Cta1aPVqIGgDb6nxkqy06DkwJ9gAnKORdHWX1QBbSZZB+biFYPFti8aKIQL7otCE1pjyPaXpFzGeG2OS2w==, + } + engines: { node: '>= 10' } cpu: [x64] os: [linux] - libc: [glibc] - '@napi-rs/lzma-linux-x64-musl@1.4.5': - resolution: {integrity: sha512-eiadGBKi7Vd0bCArBUOO/qqRYPHt/VQVvGyYvDFt6C2ZSIjlD+HuOl+2oS1sjf4CFjK4eDIog6EdXnL0NE6iyQ==} - engines: {node: '>= 10'} + '@next/swc-linux-x64-musl@15.0.3': + resolution: + { + integrity: sha512-QQEMwFd8r7C0GxQS62Zcdy6GKx999I/rTO2ubdXEe+MlZk9ZiinsrjwoiBL5/57tfyjikgh6GOU2WRQVUej3UA==, + } + engines: { node: '>= 10' } cpu: [x64] os: [linux] - libc: [musl] - '@napi-rs/lzma-wasm32-wasi@1.4.5': - resolution: {integrity: sha512-+VyHHlr68dvey6fXc2hehw9gHVFIW3TtGF1XkcbAu65qVXsA9D/T+uuoRVqhE+JCyFHFrO0ixRbZDRK1XJt1sA==} - engines: {node: '>=14.0.0'} - cpu: [wasm32] - - '@napi-rs/lzma-win32-arm64-msvc@1.4.5': - resolution: {integrity: sha512-eewnqvIyyhHi3KaZtBOJXohLvwwN27gfS2G/YDWdfHlbz1jrmfeHAmzMsP5qv8vGB+T80TMHNkro4kYjeh6Deg==} - engines: {node: '>= 10'} + '@next/swc-win32-arm64-msvc@15.0.3': + resolution: + { + integrity: sha512-9TEp47AAd/ms9fPNgtgnT7F3M1Hf7koIYYWCMQ9neOwjbVWJsHZxrFbI3iEDJ8rf1TDGpmHbKxXf2IFpAvheIQ==, + } + engines: { node: '>= 10' } cpu: [arm64] os: [win32] - '@napi-rs/lzma-win32-ia32-msvc@1.4.5': - resolution: {integrity: sha512-OeacFVRCJOKNU/a0ephUfYZ2Yt+NvaHze/4TgOwJ0J0P4P7X1mHzN+ig9Iyd74aQDXYqc7kaCXA2dpAOcH87Cg==} - engines: {node: '>= 10'} - cpu: [ia32] - os: [win32] - - '@napi-rs/lzma-win32-x64-msvc@1.4.5': - resolution: {integrity: sha512-T4I1SamdSmtyZgDXGAGP+y5LEK5vxHUFwe8mz6D4R7Sa5/WCxTcCIgPJ9BD7RkpO17lzhlaM2vmVvMy96Lvk9Q==} - engines: {node: '>= 10'} - cpu: [x64] - os: [win32] - - '@napi-rs/lzma@1.4.5': - resolution: {integrity: sha512-zS5LuN1OBPAyZpda2ZZgYOEDC+xecUdAGnrvbYzjnLXkrq/OBC3B9qcRvlxbDR3k5H/gVfvef1/jyUqPknqjbg==} - engines: {node: '>= 10'} - - '@napi-rs/tar-android-arm-eabi@1.1.0': - resolution: {integrity: sha512-h2Ryndraj/YiKgMV/r5by1cDusluYIRT0CaE0/PekQ4u+Wpy2iUVqvzVU98ZPnhXaNeYxEvVJHNGafpOfaD0TA==} - engines: {node: '>= 10'} - cpu: [arm] - os: [android] - - '@napi-rs/tar-android-arm64@1.1.0': - resolution: {integrity: sha512-DJFyQHr1ZxNZorm/gzc1qBNLF/FcKzcH0V0Vwan5P+o0aE2keQIGEjJ09FudkF9v6uOuJjHCVDdK6S6uHtShAw==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [android] - - '@napi-rs/tar-darwin-arm64@1.1.0': - resolution: {integrity: sha512-Zz2sXRzjIX4e532zD6xm2SjXEym6MkvfCvL2RMpG2+UwNVDVscHNcz3d47Pf3sysP2e2af7fBB3TIoK2f6trPw==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [darwin] - - '@napi-rs/tar-darwin-x64@1.1.0': - resolution: {integrity: sha512-EI+CptIMNweT0ms9S3mkP/q+J6FNZ1Q6pvpJOEcWglRfyfQpLqjlC0O+dptruTPE8VamKYuqdjxfqD8hifZDOA==} - engines: {node: '>= 10'} - cpu: [x64] - os: [darwin] - - '@napi-rs/tar-freebsd-x64@1.1.0': - resolution: {integrity: sha512-J0PIqX+pl6lBIAckL/c87gpodLbjZB1OtIK+RDscKC9NLdpVv6VGOxzUV/fYev/hctcE8EfkLbgFOfpmVQPg2g==} - engines: {node: '>= 10'} - cpu: [x64] - os: [freebsd] - - '@napi-rs/tar-linux-arm-gnueabihf@1.1.0': - resolution: {integrity: sha512-SLgIQo3f3EjkZ82ZwvrEgFvMdDAhsxCYjyoSuWfHCz0U16qx3SuGCp8+FYOPYCECHN3ZlGjXnoAIt9ERd0dEUg==} - engines: {node: '>= 10'} - cpu: [arm] - os: [linux] - - '@napi-rs/tar-linux-arm64-gnu@1.1.0': - resolution: {integrity: sha512-d014cdle52EGaH6GpYTQOP9Py7glMO1zz/+ynJPjjzYFSxvdYx0byrjumZk2UQdIyGZiJO2MEFpCkEEKFSgPYA==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@napi-rs/tar-linux-arm64-musl@1.1.0': - resolution: {integrity: sha512-L/y1/26q9L/uBqiW/JdOb/Dc94egFvNALUZV2WCGKQXc6UByPBMgdiEyW2dtoYxYYYYc+AKD+jr+wQPcvX2vrQ==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@napi-rs/tar-linux-ppc64-gnu@1.1.0': - resolution: {integrity: sha512-EPE1K/80RQvPbLRJDJs1QmCIcH+7WRi0F73+oTe1582y9RtfGRuzAkzeBuAGRXAQEjRQw/RjtNqr6UTJ+8UuWQ==} - engines: {node: '>= 10'} - cpu: [ppc64] - os: [linux] - libc: [glibc] - - '@napi-rs/tar-linux-s390x-gnu@1.1.0': - resolution: {integrity: sha512-B2jhWiB1ffw1nQBqLUP1h4+J1ovAxBOoe5N2IqDMOc63fsPZKNqF1PvO/dIem8z7LL4U4bsfmhy3gBfu547oNQ==} - engines: {node: '>= 10'} - cpu: [s390x] - os: [linux] - libc: [glibc] - - '@napi-rs/tar-linux-x64-gnu@1.1.0': - resolution: {integrity: sha512-tbZDHnb9617lTnsDMGo/eAMZxnsQFnaRe+MszRqHguKfMwkisc9CCJnks/r1o84u5fECI+J/HOrKXgczq/3Oww==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@napi-rs/tar-linux-x64-musl@1.1.0': - resolution: {integrity: sha512-dV6cODlzbO8u6Anmv2N/ilQHq/AWz0xyltuXoLU3yUyXbZcnWYZuB2rL8OBGPmqNcD+x9NdScBNXh7vWN0naSQ==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - libc: [musl] - - '@napi-rs/tar-wasm32-wasi@1.1.0': - resolution: {integrity: sha512-jIa9nb2HzOrfH0F8QQ9g3WE4aMH5vSI5/1NYVNm9ysCmNjCCtMXCAhlI3WKCdm/DwHf0zLqdrrtDFXODcNaqMw==} - engines: {node: '>=14.0.0'} - cpu: [wasm32] - - '@napi-rs/tar-win32-arm64-msvc@1.1.0': - resolution: {integrity: sha512-vfpG71OB0ijtjemp3WTdmBKJm9R70KM8vsSExMsIQtV0lVzP07oM1CW6JbNRPXNLhRoue9ofYLiUDk8bE0Hckg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [win32] - - '@napi-rs/tar-win32-ia32-msvc@1.1.0': - resolution: {integrity: sha512-hGPyPW60YSpOSgzfy68DLBHgi6HxkAM+L59ZZZPMQ0TOXjQg+p2EW87+TjZfJOkSpbYiEkULwa/f4a2hcVjsqQ==} - engines: {node: '>= 10'} - cpu: [ia32] - os: [win32] - - '@napi-rs/tar-win32-x64-msvc@1.1.0': - resolution: {integrity: sha512-L6Ed1DxXK9YSCMyvpR8MiNAyKNkQLjsHsHK9E0qnHa8NzLFqzDKhvs5LfnWxM2kJ+F7m/e5n9zPm24kHb3LsVw==} - engines: {node: '>= 10'} - cpu: [x64] - os: [win32] - - '@napi-rs/tar@1.1.0': - resolution: {integrity: sha512-7cmzIu+Vbupriudo7UudoMRH2OA3cTw67vva8MxeoAe5S7vPFI7z0vp0pMXiA25S8IUJefImQ90FeJjl8fjEaQ==} - engines: {node: '>= 10'} - - '@napi-rs/wasm-runtime@1.1.4': - resolution: {integrity: sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==} - peerDependencies: - '@emnapi/core': ^1.7.1 - '@emnapi/runtime': ^1.7.1 - - '@napi-rs/wasm-runtime@1.2.2': - resolution: {integrity: sha512-JfB4kuJQjaoHuCTseIINHtHWeJnvgEcxjwA5t/Y00ZgaOO1Crz3fjT/p8kT28zA/Caz7oiUMn3d6H2yOVCVwuw==} - engines: {node: ^20.19.0 || ^22.13.0 || >=23.5.0} - peerDependencies: - '@emnapi/core': ^1.7.1 || ^2.0.0-alpha.3 - '@emnapi/runtime': ^1.7.1 || ^2.0.0-alpha.3 - - '@napi-rs/wasm-tools-android-arm-eabi@1.0.1': - resolution: {integrity: sha512-lr07E/l571Gft5v4aA1dI8koJEmF1F0UigBbsqg9OWNzg80H3lDPO+auv85y3T/NHE3GirDk7x/D3sLO57vayw==} - engines: {node: '>= 10'} - cpu: [arm] - os: [android] - - '@napi-rs/wasm-tools-android-arm64@1.0.1': - resolution: {integrity: sha512-WDR7S+aRLV6LtBJAg5fmjKkTZIdrEnnQxgdsb7Cf8pYiMWBHLU+LC49OUVppQ2YSPY0+GeYm9yuZWW3kLjJ7Bg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [android] - - '@napi-rs/wasm-tools-darwin-arm64@1.0.1': - resolution: {integrity: sha512-qWTI+EEkiN0oIn/N2gQo7+TVYil+AJ20jjuzD2vATS6uIjVz+Updeqmszi7zq7rdFTLp6Ea3/z4kDKIfZwmR9g==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [darwin] - - '@napi-rs/wasm-tools-darwin-x64@1.0.1': - resolution: {integrity: sha512-bA6hubqtHROR5UI3tToAF/c6TDmaAgF0SWgo4rADHtQ4wdn0JeogvOk50gs2TYVhKPE2ZD2+qqt7oBKB+sxW3A==} - engines: {node: '>= 10'} - cpu: [x64] - os: [darwin] - - '@napi-rs/wasm-tools-freebsd-x64@1.0.1': - resolution: {integrity: sha512-90+KLBkD9hZEjPQW1MDfwSt5J1L46EUKacpCZWyRuL6iIEO5CgWU0V/JnEgFsDOGyyYtiTvHc5bUdUTWd4I9Vg==} - engines: {node: '>= 10'} - cpu: [x64] - os: [freebsd] - - '@napi-rs/wasm-tools-linux-arm64-gnu@1.0.1': - resolution: {integrity: sha512-rG0QlS65x9K/u3HrKafDf8cFKj5wV2JHGfl8abWgKew0GVPyp6vfsDweOwHbWAjcHtp2LHi6JHoW80/MTHm52Q==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@napi-rs/wasm-tools-linux-arm64-musl@1.0.1': - resolution: {integrity: sha512-jAasbIvjZXCgX0TCuEFQr+4D6Lla/3AAVx2LmDuMjgG4xoIXzjKWl7c4chuaD+TI+prWT0X6LJcdzFT+ROKGHQ==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@napi-rs/wasm-tools-linux-x64-gnu@1.0.1': - resolution: {integrity: sha512-Plgk5rPqqK2nocBGajkMVbGm010Z7dnUgq0wtnYRZbzWWxwWcXfZMPa8EYxrK4eE8SzpI7VlZP1tdVsdjgGwMw==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@napi-rs/wasm-tools-linux-x64-musl@1.0.1': - resolution: {integrity: sha512-GW7AzGuWxtQkyHknHWYFdR0CHmW6is8rG2Rf4V6GNmMpmwtXt/ItWYWtBe4zqJWycMNazpfZKSw/BpT7/MVCXQ==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - libc: [musl] - - '@napi-rs/wasm-tools-wasm32-wasi@1.0.1': - resolution: {integrity: sha512-/nQVSTrqSsn7YdAc2R7Ips/tnw5SPUcl3D7QrXCNGPqjbatIspnaexvaOYNyKMU6xPu+pc0BTnKVmqhlJJCPLA==} - engines: {node: '>=14.0.0'} - cpu: [wasm32] - - '@napi-rs/wasm-tools-win32-arm64-msvc@1.0.1': - resolution: {integrity: sha512-PFi7oJIBu5w7Qzh3dwFea3sHRO3pojMsaEnUIy22QvsW+UJfNQwJCryVrpoUt8m4QyZXI+saEq/0r4GwdoHYFQ==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [win32] - - '@napi-rs/wasm-tools-win32-ia32-msvc@1.0.1': - resolution: {integrity: sha512-gXkuYzxQsgkj05Zaq+KQTkHIN83dFAwMcTKa2aQcpYPRImFm2AQzEyLtpXmyCWzJ0F9ZYAOmbSyrNew8/us6bw==} - engines: {node: '>= 10'} - cpu: [ia32] - os: [win32] - - '@napi-rs/wasm-tools-win32-x64-msvc@1.0.1': - resolution: {integrity: sha512-rEAf05nol3e3eei2sRButmgXP+6ATgm0/38MKhz9Isne82T4rPIMYsCIFj0kOisaGeVwoi2fnm7O9oWp5YVnYQ==} - engines: {node: '>= 10'} - cpu: [x64] - os: [win32] - - '@napi-rs/wasm-tools@1.0.1': - resolution: {integrity: sha512-enkZYyuCdo+9jneCPE/0fjIta4wWnvVN9hBo2HuiMpRF0q3lzv1J6b/cl7i0mxZUKhBrV3aCKDBQnCOhwKbPmQ==} - engines: {node: '>= 10'} - - '@next/env@16.2.7': - resolution: {integrity: sha512-tMJizPlj6ZYpBMMdK8S0LJufrP4QTdR6pcv9KQ/bVETPAmg0j1mlHE9G2c38UyGHxoBapgwuj7XjbGJ2RcDFOg==} - - '@next/swc-darwin-arm64@16.2.7': - resolution: {integrity: sha512-vm1EDI/pVaBNNiychmxk3fft+OhQPVD9cIM/tReLZIQ3TfQ4kqI9DwKk00dzuS1ulC7icbrzCFrmRRlk9PfNdw==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [darwin] - - '@next/swc-darwin-x64@16.2.7': - resolution: {integrity: sha512-O3IRSv1ZBL1zs0WrIgefTEcTKFVn+ryxBNe54erJ6KsD+2f/Mmt7g2jOYh8PSBdUwPtKQJuCsTMlZ7tIu2AcsQ==} - engines: {node: '>= 10'} - cpu: [x64] - os: [darwin] - - '@next/swc-linux-arm64-gnu@16.2.7': - resolution: {integrity: sha512-Re6PZtjBDd0aMU+VcZcC/PrIvj4WhrjDYtMhhCVQamWN4L90EVP0pcEOBQD25prSlw7OzNw5QpHLWMilRLsRNw==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@next/swc-linux-arm64-musl@16.2.7': - resolution: {integrity: sha512-qyogG9QtBzWxgJfeGBvOEHI3851gTfCF3wLZ5RDLTBJGAmE9p1qDwKCOdrBrvBzRvYDT+gUDp72pzlSEfAXgNA==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@next/swc-linux-x64-gnu@16.2.7': - resolution: {integrity: sha512-Vhe4ZDuBpmMogrGi5D4R2Kq4JAQlj6+wvgaFYy31zfES0zPmt6TLA+cuYpM/OLrPZjo2MYQTHVqNUSCR6+fDZQ==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@next/swc-linux-x64-musl@16.2.7': - resolution: {integrity: sha512-srvian89JahFLw1YLBEuhvPJ0DO5lpUeJQMXy4xYo7g628ZlNgXdNkqoxSAv9OYrBfByh6vxISMwW/mRbzCY+g==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - libc: [musl] - - '@next/swc-win32-arm64-msvc@16.2.7': - resolution: {integrity: sha512-GX3wvLpULFuRFJzwHaKfm7QZJ18F4ZSuxlPJ96BoBglCzBmdSjyeBKF+ZhWhvL/ckxNfLnNa7bsObO2ipYpszw==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [win32] - - '@next/swc-win32-x64-msvc@16.2.7': - resolution: {integrity: sha512-J4WlM72NMk076Qsg0jTdK3SNXatlSdnjW7L7oNGLst1tAGjHrJh/FYi+pw9wyIjEtGRKDNzD0zuiY16oWYWVaw==} - engines: {node: '>= 10'} + '@next/swc-win32-x64-msvc@15.0.3': + resolution: + { + integrity: sha512-VNAz+HN4OGgvZs6MOoVfnn41kBzT+M+tB+OK4cww6DNyWS6wKaDpaAm/qLeOUbnMh0oVx1+mg0uoYARF69dJyA==, + } + engines: { node: '>= 10' } cpu: [x64] os: [win32] '@nodelib/fs.scandir@2.1.5': - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} + resolution: + { + integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==, + } + engines: { node: '>= 8' } '@nodelib/fs.stat@2.0.5': - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} + resolution: + { + integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==, + } + engines: { node: '>= 8' } '@nodelib/fs.walk@1.2.8': - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} + resolution: + { + integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==, + } + engines: { node: '>= 8' } - '@octokit/auth-token@6.0.0': - resolution: {integrity: sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w==} - engines: {node: '>= 20'} + '@nolyfill/is-core-module@1.0.39': + resolution: + { + integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==, + } + engines: { node: '>=12.4.0' } - '@octokit/core@7.0.6': - resolution: {integrity: sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q==} - engines: {node: '>= 20'} - - '@octokit/endpoint@11.0.3': - resolution: {integrity: sha512-FWFlNxghg4HrXkD3ifYbS/IdL/mDHjh9QcsNyhQjN8dplUoZbejsdpmuqdA76nxj2xoWPs7p8uX2SNr9rYu0Ag==} - engines: {node: '>= 20'} - - '@octokit/graphql@9.0.3': - resolution: {integrity: sha512-grAEuupr/C1rALFnXTv6ZQhFuL1D8G5y8CN04RgrO4FIPMrtm+mcZzFG7dcBm+nq+1ppNixu+Jd78aeJOYxlGA==} - engines: {node: '>= 20'} - - '@octokit/openapi-types@27.0.0': - resolution: {integrity: sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA==} - - '@octokit/plugin-paginate-rest@14.0.0': - resolution: {integrity: sha512-fNVRE7ufJiAA3XUrha2omTA39M6IXIc6GIZLvlbsm8QOQCYvpq/LkMNGyFlB1d8hTDzsAXa3OKtybdMAYsV/fw==} - engines: {node: '>= 20'} - peerDependencies: - '@octokit/core': '>=6' - - '@octokit/plugin-request-log@6.0.0': - resolution: {integrity: sha512-UkOzeEN3W91/eBq9sPZNQ7sUBvYCqYbrrD8gTbBuGtHEuycE4/awMXcYvx6sVYo7LypPhmQwwpUe4Yyu4QZN5Q==} - engines: {node: '>= 20'} - peerDependencies: - '@octokit/core': '>=6' - - '@octokit/plugin-rest-endpoint-methods@17.0.0': - resolution: {integrity: sha512-B5yCyIlOJFPqUUeiD0cnBJwWJO8lkJs5d8+ze9QDP6SvfiXSz1BF+91+0MeI1d2yxgOhU/O+CvtiZ9jSkHhFAw==} - engines: {node: '>= 20'} - peerDependencies: - '@octokit/core': '>=6' - - '@octokit/request-error@7.1.0': - resolution: {integrity: sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw==} - engines: {node: '>= 20'} - - '@octokit/request@10.0.9': - resolution: {integrity: sha512-o8Bi3f608eyM+7BmBiUWxFsdjLb3/ym1cQek5LZOv9KkZcxRrHCPhhRzm6xjO6HVZ85ItD6+sTsjxo821SVa/A==} - engines: {node: '>= 20'} - - '@octokit/rest@22.0.1': - resolution: {integrity: sha512-Jzbhzl3CEexhnivb1iQ0KJ7s5vvjMWcmRtq5aUsKmKDrRW6z3r84ngmiFKFvpZjpiU/9/S6ITPFRpn5s/3uQJw==} - engines: {node: '>= 20'} - - '@octokit/types@16.0.0': - resolution: {integrity: sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg==} - - '@oven/bun-darwin-aarch64@1.3.14': - resolution: {integrity: sha512-Omj20SuiHBOUjUBIyqtkNjSUIjOtEOJwmbix/ZyFH4BaQ6OZTaaRWIR4TjHVz0yadHgli6lLTiAh1uarnvD49A==} + '@oven/bun-darwin-aarch64@1.1.29': + resolution: + { + integrity: sha512-Z8WnrXoAXg6ENU6z+Mil94oipMBMliJIj4XWWqjNC33/ZGPqMdPT5MbFQjbdHjxe5bRBW/aHaMU3G35fGx9Seg==, + } cpu: [arm64] os: [darwin] - '@oven/bun-darwin-x64-baseline@1.3.14': - resolution: {integrity: sha512-OSfsTZstc898HHElhU4NccaBGOSSDn5VfahiVTnidZ9B/+wb7WTyfZJaBeJcfjwJ9H2W9uTh2TGtl3UfcXgV9g==} + '@oven/bun-darwin-x64-baseline@1.1.29': + resolution: + { + integrity: sha512-B+zKlJR+3ANPDU+vNjvXaqgB63hYcCk16/k45hiInvIsDXfSdDn4+LMHwZTFdfUWTCGbNMFg9u4bZCtK0nhMDw==, + } cpu: [x64] os: [darwin] - '@oven/bun-darwin-x64@1.3.14': - resolution: {integrity: sha512-FFj3QdU/OhlDyZOJ8CWfN5eWLpRlT4qjZg7lMQi7jA6GuoY5ajlO1zWLP/MuHYRSbXQUvV52RejNi8DVnAp13w==} + '@oven/bun-darwin-x64@1.1.29': + resolution: + { + integrity: sha512-tDHDR+OWLCKEP0xE8IGCWRxSsxO5tr3rvyrSzy6CXYkoWPz66kODbtbGfWl8HSwunrQxJKnE2L9LWX2Eiz3Cpw==, + } cpu: [x64] os: [darwin] - '@oven/bun-freebsd-aarch64@1.3.14': - resolution: {integrity: sha512-LIKrXaFxAHybVO5Pf+9XP2FHUj/5APvXTUKk9dqHm5iFz4oH+W24cmhjkJirNujh9hKeTyrpWSe3no9JZKowIw==} - cpu: [arm64] - os: [freebsd] - - '@oven/bun-freebsd-x64@1.3.14': - resolution: {integrity: sha512-uwD+fGUH1ADpIF3B1U2jWzzb20QwRLZfj5QZ28GUCGrAJ/nTmWrD6YYGsblCY1wuhldRez3lU40AyuvSCyLYmw==} - cpu: [x64] - os: [freebsd] - - '@oven/bun-linux-aarch64-android@1.3.14': - resolution: {integrity: sha512-y4kq5b85lsrmFb9Xvi4w9mA5IEFJkLMrSmYn06q24KjL9rUWDWO3VFZEtteZxUN5+ec3Zm5S8OnJw1umaCbVjA==} - cpu: [arm64] - os: [android] - - '@oven/bun-linux-aarch64-musl@1.3.14': - resolution: {integrity: sha512-jmqOA92Cd1NL/1XBd4bFkJLxQ86K0RW7ohxS2qzzAvuitO4JiIxjjTeCspoU44zCozH72HpfZfUE2On31OjnWA==} + '@oven/bun-linux-aarch64@1.1.29': + resolution: + { + integrity: sha512-BuV2Gni+FaMo1r7+3vLjefQYtQcWE01zJJ4zCjyzikP1L4r6PUaLeJyKXbqF6sIR0cLjG6LWj66EGskakDyvWA==, + } cpu: [arm64] os: [linux] - '@oven/bun-linux-aarch64@1.3.14': - resolution: {integrity: sha512-X5SsPZHs+iYO8R/efIcRtc7gT2Q2DgPfliCxEkx4cXBumwkw0c/EsHMNwH3EgGpCDaZ7IYVPhpCG/xBOQHEwZw==} - cpu: [arm64] - os: [linux] - - '@oven/bun-linux-x64-android@1.3.14': - resolution: {integrity: sha512-qe9e1d+3VAEU7nAA2ol9Jvmy/o99PVMSgZhHn7Q/9O3YcDrfEqyQ8zm4zoe5qTEo8HZH0dN03Le0Ys2eQPs7eg==} - cpu: [x64] - os: [android] - - '@oven/bun-linux-x64-baseline@1.3.14': - resolution: {integrity: sha512-q/8EdOC0yUE8FPeoOVq8/Pw5I9/tJaYmUfO/uDUAREx8IUnOJH1RJ5A3BjFqre8pvJoiZA9AovPJq5FnNNjSxA==} + '@oven/bun-linux-x64-baseline@1.1.29': + resolution: + { + integrity: sha512-tQhm1SDyymBvc2L3zIN7FI+sI3g9gxavDYuvL/Lz17nEk1oqP5DFE2lF9QWJMDdQL3XQKH/drI27yNpfPHgAPw==, + } cpu: [x64] os: [linux] - '@oven/bun-linux-x64-musl-baseline@1.3.14': - resolution: {integrity: sha512-n6iE71G4lQE4XkrZhQQcL5YUlxDbnq6nqV7zeQi33PMsLT/0kYE+RvHOtBWZ3w0wMdXZfINmp63hIb9ijUBGtw==} + '@oven/bun-linux-x64@1.1.29': + resolution: + { + integrity: sha512-JVLiTafybuOFIeC80mZEzHdkOCCzlOtOV5zCbvYAIb7D3SM64fNBwrR0dvDkJTQtsjbwt8YeVFN2YRSI/wlFkw==, + } cpu: [x64] os: [linux] - '@oven/bun-linux-x64-musl@1.3.14': - resolution: {integrity: sha512-GBCB/k/sIqcr06eTNgg7g46qiUv35Jasx4XiccJ/n7RGqrE4RWUD/XJBbWFprVPjvqd59+QtSnS99XGqvftHfg==} - cpu: [x64] - os: [linux] - - '@oven/bun-linux-x64@1.3.14': - resolution: {integrity: sha512-7OVTAKvwfPmSbIV1HpdOoVVx5VRc427GuPPne93N6vk4eQBPId9nXmZDh9/zGaKPdbVjVtQSZafWQoUjx38Utw==} - cpu: [x64] - os: [linux] - - '@oven/bun-windows-aarch64@1.3.14': - resolution: {integrity: sha512-T7s3x/BsVKQObGU6QDkZeI6wKynzqGbBH1yI77jrrj5siElclxr3DQrDIk8CV4G5/SJq2HHq4kpLyYY2DKCSmA==} - cpu: [arm64] - os: [win32] - - '@oven/bun-windows-x64-baseline@1.3.14': - resolution: {integrity: sha512-uIjLUC1S9DWgICzuoMba7vurBJnBruE4S5CxnvmZkdqWVXRzx1Rgu636HoH+k0qeaQCFh3jeG3JQ1y6fRHv0sw==} + '@oven/bun-windows-x64-baseline@1.1.29': + resolution: + { + integrity: sha512-+QWT8Kp+3Sl54QUa6uBsDzQlX11thMMVAw+yUwSRU4Y5FVSN8RPuxhN8ijJ1QGm1KOYA2sCI6V+3lyNMNmRvAA==, + } cpu: [x64] os: [win32] - '@oven/bun-windows-x64@1.3.14': - resolution: {integrity: sha512-mUFWL3BoYkNpjd8e9PqROiFF/1Xeotq20mABJsiQH62jM1g5zqWh4khw1RZ6bX8Q8fWvlPaxG1PjofkmjUi3vg==} + '@oven/bun-windows-x64@1.1.29': + resolution: + { + integrity: sha512-d930+pSkNVHPJJBryIh1gsAKk7lp1HzcktFe0bfxwmpHwjj4BiVfMjU1YaCnsdWKNs2Nv1Y1PLVDNyUCQVfo0Q==, + } cpu: [x64] os: [win32] - '@oxc-project/types@0.142.0': - resolution: {integrity: sha512-7W+2q5AKQVU36fkaryontrHn3YDt1RyUYXatw9i5H8ocYe2sPKSFB6eS8WNPeRKiN1qAWWZUPm7gwFzJGrccqQ==} - - '@parcel/watcher-android-arm64@2.6.0': - resolution: {integrity: sha512-trgpLSCKRC/huFjXX/Smh+0sWe4+YtKfktIToiMl59ghz7z+qkH6kMvNnUbLyRs9N11t8l4svSCs1+5B3rOAhA==} - engines: {node: '>= 10.0.0'} + '@parcel/watcher-android-arm64@2.5.0': + resolution: + { + integrity: sha512-qlX4eS28bUcQCdribHkg/herLe+0A9RyYC+mm2PXpncit8z5b3nSqGVzMNR3CmtAOgRutiZ02eIJJgP/b1iEFQ==, + } + engines: { node: '>= 10.0.0' } cpu: [arm64] os: [android] - '@parcel/watcher-darwin-arm64@2.6.0': - resolution: {integrity: sha512-Y3QV0gl7Q1zbfueunkWIERICbEojQFCgpyG7YqOGNFLsckXyI1xu9mAIUpKY9QBYzBtSkN8dBPwd3yiAO9ovMw==} - engines: {node: '>= 10.0.0'} + '@parcel/watcher-darwin-arm64@2.5.0': + resolution: + { + integrity: sha512-hyZ3TANnzGfLpRA2s/4U1kbw2ZI4qGxaRJbBH2DCSREFfubMswheh8TeiC1sGZ3z2jUf3s37P0BBlrD3sjVTUw==, + } + engines: { node: '>= 10.0.0' } cpu: [arm64] os: [darwin] - '@parcel/watcher-darwin-x64@2.6.0': - resolution: {integrity: sha512-Ohv6OpzhUfKYD7Beb8kDvG0jbIxORCYY1JRdZnaBtnjjkJxgD7ZVL0nw2sCYd0yTMKTvz3nnTnOF3cDifK+kvw==} - engines: {node: '>= 10.0.0'} + '@parcel/watcher-darwin-x64@2.5.0': + resolution: + { + integrity: sha512-9rhlwd78saKf18fT869/poydQK8YqlU26TMiNg7AIu7eBp9adqbJZqmdFOsbZ5cnLp5XvRo9wcFmNHgHdWaGYA==, + } + engines: { node: '>= 10.0.0' } cpu: [x64] os: [darwin] - '@parcel/watcher-freebsd-x64@2.6.0': - resolution: {integrity: sha512-5HmXvDgs8VK+74jF9y9/2FE3/OnlcKmc56tjmSrEuZjpSZOGL+fvAu+HKJBdPs9uwoP2hE6TlSUpXZ/C5jUFmQ==} - engines: {node: '>= 10.0.0'} + '@parcel/watcher-freebsd-x64@2.5.0': + resolution: + { + integrity: sha512-syvfhZzyM8kErg3VF0xpV8dixJ+RzbUaaGaeb7uDuz0D3FK97/mZ5AJQ3XNnDsXX7KkFNtyQyFrXZzQIcN49Tw==, + } + engines: { node: '>= 10.0.0' } cpu: [x64] os: [freebsd] - '@parcel/watcher-linux-arm-glibc@2.6.0': - resolution: {integrity: sha512-Ps/hui3A+vMbjdqlqAowK2ZL8+BO8dBjxeWXj6npTBs3jx4wWmbPpaLuqwrQrSqIVMCnpWo238bJ1U37GhQOYg==} - engines: {node: '>= 10.0.0'} + '@parcel/watcher-linux-arm-glibc@2.5.0': + resolution: + { + integrity: sha512-0VQY1K35DQET3dVYWpOaPFecqOT9dbuCfzjxoQyif1Wc574t3kOSkKevULddcR9znz1TcklCE7Ht6NIxjvTqLA==, + } + engines: { node: '>= 10.0.0' } cpu: [arm] os: [linux] - libc: [glibc] - '@parcel/watcher-linux-arm-musl@2.6.0': - resolution: {integrity: sha512-9c6AUHgHoG+IY88MRIHupztQiQnrbqHYQjkM2btA+Bf/wQnQMuiD0Wfk1EVv3TlNT3x41uU71rn6E4xh/+zvkw==} - engines: {node: '>= 10.0.0'} + '@parcel/watcher-linux-arm-musl@2.5.0': + resolution: + { + integrity: sha512-6uHywSIzz8+vi2lAzFeltnYbdHsDm3iIB57d4g5oaB9vKwjb6N6dRIgZMujw4nm5r6v9/BQH0noq6DzHrqr2pA==, + } + engines: { node: '>= 10.0.0' } cpu: [arm] os: [linux] - libc: [musl] - '@parcel/watcher-linux-arm64-glibc@2.6.0': - resolution: {integrity: sha512-yHRqS2owEXe6Hic9z6Mh1ECsCd+ODVOGvZDyciqRd21+v+o+DnXMOrw50DSpIG2sb8GPEaPPmfeCAWKPJdq46g==} - engines: {node: '>= 10.0.0'} + '@parcel/watcher-linux-arm64-glibc@2.5.0': + resolution: + { + integrity: sha512-BfNjXwZKxBy4WibDb/LDCriWSKLz+jJRL3cM/DllnHH5QUyoiUNEp3GmL80ZqxeumoADfCCP19+qiYiC8gUBjA==, + } + engines: { node: '>= 10.0.0' } cpu: [arm64] os: [linux] - '@parcel/watcher-linux-arm64-musl@2.6.0': - resolution: {integrity: sha512-WhB2e/V7rqdHHWZusBSPuy5Ei8S6lSz6FE5TKKQz5h3a0O+C+mhY7vxU9b/stqvMb8beLnPY82ZrFTLKs+SrKA==} - engines: {node: '>= 10.0.0'} + '@parcel/watcher-linux-arm64-musl@2.5.0': + resolution: + { + integrity: sha512-S1qARKOphxfiBEkwLUbHjCY9BWPdWnW9j7f7Hb2jPplu8UZ3nes7zpPOW9bkLbHRvWM0WDTsjdOTUgW0xLBN1Q==, + } + engines: { node: '>= 10.0.0' } cpu: [arm64] os: [linux] - '@parcel/watcher-linux-x64-glibc@2.6.0': - resolution: {integrity: sha512-ulGE6x6Oz6iAwg75T8YQSoguBWasniIbX+QWpaYPcCnDOpdWX3k+4xbEYPZVLxOuoJI+svJJPD3sEj8G7lrQ3A==} - engines: {node: '>= 10.0.0'} + '@parcel/watcher-linux-x64-glibc@2.5.0': + resolution: + { + integrity: sha512-d9AOkusyXARkFD66S6zlGXyzx5RvY+chTP9Jp0ypSTC9d4lzyRs9ovGf/80VCxjKddcUvnsGwCHWuF2EoPgWjw==, + } + engines: { node: '>= 10.0.0' } cpu: [x64] os: [linux] - '@parcel/watcher-linux-x64-musl@2.6.0': - resolution: {integrity: sha512-tkBYKt7YQrjIJWYDnto2YgO8MRkjlMTSNoRHzsXinBqbLdeOM3L32wPZJvIZxqaLMfSlS/4sUjH/6STVP/XDLw==} - engines: {node: '>= 10.0.0'} + '@parcel/watcher-linux-x64-musl@2.5.0': + resolution: + { + integrity: sha512-iqOC+GoTDoFyk/VYSFHwjHhYrk8bljW6zOhPuhi5t9ulqiYq1togGJB5e3PwYVFFfeVgc6pbz3JdQyDoBszVaA==, + } + engines: { node: '>= 10.0.0' } cpu: [x64] os: [linux] - '@parcel/watcher-wasm@2.5.6': - resolution: {integrity: sha512-byAiBZ1t3tXQvc8dMD/eoyE7lTXYorhn+6uVW5AC+JGI1KtJC/LvDche5cfUE+qiefH+Ybq0bUCJU0aB1cSHUA==} - engines: {node: '>= 10.0.0'} - bundledDependencies: - - napi-wasm - - '@parcel/watcher-win32-arm64@2.6.0': - resolution: {integrity: sha512-gIZAP23jaHjGWasY/TY6yL7NHFClf0Ga7FN+iINvk+KN94rhm94lYZhFsbYFNcA04/onvGD9kKmiJLJB2HbNwQ==} - engines: {node: '>= 10.0.0'} + '@parcel/watcher-win32-arm64@2.5.0': + resolution: + { + integrity: sha512-twtft1d+JRNkM5YbmexfcH/N4znDtjgysFaV9zvZmmJezQsKpkfLYJ+JFV3uygugK6AtIM2oADPkB2AdhBrNig==, + } + engines: { node: '>= 10.0.0' } cpu: [arm64] os: [win32] - '@parcel/watcher-win32-x64@2.6.0': - resolution: {integrity: sha512-cA+/pXV2YkfxlIcXOQ5fSWqAzzPyD78/x5qbK/I0vUkrlYHA8TIz+MXjAbGouguKVSI4bOmkTSJ1/poVSsgt+A==} - engines: {node: '>= 10.0.0'} + '@parcel/watcher-win32-ia32@2.5.0': + resolution: + { + integrity: sha512-+rgpsNRKwo8A53elqbbHXdOMtY/tAtTzManTWShB5Kk54N8Q9mzNWV7tV+IbGueCbcj826MfWGU3mprWtuf1TA==, + } + engines: { node: '>= 10.0.0' } + cpu: [ia32] + os: [win32] + + '@parcel/watcher-win32-x64@2.5.0': + resolution: + { + integrity: sha512-lPrxve92zEHdgeff3aiu4gDOIt4u7sJYha6wbdEZDCDUhtjTsOMiaJzG5lMY4GkWH8p0fMmO2Ppq5G5XXG+DQw==, + } + engines: { node: '>= 10.0.0' } cpu: [x64] os: [win32] - '@parcel/watcher@2.6.0': - resolution: {integrity: sha512-7FNeNl8NCE7aINx7WXiKQrPYZWC/hvrTsmk6zmxbI7LTXE7hVek/n8AfVgpe2y82zl3w0HvCHN0bVKMBoJcC0w==} - engines: {node: '>= 10.0.0'} + '@parcel/watcher@2.5.0': + resolution: + { + integrity: sha512-i0GV1yJnm2n3Yq1qw6QrUrd/LI9bE8WEBOTtOkpCXHHdyN3TAGgqAK/DAT05z4fq2x04cARXt2pDmjWjL92iTQ==, + } + engines: { node: '>= 10.0.0' } - '@playwright/test@1.62.1': - resolution: {integrity: sha512-DTcUc8qii+cpHvtOwggMtBRMjKZHXYWdw8syRYu2vtzuq4Wxphqq4NfCs5Zt44L6mA8rfDfj+PHnxFc/FeK6mQ==} - engines: {node: '>=20'} + '@pkgjs/parseargs@0.11.0': + resolution: + { + integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==, + } + engines: { node: '>=14' } + + '@playwright/test@1.49.0': + resolution: + { + integrity: sha512-DMulbwQURa8rNIQrf94+jPJQ4FmOVdpE5ZppRNvWVjvhC+6sOeo28r8MgIpQRYouXRtt/FCCXU7zn20jnHR4Qw==, + } + engines: { node: '>=18' } hasBin: true - '@rolldown/binding-android-arm64@1.2.1': - resolution: {integrity: sha512-02hOeOSryYxVrOIphmLAsqnCJWxwlzFk+pEt/N/i6OgT3lShHO7xGCU5cpgchRDHboAEbSjzgGh+O/u1GswQmA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [android] - - '@rolldown/binding-darwin-arm64@1.2.1': - resolution: {integrity: sha512-fMsTOnN0OjFm3CyppWPitKnc8UlliVARUULW6cfU6AIqjdtgmSFWSk9vecHzZduv/yMWIHDlRhM1e8Iff9uAfA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [darwin] - - '@rolldown/binding-darwin-x64@1.2.1': - resolution: {integrity: sha512-1wjKdz/XLGKHaTNHjQveQ/B23TKx4ItAqm1JbyVuvNPc4Ze0Fb48s49TAd/2zcplPl8okE/UbTgmlVfwT7eFeQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [darwin] - - '@rolldown/binding-freebsd-x64@1.2.1': - resolution: {integrity: sha512-Fa0jHR07E7YBN4vOEsbVf2briYNsuOowfLJaXULZM0ldMlaCaj2LJgLMbMe4iacRyZmvR8efFhgR9wKuGclQUg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [freebsd] - - '@rolldown/binding-linux-arm-gnueabihf@1.2.1': - resolution: {integrity: sha512-pzkgu1SSHGgRRyRZ4fbmSgmajbVt+epaLP99NDjFft69v/ypfTi6swBMiVdh2EkQ0OSnHE1lZDM7DRGkyAzUpA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [linux] - - '@rolldown/binding-linux-arm64-gnu@1.2.1': - resolution: {integrity: sha512-QI5SEDY8cbiYWHx0VO4vIc3UlS6a32vXHjU8Qy/17adEmZIPuByJg13UEvo9c/UCiUkdcVWY83C+b+JrwnNyUg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@rolldown/binding-linux-arm64-musl@1.2.1': - resolution: {integrity: sha512-Sm41FyCeXqmYcERoYOCbGIL5hNfd8w9LQ7Y61Bev48HkcjaJqV/iiVOaiDxjVTRMS+QKrZmD8cfPt4uMVnvM+A==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@rolldown/binding-linux-ppc64-gnu@1.2.1': - resolution: {integrity: sha512-2x+WhXTGl9yJYPbltW/BSEPTVz9OIWQyER4N+gJEDWkkn904eRcBzELqh/Hf7K0w/ubGbKNMv0ZC+94QK/IFEg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [ppc64] - os: [linux] - libc: [glibc] - - '@rolldown/binding-linux-s390x-gnu@1.2.1': - resolution: {integrity: sha512-eEjmQpuRQayHPWWnywaWHkFT3ToPbP3RYy42VVd/B9aBGDA+Ol25EIWHxKQST3IiWJjikCWUF7KtbfqwZrzVwQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [s390x] - os: [linux] - libc: [glibc] - - '@rolldown/binding-linux-x64-gnu@1.2.1': - resolution: {integrity: sha512-/Orga1fZYkLc/56jBICcHrKchl8Z2UKdDSr3LG9ToWO1lQ6a4Livk9Xz+9WN91zsz5QR3XQz2NNoSDEvP6qadw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@rolldown/binding-linux-x64-musl@1.2.1': - resolution: {integrity: sha512-xxBJRL+0q0Kce7orznGWLuylHDY65vuARXZRpX+hPdv+DqK2c3NlCsVA98tlWzWNEE7yPqA/1NQ5nnCrj49Y5A==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [musl] - - '@rolldown/binding-openharmony-arm64@1.2.1': - resolution: {integrity: sha512-M6AdXIXw3s+/8XpKMzdGDEXGS1S7kwUsy+rcTIUIOx5Ge4nXKCtAFHFV9YKkXvGcC5WMoTjAteLzlsQROVI0Yw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [openharmony] - - '@rolldown/binding-wasm32-wasi@1.2.1': - resolution: {integrity: sha512-/TX0SoRGojHzSAHpfVBbavRVSazg5U3h3Y3VXfcc0cdugq6kxdqw8LPGFiPr+/7gE/60zRcsOY2Vi9b9eT0jww==} - engines: {node: ^20.19.0 || ^22.13.0 || >=23.5.0} - - '@rolldown/binding-win32-arm64-msvc@1.2.1': - resolution: {integrity: sha512-EvRrivJieyHG+AO9lleZWgq+g0+S7oV2C51yuqlcyU/R9net+sI4Pj0F+lUoP2bEr6TWX3SqFaaS0SzfLxSzkw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [win32] - - '@rolldown/binding-win32-x64-msvc@1.2.1': - resolution: {integrity: sha512-Z4eCmn5QJ/5+azF9knpLWKfVd9aidn0mAe9TpJgvBLId9Ax3t0+JVxBmT25Bv7NBbVW1TZyKjQjQReouMeH5UQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [win32] - - '@rolldown/pluginutils@1.0.1': - resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} - - '@rollup/rollup-android-arm-eabi@4.60.4': - resolution: {integrity: sha512-F5QXMSiFebS9hKZj02XhWLLnRpJ3B3AROP0tWbFBSj+6kCbg5m9j5JoHKd4mmSVy5mS/IMQloYgYxCuJC0fxEQ==} + '@rollup/rollup-android-arm-eabi@4.20.0': + resolution: + { + integrity: sha512-TSpWzflCc4VGAUJZlPpgAJE1+V60MePDQnBd7PPkpuEmOy8i87aL6tinFGKBFKuEDikYpig72QzdT3QPYIi+oA==, + } cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.60.4': - resolution: {integrity: sha512-GxxTKApUpzRhof7poWvCJHRF51C67u1R7D6DiluBE8wKU1u5GWE8t+v81JvJYtbawoBFX1hLv5Ei4eVjkWokaw==} + '@rollup/rollup-android-arm-eabi@4.27.4': + resolution: + { + integrity: sha512-2Y3JT6f5MrQkICUyRVCw4oa0sutfAsgaSsb0Lmmy1Wi2y7X5vT9Euqw4gOsCyy0YfKURBg35nhUKZS4mDcfULw==, + } + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.20.0': + resolution: + { + integrity: sha512-u00Ro/nok7oGzVuh/FMYfNoGqxU5CPWz1mxV85S2w9LxHR8OoMQBuSk+3BKVIDYgkpeOET5yXkx90OYFc+ytpQ==, + } cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.60.4': - resolution: {integrity: sha512-tua0TaJxMOB1R0V0RS1jFZ/RpURFDJIOR2A6jWwQeawuFyS4gBW+rntLRaQd0EQ4bd6Vp44Z2rXW+YYDBsj6IA==} + '@rollup/rollup-android-arm64@4.27.4': + resolution: + { + integrity: sha512-wzKRQXISyi9UdCVRqEd0H4cMpzvHYt1f/C3CoIjES6cG++RHKhrBj2+29nPF0IB5kpy9MS71vs07fvrNGAl/iA==, + } + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.20.0': + resolution: + { + integrity: sha512-uFVfvzvsdGtlSLuL0ZlvPJvl6ZmrH4CBwLGEFPe7hUmf7htGAN+aXo43R/V6LATyxlKVC/m6UsLb7jbG+LG39Q==, + } cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.60.4': - resolution: {integrity: sha512-CSKq7MsP+5PFIcydhAiR1K0UhEI1A2jWXVKHPCBZ151yOutENwvnPocgVHkivu2kviURtCEB6zUQw0vs8RrhMg==} + '@rollup/rollup-darwin-arm64@4.27.4': + resolution: + { + integrity: sha512-PlNiRQapift4LNS8DPUHuDX/IdXiLjf8mc5vdEmUR0fF/pyy2qWwzdLjB+iZquGr8LuN4LnUoSEvKRwjSVYz3Q==, + } + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.20.0': + resolution: + { + integrity: sha512-xbrMDdlev53vNXexEa6l0LffojxhqDTBeL+VUxuuIXys4x6xyvbKq5XqTXBCEUA8ty8iEJblHvFaWRJTk/icAQ==, + } cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.60.4': - resolution: {integrity: sha512-+O8OkVdyvXMtJEciu2wS/pzm1IxntEEQx3z5TAVy4l32G0etZn+RsA48ARRrFm6Ri8fvqPQfgrvNxSjKAbnd3g==} + '@rollup/rollup-darwin-x64@4.27.4': + resolution: + { + integrity: sha512-o9bH2dbdgBDJaXWJCDTNDYa171ACUdzpxSZt+u/AAeQ20Nk5x+IhA+zsGmrQtpkLiumRJEYef68gcpn2ooXhSQ==, + } + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.27.4': + resolution: + { + integrity: sha512-NBI2/i2hT9Q+HySSHTBh52da7isru4aAAo6qC3I7QFVsuhxi2gM8t/EI9EVcILiHLj1vfi+VGGPaLOUENn7pmw==, + } cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.60.4': - resolution: {integrity: sha512-Iw3oMskH3AfNuhU0MSN7vNbdi4me/NiYo2azqPz/Le16zHSa+3RRmliCMWWQmh4lcndccU40xcJuTYJZxNo/lw==} + '@rollup/rollup-freebsd-x64@4.27.4': + resolution: + { + integrity: sha512-wYcC5ycW2zvqtDYrE7deary2P2UFmSh85PUpAx+dwTCO9uw3sgzD6Gv9n5X4vLaQKsrfTSZZ7Z7uynQozPVvWA==, + } cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.60.4': - resolution: {integrity: sha512-EIPRXTVQpHyF8WOo219AD2yEltPehLTcTMz2fn6JsatLYSzQf00hj3rulF+yauOlF9/FtM2WpkT/hJh/KJFGhA==} + '@rollup/rollup-linux-arm-gnueabihf@4.20.0': + resolution: + { + integrity: sha512-jMYvxZwGmoHFBTbr12Xc6wOdc2xA5tF5F2q6t7Rcfab68TT0n+r7dgawD4qhPEvasDsVpQi+MgDzj2faOLsZjA==, + } cpu: [arm] os: [linux] - libc: [glibc] - '@rollup/rollup-linux-arm-musleabihf@4.60.4': - resolution: {integrity: sha512-J3Yh9PzzF1Ovah2At+lHiGQdsYgArxBbXv/zHfSyaiFQEqvNv7DcW98pCrmdjCZBrqBiKrKKe2V+aaSGWuBe/w==} + '@rollup/rollup-linux-arm-gnueabihf@4.27.4': + resolution: + { + integrity: sha512-9OwUnK/xKw6DyRlgx8UizeqRFOfi9mf5TYCw1uolDaJSbUmBxP85DE6T4ouCMoN6pXw8ZoTeZCSEfSaYo+/s1w==, + } cpu: [arm] os: [linux] - libc: [musl] - '@rollup/rollup-linux-arm64-gnu@4.60.4': - resolution: {integrity: sha512-BFDEZMYfUvLn37ONE1yMBojPxnMlTFsdyNoqncT0qFq1mAfllL+ATMMJd8TeuVMiX84s1KbcxcZbXInmcO2mRg==} + '@rollup/rollup-linux-arm-musleabihf@4.20.0': + resolution: + { + integrity: sha512-1asSTl4HKuIHIB1GcdFHNNZhxAYEdqML/MW4QmPS4G0ivbEcBr1JKlFLKsIRqjSwOBkdItn3/ZDlyvZ/N6KPlw==, + } + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.27.4': + resolution: + { + integrity: sha512-Vgdo4fpuphS9V24WOV+KwkCVJ72u7idTgQaBoLRD0UxBAWTF9GWurJO9YD9yh00BzbkhpeXtm6na+MvJU7Z73A==, + } + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.20.0': + resolution: + { + integrity: sha512-COBb8Bkx56KldOYJfMf6wKeYJrtJ9vEgBRAOkfw6Ens0tnmzPqvlpjZiLgkhg6cA3DGzCmLmmd319pmHvKWWlQ==, + } cpu: [arm64] os: [linux] - libc: [glibc] - '@rollup/rollup-linux-arm64-musl@4.60.4': - resolution: {integrity: sha512-pc9EYOSlOgdQ2uPl1o9PF6/kLSgaUosia7gOuS8mB69IxJvlclko1MECXysjs5ryez1/5zjYqx3+xYU0TU6R1A==} + '@rollup/rollup-linux-arm64-gnu@4.27.4': + resolution: + { + integrity: sha512-pleyNgyd1kkBkw2kOqlBx+0atfIIkkExOTiifoODo6qKDSpnc6WzUY5RhHdmTdIJXBdSnh6JknnYTtmQyobrVg==, + } cpu: [arm64] os: [linux] - libc: [musl] - '@rollup/rollup-linux-loong64-gnu@4.60.4': - resolution: {integrity: sha512-NxnomyxYerDh5n4iLrNa+sH+Z+U4BMEE46V2PgQ/hoB909i8gV1M5wPojWg9fk1jWpO3IQnOs20K4wyZuFLEFQ==} - cpu: [loong64] + '@rollup/rollup-linux-arm64-musl@4.20.0': + resolution: + { + integrity: sha512-+it+mBSyMslVQa8wSPvBx53fYuZK/oLTu5RJoXogjk6x7Q7sz1GNRsXWjn6SwyJm8E/oMjNVwPhmNdIjwP135Q==, + } + cpu: [arm64] os: [linux] - libc: [glibc] - '@rollup/rollup-linux-loong64-musl@4.60.4': - resolution: {integrity: sha512-nbJnQ8a3z1mtmrwImCYhc6BGpThAyYVRQxw9uKSKG4wR6aAYno9sVjJ0zaZcW9BPJX1GbrDPf+SvdWjgTuDmnw==} - cpu: [loong64] + '@rollup/rollup-linux-arm64-musl@4.27.4': + resolution: + { + integrity: sha512-caluiUXvUuVyCHr5DxL8ohaaFFzPGmgmMvwmqAITMpV/Q+tPoaHZ/PWa3t8B2WyoRcIIuu1hkaW5KkeTDNSnMA==, + } + cpu: [arm64] os: [linux] - libc: [musl] - '@rollup/rollup-linux-ppc64-gnu@4.60.4': - resolution: {integrity: sha512-2EU6acNrQLd8tYvo/LXW535wupT3m6fo7HKo6lr7ktQoItxTyOL1ZCR/GfGCuXl2vR+zmfI6eRXkSemafv+iVg==} + '@rollup/rollup-linux-powerpc64le-gnu@4.20.0': + resolution: + { + integrity: sha512-yAMvqhPfGKsAxHN8I4+jE0CpLWD8cv4z7CK7BMmhjDuz606Q2tFKkWRY8bHR9JQXYcoLfopo5TTqzxgPUjUMfw==, + } cpu: [ppc64] os: [linux] - libc: [glibc] - '@rollup/rollup-linux-ppc64-musl@4.60.4': - resolution: {integrity: sha512-WeBtoMuaMxiiIrO2IYP3xs6GMWkJP2C0EoT8beTLkUPmzV1i/UcOSVw1d5r9KBODtHKilG5yFxsGRnBbK3wJ4A==} + '@rollup/rollup-linux-powerpc64le-gnu@4.27.4': + resolution: + { + integrity: sha512-FScrpHrO60hARyHh7s1zHE97u0KlT/RECzCKAdmI+LEoC1eDh/RDji9JgFqyO+wPDb86Oa/sXkily1+oi4FzJQ==, + } cpu: [ppc64] os: [linux] - libc: [musl] - '@rollup/rollup-linux-riscv64-gnu@4.60.4': - resolution: {integrity: sha512-FJHFfqpKUI3A10WrWKiFbBZ7yVbGT4q4B5o1qKFFojqpaYoh9LrQgqWCmmcxQzVSXYtyB5bzkXrYzlHTs21MYA==} + '@rollup/rollup-linux-riscv64-gnu@4.20.0': + resolution: + { + integrity: sha512-qmuxFpfmi/2SUkAw95TtNq/w/I7Gpjurx609OOOV7U4vhvUhBcftcmXwl3rqAek+ADBwSjIC4IVNLiszoj3dPA==, + } cpu: [riscv64] os: [linux] - libc: [glibc] - '@rollup/rollup-linux-riscv64-musl@4.60.4': - resolution: {integrity: sha512-mcEl6CUT5IAUmQf1m9FYSmVqCJlpQ8r8eyftFUHG8i9OhY7BkBXSUdnLH5DOf0wCOjcP9v/QO93zpmF1SptCCw==} + '@rollup/rollup-linux-riscv64-gnu@4.27.4': + resolution: + { + integrity: sha512-qyyprhyGb7+RBfMPeww9FlHwKkCXdKHeGgSqmIXw9VSUtvyFZ6WZRtnxgbuz76FK7LyoN8t/eINRbPUcvXB5fw==, + } cpu: [riscv64] os: [linux] - libc: [musl] - '@rollup/rollup-linux-s390x-gnu@4.60.4': - resolution: {integrity: sha512-ynt3JxVd2w2buzoKDWIyiV1pJW93xlQic1THVLXilz429oijRpSHivZAgp65KBu+cMcgf1eVVjdnTLvPxgCuoQ==} + '@rollup/rollup-linux-s390x-gnu@4.20.0': + resolution: + { + integrity: sha512-I0BtGXddHSHjV1mqTNkgUZLnS3WtsqebAXv11D5BZE/gfw5KoyXSAXVqyJximQXNvNzUo4GKlCK/dIwXlz+jlg==, + } cpu: [s390x] os: [linux] - libc: [glibc] - '@rollup/rollup-linux-x64-gnu@4.60.4': - resolution: {integrity: sha512-Boiz5+MsaROEWDf+GGEwF8VMHGhlUoQMtIPjOgA5fv4osupqTVnJteQNKJwUcnUog2G55jYXH7KZFFiJe0TEzQ==} + '@rollup/rollup-linux-s390x-gnu@4.27.4': + resolution: + { + integrity: sha512-PFz+y2kb6tbh7m3A7nA9++eInGcDVZUACulf/KzDtovvdTizHpZaJty7Gp0lFwSQcrnebHOqxF1MaKZd7psVRg==, + } + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.20.0': + resolution: + { + integrity: sha512-y+eoL2I3iphUg9tN9GB6ku1FA8kOfmF4oUEWhztDJ4KXJy1agk/9+pejOuZkNFhRwHAOxMsBPLbXPd6mJiCwew==, + } cpu: [x64] os: [linux] - libc: [glibc] - '@rollup/rollup-linux-x64-musl@4.60.4': - resolution: {integrity: sha512-+qfSY27qIrFfI/Hom04KYFw3GKZSGU4lXus51wsb5EuySfFlWRwjkKWoE9emgRw/ukoT4Udsj4W/+xxG8VbPKg==} + '@rollup/rollup-linux-x64-gnu@4.27.4': + resolution: + { + integrity: sha512-Ni8mMtfo+o/G7DVtweXXV/Ol2TFf63KYjTtoZ5f078AUgJTmaIJnj4JFU7TK/9SVWTaSJGxPi5zMDgK4w+Ez7Q==, + } cpu: [x64] os: [linux] - libc: [musl] - '@rollup/rollup-openbsd-x64@4.60.4': - resolution: {integrity: sha512-VpTfOPHgVXEBeeR8hZ2O0F3aSso+JDWqTWmTmzcQKted54IAdUVbxE+j/MVxUsKa8L20HJhv3vUezVPoquqWjA==} + '@rollup/rollup-linux-x64-musl@4.20.0': + resolution: + { + integrity: sha512-hM3nhW40kBNYUkZb/r9k2FKK+/MnKglX7UYd4ZUy5DJs8/sMsIbqWK2piZtVGE3kcXVNj3B2IrUYROJMMCikNg==, + } cpu: [x64] - os: [openbsd] + os: [linux] - '@rollup/rollup-openharmony-arm64@4.60.4': - resolution: {integrity: sha512-IPOsh5aRYuLv/nkU51X10Bf75Bsf6+gZdx1X+QP5QM6lIJFHHqbHLG0uJn/hWthzo13UAc2umiUorqZy3axoZg==} - cpu: [arm64] - os: [openharmony] + '@rollup/rollup-linux-x64-musl@4.27.4': + resolution: + { + integrity: sha512-5AeeAF1PB9TUzD+3cROzFTnAJAcVUGLuR8ng0E0WXGkYhp6RD6L+6szYVX+64Rs0r72019KHZS1ka1q+zU/wUw==, + } + cpu: [x64] + os: [linux] - '@rollup/rollup-win32-arm64-msvc@4.60.4': - resolution: {integrity: sha512-4QzE9E81OohJ/HKzHhsqU+zcYYojVOXlFMs1DdyMT6qXl/niOH7AVElmmEdUNHHS/oRkc++d5k6Vy85zFs0DEw==} + '@rollup/rollup-win32-arm64-msvc@4.20.0': + resolution: + { + integrity: sha512-psegMvP+Ik/Bg7QRJbv8w8PAytPA7Uo8fpFjXyCRHWm6Nt42L+JtoqH8eDQ5hRP7/XW2UiIriy1Z46jf0Oa1kA==, + } cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.60.4': - resolution: {integrity: sha512-zTPgT1YuHHcd+Tmx7h8aml0FWFVelV5N54oHow9SLj+GfoDy/huQ+UV396N/C7KpMDMiPspRktzM1/0r1usYEA==} + '@rollup/rollup-win32-arm64-msvc@4.27.4': + resolution: + { + integrity: sha512-yOpVsA4K5qVwu2CaS3hHxluWIK5HQTjNV4tWjQXluMiiiu4pJj4BN98CvxohNCpcjMeTXk/ZMJBRbgRg8HBB6A==, + } + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.20.0': + resolution: + { + integrity: sha512-GabekH3w4lgAJpVxkk7hUzUf2hICSQO0a/BLFA11/RMxQT92MabKAqyubzDZmMOC/hcJNlc+rrypzNzYl4Dx7A==, + } cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.60.4': - resolution: {integrity: sha512-DRS4G7mi9lJxqEDezIkKCaUIKCrLUUDCUaCsTPCi/rtqaC6D/jjwslMQyiDU50Ka0JKpeXeRBFBAXwArY52vBw==} - cpu: [x64] - os: [win32] - - '@rollup/rollup-win32-x64-msvc@4.60.4': - resolution: {integrity: sha512-QVTUovf40zgTqlFVrKA1uXMVvU2QWEFWfAH8Wdc48IxLvrJMQVMBRjuQyUpzZCDkakImib9eVazbWlC6ksWtJw==} - cpu: [x64] - os: [win32] - - '@rspack/binding-darwin-arm64@2.0.2': - resolution: {integrity: sha512-0o7lbgBBsDlICWdjIH0q3e0BsSco4GRiImHWVfZSVEG+q2+ykZJvSvYCVhPM1Co375Z0S3VMPa/8SjcY1FHwlw==} - cpu: [arm64] - os: [darwin] - - '@rspack/binding-darwin-x64@2.0.2': - resolution: {integrity: sha512-tOwxZpoPlTlRs/w6UyUinXJ4TYRVHMlR7+eQxO1R3muKpixvhXQjtvoaY16HuFyTVky5F0IfOoWr3x9FEsgdLg==} - cpu: [x64] - os: [darwin] - - '@rspack/binding-linux-arm64-gnu@2.0.2': - resolution: {integrity: sha512-1ZD4YFhG1rmgqj+W8hfwHyKV8xDxGsc/3KgU0FwmiVEX7JfzhCkgBO/xlCG79kRKSrzuVzt4icO/G3cCKn0pag==} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@rspack/binding-linux-arm64-musl@2.0.2': - resolution: {integrity: sha512-/PtTkM/DsDLjeuXTmeJeRfbjCDbcL9jvoVgZrgxYFZ28y2cdLvbChbW9uigOzs5dQEs1CIBQXMTTj7KhdBTuQg==} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@rspack/binding-linux-x64-gnu@2.0.2': - resolution: {integrity: sha512-bBjsZxMHRaPo6X9SokApm6ucs+UhXtAJFyJJyuk2BH4XJsLeCU9Dz1vMwioeohFbJUUeTASVPm6/BL+RhSaunw==} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@rspack/binding-linux-x64-musl@2.0.2': - resolution: {integrity: sha512-HjlpInqzabDNkhVsUJpsHPqa9QYVWBViJoyWNjzXCAW0vKMDvwaphyUvokSinX8FGTlZi/sr5UEaHJo6XtQ35g==} - cpu: [x64] - os: [linux] - libc: [musl] - - '@rspack/binding-wasm32-wasi@2.0.2': - resolution: {integrity: sha512-YaRYNFLJRpkGfYjSWR7n9f+nQKtrlmrrffpAn/blc2geHcRvXoBc5SCs1idPtsLhj7H9qWWhs7ucjyHy4csWFg==} - cpu: [wasm32] - - '@rspack/binding-win32-arm64-msvc@2.0.2': - resolution: {integrity: sha512-d/3kTEKq+asLjRFPO96t+wfWiM7DLN76VQEPDD9bc1kdsZXlVJBuvyXfsgK8bbEvKplWXYcSsokhmEnuXrLOpg==} - cpu: [arm64] - os: [win32] - - '@rspack/binding-win32-ia32-msvc@2.0.2': - resolution: {integrity: sha512-161cWineq3RW+Jdm1FAfSpXeUtYWvhB3kAbm46vNT9h/YYz+spwsFMvveAZ1nsVSVL0IC5lDBGUte7yUAY8K2g==} + '@rollup/rollup-win32-ia32-msvc@4.27.4': + resolution: + { + integrity: sha512-KtwEJOaHAVJlxV92rNYiG9JQwQAdhBlrjNRp7P9L8Cb4Rer3in+0A+IPhJC9y68WAi9H0sX4AiG2NTsVlmqJeQ==, + } cpu: [ia32] os: [win32] - '@rspack/binding-win32-x64-msvc@2.0.2': - resolution: {integrity: sha512-y7Q0S1FE+OlkL5GMqLG0PwxrPw6E1r892KhGrGKE1Vdufe5YTEx6xTPxzZ+b7N2KPD7s9G1/iJmWHQxb1+Bjkg==} + '@rollup/rollup-win32-x64-msvc@4.20.0': + resolution: + { + integrity: sha512-aJ1EJSuTdGnM6qbVC4B5DSmozPTqIag9fSzXRNNo+humQLG89XpPgdt16Ia56ORD7s+H8Pmyx44uczDQ0yDzpg==, + } cpu: [x64] os: [win32] - '@rspack/binding@2.0.2': - resolution: {integrity: sha512-0kZPplW9GWx8mfC6DfsaRY3QBIYPuUs42JfmSM6aSb8tMHZAXQeLeMB8M+h8i4SeI+aFtCgO6UuYGtyWf7+L+A==} + '@rollup/rollup-win32-x64-msvc@4.27.4': + resolution: + { + integrity: sha512-3j4jx1TppORdTAoBJRd+/wJRGCPC0ETWkXOecJ6PPZLj6SptXkrXcNqdj0oclbKML6FkQltdz7bBA3rUSirZug==, + } + cpu: [x64] + os: [win32] - '@rspack/core@2.0.2': - resolution: {integrity: sha512-VM3UHOo26uC+4QSqY5tU1ybI7KuXY5rTof8nhFOaBY9SYau0Smvr+hMSAPmrmHwknB6dXT8yaNVxrj7I+qxE1Q==} - engines: {node: ^20.19.0 || >=22.12.0} - peerDependencies: - '@module-federation/runtime-tools': ^0.24.1 || ^2.0.0 - '@swc/helpers': '>=0.5.1' - peerDependenciesMeta: - '@module-federation/runtime-tools': - optional: true - '@swc/helpers': - optional: true + '@rtsao/scc@1.1.0': + resolution: + { + integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==, + } - '@sindresorhus/merge-streams@4.0.0': - resolution: {integrity: sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==} - engines: {node: '>=18'} + '@rushstack/eslint-patch@1.10.4': + resolution: + { + integrity: sha512-WJgX9nzTqknM393q1QJDJmoW28kUfEnybeTfVNcNAPnIx210RXm2DiXiHzfNPJNIUUb1tJnz/l4QGtJ30PgWmA==, + } - '@standard-schema/spec@1.1.0': - resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} + '@sindresorhus/merge-streams@2.3.0': + resolution: + { + integrity: sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==, + } + engines: { node: '>=18' } - '@swc/helpers@0.5.15': - resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} + '@swc/counter@0.1.3': + resolution: + { + integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==, + } + + '@swc/helpers@0.5.13': + resolution: + { + integrity: sha512-UoKGxQ3r5kYI9dALKJapMmuK+1zWM/H17Z1+iwnNmzcJRnfFuevZs375TA5rW31pu4BS4NoSy1fRsexDXfWn5w==, + } '@tailwindcss/aspect-ratio@0.4.2': - resolution: {integrity: sha512-8QPrypskfBa7QIMuKHg2TA7BqES6vhBrDLOv8Unb6FcFyd3TjKbc6lcmb9UPQHxfl24sXoJ41ux/H7qQQvfaSQ==} + resolution: + { + integrity: sha512-8QPrypskfBa7QIMuKHg2TA7BqES6vhBrDLOv8Unb6FcFyd3TjKbc6lcmb9UPQHxfl24sXoJ41ux/H7qQQvfaSQ==, + } peerDependencies: tailwindcss: '>=2.0.0 || >=3.0.0 || >=3.0.0-alpha.1' - '@tailwindcss/forms@0.5.11': - resolution: {integrity: sha512-h9wegbZDPurxG22xZSoWtdzc41/OlNEUQERNqI/0fOwa2aVlWGu7C35E/x6LDyD3lgtztFSSjKZyuVM0hxhbgA==} + '@tailwindcss/forms@0.5.9': + resolution: + { + integrity: sha512-tM4XVr2+UVTxXJzey9Twx48c1gcxFStqn1pQz0tRsX8o3DvxhN5oY5pvyAbUx7VTaZxpej4Zzvc6h+1RJBzpIg==, + } peerDependencies: - tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20 || >= 4.0.0-beta.1' + tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20' - '@tailwindcss/typography@0.5.20': - resolution: {integrity: sha512-hwbzQuNUfcPvbegQFatVPl/MY/tcM9KLl963hQ5laJKPh81TEZ1+dNG9PirGvcaDBkp+BCshExAyKVPW91dozw==} + '@tailwindcss/typography@0.5.15': + resolution: + { + integrity: sha512-AqhlCXl+8grUz8uqExv5OTtgpjuVIwFTSXTrh8y9/pw6q2ek7fJ+Y8ZEVw7EB2DCcuCOtEjf9w3+J3rzts01uA==, + } peerDependencies: - tailwindcss: '>=3.0.0 || >=4.0.0 || insiders' + tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20' - '@turbo/darwin-64@2.10.8': - resolution: {integrity: sha512-po+7rfJfUnFXjWlcoN2RwhErgzCdRtBc1T26vYPcywHlggmCQiQe1uWaE4j+BibI2uY9/2pDoFzMN0rmSaPFOw==} - cpu: [x64] - os: [darwin] + '@types/babel__core@7.20.5': + resolution: + { + integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==, + } - '@turbo/darwin-arm64@2.10.8': - resolution: {integrity: sha512-+zB2btDJ00lnPRuqOvpVvgl4x34k/djZQGZTTCfjn7JgNCl8QFY5Njo5+dqkY1g/+9gbbsnAvWm9CmJg9ebcXA==} - cpu: [arm64] - os: [darwin] + '@types/babel__generator@7.6.8': + resolution: + { + integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==, + } - '@turbo/linux-64@2.10.8': - resolution: {integrity: sha512-K1dxqiVisyN7cViVsfQLs6xscQbYuI8aO2nbUhFURDACgEDfZRdP/b4CCxeosBJpcMfhYyiibWqJorCnvz9kKg==} - cpu: [x64] - os: [android, linux] + '@types/babel__template@7.4.4': + resolution: + { + integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==, + } - '@turbo/linux-arm64@2.10.8': - resolution: {integrity: sha512-Gi77ibVnrE1fEmvr+/wBD/yvRqhwp/RQuCp2+//lv1U1wNFFyVg0V7Wj8FG9FXPFAw5QHReo8rxc9+wBSDZjzA==} - cpu: [arm64] - os: [android, linux] + '@types/babel__traverse@7.20.6': + resolution: + { + integrity: sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==, + } - '@turbo/windows-64@2.10.8': - resolution: {integrity: sha512-znnLO1haJPYTHoKMKwlAvlkjRiYbbhBzME6wIGaMd+fwir23U6jVd1ecaTWWi1fbnRVqxMfgDBKseQ/hLKb83g==} - cpu: [x64] - os: [win32] + '@types/braces@3.0.4': + resolution: + { + integrity: sha512-0WR3b8eaISjEW7RpZnclONaLFDf7buaowRHdqLp4vLj54AsSAYWfh3DRbfiYJY9XDxMgx1B4sE1Afw2PGpuHOA==, + } - '@turbo/windows-arm64@2.10.8': - resolution: {integrity: sha512-VN30vh3b3Czh2WzYHNTfF1FE0YMZ5aHsLO8dBMGHJewA6792wX6iJR8ZxlzFW6WdOu0gEAKIvlYhfyT81Wkm4Q==} - cpu: [arm64] - os: [win32] + '@types/bun@1.1.13': + resolution: + { + integrity: sha512-KmQxSBgVWCl6RSuerlLGZlIWfdxkKqat0nxN61+qu4y1KDn0Ll3j7v1Pl8GnaL3a/U6GGWVTJh75ap62kR1E8Q==, + } - '@tybys/wasm-util@0.10.3': - resolution: {integrity: sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==} + '@types/estree@1.0.5': + resolution: + { + integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==, + } - '@types/bun@1.3.14': - resolution: {integrity: sha512-h1hFqFVcvAvD9j9K7ZW7vd82aSA+rTdznZa+5bwvCwqSB1jmmfLcbIWhOLx1/+boy/xmjgCs/OMUL8hRJSmnPw==} - - '@types/chai@5.2.3': - resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} - - '@types/deep-eql@4.0.2': - resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} - - '@types/estree@1.0.8': - resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} - - '@types/estree@1.0.9': - resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + '@types/estree@1.0.6': + resolution: + { + integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==, + } '@types/json-schema@7.0.15': - resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + resolution: + { + integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==, + } - '@types/node@22.20.1': - resolution: {integrity: sha512-EANqOCF9QFyra+4pfxUcX9STKJpCLjMbObVzljIJomAWSnuSIEAvyzEU53GaajbXJEgdh0iEcPL+DGvpUd4k1Q==} + '@types/json5@0.0.29': + resolution: + { + integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==, + } - '@types/node@25.9.1': - resolution: {integrity: sha512-xfrlY7UD5rMJk3ZVJP8BNzS28J36YJg+xp+LPXV1TdWxr8uMH5A860QNxYDGQe/ylDSgjxE52Q9VnO7p75tJxg==} + '@types/node@20.12.14': + resolution: + { + integrity: sha512-scnD59RpYD91xngrQQLGkE+6UrHUPzeKZWhhjBSa3HSkwjbQc38+q3RoIVEwxQGRw3M+j5hpNAM+lgV3cVormg==, + } + + '@types/node@20.14.13': + resolution: + { + integrity: sha512-+bHoGiZb8UiQ0+WEtmph2IWQCjIqg8MDZMAV+ppRRhUZnquF5mQkP/9vpSwJClEiSM/C7fZZExPzfU0vJTyp8w==, + } '@types/postcss-import@14.0.3': - resolution: {integrity: sha512-raZhRVTf6Vw5+QbmQ7LOHSDML71A5rj4+EqDzAbrZPfxfoGzFxMHRCq16VlddGIZpHELw0BG4G0YE2ANkdZiIQ==} + resolution: + { + integrity: sha512-raZhRVTf6Vw5+QbmQ7LOHSDML71A5rj4+EqDzAbrZPfxfoGzFxMHRCq16VlddGIZpHELw0BG4G0YE2ANkdZiIQ==, + } - '@types/react-dom@19.2.3': - resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} + '@types/prop-types@15.7.13': + resolution: + { + integrity: sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==, + } + + '@types/react-dom@18.3.1': + resolution: + { + integrity: sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==, + } + + '@types/react@18.3.12': + resolution: + { + integrity: sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==, + } + + '@types/ws@8.5.12': + resolution: + { + integrity: sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==, + } + + '@typescript-eslint/eslint-plugin@8.11.0': + resolution: + { + integrity: sha512-KhGn2LjW1PJT2A/GfDpiyOfS4a8xHQv2myUagTM5+zsormOmBlYsnQ6pobJ8XxJmh6hnHwa2Mbe3fPrDJoDhbA==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } peerDependencies: - '@types/react': ^19.2.0 - - '@types/react@19.2.15': - resolution: {integrity: sha512-eRwcGNHve+E8qtEQSSRl6urh+rFop4v8gm6O8rGv25CodbvFdLjA1vVQ1KkiFE0w0UPOnb8tDiFKL5lp0rtY5Q==} - - '@types/semver@7.8.0': - resolution: {integrity: sha512-1mAINjtQCXXeLkJ9ehXkwOcBpqtLxiVtKhpUf83DdRNdQKV0iXZpaHYqRr7nj+wvxuJzoAmAwXI+sCNMv1CzLQ==} - - '@vitejs/plugin-react@6.0.2': - resolution: {integrity: sha512-DlSMqo4WhThw4vB8Mpn0Woe9J+Jfq1geJ61AKW0QEgLzGMNwtIMdxbDUzLxcun8W7NbJO0e2Jg/Nxm3cCSVzzg==} - engines: {node: ^20.19.0 || >=22.12.0} - peerDependencies: - '@rolldown/plugin-babel': ^0.1.7 || ^0.2.0 - babel-plugin-react-compiler: ^1.0.0 - vite: ^8.0.0 + '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 + eslint: ^8.57.0 || ^9.0.0 + typescript: '*' peerDependenciesMeta: - '@rolldown/plugin-babel': - optional: true - babel-plugin-react-compiler: + typescript: optional: true - '@vitest/expect@4.1.10': - resolution: {integrity: sha512-YsCn+qAk1GWjQOWFEsEcL2gNQ0zmVmQu3T03qP6UyjhtmdtwtbuI+DASn/7iQB3HGTXkdBwGddzxPlmiql5vlA==} - - '@vitest/mocker@4.1.10': - resolution: {integrity: sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==} + '@typescript-eslint/parser@8.11.0': + resolution: + { + integrity: sha512-lmt73NeHdy1Q/2ul295Qy3uninSqi6wQI18XwSpm8w0ZbQXUpjCAWP1Vlv/obudoBiIjJVjlztjQ+d/Md98Yxg==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } peerDependencies: - msw: ^2.4.9 - vite: ^6.0.0 || ^7.0.0 || ^8.0.0 + eslint: ^8.57.0 || ^9.0.0 + typescript: '*' peerDependenciesMeta: - msw: - optional: true - vite: + typescript: optional: true - '@vitest/pretty-format@4.1.10': - resolution: {integrity: sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q==} + '@typescript-eslint/scope-manager@8.11.0': + resolution: + { + integrity: sha512-Uholz7tWhXmA4r6epo+vaeV7yjdKy5QFCERMjs1kMVsLRKIrSdM6o21W2He9ftp5PP6aWOVpD5zvrvuHZC0bMQ==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } - '@vitest/runner@4.1.10': - resolution: {integrity: sha512-IKI6kpIH+LmpROplyLwBBaCfMgOZOMsygVa6BARD6ahA04VRuJSa6OaVG7kRvSEMD870Vd91rSSw0eegtWyLGg==} + '@typescript-eslint/type-utils@8.11.0': + resolution: + { + integrity: sha512-ItiMfJS6pQU0NIKAaybBKkuVzo6IdnAhPFZA/2Mba/uBjuPQPet/8+zh5GtLHwmuFRShZx+8lhIs7/QeDHflOg==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true - '@vitest/snapshot@4.1.10': - resolution: {integrity: sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw==} + '@typescript-eslint/types@8.11.0': + resolution: + { + integrity: sha512-tn6sNMHf6EBAYMvmPUaKaVeYvhUsrE6x+bXQTxjQRp360h1giATU0WvgeEys1spbvb5R+VpNOZ+XJmjD8wOUHw==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } - '@vitest/spy@4.1.10': - resolution: {integrity: sha512-PLf/Ugvoq5wO/b4rwYCR1h2PSIdXz7wnkQFMiUpLdtM7l6pqVFcQIBEHyT1+l+cj7mNwAfZHzqXqDyjvOuwbDw==} + '@typescript-eslint/typescript-estree@8.11.0': + resolution: + { + integrity: sha512-yHC3s1z1RCHoCz5t06gf7jH24rr3vns08XXhfEqzYpd6Hll3z/3g23JRi0jM8A47UFKNc3u/y5KIMx8Ynbjohg==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true - '@vitest/utils@4.1.10': - resolution: {integrity: sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==} + '@typescript-eslint/utils@8.11.0': + resolution: + { + integrity: sha512-CYiX6WZcbXNJV7UNB4PLDIBtSdRmRI/nb0FMyqHPTQD1rMjA0foPLaPUV39C/MxkTd/QKSeX+Gb34PPsDVC35g==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 - '@webassemblyjs/ast@1.14.1': - resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==} + '@typescript-eslint/visitor-keys@8.11.0': + resolution: + { + integrity: sha512-EaewX6lxSjRJnc+99+dqzTeoDZUfyrA52d2/HRrkI830kgovWsmIiTfmr0NZorzqic7ga+1bS60lRBUgR3n/Bw==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } - '@webassemblyjs/floating-point-hex-parser@1.13.2': - resolution: {integrity: sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==} + '@vitejs/plugin-react@4.3.1': + resolution: + { + integrity: sha512-m/V2syj5CuVnaxcUJOQRel/Wr31FFXRFlnOoq1TVtkCxsY5veGMTEmpWHndrhB2U8ScHtCQB1e+4hWYExQc6Lg==, + } + engines: { node: ^14.18.0 || >=16.0.0 } + peerDependencies: + vite: ^4.2.0 || ^5.0.0 - '@webassemblyjs/helper-api-error@1.13.2': - resolution: {integrity: sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==} + '@vitest/expect@2.0.5': + resolution: + { + integrity: sha512-yHZtwuP7JZivj65Gxoi8upUN2OzHTi3zVfjwdpu2WrvCZPLwsJ2Ey5ILIPccoW23dd/zQBlJ4/dhi7DWNyXCpA==, + } - '@webassemblyjs/helper-buffer@1.14.1': - resolution: {integrity: sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==} + '@vitest/pretty-format@2.0.5': + resolution: + { + integrity: sha512-h8k+1oWHfwTkyTkb9egzwNMfJAEx4veaPSnMeKbVSjp4euqGSbQlm5+6VHwTr7u4FJslVVsUG5nopCaAYdOmSQ==, + } - '@webassemblyjs/helper-numbers@1.13.2': - resolution: {integrity: sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==} + '@vitest/runner@2.0.5': + resolution: + { + integrity: sha512-TfRfZa6Bkk9ky4tW0z20WKXFEwwvWhRY+84CnSEtq4+3ZvDlJyY32oNTJtM7AW9ihW90tX/1Q78cb6FjoAs+ig==, + } - '@webassemblyjs/helper-wasm-bytecode@1.13.2': - resolution: {integrity: sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==} + '@vitest/snapshot@2.0.5': + resolution: + { + integrity: sha512-SgCPUeDFLaM0mIUHfaArq8fD2WbaXG/zVXjRupthYfYGzc8ztbFbu6dUNOblBG7XLMR1kEhS/DNnfCZ2IhdDew==, + } - '@webassemblyjs/helper-wasm-section@1.14.1': - resolution: {integrity: sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==} + '@vitest/spy@2.0.5': + resolution: + { + integrity: sha512-c/jdthAhvJdpfVuaexSrnawxZz6pywlTPe84LUB2m/4t3rl2fTo9NFGBG4oWgaD+FTgDDV8hJ/nibT7IfH3JfA==, + } - '@webassemblyjs/ieee754@1.13.2': - resolution: {integrity: sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==} + '@vitest/utils@2.0.5': + resolution: + { + integrity: sha512-d8HKbqIcya+GR67mkZbrzhS5kKhtp8dQLcmRZLGTscGVg7yImT82cIrhtn2L8+VujWcy6KZweApgNmPsTAO/UQ==, + } - '@webassemblyjs/leb128@1.13.2': - resolution: {integrity: sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==} + acorn-jsx@5.3.2: + resolution: + { + integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==, + } + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - '@webassemblyjs/utf8@1.13.2': - resolution: {integrity: sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==} - - '@webassemblyjs/wasm-edit@1.14.1': - resolution: {integrity: sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==} - - '@webassemblyjs/wasm-gen@1.14.1': - resolution: {integrity: sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==} - - '@webassemblyjs/wasm-opt@1.14.1': - resolution: {integrity: sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==} - - '@webassemblyjs/wasm-parser@1.14.1': - resolution: {integrity: sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==} - - '@webassemblyjs/wast-printer@1.14.1': - resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==} - - '@xtuc/ieee754@1.2.0': - resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} - - '@xtuc/long@4.2.2': - resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} - - acorn@8.16.0: - resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} - engines: {node: '>=0.4.0'} + acorn@8.14.0: + resolution: + { + integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==, + } + engines: { node: '>=0.4.0' } hasBin: true - ajv-formats@2.1.1: - resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} - peerDependencies: - ajv: ^8.0.0 - peerDependenciesMeta: - ajv: - optional: true + ajv@6.12.6: + resolution: + { + integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==, + } - ajv-keywords@5.1.0: - resolution: {integrity: sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==} - peerDependencies: - ajv: ^8.8.2 + ansi-regex@5.0.1: + resolution: + { + integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==, + } + engines: { node: '>=8' } - ajv@8.20.0: - resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} + ansi-regex@6.0.1: + resolution: + { + integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==, + } + engines: { node: '>=12' } + + ansi-styles@3.2.1: + resolution: + { + integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==, + } + engines: { node: '>=4' } + + ansi-styles@4.3.0: + resolution: + { + integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==, + } + engines: { node: '>=8' } + + ansi-styles@6.2.1: + resolution: + { + integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==, + } + engines: { node: '>=12' } any-promise@1.3.0: - resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + resolution: + { + integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==, + } anymatch@3.1.3: - resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} - engines: {node: '>= 8'} + resolution: + { + integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==, + } + engines: { node: '>= 8' } arg@5.0.2: - resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + resolution: + { + integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==, + } argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + resolution: + { + integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==, + } + + aria-query@5.3.2: + resolution: + { + integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==, + } + engines: { node: '>= 0.4' } + + array-buffer-byte-length@1.0.1: + resolution: + { + integrity: sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==, + } + engines: { node: '>= 0.4' } + + array-includes@3.1.8: + resolution: + { + integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==, + } + engines: { node: '>= 0.4' } + + array-union@2.1.0: + resolution: + { + integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==, + } + engines: { node: '>=8' } + + array.prototype.findlast@1.2.5: + resolution: + { + integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==, + } + engines: { node: '>= 0.4' } + + array.prototype.findlastindex@1.2.5: + resolution: + { + integrity: sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==, + } + engines: { node: '>= 0.4' } + + array.prototype.flat@1.3.2: + resolution: + { + integrity: sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==, + } + engines: { node: '>= 0.4' } + + array.prototype.flatmap@1.3.2: + resolution: + { + integrity: sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==, + } + engines: { node: '>= 0.4' } + + array.prototype.tosorted@1.1.4: + resolution: + { + integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==, + } + engines: { node: '>= 0.4' } + + arraybuffer.prototype.slice@1.0.3: + resolution: + { + integrity: sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==, + } + engines: { node: '>= 0.4' } assertion-error@2.0.1: - resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} - engines: {node: '>=12'} + resolution: + { + integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==, + } + engines: { node: '>=12' } - autoprefixer@10.5.0: - resolution: {integrity: sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong==} - engines: {node: ^10 || ^12 || >=14} + ast-types-flow@0.0.8: + resolution: + { + integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==, + } + + autoprefixer@10.4.20: + resolution: + { + integrity: sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==, + } + engines: { node: ^10 || ^12 || >=14 } hasBin: true peerDependencies: postcss: ^8.1.0 - baseline-browser-mapping@2.10.31: - resolution: {integrity: sha512-MujYO3eP72uvmSE0i4wltsodRfIpZATP3jvzRNRGGxgzId7aVocVJJV3nf01qnzzKFGxQVC9bpWxl5cjxTr/7Q==} - engines: {node: '>=6.0.0'} - hasBin: true + available-typed-arrays@1.0.7: + resolution: + { + integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==, + } + engines: { node: '>= 0.4' } - before-after-hook@4.0.0: - resolution: {integrity: sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==} + axe-core@4.10.2: + resolution: + { + integrity: sha512-RE3mdQ7P3FRSe7eqCWoeQ/Z9QXrtniSjp1wUjt5nRC3WIpz5rSCve6o3fsZ2aCpJtrZjSZgjwXAoTO5k4tEI0w==, + } + engines: { node: '>=4' } + + axobject-query@4.1.0: + resolution: + { + integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==, + } + engines: { node: '>= 0.4' } + + balanced-match@1.0.2: + resolution: + { + integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==, + } binary-extensions@2.3.0: - resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==, + } + engines: { node: '>=8' } + + brace-expansion@1.1.11: + resolution: + { + integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==, + } + + brace-expansion@2.0.1: + resolution: + { + integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==, + } braces@3.0.3: - resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==, + } + engines: { node: '>=8' } - browserslist@4.28.2: - resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + browserslist@4.23.2: + resolution: + { + integrity: sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==, + } + engines: { node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7 } + hasBin: true + + browserslist@4.24.2: + resolution: + { + integrity: sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==, + } + engines: { node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7 } hasBin: true buffer-from@1.1.2: - resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + resolution: + { + integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==, + } - bun-types@1.3.14: - resolution: {integrity: sha512-4N0ig0fEomHt5R0KCFWjovxow98rIoRwKolrYdCcknNwMekCXRnWEUvgu5soYV8QXtVsrUD8B95MBOZGPvr6KQ==} + bun-types@1.1.34: + resolution: + { + integrity: sha512-br5QygTEL/TwB4uQOb96Ky22j4Gq2WxWH/8Oqv20fk5HagwKXo/akB+LiYgSfzexCt6kkcUaVm+bKiPl71xPvw==, + } - bun@1.3.14: - resolution: {integrity: sha512-aB6GVd42x1Y5ie1K16SF+oLGtgSkwX9hgoDdIW88pjvfTccU8F1vfpoOt34QLv0dZ1v3XimtaxPlZUG81Gx9Zg==} + bun@1.1.29: + resolution: + { + integrity: sha512-SKhpyKNZtgxrVel9ec9xon3LDv8mgpiuFhARgcJo1YIbggY2PBrKHRNiwQ6Qlb+x3ivmRurfuwWgwGexjpgBRg==, + } cpu: [arm64, x64] - os: [darwin, linux, android, freebsd, win32] + os: [darwin, linux, win32] hasBin: true - bundle-require@5.1.0: - resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + bundle-require@5.0.0: + resolution: + { + integrity: sha512-GuziW3fSSmopcx4KRymQEJVbZUfqlCqcq7dvs6TYwKRZiegK/2buMxQTPs6MGlNv50wms1699qYO54R8XfRX4w==, + } + engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 } peerDependencies: esbuild: '>=0.18' + busboy@1.6.0: + resolution: + { + integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==, + } + engines: { node: '>=10.16.0' } + cac@6.7.14: - resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==, + } + engines: { node: '>=8' } + + call-bind@1.0.7: + resolution: + { + integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==, + } + engines: { node: '>= 0.4' } + + callsites@3.1.0: + resolution: + { + integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==, + } + engines: { node: '>=6' } camelcase-css@2.0.1: - resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} - engines: {node: '>= 6'} + resolution: + { + integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==, + } + engines: { node: '>= 6' } - caniuse-lite@1.0.30001793: - resolution: {integrity: sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==} + caniuse-lite@1.0.30001669: + resolution: + { + integrity: sha512-DlWzFDJqstqtIVx1zeSpIMLjunf5SmwOw0N2Ck/QSQdS8PLS4+9HrLaYei4w8BIAL7IB/UEDu889d8vhCTPA0w==, + } - chai@6.2.2: - resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} - engines: {node: '>=18'} + chai@5.1.1: + resolution: + { + integrity: sha512-pT1ZgP8rPNqUgieVaEY+ryQr6Q4HXNg8Ei9UnLUrjN4IA7dvQC5JB+/kxVcPNDHyBcc/26CXPkbNzq3qwrOEKA==, + } + engines: { node: '>=12' } - chardet@2.1.1: - resolution: {integrity: sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==} + chalk@2.4.2: + resolution: + { + integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==, + } + engines: { node: '>=4' } + + chalk@4.1.2: + resolution: + { + integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==, + } + engines: { node: '>=10' } + + check-error@2.1.1: + resolution: + { + integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==, + } + engines: { node: '>= 16' } chokidar@3.6.0: - resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} - engines: {node: '>= 8.10.0'} - - chokidar@4.0.3: - resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} - engines: {node: '>= 14.16.0'} - - chrome-trace-event@1.0.4: - resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} - engines: {node: '>=6.0'} - - citty@0.2.2: - resolution: {integrity: sha512-+6vJA3L98yv+IdfKGZHBNiGW5KHn22e/JwID0Strsz8h4S/csAu/OuICwxrg44k5MRiZHWIo8XXuJgQTriRP4w==} - - cli-width@4.1.0: - resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} - engines: {node: '>= 12'} + resolution: + { + integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==, + } + engines: { node: '>= 8.10.0' } client-only@0.0.1: - resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + resolution: + { + integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==, + } - clipanion@4.0.0-rc.4: - resolution: {integrity: sha512-CXkMQxU6s9GklO/1f714dkKBMu1lopS1WFF0B8o4AxPykR1hpozxSiUZ5ZUeBjfPgCWqbcNOtZVFhB8Lkfp1+Q==} - peerDependencies: - typanion: '*' + color-convert@1.9.3: + resolution: + { + integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==, + } - colorette@2.0.20: - resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + color-convert@2.0.1: + resolution: + { + integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==, + } + engines: { node: '>=7.0.0' } + + color-name@1.1.3: + resolution: + { + integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==, + } + + color-name@1.1.4: + resolution: + { + integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==, + } + + color-string@1.9.1: + resolution: + { + integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==, + } + + color@4.2.3: + resolution: + { + integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==, + } + engines: { node: '>=12.5.0' } commander@2.20.3: - resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + resolution: + { + integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==, + } commander@4.1.1: - resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} - engines: {node: '>= 6'} + resolution: + { + integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==, + } + engines: { node: '>= 6' } - confbox@0.1.8: - resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + concat-map@0.0.1: + resolution: + { + integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==, + } - consola@3.4.2: - resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} - engines: {node: ^14.18.0 || >=16.10.0} - - content-type@2.0.0: - resolution: {integrity: sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==} - engines: {node: '>=18'} + consola@3.2.3: + resolution: + { + integrity: sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==, + } + engines: { node: ^14.18.0 || >=16.10.0 } convert-source-map@2.0.0: - resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + resolution: + { + integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==, + } - cookie-es@1.2.3: - resolution: {integrity: sha512-lXVyvUvrNXblMqzIRrxHb57UUVmqsSWlxqt3XIjCkUP0wDAf6uicO6KMbEgYrMNtEvWgWHwe42CKxPu9MYAnWw==} + cross-spawn@7.0.3: + resolution: + { + integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==, + } + engines: { node: '>= 8' } - crossws@0.3.5: - resolution: {integrity: sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==} - - crossws@0.4.10: - resolution: {integrity: sha512-pz3oubH/dt12KjqsUB0IuXW4nwRDQ583iDsP4555Cpdqx0NoU7pGlWBcayyFI8f/l/idRpgjMEfwuOxSWJYlIA==} - peerDependencies: - srvx: '>=0.11.5' - peerDependenciesMeta: - srvx: - optional: true + cross-spawn@7.0.6: + resolution: + { + integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==, + } + engines: { node: '>= 8' } cssesc@3.0.0: - resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} - engines: {node: '>=4'} + resolution: + { + integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==, + } + engines: { node: '>=4' } hasBin: true - csstype@3.2.3: - resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + csstype@3.1.3: + resolution: + { + integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==, + } - debug@4.4.3: - resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} - engines: {node: '>=6.0'} + damerau-levenshtein@1.0.8: + resolution: + { + integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==, + } + + data-view-buffer@1.0.1: + resolution: + { + integrity: sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==, + } + engines: { node: '>= 0.4' } + + data-view-byte-length@1.0.1: + resolution: + { + integrity: sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==, + } + engines: { node: '>= 0.4' } + + data-view-byte-offset@1.0.0: + resolution: + { + integrity: sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==, + } + engines: { node: '>= 0.4' } + + debug@3.2.7: + resolution: + { + integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==, + } peerDependencies: supports-color: '*' peerDependenciesMeta: supports-color: optional: true - dedent@1.7.2: - resolution: {integrity: sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==} + debug@4.3.6: + resolution: + { + integrity: sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==, + } + engines: { node: '>=6.0' } + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.3.7: + resolution: + { + integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==, + } + engines: { node: '>=6.0' } + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + dedent@1.5.3: + resolution: + { + integrity: sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==, + } peerDependencies: babel-plugin-macros: ^3.1.0 peerDependenciesMeta: babel-plugin-macros: optional: true - defu@6.1.7: - resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==} + deep-eql@5.0.2: + resolution: + { + integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==, + } + engines: { node: '>=6' } - destr@2.0.5: - resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} + deep-is@0.1.4: + resolution: + { + integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==, + } + + define-data-property@1.1.4: + resolution: + { + integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==, + } + engines: { node: '>= 0.4' } + + define-properties@1.2.1: + resolution: + { + integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==, + } + engines: { node: '>= 0.4' } detect-libc@1.0.3: - resolution: {integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==} - engines: {node: '>=0.10'} + resolution: + { + integrity: sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==, + } + engines: { node: '>=0.10' } hasBin: true - detect-libc@2.1.2: - resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} - engines: {node: '>=8'} + detect-libc@2.0.3: + resolution: + { + integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==, + } + engines: { node: '>=8' } didyoumean@1.2.2: - resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + resolution: + { + integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==, + } + + dir-glob@3.0.1: + resolution: + { + integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==, + } + engines: { node: '>=8' } dlv@1.1.3: - resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} + resolution: + { + integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==, + } - electron-to-chromium@1.5.361: - resolution: {integrity: sha512-Q6Hts7N9FnJc5LeGRINFvLhCI9xZmNtTDe5ZbcVezQz7cU4a8Aua3GH1b8J2XY8Al9PF+OCwYqhgsOOheMdvkA==} + doctrine@2.1.0: + resolution: + { + integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==, + } + engines: { node: '>=0.10.0' } - emnapi@1.11.3: - resolution: {integrity: sha512-+/ZS90YK/rYfVOHtGLHkGffVsnmD/MAKaBHio+Y4XAtg75RLr4cveV/w0jTkUdLM1CcAlaRgG76mpIemWAlk0A==} - peerDependencies: - node-addon-api: '>= 6.1.0' - peerDependenciesMeta: - node-addon-api: - optional: true + eastasianwidth@0.2.0: + resolution: + { + integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==, + } - enhanced-resolve@5.24.5: - resolution: {integrity: sha512-L1l8TNvomm6UVW5B253AGxQagSQr+vGwhMlrrfRS2qmhx46AMpMVJKQYLvWYbysTMY8VoicOvzHzoHMbyzB+4A==} - engines: {node: '>=10.13.0'} + electron-to-chromium@1.5.4: + resolution: + { + integrity: sha512-orzA81VqLyIGUEA77YkVA1D+N+nNfl2isJVjjmOyrlxuooZ19ynb+dOlaDTqd/idKRS9lDCSBmtzM+kyCsMnkA==, + } + + electron-to-chromium@1.5.45: + resolution: + { + integrity: sha512-vOzZS6uZwhhbkZbcRyiy99Wg+pYFV5hk+5YaECvx0+Z31NR3Tt5zS6dze2OepT6PCTzVzT0dIJItti+uAW5zmw==, + } + + emoji-regex@8.0.0: + resolution: + { + integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==, + } + + emoji-regex@9.2.2: + resolution: + { + integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==, + } + + enhanced-resolve@5.17.1: + resolution: + { + integrity: sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==, + } + engines: { node: '>=10.13.0' } + + es-abstract@1.23.3: + resolution: + { + integrity: sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==, + } + engines: { node: '>= 0.4' } + + es-define-property@1.0.0: + resolution: + { + integrity: sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==, + } + engines: { node: '>= 0.4' } es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==, + } + engines: { node: '>= 0.4' } - es-module-lexer@2.1.0: - resolution: {integrity: sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==} + es-iterator-helpers@1.1.0: + resolution: + { + integrity: sha512-/SurEfycdyssORP/E+bj4sEu1CWw4EmLDsHynHwSXQ7utgbrMRWW195pTrCjFgFCddf/UkYm3oqKPRq5i8bJbw==, + } + engines: { node: '>= 0.4' } - es-toolkit@1.50.0: - resolution: {integrity: sha512-OyZKhUVvEep9ITEiwHn8GKnMRQIVqoSIX7WnRbkWgJkllCujilqP2rD0u979tkl8wqyc8ICwlc1UBVv/Sl1G6w==} + es-object-atoms@1.0.0: + resolution: + { + integrity: sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==, + } + engines: { node: '>= 0.4' } - esbuild@0.27.7: - resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} - engines: {node: '>=18'} + es-set-tostringtag@2.0.3: + resolution: + { + integrity: sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==, + } + engines: { node: '>= 0.4' } + + es-shim-unscopables@1.0.2: + resolution: + { + integrity: sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==, + } + + es-to-primitive@1.2.1: + resolution: + { + integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==, + } + engines: { node: '>= 0.4' } + + esbuild@0.21.5: + resolution: + { + integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==, + } + engines: { node: '>=12' } hasBin: true + esbuild@0.23.0: + resolution: + { + integrity: sha512-1lvV17H2bMYda/WaFb2jLPeHU3zml2k4/yagNMG8Q/YtfMjCwEUZa2eXXMgZTVSL5q1n4H7sQ0X6CdJDqqeCFA==, + } + engines: { node: '>=18' } + hasBin: true + + esbuild@0.23.1: + resolution: + { + integrity: sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==, + } + engines: { node: '>=18' } + hasBin: true + + esbuild@0.24.0: + resolution: + { + integrity: sha512-FuLPevChGDshgSicjisSooU0cemp/sGXR841D5LHMB7mTVOmsEHcAxaH3irL53+8YDIeVNQEySh4DaYU/iuPqQ==, + } + engines: { node: '>=18' } + hasBin: true + + escalade@3.1.2: + resolution: + { + integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==, + } + engines: { node: '>=6' } + escalade@3.2.0: - resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} - engines: {node: '>=6'} + resolution: + { + integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==, + } + engines: { node: '>=6' } - eslint-scope@5.1.1: - resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} - engines: {node: '>=8.0.0'} + escape-string-regexp@1.0.5: + resolution: + { + integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==, + } + engines: { node: '>=0.8.0' } - esrecurse@4.3.0: - resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} - engines: {node: '>=4.0'} + escape-string-regexp@4.0.0: + resolution: + { + integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==, + } + engines: { node: '>=10' } - estraverse@4.3.0: - resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} - engines: {node: '>=4.0'} - - estraverse@5.3.0: - resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} - engines: {node: '>=4.0'} - - estree-walker@3.0.3: - resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} - - events@3.3.0: - resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} - engines: {node: '>=0.8.x'} - - expect-type@1.3.0: - resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} - engines: {node: '>=12.0.0'} - - fast-content-type-parse@3.0.0: - resolution: {integrity: sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg==} - - fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - - fast-equals@5.4.0: - resolution: {integrity: sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==} - engines: {node: '>=6.0.0'} - - fast-glob@3.3.3: - resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} - engines: {node: '>=8.6.0'} - - fast-string-truncated-width@3.0.3: - resolution: {integrity: sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==} - - fast-string-width@3.0.2: - resolution: {integrity: sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==} - - fast-stringify@4.0.0: - resolution: {integrity: sha512-lE2DIivBaLysf6hK5WH/VfMgqRbvBVHcpGVVTmA5Zi8oWIjq9YxIt6lYGdUgP1HNSXxTIat7HEIDnrSvXSeKQw==} - - fast-uri@3.1.2: - resolution: {integrity: sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==} - - fast-wrap-ansi@0.2.2: - resolution: {integrity: sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==} - - fastq@1.20.1: - resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} - - fdir@6.5.0: - resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} - engines: {node: '>=12.0.0'} + eslint-config-next@15.0.3: + resolution: + { + integrity: sha512-IGP2DdQQrgjcr4mwFPve4DrCqo7CVVez1WoYY47XwKSrYO4hC0Dlb+iJA60i0YfICOzgNADIb8r28BpQ5Zs0wg==, + } peerDependencies: - picomatch: ^3 || ^4 + eslint: ^7.23.0 || ^8.0.0 || ^9.0.0 + typescript: '>=3.3.1' peerDependenciesMeta: - picomatch: + typescript: optional: true + eslint-import-resolver-node@0.3.9: + resolution: + { + integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==, + } + + eslint-import-resolver-typescript@3.6.3: + resolution: + { + integrity: sha512-ud9aw4szY9cCT1EWWdGv1L1XR6hh2PaRWif0j2QjQ0pgTY/69iw+W0Z4qZv5wHahOl8isEr+k/JnyAqNQkLkIA==, + } + engines: { node: ^14.18.0 || >=16.0.0 } + peerDependencies: + eslint: '*' + eslint-plugin-import: '*' + eslint-plugin-import-x: '*' + peerDependenciesMeta: + eslint-plugin-import: + optional: true + eslint-plugin-import-x: + optional: true + + eslint-module-utils@2.12.0: + resolution: + { + integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==, + } + engines: { node: '>=4' } + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + + eslint-plugin-import@2.31.0: + resolution: + { + integrity: sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==, + } + engines: { node: '>=4' } + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + + eslint-plugin-jsx-a11y@6.10.1: + resolution: + { + integrity: sha512-zHByM9WTUMnfsDTafGXRiqxp6lFtNoSOWBY6FonVRn3A+BUwN1L/tdBXT40BcBJi0cZjOGTXZ0eD/rTG9fEJ0g==, + } + engines: { node: '>=4.0' } + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9 + + eslint-plugin-react-hooks@5.0.0: + resolution: + { + integrity: sha512-hIOwI+5hYGpJEc4uPRmz2ulCjAGD/N13Lukkh8cLV0i2IRk/bdZDYjgLVHj+U9Z704kLIdIO6iueGvxNur0sgw==, + } + engines: { node: '>=10' } + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 + + eslint-plugin-react@7.37.2: + resolution: + { + integrity: sha512-EsTAnj9fLVr/GZleBLFbj/sSuXeWmp1eXIN60ceYnZveqEaUCyW4X+Vh4WTdUhCkW4xutXYqTXCUSyqD4rB75w==, + } + engines: { node: '>=4' } + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 + + eslint-scope@8.2.0: + resolution: + { + integrity: sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + eslint-visitor-keys@3.4.3: + resolution: + { + integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==, + } + engines: { node: ^12.22.0 || ^14.17.0 || >=16.0.0 } + + eslint-visitor-keys@4.2.0: + resolution: + { + integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + eslint@9.15.0: + resolution: + { + integrity: sha512-7CrWySmIibCgT1Os28lUU6upBshZ+GxybLOrmRzi08kS8MBuO8QA7pXEgYgY5W8vK3e74xv0lpjo9DbaGU9Rkw==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + espree@10.3.0: + resolution: + { + integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==, + } + engines: { node: ^18.18.0 || ^20.9.0 || >=21.1.0 } + + esquery@1.6.0: + resolution: + { + integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==, + } + engines: { node: '>=0.10' } + + esrecurse@4.3.0: + resolution: + { + integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==, + } + engines: { node: '>=4.0' } + + estraverse@5.3.0: + resolution: + { + integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==, + } + engines: { node: '>=4.0' } + + estree-walker@3.0.3: + resolution: + { + integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==, + } + + esutils@2.0.3: + resolution: + { + integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==, + } + engines: { node: '>=0.10.0' } + + execa@5.1.1: + resolution: + { + integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==, + } + engines: { node: '>=10' } + + execa@8.0.1: + resolution: + { + integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==, + } + engines: { node: '>=16.17' } + + fast-deep-equal@3.1.3: + resolution: + { + integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==, + } + + fast-glob@3.3.1: + resolution: + { + integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==, + } + engines: { node: '>=8.6.0' } + + fast-glob@3.3.2: + resolution: + { + integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==, + } + engines: { node: '>=8.6.0' } + + fast-json-stable-stringify@2.1.0: + resolution: + { + integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==, + } + + fast-levenshtein@2.0.6: + resolution: + { + integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==, + } + + fastq@1.17.1: + resolution: + { + integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==, + } + + file-entry-cache@8.0.0: + resolution: + { + integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==, + } + engines: { node: '>=16.0.0' } + fill-range@7.1.1: - resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==, + } + engines: { node: '>=8' } - find-up-simple@1.0.1: - resolution: {integrity: sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==} - engines: {node: '>=18'} + find-up-simple@1.0.0: + resolution: + { + integrity: sha512-q7Us7kcjj2VMePAa02hDAF6d+MzsdsAWEwYyOpwUtlerRBkOEPBCRZrAV4XfcSN8fHAgaD0hP7miwoay6DCprw==, + } + engines: { node: '>=18' } - fix-dts-default-cjs-exports@1.0.1: - resolution: {integrity: sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==} + find-up@5.0.0: + resolution: + { + integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==, + } + engines: { node: '>=10' } - fraction.js@5.3.4: - resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} + flat-cache@4.0.1: + resolution: + { + integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==, + } + engines: { node: '>=16' } + + flatted@3.3.1: + resolution: + { + integrity: sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==, + } + + for-each@0.3.3: + resolution: + { + integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==, + } + + foreground-child@3.3.0: + resolution: + { + integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==, + } + engines: { node: '>=14' } + + fraction.js@4.3.7: + resolution: + { + integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==, + } fsevents@2.3.2: - resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + resolution: + { + integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==, + } + engines: { node: ^8.16.0 || ^10.6.0 || >=11.0.0 } os: [darwin] fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + resolution: + { + integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==, + } + engines: { node: ^8.16.0 || ^10.6.0 || >=11.0.0 } os: [darwin] function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + resolution: + { + integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==, + } - get-port-please@3.2.0: - resolution: {integrity: sha512-I9QVvBw5U/hw3RmWpYKRumUeaDgxTPd401x364rLmWBJcOQ753eov1eTgzDqRG9bqFIfDc7gfzcQEWrUri3o1A==} + function.prototype.name@1.1.6: + resolution: + { + integrity: sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==, + } + engines: { node: '>= 0.4' } + + functions-have-names@1.2.3: + resolution: + { + integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==, + } + + gensync@1.0.0-beta.2: + resolution: + { + integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==, + } + engines: { node: '>=6.9.0' } + + get-func-name@2.0.2: + resolution: + { + integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==, + } + + get-intrinsic@1.2.4: + resolution: + { + integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==, + } + engines: { node: '>= 0.4' } + + get-stream@6.0.1: + resolution: + { + integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==, + } + engines: { node: '>=10' } + + get-stream@8.0.1: + resolution: + { + integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==, + } + engines: { node: '>=16' } + + get-symbol-description@1.0.2: + resolution: + { + integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==, + } + engines: { node: '>= 0.4' } + + get-tsconfig@4.8.1: + resolution: + { + integrity: sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==, + } glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} + resolution: + { + integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==, + } + engines: { node: '>= 6' } glob-parent@6.0.2: - resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} - engines: {node: '>=10.13.0'} + resolution: + { + integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==, + } + engines: { node: '>=10.13.0' } - globby@16.2.2: - resolution: {integrity: sha512-NLvV9ubZ6NDsJaOpKPy3cQeJpKi9DcWiyCiFUpJPA0YihRqiE6RWaLUmgNNPr8MgPpLZjnBjSmou7uZBRJv9wA==} - engines: {node: '>=20'} - - graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - - h3@1.15.11: - resolution: {integrity: sha512-L3THSe2MPeBwgIZVSH5zLdBBU90TOxarvhK9d04IDY2AmVS8j2Jz2LIWtwsGOU3lu2I5jCN7FNvVfY2+XyF+mg==} - - has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - - hasown@2.0.3: - resolution: {integrity: sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==} - engines: {node: '>= 0.4'} - - http-shutdown@1.2.2: - resolution: {integrity: sha512-S9wWkJ/VSY9/k4qcjG318bqJNruzE4HySUhFYknwmu6LBP97KLLfwNf+n4V1BHurvFNkSKLFnK/RsuUnRTf9Vw==} - engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} - - iconv-lite@0.7.2: - resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} - engines: {node: '>=0.10.0'} - - ignore@7.0.5: - resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} - engines: {node: '>= 4'} - - iron-webcrypto@1.2.1: - resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==} - - is-binary-path@2.1.0: - resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} - engines: {node: '>=8'} - - is-core-module@2.16.2: - resolution: {integrity: sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==} - engines: {node: '>= 0.4'} - - is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - - is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - - is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - - is-path-inside@4.0.0: - resolution: {integrity: sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==} - engines: {node: '>=12'} - - jest-worker@27.5.1: - resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} - engines: {node: '>= 10.13.0'} - - jiti@1.21.7: - resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} + glob@10.4.5: + resolution: + { + integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==, + } hasBin: true - jiti@2.7.0: - resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} + globals@11.12.0: + resolution: + { + integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==, + } + engines: { node: '>=4' } + + globals@14.0.0: + resolution: + { + integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==, + } + engines: { node: '>=18' } + + globalthis@1.0.4: + resolution: + { + integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==, + } + engines: { node: '>= 0.4' } + + globby@11.1.0: + resolution: + { + integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==, + } + engines: { node: '>=10' } + + globby@14.0.2: + resolution: + { + integrity: sha512-s3Fq41ZVh7vbbe2PN3nrW7yC7U7MFVc5c98/iTl9c2GawNMKx/J648KQRW6WKkuU8GIbbh2IXfIRQjOZnXcTnw==, + } + engines: { node: '>=18' } + + gopd@1.0.1: + resolution: + { + integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==, + } + + graceful-fs@4.2.11: + resolution: + { + integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==, + } + + graphemer@1.4.0: + resolution: + { + integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==, + } + + has-bigints@1.0.2: + resolution: + { + integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==, + } + + has-flag@3.0.0: + resolution: + { + integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==, + } + engines: { node: '>=4' } + + has-flag@4.0.0: + resolution: + { + integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==, + } + engines: { node: '>=8' } + + has-property-descriptors@1.0.2: + resolution: + { + integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==, + } + + has-proto@1.0.3: + resolution: + { + integrity: sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==, + } + engines: { node: '>= 0.4' } + + has-symbols@1.0.3: + resolution: + { + integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==, + } + engines: { node: '>= 0.4' } + + has-tostringtag@1.0.2: + resolution: + { + integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==, + } + engines: { node: '>= 0.4' } + + hasown@2.0.2: + resolution: + { + integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==, + } + engines: { node: '>= 0.4' } + + human-signals@2.1.0: + resolution: + { + integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==, + } + engines: { node: '>=10.17.0' } + + human-signals@5.0.0: + resolution: + { + integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==, + } + engines: { node: '>=16.17.0' } + + ignore@5.3.1: + resolution: + { + integrity: sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==, + } + engines: { node: '>= 4' } + + ignore@5.3.2: + resolution: + { + integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==, + } + engines: { node: '>= 4' } + + import-fresh@3.3.0: + resolution: + { + integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==, + } + engines: { node: '>=6' } + + imurmurhash@0.1.4: + resolution: + { + integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==, + } + engines: { node: '>=0.8.19' } + + internal-slot@1.0.7: + resolution: + { + integrity: sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==, + } + engines: { node: '>= 0.4' } + + is-array-buffer@3.0.4: + resolution: + { + integrity: sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==, + } + engines: { node: '>= 0.4' } + + is-arrayish@0.3.2: + resolution: + { + integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==, + } + + is-async-function@2.0.0: + resolution: + { + integrity: sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==, + } + engines: { node: '>= 0.4' } + + is-bigint@1.0.4: + resolution: + { + integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==, + } + + is-binary-path@2.1.0: + resolution: + { + integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==, + } + engines: { node: '>=8' } + + is-boolean-object@1.1.2: + resolution: + { + integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==, + } + engines: { node: '>= 0.4' } + + is-bun-module@1.2.1: + resolution: + { + integrity: sha512-AmidtEM6D6NmUiLOvvU7+IePxjEjOzra2h0pSrsfSAcXwl/83zLLXDByafUJy9k/rKK0pvXMLdwKwGHlX2Ke6Q==, + } + + is-callable@1.2.7: + resolution: + { + integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==, + } + engines: { node: '>= 0.4' } + + is-core-module@2.15.0: + resolution: + { + integrity: sha512-Dd+Lb2/zvk9SKy1TGCt1wFJFo/MWBPMX5x7KcvLajWTGuomczdQX61PvY5yK6SVACwpoexWo81IfFyoKY2QnTA==, + } + engines: { node: '>= 0.4' } + + is-core-module@2.15.1: + resolution: + { + integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==, + } + engines: { node: '>= 0.4' } + + is-data-view@1.0.1: + resolution: + { + integrity: sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==, + } + engines: { node: '>= 0.4' } + + is-date-object@1.0.5: + resolution: + { + integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==, + } + engines: { node: '>= 0.4' } + + is-extglob@2.1.1: + resolution: + { + integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==, + } + engines: { node: '>=0.10.0' } + + is-finalizationregistry@1.0.2: + resolution: + { + integrity: sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==, + } + + is-fullwidth-code-point@3.0.0: + resolution: + { + integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==, + } + engines: { node: '>=8' } + + is-generator-function@1.0.10: + resolution: + { + integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==, + } + engines: { node: '>= 0.4' } + + is-glob@4.0.3: + resolution: + { + integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==, + } + engines: { node: '>=0.10.0' } + + is-map@2.0.3: + resolution: + { + integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==, + } + engines: { node: '>= 0.4' } + + is-negative-zero@2.0.3: + resolution: + { + integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==, + } + engines: { node: '>= 0.4' } + + is-number-object@1.0.7: + resolution: + { + integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==, + } + engines: { node: '>= 0.4' } + + is-number@7.0.0: + resolution: + { + integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==, + } + engines: { node: '>=0.12.0' } + + is-regex@1.1.4: + resolution: + { + integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==, + } + engines: { node: '>= 0.4' } + + is-set@2.0.3: + resolution: + { + integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==, + } + engines: { node: '>= 0.4' } + + is-shared-array-buffer@1.0.3: + resolution: + { + integrity: sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==, + } + engines: { node: '>= 0.4' } + + is-stream@2.0.1: + resolution: + { + integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==, + } + engines: { node: '>=8' } + + is-stream@3.0.0: + resolution: + { + integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==, + } + engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 } + + is-string@1.0.7: + resolution: + { + integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==, + } + engines: { node: '>= 0.4' } + + is-symbol@1.0.4: + resolution: + { + integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==, + } + engines: { node: '>= 0.4' } + + is-typed-array@1.1.13: + resolution: + { + integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==, + } + engines: { node: '>= 0.4' } + + is-weakmap@2.0.2: + resolution: + { + integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==, + } + engines: { node: '>= 0.4' } + + is-weakref@1.0.2: + resolution: + { + integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==, + } + + is-weakset@2.0.3: + resolution: + { + integrity: sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==, + } + engines: { node: '>= 0.4' } + + isarray@2.0.5: + resolution: + { + integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==, + } + + isexe@2.0.0: + resolution: + { + integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==, + } + + iterator.prototype@1.1.3: + resolution: + { + integrity: sha512-FW5iMbeQ6rBGm/oKgzq2aW4KvAGpxPzYES8N4g4xNXUKpL1mclMvOe+76AcLDTvD+Ze+sOpVhgdAQEKF4L9iGQ==, + } + engines: { node: '>= 0.4' } + + jackspeak@3.4.3: + resolution: + { + integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==, + } + + jiti@1.21.6: + resolution: + { + integrity: sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==, + } + hasBin: true + + jiti@2.4.0: + resolution: + { + integrity: sha512-H5UpaUI+aHOqZXlYOaFP/8AzKsg+guWu+Pr3Y8i7+Y3zr1aXAvCvTAQ1RxSc6oVD8R8c7brgNtTVP91E7upH/g==, + } hasBin: true joycon@3.1.1: - resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} - engines: {node: '>=10'} + resolution: + { + integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==, + } + engines: { node: '>=10' } - js-yaml@4.3.1: - resolution: {integrity: sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==} + js-tokens@4.0.0: + resolution: + { + integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==, + } + + js-yaml@4.1.0: + resolution: + { + integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==, + } hasBin: true - json-schema-traverse@1.0.0: - resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + jsesc@2.5.2: + resolution: + { + integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==, + } + engines: { node: '>=4' } + hasBin: true - json-with-bigint@3.5.8: - resolution: {integrity: sha512-eq/4KP6K34kwa7TcFdtvnftvHCD9KvHOGGICWwMFc4dOOKF5t4iYqnfLK8otCRCRv06FXOzGGyqE8h8ElMvvdw==} + json-buffer@3.0.1: + resolution: + { + integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==, + } - lightningcss-android-arm64@1.33.0: - resolution: {integrity: sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [android] + json-schema-traverse@0.4.1: + resolution: + { + integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==, + } - lightningcss-darwin-arm64@1.33.0: - resolution: {integrity: sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==} - engines: {node: '>= 12.0.0'} + json-stable-stringify-without-jsonify@1.0.1: + resolution: + { + integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==, + } + + json5@1.0.2: + resolution: + { + integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==, + } + hasBin: true + + json5@2.2.3: + resolution: + { + integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==, + } + engines: { node: '>=6' } + hasBin: true + + jsx-ast-utils@3.3.5: + resolution: + { + integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==, + } + engines: { node: '>=4.0' } + + keyv@4.5.4: + resolution: + { + integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==, + } + + language-subtag-registry@0.3.23: + resolution: + { + integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==, + } + + language-tags@1.0.9: + resolution: + { + integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==, + } + engines: { node: '>=0.10' } + + levn@0.4.1: + resolution: + { + integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==, + } + engines: { node: '>= 0.8.0' } + + lightningcss-darwin-arm64@1.26.0: + resolution: + { + integrity: sha512-n4TIvHO1NY1ondKFYpL2ZX0bcC2y6yjXMD6JfyizgR8BCFNEeArINDzEaeqlfX9bXz73Bpz/Ow0nu+1qiDrBKg==, + } + engines: { node: '>= 12.0.0' } cpu: [arm64] os: [darwin] - lightningcss-darwin-x64@1.33.0: - resolution: {integrity: sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==} - engines: {node: '>= 12.0.0'} + lightningcss-darwin-x64@1.26.0: + resolution: + { + integrity: sha512-Rf9HuHIDi1R6/zgBkJh25SiJHF+dm9axUZW/0UoYCW1/8HV0gMI0blARhH4z+REmWiU1yYT/KyNF3h7tHyRXUg==, + } + engines: { node: '>= 12.0.0' } cpu: [x64] os: [darwin] - lightningcss-freebsd-x64@1.33.0: - resolution: {integrity: sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==} - engines: {node: '>= 12.0.0'} + lightningcss-freebsd-x64@1.26.0: + resolution: + { + integrity: sha512-C/io7POAxp6sZxFSVGezjajMlCKQ8KSwISLLGRq8xLQpQMokYrUoqYEwmIX8mLmF6C/CZPk0gFmRSzd8biWM0g==, + } + engines: { node: '>= 12.0.0' } cpu: [x64] os: [freebsd] - lightningcss-linux-arm-gnueabihf@1.33.0: - resolution: {integrity: sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==} - engines: {node: '>= 12.0.0'} + lightningcss-linux-arm-gnueabihf@1.26.0: + resolution: + { + integrity: sha512-Aag9kqXqkyPSW+dXMgyWk66C984Nay2pY8Nws+67gHlDzV3cWh7TvFlzuaTaVFMVqdDTzN484LSK3u39zFBnzg==, + } + engines: { node: '>= 12.0.0' } cpu: [arm] os: [linux] - lightningcss-linux-arm64-gnu@1.33.0: - resolution: {integrity: sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==} - engines: {node: '>= 12.0.0'} + lightningcss-linux-arm64-gnu@1.26.0: + resolution: + { + integrity: sha512-iJmZM7fUyVjH+POtdiCtExG+67TtPUTer7K/5A8DIfmPfrmeGvzfRyBltGhQz13Wi15K1lf2cPYoRaRh6vcwNA==, + } + engines: { node: '>= 12.0.0' } cpu: [arm64] os: [linux] - lightningcss-linux-arm64-musl@1.33.0: - resolution: {integrity: sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==} - engines: {node: '>= 12.0.0'} + lightningcss-linux-arm64-musl@1.26.0: + resolution: + { + integrity: sha512-XxoEL++tTkyuvu+wq/QS8bwyTXZv2y5XYCMcWL45b8XwkiS8eEEEej9BkMGSRwxa5J4K+LDeIhLrS23CpQyfig==, + } + engines: { node: '>= 12.0.0' } cpu: [arm64] os: [linux] - lightningcss-linux-x64-gnu@1.33.0: - resolution: {integrity: sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==} - engines: {node: '>= 12.0.0'} + lightningcss-linux-x64-gnu@1.26.0: + resolution: + { + integrity: sha512-1dkTfZQAYLj8MUSkd6L/+TWTG8V6Kfrzfa0T1fSlXCXQHrt1HC1/UepXHtKHDt/9yFwyoeayivxXAsApVxn6zA==, + } + engines: { node: '>= 12.0.0' } cpu: [x64] os: [linux] - lightningcss-linux-x64-musl@1.33.0: - resolution: {integrity: sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==} - engines: {node: '>= 12.0.0'} + lightningcss-linux-x64-musl@1.26.0: + resolution: + { + integrity: sha512-yX3Rk9m00JGCUzuUhFEojY+jf/6zHs3XU8S8Vk+FRbnr4St7cjyMXdNjuA2LjiT8e7j8xHRCH8hyZ4H/btRE4A==, + } + engines: { node: '>= 12.0.0' } cpu: [x64] os: [linux] - lightningcss-win32-arm64-msvc@1.33.0: - resolution: {integrity: sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==} - engines: {node: '>= 12.0.0'} + lightningcss-win32-arm64-msvc@1.26.0: + resolution: + { + integrity: sha512-X/597/cFnCogy9VItj/+7Tgu5VLbAtDF7KZDPdSw0MaL6FL940th1y3HiOzFIlziVvAtbo0RB3NAae1Oofr+Tw==, + } + engines: { node: '>= 12.0.0' } cpu: [arm64] os: [win32] - lightningcss-win32-x64-msvc@1.33.0: - resolution: {integrity: sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==} - engines: {node: '>= 12.0.0'} + lightningcss-win32-x64-msvc@1.26.0: + resolution: + { + integrity: sha512-pYS3EyGP3JRhfqEFYmfFDiZ9/pVNfy8jVIYtrx9TVNusVyDK3gpW1w/rbvroQ4bDJi7grdUtyrYU6V2xkY/bBw==, + } + engines: { node: '>= 12.0.0' } cpu: [x64] os: [win32] - lightningcss@1.33.0: - resolution: {integrity: sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==} - engines: {node: '>= 12.0.0'} + lightningcss@1.26.0: + resolution: + { + integrity: sha512-a/XZ5hdgifrofQJUArr5AiJjx26SwMam3SJUSMjgebZbESZ96i+6Qsl8tLi0kaUsdMzBWXh9sN1Oe6hp2/dkQw==, + } + engines: { node: '>= 12.0.0' } - lilconfig@3.1.3: - resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} - engines: {node: '>=14'} + lilconfig@2.1.0: + resolution: + { + integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==, + } + engines: { node: '>=10' } + + lilconfig@3.1.2: + resolution: + { + integrity: sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==, + } + engines: { node: '>=14' } lines-and-columns@1.2.4: - resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - - listhen@1.10.1: - resolution: {integrity: sha512-6nt/86SkqUQSLW1ofz8MxC6RhRMqOl3ONISe6qqvJ3xj09aJWQx6DhgSZpugs3PX4PXdOas/WD6A9jx6J2N19A==} - hasBin: true - peerDependencies: - '@parcel/watcher': ^2.5.6 - peerDependenciesMeta: - '@parcel/watcher': - optional: true + resolution: + { + integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==, + } load-tsconfig@0.2.5: - resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + resolution: + { + integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==, + } + engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 } - magic-string@0.30.21: - resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + locate-path@6.0.0: + resolution: + { + integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==, + } + engines: { node: '>=10' } - magic-string@1.1.0: - resolution: {integrity: sha512-kS3VHe0nEPST2saQV4Rbkchcd3UBRkVTQHo1D3h/ZTwFDhai/mfKkmtPAtD129EOI7K3HlHIsFOt0WrI2/oU9g==} + lodash.castarray@4.4.0: + resolution: + { + integrity: sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==, + } + + lodash.isplainobject@4.0.6: + resolution: + { + integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==, + } + + lodash.merge@4.6.2: + resolution: + { + integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==, + } + + lodash.sortby@4.7.0: + resolution: + { + integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==, + } + + loose-envify@1.4.0: + resolution: + { + integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==, + } + hasBin: true + + loupe@3.1.1: + resolution: + { + integrity: sha512-edNu/8D5MKVfGVFRhFf8aAxiTM6Wumfz5XsaatSxlD3w4R1d/WEKUTydCdPGbl9K7QG/Ca3GnDV2sIKIpXRQcw==, + } + + lru-cache@10.4.3: + resolution: + { + integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==, + } + + lru-cache@5.1.1: + resolution: + { + integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==, + } + + magic-string@0.30.11: + resolution: + { + integrity: sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==, + } merge-stream@2.0.0: - resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + resolution: + { + integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==, + } merge2@1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} + resolution: + { + integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==, + } + engines: { node: '>= 8' } - micro-memoize@5.1.1: - resolution: {integrity: sha512-QDwluos8YeMijiKxZGwaV4f4tzj0soS6+xcsJhJ3+4wdEIHMyKbIKVUziebOgWX3e6yiijdoaHo+9tyhbnaWXA==} + micro-memoize@4.1.2: + resolution: + { + integrity: sha512-+HzcV2H+rbSJzApgkj0NdTakkC+bnyeiUxgT6/m7mjcz1CmM22KYFKp+EVj1sWe4UYcnriJr5uqHQD/gMHLD+g==, + } - micromatch@4.0.8: - resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} - engines: {node: '>=8.6'} + micromatch@4.0.7: + resolution: + { + integrity: sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==, + } + engines: { node: '>=8.6' } - mime-db@1.54.0: - resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} - engines: {node: '>= 0.6'} + mimic-fn@2.1.0: + resolution: + { + integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==, + } + engines: { node: '>=6' } + + mimic-fn@4.0.0: + resolution: + { + integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==, + } + engines: { node: '>=12' } mini-svg-data-uri@1.4.4: - resolution: {integrity: sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==} + resolution: + { + integrity: sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==, + } hasBin: true - minimizer-webpack-plugin@5.6.1: - resolution: {integrity: sha512-DoeAZz8Q1C1znwsUzej1fdoi4jCf7/+Em27ouLqfK/+3m8G+D7yDhUwrc3CNhjSzGUN1kn7Iv4sWmjflQHenpw==} - engines: {node: '>= 10.13.0'} - peerDependencies: - '@minify-html/node': '*' - '@swc/core': '*' - '@swc/css': '*' - '@swc/html': '*' - clean-css: '*' - cssnano: '*' - csso: '*' - esbuild: '*' - html-minifier-terser: '*' - lightningcss: '*' - postcss: '*' - uglify-js: '*' - webpack: ^5.1.0 - peerDependenciesMeta: - '@minify-html/node': - optional: true - '@swc/core': - optional: true - '@swc/css': - optional: true - '@swc/html': - optional: true - clean-css: - optional: true - cssnano: - optional: true - csso: - optional: true - esbuild: - optional: true - html-minifier-terser: - optional: true - lightningcss: - optional: true - postcss: - optional: true - uglify-js: - optional: true + minimatch@3.1.2: + resolution: + { + integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==, + } - mlly@1.8.2: - resolution: {integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==} + minimatch@9.0.5: + resolution: + { + integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==, + } + engines: { node: '>=16 || 14 >=14.17' } + + minimist@1.2.8: + resolution: + { + integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==, + } + + minipass@7.1.2: + resolution: + { + integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==, + } + engines: { node: '>=16 || 14 >=14.17' } mri@1.2.0: - resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} - engines: {node: '>=4'} + resolution: + { + integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==, + } + engines: { node: '>=4' } + + ms@2.1.2: + resolution: + { + integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==, + } ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - - mute-stream@3.0.0: - resolution: {integrity: sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==} - engines: {node: ^20.17.0 || >=22.9.0} + resolution: + { + integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==, + } mz@2.7.0: - resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + resolution: + { + integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==, + } - nanoid@3.3.12: - resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + nanoid@3.3.7: + resolution: + { + integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==, + } + engines: { node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1 } hasBin: true - nanoid@3.3.16: - resolution: {integrity: sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true + natural-compare@1.4.0: + resolution: + { + integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==, + } - neo-async@2.6.2: - resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} - - next@16.2.7: - resolution: {integrity: sha512-eMJxgjRzBaj3olkP4cBamHDXL79A8FC6u1GcsO1D1Tsx8bw/LLXUJCaoajVxtnhD3A1IJqIT8IcRJjgBIPJq4w==} - engines: {node: '>=20.9.0'} + next@15.0.3: + resolution: + { + integrity: sha512-ontCbCRKJUIoivAdGB34yCaOcPgYXr9AAkV/IwqFfWWTXEPUgLYkSkqBhIk9KK7gGmgjc64B+RdoeIDM13Irnw==, + } + engines: { node: ^18.18.0 || ^19.8.0 || >= 20.0.0 } hasBin: true peerDependencies: '@opentelemetry/api': ^1.1.0 - '@playwright/test': ^1.51.1 + '@playwright/test': ^1.41.2 babel-plugin-react-compiler: '*' - react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 - react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + react: ^18.2.0 || 19.0.0-rc-66855b96-20241106 + react-dom: ^18.2.0 || 19.0.0-rc-66855b96-20241106 sass: ^1.3.0 peerDependenciesMeta: '@opentelemetry/api': @@ -2937,113 +4654,336 @@ packages: optional: true node-addon-api@7.1.1: - resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} + resolution: + { + integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==, + } - node-addon-api@8.7.0: - resolution: {integrity: sha512-9MdFxmkKaOYVTV+XVRG8ArDwwQ77XIgIPyKASB1k3JPq3M8fGQQQE3YpMOrKm6g//Ktx8ivZr8xo1Qmtqub+GA==} - engines: {node: ^18 || ^20 || >= 21} + node-addon-api@8.2.2: + resolution: + { + integrity: sha512-9emqXAKhVoNrQ792nLI/wpzPpJ/bj/YXxW0CvAau1+RdGBcCRF1Dmz7719zgVsQNrzHl9Tzn3ImZ4qWFarWL0A==, + } + engines: { node: ^18 || ^20 || >= 21 } - node-forge@1.4.0: - resolution: {integrity: sha512-LarFH0+6VfriEhqMMcLX2F7SwSXeWwnEAJEsYm5QKWchiVYVvJyV9v7UDvUv+w5HO23ZpQTXDv/GxdDdMyOuoQ==} - engines: {node: '>= 6.13.0'} - - node-gyp-build@4.8.4: - resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} + node-gyp-build@4.8.2: + resolution: + { + integrity: sha512-IRUxE4BVsHWXkV/SFOut4qTlagw2aM8T5/vnTsmrHJvVoKueJHRc/JaFND7QDDc61kLYUJ6qlZM3sqTSyx2dTw==, + } hasBin: true - node-mock-http@1.0.4: - resolution: {integrity: sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ==} - - node-releases@2.0.46: - resolution: {integrity: sha512-GYVXHE2KnrzAfsAjl4uP++evGFCrAU1jta4ubEjIG7YWt/64Gqv66a30yKwWczVjA6j3bM4nBwH7Pk1JmDHaxQ==} - engines: {node: '>=18'} + node-releases@2.0.18: + resolution: + { + integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==, + } normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} + resolution: + { + integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==, + } + engines: { node: '>=0.10.0' } + + normalize-range@0.1.2: + resolution: + { + integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==, + } + engines: { node: '>=0.10.0' } + + npm-run-path@4.0.1: + resolution: + { + integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==, + } + engines: { node: '>=8' } + + npm-run-path@5.3.0: + resolution: + { + integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==, + } + engines: { node: ^12.20.0 || ^14.13.1 || >=16.0.0 } object-assign@4.1.1: - resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} - engines: {node: '>=0.10.0'} + resolution: + { + integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==, + } + engines: { node: '>=0.10.0' } object-hash@3.0.0: - resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} - engines: {node: '>= 6'} + resolution: + { + integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==, + } + engines: { node: '>= 6' } - obug@2.1.1: - resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} + object-inspect@1.13.2: + resolution: + { + integrity: sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==, + } + engines: { node: '>= 0.4' } - obug@2.1.4: - resolution: {integrity: sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==} - engines: {node: '>=12.20.0'} + object-keys@1.1.1: + resolution: + { + integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==, + } + engines: { node: '>= 0.4' } + + object.assign@4.1.5: + resolution: + { + integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==, + } + engines: { node: '>= 0.4' } + + object.entries@1.1.8: + resolution: + { + integrity: sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==, + } + engines: { node: '>= 0.4' } + + object.fromentries@2.0.8: + resolution: + { + integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==, + } + engines: { node: '>= 0.4' } + + object.groupby@1.0.3: + resolution: + { + integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==, + } + engines: { node: '>= 0.4' } + + object.values@1.2.0: + resolution: + { + integrity: sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==, + } + engines: { node: '>= 0.4' } + + onetime@5.1.2: + resolution: + { + integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==, + } + engines: { node: '>=6' } + + onetime@6.0.0: + resolution: + { + integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==, + } + engines: { node: '>=12' } + + optionator@0.9.4: + resolution: + { + integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==, + } + engines: { node: '>= 0.8.0' } + + p-limit@3.1.0: + resolution: + { + integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==, + } + engines: { node: '>=10' } + + p-locate@5.0.0: + resolution: + { + integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==, + } + engines: { node: '>=10' } + + package-json-from-dist@1.0.1: + resolution: + { + integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==, + } package-up@5.0.0: - resolution: {integrity: sha512-MQEgDUvXCa3sGvqHg3pzHO8e9gqTCMPVrWUko3vPQGntwegmFo52mZb2abIVTjFnUcW0BcPz0D93jV5Cas1DWA==} - engines: {node: '>=18'} + resolution: + { + integrity: sha512-MQEgDUvXCa3sGvqHg3pzHO8e9gqTCMPVrWUko3vPQGntwegmFo52mZb2abIVTjFnUcW0BcPz0D93jV5Cas1DWA==, + } + engines: { node: '>=18' } + + parent-module@1.0.1: + resolution: + { + integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==, + } + engines: { node: '>=6' } + + path-exists@4.0.0: + resolution: + { + integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==, + } + engines: { node: '>=8' } + + path-key@3.1.1: + resolution: + { + integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==, + } + engines: { node: '>=8' } + + path-key@4.0.0: + resolution: + { + integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==, + } + engines: { node: '>=12' } path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + resolution: + { + integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==, + } - pathe@2.0.3: - resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + path-scurry@1.11.1: + resolution: + { + integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==, + } + engines: { node: '>=16 || 14 >=14.18' } + + path-type@4.0.0: + resolution: + { + integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==, + } + engines: { node: '>=8' } + + path-type@5.0.0: + resolution: + { + integrity: sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==, + } + engines: { node: '>=12' } + + pathe@1.1.2: + resolution: + { + integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==, + } + + pathval@2.0.0: + resolution: + { + integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==, + } + engines: { node: '>= 14.16' } picocolors@1.1.1: - resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + resolution: + { + integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==, + } - picomatch@2.3.2: - resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} - engines: {node: '>=8.6'} - - picomatch@4.0.4: - resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} - engines: {node: '>=12'} - - picomatch@4.0.5: - resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==} - engines: {node: '>=12'} + picomatch@2.3.1: + resolution: + { + integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==, + } + engines: { node: '>=8.6' } pify@2.3.0: - resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} - engines: {node: '>=0.10.0'} + resolution: + { + integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==, + } + engines: { node: '>=0.10.0' } - pirates@4.0.7: - resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} - engines: {node: '>= 6'} + pirates@4.0.6: + resolution: + { + integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==, + } + engines: { node: '>= 6' } - pkg-types@1.3.1: - resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} - - playwright-core@1.62.1: - resolution: {integrity: sha512-wPYSwEBJY9GHraISXqyqtx0na0LpO3XEX7jNDhntbex7tzUS7kLnZsOlFruFJB4Hi/rhDMjXGqHewDZ68nYZVw==} - engines: {node: '>=20'} + playwright-core@1.49.0: + resolution: + { + integrity: sha512-R+3KKTQF3npy5GTiKH/T+kdhoJfJojjHESR1YEWhYuEKRVfVaxH3+4+GvXE5xyCngCxhxnykk0Vlah9v8fs3jA==, + } + engines: { node: '>=18' } hasBin: true - playwright@1.62.1: - resolution: {integrity: sha512-0M+L3LAD8/nm554LOla9Ayx0j0tmFZ0FBcoQ7F1VuVHpM/XpiC8RcDzBQB8W5+hA8L22THxELzeF+2WcUzvcLg==} - engines: {node: '>=20'} + playwright@1.49.0: + resolution: + { + integrity: sha512-eKpmys0UFDnfNb3vfsf8Vx2LEOtflgRebl0Im2eQQnYMA4Aqd+Zw8bEOB+7ZKvN76901mRnqdsiOGKxzVTbi7A==, + } + engines: { node: '>=18' } hasBin: true + possible-typed-array-names@1.0.0: + resolution: + { + integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==, + } + engines: { node: '>= 0.4' } + postcss-import@15.1.0: - resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} - engines: {node: '>=14.0.0'} + resolution: + { + integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==, + } + engines: { node: '>=14.0.0' } peerDependencies: postcss: ^8.0.0 - postcss-import@16.1.1: - resolution: {integrity: sha512-2xVS1NCZAfjtVdvXiyegxzJ447GyqCeEI5V7ApgQVOWnros1p5lGNovJNapwPpMombyFBfqDwt7AD3n2l0KOfQ==} - engines: {node: '>=18.0.0'} + postcss-import@16.1.0: + resolution: + { + integrity: sha512-7hsAZ4xGXl4MW+OKEWCnF6T5jqBw80/EE9aXg1r2yyn1RsVEU8EtKXbijEODa+rg7iih4bKf7vlvTGYR4CnPNg==, + } + engines: { node: '>=18.0.0' } peerDependencies: postcss: ^8.0.0 - postcss-js@4.1.0: - resolution: {integrity: sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==} - engines: {node: ^12 || ^14 || >= 16} + postcss-js@4.0.1: + resolution: + { + integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==, + } + engines: { node: ^12 || ^14 || >= 16 } peerDependencies: postcss: ^8.4.21 + postcss-load-config@4.0.2: + resolution: + { + integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==, + } + engines: { node: '>= 14' } + peerDependencies: + postcss: '>=8.0.9' + ts-node: '>=9.0.0' + peerDependenciesMeta: + postcss: + optional: true + ts-node: + optional: true + postcss-load-config@6.0.1: - resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} - engines: {node: '>= 18'} + resolution: + { + integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==, + } + engines: { node: '>= 18' } peerDependencies: jiti: '>=1.21.0' postcss: '>=8.0.9' @@ -3060,178 +5000,514 @@ packages: optional: true postcss-nested@6.2.0: - resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==} - engines: {node: '>=12.0'} + resolution: + { + integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==, + } + engines: { node: '>=12.0' } peerDependencies: postcss: ^8.2.14 postcss-selector-parser@6.0.10: - resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==} - engines: {node: '>=4'} + resolution: + { + integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==, + } + engines: { node: '>=4' } postcss-selector-parser@6.1.2: - resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} - engines: {node: '>=4'} + resolution: + { + integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==, + } + engines: { node: '>=4' } - postcss-selector-parser@7.1.4: - resolution: {integrity: sha512-HeP7D2wyhkR+XaK6v4W8oRF62Dsz4flyuczALJp61GckGm42u1saSSJ/0auvcBqxs3jMRFEcPK34At/0JBKdOg==} - engines: {node: '>=4'} + postcss-selector-parser@7.0.0: + resolution: + { + integrity: sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ==, + } + engines: { node: '>=4' } postcss-value-parser@4.2.0: - resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + resolution: + { + integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==, + } postcss@8.4.31: - resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} - engines: {node: ^10 || ^12 || >=14} + resolution: + { + integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==, + } + engines: { node: ^10 || ^12 || >=14 } - postcss@8.5.16: - resolution: {integrity: sha512-vuwillviilfKZsg0VGj5R/YwwcHx4SLsIOI/7K6mQkWx+l5cUHTjj5g0AasTBcyXsbfTgrwsUNmVUb5xVwyPwg==} - engines: {node: ^10 || ^12 || >=14} + postcss@8.4.41: + resolution: + { + integrity: sha512-TesUflQ0WKZqAvg52PWL6kHgLKP6xB6heTOdoYM0Wt2UHyxNa4K25EZZMgKns3BH1RLVbZCREPpLY0rhnNoHVQ==, + } + engines: { node: ^10 || ^12 || >=14 } - postcss@8.5.25: - resolution: {integrity: sha512-DTPx3RWSSnWyzLxQnlH0rJP+EW5ekl16ZU4/psbIhA0e53kJfdgaN5vKM+xP7yJtXVu+nfdVFmlgFDEKAe4Pyw==} - engines: {node: ^10 || ^12 || >=14} + postcss@8.4.47: + resolution: + { + integrity: sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==, + } + engines: { node: ^10 || ^12 || >=14 } - prettier-plugin-embed@0.5.1: - resolution: {integrity: sha512-2Ege8gIlLNTvHElUeU5XcFsD7/dbDXkQA6H9TczHSJAGxB58nNjjifk/dlRMS5E29eqQx/z+ToA4ZVMWzjME/A==} + postcss@8.4.49: + resolution: + { + integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==, + } + engines: { node: ^10 || ^12 || >=14 } - prettier-plugin-organize-imports@4.3.0: - resolution: {integrity: sha512-FxFz0qFhyBsGdIsb697f/EkvHzi5SZOhWAjxcx2dLt+Q532bAlhswcXGYB1yzjZ69kW8UoadFBw7TyNwlq96Iw==} + prelude-ls@1.2.1: + resolution: + { + integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==, + } + engines: { node: '>= 0.8.0' } + + prettier-plugin-embed@0.4.15: + resolution: + { + integrity: sha512-9pZVIp3bw2jw+Ge+iAMZ4j+sIVC9cPruZ93H2tj5Wa/3YDFDJ/uYyVWdUGfcFUnv28drhW2Bmome9xSGXsPKOw==, + } + + prettier-plugin-organize-imports@4.0.0: + resolution: + { + integrity: sha512-vnKSdgv9aOlqKeEFGhf9SCBsTyzDSyScy1k7E0R1Uo4L0cTcOV7c1XQaT7jfXIOc/p08WLBfN2QUQA9zDSZMxA==, + } peerDependencies: + '@vue/language-plugin-pug': ^2.0.24 prettier: '>=2.0' typescript: '>=2.9' - vue-tsc: ^2.1.0 || 3 + vue-tsc: ^2.0.24 peerDependenciesMeta: + '@vue/language-plugin-pug': + optional: true vue-tsc: optional: true - prettier@3.9.6: - resolution: {integrity: sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g==} - engines: {node: '>=14'} + prettier@3.3.3: + resolution: + { + integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==, + } + engines: { node: '>=14' } hasBin: true + prop-types@15.8.1: + resolution: + { + integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==, + } + + punycode@2.3.1: + resolution: + { + integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==, + } + engines: { node: '>=6' } + queue-microtask@1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + resolution: + { + integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==, + } - radix3@1.1.2: - resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==} - - react-dom@19.2.6: - resolution: {integrity: sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==} + react-dom@18.3.1: + resolution: + { + integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==, + } peerDependencies: - react: ^19.2.6 + react: ^18.3.1 - react-dom@19.2.7: - resolution: {integrity: sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==} - peerDependencies: - react: ^19.2.7 + react-is@16.13.1: + resolution: + { + integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==, + } - react@19.2.6: - resolution: {integrity: sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==} - engines: {node: '>=0.10.0'} + react-refresh@0.14.2: + resolution: + { + integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==, + } + engines: { node: '>=0.10.0' } - react@19.2.7: - resolution: {integrity: sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==} - engines: {node: '>=0.10.0'} + react@18.3.1: + resolution: + { + integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==, + } + engines: { node: '>=0.10.0' } read-cache@1.0.0: - resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} + resolution: + { + integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==, + } readdirp@3.6.0: - resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} - engines: {node: '>=8.10.0'} + resolution: + { + integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==, + } + engines: { node: '>=8.10.0' } - readdirp@4.1.2: - resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} - engines: {node: '>= 14.18.0'} + reflect.getprototypeof@1.0.6: + resolution: + { + integrity: sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==, + } + engines: { node: '>= 0.4' } - require-from-string@2.0.2: - resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} - engines: {node: '>=0.10.0'} + regexp.prototype.flags@1.5.2: + resolution: + { + integrity: sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==, + } + engines: { node: '>= 0.4' } + + resolve-from@4.0.0: + resolution: + { + integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==, + } + engines: { node: '>=4' } resolve-from@5.0.0: - resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==, + } + engines: { node: '>=8' } - resolve@1.22.12: - resolution: {integrity: sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==} - engines: {node: '>= 0.4'} + resolve-pkg-maps@1.0.0: + resolution: + { + integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==, + } + + resolve@1.22.8: + resolution: + { + integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==, + } hasBin: true - reusify@1.1.0: - resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - - rolldown@1.2.1: - resolution: {integrity: sha512-4FKJhg8d3OiyQOA6Q1Q0hoFFpW9/OoX+VsHzpECsdsIZoOArrAK90gl59YK/Z+gnDel45bgJZK03ozH/9bCqEw==} - engines: {node: ^20.19.0 || >=22.12.0} + resolve@2.0.0-next.5: + resolution: + { + integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==, + } hasBin: true - rollup@4.60.4: - resolution: {integrity: sha512-WHeFSbZYsPu3+bLoNRUuAO+wavNlocOPf3wSHTP7hcFKVnJeWsYlCDbr3mTS14FCizf9ccIxXA8sGL8zKeQN3g==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} + reusify@1.0.4: + resolution: + { + integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==, + } + engines: { iojs: '>=1.0.0', node: '>=0.10.0' } + + rollup@4.20.0: + resolution: + { + integrity: sha512-6rbWBChcnSGzIlXeIdNIZTopKYad8ZG8ajhl78lGRLsI2rX8IkaotQhVas2Ma+GPxJav19wrSzvRvuiv0YKzWw==, + } + engines: { node: '>=18.0.0', npm: '>=8.0.0' } + hasBin: true + + rollup@4.27.4: + resolution: + { + integrity: sha512-RLKxqHEMjh/RGLsDxAEsaLO3mWgyoU6x9w6n1ikAzet4B3gI2/3yP6PWY2p9QzRTh6MfEIXB3MwsOY0Iv3vNrw==, + } + engines: { node: '>=18.0.0', npm: '>=8.0.0' } hasBin: true run-parallel@1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + resolution: + { + integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==, + } - safer-buffer@2.1.2: - resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + safe-array-concat@1.1.2: + resolution: + { + integrity: sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==, + } + engines: { node: '>=0.4' } - scheduler@0.27.0: - resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + safe-regex-test@1.0.3: + resolution: + { + integrity: sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==, + } + engines: { node: '>= 0.4' } - schema-utils@4.3.3: - resolution: {integrity: sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==} - engines: {node: '>= 10.13.0'} + scheduler@0.23.2: + resolution: + { + integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==, + } - semver@7.8.5: - resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} - engines: {node: '>=10'} + semver@6.3.1: + resolution: + { + integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==, + } hasBin: true - sharp@0.34.5: - resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + semver@7.6.3: + resolution: + { + integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==, + } + engines: { node: '>=10' } + hasBin: true + + set-function-length@1.2.2: + resolution: + { + integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==, + } + engines: { node: '>= 0.4' } + + set-function-name@2.0.2: + resolution: + { + integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==, + } + engines: { node: '>= 0.4' } + + sharp@0.33.5: + resolution: + { + integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==, + } + engines: { node: ^18.17.0 || ^20.3.0 || >=21.0.0 } + + shebang-command@2.0.0: + resolution: + { + integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==, + } + engines: { node: '>=8' } + + shebang-regex@3.0.0: + resolution: + { + integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==, + } + engines: { node: '>=8' } + + side-channel@1.0.6: + resolution: + { + integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==, + } + engines: { node: '>= 0.4' } siginfo@2.0.0: - resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + resolution: + { + integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==, + } + + signal-exit@3.0.7: + resolution: + { + integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==, + } signal-exit@4.1.0: - resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} - engines: {node: '>=14'} + resolution: + { + integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==, + } + engines: { node: '>=14' } + + simple-swizzle@0.2.2: + resolution: + { + integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==, + } + + slash@3.0.0: + resolution: + { + integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==, + } + engines: { node: '>=8' } slash@5.1.0: - resolution: {integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==} - engines: {node: '>=14.16'} + resolution: + { + integrity: sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==, + } + engines: { node: '>=14.16' } + + source-map-js@1.2.0: + resolution: + { + integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==, + } + engines: { node: '>=0.10.0' } source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} - engines: {node: '>=0.10.0'} + resolution: + { + integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==, + } + engines: { node: '>=0.10.0' } source-map-support@0.5.21: - resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + resolution: + { + integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==, + } source-map@0.6.1: - resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} - engines: {node: '>=0.10.0'} + resolution: + { + integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==, + } + engines: { node: '>=0.10.0' } - source-map@0.7.6: - resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} - engines: {node: '>= 12'} + source-map@0.8.0-beta.0: + resolution: + { + integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==, + } + engines: { node: '>= 8' } stackback@0.0.2: - resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + resolution: + { + integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==, + } - std-env@4.1.0: - resolution: {integrity: sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==} + std-env@3.7.0: + resolution: + { + integrity: sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==, + } - std-env@4.2.0: - resolution: {integrity: sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==} + streamsearch@1.1.0: + resolution: + { + integrity: sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==, + } + engines: { node: '>=10.0.0' } + + string-width@4.2.3: + resolution: + { + integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==, + } + engines: { node: '>=8' } + + string-width@5.1.2: + resolution: + { + integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==, + } + engines: { node: '>=12' } + + string.prototype.includes@2.0.1: + resolution: + { + integrity: sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==, + } + engines: { node: '>= 0.4' } + + string.prototype.matchall@4.0.11: + resolution: + { + integrity: sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==, + } + engines: { node: '>= 0.4' } + + string.prototype.repeat@1.0.0: + resolution: + { + integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==, + } + + string.prototype.trim@1.2.9: + resolution: + { + integrity: sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==, + } + engines: { node: '>= 0.4' } + + string.prototype.trimend@1.0.8: + resolution: + { + integrity: sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==, + } + + string.prototype.trimstart@1.0.8: + resolution: + { + integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==, + } + engines: { node: '>= 0.4' } + + strip-ansi@6.0.1: + resolution: + { + integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==, + } + engines: { node: '>=8' } + + strip-ansi@7.1.0: + resolution: + { + integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==, + } + engines: { node: '>=12' } + + strip-bom@3.0.0: + resolution: + { + integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==, + } + engines: { node: '>=4' } + + strip-final-newline@2.0.0: + resolution: + { + integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==, + } + engines: { node: '>=6' } + + strip-final-newline@3.0.0: + resolution: + { + integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==, + } + engines: { node: '>=12' } + + strip-json-comments@3.1.1: + resolution: + { + integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==, + } + engines: { node: '>=8' } styled-jsx@5.1.6: - resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} - engines: {node: '>= 12.0.0'} + resolution: + { + integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==, + } + engines: { node: '>= 12.0.0' } peerDependencies: '@babel/core': '*' babel-plugin-macros: '*' @@ -3242,83 +5518,136 @@ packages: babel-plugin-macros: optional: true - sucrase@3.35.1: - resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==} - engines: {node: '>=16 || 14 >=14.17'} + sucrase@3.35.0: + resolution: + { + integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==, + } + engines: { node: '>=16 || 14 >=14.17' } hasBin: true - supports-color@8.1.1: - resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} - engines: {node: '>=10'} + supports-color@5.5.0: + resolution: + { + integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==, + } + engines: { node: '>=4' } + + supports-color@7.2.0: + resolution: + { + integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==, + } + engines: { node: '>=8' } supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} + resolution: + { + integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==, + } + engines: { node: '>= 0.4' } - tagged-tag@1.0.0: - resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==} - engines: {node: '>=20'} - - tailwindcss@3.4.19: - resolution: {integrity: sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==} - engines: {node: '>=14.0.0'} + tailwindcss@3.4.14: + resolution: + { + integrity: sha512-IcSvOcTRcUtQQ7ILQL5quRDg7Xs93PdJEk1ZLbhhvJc7uj/OAhYOnruEiwnGgBvUtaUAJ8/mhSw1o8L2jCiENA==, + } + engines: { node: '>=14.0.0' } hasBin: true - tapable@2.3.3: - resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} - engines: {node: '>=6'} + tapable@2.2.1: + resolution: + { + integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==, + } + engines: { node: '>=6' } - terser@5.48.0: - resolution: {integrity: sha512-J/9An6vs9Us6wKRriSFXBWdRZapREHqFzdNUKk0pmu804EMR6dr6winwo7e5JDxN4xahxQsuysyYFwlwj4XN/Q==} - engines: {node: '>=10'} + terser@5.31.6: + resolution: + { + integrity: sha512-PQ4DAriWzKj+qgehQ7LK5bQqCFNMmlhjR2PFFLuqGCpuCAauxemVBWwWOxo3UIwWQx8+Pr61Df++r76wDmkQBg==, + } + engines: { node: '>=10' } hasBin: true thenify-all@1.6.0: - resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} - engines: {node: '>=0.8'} + resolution: + { + integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==, + } + engines: { node: '>=0.8' } thenify@3.3.1: - resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + resolution: + { + integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==, + } - tiny-jsonc@1.0.2: - resolution: {integrity: sha512-f5QDAfLq6zIVSyCZQZhhyl0QS6MvAyTxgz4X4x3+EoCktNWEYJ6PeoEA97fyb98njpBNNi88ybpD7m+BDFXaCw==} + tiny-jsonc@1.0.1: + resolution: + { + integrity: sha512-ik6BCxzva9DoiEfDX/li0L2cWKPPENYvixUprFdl3YPi4bZZUhDnNI9YUkacrv+uIG90dnxR5mNqaoD6UhD6Bw==, + } tinybench@2.9.0: - resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + resolution: + { + integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==, + } - tinyclip@0.1.15: - resolution: {integrity: sha512-uo33abH+Ays0xYaDysoBt494Hb3hsEczMpcC0MwFl773pazORx4fmvKhclhR1wonUbB6vvpRsvVMwnhfqeMc+A==} - engines: {node: ^16.14.0 || >= 17.3.0} + tinypool@1.0.0: + resolution: + { + integrity: sha512-KIKExllK7jp3uvrNtvRBYBWBOAXSX8ZvoaD8T+7KB/QHIuoJW3Pmr60zucywjAlMb5TeXUkcs/MWeWLu0qvuAQ==, + } + engines: { node: ^18.0.0 || >=20.0.0 } - tinyexec@0.3.2: - resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + tinyrainbow@1.2.0: + resolution: + { + integrity: sha512-weEDEq7Z5eTHPDh4xjX789+fHfF+P8boiFB+0vbWzpbnbsEr/GRaohi/uMKxg8RZMXnl1ItAi/IUHWMsjDV7kQ==, + } + engines: { node: '>=14.0.0' } - tinyexec@1.1.2: - resolution: {integrity: sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA==} - engines: {node: '>=18'} + tinyspy@3.0.0: + resolution: + { + integrity: sha512-q5nmENpTHgiPVd1cJDDc9cVoYN5x4vCvwT3FMilvKPKneCBZAxn2YWQjDF0UMcE9k0Cay1gBiDfTMU0g+mPMQA==, + } + engines: { node: '>=14.0.0' } - tinyglobby@0.2.16: - resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} - engines: {node: '>=12.0.0'} - - tinyglobby@0.2.17: - resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} - engines: {node: '>=12.0.0'} - - tinyrainbow@3.1.0: - resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} - engines: {node: '>=14.0.0'} + to-fast-properties@2.0.0: + resolution: + { + integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==, + } + engines: { node: '>=4' } to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} + resolution: + { + integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==, + } + engines: { node: '>=8.0' } + + tr46@1.0.1: + resolution: + { + integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==, + } tree-kill@1.2.2: - resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + resolution: + { + integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==, + } hasBin: true tree-sitter-javascript@0.23.1: - resolution: {integrity: sha512-/bnhbrTD9frUYHQTiYnPcxyHORIw157ERBa6dqzaKxvR/x3PC4Yzd+D1pZIMS6zNg2v3a8BZ0oK7jHqsQo9fWA==} + resolution: + { + integrity: sha512-/bnhbrTD9frUYHQTiYnPcxyHORIw157ERBa6dqzaKxvR/x3PC4Yzd+D1pZIMS6zNg2v3a8BZ0oK7jHqsQo9fWA==, + } peerDependencies: tree-sitter: ^0.21.1 peerDependenciesMeta: @@ -3326,25 +5655,55 @@ packages: optional: true tree-sitter-typescript@0.23.2: - resolution: {integrity: sha512-e04JUUKxTT53/x3Uq1zIL45DoYKVfHH4CZqwgZhPg5qYROl5nQjV+85ruFzFGZxu+QeFVbRTPDRnqL9UbU4VeA==} + resolution: + { + integrity: sha512-e04JUUKxTT53/x3Uq1zIL45DoYKVfHH4CZqwgZhPg5qYROl5nQjV+85ruFzFGZxu+QeFVbRTPDRnqL9UbU4VeA==, + } peerDependencies: tree-sitter: ^0.21.0 peerDependenciesMeta: tree-sitter: optional: true - tree-sitter@0.25.1: - resolution: {integrity: sha512-mrcEdkYtHfrK1A6fs3O6FxkBo0Qig5XUXqHhxUOQu0bmPo00QF4XaSx4edpazdHwxnSCjlGKGgIqWdaN4dvTLA==} + tree-sitter@0.22.1: + resolution: + { + integrity: sha512-gRO+jk2ljxZlIn20QRskIvpLCMtzuLl5T0BY6L9uvPYD17uUrxlxWkvYCiVqED2q2q7CVtY52Uex4WcYo2FEXw==, + } + + ts-api-utils@1.3.0: + resolution: + { + integrity: sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==, + } + engines: { node: '>=16' } + peerDependencies: + typescript: '>=4.2.0' ts-interface-checker@0.1.13: - resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + resolution: + { + integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==, + } - tslib@2.8.1: - resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tsconfig-paths@3.15.0: + resolution: + { + integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==, + } - tsup@8.5.1: - resolution: {integrity: sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing==} - engines: {node: '>=18'} + tslib@2.8.0: + resolution: + { + integrity: sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==, + } + + tsup@8.2.4: + resolution: + { + integrity: sha512-akpCPePnBnC/CXgRrcy72ZSntgIEUa1jN0oJbbvpALWKNOz1B7aM+UVDWGRGIO/T/PZugAESWDJUAb5FD48o8Q==, + } + engines: { node: '>=18' } hasBin: true peerDependencies: '@microsoft/api-extractor': ^7.36.0 @@ -3361,90 +5720,246 @@ packages: typescript: optional: true - turbo@2.10.8: - resolution: {integrity: sha512-9+8YX5QOkGXzZxcIykTHgaooRHGMWO+jfdyRK0o+rN0U7hBIig2MrJ8r/aNzIPDPhdA73SGb0O+tIztaModTMg==} + tsx@4.19.1: + resolution: + { + integrity: sha512-0flMz1lh74BR4wOvBjuh9olbnwqCPc35OOlfyzHba0Dc+QNUeWX/Gq2YTbnwcWPO3BMd8fkzRVrHcsR+a7z7rA==, + } + engines: { node: '>=18.0.0' } hasBin: true - typanion@3.14.0: - resolution: {integrity: sha512-ZW/lVMRabETuYCd9O9ZvMhAh8GslSqaUjxmK/JLPCh6l73CvLBiuXswj/+7LdnWOgYsQ130FqLzFz5aGT4I3Ug==} + turbo-darwin-64@2.2.3: + resolution: + { + integrity: sha512-Rcm10CuMKQGcdIBS3R/9PMeuYnv6beYIHqfZFeKWVYEWH69sauj4INs83zKMTUiZJ3/hWGZ4jet9AOwhsssLyg==, + } + cpu: [x64] + os: [darwin] - type-fest@5.6.0: - resolution: {integrity: sha512-8ZiHFm91orbSAe2PSAiSVBVko18pbhbiB3U9GglSzF/zCGkR+rxpHx6sEMCUm4kxY4LjDIUGgCfUMtwfZfjfUA==} - engines: {node: '>=20'} + turbo-darwin-arm64@2.2.3: + resolution: + { + integrity: sha512-+EIMHkuLFqUdJYsA3roj66t9+9IciCajgj+DVek+QezEdOJKcRxlvDOS2BUaeN8kEzVSsNiAGnoysFWYw4K0HA==, + } + cpu: [arm64] + os: [darwin] - typescript@5.9.3: - resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} - engines: {node: '>=14.17'} + turbo-linux-64@2.2.3: + resolution: + { + integrity: sha512-UBhJCYnqtaeOBQLmLo8BAisWbc9v9daL9G8upLR+XGj6vuN/Nz6qUAhverN4Pyej1g4Nt1BhROnj6GLOPYyqxQ==, + } + cpu: [x64] + os: [linux] + + turbo-linux-arm64@2.2.3: + resolution: + { + integrity: sha512-hJYT9dN06XCQ3jBka/EWvvAETnHRs3xuO/rb5bESmDfG+d9yQjeTMlhRXKrr4eyIMt6cLDt1LBfyi+6CQ+VAwQ==, + } + cpu: [arm64] + os: [linux] + + turbo-windows-64@2.2.3: + resolution: + { + integrity: sha512-NPrjacrZypMBF31b4HE4ROg4P3nhMBPHKS5WTpMwf7wydZ8uvdEHpESVNMOtqhlp857zbnKYgP+yJF30H3N2dQ==, + } + cpu: [x64] + os: [win32] + + turbo-windows-arm64@2.2.3: + resolution: + { + integrity: sha512-fnNrYBCqn6zgKPKLHu4sOkihBI/+0oYFr075duRxqUZ+1aLWTAGfHZLgjVeLh3zR37CVzuerGIPWAEkNhkWEIw==, + } + cpu: [arm64] + os: [win32] + + turbo@2.2.3: + resolution: + { + integrity: sha512-5lDvSqIxCYJ/BAd6rQGK/AzFRhBkbu4JHVMLmGh/hCb7U3CqSnr5Tjwfy9vc+/5wG2DJ6wttgAaA7MoCgvBKZQ==, + } hasBin: true - typescript@6.0.3: - resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} - engines: {node: '>=14.17'} + type-check@0.4.0: + resolution: + { + integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==, + } + engines: { node: '>= 0.8.0' } + + type-fest@4.24.0: + resolution: + { + integrity: sha512-spAaHzc6qre0TlZQQ2aA/nGMe+2Z/wyGk5Z+Ru2VUfdNwT6kWO6TjevOlpebsATEG1EIQ2sOiDszud3lO5mt/Q==, + } + engines: { node: '>=16' } + + typed-array-buffer@1.0.2: + resolution: + { + integrity: sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==, + } + engines: { node: '>= 0.4' } + + typed-array-byte-length@1.0.1: + resolution: + { + integrity: sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==, + } + engines: { node: '>= 0.4' } + + typed-array-byte-offset@1.0.2: + resolution: + { + integrity: sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==, + } + engines: { node: '>= 0.4' } + + typed-array-length@1.0.6: + resolution: + { + integrity: sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==, + } + engines: { node: '>= 0.4' } + + typescript@5.5.4: + resolution: + { + integrity: sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==, + } + engines: { node: '>=14.17' } hasBin: true - ufo@1.6.4: - resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==} - - uncrypto@0.1.3: - resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} - - undici-types@6.21.0: - resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - - undici-types@7.24.6: - resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==} - - unicorn-magic@0.4.0: - resolution: {integrity: sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw==} - engines: {node: '>=20'} - - universal-user-agent@7.0.3: - resolution: {integrity: sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==} - - untun@0.2.2: - resolution: {integrity: sha512-+NnOJcSiEtYsVgJmXUzQbJeRAFXJC4yPJYuh6kF9B0Rm6zunXcs/3GZOTllyocSbUDIxD6Bj7e/4ATw7sph1Sw==} + typescript@5.6.3: + resolution: + { + integrity: sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==, + } + engines: { node: '>=14.17' } hasBin: true - update-browserslist-db@1.2.3: - resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + unbox-primitive@1.0.2: + resolution: + { + integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==, + } + + undici-types@5.26.5: + resolution: + { + integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==, + } + + unicorn-magic@0.1.0: + resolution: + { + integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==, + } + engines: { node: '>=18' } + + update-browserslist-db@1.1.0: + resolution: + { + integrity: sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==, + } hasBin: true peerDependencies: browserslist: '>= 4.21.0' - uqr@0.1.3: - resolution: {integrity: sha512-0rjE8iEJe4YmT9TOhwsZtqCMRLc5DXZUI2UEYUUg63ikBkqqE5EYWaI0etFe/5KUcmcYwLih2RND1kq+hrUJXA==} - - util-deprecate@1.0.2: - resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - - vite@8.2.0: - resolution: {integrity: sha512-pn+CFpM0lwDeKwmOq1ZaBK/9sjorZcgqxki6MbY/jPEVd9vichIlmlD4HmQ5wdP5EgqQCFRaACBxMC7uEGc6lQ==} - engines: {node: ^20.19.0 || >=22.12.0} + update-browserslist-db@1.1.1: + resolution: + { + integrity: sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==, + } hasBin: true peerDependencies: - '@types/node': ^20.19.0 || >=22.12.0 - '@vitejs/devtools': ^0.4.0 - esbuild: ^0.27.0 || ^0.28.0 + browserslist: '>= 4.21.0' + + uri-js@4.4.1: + resolution: + { + integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==, + } + + util-deprecate@1.0.2: + resolution: + { + integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==, + } + + vite-node@2.0.5: + resolution: + { + integrity: sha512-LdsW4pxj0Ot69FAoXZ1yTnA9bjGohr2yNBU7QKRxpz8ITSkhuDl6h3zS/tvgz4qrNjeRnvrWeXQ8ZF7Um4W00Q==, + } + engines: { node: ^18.0.0 || >=20.0.0 } + hasBin: true + + vite@5.4.0: + resolution: + { + integrity: sha512-5xokfMX0PIiwCMCMb9ZJcMyh5wbBun0zUzKib+L65vAZ8GY9ePZMXxFrHbr/Kyll2+LSCY7xtERPpxkBDKngwg==, + } + engines: { node: ^18.0.0 || >=20.0.0 } + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || >=20.0.0 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + + vite@6.0.0: + resolution: + { + integrity: sha512-Q2+5yQV79EdnpbNxjD3/QHVMCBaQ3Kpd4/uL51UGuh38bIIM+s4o3FqyCzRvTRwFb+cWIUeZvaWwS9y2LD2qeQ==, + } + engines: { node: ^18.0.0 || ^20.0.0 || >=22.0.0 } + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 jiti: '>=1.21.0' - less: ^4.0.0 - sass: ^1.70.0 - sass-embedded: ^1.70.0 - stylus: '>=0.54.8' - sugarss: ^5.0.0 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' terser: ^5.16.0 tsx: ^4.8.1 yaml: ^2.4.2 peerDependenciesMeta: '@types/node': optional: true - '@vitejs/devtools': - optional: true - esbuild: - optional: true jiti: optional: true less: optional: true + lightningcss: + optional: true sass: optional: true sass-embedded: @@ -3460,39 +5975,26 @@ packages: yaml: optional: true - vitest@4.1.10: - resolution: {integrity: sha512-R9jUTe5S4Qb0HCd4TNqpC7oGcrMssMRGXLW80ubjWsW9VH5GF8y1Y0SFLY9AbqSk6nt0PnOx4H4WNJYZ13GUPw==} - engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} + vitest@2.0.5: + resolution: + { + integrity: sha512-8GUxONfauuIdeSl5f9GTgVEpg5BTOlplET4WEDaeY2QBiN8wSm68vxN/tb5z405OwppfoCavnwXafiaYBC/xOA==, + } + engines: { node: ^18.0.0 || >=20.0.0 } hasBin: true peerDependencies: '@edge-runtime/vm': '*' - '@opentelemetry/api': ^1.9.0 - '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.1.10 - '@vitest/browser-preview': 4.1.10 - '@vitest/browser-webdriverio': 4.1.10 - '@vitest/coverage-istanbul': 4.1.10 - '@vitest/coverage-v8': 4.1.10 - '@vitest/ui': 4.1.10 + '@types/node': ^18.0.0 || >=20.0.0 + '@vitest/browser': 2.0.5 + '@vitest/ui': 2.0.5 happy-dom: '*' jsdom: '*' - vite: ^6.0.0 || ^7.0.0 || ^8.0.0 peerDependenciesMeta: '@edge-runtime/vm': optional: true - '@opentelemetry/api': - optional: true '@types/node': optional: true - '@vitest/browser-playwright': - optional: true - '@vitest/browser-preview': - optional: true - '@vitest/browser-webdriverio': - optional: true - '@vitest/coverage-istanbul': - optional: true - '@vitest/coverage-v8': + '@vitest/browser': optional: true '@vitest/ui': optional: true @@ -3501,704 +6003,716 @@ packages: jsdom: optional: true - watchpack@2.5.2: - resolution: {integrity: sha512-6i/00NBjP4yGPs+caKSyRfpTF/8Torsu0MOW3mMzIbhgISFder8i7xbqgHlLMwJrdiN8ndBV3UA1/AfzPSr+jg==} - engines: {node: '>=10.13.0'} + webidl-conversions@4.0.2: + resolution: + { + integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==, + } - webpack-sources@3.5.1: - resolution: {integrity: sha512-jyuiGJdtvY434z5bUZrjz67v76/ePNvFZTp9Mdz29IlH4+GPsgyGjiv0fKI+M7BdkU6ADjulUcKAd3tUK3WlEw==} - engines: {node: '>=10.13.0'} + whatwg-url@7.1.0: + resolution: + { + integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==, + } - webpack@5.109.2: - resolution: {integrity: sha512-U9/cvLzxObKNEZ9+TtdqrHM5/9z3lgl2c+c4BzbqGxFQvQvBAq87yql5A8pQ+rrMbS496MZJeF5enVBndIy2hw==} - engines: {node: '>=10.13.0'} + which-boxed-primitive@1.0.2: + resolution: + { + integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==, + } + + which-builtin-type@1.1.4: + resolution: + { + integrity: sha512-bppkmBSsHFmIMSl8BO9TbsyzsvGjVoppt8xUiGzwiu/bhDCGxnpOKCxgqj6GuyHE0mINMDecBFPlOm2hzY084w==, + } + engines: { node: '>= 0.4' } + + which-collection@1.0.2: + resolution: + { + integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==, + } + engines: { node: '>= 0.4' } + + which-typed-array@1.1.15: + resolution: + { + integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==, + } + engines: { node: '>= 0.4' } + + which@2.0.2: + resolution: + { + integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==, + } + engines: { node: '>= 8' } hasBin: true - peerDependencies: - webpack-cli: '*' - peerDependenciesMeta: - webpack-cli: - optional: true why-is-node-running@2.3.0: - resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} - engines: {node: '>=8'} + resolution: + { + integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==, + } + engines: { node: '>=8' } hasBin: true - yaml@2.9.0: - resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==} - engines: {node: '>= 14.6'} + word-wrap@1.2.5: + resolution: + { + integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==, + } + engines: { node: '>=0.10.0' } + + wrap-ansi@7.0.0: + resolution: + { + integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==, + } + engines: { node: '>=10' } + + wrap-ansi@8.1.0: + resolution: + { + integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==, + } + engines: { node: '>=12' } + + yallist@3.1.1: + resolution: + { + integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==, + } + + yaml@2.6.0: + resolution: + { + integrity: sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ==, + } + engines: { node: '>= 14' } hasBin: true + yocto-queue@0.1.0: + resolution: + { + integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==, + } + engines: { node: '>=10' } + snapshots: - '@alloc/quick-lru@5.2.0': {} - '@emnapi/core@1.10.0': + '@ampproject/remapping@2.3.0': dependencies: - '@emnapi/wasi-threads': 1.2.1 - tslib: 2.8.1 - optional: true + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 - '@emnapi/core@1.11.3': + '@babel/code-frame@7.24.7': dependencies: - '@emnapi/wasi-threads': 1.2.3 - tslib: 2.8.1 + '@babel/highlight': 7.24.7 + picocolors: 1.1.1 - '@emnapi/core@2.0.0-alpha.3': + '@babel/compat-data@7.25.2': {} + + '@babel/core@7.25.2': dependencies: - '@emnapi/wasi-threads': 2.0.1 - tslib: 2.8.1 - optional: true + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.24.7 + '@babel/generator': 7.25.0 + '@babel/helper-compilation-targets': 7.25.2 + '@babel/helper-module-transforms': 7.25.2(@babel/core@7.25.2) + '@babel/helpers': 7.25.0 + '@babel/parser': 7.25.3 + '@babel/template': 7.25.0 + '@babel/traverse': 7.25.3 + '@babel/types': 7.25.2 + convert-source-map: 2.0.0 + debug: 4.3.7 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color - '@emnapi/runtime@1.10.0': + '@babel/generator@7.25.0': dependencies: - tslib: 2.8.1 - optional: true + '@babel/types': 7.25.2 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + jsesc: 2.5.2 - '@emnapi/runtime@1.11.3': + '@babel/helper-compilation-targets@7.25.2': dependencies: - tslib: 2.8.1 + '@babel/compat-data': 7.25.2 + '@babel/helper-validator-option': 7.24.8 + browserslist: 4.23.2 + lru-cache: 5.1.1 + semver: 6.3.1 - '@emnapi/runtime@2.0.0-alpha.3': + '@babel/helper-module-imports@7.24.7': dependencies: - tslib: 2.8.1 - optional: true + '@babel/traverse': 7.25.3 + '@babel/types': 7.25.2 + transitivePeerDependencies: + - supports-color - '@emnapi/wasi-threads@1.2.1': + '@babel/helper-module-transforms@7.25.2(@babel/core@7.25.2)': dependencies: - tslib: 2.8.1 - optional: true + '@babel/core': 7.25.2 + '@babel/helper-module-imports': 7.24.7 + '@babel/helper-simple-access': 7.24.7 + '@babel/helper-validator-identifier': 7.24.7 + '@babel/traverse': 7.25.3 + transitivePeerDependencies: + - supports-color - '@emnapi/wasi-threads@1.2.3': + '@babel/helper-plugin-utils@7.24.8': {} + + '@babel/helper-simple-access@7.24.7': dependencies: - tslib: 2.8.1 + '@babel/traverse': 7.25.3 + '@babel/types': 7.25.2 + transitivePeerDependencies: + - supports-color - '@emnapi/wasi-threads@2.0.1': + '@babel/helper-string-parser@7.24.8': {} + + '@babel/helper-validator-identifier@7.24.7': {} + + '@babel/helper-validator-option@7.24.8': {} + + '@babel/helpers@7.25.0': dependencies: - tslib: 2.8.1 + '@babel/template': 7.25.0 + '@babel/types': 7.25.2 + + '@babel/highlight@7.24.7': + dependencies: + '@babel/helper-validator-identifier': 7.24.7 + chalk: 2.4.2 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/parser@7.25.3': + dependencies: + '@babel/types': 7.25.2 + + '@babel/plugin-transform-react-jsx-self@7.24.7(@babel/core@7.25.2)': + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + + '@babel/plugin-transform-react-jsx-source@7.24.7(@babel/core@7.25.2)': + dependencies: + '@babel/core': 7.25.2 + '@babel/helper-plugin-utils': 7.24.8 + + '@babel/template@7.25.0': + dependencies: + '@babel/code-frame': 7.24.7 + '@babel/parser': 7.25.3 + '@babel/types': 7.25.2 + + '@babel/traverse@7.25.3': + dependencies: + '@babel/code-frame': 7.24.7 + '@babel/generator': 7.25.0 + '@babel/parser': 7.25.3 + '@babel/template': 7.25.0 + '@babel/types': 7.25.2 + debug: 4.3.7 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.25.2': + dependencies: + '@babel/helper-string-parser': 7.24.8 + '@babel/helper-validator-identifier': 7.24.7 + to-fast-properties: 2.0.0 + + '@emnapi/runtime@1.3.1': + dependencies: + tslib: 2.8.0 optional: true - '@esbuild/aix-ppc64@0.27.7': + '@esbuild/aix-ppc64@0.21.5': optional: true - '@esbuild/android-arm64@0.27.7': + '@esbuild/aix-ppc64@0.23.0': optional: true - '@esbuild/android-arm@0.27.7': + '@esbuild/aix-ppc64@0.23.1': optional: true - '@esbuild/android-x64@0.27.7': + '@esbuild/aix-ppc64@0.24.0': optional: true - '@esbuild/darwin-arm64@0.27.7': + '@esbuild/android-arm64@0.21.5': optional: true - '@esbuild/darwin-x64@0.27.7': + '@esbuild/android-arm64@0.23.0': optional: true - '@esbuild/freebsd-arm64@0.27.7': + '@esbuild/android-arm64@0.23.1': optional: true - '@esbuild/freebsd-x64@0.27.7': + '@esbuild/android-arm64@0.24.0': optional: true - '@esbuild/linux-arm64@0.27.7': + '@esbuild/android-arm@0.21.5': optional: true - '@esbuild/linux-arm@0.27.7': + '@esbuild/android-arm@0.23.0': optional: true - '@esbuild/linux-ia32@0.27.7': + '@esbuild/android-arm@0.23.1': optional: true - '@esbuild/linux-loong64@0.27.7': + '@esbuild/android-arm@0.24.0': optional: true - '@esbuild/linux-mips64el@0.27.7': + '@esbuild/android-x64@0.21.5': optional: true - '@esbuild/linux-ppc64@0.27.7': + '@esbuild/android-x64@0.23.0': optional: true - '@esbuild/linux-riscv64@0.27.7': + '@esbuild/android-x64@0.23.1': optional: true - '@esbuild/linux-s390x@0.27.7': + '@esbuild/android-x64@0.24.0': optional: true - '@esbuild/linux-x64@0.27.7': + '@esbuild/darwin-arm64@0.21.5': optional: true - '@esbuild/netbsd-arm64@0.27.7': + '@esbuild/darwin-arm64@0.23.0': optional: true - '@esbuild/netbsd-x64@0.27.7': + '@esbuild/darwin-arm64@0.23.1': optional: true - '@esbuild/openbsd-arm64@0.27.7': + '@esbuild/darwin-arm64@0.24.0': optional: true - '@esbuild/openbsd-x64@0.27.7': + '@esbuild/darwin-x64@0.21.5': optional: true - '@esbuild/openharmony-arm64@0.27.7': + '@esbuild/darwin-x64@0.23.0': optional: true - '@esbuild/sunos-x64@0.27.7': + '@esbuild/darwin-x64@0.23.1': optional: true - '@esbuild/win32-arm64@0.27.7': + '@esbuild/darwin-x64@0.24.0': optional: true - '@esbuild/win32-ia32@0.27.7': + '@esbuild/freebsd-arm64@0.21.5': optional: true - '@esbuild/win32-x64@0.27.7': + '@esbuild/freebsd-arm64@0.23.0': optional: true - '@img/colour@1.1.0': + '@esbuild/freebsd-arm64@0.23.1': optional: true - '@img/sharp-darwin-arm64@0.34.5': + '@esbuild/freebsd-arm64@0.24.0': + optional: true + + '@esbuild/freebsd-x64@0.21.5': + optional: true + + '@esbuild/freebsd-x64@0.23.0': + optional: true + + '@esbuild/freebsd-x64@0.23.1': + optional: true + + '@esbuild/freebsd-x64@0.24.0': + optional: true + + '@esbuild/linux-arm64@0.21.5': + optional: true + + '@esbuild/linux-arm64@0.23.0': + optional: true + + '@esbuild/linux-arm64@0.23.1': + optional: true + + '@esbuild/linux-arm64@0.24.0': + optional: true + + '@esbuild/linux-arm@0.21.5': + optional: true + + '@esbuild/linux-arm@0.23.0': + optional: true + + '@esbuild/linux-arm@0.23.1': + optional: true + + '@esbuild/linux-arm@0.24.0': + optional: true + + '@esbuild/linux-ia32@0.21.5': + optional: true + + '@esbuild/linux-ia32@0.23.0': + optional: true + + '@esbuild/linux-ia32@0.23.1': + optional: true + + '@esbuild/linux-ia32@0.24.0': + optional: true + + '@esbuild/linux-loong64@0.21.5': + optional: true + + '@esbuild/linux-loong64@0.23.0': + optional: true + + '@esbuild/linux-loong64@0.23.1': + optional: true + + '@esbuild/linux-loong64@0.24.0': + optional: true + + '@esbuild/linux-mips64el@0.21.5': + optional: true + + '@esbuild/linux-mips64el@0.23.0': + optional: true + + '@esbuild/linux-mips64el@0.23.1': + optional: true + + '@esbuild/linux-mips64el@0.24.0': + optional: true + + '@esbuild/linux-ppc64@0.21.5': + optional: true + + '@esbuild/linux-ppc64@0.23.0': + optional: true + + '@esbuild/linux-ppc64@0.23.1': + optional: true + + '@esbuild/linux-ppc64@0.24.0': + optional: true + + '@esbuild/linux-riscv64@0.21.5': + optional: true + + '@esbuild/linux-riscv64@0.23.0': + optional: true + + '@esbuild/linux-riscv64@0.23.1': + optional: true + + '@esbuild/linux-riscv64@0.24.0': + optional: true + + '@esbuild/linux-s390x@0.21.5': + optional: true + + '@esbuild/linux-s390x@0.23.0': + optional: true + + '@esbuild/linux-s390x@0.23.1': + optional: true + + '@esbuild/linux-s390x@0.24.0': + optional: true + + '@esbuild/linux-x64@0.21.5': + optional: true + + '@esbuild/linux-x64@0.23.0': + optional: true + + '@esbuild/linux-x64@0.23.1': + optional: true + + '@esbuild/linux-x64@0.24.0': + optional: true + + '@esbuild/netbsd-x64@0.21.5': + optional: true + + '@esbuild/netbsd-x64@0.23.0': + optional: true + + '@esbuild/netbsd-x64@0.23.1': + optional: true + + '@esbuild/netbsd-x64@0.24.0': + optional: true + + '@esbuild/openbsd-arm64@0.23.0': + optional: true + + '@esbuild/openbsd-arm64@0.23.1': + optional: true + + '@esbuild/openbsd-arm64@0.24.0': + optional: true + + '@esbuild/openbsd-x64@0.21.5': + optional: true + + '@esbuild/openbsd-x64@0.23.0': + optional: true + + '@esbuild/openbsd-x64@0.23.1': + optional: true + + '@esbuild/openbsd-x64@0.24.0': + optional: true + + '@esbuild/sunos-x64@0.21.5': + optional: true + + '@esbuild/sunos-x64@0.23.0': + optional: true + + '@esbuild/sunos-x64@0.23.1': + optional: true + + '@esbuild/sunos-x64@0.24.0': + optional: true + + '@esbuild/win32-arm64@0.21.5': + optional: true + + '@esbuild/win32-arm64@0.23.0': + optional: true + + '@esbuild/win32-arm64@0.23.1': + optional: true + + '@esbuild/win32-arm64@0.24.0': + optional: true + + '@esbuild/win32-ia32@0.21.5': + optional: true + + '@esbuild/win32-ia32@0.23.0': + optional: true + + '@esbuild/win32-ia32@0.23.1': + optional: true + + '@esbuild/win32-ia32@0.24.0': + optional: true + + '@esbuild/win32-x64@0.21.5': + optional: true + + '@esbuild/win32-x64@0.23.0': + optional: true + + '@esbuild/win32-x64@0.23.1': + optional: true + + '@esbuild/win32-x64@0.24.0': + optional: true + + '@eslint-community/eslint-utils@4.4.0(eslint@9.15.0(jiti@2.4.0))': + dependencies: + eslint: 9.15.0(jiti@2.4.0) + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.11.1': {} + + '@eslint-community/regexpp@4.12.1': {} + + '@eslint/config-array@0.19.0': + dependencies: + '@eslint/object-schema': 2.1.4 + debug: 4.3.7 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@eslint/core@0.9.0': {} + + '@eslint/eslintrc@3.2.0': + dependencies: + ajv: 6.12.6 + debug: 4.3.7 + espree: 10.3.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.0 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@9.15.0': {} + + '@eslint/object-schema@2.1.4': {} + + '@eslint/plugin-kit@0.2.3': + dependencies: + levn: 0.4.1 + + '@humanfs/core@0.19.1': {} + + '@humanfs/node@0.16.6': + dependencies: + '@humanfs/core': 0.19.1 + '@humanwhocodes/retry': 0.3.1 + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.3.1': {} + + '@humanwhocodes/retry@0.4.1': {} + + '@img/sharp-darwin-arm64@0.33.5': optionalDependencies: - '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-arm64': 1.0.4 optional: true - '@img/sharp-darwin-x64@0.34.5': + '@img/sharp-darwin-x64@0.33.5': optionalDependencies: - '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.0.4 optional: true - '@img/sharp-libvips-darwin-arm64@1.2.4': + '@img/sharp-libvips-darwin-arm64@1.0.4': optional: true - '@img/sharp-libvips-darwin-x64@1.2.4': + '@img/sharp-libvips-darwin-x64@1.0.4': optional: true - '@img/sharp-libvips-linux-arm64@1.2.4': + '@img/sharp-libvips-linux-arm64@1.0.4': optional: true - '@img/sharp-libvips-linux-arm@1.2.4': + '@img/sharp-libvips-linux-arm@1.0.5': optional: true - '@img/sharp-libvips-linux-ppc64@1.2.4': + '@img/sharp-libvips-linux-s390x@1.0.4': optional: true - '@img/sharp-libvips-linux-riscv64@1.2.4': + '@img/sharp-libvips-linux-x64@1.0.4': optional: true - '@img/sharp-libvips-linux-s390x@1.2.4': + '@img/sharp-libvips-linuxmusl-arm64@1.0.4': optional: true - '@img/sharp-libvips-linux-x64@1.2.4': + '@img/sharp-libvips-linuxmusl-x64@1.0.4': optional: true - '@img/sharp-libvips-linuxmusl-arm64@1.2.4': - optional: true - - '@img/sharp-libvips-linuxmusl-x64@1.2.4': - optional: true - - '@img/sharp-linux-arm64@0.34.5': + '@img/sharp-linux-arm64@0.33.5': optionalDependencies: - '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.0.4 optional: true - '@img/sharp-linux-arm@0.34.5': + '@img/sharp-linux-arm@0.33.5': optionalDependencies: - '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.0.5 optional: true - '@img/sharp-linux-ppc64@0.34.5': + '@img/sharp-linux-s390x@0.33.5': optionalDependencies: - '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.0.4 optional: true - '@img/sharp-linux-riscv64@0.34.5': + '@img/sharp-linux-x64@0.33.5': optionalDependencies: - '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.0.4 optional: true - '@img/sharp-linux-s390x@0.34.5': + '@img/sharp-linuxmusl-arm64@0.33.5': optionalDependencies: - '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 optional: true - '@img/sharp-linux-x64@0.34.5': + '@img/sharp-linuxmusl-x64@0.33.5': optionalDependencies: - '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.0.4 optional: true - '@img/sharp-linuxmusl-arm64@0.34.5': - optionalDependencies: - '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 - optional: true - - '@img/sharp-linuxmusl-x64@0.34.5': - optionalDependencies: - '@img/sharp-libvips-linuxmusl-x64': 1.2.4 - optional: true - - '@img/sharp-wasm32@0.34.5': + '@img/sharp-wasm32@0.33.5': dependencies: - '@emnapi/runtime': 1.11.3 + '@emnapi/runtime': 1.3.1 optional: true - '@img/sharp-win32-arm64@0.34.5': + '@img/sharp-win32-ia32@0.33.5': optional: true - '@img/sharp-win32-ia32@0.34.5': + '@img/sharp-win32-x64@0.33.5': optional: true - '@img/sharp-win32-x64@0.34.5': - optional: true - - '@inquirer/ansi@2.0.7': {} - - '@inquirer/checkbox@5.2.1(@types/node@25.9.1)': + '@isaacs/cliui@8.0.2': dependencies: - '@inquirer/ansi': 2.0.7 - '@inquirer/core': 11.2.1(@types/node@25.9.1) - '@inquirer/figures': 2.0.7 - '@inquirer/type': 4.0.7(@types/node@25.9.1) - optionalDependencies: - '@types/node': 25.9.1 + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 - '@inquirer/confirm@6.1.1(@types/node@25.9.1)': + '@jridgewell/gen-mapping@0.3.5': dependencies: - '@inquirer/core': 11.2.1(@types/node@25.9.1) - '@inquirer/type': 4.0.7(@types/node@25.9.1) - optionalDependencies: - '@types/node': 25.9.1 - - '@inquirer/core@11.2.1(@types/node@25.9.1)': - dependencies: - '@inquirer/ansi': 2.0.7 - '@inquirer/figures': 2.0.7 - '@inquirer/type': 4.0.7(@types/node@25.9.1) - cli-width: 4.1.0 - fast-wrap-ansi: 0.2.2 - mute-stream: 3.0.0 - signal-exit: 4.1.0 - optionalDependencies: - '@types/node': 25.9.1 - - '@inquirer/editor@5.2.2(@types/node@25.9.1)': - dependencies: - '@inquirer/core': 11.2.1(@types/node@25.9.1) - '@inquirer/external-editor': 3.0.3(@types/node@25.9.1) - '@inquirer/type': 4.0.7(@types/node@25.9.1) - optionalDependencies: - '@types/node': 25.9.1 - - '@inquirer/expand@5.1.1(@types/node@25.9.1)': - dependencies: - '@inquirer/core': 11.2.1(@types/node@25.9.1) - '@inquirer/type': 4.0.7(@types/node@25.9.1) - optionalDependencies: - '@types/node': 25.9.1 - - '@inquirer/external-editor@3.0.3(@types/node@25.9.1)': - dependencies: - chardet: 2.1.1 - iconv-lite: 0.7.2 - optionalDependencies: - '@types/node': 25.9.1 - - '@inquirer/figures@2.0.7': {} - - '@inquirer/input@5.1.2(@types/node@25.9.1)': - dependencies: - '@inquirer/core': 11.2.1(@types/node@25.9.1) - '@inquirer/type': 4.0.7(@types/node@25.9.1) - optionalDependencies: - '@types/node': 25.9.1 - - '@inquirer/number@4.1.1(@types/node@25.9.1)': - dependencies: - '@inquirer/core': 11.2.1(@types/node@25.9.1) - '@inquirer/type': 4.0.7(@types/node@25.9.1) - optionalDependencies: - '@types/node': 25.9.1 - - '@inquirer/password@5.1.1(@types/node@25.9.1)': - dependencies: - '@inquirer/ansi': 2.0.7 - '@inquirer/core': 11.2.1(@types/node@25.9.1) - '@inquirer/type': 4.0.7(@types/node@25.9.1) - optionalDependencies: - '@types/node': 25.9.1 - - '@inquirer/prompts@8.5.2(@types/node@25.9.1)': - dependencies: - '@inquirer/checkbox': 5.2.1(@types/node@25.9.1) - '@inquirer/confirm': 6.1.1(@types/node@25.9.1) - '@inquirer/editor': 5.2.2(@types/node@25.9.1) - '@inquirer/expand': 5.1.1(@types/node@25.9.1) - '@inquirer/input': 5.1.2(@types/node@25.9.1) - '@inquirer/number': 4.1.1(@types/node@25.9.1) - '@inquirer/password': 5.1.1(@types/node@25.9.1) - '@inquirer/rawlist': 5.3.1(@types/node@25.9.1) - '@inquirer/search': 4.2.1(@types/node@25.9.1) - '@inquirer/select': 5.2.1(@types/node@25.9.1) - optionalDependencies: - '@types/node': 25.9.1 - - '@inquirer/rawlist@5.3.1(@types/node@25.9.1)': - dependencies: - '@inquirer/core': 11.2.1(@types/node@25.9.1) - '@inquirer/type': 4.0.7(@types/node@25.9.1) - optionalDependencies: - '@types/node': 25.9.1 - - '@inquirer/search@4.2.1(@types/node@25.9.1)': - dependencies: - '@inquirer/core': 11.2.1(@types/node@25.9.1) - '@inquirer/figures': 2.0.7 - '@inquirer/type': 4.0.7(@types/node@25.9.1) - optionalDependencies: - '@types/node': 25.9.1 - - '@inquirer/select@5.2.1(@types/node@25.9.1)': - dependencies: - '@inquirer/ansi': 2.0.7 - '@inquirer/core': 11.2.1(@types/node@25.9.1) - '@inquirer/figures': 2.0.7 - '@inquirer/type': 4.0.7(@types/node@25.9.1) - optionalDependencies: - '@types/node': 25.9.1 - - '@inquirer/type@4.0.7(@types/node@25.9.1)': - optionalDependencies: - '@types/node': 25.9.1 - - '@jridgewell/gen-mapping@0.3.13': - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping': 0.3.31 - - '@jridgewell/remapping@2.3.5': - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/trace-mapping': 0.3.25 '@jridgewell/resolve-uri@3.1.2': {} - '@jridgewell/source-map@0.3.11': + '@jridgewell/set-array@1.2.1': {} + + '@jridgewell/source-map@0.3.6': dependencies: - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 + '@jridgewell/gen-mapping': 0.3.5 + '@jridgewell/trace-mapping': 0.3.25 + optional: true - '@jridgewell/sourcemap-codec@1.5.5': {} + '@jridgewell/sourcemap-codec@1.5.0': {} - '@jridgewell/trace-mapping@0.3.31': + '@jridgewell/trace-mapping@0.3.25': dependencies: '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/sourcemap-codec': 1.5.0 - '@napi-rs/cli@3.7.4(patch_hash=9912bf0a9c2cef8329d11c41fbce4d33ce2bdcf660a630b258c962c0a3c44bed)(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)(@types/node@25.9.1)(node-addon-api@8.7.0)': + '@napi-rs/cli@2.18.4': {} + + '@next/env@15.0.3': {} + + '@next/eslint-plugin-next@15.0.3': dependencies: - '@inquirer/prompts': 8.5.2(@types/node@25.9.1) - '@napi-rs/cross-toolchain': 1.0.3(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3) - '@napi-rs/wasm-tools': 1.0.1(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3) - '@octokit/rest': 22.0.1 - clipanion: 4.0.0-rc.4(typanion@3.14.0) - colorette: 2.0.20 - emnapi: 1.11.3(node-addon-api@8.7.0) - es-toolkit: 1.50.0 - js-yaml: 4.3.1 - obug: 2.1.4 - semver: 7.8.5 - typanion: 3.14.0 - optionalDependencies: - '@emnapi/runtime': 1.11.3 - transitivePeerDependencies: - - '@emnapi/core' - - '@napi-rs/cross-toolchain-arm64-target-aarch64' - - '@napi-rs/cross-toolchain-arm64-target-armv7' - - '@napi-rs/cross-toolchain-arm64-target-ppc64le' - - '@napi-rs/cross-toolchain-arm64-target-s390x' - - '@napi-rs/cross-toolchain-arm64-target-x86_64' - - '@napi-rs/cross-toolchain-x64-target-aarch64' - - '@napi-rs/cross-toolchain-x64-target-armv7' - - '@napi-rs/cross-toolchain-x64-target-ppc64le' - - '@napi-rs/cross-toolchain-x64-target-s390x' - - '@napi-rs/cross-toolchain-x64-target-x86_64' - - '@types/node' - - node-addon-api - - supports-color + fast-glob: 3.3.1 - '@napi-rs/cross-toolchain@1.0.3(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)': - dependencies: - '@napi-rs/lzma': 1.4.5(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3) - '@napi-rs/tar': 1.1.0(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3) - debug: 4.4.3 - transitivePeerDependencies: - - '@emnapi/core' - - '@emnapi/runtime' - - supports-color - - '@napi-rs/lzma-android-arm-eabi@1.4.5': + '@next/swc-darwin-arm64@15.0.3': optional: true - '@napi-rs/lzma-android-arm64@1.4.5': + '@next/swc-darwin-x64@15.0.3': optional: true - '@napi-rs/lzma-darwin-arm64@1.4.5': + '@next/swc-linux-arm64-gnu@15.0.3': optional: true - '@napi-rs/lzma-darwin-x64@1.4.5': + '@next/swc-linux-arm64-musl@15.0.3': optional: true - '@napi-rs/lzma-freebsd-x64@1.4.5': + '@next/swc-linux-x64-gnu@15.0.3': optional: true - '@napi-rs/lzma-linux-arm-gnueabihf@1.4.5': + '@next/swc-linux-x64-musl@15.0.3': optional: true - '@napi-rs/lzma-linux-arm64-gnu@1.4.5': + '@next/swc-win32-arm64-msvc@15.0.3': optional: true - '@napi-rs/lzma-linux-arm64-musl@1.4.5': - optional: true - - '@napi-rs/lzma-linux-ppc64-gnu@1.4.5': - optional: true - - '@napi-rs/lzma-linux-riscv64-gnu@1.4.5': - optional: true - - '@napi-rs/lzma-linux-s390x-gnu@1.4.5': - optional: true - - '@napi-rs/lzma-linux-x64-gnu@1.4.5': - optional: true - - '@napi-rs/lzma-linux-x64-musl@1.4.5': - optional: true - - '@napi-rs/lzma-wasm32-wasi@1.4.5(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)': - dependencies: - '@napi-rs/wasm-runtime': 1.2.2(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3) - transitivePeerDependencies: - - '@emnapi/core' - - '@emnapi/runtime' - optional: true - - '@napi-rs/lzma-win32-arm64-msvc@1.4.5': - optional: true - - '@napi-rs/lzma-win32-ia32-msvc@1.4.5': - optional: true - - '@napi-rs/lzma-win32-x64-msvc@1.4.5': - optional: true - - '@napi-rs/lzma@1.4.5(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)': - optionalDependencies: - '@napi-rs/lzma-android-arm-eabi': 1.4.5 - '@napi-rs/lzma-android-arm64': 1.4.5 - '@napi-rs/lzma-darwin-arm64': 1.4.5 - '@napi-rs/lzma-darwin-x64': 1.4.5 - '@napi-rs/lzma-freebsd-x64': 1.4.5 - '@napi-rs/lzma-linux-arm-gnueabihf': 1.4.5 - '@napi-rs/lzma-linux-arm64-gnu': 1.4.5 - '@napi-rs/lzma-linux-arm64-musl': 1.4.5 - '@napi-rs/lzma-linux-ppc64-gnu': 1.4.5 - '@napi-rs/lzma-linux-riscv64-gnu': 1.4.5 - '@napi-rs/lzma-linux-s390x-gnu': 1.4.5 - '@napi-rs/lzma-linux-x64-gnu': 1.4.5 - '@napi-rs/lzma-linux-x64-musl': 1.4.5 - '@napi-rs/lzma-wasm32-wasi': 1.4.5(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3) - '@napi-rs/lzma-win32-arm64-msvc': 1.4.5 - '@napi-rs/lzma-win32-ia32-msvc': 1.4.5 - '@napi-rs/lzma-win32-x64-msvc': 1.4.5 - transitivePeerDependencies: - - '@emnapi/core' - - '@emnapi/runtime' - - '@napi-rs/tar-android-arm-eabi@1.1.0': - optional: true - - '@napi-rs/tar-android-arm64@1.1.0': - optional: true - - '@napi-rs/tar-darwin-arm64@1.1.0': - optional: true - - '@napi-rs/tar-darwin-x64@1.1.0': - optional: true - - '@napi-rs/tar-freebsd-x64@1.1.0': - optional: true - - '@napi-rs/tar-linux-arm-gnueabihf@1.1.0': - optional: true - - '@napi-rs/tar-linux-arm64-gnu@1.1.0': - optional: true - - '@napi-rs/tar-linux-arm64-musl@1.1.0': - optional: true - - '@napi-rs/tar-linux-ppc64-gnu@1.1.0': - optional: true - - '@napi-rs/tar-linux-s390x-gnu@1.1.0': - optional: true - - '@napi-rs/tar-linux-x64-gnu@1.1.0': - optional: true - - '@napi-rs/tar-linux-x64-musl@1.1.0': - optional: true - - '@napi-rs/tar-wasm32-wasi@1.1.0(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)': - dependencies: - '@napi-rs/wasm-runtime': 1.2.2(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3) - transitivePeerDependencies: - - '@emnapi/core' - - '@emnapi/runtime' - optional: true - - '@napi-rs/tar-win32-arm64-msvc@1.1.0': - optional: true - - '@napi-rs/tar-win32-ia32-msvc@1.1.0': - optional: true - - '@napi-rs/tar-win32-x64-msvc@1.1.0': - optional: true - - '@napi-rs/tar@1.1.0(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)': - optionalDependencies: - '@napi-rs/tar-android-arm-eabi': 1.1.0 - '@napi-rs/tar-android-arm64': 1.1.0 - '@napi-rs/tar-darwin-arm64': 1.1.0 - '@napi-rs/tar-darwin-x64': 1.1.0 - '@napi-rs/tar-freebsd-x64': 1.1.0 - '@napi-rs/tar-linux-arm-gnueabihf': 1.1.0 - '@napi-rs/tar-linux-arm64-gnu': 1.1.0 - '@napi-rs/tar-linux-arm64-musl': 1.1.0 - '@napi-rs/tar-linux-ppc64-gnu': 1.1.0 - '@napi-rs/tar-linux-s390x-gnu': 1.1.0 - '@napi-rs/tar-linux-x64-gnu': 1.1.0 - '@napi-rs/tar-linux-x64-musl': 1.1.0 - '@napi-rs/tar-wasm32-wasi': 1.1.0(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3) - '@napi-rs/tar-win32-arm64-msvc': 1.1.0 - '@napi-rs/tar-win32-ia32-msvc': 1.1.0 - '@napi-rs/tar-win32-x64-msvc': 1.1.0 - transitivePeerDependencies: - - '@emnapi/core' - - '@emnapi/runtime' - - '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': - dependencies: - '@emnapi/core': 1.10.0 - '@emnapi/runtime': 1.10.0 - '@tybys/wasm-util': 0.10.3 - optional: true - - '@napi-rs/wasm-runtime@1.2.2(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)': - dependencies: - '@emnapi/core': 1.11.3 - '@emnapi/runtime': 1.11.3 - '@tybys/wasm-util': 0.10.3 - - '@napi-rs/wasm-runtime@1.2.2(@emnapi/core@2.0.0-alpha.3)(@emnapi/runtime@2.0.0-alpha.3)': - dependencies: - '@emnapi/core': 2.0.0-alpha.3 - '@emnapi/runtime': 2.0.0-alpha.3 - '@tybys/wasm-util': 0.10.3 - optional: true - - '@napi-rs/wasm-tools-android-arm-eabi@1.0.1': - optional: true - - '@napi-rs/wasm-tools-android-arm64@1.0.1': - optional: true - - '@napi-rs/wasm-tools-darwin-arm64@1.0.1': - optional: true - - '@napi-rs/wasm-tools-darwin-x64@1.0.1': - optional: true - - '@napi-rs/wasm-tools-freebsd-x64@1.0.1': - optional: true - - '@napi-rs/wasm-tools-linux-arm64-gnu@1.0.1': - optional: true - - '@napi-rs/wasm-tools-linux-arm64-musl@1.0.1': - optional: true - - '@napi-rs/wasm-tools-linux-x64-gnu@1.0.1': - optional: true - - '@napi-rs/wasm-tools-linux-x64-musl@1.0.1': - optional: true - - '@napi-rs/wasm-tools-wasm32-wasi@1.0.1(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)': - dependencies: - '@napi-rs/wasm-runtime': 1.2.2(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3) - transitivePeerDependencies: - - '@emnapi/core' - - '@emnapi/runtime' - optional: true - - '@napi-rs/wasm-tools-win32-arm64-msvc@1.0.1': - optional: true - - '@napi-rs/wasm-tools-win32-ia32-msvc@1.0.1': - optional: true - - '@napi-rs/wasm-tools-win32-x64-msvc@1.0.1': - optional: true - - '@napi-rs/wasm-tools@1.0.1(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3)': - optionalDependencies: - '@napi-rs/wasm-tools-android-arm-eabi': 1.0.1 - '@napi-rs/wasm-tools-android-arm64': 1.0.1 - '@napi-rs/wasm-tools-darwin-arm64': 1.0.1 - '@napi-rs/wasm-tools-darwin-x64': 1.0.1 - '@napi-rs/wasm-tools-freebsd-x64': 1.0.1 - '@napi-rs/wasm-tools-linux-arm64-gnu': 1.0.1 - '@napi-rs/wasm-tools-linux-arm64-musl': 1.0.1 - '@napi-rs/wasm-tools-linux-x64-gnu': 1.0.1 - '@napi-rs/wasm-tools-linux-x64-musl': 1.0.1 - '@napi-rs/wasm-tools-wasm32-wasi': 1.0.1(@emnapi/core@1.11.3)(@emnapi/runtime@1.11.3) - '@napi-rs/wasm-tools-win32-arm64-msvc': 1.0.1 - '@napi-rs/wasm-tools-win32-ia32-msvc': 1.0.1 - '@napi-rs/wasm-tools-win32-x64-msvc': 1.0.1 - transitivePeerDependencies: - - '@emnapi/core' - - '@emnapi/runtime' - - '@next/env@16.2.7': {} - - '@next/swc-darwin-arm64@16.2.7': - optional: true - - '@next/swc-darwin-x64@16.2.7': - optional: true - - '@next/swc-linux-arm64-gnu@16.2.7': - optional: true - - '@next/swc-linux-arm64-musl@16.2.7': - optional: true - - '@next/swc-linux-x64-gnu@16.2.7': - optional: true - - '@next/swc-linux-x64-musl@16.2.7': - optional: true - - '@next/swc-win32-arm64-msvc@16.2.7': - optional: true - - '@next/swc-win32-x64-msvc@16.2.7': + '@next/swc-win32-x64-msvc@15.0.3': optional: true '@nodelib/fs.scandir@2.1.5': @@ -4211,665 +6725,705 @@ snapshots: '@nodelib/fs.walk@1.2.8': dependencies: '@nodelib/fs.scandir': 2.1.5 - fastq: 1.20.1 + fastq: 1.17.1 - '@octokit/auth-token@6.0.0': {} + '@nolyfill/is-core-module@1.0.39': {} - '@octokit/core@7.0.6': - dependencies: - '@octokit/auth-token': 6.0.0 - '@octokit/graphql': 9.0.3 - '@octokit/request': 10.0.9 - '@octokit/request-error': 7.1.0 - '@octokit/types': 16.0.0 - before-after-hook: 4.0.0 - universal-user-agent: 7.0.3 - - '@octokit/endpoint@11.0.3': - dependencies: - '@octokit/types': 16.0.0 - universal-user-agent: 7.0.3 - - '@octokit/graphql@9.0.3': - dependencies: - '@octokit/request': 10.0.9 - '@octokit/types': 16.0.0 - universal-user-agent: 7.0.3 - - '@octokit/openapi-types@27.0.0': {} - - '@octokit/plugin-paginate-rest@14.0.0(@octokit/core@7.0.6)': - dependencies: - '@octokit/core': 7.0.6 - '@octokit/types': 16.0.0 - - '@octokit/plugin-request-log@6.0.0(@octokit/core@7.0.6)': - dependencies: - '@octokit/core': 7.0.6 - - '@octokit/plugin-rest-endpoint-methods@17.0.0(@octokit/core@7.0.6)': - dependencies: - '@octokit/core': 7.0.6 - '@octokit/types': 16.0.0 - - '@octokit/request-error@7.1.0': - dependencies: - '@octokit/types': 16.0.0 - - '@octokit/request@10.0.9': - dependencies: - '@octokit/endpoint': 11.0.3 - '@octokit/request-error': 7.1.0 - '@octokit/types': 16.0.0 - content-type: 2.0.0 - fast-content-type-parse: 3.0.0 - json-with-bigint: 3.5.8 - universal-user-agent: 7.0.3 - - '@octokit/rest@22.0.1': - dependencies: - '@octokit/core': 7.0.6 - '@octokit/plugin-paginate-rest': 14.0.0(@octokit/core@7.0.6) - '@octokit/plugin-request-log': 6.0.0(@octokit/core@7.0.6) - '@octokit/plugin-rest-endpoint-methods': 17.0.0(@octokit/core@7.0.6) - - '@octokit/types@16.0.0': - dependencies: - '@octokit/openapi-types': 27.0.0 - - '@oven/bun-darwin-aarch64@1.3.14': - optional: true - - '@oven/bun-darwin-x64-baseline@1.3.14': - optional: true - - '@oven/bun-darwin-x64@1.3.14': - optional: true - - '@oven/bun-freebsd-aarch64@1.3.14': - optional: true - - '@oven/bun-freebsd-x64@1.3.14': - optional: true - - '@oven/bun-linux-aarch64-android@1.3.14': - optional: true - - '@oven/bun-linux-aarch64-musl@1.3.14': - optional: true - - '@oven/bun-linux-aarch64@1.3.14': - optional: true - - '@oven/bun-linux-x64-android@1.3.14': - optional: true - - '@oven/bun-linux-x64-baseline@1.3.14': - optional: true - - '@oven/bun-linux-x64-musl-baseline@1.3.14': - optional: true - - '@oven/bun-linux-x64-musl@1.3.14': - optional: true - - '@oven/bun-linux-x64@1.3.14': - optional: true - - '@oven/bun-windows-aarch64@1.3.14': - optional: true - - '@oven/bun-windows-x64-baseline@1.3.14': - optional: true - - '@oven/bun-windows-x64@1.3.14': - optional: true - - '@oxc-project/types@0.142.0': {} - - '@parcel/watcher-android-arm64@2.6.0': - optional: true - - '@parcel/watcher-darwin-arm64@2.6.0': {} - - '@parcel/watcher-darwin-x64@2.6.0': {} - - '@parcel/watcher-freebsd-x64@2.6.0': - optional: true - - '@parcel/watcher-linux-arm-glibc@2.6.0': - optional: true - - '@parcel/watcher-linux-arm-musl@2.6.0': - optional: true - - '@parcel/watcher-linux-arm64-glibc@2.6.0': {} - - '@parcel/watcher-linux-arm64-musl@2.6.0': {} - - '@parcel/watcher-linux-x64-glibc@2.6.0': {} - - '@parcel/watcher-linux-x64-musl@2.6.0': {} - - '@parcel/watcher-wasm@2.5.6': + '@oven/bun-darwin-aarch64@1.1.29': + optional: true + + '@oven/bun-darwin-x64-baseline@1.1.29': + optional: true + + '@oven/bun-darwin-x64@1.1.29': + optional: true + + '@oven/bun-linux-aarch64@1.1.29': + optional: true + + '@oven/bun-linux-x64-baseline@1.1.29': + optional: true + + '@oven/bun-linux-x64@1.1.29': + optional: true + + '@oven/bun-windows-x64-baseline@1.1.29': + optional: true + + '@oven/bun-windows-x64@1.1.29': + optional: true + + '@parcel/watcher-android-arm64@2.5.0': + optional: true + + '@parcel/watcher-darwin-arm64@2.5.0': {} + + '@parcel/watcher-darwin-x64@2.5.0': {} + + '@parcel/watcher-freebsd-x64@2.5.0': + optional: true + + '@parcel/watcher-linux-arm-glibc@2.5.0': + optional: true + + '@parcel/watcher-linux-arm-musl@2.5.0': + optional: true + + '@parcel/watcher-linux-arm64-glibc@2.5.0': {} + + '@parcel/watcher-linux-arm64-musl@2.5.0': {} + + '@parcel/watcher-linux-x64-glibc@2.5.0': {} + + '@parcel/watcher-linux-x64-musl@2.5.0': {} + + '@parcel/watcher-win32-arm64@2.5.0': + optional: true + + '@parcel/watcher-win32-ia32@2.5.0': + optional: true + + '@parcel/watcher-win32-x64@2.5.0': {} + + '@parcel/watcher@2.5.0(patch_hash=pyfayeoxwesjxsefsxp3jpev4q)': dependencies: + detect-libc: 1.0.3 is-glob: 4.0.3 - picomatch: 4.0.5 - - '@parcel/watcher-win32-arm64@2.6.0': - optional: true - - '@parcel/watcher-win32-x64@2.6.0': {} - - '@parcel/watcher@2.6.0(patch_hash=705ce75ccea54337110c4d7fe0a8b421658ea0c23e1a77c1fa890a86041179da)': - dependencies: - detect-libc: 2.1.2 - is-glob: 4.0.3 + micromatch: 4.0.7 node-addon-api: 7.1.1 - picomatch: 4.0.5 optionalDependencies: - '@parcel/watcher-android-arm64': 2.6.0 - '@parcel/watcher-darwin-arm64': 2.6.0 - '@parcel/watcher-darwin-x64': 2.6.0 - '@parcel/watcher-freebsd-x64': 2.6.0 - '@parcel/watcher-linux-arm-glibc': 2.6.0 - '@parcel/watcher-linux-arm-musl': 2.6.0 - '@parcel/watcher-linux-arm64-glibc': 2.6.0 - '@parcel/watcher-linux-arm64-musl': 2.6.0 - '@parcel/watcher-linux-x64-glibc': 2.6.0 - '@parcel/watcher-linux-x64-musl': 2.6.0 - '@parcel/watcher-win32-arm64': 2.6.0 - '@parcel/watcher-win32-x64': 2.6.0 + '@parcel/watcher-android-arm64': 2.5.0 + '@parcel/watcher-darwin-arm64': 2.5.0 + '@parcel/watcher-darwin-x64': 2.5.0 + '@parcel/watcher-freebsd-x64': 2.5.0 + '@parcel/watcher-linux-arm-glibc': 2.5.0 + '@parcel/watcher-linux-arm-musl': 2.5.0 + '@parcel/watcher-linux-arm64-glibc': 2.5.0 + '@parcel/watcher-linux-arm64-musl': 2.5.0 + '@parcel/watcher-linux-x64-glibc': 2.5.0 + '@parcel/watcher-linux-x64-musl': 2.5.0 + '@parcel/watcher-win32-arm64': 2.5.0 + '@parcel/watcher-win32-ia32': 2.5.0 + '@parcel/watcher-win32-x64': 2.5.0 - '@playwright/test@1.62.1': + '@pkgjs/parseargs@0.11.0': + optional: true + + '@playwright/test@1.49.0': dependencies: - playwright: 1.62.1 + playwright: 1.49.0 - '@rolldown/binding-android-arm64@1.2.1': + '@rollup/rollup-android-arm-eabi@4.20.0': optional: true - '@rolldown/binding-darwin-arm64@1.2.1': + '@rollup/rollup-android-arm-eabi@4.27.4': optional: true - '@rolldown/binding-darwin-x64@1.2.1': + '@rollup/rollup-android-arm64@4.20.0': optional: true - '@rolldown/binding-freebsd-x64@1.2.1': + '@rollup/rollup-android-arm64@4.27.4': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.2.1': + '@rollup/rollup-darwin-arm64@4.20.0': optional: true - '@rolldown/binding-linux-arm64-gnu@1.2.1': + '@rollup/rollup-darwin-arm64@4.27.4': optional: true - '@rolldown/binding-linux-arm64-musl@1.2.1': + '@rollup/rollup-darwin-x64@4.20.0': optional: true - '@rolldown/binding-linux-ppc64-gnu@1.2.1': + '@rollup/rollup-darwin-x64@4.27.4': optional: true - '@rolldown/binding-linux-s390x-gnu@1.2.1': + '@rollup/rollup-freebsd-arm64@4.27.4': optional: true - '@rolldown/binding-linux-x64-gnu@1.2.1': + '@rollup/rollup-freebsd-x64@4.27.4': optional: true - '@rolldown/binding-linux-x64-musl@1.2.1': + '@rollup/rollup-linux-arm-gnueabihf@4.20.0': optional: true - '@rolldown/binding-openharmony-arm64@1.2.1': + '@rollup/rollup-linux-arm-gnueabihf@4.27.4': optional: true - '@rolldown/binding-wasm32-wasi@1.2.1': + '@rollup/rollup-linux-arm-musleabihf@4.20.0': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.27.4': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.20.0': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.27.4': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.20.0': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.27.4': + optional: true + + '@rollup/rollup-linux-powerpc64le-gnu@4.20.0': + optional: true + + '@rollup/rollup-linux-powerpc64le-gnu@4.27.4': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.20.0': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.27.4': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.20.0': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.27.4': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.20.0': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.27.4': + optional: true + + '@rollup/rollup-linux-x64-musl@4.20.0': + optional: true + + '@rollup/rollup-linux-x64-musl@4.27.4': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.20.0': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.27.4': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.20.0': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.27.4': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.20.0': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.27.4': + optional: true + + '@rtsao/scc@1.1.0': {} + + '@rushstack/eslint-patch@1.10.4': {} + + '@sindresorhus/merge-streams@2.3.0': {} + + '@swc/counter@0.1.3': {} + + '@swc/helpers@0.5.13': dependencies: - '@emnapi/core': 2.0.0-alpha.3 - '@emnapi/runtime': 2.0.0-alpha.3 - '@napi-rs/wasm-runtime': 1.2.2(@emnapi/core@2.0.0-alpha.3)(@emnapi/runtime@2.0.0-alpha.3) - optional: true - - '@rolldown/binding-win32-arm64-msvc@1.2.1': - optional: true - - '@rolldown/binding-win32-x64-msvc@1.2.1': - optional: true - - '@rolldown/pluginutils@1.0.1': {} - - '@rollup/rollup-android-arm-eabi@4.60.4': - optional: true - - '@rollup/rollup-android-arm64@4.60.4': - optional: true - - '@rollup/rollup-darwin-arm64@4.60.4': - optional: true - - '@rollup/rollup-darwin-x64@4.60.4': - optional: true - - '@rollup/rollup-freebsd-arm64@4.60.4': - optional: true - - '@rollup/rollup-freebsd-x64@4.60.4': - optional: true - - '@rollup/rollup-linux-arm-gnueabihf@4.60.4': - optional: true - - '@rollup/rollup-linux-arm-musleabihf@4.60.4': - optional: true - - '@rollup/rollup-linux-arm64-gnu@4.60.4': - optional: true - - '@rollup/rollup-linux-arm64-musl@4.60.4': - optional: true - - '@rollup/rollup-linux-loong64-gnu@4.60.4': - optional: true - - '@rollup/rollup-linux-loong64-musl@4.60.4': - optional: true - - '@rollup/rollup-linux-ppc64-gnu@4.60.4': - optional: true - - '@rollup/rollup-linux-ppc64-musl@4.60.4': - optional: true - - '@rollup/rollup-linux-riscv64-gnu@4.60.4': - optional: true - - '@rollup/rollup-linux-riscv64-musl@4.60.4': - optional: true - - '@rollup/rollup-linux-s390x-gnu@4.60.4': - optional: true - - '@rollup/rollup-linux-x64-gnu@4.60.4': - optional: true - - '@rollup/rollup-linux-x64-musl@4.60.4': - optional: true - - '@rollup/rollup-openbsd-x64@4.60.4': - optional: true - - '@rollup/rollup-openharmony-arm64@4.60.4': - optional: true - - '@rollup/rollup-win32-arm64-msvc@4.60.4': - optional: true - - '@rollup/rollup-win32-ia32-msvc@4.60.4': - optional: true - - '@rollup/rollup-win32-x64-gnu@4.60.4': - optional: true - - '@rollup/rollup-win32-x64-msvc@4.60.4': - optional: true - - '@rspack/binding-darwin-arm64@2.0.2': - optional: true - - '@rspack/binding-darwin-x64@2.0.2': - optional: true - - '@rspack/binding-linux-arm64-gnu@2.0.2': - optional: true - - '@rspack/binding-linux-arm64-musl@2.0.2': - optional: true - - '@rspack/binding-linux-x64-gnu@2.0.2': - optional: true - - '@rspack/binding-linux-x64-musl@2.0.2': - optional: true - - '@rspack/binding-wasm32-wasi@2.0.2': - dependencies: - '@emnapi/core': 1.10.0 - '@emnapi/runtime': 1.10.0 - '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) - optional: true - - '@rspack/binding-win32-arm64-msvc@2.0.2': - optional: true - - '@rspack/binding-win32-ia32-msvc@2.0.2': - optional: true - - '@rspack/binding-win32-x64-msvc@2.0.2': - optional: true - - '@rspack/binding@2.0.2': - optionalDependencies: - '@rspack/binding-darwin-arm64': 2.0.2 - '@rspack/binding-darwin-x64': 2.0.2 - '@rspack/binding-linux-arm64-gnu': 2.0.2 - '@rspack/binding-linux-arm64-musl': 2.0.2 - '@rspack/binding-linux-x64-gnu': 2.0.2 - '@rspack/binding-linux-x64-musl': 2.0.2 - '@rspack/binding-wasm32-wasi': 2.0.2 - '@rspack/binding-win32-arm64-msvc': 2.0.2 - '@rspack/binding-win32-ia32-msvc': 2.0.2 - '@rspack/binding-win32-x64-msvc': 2.0.2 - - '@rspack/core@2.0.2(@swc/helpers@0.5.15)': - dependencies: - '@rspack/binding': 2.0.2 - optionalDependencies: - '@swc/helpers': 0.5.15 - - '@sindresorhus/merge-streams@4.0.0': {} - - '@standard-schema/spec@1.1.0': {} - - '@swc/helpers@0.5.15': - dependencies: - tslib: 2.8.1 + tslib: 2.8.0 '@tailwindcss/aspect-ratio@0.4.2(tailwindcss@packages+tailwindcss)': dependencies: tailwindcss: link:packages/tailwindcss - '@tailwindcss/forms@0.5.11(tailwindcss@packages+tailwindcss)': + '@tailwindcss/forms@0.5.9(tailwindcss@packages+tailwindcss)': dependencies: mini-svg-data-uri: 1.4.4 tailwindcss: link:packages/tailwindcss - '@tailwindcss/typography@0.5.20(tailwindcss@packages+tailwindcss)': + '@tailwindcss/typography@0.5.15(tailwindcss@packages+tailwindcss)': dependencies: + lodash.castarray: 4.4.0 + lodash.isplainobject: 4.0.6 + lodash.merge: 4.6.2 postcss-selector-parser: 6.0.10 tailwindcss: link:packages/tailwindcss - '@turbo/darwin-64@2.10.8': - optional: true - - '@turbo/darwin-arm64@2.10.8': - optional: true - - '@turbo/linux-64@2.10.8': - optional: true - - '@turbo/linux-arm64@2.10.8': - optional: true - - '@turbo/windows-64@2.10.8': - optional: true - - '@turbo/windows-arm64@2.10.8': - optional: true - - '@tybys/wasm-util@0.10.3': + '@types/babel__core@7.20.5': dependencies: - tslib: 2.8.1 + '@babel/parser': 7.25.3 + '@babel/types': 7.25.2 + '@types/babel__generator': 7.6.8 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.20.6 - '@types/bun@1.3.14': + '@types/babel__generator@7.6.8': dependencies: - bun-types: 1.3.14 + '@babel/types': 7.25.2 - '@types/chai@5.2.3': + '@types/babel__template@7.4.4': dependencies: - '@types/deep-eql': 4.0.2 - assertion-error: 2.0.1 + '@babel/parser': 7.25.3 + '@babel/types': 7.25.2 - '@types/deep-eql@4.0.2': {} + '@types/babel__traverse@7.20.6': + dependencies: + '@babel/types': 7.25.2 - '@types/estree@1.0.8': {} + '@types/braces@3.0.4': {} - '@types/estree@1.0.9': {} + '@types/bun@1.1.13': + dependencies: + bun-types: 1.1.34 + + '@types/estree@1.0.5': {} + + '@types/estree@1.0.6': {} '@types/json-schema@7.0.15': {} - '@types/node@22.20.1': - dependencies: - undici-types: 6.21.0 + '@types/json5@0.0.29': {} - '@types/node@25.9.1': + '@types/node@20.12.14': dependencies: - undici-types: 7.24.6 + undici-types: 5.26.5 + + '@types/node@20.14.13': + dependencies: + undici-types: 5.26.5 '@types/postcss-import@14.0.3': dependencies: - postcss: 8.5.25 + postcss: 8.4.41 - '@types/react-dom@19.2.3(@types/react@19.2.15)': + '@types/prop-types@15.7.13': {} + + '@types/react-dom@18.3.1': dependencies: - '@types/react': 19.2.15 + '@types/react': 18.3.12 - '@types/react@19.2.15': + '@types/react@18.3.12': dependencies: - csstype: 3.2.3 + '@types/prop-types': 15.7.13 + csstype: 3.1.3 - '@types/semver@7.8.0': {} - - '@vitejs/plugin-react@6.0.2(vite@8.2.0(@types/node@25.9.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.48.0)(yaml@2.9.0))': + '@types/ws@8.5.12': dependencies: - '@rolldown/pluginutils': 1.0.1 - vite: 8.2.0(@types/node@25.9.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.48.0)(yaml@2.9.0) + '@types/node': 20.14.13 - '@vitest/expect@4.1.10': + '@typescript-eslint/eslint-plugin@8.11.0(@typescript-eslint/parser@8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.5.4))(eslint@9.15.0(jiti@2.4.0))(typescript@5.5.4)': dependencies: - '@standard-schema/spec': 1.1.0 - '@types/chai': 5.2.3 - '@vitest/spy': 4.1.10 - '@vitest/utils': 4.1.10 - chai: 6.2.2 - tinyrainbow: 3.1.0 + '@eslint-community/regexpp': 4.11.1 + '@typescript-eslint/parser': 8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.5.4) + '@typescript-eslint/scope-manager': 8.11.0 + '@typescript-eslint/type-utils': 8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.5.4) + '@typescript-eslint/utils': 8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.5.4) + '@typescript-eslint/visitor-keys': 8.11.0 + eslint: 9.15.0(jiti@2.4.0) + graphemer: 1.4.0 + ignore: 5.3.2 + natural-compare: 1.4.0 + ts-api-utils: 1.3.0(typescript@5.5.4) + optionalDependencies: + typescript: 5.5.4 + transitivePeerDependencies: + - supports-color - '@vitest/mocker@4.1.10(vite@8.2.0(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.48.0)(yaml@2.9.0))': + '@typescript-eslint/eslint-plugin@8.11.0(@typescript-eslint/parser@8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.15.0(jiti@2.4.0))(typescript@5.6.3)': dependencies: - '@vitest/spy': 4.1.10 + '@eslint-community/regexpp': 4.11.1 + '@typescript-eslint/parser': 8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.6.3) + '@typescript-eslint/scope-manager': 8.11.0 + '@typescript-eslint/type-utils': 8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.6.3) + '@typescript-eslint/utils': 8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.6.3) + '@typescript-eslint/visitor-keys': 8.11.0 + eslint: 9.15.0(jiti@2.4.0) + graphemer: 1.4.0 + ignore: 5.3.2 + natural-compare: 1.4.0 + ts-api-utils: 1.3.0(typescript@5.6.3) + optionalDependencies: + typescript: 5.6.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.5.4)': + dependencies: + '@typescript-eslint/scope-manager': 8.11.0 + '@typescript-eslint/types': 8.11.0 + '@typescript-eslint/typescript-estree': 8.11.0(typescript@5.5.4) + '@typescript-eslint/visitor-keys': 8.11.0 + debug: 4.3.7 + eslint: 9.15.0(jiti@2.4.0) + optionalDependencies: + typescript: 5.5.4 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.6.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.11.0 + '@typescript-eslint/types': 8.11.0 + '@typescript-eslint/typescript-estree': 8.11.0(typescript@5.6.3) + '@typescript-eslint/visitor-keys': 8.11.0 + debug: 4.3.7 + eslint: 9.15.0(jiti@2.4.0) + optionalDependencies: + typescript: 5.6.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.11.0': + dependencies: + '@typescript-eslint/types': 8.11.0 + '@typescript-eslint/visitor-keys': 8.11.0 + + '@typescript-eslint/type-utils@8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.5.4)': + dependencies: + '@typescript-eslint/typescript-estree': 8.11.0(typescript@5.5.4) + '@typescript-eslint/utils': 8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.5.4) + debug: 4.3.7 + ts-api-utils: 1.3.0(typescript@5.5.4) + optionalDependencies: + typescript: 5.5.4 + transitivePeerDependencies: + - eslint + - supports-color + + '@typescript-eslint/type-utils@8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.6.3)': + dependencies: + '@typescript-eslint/typescript-estree': 8.11.0(typescript@5.6.3) + '@typescript-eslint/utils': 8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.6.3) + debug: 4.3.7 + ts-api-utils: 1.3.0(typescript@5.6.3) + optionalDependencies: + typescript: 5.6.3 + transitivePeerDependencies: + - eslint + - supports-color + + '@typescript-eslint/types@8.11.0': {} + + '@typescript-eslint/typescript-estree@8.11.0(typescript@5.5.4)': + dependencies: + '@typescript-eslint/types': 8.11.0 + '@typescript-eslint/visitor-keys': 8.11.0 + debug: 4.3.7 + fast-glob: 3.3.2 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.6.3 + ts-api-utils: 1.3.0(typescript@5.5.4) + optionalDependencies: + typescript: 5.5.4 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/typescript-estree@8.11.0(typescript@5.6.3)': + dependencies: + '@typescript-eslint/types': 8.11.0 + '@typescript-eslint/visitor-keys': 8.11.0 + debug: 4.3.7 + fast-glob: 3.3.2 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.6.3 + ts-api-utils: 1.3.0(typescript@5.6.3) + optionalDependencies: + typescript: 5.6.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.5.4)': + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@9.15.0(jiti@2.4.0)) + '@typescript-eslint/scope-manager': 8.11.0 + '@typescript-eslint/types': 8.11.0 + '@typescript-eslint/typescript-estree': 8.11.0(typescript@5.5.4) + eslint: 9.15.0(jiti@2.4.0) + transitivePeerDependencies: + - supports-color + - typescript + + '@typescript-eslint/utils@8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.6.3)': + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@9.15.0(jiti@2.4.0)) + '@typescript-eslint/scope-manager': 8.11.0 + '@typescript-eslint/types': 8.11.0 + '@typescript-eslint/typescript-estree': 8.11.0(typescript@5.6.3) + eslint: 9.15.0(jiti@2.4.0) + transitivePeerDependencies: + - supports-color + - typescript + + '@typescript-eslint/visitor-keys@8.11.0': + dependencies: + '@typescript-eslint/types': 8.11.0 + eslint-visitor-keys: 3.4.3 + + '@vitejs/plugin-react@4.3.1(vite@6.0.0(@types/node@20.14.13)(jiti@2.4.0)(lightningcss@1.26.0(patch_hash=5hwfyehqvg5wjb7mwtdvubqbl4))(terser@5.31.6)(tsx@4.19.1)(yaml@2.6.0))': + dependencies: + '@babel/core': 7.25.2 + '@babel/plugin-transform-react-jsx-self': 7.24.7(@babel/core@7.25.2) + '@babel/plugin-transform-react-jsx-source': 7.24.7(@babel/core@7.25.2) + '@types/babel__core': 7.20.5 + react-refresh: 0.14.2 + vite: 6.0.0(@types/node@20.14.13)(jiti@2.4.0)(lightningcss@1.26.0(patch_hash=5hwfyehqvg5wjb7mwtdvubqbl4))(terser@5.31.6)(tsx@4.19.1)(yaml@2.6.0) + transitivePeerDependencies: + - supports-color + + '@vitest/expect@2.0.5': + dependencies: + '@vitest/spy': 2.0.5 + '@vitest/utils': 2.0.5 + chai: 5.1.1 + tinyrainbow: 1.2.0 + + '@vitest/pretty-format@2.0.5': + dependencies: + tinyrainbow: 1.2.0 + + '@vitest/runner@2.0.5': + dependencies: + '@vitest/utils': 2.0.5 + pathe: 1.1.2 + + '@vitest/snapshot@2.0.5': + dependencies: + '@vitest/pretty-format': 2.0.5 + magic-string: 0.30.11 + pathe: 1.1.2 + + '@vitest/spy@2.0.5': + dependencies: + tinyspy: 3.0.0 + + '@vitest/utils@2.0.5': + dependencies: + '@vitest/pretty-format': 2.0.5 estree-walker: 3.0.3 - magic-string: 0.30.21 - optionalDependencies: - vite: 8.2.0(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.48.0)(yaml@2.9.0) + loupe: 3.1.1 + tinyrainbow: 1.2.0 - '@vitest/pretty-format@4.1.10': + acorn-jsx@5.3.2(acorn@8.14.0): dependencies: - tinyrainbow: 3.1.0 + acorn: 8.14.0 - '@vitest/runner@4.1.10': - dependencies: - '@vitest/utils': 4.1.10 - pathe: 2.0.3 + acorn@8.14.0: {} - '@vitest/snapshot@4.1.10': - dependencies: - '@vitest/pretty-format': 4.1.10 - '@vitest/utils': 4.1.10 - magic-string: 0.30.21 - pathe: 2.0.3 - - '@vitest/spy@4.1.10': {} - - '@vitest/utils@4.1.10': - dependencies: - '@vitest/pretty-format': 4.1.10 - convert-source-map: 2.0.0 - tinyrainbow: 3.1.0 - - '@webassemblyjs/ast@1.14.1': - dependencies: - '@webassemblyjs/helper-numbers': 1.13.2 - '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - - '@webassemblyjs/floating-point-hex-parser@1.13.2': {} - - '@webassemblyjs/helper-api-error@1.13.2': {} - - '@webassemblyjs/helper-buffer@1.14.1': {} - - '@webassemblyjs/helper-numbers@1.13.2': - dependencies: - '@webassemblyjs/floating-point-hex-parser': 1.13.2 - '@webassemblyjs/helper-api-error': 1.13.2 - '@xtuc/long': 4.2.2 - - '@webassemblyjs/helper-wasm-bytecode@1.13.2': {} - - '@webassemblyjs/helper-wasm-section@1.14.1': - dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-buffer': 1.14.1 - '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - '@webassemblyjs/wasm-gen': 1.14.1 - - '@webassemblyjs/ieee754@1.13.2': - dependencies: - '@xtuc/ieee754': 1.2.0 - - '@webassemblyjs/leb128@1.13.2': - dependencies: - '@xtuc/long': 4.2.2 - - '@webassemblyjs/utf8@1.13.2': {} - - '@webassemblyjs/wasm-edit@1.14.1': - dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-buffer': 1.14.1 - '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - '@webassemblyjs/helper-wasm-section': 1.14.1 - '@webassemblyjs/wasm-gen': 1.14.1 - '@webassemblyjs/wasm-opt': 1.14.1 - '@webassemblyjs/wasm-parser': 1.14.1 - '@webassemblyjs/wast-printer': 1.14.1 - - '@webassemblyjs/wasm-gen@1.14.1': - dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - '@webassemblyjs/ieee754': 1.13.2 - '@webassemblyjs/leb128': 1.13.2 - '@webassemblyjs/utf8': 1.13.2 - - '@webassemblyjs/wasm-opt@1.14.1': - dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-buffer': 1.14.1 - '@webassemblyjs/wasm-gen': 1.14.1 - '@webassemblyjs/wasm-parser': 1.14.1 - - '@webassemblyjs/wasm-parser@1.14.1': - dependencies: - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/helper-api-error': 1.13.2 - '@webassemblyjs/helper-wasm-bytecode': 1.13.2 - '@webassemblyjs/ieee754': 1.13.2 - '@webassemblyjs/leb128': 1.13.2 - '@webassemblyjs/utf8': 1.13.2 - - '@webassemblyjs/wast-printer@1.14.1': - dependencies: - '@webassemblyjs/ast': 1.14.1 - '@xtuc/long': 4.2.2 - - '@xtuc/ieee754@1.2.0': {} - - '@xtuc/long@4.2.2': {} - - acorn@8.16.0: {} - - ajv-formats@2.1.1(ajv@8.20.0): - optionalDependencies: - ajv: 8.20.0 - - ajv-keywords@5.1.0(ajv@8.20.0): - dependencies: - ajv: 8.20.0 - fast-deep-equal: 3.1.3 - - ajv@8.20.0: + ajv@6.12.6: dependencies: fast-deep-equal: 3.1.3 - fast-uri: 3.1.2 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ansi-regex@5.0.1: {} + + ansi-regex@6.0.1: {} + + ansi-styles@3.2.1: + dependencies: + color-convert: 1.9.3 + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@6.2.1: {} any-promise@1.3.0: {} anymatch@3.1.3: dependencies: normalize-path: 3.0.0 - picomatch: 2.3.2 + picomatch: 2.3.1 arg@5.0.2: {} argparse@2.0.1: {} + aria-query@5.3.2: {} + + array-buffer-byte-length@1.0.1: + dependencies: + call-bind: 1.0.7 + is-array-buffer: 3.0.4 + + array-includes@3.1.8: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 + get-intrinsic: 1.2.4 + is-string: 1.0.7 + + array-union@2.1.0: {} + + array.prototype.findlast@1.2.5: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + es-shim-unscopables: 1.0.2 + + array.prototype.findlastindex@1.2.5: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + es-shim-unscopables: 1.0.2 + + array.prototype.flat@1.3.2: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-shim-unscopables: 1.0.2 + + array.prototype.flatmap@1.3.2: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-shim-unscopables: 1.0.2 + + array.prototype.tosorted@1.1.4: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + es-shim-unscopables: 1.0.2 + + arraybuffer.prototype.slice@1.0.3: + dependencies: + array-buffer-byte-length: 1.0.1 + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + is-array-buffer: 3.0.4 + is-shared-array-buffer: 1.0.3 + assertion-error@2.0.1: {} - autoprefixer@10.5.0(postcss@8.5.25): + ast-types-flow@0.0.8: {} + + autoprefixer@10.4.20(postcss@8.4.47): dependencies: - browserslist: 4.28.2 - caniuse-lite: 1.0.30001793 - fraction.js: 5.3.4 + browserslist: 4.24.2 + caniuse-lite: 1.0.30001669 + fraction.js: 4.3.7 + normalize-range: 0.1.2 picocolors: 1.1.1 - postcss: 8.5.25 + postcss: 8.4.47 postcss-value-parser: 4.2.0 - baseline-browser-mapping@2.10.31: {} + available-typed-arrays@1.0.7: + dependencies: + possible-typed-array-names: 1.0.0 - before-after-hook@4.0.0: {} + axe-core@4.10.2: {} + + axobject-query@4.1.0: {} + + balanced-match@1.0.2: {} binary-extensions@2.3.0: {} + brace-expansion@1.1.11: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.1: + dependencies: + balanced-match: 1.0.2 + braces@3.0.3: dependencies: fill-range: 7.1.1 - browserslist@4.28.2: + browserslist@4.23.2: dependencies: - baseline-browser-mapping: 2.10.31 - caniuse-lite: 1.0.30001793 - electron-to-chromium: 1.5.361 - node-releases: 2.0.46 - update-browserslist-db: 1.2.3(browserslist@4.28.2) + caniuse-lite: 1.0.30001669 + electron-to-chromium: 1.5.4 + node-releases: 2.0.18 + update-browserslist-db: 1.1.0(browserslist@4.23.2) - buffer-from@1.1.2: {} - - bun-types@1.3.14: + browserslist@4.24.2: dependencies: - '@types/node': 25.9.1 + caniuse-lite: 1.0.30001669 + electron-to-chromium: 1.5.45 + node-releases: 2.0.18 + update-browserslist-db: 1.1.1(browserslist@4.24.2) - bun@1.3.14: + buffer-from@1.1.2: + optional: true + + bun-types@1.1.34: + dependencies: + '@types/node': 20.12.14 + '@types/ws': 8.5.12 + + bun@1.1.29: optionalDependencies: - '@oven/bun-darwin-aarch64': 1.3.14 - '@oven/bun-darwin-x64': 1.3.14 - '@oven/bun-darwin-x64-baseline': 1.3.14 - '@oven/bun-freebsd-aarch64': 1.3.14 - '@oven/bun-freebsd-x64': 1.3.14 - '@oven/bun-linux-aarch64': 1.3.14 - '@oven/bun-linux-aarch64-android': 1.3.14 - '@oven/bun-linux-aarch64-musl': 1.3.14 - '@oven/bun-linux-x64': 1.3.14 - '@oven/bun-linux-x64-android': 1.3.14 - '@oven/bun-linux-x64-baseline': 1.3.14 - '@oven/bun-linux-x64-musl': 1.3.14 - '@oven/bun-linux-x64-musl-baseline': 1.3.14 - '@oven/bun-windows-aarch64': 1.3.14 - '@oven/bun-windows-x64': 1.3.14 - '@oven/bun-windows-x64-baseline': 1.3.14 + '@oven/bun-darwin-aarch64': 1.1.29 + '@oven/bun-darwin-x64': 1.1.29 + '@oven/bun-darwin-x64-baseline': 1.1.29 + '@oven/bun-linux-aarch64': 1.1.29 + '@oven/bun-linux-x64': 1.1.29 + '@oven/bun-linux-x64-baseline': 1.1.29 + '@oven/bun-windows-x64': 1.1.29 + '@oven/bun-windows-x64-baseline': 1.1.29 - bundle-require@5.1.0(esbuild@0.27.7): + bundle-require@5.0.0(esbuild@0.23.0): dependencies: - esbuild: 0.27.7 + esbuild: 0.23.0 load-tsconfig: 0.2.5 + busboy@1.6.0: + dependencies: + streamsearch: 1.1.0 + cac@6.7.14: {} + call-bind@1.0.7: + dependencies: + es-define-property: 1.0.0 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.4 + set-function-length: 1.2.2 + + callsites@3.1.0: {} + camelcase-css@2.0.1: {} - caniuse-lite@1.0.30001793: {} + caniuse-lite@1.0.30001669: {} - chai@6.2.2: {} + chai@5.1.1: + dependencies: + assertion-error: 2.0.1 + check-error: 2.1.1 + deep-eql: 5.0.2 + loupe: 3.1.1 + pathval: 2.0.0 - chardet@2.1.1: {} + chalk@2.4.2: + dependencies: + ansi-styles: 3.2.1 + escape-string-regexp: 1.0.5 + supports-color: 5.5.0 + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + check-error@2.1.1: {} chokidar@3.6.0: dependencies: @@ -4883,188 +7437,715 @@ snapshots: optionalDependencies: fsevents: 2.3.3 - chokidar@4.0.3: - dependencies: - readdirp: 4.1.2 - - chrome-trace-event@1.0.4: {} - - citty@0.2.2: {} - - cli-width@4.1.0: {} - client-only@0.0.1: {} - clipanion@4.0.0-rc.4(typanion@3.14.0): + color-convert@1.9.3: dependencies: - typanion: 3.14.0 + color-name: 1.1.3 - colorette@2.0.20: {} + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 - commander@2.20.3: {} + color-name@1.1.3: {} + + color-name@1.1.4: {} + + color-string@1.9.1: + dependencies: + color-name: 1.1.4 + simple-swizzle: 0.2.2 + optional: true + + color@4.2.3: + dependencies: + color-convert: 2.0.1 + color-string: 1.9.1 + optional: true + + commander@2.20.3: + optional: true commander@4.1.1: {} - confbox@0.1.8: {} + concat-map@0.0.1: {} - consola@3.4.2: {} - - content-type@2.0.0: {} + consola@3.2.3: {} convert-source-map@2.0.0: {} - cookie-es@1.2.3: {} - - crossws@0.3.5: + cross-spawn@7.0.3: dependencies: - uncrypto: 0.1.3 + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 - crossws@0.4.10: {} + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 cssesc@3.0.0: {} - csstype@3.2.3: {} + csstype@3.1.3: {} - debug@4.4.3: + damerau-levenshtein@1.0.8: {} + + data-view-buffer@1.0.1: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 + + data-view-byte-length@1.0.1: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 + + data-view-byte-offset@1.0.0: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + is-data-view: 1.0.1 + + debug@3.2.7: dependencies: ms: 2.1.3 - dedent@1.7.2: {} + debug@4.3.6: + dependencies: + ms: 2.1.2 - defu@6.1.7: {} + debug@4.3.7: + dependencies: + ms: 2.1.3 - destr@2.0.5: {} + dedent@1.5.3: {} + + deep-eql@5.0.2: {} + + deep-is@0.1.4: {} + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.0 + es-errors: 1.3.0 + gopd: 1.0.1 + + define-properties@1.2.1: + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 detect-libc@1.0.3: {} - detect-libc@2.1.2: {} + detect-libc@2.0.3: + optional: true didyoumean@1.2.2: {} + dir-glob@3.0.1: + dependencies: + path-type: 4.0.0 + dlv@1.1.3: {} - electron-to-chromium@1.5.361: {} + doctrine@2.1.0: + dependencies: + esutils: 2.0.3 - emnapi@1.11.3(node-addon-api@8.7.0): - optionalDependencies: - node-addon-api: 8.7.0 + eastasianwidth@0.2.0: {} - enhanced-resolve@5.24.5: + electron-to-chromium@1.5.4: {} + + electron-to-chromium@1.5.45: {} + + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + + enhanced-resolve@5.17.1: dependencies: graceful-fs: 4.2.11 - tapable: 2.3.3 + tapable: 2.2.1 + + es-abstract@1.23.3: + dependencies: + array-buffer-byte-length: 1.0.1 + arraybuffer.prototype.slice: 1.0.3 + available-typed-arrays: 1.0.7 + call-bind: 1.0.7 + data-view-buffer: 1.0.1 + data-view-byte-length: 1.0.1 + data-view-byte-offset: 1.0.0 + es-define-property: 1.0.0 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + es-set-tostringtag: 2.0.3 + es-to-primitive: 1.2.1 + function.prototype.name: 1.1.6 + get-intrinsic: 1.2.4 + get-symbol-description: 1.0.2 + globalthis: 1.0.4 + gopd: 1.0.1 + has-property-descriptors: 1.0.2 + has-proto: 1.0.3 + has-symbols: 1.0.3 + hasown: 2.0.2 + internal-slot: 1.0.7 + is-array-buffer: 3.0.4 + is-callable: 1.2.7 + is-data-view: 1.0.1 + is-negative-zero: 2.0.3 + is-regex: 1.1.4 + is-shared-array-buffer: 1.0.3 + is-string: 1.0.7 + is-typed-array: 1.1.13 + is-weakref: 1.0.2 + object-inspect: 1.13.2 + object-keys: 1.1.1 + object.assign: 4.1.5 + regexp.prototype.flags: 1.5.2 + safe-array-concat: 1.1.2 + safe-regex-test: 1.0.3 + string.prototype.trim: 1.2.9 + string.prototype.trimend: 1.0.8 + string.prototype.trimstart: 1.0.8 + typed-array-buffer: 1.0.2 + typed-array-byte-length: 1.0.1 + typed-array-byte-offset: 1.0.2 + typed-array-length: 1.0.6 + unbox-primitive: 1.0.2 + which-typed-array: 1.1.15 + + es-define-property@1.0.0: + dependencies: + get-intrinsic: 1.2.4 es-errors@1.3.0: {} - es-module-lexer@2.1.0: {} + es-iterator-helpers@1.1.0: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + es-set-tostringtag: 2.0.3 + function-bind: 1.1.2 + get-intrinsic: 1.2.4 + globalthis: 1.0.4 + has-property-descriptors: 1.0.2 + has-proto: 1.0.3 + has-symbols: 1.0.3 + internal-slot: 1.0.7 + iterator.prototype: 1.1.3 + safe-array-concat: 1.1.2 - es-toolkit@1.50.0: {} + es-object-atoms@1.0.0: + dependencies: + es-errors: 1.3.0 - esbuild@0.27.7: + es-set-tostringtag@2.0.3: + dependencies: + get-intrinsic: 1.2.4 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + es-shim-unscopables@1.0.2: + dependencies: + hasown: 2.0.2 + + es-to-primitive@1.2.1: + dependencies: + is-callable: 1.2.7 + is-date-object: 1.0.5 + is-symbol: 1.0.4 + + esbuild@0.21.5: optionalDependencies: - '@esbuild/aix-ppc64': 0.27.7 - '@esbuild/android-arm': 0.27.7 - '@esbuild/android-arm64': 0.27.7 - '@esbuild/android-x64': 0.27.7 - '@esbuild/darwin-arm64': 0.27.7 - '@esbuild/darwin-x64': 0.27.7 - '@esbuild/freebsd-arm64': 0.27.7 - '@esbuild/freebsd-x64': 0.27.7 - '@esbuild/linux-arm': 0.27.7 - '@esbuild/linux-arm64': 0.27.7 - '@esbuild/linux-ia32': 0.27.7 - '@esbuild/linux-loong64': 0.27.7 - '@esbuild/linux-mips64el': 0.27.7 - '@esbuild/linux-ppc64': 0.27.7 - '@esbuild/linux-riscv64': 0.27.7 - '@esbuild/linux-s390x': 0.27.7 - '@esbuild/linux-x64': 0.27.7 - '@esbuild/netbsd-arm64': 0.27.7 - '@esbuild/netbsd-x64': 0.27.7 - '@esbuild/openbsd-arm64': 0.27.7 - '@esbuild/openbsd-x64': 0.27.7 - '@esbuild/openharmony-arm64': 0.27.7 - '@esbuild/sunos-x64': 0.27.7 - '@esbuild/win32-arm64': 0.27.7 - '@esbuild/win32-ia32': 0.27.7 - '@esbuild/win32-x64': 0.27.7 + '@esbuild/aix-ppc64': 0.21.5 + '@esbuild/android-arm': 0.21.5 + '@esbuild/android-arm64': 0.21.5 + '@esbuild/android-x64': 0.21.5 + '@esbuild/darwin-arm64': 0.21.5 + '@esbuild/darwin-x64': 0.21.5 + '@esbuild/freebsd-arm64': 0.21.5 + '@esbuild/freebsd-x64': 0.21.5 + '@esbuild/linux-arm': 0.21.5 + '@esbuild/linux-arm64': 0.21.5 + '@esbuild/linux-ia32': 0.21.5 + '@esbuild/linux-loong64': 0.21.5 + '@esbuild/linux-mips64el': 0.21.5 + '@esbuild/linux-ppc64': 0.21.5 + '@esbuild/linux-riscv64': 0.21.5 + '@esbuild/linux-s390x': 0.21.5 + '@esbuild/linux-x64': 0.21.5 + '@esbuild/netbsd-x64': 0.21.5 + '@esbuild/openbsd-x64': 0.21.5 + '@esbuild/sunos-x64': 0.21.5 + '@esbuild/win32-arm64': 0.21.5 + '@esbuild/win32-ia32': 0.21.5 + '@esbuild/win32-x64': 0.21.5 + + esbuild@0.23.0: + optionalDependencies: + '@esbuild/aix-ppc64': 0.23.0 + '@esbuild/android-arm': 0.23.0 + '@esbuild/android-arm64': 0.23.0 + '@esbuild/android-x64': 0.23.0 + '@esbuild/darwin-arm64': 0.23.0 + '@esbuild/darwin-x64': 0.23.0 + '@esbuild/freebsd-arm64': 0.23.0 + '@esbuild/freebsd-x64': 0.23.0 + '@esbuild/linux-arm': 0.23.0 + '@esbuild/linux-arm64': 0.23.0 + '@esbuild/linux-ia32': 0.23.0 + '@esbuild/linux-loong64': 0.23.0 + '@esbuild/linux-mips64el': 0.23.0 + '@esbuild/linux-ppc64': 0.23.0 + '@esbuild/linux-riscv64': 0.23.0 + '@esbuild/linux-s390x': 0.23.0 + '@esbuild/linux-x64': 0.23.0 + '@esbuild/netbsd-x64': 0.23.0 + '@esbuild/openbsd-arm64': 0.23.0 + '@esbuild/openbsd-x64': 0.23.0 + '@esbuild/sunos-x64': 0.23.0 + '@esbuild/win32-arm64': 0.23.0 + '@esbuild/win32-ia32': 0.23.0 + '@esbuild/win32-x64': 0.23.0 + + esbuild@0.23.1: + optionalDependencies: + '@esbuild/aix-ppc64': 0.23.1 + '@esbuild/android-arm': 0.23.1 + '@esbuild/android-arm64': 0.23.1 + '@esbuild/android-x64': 0.23.1 + '@esbuild/darwin-arm64': 0.23.1 + '@esbuild/darwin-x64': 0.23.1 + '@esbuild/freebsd-arm64': 0.23.1 + '@esbuild/freebsd-x64': 0.23.1 + '@esbuild/linux-arm': 0.23.1 + '@esbuild/linux-arm64': 0.23.1 + '@esbuild/linux-ia32': 0.23.1 + '@esbuild/linux-loong64': 0.23.1 + '@esbuild/linux-mips64el': 0.23.1 + '@esbuild/linux-ppc64': 0.23.1 + '@esbuild/linux-riscv64': 0.23.1 + '@esbuild/linux-s390x': 0.23.1 + '@esbuild/linux-x64': 0.23.1 + '@esbuild/netbsd-x64': 0.23.1 + '@esbuild/openbsd-arm64': 0.23.1 + '@esbuild/openbsd-x64': 0.23.1 + '@esbuild/sunos-x64': 0.23.1 + '@esbuild/win32-arm64': 0.23.1 + '@esbuild/win32-ia32': 0.23.1 + '@esbuild/win32-x64': 0.23.1 + optional: true + + esbuild@0.24.0: + optionalDependencies: + '@esbuild/aix-ppc64': 0.24.0 + '@esbuild/android-arm': 0.24.0 + '@esbuild/android-arm64': 0.24.0 + '@esbuild/android-x64': 0.24.0 + '@esbuild/darwin-arm64': 0.24.0 + '@esbuild/darwin-x64': 0.24.0 + '@esbuild/freebsd-arm64': 0.24.0 + '@esbuild/freebsd-x64': 0.24.0 + '@esbuild/linux-arm': 0.24.0 + '@esbuild/linux-arm64': 0.24.0 + '@esbuild/linux-ia32': 0.24.0 + '@esbuild/linux-loong64': 0.24.0 + '@esbuild/linux-mips64el': 0.24.0 + '@esbuild/linux-ppc64': 0.24.0 + '@esbuild/linux-riscv64': 0.24.0 + '@esbuild/linux-s390x': 0.24.0 + '@esbuild/linux-x64': 0.24.0 + '@esbuild/netbsd-x64': 0.24.0 + '@esbuild/openbsd-arm64': 0.24.0 + '@esbuild/openbsd-x64': 0.24.0 + '@esbuild/sunos-x64': 0.24.0 + '@esbuild/win32-arm64': 0.24.0 + '@esbuild/win32-ia32': 0.24.0 + '@esbuild/win32-x64': 0.24.0 + + escalade@3.1.2: {} escalade@3.2.0: {} - eslint-scope@5.1.1: + escape-string-regexp@1.0.5: {} + + escape-string-regexp@4.0.0: {} + + eslint-config-next@15.0.3(eslint@9.15.0(jiti@2.4.0))(typescript@5.5.4): + dependencies: + '@next/eslint-plugin-next': 15.0.3 + '@rushstack/eslint-patch': 1.10.4 + '@typescript-eslint/eslint-plugin': 8.11.0(@typescript-eslint/parser@8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.5.4))(eslint@9.15.0(jiti@2.4.0))(typescript@5.5.4) + '@typescript-eslint/parser': 8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.5.4) + eslint: 9.15.0(jiti@2.4.0) + eslint-import-resolver-node: 0.3.9 + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@9.15.0(jiti@2.4.0)) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.5.4))(eslint-import-resolver-typescript@3.6.3)(eslint@9.15.0(jiti@2.4.0)) + eslint-plugin-jsx-a11y: 6.10.1(eslint@9.15.0(jiti@2.4.0)) + eslint-plugin-react: 7.37.2(eslint@9.15.0(jiti@2.4.0)) + eslint-plugin-react-hooks: 5.0.0(eslint@9.15.0(jiti@2.4.0)) + optionalDependencies: + typescript: 5.5.4 + transitivePeerDependencies: + - eslint-import-resolver-webpack + - eslint-plugin-import-x + - supports-color + + eslint-config-next@15.0.3(eslint@9.15.0(jiti@2.4.0))(typescript@5.6.3): + dependencies: + '@next/eslint-plugin-next': 15.0.3 + '@rushstack/eslint-patch': 1.10.4 + '@typescript-eslint/eslint-plugin': 8.11.0(@typescript-eslint/parser@8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.15.0(jiti@2.4.0))(typescript@5.6.3) + '@typescript-eslint/parser': 8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.6.3) + eslint: 9.15.0(jiti@2.4.0) + eslint-import-resolver-node: 0.3.9 + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@9.15.0(jiti@2.4.0)) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.15.0(jiti@2.4.0)) + eslint-plugin-jsx-a11y: 6.10.1(eslint@9.15.0(jiti@2.4.0)) + eslint-plugin-react: 7.37.2(eslint@9.15.0(jiti@2.4.0)) + eslint-plugin-react-hooks: 5.0.0(eslint@9.15.0(jiti@2.4.0)) + optionalDependencies: + typescript: 5.6.3 + transitivePeerDependencies: + - eslint-import-resolver-webpack + - eslint-plugin-import-x + - supports-color + + eslint-import-resolver-node@0.3.9: + dependencies: + debug: 3.2.7 + is-core-module: 2.15.1 + resolve: 1.22.8 + transitivePeerDependencies: + - supports-color + + eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@9.15.0(jiti@2.4.0)): + dependencies: + '@nolyfill/is-core-module': 1.0.39 + debug: 4.3.7 + enhanced-resolve: 5.17.1 + eslint: 9.15.0(jiti@2.4.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@9.15.0(jiti@2.4.0)))(eslint@9.15.0(jiti@2.4.0)) + fast-glob: 3.3.2 + get-tsconfig: 4.8.1 + is-bun-module: 1.2.1 + is-glob: 4.0.3 + optionalDependencies: + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.5.4))(eslint-import-resolver-typescript@3.6.3)(eslint@9.15.0(jiti@2.4.0)) + transitivePeerDependencies: + - '@typescript-eslint/parser' + - eslint-import-resolver-node + - eslint-import-resolver-webpack + - supports-color + + eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@9.15.0(jiti@2.4.0)): + dependencies: + '@nolyfill/is-core-module': 1.0.39 + debug: 4.3.7 + enhanced-resolve: 5.17.1 + eslint: 9.15.0(jiti@2.4.0) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@9.15.0(jiti@2.4.0)))(eslint@9.15.0(jiti@2.4.0)) + fast-glob: 3.3.2 + get-tsconfig: 4.8.1 + is-bun-module: 1.2.1 + is-glob: 4.0.3 + optionalDependencies: + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.15.0(jiti@2.4.0)) + transitivePeerDependencies: + - '@typescript-eslint/parser' + - eslint-import-resolver-node + - eslint-import-resolver-webpack + - supports-color + + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@9.15.0(jiti@2.4.0)))(eslint@9.15.0(jiti@2.4.0)): + dependencies: + debug: 3.2.7 + optionalDependencies: + '@typescript-eslint/parser': 8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.5.4) + eslint: 9.15.0(jiti@2.4.0) + eslint-import-resolver-node: 0.3.9 + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@9.15.0(jiti@2.4.0)) + transitivePeerDependencies: + - supports-color + + eslint-module-utils@2.12.0(@typescript-eslint/parser@8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@9.15.0(jiti@2.4.0)))(eslint@9.15.0(jiti@2.4.0)): + dependencies: + debug: 3.2.7 + optionalDependencies: + '@typescript-eslint/parser': 8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.6.3) + eslint: 9.15.0(jiti@2.4.0) + eslint-import-resolver-node: 0.3.9 + eslint-import-resolver-typescript: 3.6.3(@typescript-eslint/parser@8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@9.15.0(jiti@2.4.0)) + transitivePeerDependencies: + - supports-color + + eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.5.4))(eslint-import-resolver-typescript@3.6.3)(eslint@9.15.0(jiti@2.4.0)): + dependencies: + '@rtsao/scc': 1.1.0 + array-includes: 3.1.8 + array.prototype.findlastindex: 1.2.5 + array.prototype.flat: 1.3.2 + array.prototype.flatmap: 1.3.2 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 9.15.0(jiti@2.4.0) + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.5.4))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@9.15.0(jiti@2.4.0)))(eslint@9.15.0(jiti@2.4.0)) + hasown: 2.0.2 + is-core-module: 2.15.1 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 + object.values: 1.2.0 + semver: 6.3.1 + string.prototype.trimend: 1.0.8 + tsconfig-paths: 3.15.0 + optionalDependencies: + '@typescript-eslint/parser': 8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.5.4) + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + + eslint-plugin-import@2.31.0(@typescript-eslint/parser@8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.6.3))(eslint@9.15.0(jiti@2.4.0)): + dependencies: + '@rtsao/scc': 1.1.0 + array-includes: 3.1.8 + array.prototype.findlastindex: 1.2.5 + array.prototype.flat: 1.3.2 + array.prototype.flatmap: 1.3.2 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 9.15.0(jiti@2.4.0) + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.12.0(@typescript-eslint/parser@8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.6.3))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0)(eslint@9.15.0(jiti@2.4.0)))(eslint@9.15.0(jiti@2.4.0)) + hasown: 2.0.2 + is-core-module: 2.15.1 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 + object.values: 1.2.0 + semver: 6.3.1 + string.prototype.trimend: 1.0.8 + tsconfig-paths: 3.15.0 + optionalDependencies: + '@typescript-eslint/parser': 8.11.0(eslint@9.15.0(jiti@2.4.0))(typescript@5.6.3) + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + + eslint-plugin-jsx-a11y@6.10.1(eslint@9.15.0(jiti@2.4.0)): + dependencies: + aria-query: 5.3.2 + array-includes: 3.1.8 + array.prototype.flatmap: 1.3.2 + ast-types-flow: 0.0.8 + axe-core: 4.10.2 + axobject-query: 4.1.0 + damerau-levenshtein: 1.0.8 + emoji-regex: 9.2.2 + es-iterator-helpers: 1.1.0 + eslint: 9.15.0(jiti@2.4.0) + hasown: 2.0.2 + jsx-ast-utils: 3.3.5 + language-tags: 1.0.9 + minimatch: 3.1.2 + object.fromentries: 2.0.8 + safe-regex-test: 1.0.3 + string.prototype.includes: 2.0.1 + + eslint-plugin-react-hooks@5.0.0(eslint@9.15.0(jiti@2.4.0)): + dependencies: + eslint: 9.15.0(jiti@2.4.0) + + eslint-plugin-react@7.37.2(eslint@9.15.0(jiti@2.4.0)): + dependencies: + array-includes: 3.1.8 + array.prototype.findlast: 1.2.5 + array.prototype.flatmap: 1.3.2 + array.prototype.tosorted: 1.1.4 + doctrine: 2.1.0 + es-iterator-helpers: 1.1.0 + eslint: 9.15.0(jiti@2.4.0) + estraverse: 5.3.0 + hasown: 2.0.2 + jsx-ast-utils: 3.3.5 + minimatch: 3.1.2 + object.entries: 1.1.8 + object.fromentries: 2.0.8 + object.values: 1.2.0 + prop-types: 15.8.1 + resolve: 2.0.0-next.5 + semver: 6.3.1 + string.prototype.matchall: 4.0.11 + string.prototype.repeat: 1.0.0 + + eslint-scope@8.2.0: dependencies: esrecurse: 4.3.0 - estraverse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.2.0: {} + + eslint@9.15.0(jiti@2.4.0): + dependencies: + '@eslint-community/eslint-utils': 4.4.0(eslint@9.15.0(jiti@2.4.0)) + '@eslint-community/regexpp': 4.12.1 + '@eslint/config-array': 0.19.0 + '@eslint/core': 0.9.0 + '@eslint/eslintrc': 3.2.0 + '@eslint/js': 9.15.0 + '@eslint/plugin-kit': 0.2.3 + '@humanfs/node': 0.16.6 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.1 + '@types/estree': 1.0.6 + '@types/json-schema': 7.0.15 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.3.7 + escape-string-regexp: 4.0.0 + eslint-scope: 8.2.0 + eslint-visitor-keys: 4.2.0 + espree: 10.3.0 + esquery: 1.6.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + optionalDependencies: + jiti: 2.4.0 + transitivePeerDependencies: + - supports-color + + espree@10.3.0: + dependencies: + acorn: 8.14.0 + acorn-jsx: 5.3.2(acorn@8.14.0) + eslint-visitor-keys: 4.2.0 + + esquery@1.6.0: + dependencies: + estraverse: 5.3.0 esrecurse@4.3.0: dependencies: estraverse: 5.3.0 - estraverse@4.3.0: {} - estraverse@5.3.0: {} estree-walker@3.0.3: dependencies: - '@types/estree': 1.0.9 + '@types/estree': 1.0.6 - events@3.3.0: {} + esutils@2.0.3: {} - expect-type@1.3.0: {} + execa@5.1.1: + dependencies: + cross-spawn: 7.0.3 + get-stream: 6.0.1 + human-signals: 2.1.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 - fast-content-type-parse@3.0.0: {} + execa@8.0.1: + dependencies: + cross-spawn: 7.0.3 + get-stream: 8.0.1 + human-signals: 5.0.0 + is-stream: 3.0.0 + merge-stream: 2.0.0 + npm-run-path: 5.3.0 + onetime: 6.0.0 + signal-exit: 4.1.0 + strip-final-newline: 3.0.0 fast-deep-equal@3.1.3: {} - fast-equals@5.4.0: {} - - fast-glob@3.3.3: + fast-glob@3.3.1: dependencies: '@nodelib/fs.stat': 2.0.5 '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 - micromatch: 4.0.8 + micromatch: 4.0.7 - fast-string-truncated-width@3.0.3: {} - - fast-string-width@3.0.2: + fast-glob@3.3.2: dependencies: - fast-string-truncated-width: 3.0.3 + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.7 - fast-stringify@4.0.0: {} + fast-json-stable-stringify@2.1.0: {} - fast-uri@3.1.2: {} + fast-levenshtein@2.0.6: {} - fast-wrap-ansi@0.2.2: + fastq@1.17.1: dependencies: - fast-string-width: 3.0.2 + reusify: 1.0.4 - fastq@1.20.1: + file-entry-cache@8.0.0: dependencies: - reusify: 1.1.0 - - fdir@6.5.0(picomatch@4.0.4): - optionalDependencies: - picomatch: 4.0.4 - - fdir@6.5.0(picomatch@4.0.5): - optionalDependencies: - picomatch: 4.0.5 + flat-cache: 4.0.1 fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 - find-up-simple@1.0.1: {} + find-up-simple@1.0.0: {} - fix-dts-default-cjs-exports@1.0.1: + find-up@5.0.0: dependencies: - magic-string: 0.30.21 - mlly: 1.8.2 - rollup: 4.60.4 + locate-path: 6.0.0 + path-exists: 4.0.0 - fraction.js@5.3.4: {} + flat-cache@4.0.1: + dependencies: + flatted: 3.3.1 + keyv: 4.5.4 + + flatted@3.3.1: {} + + for-each@0.3.3: + dependencies: + is-callable: 1.2.7 + + foreground-child@3.3.0: + dependencies: + cross-spawn: 7.0.3 + signal-exit: 4.1.0 + + fraction.js@4.3.7: {} fsevents@2.3.2: optional: true @@ -5074,7 +8155,40 @@ snapshots: function-bind@1.1.2: {} - get-port-please@3.2.0: {} + function.prototype.name@1.1.6: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + functions-have-names: 1.2.3 + + functions-have-names@1.2.3: {} + + gensync@1.0.0-beta.2: {} + + get-func-name@2.0.2: {} + + get-intrinsic@1.2.4: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + has-proto: 1.0.3 + has-symbols: 1.0.3 + hasown: 2.0.2 + + get-stream@6.0.1: {} + + get-stream@8.0.1: {} + + get-symbol-description@1.0.2: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + + get-tsconfig@4.8.1: + dependencies: + resolve-pkg-maps: 1.0.0 glob-parent@5.1.2: dependencies: @@ -5084,203 +8198,380 @@ snapshots: dependencies: is-glob: 4.0.3 - globby@16.2.2: + glob@10.4.5: dependencies: - '@sindresorhus/merge-streams': 4.0.0 - fast-glob: 3.3.3 - ignore: 7.0.5 - is-path-inside: 4.0.0 + foreground-child: 3.3.0 + jackspeak: 3.4.3 + minimatch: 9.0.5 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + + globals@11.12.0: {} + + globals@14.0.0: {} + + globalthis@1.0.4: + dependencies: + define-properties: 1.2.1 + gopd: 1.0.1 + + globby@11.1.0: + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.2 + ignore: 5.3.2 + merge2: 1.4.1 + slash: 3.0.0 + + globby@14.0.2: + dependencies: + '@sindresorhus/merge-streams': 2.3.0 + fast-glob: 3.3.2 + ignore: 5.3.1 + path-type: 5.0.0 slash: 5.1.0 - unicorn-magic: 0.4.0 + unicorn-magic: 0.1.0 + + gopd@1.0.1: + dependencies: + get-intrinsic: 1.2.4 graceful-fs@4.2.11: {} - h3@1.15.11: - dependencies: - cookie-es: 1.2.3 - crossws: 0.3.5 - defu: 6.1.7 - destr: 2.0.5 - iron-webcrypto: 1.2.1 - node-mock-http: 1.0.4 - radix3: 1.1.2 - ufo: 1.6.4 - uncrypto: 0.1.3 + graphemer@1.4.0: {} + + has-bigints@1.0.2: {} + + has-flag@3.0.0: {} has-flag@4.0.0: {} - hasown@2.0.3: + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.0 + + has-proto@1.0.3: {} + + has-symbols@1.0.3: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.0.3 + + hasown@2.0.2: dependencies: function-bind: 1.1.2 - http-shutdown@1.2.2: {} + human-signals@2.1.0: {} - iconv-lite@0.7.2: + human-signals@5.0.0: {} + + ignore@5.3.1: {} + + ignore@5.3.2: {} + + import-fresh@3.3.0: dependencies: - safer-buffer: 2.1.2 + parent-module: 1.0.1 + resolve-from: 4.0.0 - ignore@7.0.5: {} + imurmurhash@0.1.4: {} - iron-webcrypto@1.2.1: {} + internal-slot@1.0.7: + dependencies: + es-errors: 1.3.0 + hasown: 2.0.2 + side-channel: 1.0.6 + + is-array-buffer@3.0.4: + dependencies: + call-bind: 1.0.7 + get-intrinsic: 1.2.4 + + is-arrayish@0.3.2: + optional: true + + is-async-function@2.0.0: + dependencies: + has-tostringtag: 1.0.2 + + is-bigint@1.0.4: + dependencies: + has-bigints: 1.0.2 is-binary-path@2.1.0: dependencies: binary-extensions: 2.3.0 - is-core-module@2.16.2: + is-boolean-object@1.1.2: dependencies: - hasown: 2.0.3 + call-bind: 1.0.7 + has-tostringtag: 1.0.2 + + is-bun-module@1.2.1: + dependencies: + semver: 7.6.3 + + is-callable@1.2.7: {} + + is-core-module@2.15.0: + dependencies: + hasown: 2.0.2 + + is-core-module@2.15.1: + dependencies: + hasown: 2.0.2 + + is-data-view@1.0.1: + dependencies: + is-typed-array: 1.1.13 + + is-date-object@1.0.5: + dependencies: + has-tostringtag: 1.0.2 is-extglob@2.1.1: {} + is-finalizationregistry@1.0.2: + dependencies: + call-bind: 1.0.7 + + is-fullwidth-code-point@3.0.0: {} + + is-generator-function@1.0.10: + dependencies: + has-tostringtag: 1.0.2 + is-glob@4.0.3: dependencies: is-extglob: 2.1.1 + is-map@2.0.3: {} + + is-negative-zero@2.0.3: {} + + is-number-object@1.0.7: + dependencies: + has-tostringtag: 1.0.2 + is-number@7.0.0: {} - is-path-inside@4.0.0: {} - - jest-worker@27.5.1: + is-regex@1.1.4: dependencies: - '@types/node': 25.9.1 - merge-stream: 2.0.0 - supports-color: 8.1.1 + call-bind: 1.0.7 + has-tostringtag: 1.0.2 - jiti@1.21.7: {} + is-set@2.0.3: {} - jiti@2.7.0: {} + is-shared-array-buffer@1.0.3: + dependencies: + call-bind: 1.0.7 + + is-stream@2.0.1: {} + + is-stream@3.0.0: {} + + is-string@1.0.7: + dependencies: + has-tostringtag: 1.0.2 + + is-symbol@1.0.4: + dependencies: + has-symbols: 1.0.3 + + is-typed-array@1.1.13: + dependencies: + which-typed-array: 1.1.15 + + is-weakmap@2.0.2: {} + + is-weakref@1.0.2: + dependencies: + call-bind: 1.0.7 + + is-weakset@2.0.3: + dependencies: + call-bind: 1.0.7 + get-intrinsic: 1.2.4 + + isarray@2.0.5: {} + + isexe@2.0.0: {} + + iterator.prototype@1.1.3: + dependencies: + define-properties: 1.2.1 + get-intrinsic: 1.2.4 + has-symbols: 1.0.3 + reflect.getprototypeof: 1.0.6 + set-function-name: 2.0.2 + + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + jiti@1.21.6: {} + + jiti@2.4.0: {} joycon@3.1.1: {} - js-yaml@4.3.1: + js-tokens@4.0.0: {} + + js-yaml@4.1.0: dependencies: argparse: 2.0.1 - json-schema-traverse@1.0.0: {} + jsesc@2.5.2: {} - json-with-bigint@3.5.8: {} + json-buffer@3.0.1: {} - lightningcss-android-arm64@1.33.0: - optional: true + json-schema-traverse@0.4.1: {} - lightningcss-darwin-arm64@1.33.0: {} + json-stable-stringify-without-jsonify@1.0.1: {} - lightningcss-darwin-x64@1.33.0: {} - - lightningcss-freebsd-x64@1.33.0: - optional: true - - lightningcss-linux-arm-gnueabihf@1.33.0: - optional: true - - lightningcss-linux-arm64-gnu@1.33.0: {} - - lightningcss-linux-arm64-musl@1.33.0: {} - - lightningcss-linux-x64-gnu@1.33.0: {} - - lightningcss-linux-x64-musl@1.33.0: {} - - lightningcss-win32-arm64-msvc@1.33.0: - optional: true - - lightningcss-win32-x64-msvc@1.33.0: {} - - lightningcss@1.33.0(patch_hash=1d4a8800d60d13d42887b88b3a86576df4b451670308145fb432ec8abbf40930): + json5@1.0.2: dependencies: - detect-libc: 2.1.2 - optionalDependencies: - lightningcss-android-arm64: 1.33.0 - lightningcss-darwin-arm64: 1.33.0 - lightningcss-darwin-x64: 1.33.0 - lightningcss-freebsd-x64: 1.33.0 - lightningcss-linux-arm-gnueabihf: 1.33.0 - lightningcss-linux-arm64-gnu: 1.33.0 - lightningcss-linux-arm64-musl: 1.33.0 - lightningcss-linux-x64-gnu: 1.33.0 - lightningcss-linux-x64-musl: 1.33.0 - lightningcss-win32-arm64-msvc: 1.33.0 - lightningcss-win32-x64-msvc: 1.33.0 + minimist: 1.2.8 - lilconfig@3.1.3: {} + json5@2.2.3: {} + + jsx-ast-utils@3.3.5: + dependencies: + array-includes: 3.1.8 + array.prototype.flat: 1.3.2 + object.assign: 4.1.5 + object.values: 1.2.0 + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + language-subtag-registry@0.3.23: {} + + language-tags@1.0.9: + dependencies: + language-subtag-registry: 0.3.23 + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + lightningcss-darwin-arm64@1.26.0: {} + + lightningcss-darwin-x64@1.26.0: {} + + lightningcss-freebsd-x64@1.26.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.26.0: + optional: true + + lightningcss-linux-arm64-gnu@1.26.0: {} + + lightningcss-linux-arm64-musl@1.26.0: {} + + lightningcss-linux-x64-gnu@1.26.0: {} + + lightningcss-linux-x64-musl@1.26.0: {} + + lightningcss-win32-arm64-msvc@1.26.0: + optional: true + + lightningcss-win32-x64-msvc@1.26.0: {} + + lightningcss@1.26.0(patch_hash=5hwfyehqvg5wjb7mwtdvubqbl4): + dependencies: + detect-libc: 1.0.3 + optionalDependencies: + lightningcss-darwin-arm64: 1.26.0 + lightningcss-darwin-x64: 1.26.0 + lightningcss-freebsd-x64: 1.26.0 + lightningcss-linux-arm-gnueabihf: 1.26.0 + lightningcss-linux-arm64-gnu: 1.26.0 + lightningcss-linux-arm64-musl: 1.26.0 + lightningcss-linux-x64-gnu: 1.26.0 + lightningcss-linux-x64-musl: 1.26.0 + lightningcss-win32-arm64-msvc: 1.26.0 + lightningcss-win32-x64-msvc: 1.26.0 + + lilconfig@2.1.0: {} + + lilconfig@3.1.2: {} lines-and-columns@1.2.4: {} - listhen@1.10.1(@parcel/watcher@2.6.0(patch_hash=705ce75ccea54337110c4d7fe0a8b421658ea0c23e1a77c1fa890a86041179da)): - dependencies: - '@parcel/watcher-wasm': 2.5.6 - citty: 0.2.2 - consola: 3.4.2 - crossws: 0.4.10 - defu: 6.1.7 - get-port-please: 3.2.0 - h3: 1.15.11 - http-shutdown: 1.2.2 - jiti: 2.7.0 - node-forge: 1.4.0 - pathe: 2.0.3 - std-env: 4.2.0 - tinyclip: 0.1.15 - ufo: 1.6.4 - untun: 0.2.2 - uqr: 0.1.3 - optionalDependencies: - '@parcel/watcher': 2.6.0(patch_hash=705ce75ccea54337110c4d7fe0a8b421658ea0c23e1a77c1fa890a86041179da) - transitivePeerDependencies: - - srvx - load-tsconfig@0.2.5: {} - magic-string@0.30.21: + locate-path@6.0.0: dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 + p-locate: 5.0.0 - magic-string@1.1.0: + lodash.castarray@4.4.0: {} + + lodash.isplainobject@4.0.6: {} + + lodash.merge@4.6.2: {} + + lodash.sortby@4.7.0: {} + + loose-envify@1.4.0: dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 + js-tokens: 4.0.0 + + loupe@3.1.1: + dependencies: + get-func-name: 2.0.2 + + lru-cache@10.4.3: {} + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + magic-string@0.30.11: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 merge-stream@2.0.0: {} merge2@1.4.1: {} - micro-memoize@5.1.1: - dependencies: - fast-equals: 5.4.0 - fast-stringify: 4.0.0 + micro-memoize@4.1.2: {} - micromatch@4.0.8: + micromatch@4.0.7: dependencies: braces: 3.0.3 - picomatch: 2.3.2 + picomatch: 2.3.1 - mime-db@1.54.0: {} + mimic-fn@2.1.0: {} + + mimic-fn@4.0.0: {} mini-svg-data-uri@1.4.4: {} - minimizer-webpack-plugin@5.6.1(esbuild@0.27.7)(postcss@8.5.25)(webpack@5.109.2(esbuild@0.27.7)(postcss@8.5.25)): + minimatch@3.1.2: dependencies: - '@jridgewell/trace-mapping': 0.3.31 - jest-worker: 27.5.1 - schema-utils: 4.3.3 - terser: 5.48.0 - webpack: 5.109.2(esbuild@0.27.7)(postcss@8.5.25) - optionalDependencies: - esbuild: 0.27.7 - postcss: 8.5.25 + brace-expansion: 1.1.11 - mlly@1.8.2: + minimatch@9.0.5: dependencies: - acorn: 8.16.0 - pathe: 2.0.3 - pkg-types: 1.3.1 - ufo: 1.6.4 + brace-expansion: 2.0.1 + + minimist@1.2.8: {} + + minipass@7.1.2: {} mri@1.2.0: {} - ms@2.1.3: {} + ms@2.1.2: {} - mute-stream@3.0.0: {} + ms@2.1.3: {} mz@2.7.0: dependencies: @@ -5288,131 +8579,215 @@ snapshots: object-assign: 4.1.1 thenify-all: 1.6.0 - nanoid@3.3.12: {} + nanoid@3.3.7: {} - nanoid@3.3.16: {} + natural-compare@1.4.0: {} - neo-async@2.6.2: {} - - next@16.2.7(@playwright/test@1.62.1)(react-dom@19.2.7(react@19.2.7))(react@19.2.7): + next@15.0.3(@playwright/test@1.49.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): dependencies: - '@next/env': 16.2.7 - '@swc/helpers': 0.5.15 - baseline-browser-mapping: 2.10.31 - caniuse-lite: 1.0.30001793 + '@next/env': 15.0.3 + '@swc/counter': 0.1.3 + '@swc/helpers': 0.5.13 + busboy: 1.6.0 + caniuse-lite: 1.0.30001669 postcss: 8.4.31 - react: 19.2.7 - react-dom: 19.2.7(react@19.2.7) - styled-jsx: 5.1.6(react@19.2.7) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + styled-jsx: 5.1.6(react@18.3.1) optionalDependencies: - '@next/swc-darwin-arm64': 16.2.7 - '@next/swc-darwin-x64': 16.2.7 - '@next/swc-linux-arm64-gnu': 16.2.7 - '@next/swc-linux-arm64-musl': 16.2.7 - '@next/swc-linux-x64-gnu': 16.2.7 - '@next/swc-linux-x64-musl': 16.2.7 - '@next/swc-win32-arm64-msvc': 16.2.7 - '@next/swc-win32-x64-msvc': 16.2.7 - '@playwright/test': 1.62.1 - sharp: 0.34.5 + '@next/swc-darwin-arm64': 15.0.3 + '@next/swc-darwin-x64': 15.0.3 + '@next/swc-linux-arm64-gnu': 15.0.3 + '@next/swc-linux-arm64-musl': 15.0.3 + '@next/swc-linux-x64-gnu': 15.0.3 + '@next/swc-linux-x64-musl': 15.0.3 + '@next/swc-win32-arm64-msvc': 15.0.3 + '@next/swc-win32-x64-msvc': 15.0.3 + '@playwright/test': 1.49.0 + sharp: 0.33.5 transitivePeerDependencies: - '@babel/core' - babel-plugin-macros node-addon-api@7.1.1: {} - node-addon-api@8.7.0: {} + node-addon-api@8.2.2: {} - node-forge@1.4.0: {} + node-gyp-build@4.8.2: {} - node-gyp-build@4.8.4: {} - - node-mock-http@1.0.4: {} - - node-releases@2.0.46: {} + node-releases@2.0.18: {} normalize-path@3.0.0: {} + normalize-range@0.1.2: {} + + npm-run-path@4.0.1: + dependencies: + path-key: 3.1.1 + + npm-run-path@5.3.0: + dependencies: + path-key: 4.0.0 + object-assign@4.1.1: {} object-hash@3.0.0: {} - obug@2.1.1: {} + object-inspect@1.13.2: {} - obug@2.1.4: {} + object-keys@1.1.1: {} + + object.assign@4.1.5: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + has-symbols: 1.0.3 + object-keys: 1.1.1 + + object.entries@1.1.8: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + + object.fromentries@2.0.8: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 + + object.groupby@1.0.3: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + + object.values@1.2.0: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + + onetime@5.1.2: + dependencies: + mimic-fn: 2.1.0 + + onetime@6.0.0: + dependencies: + mimic-fn: 4.0.0 + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + package-json-from-dist@1.0.1: {} package-up@5.0.0: dependencies: - find-up-simple: 1.0.1 + find-up-simple: 1.0.0 + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + path-exists@4.0.0: {} + + path-key@3.1.1: {} + + path-key@4.0.0: {} path-parse@1.0.7: {} - pathe@2.0.3: {} + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.2 + + path-type@4.0.0: {} + + path-type@5.0.0: {} + + pathe@1.1.2: {} + + pathval@2.0.0: {} picocolors@1.1.1: {} - picomatch@2.3.2: {} - - picomatch@4.0.4: {} - - picomatch@4.0.5: {} + picomatch@2.3.1: {} pify@2.3.0: {} - pirates@4.0.7: {} + pirates@4.0.6: {} - pkg-types@1.3.1: + playwright-core@1.49.0: {} + + playwright@1.49.0: dependencies: - confbox: 0.1.8 - mlly: 1.8.2 - pathe: 2.0.3 - - playwright-core@1.62.1: {} - - playwright@1.62.1: - dependencies: - playwright-core: 1.62.1 + playwright-core: 1.49.0 optionalDependencies: fsevents: 2.3.2 - postcss-import@15.1.0(postcss@8.5.16): + possible-typed-array-names@1.0.0: {} + + postcss-import@15.1.0(postcss@8.4.47): dependencies: - postcss: 8.5.16 + postcss: 8.4.47 postcss-value-parser: 4.2.0 read-cache: 1.0.0 - resolve: 1.22.12 + resolve: 1.22.8 - postcss-import@16.1.1(postcss@8.5.25): + postcss-import@16.1.0(postcss@8.4.41): dependencies: - postcss: 8.5.25 + postcss: 8.4.41 postcss-value-parser: 4.2.0 read-cache: 1.0.0 - resolve: 1.22.12 + resolve: 1.22.8 - postcss-js@4.1.0(postcss@8.5.16): + postcss-import@16.1.0(postcss@8.4.49): + dependencies: + postcss: 8.4.49 + postcss-value-parser: 4.2.0 + read-cache: 1.0.0 + resolve: 1.22.8 + + postcss-js@4.0.1(postcss@8.4.47): dependencies: camelcase-css: 2.0.1 - postcss: 8.5.16 + postcss: 8.4.47 - postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.16)(yaml@2.9.0): + postcss-load-config@4.0.2(postcss@8.4.47): dependencies: - lilconfig: 3.1.3 + lilconfig: 3.1.2 + yaml: 2.6.0 optionalDependencies: - jiti: 1.21.7 - postcss: 8.5.16 - yaml: 2.9.0 + postcss: 8.4.47 - postcss-load-config@6.0.1(jiti@2.7.0)(postcss@8.5.25)(yaml@2.9.0): + postcss-load-config@6.0.1(jiti@2.4.0)(postcss@8.4.49)(tsx@4.19.1)(yaml@2.6.0): dependencies: - lilconfig: 3.1.3 + lilconfig: 3.1.2 optionalDependencies: - jiti: 2.7.0 - postcss: 8.5.25 - yaml: 2.9.0 + jiti: 2.4.0 + postcss: 8.4.49 + tsx: 4.19.1 + yaml: 2.6.0 - postcss-nested@6.2.0(postcss@8.5.16): + postcss-nested@6.2.0(postcss@8.4.47): dependencies: - postcss: 8.5.16 + postcss: 8.4.47 postcss-selector-parser: 6.1.2 postcss-selector-parser@6.0.10: @@ -5425,7 +8800,7 @@ snapshots: cssesc: 3.0.0 util-deprecate: 1.0.2 - postcss-selector-parser@7.1.4: + postcss-selector-parser@7.0.0: dependencies: cssesc: 3.0.0 util-deprecate: 1.0.2 @@ -5434,57 +8809,71 @@ snapshots: postcss@8.4.31: dependencies: - nanoid: 3.3.12 + nanoid: 3.3.7 picocolors: 1.1.1 source-map-js: 1.2.1 - postcss@8.5.16: + postcss@8.4.41: dependencies: - nanoid: 3.3.12 + nanoid: 3.3.7 + picocolors: 1.1.1 + source-map-js: 1.2.0 + + postcss@8.4.47: + dependencies: + nanoid: 3.3.7 picocolors: 1.1.1 source-map-js: 1.2.1 - postcss@8.5.25: + postcss@8.4.49: dependencies: - nanoid: 3.3.16 + nanoid: 3.3.7 picocolors: 1.1.1 source-map-js: 1.2.1 - prettier-plugin-embed@0.5.1: + prelude-ls@1.2.1: {} + + prettier-plugin-embed@0.4.15: dependencies: - '@types/estree': 1.0.9 - dedent: 1.7.2 - micro-memoize: 5.1.1 + '@types/estree': 1.0.5 + dedent: 1.5.3 + micro-memoize: 4.1.2 package-up: 5.0.0 - tiny-jsonc: 1.0.2 - type-fest: 5.6.0 + tiny-jsonc: 1.0.1 + type-fest: 4.24.0 transitivePeerDependencies: - babel-plugin-macros - prettier-plugin-organize-imports@4.3.0(prettier@3.9.6)(typescript@5.9.3): + prettier-plugin-organize-imports@4.0.0(prettier@3.3.3)(typescript@5.5.4): dependencies: - prettier: 3.9.6 - typescript: 5.9.3 + prettier: 3.3.3 + typescript: 5.5.4 - prettier@3.9.6: {} + prettier@3.3.3: {} + + prop-types@15.8.1: + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + react-is: 16.13.1 + + punycode@2.3.1: {} queue-microtask@1.2.3: {} - radix3@1.1.2: {} - - react-dom@19.2.6(react@19.2.6): + react-dom@18.3.1(react@18.3.1): dependencies: - react: 19.2.6 - scheduler: 0.27.0 + loose-envify: 1.4.0 + react: 18.3.1 + scheduler: 0.23.2 - react-dom@19.2.7(react@19.2.7): + react-is@16.13.1: {} + + react-refresh@0.14.2: {} + + react@18.3.1: dependencies: - react: 19.2.7 - scheduler: 0.27.0 - - react@19.2.6: {} - - react@19.2.7: {} + loose-envify: 1.4.0 read-cache@1.0.0: dependencies: @@ -5492,206 +8881,344 @@ snapshots: readdirp@3.6.0: dependencies: - picomatch: 2.3.2 + picomatch: 2.3.1 - readdirp@4.1.2: {} + reflect.getprototypeof@1.0.6: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + globalthis: 1.0.4 + which-builtin-type: 1.1.4 - require-from-string@2.0.2: {} + regexp.prototype.flags@1.5.2: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-errors: 1.3.0 + set-function-name: 2.0.2 + + resolve-from@4.0.0: {} resolve-from@5.0.0: {} - resolve@1.22.12: + resolve-pkg-maps@1.0.0: {} + + resolve@1.22.8: dependencies: - es-errors: 1.3.0 - is-core-module: 2.16.2 + is-core-module: 2.15.0 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - reusify@1.1.0: {} - - rolldown@1.2.1: + resolve@2.0.0-next.5: dependencies: - '@oxc-project/types': 0.142.0 - '@rolldown/pluginutils': 1.0.1 - optionalDependencies: - '@rolldown/binding-android-arm64': 1.2.1 - '@rolldown/binding-darwin-arm64': 1.2.1 - '@rolldown/binding-darwin-x64': 1.2.1 - '@rolldown/binding-freebsd-x64': 1.2.1 - '@rolldown/binding-linux-arm-gnueabihf': 1.2.1 - '@rolldown/binding-linux-arm64-gnu': 1.2.1 - '@rolldown/binding-linux-arm64-musl': 1.2.1 - '@rolldown/binding-linux-ppc64-gnu': 1.2.1 - '@rolldown/binding-linux-s390x-gnu': 1.2.1 - '@rolldown/binding-linux-x64-gnu': 1.2.1 - '@rolldown/binding-linux-x64-musl': 1.2.1 - '@rolldown/binding-openharmony-arm64': 1.2.1 - '@rolldown/binding-wasm32-wasi': 1.2.1 - '@rolldown/binding-win32-arm64-msvc': 1.2.1 - '@rolldown/binding-win32-x64-msvc': 1.2.1 + is-core-module: 2.15.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 - rollup@4.60.4: + reusify@1.0.4: {} + + rollup@4.20.0: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.5 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.60.4 - '@rollup/rollup-android-arm64': 4.60.4 - '@rollup/rollup-darwin-arm64': 4.60.4 - '@rollup/rollup-darwin-x64': 4.60.4 - '@rollup/rollup-freebsd-arm64': 4.60.4 - '@rollup/rollup-freebsd-x64': 4.60.4 - '@rollup/rollup-linux-arm-gnueabihf': 4.60.4 - '@rollup/rollup-linux-arm-musleabihf': 4.60.4 - '@rollup/rollup-linux-arm64-gnu': 4.60.4 - '@rollup/rollup-linux-arm64-musl': 4.60.4 - '@rollup/rollup-linux-loong64-gnu': 4.60.4 - '@rollup/rollup-linux-loong64-musl': 4.60.4 - '@rollup/rollup-linux-ppc64-gnu': 4.60.4 - '@rollup/rollup-linux-ppc64-musl': 4.60.4 - '@rollup/rollup-linux-riscv64-gnu': 4.60.4 - '@rollup/rollup-linux-riscv64-musl': 4.60.4 - '@rollup/rollup-linux-s390x-gnu': 4.60.4 - '@rollup/rollup-linux-x64-gnu': 4.60.4 - '@rollup/rollup-linux-x64-musl': 4.60.4 - '@rollup/rollup-openbsd-x64': 4.60.4 - '@rollup/rollup-openharmony-arm64': 4.60.4 - '@rollup/rollup-win32-arm64-msvc': 4.60.4 - '@rollup/rollup-win32-ia32-msvc': 4.60.4 - '@rollup/rollup-win32-x64-gnu': 4.60.4 - '@rollup/rollup-win32-x64-msvc': 4.60.4 + '@rollup/rollup-android-arm-eabi': 4.20.0 + '@rollup/rollup-android-arm64': 4.20.0 + '@rollup/rollup-darwin-arm64': 4.20.0 + '@rollup/rollup-darwin-x64': 4.20.0 + '@rollup/rollup-linux-arm-gnueabihf': 4.20.0 + '@rollup/rollup-linux-arm-musleabihf': 4.20.0 + '@rollup/rollup-linux-arm64-gnu': 4.20.0 + '@rollup/rollup-linux-arm64-musl': 4.20.0 + '@rollup/rollup-linux-powerpc64le-gnu': 4.20.0 + '@rollup/rollup-linux-riscv64-gnu': 4.20.0 + '@rollup/rollup-linux-s390x-gnu': 4.20.0 + '@rollup/rollup-linux-x64-gnu': 4.20.0 + '@rollup/rollup-linux-x64-musl': 4.20.0 + '@rollup/rollup-win32-arm64-msvc': 4.20.0 + '@rollup/rollup-win32-ia32-msvc': 4.20.0 + '@rollup/rollup-win32-x64-msvc': 4.20.0 + fsevents: 2.3.3 + + rollup@4.27.4: + dependencies: + '@types/estree': 1.0.6 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.27.4 + '@rollup/rollup-android-arm64': 4.27.4 + '@rollup/rollup-darwin-arm64': 4.27.4 + '@rollup/rollup-darwin-x64': 4.27.4 + '@rollup/rollup-freebsd-arm64': 4.27.4 + '@rollup/rollup-freebsd-x64': 4.27.4 + '@rollup/rollup-linux-arm-gnueabihf': 4.27.4 + '@rollup/rollup-linux-arm-musleabihf': 4.27.4 + '@rollup/rollup-linux-arm64-gnu': 4.27.4 + '@rollup/rollup-linux-arm64-musl': 4.27.4 + '@rollup/rollup-linux-powerpc64le-gnu': 4.27.4 + '@rollup/rollup-linux-riscv64-gnu': 4.27.4 + '@rollup/rollup-linux-s390x-gnu': 4.27.4 + '@rollup/rollup-linux-x64-gnu': 4.27.4 + '@rollup/rollup-linux-x64-musl': 4.27.4 + '@rollup/rollup-win32-arm64-msvc': 4.27.4 + '@rollup/rollup-win32-ia32-msvc': 4.27.4 + '@rollup/rollup-win32-x64-msvc': 4.27.4 fsevents: 2.3.3 run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 - safer-buffer@2.1.2: {} - - scheduler@0.27.0: {} - - schema-utils@4.3.3: + safe-array-concat@1.1.2: dependencies: - '@types/json-schema': 7.0.15 - ajv: 8.20.0 - ajv-formats: 2.1.1(ajv@8.20.0) - ajv-keywords: 5.1.0(ajv@8.20.0) + call-bind: 1.0.7 + get-intrinsic: 1.2.4 + has-symbols: 1.0.3 + isarray: 2.0.5 - semver@7.8.5: {} - - sharp@0.34.5: + safe-regex-test@1.0.3: dependencies: - '@img/colour': 1.1.0 - detect-libc: 2.1.2 - semver: 7.8.5 + call-bind: 1.0.7 + es-errors: 1.3.0 + is-regex: 1.1.4 + + scheduler@0.23.2: + dependencies: + loose-envify: 1.4.0 + + semver@6.3.1: {} + + semver@7.6.3: {} + + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.2.4 + gopd: 1.0.1 + has-property-descriptors: 1.0.2 + + set-function-name@2.0.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + functions-have-names: 1.2.3 + has-property-descriptors: 1.0.2 + + sharp@0.33.5: + dependencies: + color: 4.2.3 + detect-libc: 2.0.3 + semver: 7.6.3 optionalDependencies: - '@img/sharp-darwin-arm64': 0.34.5 - '@img/sharp-darwin-x64': 0.34.5 - '@img/sharp-libvips-darwin-arm64': 1.2.4 - '@img/sharp-libvips-darwin-x64': 1.2.4 - '@img/sharp-libvips-linux-arm': 1.2.4 - '@img/sharp-libvips-linux-arm64': 1.2.4 - '@img/sharp-libvips-linux-ppc64': 1.2.4 - '@img/sharp-libvips-linux-riscv64': 1.2.4 - '@img/sharp-libvips-linux-s390x': 1.2.4 - '@img/sharp-libvips-linux-x64': 1.2.4 - '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 - '@img/sharp-libvips-linuxmusl-x64': 1.2.4 - '@img/sharp-linux-arm': 0.34.5 - '@img/sharp-linux-arm64': 0.34.5 - '@img/sharp-linux-ppc64': 0.34.5 - '@img/sharp-linux-riscv64': 0.34.5 - '@img/sharp-linux-s390x': 0.34.5 - '@img/sharp-linux-x64': 0.34.5 - '@img/sharp-linuxmusl-arm64': 0.34.5 - '@img/sharp-linuxmusl-x64': 0.34.5 - '@img/sharp-wasm32': 0.34.5 - '@img/sharp-win32-arm64': 0.34.5 - '@img/sharp-win32-ia32': 0.34.5 - '@img/sharp-win32-x64': 0.34.5 + '@img/sharp-darwin-arm64': 0.33.5 + '@img/sharp-darwin-x64': 0.33.5 + '@img/sharp-libvips-darwin-arm64': 1.0.4 + '@img/sharp-libvips-darwin-x64': 1.0.4 + '@img/sharp-libvips-linux-arm': 1.0.5 + '@img/sharp-libvips-linux-arm64': 1.0.4 + '@img/sharp-libvips-linux-s390x': 1.0.4 + '@img/sharp-libvips-linux-x64': 1.0.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 + '@img/sharp-libvips-linuxmusl-x64': 1.0.4 + '@img/sharp-linux-arm': 0.33.5 + '@img/sharp-linux-arm64': 0.33.5 + '@img/sharp-linux-s390x': 0.33.5 + '@img/sharp-linux-x64': 0.33.5 + '@img/sharp-linuxmusl-arm64': 0.33.5 + '@img/sharp-linuxmusl-x64': 0.33.5 + '@img/sharp-wasm32': 0.33.5 + '@img/sharp-win32-ia32': 0.33.5 + '@img/sharp-win32-x64': 0.33.5 optional: true + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + side-channel@1.0.6: + dependencies: + call-bind: 1.0.7 + es-errors: 1.3.0 + get-intrinsic: 1.2.4 + object-inspect: 1.13.2 + siginfo@2.0.0: {} + signal-exit@3.0.7: {} + signal-exit@4.1.0: {} + simple-swizzle@0.2.2: + dependencies: + is-arrayish: 0.3.2 + optional: true + + slash@3.0.0: {} + slash@5.1.0: {} + source-map-js@1.2.0: {} + source-map-js@1.2.1: {} source-map-support@0.5.21: dependencies: buffer-from: 1.1.2 source-map: 0.6.1 + optional: true - source-map@0.6.1: {} + source-map@0.6.1: + optional: true - source-map@0.7.6: {} + source-map@0.8.0-beta.0: + dependencies: + whatwg-url: 7.1.0 stackback@0.0.2: {} - std-env@4.1.0: {} + std-env@3.7.0: {} - std-env@4.2.0: {} + streamsearch@1.1.0: {} - styled-jsx@5.1.6(react@19.2.7): + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + + string.prototype.includes@2.0.1: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + + string.prototype.matchall@4.0.11: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-errors: 1.3.0 + es-object-atoms: 1.0.0 + get-intrinsic: 1.2.4 + gopd: 1.0.1 + has-symbols: 1.0.3 + internal-slot: 1.0.7 + regexp.prototype.flags: 1.5.2 + set-function-name: 2.0.2 + side-channel: 1.0.6 + + string.prototype.repeat@1.0.0: + dependencies: + define-properties: 1.2.1 + es-abstract: 1.23.3 + + string.prototype.trim@1.2.9: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-abstract: 1.23.3 + es-object-atoms: 1.0.0 + + string.prototype.trimend@1.0.8: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + + string.prototype.trimstart@1.0.8: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + es-object-atoms: 1.0.0 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.1.0: + dependencies: + ansi-regex: 6.0.1 + + strip-bom@3.0.0: {} + + strip-final-newline@2.0.0: {} + + strip-final-newline@3.0.0: {} + + strip-json-comments@3.1.1: {} + + styled-jsx@5.1.6(react@18.3.1): dependencies: client-only: 0.0.1 - react: 19.2.7 + react: 18.3.1 - sucrase@3.35.1: + sucrase@3.35.0: dependencies: - '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/gen-mapping': 0.3.5 commander: 4.1.1 + glob: 10.4.5 lines-and-columns: 1.2.4 mz: 2.7.0 - pirates: 4.0.7 - tinyglobby: 0.2.16 + pirates: 4.0.6 ts-interface-checker: 0.1.13 - supports-color@8.1.1: + supports-color@5.5.0: + dependencies: + has-flag: 3.0.0 + + supports-color@7.2.0: dependencies: has-flag: 4.0.0 supports-preserve-symlinks-flag@1.0.0: {} - tagged-tag@1.0.0: {} - - tailwindcss@3.4.19(yaml@2.9.0): + tailwindcss@3.4.14: dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 chokidar: 3.6.0 didyoumean: 1.2.2 dlv: 1.1.3 - fast-glob: 3.3.3 + fast-glob: 3.3.2 glob-parent: 6.0.2 is-glob: 4.0.3 - jiti: 1.21.7 - lilconfig: 3.1.3 - micromatch: 4.0.8 + jiti: 1.21.6 + lilconfig: 2.1.0 + micromatch: 4.0.7 normalize-path: 3.0.0 object-hash: 3.0.0 picocolors: 1.1.1 - postcss: 8.5.16 - postcss-import: 15.1.0(postcss@8.5.16) - postcss-js: 4.1.0(postcss@8.5.16) - postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.16)(yaml@2.9.0) - postcss-nested: 6.2.0(postcss@8.5.16) + postcss: 8.4.47 + postcss-import: 15.1.0(postcss@8.4.47) + postcss-js: 4.0.1(postcss@8.4.47) + postcss-load-config: 4.0.2(postcss@8.4.47) + postcss-nested: 6.2.0(postcss@8.4.47) postcss-selector-parser: 6.1.2 - resolve: 1.22.12 - sucrase: 3.35.1 + resolve: 1.22.8 + sucrase: 3.35.0 transitivePeerDependencies: - - tsx - - yaml + - ts-node - tapable@2.3.3: {} + tapable@2.2.1: {} - terser@5.48.0: + terser@5.31.6: dependencies: - '@jridgewell/source-map': 0.3.11 - acorn: 8.16.0 + '@jridgewell/source-map': 0.3.6 + acorn: 8.14.0 commander: 2.20.3 source-map-support: 0.5.21 + optional: true thenify-all@1.6.0: dependencies: @@ -5701,231 +9228,347 @@ snapshots: dependencies: any-promise: 1.3.0 - tiny-jsonc@1.0.2: {} + tiny-jsonc@1.0.1: {} tinybench@2.9.0: {} - tinyclip@0.1.15: {} + tinypool@1.0.0: {} - tinyexec@0.3.2: {} + tinyrainbow@1.2.0: {} - tinyexec@1.1.2: {} + tinyspy@3.0.0: {} - tinyglobby@0.2.16: - dependencies: - fdir: 6.5.0(picomatch@4.0.4) - picomatch: 4.0.4 - - tinyglobby@0.2.17: - dependencies: - fdir: 6.5.0(picomatch@4.0.5) - picomatch: 4.0.5 - - tinyrainbow@3.1.0: {} + to-fast-properties@2.0.0: {} to-regex-range@5.0.1: dependencies: is-number: 7.0.0 + tr46@1.0.1: + dependencies: + punycode: 2.3.1 + tree-kill@1.2.2: {} - tree-sitter-javascript@0.23.1(tree-sitter@0.25.1): + tree-sitter-javascript@0.23.1(tree-sitter@0.22.1): dependencies: - node-addon-api: 8.7.0 - node-gyp-build: 4.8.4 + node-addon-api: 8.2.2 + node-gyp-build: 4.8.2 optionalDependencies: - tree-sitter: 0.25.1 + tree-sitter: 0.22.1 - tree-sitter-typescript@0.23.2(tree-sitter@0.25.1): + tree-sitter-typescript@0.23.2(tree-sitter@0.22.1): dependencies: - node-addon-api: 8.7.0 - node-gyp-build: 4.8.4 - tree-sitter-javascript: 0.23.1(tree-sitter@0.25.1) + node-addon-api: 8.2.2 + node-gyp-build: 4.8.2 + tree-sitter-javascript: 0.23.1(tree-sitter@0.22.1) optionalDependencies: - tree-sitter: 0.25.1 + tree-sitter: 0.22.1 - tree-sitter@0.25.1: + tree-sitter@0.22.1: dependencies: - node-addon-api: 8.7.0 - node-gyp-build: 4.8.4 + node-addon-api: 8.2.2 + node-gyp-build: 4.8.2 + + ts-api-utils@1.3.0(typescript@5.5.4): + dependencies: + typescript: 5.5.4 + + ts-api-utils@1.3.0(typescript@5.6.3): + dependencies: + typescript: 5.6.3 ts-interface-checker@0.1.13: {} - tslib@2.8.1: {} - - tsup@8.5.1(jiti@2.7.0)(postcss@8.5.25)(typescript@5.9.3)(yaml@2.9.0): + tsconfig-paths@3.15.0: dependencies: - bundle-require: 5.1.0(esbuild@0.27.7) + '@types/json5': 0.0.29 + json5: 1.0.2 + minimist: 1.2.8 + strip-bom: 3.0.0 + + tslib@2.8.0: {} + + tsup@8.2.4(jiti@2.4.0)(postcss@8.4.49)(tsx@4.19.1)(typescript@5.5.4)(yaml@2.6.0): + dependencies: + bundle-require: 5.0.0(esbuild@0.23.0) cac: 6.7.14 - chokidar: 4.0.3 - consola: 3.4.2 - debug: 4.4.3 - esbuild: 0.27.7 - fix-dts-default-cjs-exports: 1.0.1 + chokidar: 3.6.0 + consola: 3.2.3 + debug: 4.3.6 + esbuild: 0.23.0 + execa: 5.1.1 + globby: 11.1.0 joycon: 3.1.1 picocolors: 1.1.1 - postcss-load-config: 6.0.1(jiti@2.7.0)(postcss@8.5.25)(yaml@2.9.0) + postcss-load-config: 6.0.1(jiti@2.4.0)(postcss@8.4.49)(tsx@4.19.1)(yaml@2.6.0) resolve-from: 5.0.0 - rollup: 4.60.4 - source-map: 0.7.6 - sucrase: 3.35.1 - tinyexec: 0.3.2 - tinyglobby: 0.2.16 + rollup: 4.20.0 + source-map: 0.8.0-beta.0 + sucrase: 3.35.0 tree-kill: 1.2.2 optionalDependencies: - postcss: 8.5.25 - typescript: 5.9.3 + postcss: 8.4.49 + typescript: 5.5.4 transitivePeerDependencies: - jiti - supports-color - tsx - yaml - turbo@2.10.8: + tsx@4.19.1: + dependencies: + esbuild: 0.23.1 + get-tsconfig: 4.8.1 optionalDependencies: - '@turbo/darwin-64': 2.10.8 - '@turbo/darwin-arm64': 2.10.8 - '@turbo/linux-64': 2.10.8 - '@turbo/linux-arm64': 2.10.8 - '@turbo/windows-64': 2.10.8 - '@turbo/windows-arm64': 2.10.8 + fsevents: 2.3.3 + optional: true - typanion@3.14.0: {} + turbo-darwin-64@2.2.3: + optional: true - type-fest@5.6.0: + turbo-darwin-arm64@2.2.3: + optional: true + + turbo-linux-64@2.2.3: + optional: true + + turbo-linux-arm64@2.2.3: + optional: true + + turbo-windows-64@2.2.3: + optional: true + + turbo-windows-arm64@2.2.3: + optional: true + + turbo@2.2.3: + optionalDependencies: + turbo-darwin-64: 2.2.3 + turbo-darwin-arm64: 2.2.3 + turbo-linux-64: 2.2.3 + turbo-linux-arm64: 2.2.3 + turbo-windows-64: 2.2.3 + turbo-windows-arm64: 2.2.3 + + type-check@0.4.0: dependencies: - tagged-tag: 1.0.0 + prelude-ls: 1.2.1 - typescript@5.9.3: {} + type-fest@4.24.0: {} - typescript@6.0.3: {} - - ufo@1.6.4: {} - - uncrypto@0.1.3: {} - - undici-types@6.21.0: {} - - undici-types@7.24.6: {} - - unicorn-magic@0.4.0: {} - - universal-user-agent@7.0.3: {} - - untun@0.2.2: {} - - update-browserslist-db@1.2.3(browserslist@4.28.2): + typed-array-buffer@1.0.2: dependencies: - browserslist: 4.28.2 + call-bind: 1.0.7 + es-errors: 1.3.0 + is-typed-array: 1.1.13 + + typed-array-byte-length@1.0.1: + dependencies: + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-proto: 1.0.3 + is-typed-array: 1.1.13 + + typed-array-byte-offset@1.0.2: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-proto: 1.0.3 + is-typed-array: 1.1.13 + + typed-array-length@1.0.6: + dependencies: + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-proto: 1.0.3 + is-typed-array: 1.1.13 + possible-typed-array-names: 1.0.0 + + typescript@5.5.4: {} + + typescript@5.6.3: {} + + unbox-primitive@1.0.2: + dependencies: + call-bind: 1.0.7 + has-bigints: 1.0.2 + has-symbols: 1.0.3 + which-boxed-primitive: 1.0.2 + + undici-types@5.26.5: {} + + unicorn-magic@0.1.0: {} + + update-browserslist-db@1.1.0(browserslist@4.23.2): + dependencies: + browserslist: 4.23.2 + escalade: 3.1.2 + picocolors: 1.1.1 + + update-browserslist-db@1.1.1(browserslist@4.24.2): + dependencies: + browserslist: 4.24.2 escalade: 3.2.0 picocolors: 1.1.1 - uqr@0.1.3: {} + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 util-deprecate@1.0.2: {} - vite@8.2.0(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.48.0)(yaml@2.9.0): + vite-node@2.0.5(@types/node@20.14.13)(lightningcss@1.26.0(patch_hash=5hwfyehqvg5wjb7mwtdvubqbl4))(terser@5.31.6): dependencies: - lightningcss: 1.33.0(patch_hash=1d4a8800d60d13d42887b88b3a86576df4b451670308145fb432ec8abbf40930) - picomatch: 4.0.5 - postcss: 8.5.25 - rolldown: 1.2.1 - tinyglobby: 0.2.17 - optionalDependencies: - '@types/node': 22.20.1 - esbuild: 0.27.7 - fsevents: 2.3.3 - jiti: 2.7.0 - terser: 5.48.0 - yaml: 2.9.0 + cac: 6.7.14 + debug: 4.3.6 + pathe: 1.1.2 + tinyrainbow: 1.2.0 + vite: 5.4.0(@types/node@20.14.13)(lightningcss@1.26.0(patch_hash=5hwfyehqvg5wjb7mwtdvubqbl4))(terser@5.31.6) + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser - vite@8.2.0(@types/node@25.9.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.48.0)(yaml@2.9.0): + vite@5.4.0(@types/node@20.14.13)(lightningcss@1.26.0(patch_hash=5hwfyehqvg5wjb7mwtdvubqbl4))(terser@5.31.6): dependencies: - lightningcss: 1.33.0(patch_hash=1d4a8800d60d13d42887b88b3a86576df4b451670308145fb432ec8abbf40930) - picomatch: 4.0.5 - postcss: 8.5.25 - rolldown: 1.2.1 - tinyglobby: 0.2.17 + esbuild: 0.21.5 + postcss: 8.4.49 + rollup: 4.27.4 optionalDependencies: - '@types/node': 25.9.1 - esbuild: 0.27.7 + '@types/node': 20.14.13 fsevents: 2.3.3 - jiti: 2.7.0 - terser: 5.48.0 - yaml: 2.9.0 + lightningcss: 1.26.0(patch_hash=5hwfyehqvg5wjb7mwtdvubqbl4) + terser: 5.31.6 - vitest@4.1.10(@types/node@22.20.1)(vite@8.2.0(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.48.0)(yaml@2.9.0)): + vite@6.0.0(@types/node@20.14.13)(jiti@2.4.0)(lightningcss@1.26.0(patch_hash=5hwfyehqvg5wjb7mwtdvubqbl4))(terser@5.31.6)(tsx@4.19.1)(yaml@2.6.0): dependencies: - '@vitest/expect': 4.1.10 - '@vitest/mocker': 4.1.10(vite@8.2.0(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.48.0)(yaml@2.9.0)) - '@vitest/pretty-format': 4.1.10 - '@vitest/runner': 4.1.10 - '@vitest/snapshot': 4.1.10 - '@vitest/spy': 4.1.10 - '@vitest/utils': 4.1.10 - es-module-lexer: 2.1.0 - expect-type: 1.3.0 - magic-string: 0.30.21 - obug: 2.1.1 - pathe: 2.0.3 - picomatch: 4.0.4 - std-env: 4.1.0 + esbuild: 0.24.0 + postcss: 8.4.49 + rollup: 4.27.4 + optionalDependencies: + '@types/node': 20.14.13 + fsevents: 2.3.3 + jiti: 2.4.0 + lightningcss: 1.26.0(patch_hash=5hwfyehqvg5wjb7mwtdvubqbl4) + terser: 5.31.6 + tsx: 4.19.1 + yaml: 2.6.0 + + vitest@2.0.5(@types/node@20.14.13)(lightningcss@1.26.0(patch_hash=5hwfyehqvg5wjb7mwtdvubqbl4))(terser@5.31.6): + dependencies: + '@ampproject/remapping': 2.3.0 + '@vitest/expect': 2.0.5 + '@vitest/pretty-format': 2.0.5 + '@vitest/runner': 2.0.5 + '@vitest/snapshot': 2.0.5 + '@vitest/spy': 2.0.5 + '@vitest/utils': 2.0.5 + chai: 5.1.1 + debug: 4.3.6 + execa: 8.0.1 + magic-string: 0.30.11 + pathe: 1.1.2 + std-env: 3.7.0 tinybench: 2.9.0 - tinyexec: 1.1.2 - tinyglobby: 0.2.17 - tinyrainbow: 3.1.0 - vite: 8.2.0(@types/node@22.20.1)(esbuild@0.27.7)(jiti@2.7.0)(terser@5.48.0)(yaml@2.9.0) + tinypool: 1.0.0 + tinyrainbow: 1.2.0 + vite: 5.4.0(@types/node@20.14.13)(lightningcss@1.26.0(patch_hash=5hwfyehqvg5wjb7mwtdvubqbl4))(terser@5.31.6) + vite-node: 2.0.5(@types/node@20.14.13)(lightningcss@1.26.0(patch_hash=5hwfyehqvg5wjb7mwtdvubqbl4))(terser@5.31.6) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 22.20.1 + '@types/node': 20.14.13 transitivePeerDependencies: - - msw - - watchpack@2.5.2: - dependencies: - graceful-fs: 4.2.11 - - webpack-sources@3.5.1: {} - - webpack@5.109.2(esbuild@0.27.7)(postcss@8.5.25): - dependencies: - '@types/estree': 1.0.9 - '@types/json-schema': 7.0.15 - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/wasm-edit': 1.14.1 - '@webassemblyjs/wasm-parser': 1.14.1 - acorn: 8.16.0 - browserslist: 4.28.2 - chrome-trace-event: 1.0.4 - enhanced-resolve: 5.24.5 - es-module-lexer: 2.1.0 - eslint-scope: 5.1.1 - events: 3.3.0 - graceful-fs: 4.2.11 - mime-db: 1.54.0 - minimizer-webpack-plugin: 5.6.1(esbuild@0.27.7)(postcss@8.5.25)(webpack@5.109.2(esbuild@0.27.7)(postcss@8.5.25)) - neo-async: 2.6.2 - schema-utils: 4.3.3 - tapable: 2.3.3 - watchpack: 2.5.2 - webpack-sources: 3.5.1 - transitivePeerDependencies: - - '@minify-html/node' - - '@swc/core' - - '@swc/css' - - '@swc/html' - - clean-css - - cssnano - - csso - - esbuild - - html-minifier-terser + - less - lightningcss - - postcss - - uglify-js + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + + webidl-conversions@4.0.2: {} + + whatwg-url@7.1.0: + dependencies: + lodash.sortby: 4.7.0 + tr46: 1.0.1 + webidl-conversions: 4.0.2 + + which-boxed-primitive@1.0.2: + dependencies: + is-bigint: 1.0.4 + is-boolean-object: 1.1.2 + is-number-object: 1.0.7 + is-string: 1.0.7 + is-symbol: 1.0.4 + + which-builtin-type@1.1.4: + dependencies: + function.prototype.name: 1.1.6 + has-tostringtag: 1.0.2 + is-async-function: 2.0.0 + is-date-object: 1.0.5 + is-finalizationregistry: 1.0.2 + is-generator-function: 1.0.10 + is-regex: 1.1.4 + is-weakref: 1.0.2 + isarray: 2.0.5 + which-boxed-primitive: 1.0.2 + which-collection: 1.0.2 + which-typed-array: 1.1.15 + + which-collection@1.0.2: + dependencies: + is-map: 2.0.3 + is-set: 2.0.3 + is-weakmap: 2.0.2 + is-weakset: 2.0.3 + + which-typed-array@1.1.15: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-tostringtag: 1.0.2 + + which@2.0.2: + dependencies: + isexe: 2.0.0 why-is-node-running@2.3.0: dependencies: siginfo: 2.0.0 stackback: 0.0.2 - yaml@2.9.0: {} + word-wrap@1.2.5: {} + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + + yallist@3.1.1: {} + + yaml@2.6.0: {} + + yocto-queue@0.1.0: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index bcddef126..4573bf90d 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -5,50 +5,7 @@ packages: - 'playgrounds/*' - 'integrations' -patchedDependencies: - '@napi-rs/cli@3.7.4': patches/@napi-rs__cli@3.7.4.patch - '@parcel/watcher@2.6.0': patches/@parcel__watcher@2.6.0.patch - lightningcss@1.33.0: patches/lightningcss@1.33.0.patch - catalog: - '@types/node': 22.20.1 - dedent: 1.7.2 - enhanced-resolve: ^5.24.5 - lightningcss-darwin-arm64: 1.33.0 - lightningcss-darwin-x64: 1.33.0 - lightningcss-linux-arm64-gnu: 1.33.0 - lightningcss-linux-arm64-musl: 1.33.0 - lightningcss-linux-x64-gnu: 1.33.0 - lightningcss-linux-x64-musl: 1.33.0 - lightningcss-win32-x64-msvc: 1.33.0 - lightningcss: 1.33.0 - '@parcel/watcher-darwin-arm64': 2.6.0 - '@parcel/watcher-darwin-x64': 2.6.0 - '@parcel/watcher-linux-arm64-glibc': 2.6.0 - '@parcel/watcher-linux-arm64-musl': 2.6.0 - '@parcel/watcher-linux-x64-glibc': 2.6.0 - '@parcel/watcher-linux-x64-musl': 2.6.0 - '@parcel/watcher-win32-x64': 2.6.0 - '@parcel/watcher': 2.6.0 - postcss: ^8.5.25 - prettier: 3.9.6 - vite: ^8.2.0 - webpack: ^5.109.2 - -onlyBuiltDependencies: - - '@parcel/watcher' - - bun - - esbuild - - sharp - - tree-sitter - - tree-sitter-javascript - - tree-sitter-typescript - -allowBuilds: - '@parcel/watcher': true - bun: true - esbuild: true - sharp: true - tree-sitter: true - tree-sitter-javascript: true - tree-sitter-typescript: true + '@types/node': ^20.14.8 + lightningcss: ^1.26.0 + vite: ^6.0.0 diff --git a/rust-toolchain.toml b/rust-toolchain.toml index f92020c65..7f466bd2d 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "1.95.0" +channel = "1.80.1" profile = "default" diff --git a/scripts/pack-packages.mjs b/scripts/pack-packages.mjs index 2b0b9f15d..3bcf23bec 100644 --- a/scripts/pack-packages.mjs +++ b/scripts/pack-packages.mjs @@ -21,25 +21,30 @@ let workspaces = new Map() for (let path of paths) { let pkg = await fs.readFile(path, 'utf8').then(JSON.parse) if (pkg.private) continue - workspaces.set(pkg.name, { - version: pkg.version ?? '', - dir: dirname(path), - hasBundledDependencies: pkg.bundledDependencies?.length > 0 ?? false, - }) + workspaces.set(pkg.name, { version: pkg.version ?? '', dir: dirname(path) }) +} + +// Move napi artifacts into sub packages +const tailwindcssOxideRoot = path.join(root, 'crates', 'node') +for (let file of await fs.readdir(tailwindcssOxideRoot)) { + if (file.startsWith('tailwindcss-oxide.') && file.endsWith('.node')) { + let target = file.split('.')[1] + await fs.cp( + path.join(tailwindcssOxideRoot, file), + path.join(tailwindcssOxideRoot, 'npm', target, file), + ) + } } // Clean dist folder await fs.rm(path.join(root, 'dist'), { recursive: true, force: true }) Promise.all( - [...workspaces.entries()].map(async ([name, { dir, hasBundledDependencies }]) => { + [...workspaces.entries()].map(async ([name, { version, dir }]) => { function pack() { return new Promise((resolve) => { - // `bundledDependencies` can only be packed with the hoisted node linker - // since pnpm v10. We opt into it for those packages only, instead of - // changing the node linker for the entire workspace. exec( - `pnpm pack --pack-gzip-level=0 --pack-destination="${path.join(root, 'dist').replace(/\\/g, '\\\\')}"${hasBundledDependencies ? ' --config.node-linker=hoisted' : ''}`, + `pnpm pack --pack-gzip-level=0 --pack-destination="${path.join(root, 'dist').replace(/\\/g, '\\\\')}"`, { cwd: dir }, (err, stdout, stderr) => { if (err) { diff --git a/scripts/release-channel.js b/scripts/release-channel.js deleted file mode 100644 index 15dc7df82..000000000 --- a/scripts/release-channel.js +++ /dev/null @@ -1,20 +0,0 @@ -// Given a version, figure out what the release channel is so that we can publish to the correct -// channel on npm. -// -// E.g.: -// -// 1.2.3 -> latest (default) -// 0.0.0-insiders.ffaa88 -> insiders -// 4.1.0-alpha.4 -> alpha - -let version = - process.argv[2] || - process.env.npm_package_version || - require('../packages/tailwindcss/package.json').version - -let match = /\d+\.\d+\.\d+-(.*)\.\d+/g.exec(version) -if (match) { - console.log(match[1]) -} else { - console.log('latest') -} diff --git a/scripts/release-notes.mjs b/scripts/release-notes.mjs index bb703c07b..289cb1d96 100644 --- a/scripts/release-notes.mjs +++ b/scripts/release-notes.mjs @@ -1,5 +1,5 @@ // Given a version, figure out what the release notes are so that we can use this to pre-fill the -// release notes on a GitHub release for the current version. +// relase notes on a GitHub release for the current version. import * as fs from 'node:fs/promises' import * as path from 'node:path' diff --git a/scripts/version-packages.mjs b/scripts/version-packages.mjs index 1641d5404..2e3d93a3e 100644 --- a/scripts/version-packages.mjs +++ b/scripts/version-packages.mjs @@ -8,7 +8,6 @@ import prettier from 'prettier' const __dirname = path.dirname(url.fileURLToPath(import.meta.url)) const root = path.resolve(__dirname, '..') -const version = process.argv[2] || null // The known workspace is: @tailwindcss/oxide // All the workspaces in `crates/node/npm/*` should always be in sync with @@ -28,9 +27,8 @@ const syncedWorkspaces = new Map([ 'crates/node/npm/linux-arm64-musl', 'crates/node/npm/linux-x64-gnu', 'crates/node/npm/linux-x64-musl', - 'crates/node/npm/wasm32-wasi', - 'crates/node/npm/win32-arm64-msvc', 'crates/node/npm/win32-x64-msvc', + 'crates/node/npm/win32-arm64-msvc', ], ], ['@tailwindcss/cli', ['packages/@tailwindcss-standalone']], @@ -48,19 +46,80 @@ for (let [name, paths] of syncedWorkspaces) { } } -exec( - "pnpm --silent --filter='!./playgrounds/*' --filter='!./integrations' --filter='!./packages/internal-example-plugin' -r exec pwd", - async (err, stdout) => { - if (err) { - console.error(err) - process.exit(1) - } +exec('pnpm --silent --filter=!./playgrounds/* -r exec pwd', async (err, stdout) => { + if (err) { + console.error(err) + process.exit(1) + } - if (version !== null) { - for (let pkgPath of stdout - .trim() - .split('\n') - .map((x) => path.resolve(x, 'package.json'))) { + let paths = stdout + .trim() + .split('\n') + .map((x) => path.resolve(x, 'package.json')) + // Workspaces that are in sync with another workspace should not be updated + // manually, they should be updated by updating the main workspace. + .filter((x) => !inverseSyncedWorkspaces.has(x)) + + let workspaces = new Map() + + // Track all the workspaces + for (let path of paths) { + let pkg = await fs.readFile(path, 'utf8').then(JSON.parse) + if (pkg.private) continue + workspaces.set(pkg.name, { version: pkg.version ?? '', path }) + } + + // Build the editable output + let lines = ['# Update the versions of the packages you want to change', ''] + for (let [name, info] of workspaces) { + lines.push(`${name}: ${info.version}`) + } + let output = lines.join('\n') + + // Edit the file + { + // Figure out which editor to use. + // + // In this case we still split on whitespace, because it can happen that the + // EDITOR env variable is configured as `code --wait`. This means that we + // want `code` as the editor, but `--wait` is one of the arguments. + let args = process.env.EDITOR.split(' ') + let editor = args.shift() + + // Create a temporary file which will be edited + let filepath = path.resolve(tmpdir(), `version-${randomUUID()}.txt`) + await fs.writeFile(filepath, output) + + // Edit the file, once the editor is closed, the file will be saved and we + // can read the changes + spawnSync(editor, [...args, filepath], { + stdio: 'inherit', + }) + + let newOutput = await fs.readFile(filepath, 'utf8').then((x) => x.trim().split('\n')) + + // Cleanup temporary file + await fs.unlink(filepath) + + // Update the package.json files + for (let line of newOutput) { + if (line[0] === '#') continue // Skip comment lines + if (line.trim() === '') continue // Skip empty lines + + let [name, version = ''] = line.split(':').map((x) => x.trim()) + + // Figure out all the paths to the package.json files that need to be + // updated with the new version + let paths = [ + // The package.json file of the main workspace + workspaces.get(name).path, + + // The package.json files of the workspaces that are in sync with the + // main workspace + ...(syncedWorkspaces.get(name) ?? []), + ] + + for (let pkgPath of paths) { let pkg = await fs.readFile(pkgPath, 'utf8').then(JSON.parse) let name = pkg.name if (version !== '') { @@ -79,100 +138,8 @@ exec( .then((x) => `${x.trim()}\n`), ) } - - console.log('Done.') - return } + } - let paths = stdout - .trim() - .split('\n') - .map((x) => path.resolve(x, 'package.json')) - // Workspaces that are in sync with another workspace should not be updated - // manually, they should be updated by updating the main workspace. - .filter((x) => !inverseSyncedWorkspaces.has(x)) - - let workspaces = new Map() - - // Track all the workspaces - for (let path of paths) { - let pkg = await fs.readFile(path, 'utf8').then(JSON.parse) - if (pkg.private) continue - workspaces.set(pkg.name, { version: pkg.version ?? '', path }) - } - - // Build the editable output - let lines = ['# Update the versions of the packages you want to change', ''] - for (let [name, info] of workspaces) { - lines.push(`${name}: ${info.version}`) - } - let output = lines.join('\n') - - // Edit the file - { - // Figure out which editor to use. - // - // In this case we still split on whitespace, because it can happen that the - // EDITOR env variable is configured as `code --wait`. This means that we - // want `code` as the editor, but `--wait` is one of the arguments. - let args = process.env.EDITOR.split(' ') - let editor = args.shift() - - // Create a temporary file which will be edited - let filepath = path.resolve(tmpdir(), `version-${randomUUID()}.txt`) - await fs.writeFile(filepath, output) - - // Edit the file, once the editor is closed, the file will be saved and we - // can read the changes - spawnSync(editor, [...args, filepath], { - stdio: 'inherit', - }) - - let newOutput = await fs.readFile(filepath, 'utf8').then((x) => x.trim().split('\n')) - - // Cleanup temporary file - await fs.unlink(filepath) - - // Update the package.json files - for (let line of newOutput) { - if (line[0] === '#') continue // Skip comment lines - if (line.trim() === '') continue // Skip empty lines - - let [name, version = ''] = line.split(':').map((x) => x.trim()) - - // Figure out all the paths to the package.json files that need to be - // updated with the new version - let paths = [ - // The package.json file of the main workspace - workspaces.get(name).path, - - // The package.json files of the workspaces that are in sync with the - // main workspace - ...(syncedWorkspaces.get(name) ?? []), - ] - - for (let pkgPath of paths) { - let pkg = await fs.readFile(pkgPath, 'utf8').then(JSON.parse) - let name = pkg.name - if (version !== '') { - // Ensure the version is set after the name and before everything else - delete pkg.name - delete pkg.version - - // This allows us to keep the order of the keys in the package.json - pkg = { name, version, ...pkg } - } - - await fs.writeFile( - pkgPath, - await prettier - .format(JSON.stringify(pkg, null, 2), { filepath: pkgPath }) - .then((x) => `${x.trim()}\n`), - ) - } - } - } - - console.log('Done.') - }, -) + console.log('Done.') +}) diff --git a/turbo.json b/turbo.json index c48410b29..35a3e63a7 100644 --- a/turbo.json +++ b/turbo.json @@ -1,5 +1,5 @@ { - "$schema": "https://v2-10-8.turborepo.dev/schema.json", + "$schema": "https://turbo.build/schema.json", "ui": "tui", "tasks": { "@tailwindcss/oxide#build": { @@ -10,7 +10,6 @@ "./build.rs", "./package.json", "./Cargo.toml", - "./.cargo/config.toml", "../oxide/src/**/*", "../oxide/Cargo.toml", "../Cargo.toml", @@ -25,7 +24,6 @@ "./build.rs", "./package.json", "./Cargo.toml", - "./.cargo/config.toml", "../oxide/src/**/*", "../oxide/Cargo.toml", "../Cargo.toml", @@ -36,8 +34,7 @@ }, "build": { "dependsOn": ["^build"], - "outputs": ["dist/**"], - "env": ["FEATURES_ENV"] + "outputs": ["dist/**"] }, "lint": {}, "dev": { diff --git a/vitest.config.mts b/vitest.config.mts deleted file mode 100644 index 3ef999be2..000000000 --- a/vitest.config.mts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from 'vitest/config' - -export default defineConfig({ - test: { - projects: ['./packages/*', '!./packages/tsconfig.base.json'], - exclude: ['**/*.spec.?(c|m)[jt]s?(x)', 'integrations/**/*'], - }, -}) diff --git a/vitest.workspace.ts b/vitest.workspace.ts new file mode 100644 index 000000000..4ccde0667 --- /dev/null +++ b/vitest.workspace.ts @@ -0,0 +1 @@ +export default ['packages/*']